blob: e57409d352adc849788da8b5a35d17d4d1612196 [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_OWNER_SW_CFG_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((watchdog_config_t){
// 1.125 x bite_threshold
.bark_threshold = (9 * threshold) / 8,
.bite_threshold = threshold,
.enable = enable,
});
}
void watchdog_configure(watchdog_config_t config) {
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,
config.bark_threshold);
sec_mmio_write32(kBase + AON_TIMER_WDOG_BITE_THOLD_REG_OFFSET,
config.bite_threshold);
// Enable or disable the watchdog as requested.
uint32_t ctrl = kCtrlEnable;
switch (launder32(config.enable)) {
case kHardenedBoolTrue:
HARDENED_CHECK_EQ(config.enable, kHardenedBoolTrue);
ctrl = kCtrlEnable;
break;
case kHardenedBoolFalse:
HARDENED_CHECK_EQ(config.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);
}