Skip to content

Commit 40b8b2f

Browse files
committed
[ot] hw/opentitan: ot_pwrmgr: implement initial support for clock domain crossing
Several register properties are not used as-is, as they drive features implemented in the slow clock domain, while the registers themselves are in the default, "fast" clock domain. It is required for the guest SW to write and poll the CFG_CDC_SYNC register to commit new settings to the slow clock domain. QEMU was not supporting this feature, the guest SW could then miss to synchronize these features. Application would have run fine on QEMU but not on the real HW. Note that the doc is out-of-date, and only the RTL can provide a list of the actual slow clock domain features gated by the CFG_CDC_DOMAIN. Also update the guest error message to give a hint when reset cannot be successfully enabled in this case. Signed-off-by: Emmanuel Blot <[email protected]>
1 parent 13fe1f3 commit 40b8b2f

File tree

2 files changed

+33
-4
lines changed

2 files changed

+33
-4
lines changed

hw/opentitan/ot_pwrmgr.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ REG32(FAULT_STATUS, 0x40u)
9292
FIELD(FAULT_STATUS, MAIN_PD_GLITCH, 2u, 1u)
9393
/* clang-format on */
9494

95+
#define CDC_SYNC_PULSE_DURATION_NS 1000u /* 1us */
9596

96-
#define CDC_SYNC_PULSE_DURATION_NS 100000u /* 100us */
9797
#define PWRMGR_WAKEUP_MAX ((unsigned)OT_PWRMGR_WAKEUP_COUNT)
9898
#define PWRMGR_RST_REQ_MAX 2u
9999

@@ -193,6 +193,15 @@ typedef struct {
193193
int req;
194194
} OtPwrMgrResetReq;
195195

196+
/*
197+
* Registers in the slow clock domain which get synchronized on CDC sync
198+
*/
199+
typedef struct {
200+
uint32_t reset_en;
201+
uint32_t wakeup_en;
202+
uint32_t control; /* for clock enablement */
203+
} OtPwrMgrSlowRegs;
204+
196205
typedef union {
197206
uint32_t bitmap;
198207
struct {
@@ -228,6 +237,7 @@ struct OtPwrMgrState {
228237
OtPwrMgrFastState f_state;
229238
OtPwrMgrSlowState s_state;
230239
OtPwrMgrEvents fsm_events;
240+
OtPwrMgrSlowRegs slow_regs;
231241

232242
uint32_t *regs;
233243
OtPwrMgrResetReq reset_request;
@@ -444,10 +454,21 @@ static void ot_pwrmgr_xschedule_fsm(OtPwrMgrState *s, const char *func,
444454
qemu_bh_schedule(s->fsm_tick_bh);
445455
}
446456

457+
static void ot_pwrmgr_sync_slow_regs(OtPwrMgrState *s)
458+
{
459+
s->slow_regs.reset_en = s->regs[R_RESET_EN];
460+
s->slow_regs.wakeup_en = s->regs[R_WAKEUP_EN];
461+
s->slow_regs.control = s->regs[R_CONTROL];
462+
}
463+
447464
static void ot_pwrmgr_cdc_sync(void *opaque)
448465
{
449466
OtPwrMgrState *s = opaque;
450467

468+
trace_ot_pwrmgr_cdc_sync(s->ot_id);
469+
470+
ot_pwrmgr_sync_slow_regs(s);
471+
451472
s->regs[R_CFG_CDC_SYNC] &= ~R_CFG_CDC_SYNC_SYNC_MASK;
452473
}
453474

@@ -523,10 +544,12 @@ static void ot_pwrmgr_rst_req(void *opaque, int irq, int level)
523544
uint32_t rstmask = PWRMGR_CONFIG[s->version].reset_mask;
524545

525546
/* if HW reset is maskable and not HW reset is not enabled */
526-
if ((rstbit & rstmask) && !(s->regs[R_RESET_EN] & rstbit)) {
547+
if ((rstbit & rstmask) && !(s->slow_regs.reset_en & rstbit)) {
548+
bool cdc_sync = s->slow_regs.reset_en == s->regs[R_RESET_EN];
527549
qemu_log_mask(LOG_GUEST_ERROR,
528-
"%s: HW reset #%u not enabled 0x%08x 0x%08x\n",
529-
__func__, src, s->regs[R_RESET_EN], rstbit);
550+
"%s: %s: HW reset #%u not enabled 0x%x 0x%x%s\n",
551+
__func__, s->ot_id, src, s->regs[R_RESET_EN], rstbit,
552+
cdc_sync ? "" : ": check CFG_CDC_SYNC");
530553
return;
531554
}
532555

@@ -897,6 +920,10 @@ static void ot_pwrmgr_regs_write(void *opaque, hwaddr addr, uint64_t val64,
897920
val32 &= R_CFG_CDC_SYNC_SYNC_MASK;
898921
s->regs[reg] |= val32; /* not described as RW1S, but looks like it */
899922
if (val32) {
923+
/*
924+
* schedule CDC synchronization;
925+
* SW guest should poll this register till it is released.
926+
*/
900927
timer_mod(s->cdc_sync, qemu_clock_get_ns(OT_VIRTUAL_CLOCK) +
901928
CDC_SYNC_PULSE_DURATION_NS);
902929
}
@@ -999,6 +1026,7 @@ static void ot_pwrmgr_reset_enter(Object *obj, ResetType type)
9991026
s->fsm_events.bitmap = 0;
10001027
s->fsm_events.holdon_fetch = s->fetch_ctrl;
10011028
s->boot_status.i32 = 0;
1029+
ot_pwrmgr_sync_slow_regs(s);
10021030

10031031
PWR_CHANGE_FAST_STATE(s, LOW_POWER);
10041032
PWR_CHANGE_SLOW_STATE(s, RESET);

hw/opentitan/trace-events

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ ot_plic_ext_io_alert_write(const char *id, uint32_t addr, const char *regname, u
463463

464464
# ot_pwrmgr.c
465465

466+
ot_pwrmgr_cdc_sync(const char *id) "%s"
466467
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]"
467468
ot_pwrmgr_clock_enable(const char *d, const char *clkname, bool enable) "%s: %s en:%u"
468469
ot_pwrmgr_escalate_rx(const char *id, bool level) "%s: level %u"

0 commit comments

Comments
 (0)