diff --git a/hw/opentitan/ot_aon_timer.c b/hw/opentitan/ot_aon_timer.c index 3e78bf502b13..3a9cc4257119 100644 --- a/hw/opentitan/ot_aon_timer.c +++ b/hw/opentitan/ot_aon_timer.c @@ -172,10 +172,10 @@ static uint64_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now) static uint32_t ot_aon_timer_get_wdog_count(OtAonTimerState *s, uint64_t now) { - return s->regs[R_WDOG_COUNT] + - (uint32_t) - ot_aon_timer_ns_to_ticks(s, 0u, - (int64_t)(now - s->wdog_origin_ns)); + int64_t delta = (int64_t)(now - s->wdog_origin_ns); + uint64_t ticks = ot_aon_timer_ns_to_ticks(s, 0u, delta); + + return s->regs[R_WDOG_COUNT] + (uint32_t)ticks; } static int64_t ot_aon_timer_compute_next_timeout(OtAonTimerState *s, @@ -577,6 +577,8 @@ static void ot_aon_timer_reset_enter(Object *obj, ResetType type) OtAonTimerClass *c = OT_AON_TIMER_GET_CLASS(obj); OtAonTimerState *s = OT_AON_TIMER(obj); + trace_ot_aon_timer_reset(s->ot_id, "enter"); + if (c->parent_phases.enter) { c->parent_phases.enter(obj, type); } diff --git a/hw/opentitan/ot_pwrmgr.c b/hw/opentitan/ot_pwrmgr.c index e26d9ca58e1c..a65e1b4fe875 100644 --- a/hw/opentitan/ot_pwrmgr.c +++ b/hw/opentitan/ot_pwrmgr.c @@ -45,13 +45,13 @@ #include "sysemu/runstate.h" #include "trace.h" -#define PARAM_NUM_RST_REQS 2u -#define PARAM_NUM_INT_RST_REQS 2u -#define PARAM_NUM_DEBUG_RST_REQS 1u -#define PARAM_RESET_MAIN_PWR_IDX 2u -#define PARAM_RESET_ESC_IDX 3u -#define PARAM_RESET_NDM_IDX 4u -#define PARAM_NUM_ALERTS 1u +#define NUM_INT_RST_REQS 2u +#define NUM_DEBUG_RST_REQS 1u +#define NUM_SW_RST_REQ 1u +#define NUM_ALERTS 1u +#define RESET_MAIN_PWR_IDX 2u +#define RESET_ESC_IDX 3u +#define RESET_NDM_IDX 4u /* clang-format off */ REG32(INTR_STATE, 0x0u) @@ -74,12 +74,7 @@ REG32(CFG_CDC_SYNC, 0x18u) REG32(WAKEUP_EN_REGWEN, 0x1cu) FIELD(WAKEUP_EN_REGWEN, EN, 0u, 1u) REG32(WAKEUP_EN, 0x20u) - SHARED_FIELD(WAKEUP_CHANNEL_0, 0u, 1u) - SHARED_FIELD(WAKEUP_CHANNEL_1, 1u, 1u) - SHARED_FIELD(WAKEUP_CHANNEL_2, 2u, 1u) - SHARED_FIELD(WAKEUP_CHANNEL_3, 3u, 1u) - SHARED_FIELD(WAKEUP_CHANNEL_4, 4u, 1u) - SHARED_FIELD(WAKEUP_CHANNEL_5, 5u, 1u) + /* note: wake up channel count depends on top */ REG32(WAKE_STATUS, 0x24u) REG32(RESET_EN_REGWEN, 0x28u) FIELD(RESET_EN_REGWEN, EN, 0u, 1u) @@ -90,39 +85,21 @@ REG32(ESCALATE_RESET_STATUS, 0x34u) REG32(WAKE_INFO_CAPTURE_DIS, 0x38u) FIELD(WAKE_INFO_CAPTURE_DIS, VAL, 0u, 1u) REG32(WAKE_INFO, 0x3cu) - FIELD(WAKE_INFO, REASONS, 0u, 6u) - FIELD(WAKE_INFO, FALL_THROUGH, 6u, 1u) - FIELD(WAKE_INFO, ABORT, 7u, 1u) + /* note: wake info fields depend on top */ REG32(FAULT_STATUS, 0x40u) FIELD(FAULT_STATUS, REG_INTG_ERR, 0u, 1u) FIELD(FAULT_STATUS, ESC_TIMEOUT, 1u, 1u) FIELD(FAULT_STATUS, MAIN_PD_GLITCH, 2u, 1u) /* clang-format on */ -#define CONTROL_MASK \ - (R_CONTROL_LOW_POWER_HINT_MASK | R_CONTROL_CORE_CLK_EN_MASK | \ - R_CONTROL_IO_CLK_EN_MASK | R_CONTROL_USB_CLK_EN_LP_MASK | \ - R_CONTROL_USB_CLK_EN_ACTIVE_MASK | R_CONTROL_MAIN_PD_N_MASK) -#define WAKEUP_MASK \ - (WAKEUP_CHANNEL_0_MASK | WAKEUP_CHANNEL_1_MASK | WAKEUP_CHANNEL_2_MASK | \ - WAKEUP_CHANNEL_3_MASK | WAKEUP_CHANNEL_4_MASK | WAKEUP_CHANNEL_5_MASK) -#define WAKE_INFO_MASK \ - (R_WAKE_INFO_REASONS_MASK | R_WAKE_INFO_FALL_THROUGH_MASK | \ - R_WAKE_INFO_ABORT_MASK) +#define CDC_SYNC_PULSE_DURATION_NS 1000u /* 1us */ -#define CDC_SYNC_PULSE_DURATION_NS 100000u /* 100us */ - -#define PWRMGR_WAKEUP_MAX 6u +#define PWRMGR_WAKEUP_MAX ((unsigned)OT_PWRMGR_WAKEUP_COUNT) +#define PWRMGR_RST_REQ_MAX 2u /* special exit error code to report escalation panic */ #define EXIT_ESCALATION_PANIC 39 -/* Verbatim definitions from RTL */ -#define NUM_SW_RST_REQ 1u -#define HW_RESET_WIDTH \ - (PARAM_NUM_RST_REQS + PARAM_NUM_INT_RST_REQS + PARAM_NUM_DEBUG_RST_REQS) -#define RESET_SW_REQ_IDX (HW_RESET_WIDTH) - #define R32_OFF(_r_) ((_r_) / sizeof(uint32_t)) #define R_LAST_REG (R_FAULT_STATUS) @@ -216,6 +193,15 @@ typedef struct { int req; } OtPwrMgrResetReq; +/* + * Registers in the slow clock domain which get synchronized on CDC sync + */ +typedef struct { + uint32_t reset_en; + uint32_t wakeup_en; + uint32_t control; /* for clock enablement */ +} OtPwrMgrSlowRegs; + typedef union { uint32_t bitmap; struct { @@ -251,6 +237,7 @@ struct OtPwrMgrState { OtPwrMgrFastState f_state; OtPwrMgrSlowState s_state; OtPwrMgrEvents fsm_events; + OtPwrMgrSlowRegs slow_regs; uint32_t *regs; OtPwrMgrResetReq reset_request; @@ -328,6 +315,8 @@ typedef struct { unsigned wakeup_count; unsigned reset_count; uint32_t reset_mask; + uint32_t control_mask; + uint32_t control_res_val; /* reset value for CONTROL regsisters */ } OtPwrMgrConfig; typedef struct { @@ -340,16 +329,36 @@ static const OtPwrMgrConfig PWRMGR_CONFIG[OT_PWRMGR_VERSION_COUNT] = { [OT_PWRMGR_VERSION_EG_1_0_0] = { .wakeup_count = 6u, .reset_count = 2u, - .reset_mask = 0x3u + .reset_mask = 0x3u, + .control_mask = 0x1f1u, + .control_res_val = 0x180u, /* MAIN_PD_N | USB_CLK_EN_ACTIVE */ }, [OT_PWRMGR_VERSION_DJ_PRE] = { - .wakeup_count = 6u, + .wakeup_count = 4u, .reset_count = 2u, - .reset_mask = 0x3u + .reset_mask = 0x3u, + .control_mask = 0x71u, + .control_res_val = 0x40u, /* MAIN_PD_N */ }, }; -static int PWRMGR_RESET_DISPATCH[OT_PWRMGR_VERSION_COUNT][PARAM_NUM_RST_REQS] = { +#define WAKE_INFO_REASONS_MASK(_s_) \ + ((1u << (PWRMGR_CONFIG[(_s_)->version].wakeup_count)) - 1u) +#define WAKE_INFO_FALL_THROUGH_MASK(_s_) \ + (1u << (PWRMGR_CONFIG[(_s_)->version].wakeup_count)) +#define WAKE_INFO_ABORT_MASK_MASK(_s_) \ + (1u << (PWRMGR_CONFIG[(_s_)->version].wakeup_count + 1u)) +#define WAKE_INFO_MASK(_s_) \ + ((1u << (PWRMGR_CONFIG[(_s_)->version].wakeup_count + 2u)) - 1u) +#define WAKEUP_MASK(_s_) WAKE_INFO_REASONS_MASK(_s_) +#define CONTROL_MASK(_s_) (PWRMGR_CONFIG[(_s_)->version].control_mask) +#define HW_RESET_WIDTH(_s_) \ + ((PWRMGR_CONFIG[(_s_)->version].wakeup_count) + \ + NUM_INT_RST_REQS + NUM_DEBUG_RST_REQS) +#define RESET_SW_REQ_IDX(_s_) HW_RESET_WIDTH(_s_) + +static int +PWRMGR_RESET_DISPATCH[OT_PWRMGR_VERSION_COUNT][PWRMGR_RST_REQ_MAX] = { [OT_PWRMGR_VERSION_EG_1_0_0] = { [0] = OT_RSTMGR_RESET_SYSCTRL, [1] = OT_RSTMGR_RESET_AON_TIMER, @@ -380,7 +389,8 @@ PWRMGR_WAKEUP_NAMES[OT_PWRMGR_VERSION_COUNT][PWRMGR_WAKEUP_MAX] = { }, }; -static const char *PWRMGR_RST_NAMES[OT_PWRMGR_VERSION_COUNT][PARAM_NUM_RST_REQS] = { +static const char * +PWRMGR_RST_NAMES[OT_PWRMGR_VERSION_COUNT][PWRMGR_RST_REQ_MAX] = { [OT_PWRMGR_VERSION_EG_1_0_0] = { [0] = "SYSRST", [1] = "AON_TIMER", @@ -444,10 +454,21 @@ static void ot_pwrmgr_xschedule_fsm(OtPwrMgrState *s, const char *func, qemu_bh_schedule(s->fsm_tick_bh); } +static void ot_pwrmgr_sync_slow_regs(OtPwrMgrState *s) +{ + s->slow_regs.reset_en = s->regs[R_RESET_EN]; + s->slow_regs.wakeup_en = s->regs[R_WAKEUP_EN]; + s->slow_regs.control = s->regs[R_CONTROL]; +} + static void ot_pwrmgr_cdc_sync(void *opaque) { OtPwrMgrState *s = opaque; + trace_ot_pwrmgr_cdc_sync(s->ot_id); + + ot_pwrmgr_sync_slow_regs(s); + s->regs[R_CFG_CDC_SYNC] &= ~R_CFG_CDC_SYNC_SYNC_MASK; } @@ -523,17 +544,19 @@ static void ot_pwrmgr_rst_req(void *opaque, int irq, int level) uint32_t rstmask = PWRMGR_CONFIG[s->version].reset_mask; /* if HW reset is maskable and not HW reset is not enabled */ - if ((rstbit & rstmask) && !(s->regs[R_RESET_EN] & rstbit)) { + if ((rstbit & rstmask) && !(s->slow_regs.reset_en & rstbit)) { + bool cdc_sync = s->slow_regs.reset_en == s->regs[R_RESET_EN]; qemu_log_mask(LOG_GUEST_ERROR, - "%s: HW reset #%u not enabled 0x%08x 0x%08x\n", - __func__, src, s->regs[R_RESET_EN], rstbit); + "%s: %s: HW reset #%u not enabled 0x%x 0x%x%s\n", + __func__, s->ot_id, src, s->regs[R_RESET_EN], rstbit, + cdc_sync ? "" : ": check CFG_CDC_SYNC"); return; } if (s->regs[R_RESET_STATUS]) { /* do nothing if a reset is already in progress */ /* TODO: is it true for HW vs. SW request ?*/ - trace_ot_pwrmgr_ignore_req("reset on-going"); + trace_ot_pwrmgr_ignore_req(s->ot_id, "reset on-going"); return; } s->regs[R_RESET_STATUS] |= rstbit; @@ -563,14 +586,14 @@ static void ot_pwrmgr_sw_rst_req(void *opaque, int irq, int level) unsigned src = (unsigned)irq; g_assert(src < NUM_SW_RST_REQ); - uint32_t rstbit = 1u << (RESET_SW_REQ_IDX + src); + uint32_t rstbit = 1u << (RESET_SW_REQ_IDX(s) + src); if (level) { trace_ot_pwrmgr_rst_req(s->ot_id, "SW", src); if (s->regs[R_RESET_STATUS]) { /* do nothing if a reset is already in progress */ - trace_ot_pwrmgr_ignore_req("reset on-going"); + trace_ot_pwrmgr_ignore_req(s->ot_id, "reset on-going"); return; } @@ -700,8 +723,9 @@ static void ot_pwrmgr_fast_fsm_tick(OtPwrMgrState *s) case OT_PWR_FAST_ST_NVM_IDLE_CHK: case OT_PWR_FAST_ST_LOW_POWER_PREP: case OT_PWR_FAST_ST_NVM_SHUT_DOWN: - qemu_log_mask(LOG_UNIMP, "%s: low power modes are not implemented\n", - __func__); + qemu_log_mask(LOG_UNIMP, + "%s: %s: low power modes are not implemented\n", __func__, + s->ot_id); /* fallthrough */ case OT_PWR_FAST_ST_RESET_PREP: PWR_CHANGE_FAST_STATE(s, RESET_WAIT); @@ -793,7 +817,8 @@ static void ot_pwrmgr_holdon_fetch(void *opaque, int n, int level) static void ot_pwrmgr_parse_clocks(OtPwrMgrState *s, Error **errp) { if (!s->cfg_clocks) { - error_setg(errp, "%s: clocks config not defined", __func__); + error_setg(errp, "%s: %s: clocks config not defined", __func__, + s->ot_id); return; } @@ -869,17 +894,17 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, pc); switch (reg) { case R_INTR_STATE: - val32 &= WAKEUP_MASK; + val32 &= WAKEUP_MASK(s); s->regs[R_INTR_STATE] &= ~val32; /* RW1C */ ot_pwrmgr_update_irq(s); break; case R_INTR_ENABLE: - val32 &= WAKEUP_MASK; + val32 &= WAKEUP_MASK(s); s->regs[R_INTR_ENABLE] = val32; ot_pwrmgr_update_irq(s); break; case R_INTR_TEST: - val32 &= WAKEUP_MASK; + val32 &= WAKEUP_MASK(s); s->regs[R_INTR_STATE] |= val32; ot_pwrmgr_update_irq(s); break; @@ -890,13 +915,17 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_CONTROL: /* TODO: clear LOW_POWER_HINT on next WFI? */ - val32 &= CONTROL_MASK; + val32 &= CONTROL_MASK(s); s->regs[reg] = val32; break; case R_CFG_CDC_SYNC: val32 &= R_CFG_CDC_SYNC_SYNC_MASK; s->regs[reg] |= val32; /* not described as RW1S, but looks like it */ if (val32) { + /* + * schedule CDC synchronization; + * SW guest should poll this register till it is released. + */ timer_mod(s->cdc_sync, qemu_clock_get_ns(OT_VIRTUAL_CLOCK) + CDC_SYNC_PULSE_DURATION_NS); } @@ -907,7 +936,7 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, break; case R_WAKEUP_EN: if (s->regs[R_WAKEUP_EN_REGWEN] & R_WAKEUP_EN_REGWEN_EN_MASK) { - val32 &= WAKEUP_MASK; + val32 &= WAKEUP_MASK(s); s->regs[reg] = val32; } else { qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: %s protected w/ REGWEN\n", @@ -932,7 +961,7 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64, s->regs[reg] = val32; break; case R_WAKE_INFO: - val32 &= WAKE_INFO_MASK; + val32 &= WAKE_INFO_MASK(s); s->regs[reg] &= ~val32; /* RW1C */ break; case R_CTRL_CFG_REGWEN: @@ -978,7 +1007,7 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) OtPwrMgrState *s = OT_PWRMGR(obj); /* sanity checks for platform reset count and mask */ - g_assert(PWRMGR_CONFIG[s->version].reset_count <= PARAM_NUM_RST_REQS); + g_assert(PWRMGR_CONFIG[s->version].reset_count <= PWRMGR_RST_REQ_MAX); g_assert(ctpop32(PWRMGR_CONFIG[s->version].reset_mask + 1u) == 1); g_assert(PWRMGR_CONFIG[s->version].reset_mask < (1u << PWRMGR_CONFIG[s->version].reset_count)); @@ -993,12 +1022,13 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type) memset(s->regs, 0, REGS_SIZE); s->regs[R_CTRL_CFG_REGWEN] = 0x1u; - s->regs[R_CONTROL] = 0x180u; + s->regs[R_CONTROL] = PWRMGR_CONFIG[s->version].control_res_val; s->regs[R_WAKEUP_EN_REGWEN] = 0x1u; s->regs[R_RESET_EN_REGWEN] = 0x1u; s->fsm_events.bitmap = 0; s->fsm_events.holdon_fetch = s->fetch_ctrl; s->boot_status.i32 = 0; + ot_pwrmgr_sync_slow_regs(s); PWR_CHANGE_FAST_STATE(s, LOW_POWER); PWR_CHANGE_SLOW_STATE(s, RESET); @@ -1039,9 +1069,13 @@ static void ot_pwrmgr_realize(DeviceState *dev, Error **errp) g_assert(s->clock_ctrl); OBJECT_CHECK(OtClockCtrlIf, s->clock_ctrl, TYPE_OT_CLOCK_CTRL_IF); + qdev_init_gpio_in_named(dev, &ot_pwrmgr_rst_req, OT_PWRMGR_RST, + (int)PWRMGR_CONFIG[s->version].reset_count); + if (s->num_rom) { if (s->num_rom > 8u * sizeof(uint8_t)) { - error_setg(&error_fatal, "too many ROMs\n"); + error_setg(&error_fatal, "%s: %s: too many ROMs\n", __func__, + s->ot_id); g_assert_not_reached(); } qdev_init_gpio_in_named(dev, &ot_pwrmgr_rom_good, OT_PWRMGR_ROM_GOOD, @@ -1080,8 +1114,6 @@ static void ot_pwrmgr_init(Object *obj) qdev_init_gpio_in_named(DEVICE(obj), &ot_pwrmgr_wkup, OT_PWRMGR_WKUP, PWRMGR_WAKEUP_MAX); - qdev_init_gpio_in_named(DEVICE(obj), &ot_pwrmgr_rst_req, OT_PWRMGR_RST, - PARAM_NUM_RST_REQS); qdev_init_gpio_in_named(DEVICE(obj), &ot_pwrmgr_sw_rst_req, OT_PWRMGR_SW_RST, NUM_SW_RST_REQ); qdev_init_gpio_in_named(DEVICE(obj), &ot_pwrmgr_pwr_lc_rsp, diff --git a/hw/opentitan/trace-events b/hw/opentitan/trace-events index d9bd013a01f5..16a0d9164020 100644 --- a/hw/opentitan/trace-events +++ b/hw/opentitan/trace-events @@ -37,6 +37,7 @@ ot_alert_skip_active(const char *id, char cls, const char *stname) "%s: class %c ot_aon_timer_irqs(const char *id, bool wakeup, bool bark, bool bite) "%s: wkup:%u bark:%u bite:%u" ot_aon_timer_io_read_out(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_aon_timer_io_write(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" +ot_aon_timer_reset(const char *id, const char *action) "%s: %s" ot_aon_timer_set_wdog(const char *id, int64_t now, int64_t next) "%s: now %" PRId64 ", next %" PRId64 ot_aon_timer_update_clock(const char *id, int tid, uint32_t frequency) "%s: [%d] @ %u Hz" @@ -462,11 +463,12 @@ ot_plic_ext_io_alert_write(const char *id, uint32_t addr, const char *regname, u # ot_pwrmgr.c +ot_pwrmgr_cdc_sync(const char *id) "%s" ot_pwrmgr_change_state(const char *id, int line, const char *type, const char *old, int nold, const char *new, int nnew) "%s @ %d %s: [%s:%d] -> [%s:%d]" ot_pwrmgr_clock_enable(const char *d, const char *clkname, bool enable) "%s: %s en:%u" ot_pwrmgr_escalate_rx(const char *id, bool level) "%s: level %u" ot_pwrmgr_go_idle(const char *id, const char *state) "%s: %s" -ot_pwrmgr_ignore_req(const char *reason) "%s" +ot_pwrmgr_ignore_req(const char *id, const char *reason) "%s: %s" ot_pwrmgr_io_read_out(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_pwrmgr_io_write(const char *id, uint32_t addr, const char * regname, uint32_t val, uint32_t pc) "%s: addr=0x%02x (%s), val=0x%x, pc=0x%x" ot_pwrmgr_reset(const char *id, const char *action) "%s: %s" diff --git a/include/hw/opentitan/ot_pwrmgr.h b/include/hw/opentitan/ot_pwrmgr.h index 8592b6503934..beeaa220c45a 100644 --- a/include/hw/opentitan/ot_pwrmgr.h +++ b/include/hw/opentitan/ot_pwrmgr.h @@ -41,7 +41,7 @@ typedef enum { OT_PWRMGR_VERSION_COUNT, } OtPwrMgrVersion; -/* Match PWRMGR_PARAM_*_WKUP_REQ_IDX definitions */ +/* Union of PWRMGR_PARAM_*_WKUP_REQ_IDX definitions for all supported tops */ typedef enum { OT_PWRMGR_WAKEUP_SYSRST, OT_PWRMGR_WAKEUP_ADC_CTRL,