blob: d254e043b95787fe88de8542e5022f616e11df66 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#include "sw/device/silicon_creator/lib/drivers/watchdog.h"
#include "sw/device/lib/base/abs_mmio.h"
#include "sw/device/silicon_creator/lib/base/sec_mmio.h"
#include "sw/device/silicon_creator/lib/drivers/lifecycle.h"
#include "sw/device/silicon_creator/lib/drivers/otp.h"
#include "aon_timer_regs.h"
#include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
#include "otp_ctrl_regs.h"
#include "pwrmgr_regs.h"
enum {
kBase = TOP_EARLGREY_AON_TIMER_AON_BASE_ADDR,
kPwrMgrBase = TOP_EARLGREY_PWRMGR_AON_BASE_ADDR,
kCtrlEnable = 1 << AON_TIMER_WDOG_CTRL_ENABLE_BIT,
kCtrlDisable = 0 << AON_TIMER_WDOG_CTRL_ENABLE_BIT,
};
void watchdog_init(lifecycle_state_t lc_state) {
SEC_MMIO_ASSERT_WRITE_INCREMENT(kWatchdogSecMmioInit,
kWatchdogSecMmioConfigure);
// Disable the watchdog bite when in test and RMA lifecycle states.
hardened_bool_t enable = kHardenedBoolTrue;
switch (launder32(lc_state)) {
case kLcStateTest:
HARDENED_CHECK_EQ(lc_state, kLcStateTest);
enable = kHardenedBoolFalse;
break;
case kLcStateDev:
HARDENED_CHECK_EQ(lc_state, kLcStateDev);
enable = kHardenedBoolTrue;
break;
case kLcStateProd:
HARDENED_CHECK_EQ(lc_state, kLcStateProd);
enable = kHardenedBoolTrue;
break;
case kLcStateProdEnd:
HARDENED_CHECK_EQ(lc_state, kLcStateProdEnd);
enable = kHardenedBoolTrue;
break;
case kLcStateRma:
HARDENED_CHECK_EQ(lc_state, kLcStateRma);
enable = kHardenedBoolFalse;
break;
default:
HARDENED_UNREACHABLE();
}
uint32_t threshold =
otp_read32(OTP_CTRL_PARAM_ROM_WATCHDOG_BITE_THRESHOLD_CYCLES_OFFSET);
// Disable watchdog if `threshold` is less than minimum.
if (launder32(threshold) < kWatchdogMinThreshold) {
HARDENED_CHECK_LT(threshold, kWatchdogMinThreshold);
enable = kHardenedBoolFalse;
}
watchdog_configure(threshold, enable);
}
void watchdog_configure(uint32_t threshold, hardened_bool_t enable) {
SEC_MMIO_ASSERT_WRITE_INCREMENT(kWatchdogSecMmioConfigure, 4);
// Tell pwrmgr we want watchdog reset events to reset the chip.
sec_mmio_write32(
kPwrMgrBase + PWRMGR_RESET_EN_REG_OFFSET,
bitfield_bit32_write(
0, kTopEarlgreyPowerManagerResetRequestsAonTimerAonAonTimerRstReq,
true));
abs_mmio_write32(kPwrMgrBase + PWRMGR_CFG_CDC_SYNC_REG_OFFSET, 1);
// Set the watchdog bite and bark thresholds.
sec_mmio_write32(kBase + AON_TIMER_WDOG_CTRL_REG_OFFSET, kCtrlDisable);
abs_mmio_write32(kBase + AON_TIMER_WDOG_COUNT_REG_OFFSET, 0);
abs_mmio_write32(kBase + AON_TIMER_WDOG_BARK_THOLD_REG_OFFSET, UINT32_MAX);
sec_mmio_write32(kBase + AON_TIMER_WDOG_BITE_THOLD_REG_OFFSET, threshold);
// Enable or disable the watchdog as requested.
uint32_t ctrl = kCtrlEnable;
switch (launder32(enable)) {
case kHardenedBoolTrue:
HARDENED_CHECK_EQ(enable, kHardenedBoolTrue);
ctrl = kCtrlEnable;
break;
case kHardenedBoolFalse:
HARDENED_CHECK_EQ(enable, kHardenedBoolFalse);
ctrl = kCtrlDisable;
break;
default:
HARDENED_UNREACHABLE();
}
sec_mmio_write32(kBase + AON_TIMER_WDOG_CTRL_REG_OFFSET, ctrl);
// Redundantly re-request the pwrmgr configuration sync since it isn't
// possible to use sec_mmio for it.
abs_mmio_write32(kPwrMgrBase + PWRMGR_CFG_CDC_SYNC_REG_OFFSET, 1);
}
void watchdog_disable(void) {
SEC_MMIO_ASSERT_WRITE_INCREMENT(kWatchdogSecMmioDisable, 1);
sec_mmio_write32(kBase + AON_TIMER_WDOG_CTRL_REG_OFFSET, kCtrlDisable);
}
void watchdog_pet(void) {
abs_mmio_write32(kBase + AON_TIMER_WDOG_COUNT_REG_OFFSET, 0);
}
uint32_t watchdog_get(void) {
return abs_mmio_read32(kBase + AON_TIMER_WDOG_COUNT_REG_OFFSET);
}