Skip to content

Commit 609a103

Browse files
committed
[ot] hw/opentitan: ot_aon_timer: Make wakeup timer 64 bits
For earlgrey-1.0.0, OpenTitan's aon_timer has been updated so that it's wakeup timer is now a 64-bit counter rather than a 32-bit counter (whereas the watchdog timer remains 32-bit). This requires the implementation of register mapping changes with each wakeup count / threshold register now having a HI/LO counterpart. Signed-off-by: Alex Jones <alex.jones@lowrisc.org>
1 parent 3059172 commit 609a103

File tree

1 file changed

+54
-33
lines changed

1 file changed

+54
-33
lines changed

hw/opentitan/ot_aon_timer.c

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* QEMU OpenTitan AON Timer device
33
*
44
* Copyright (c) 2023-2024 Rivos, Inc.
5+
* Copyright (c) 2025 lowRISC contributors.
56
*
67
* Author(s):
78
* Loïc Lefort <loic@rivosinc.com>
@@ -47,21 +48,23 @@ REG32(ALERT_TEST, 0x00u)
4748
REG32(WKUP_CTRL, 0x04u)
4849
FIELD(WKUP_CTRL, ENABLE, 0u, 1u)
4950
FIELD(WKUP_CTRL, PRESCALER, 1u, 12u)
50-
REG32(WKUP_THOLD, 0x08)
51-
REG32(WKUP_COUNT, 0x0cu)
52-
REG32(WDOG_REGWEN, 0x10u)
51+
REG32(WKUP_THOLD_HI, 0x08u)
52+
REG32(WKUP_THOLD_LO, 0x0cu)
53+
REG32(WKUP_COUNT_HI, 0x10u)
54+
REG32(WKUP_COUNT_LO, 0x14u)
55+
REG32(WDOG_REGWEN, 0x18u)
5356
FIELD(WDOG_REGWEN, REGWEN, 0u, 1u)
54-
REG32(WDOG_CTRL, 0x14u)
57+
REG32(WDOG_CTRL, 0x1cu)
5558
FIELD(WDOG_CTRL, ENABLE, 0u, 1u)
56-
FIELD(WDOG_CTRL, PAUSE_IN_SLEEP, 0u, 1u)
57-
REG32(WDOG_BARK_THOLD, 0x18u)
58-
REG32(WDOG_BITE_THOLD, 0x1cu)
59-
REG32(WDOG_COUNT, 0x20u)
60-
REG32(INTR_STATE, 0x24u)
59+
FIELD(WDOG_CTRL, PAUSE_IN_SLEEP, 1u, 1u)
60+
REG32(WDOG_BARK_THOLD, 0x20u)
61+
REG32(WDOG_BITE_THOLD, 0x24u)
62+
REG32(WDOG_COUNT, 0x28u)
63+
REG32(INTR_STATE, 0x2cu)
6164
SHARED_FIELD(INTR_WKUP_TIMER_EXPIRED, 0u, 1u)
6265
SHARED_FIELD(INTR_WDOG_TIMER_BARK, 1u, 1u)
63-
REG32(INTR_TEST, 0x28u)
64-
REG32(WKUP_CAUSE, 0x2cu)
66+
REG32(INTR_TEST, 0x30u)
67+
REG32(WKUP_CAUSE, 0x34u)
6568
FIELD(WKUP_CAUSE, CAUSE, 0u, 1u)
6669
/* clang-format on */
6770

@@ -80,8 +83,10 @@ static const char REG_NAMES[REGS_COUNT][20u] = {
8083
/* clang-format off */
8184
REG_NAME_ENTRY(ALERT_TEST),
8285
REG_NAME_ENTRY(WKUP_CTRL),
83-
REG_NAME_ENTRY(WKUP_THOLD),
84-
REG_NAME_ENTRY(WKUP_COUNT),
86+
REG_NAME_ENTRY(WKUP_THOLD_HI),
87+
REG_NAME_ENTRY(WKUP_THOLD_LO),
88+
REG_NAME_ENTRY(WKUP_COUNT_HI),
89+
REG_NAME_ENTRY(WKUP_COUNT_LO),
8590
REG_NAME_ENTRY(WDOG_REGWEN),
8691
REG_NAME_ENTRY(WDOG_CTRL),
8792
REG_NAME_ENTRY(WDOG_BARK_THOLD),
@@ -119,36 +124,40 @@ struct OtAonTimerState {
119124
uint32_t pclk;
120125
};
121126

122-
static uint32_t
127+
static uint64_t
123128
ot_aon_timer_ns_to_ticks(OtAonTimerState *s, uint32_t prescaler, int64_t ns)
124129
{
125130
uint64_t ticks = muldiv64((uint64_t)ns, s->pclk, NANOSECONDS_PER_SECOND);
126-
return (uint32_t)(ticks / (prescaler + 1u));
131+
return ticks / (prescaler + 1u);
127132
}
128133

129134
static int64_t
130-
ot_aon_timer_ticks_to_ns(OtAonTimerState *s, uint32_t prescaler, uint32_t ticks)
135+
ot_aon_timer_ticks_to_ns(OtAonTimerState *s, uint32_t prescaler, uint64_t ticks)
131136
{
132-
uint64_t ns = muldiv64((uint64_t)ticks * (prescaler + 1u),
133-
NANOSECONDS_PER_SECOND, s->pclk);
137+
uint64_t ns =
138+
muldiv64(ticks * (prescaler + 1u), NANOSECONDS_PER_SECOND, s->pclk);
134139
if (ns > INT64_MAX) {
135140
return INT64_MAX;
136141
}
137142
return (int64_t)ns;
138143
}
139144

140-
static uint32_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now)
145+
static uint64_t ot_aon_timer_get_wkup_count(OtAonTimerState *s, uint64_t now)
141146
{
142147
uint32_t prescaler = FIELD_EX32(s->regs[R_WKUP_CTRL], WKUP_CTRL, PRESCALER);
143-
return s->regs[R_WKUP_COUNT] +
148+
uint64_t wkup_count =
149+
((uint64_t)s->regs[R_WKUP_COUNT_HI] << 32u) | s->regs[R_WKUP_COUNT_LO];
150+
return wkup_count +
144151
ot_aon_timer_ns_to_ticks(s, prescaler,
145152
(int64_t)(now - s->wkup_origin_ns));
146153
}
147154

148155
static uint32_t ot_aon_timer_get_wdog_count(OtAonTimerState *s, uint64_t now)
149156
{
150157
return s->regs[R_WDOG_COUNT] +
151-
ot_aon_timer_ns_to_ticks(s, 0u, (int64_t)(now - s->wdog_origin_ns));
158+
(uint32_t)
159+
ot_aon_timer_ns_to_ticks(s, 0u,
160+
(int64_t)(now - s->wdog_origin_ns));
152161
}
153162

154163
static int64_t ot_aon_timer_compute_next_timeout(OtAonTimerState *s,
@@ -192,7 +201,6 @@ static void ot_aon_timer_update_irqs(OtAonTimerState *s)
192201
{
193202
bool wkup = (bool)(s->regs[R_INTR_STATE] & INTR_WKUP_TIMER_EXPIRED_MASK);
194203
bool bark = (bool)(s->regs[R_INTR_STATE] & INTR_WDOG_TIMER_BARK_MASK);
195-
196204
trace_ot_aon_timer_irqs(s->ot_id, wkup, bark, s->wdog_bite);
197205

198206
ibex_irq_set(&s->irq_wkup, wkup);
@@ -218,8 +226,9 @@ static void ot_aon_timer_rearm_wkup(OtAonTimerState *s, bool reset_origin)
218226
return;
219227
}
220228

221-
uint32_t count = ot_aon_timer_get_wkup_count(s, now);
222-
uint32_t threshold = s->regs[R_WKUP_THOLD];
229+
uint64_t count = ot_aon_timer_get_wkup_count(s, now);
230+
uint64_t threshold =
231+
((uint64_t)s->regs[R_WKUP_THOLD_HI] << 32u) | s->regs[R_WKUP_THOLD_LO];
223232

224233
if (count >= threshold) {
225234
s->regs[R_INTR_STATE] |= INTR_WKUP_TIMER_EXPIRED_MASK;
@@ -309,7 +318,8 @@ static uint64_t ot_aon_timer_read(void *opaque, hwaddr addr, unsigned size)
309318
hwaddr reg = R32_OFF(addr);
310319
switch (reg) {
311320
case R_WKUP_CTRL:
312-
case R_WKUP_THOLD:
321+
case R_WKUP_THOLD_HI:
322+
case R_WKUP_THOLD_LO:
313323
case R_WDOG_REGWEN:
314324
case R_WDOG_CTRL:
315325
case R_WDOG_BARK_THOLD:
@@ -318,11 +328,18 @@ static uint64_t ot_aon_timer_read(void *opaque, hwaddr addr, unsigned size)
318328
case R_WKUP_CAUSE:
319329
val32 = s->regs[reg];
320330
break;
321-
case R_WKUP_COUNT: {
331+
case R_WKUP_COUNT_HI: {
332+
uint64_t now = ot_aon_timer_is_wkup_enabled(s) ?
333+
qemu_clock_get_ns(OT_VIRTUAL_CLOCK) :
334+
s->wkup_origin_ns;
335+
val32 = (uint32_t)(ot_aon_timer_get_wkup_count(s, now) >> 32u);
336+
break;
337+
}
338+
case R_WKUP_COUNT_LO: {
322339
uint64_t now = ot_aon_timer_is_wkup_enabled(s) ?
323340
qemu_clock_get_ns(OT_VIRTUAL_CLOCK) :
324341
s->wkup_origin_ns;
325-
val32 = ot_aon_timer_get_wkup_count(s, now);
342+
val32 = (uint32_t)ot_aon_timer_get_wkup_count(s, now);
326343
break;
327344
}
328345
case R_WDOG_COUNT: {
@@ -384,19 +401,23 @@ static void ot_aon_timer_write(void *opaque, hwaddr addr, uint64_t value,
384401
/* stop timer */
385402
timer_del(s->wkup_timer);
386403
/* save current count */
387-
uint32_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK);
388-
s->regs[R_WKUP_COUNT] = ot_aon_timer_get_wkup_count(s, now);
404+
int64_t now = qemu_clock_get_ns(OT_VIRTUAL_CLOCK);
405+
uint64_t count = ot_aon_timer_get_wkup_count(s, now);
406+
s->regs[R_WKUP_COUNT_HI] = (uint32_t)(count >> 32u);
407+
s->regs[R_WKUP_COUNT_LO] = (uint32_t)count;
389408
s->wkup_origin_ns = now;
390409
}
391410
}
392411
break;
393412
}
394-
case R_WKUP_THOLD:
395-
s->regs[R_WKUP_THOLD] = val32;
413+
case R_WKUP_THOLD_HI:
414+
case R_WKUP_THOLD_LO:
415+
s->regs[reg] = val32;
396416
ot_aon_timer_rearm_wkup(s, false);
397417
break;
398-
case R_WKUP_COUNT:
399-
s->regs[R_WKUP_COUNT] = val32;
418+
case R_WKUP_COUNT_HI:
419+
case R_WKUP_COUNT_LO:
420+
s->regs[reg] = val32;
400421
ot_aon_timer_rearm_wkup(s, true);
401422
break;
402423
case R_WDOG_REGWEN:

0 commit comments

Comments
 (0)