Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions hw/opentitan/ot_aon_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down
152 changes: 92 additions & 60 deletions hw/opentitan/ot_pwrmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -251,6 +237,7 @@ struct OtPwrMgrState {
OtPwrMgrFastState f_state;
OtPwrMgrSlowState s_state;
OtPwrMgrEvents fsm_events;
OtPwrMgrSlowRegs slow_regs;

uint32_t *regs;
OtPwrMgrResetReq reset_request;
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand All @@ -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",
Expand All @@ -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:
Expand Down Expand Up @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 3 additions & 1 deletion hw/opentitan/trace-events
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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"
Expand Down
Loading
Loading