2
2
* QEMU OpenTitan AON Timer device
3
3
*
4
4
* Copyright (c) 2023-2024 Rivos, Inc.
5
+ * Copyright (c) 2025 lowRISC contributors.
5
6
*
6
7
* Author(s):
7
8
* Loïc Lefort <loic@rivosinc.com>
@@ -47,21 +48,23 @@ REG32(ALERT_TEST, 0x00u)
47
48
REG32 (WKUP_CTRL , 0x04u )
48
49
FIELD (WKUP_CTRL , ENABLE , 0u , 1u )
49
50
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 )
53
56
FIELD (WDOG_REGWEN , REGWEN , 0u , 1u )
54
- REG32 (WDOG_CTRL , 0x14u )
57
+ REG32 (WDOG_CTRL , 0x1cu )
55
58
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 )
61
64
SHARED_FIELD (INTR_WKUP_TIMER_EXPIRED , 0u , 1u )
62
65
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 )
65
68
FIELD (WKUP_CAUSE , CAUSE , 0u , 1u )
66
69
/* clang-format on */
67
70
@@ -80,8 +83,10 @@ static const char REG_NAMES[REGS_COUNT][20u] = {
80
83
/* clang-format off */
81
84
REG_NAME_ENTRY (ALERT_TEST ),
82
85
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 ),
85
90
REG_NAME_ENTRY (WDOG_REGWEN ),
86
91
REG_NAME_ENTRY (WDOG_CTRL ),
87
92
REG_NAME_ENTRY (WDOG_BARK_THOLD ),
@@ -119,36 +124,40 @@ struct OtAonTimerState {
119
124
uint32_t pclk ;
120
125
};
121
126
122
- static uint32_t
127
+ static uint64_t
123
128
ot_aon_timer_ns_to_ticks (OtAonTimerState * s , uint32_t prescaler , int64_t ns )
124
129
{
125
130
uint64_t ticks = muldiv64 ((uint64_t )ns , s -> pclk , NANOSECONDS_PER_SECOND );
126
- return ( uint32_t )( ticks / (prescaler + 1u ) );
131
+ return ticks / (prescaler + 1u );
127
132
}
128
133
129
134
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 )
131
136
{
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 );
134
139
if (ns > INT64_MAX ) {
135
140
return INT64_MAX ;
136
141
}
137
142
return (int64_t )ns ;
138
143
}
139
144
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 )
141
146
{
142
147
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 +
144
151
ot_aon_timer_ns_to_ticks (s , prescaler ,
145
152
(int64_t )(now - s -> wkup_origin_ns ));
146
153
}
147
154
148
155
static uint32_t ot_aon_timer_get_wdog_count (OtAonTimerState * s , uint64_t now )
149
156
{
150
157
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 ));
152
161
}
153
162
154
163
static int64_t ot_aon_timer_compute_next_timeout (OtAonTimerState * s ,
@@ -192,7 +201,6 @@ static void ot_aon_timer_update_irqs(OtAonTimerState *s)
192
201
{
193
202
bool wkup = (bool )(s -> regs [R_INTR_STATE ] & INTR_WKUP_TIMER_EXPIRED_MASK );
194
203
bool bark = (bool )(s -> regs [R_INTR_STATE ] & INTR_WDOG_TIMER_BARK_MASK );
195
-
196
204
trace_ot_aon_timer_irqs (s -> ot_id , wkup , bark , s -> wdog_bite );
197
205
198
206
ibex_irq_set (& s -> irq_wkup , wkup );
@@ -218,8 +226,9 @@ static void ot_aon_timer_rearm_wkup(OtAonTimerState *s, bool reset_origin)
218
226
return ;
219
227
}
220
228
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 ];
223
232
224
233
if (count >= threshold ) {
225
234
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)
309
318
hwaddr reg = R32_OFF (addr );
310
319
switch (reg ) {
311
320
case R_WKUP_CTRL :
312
- case R_WKUP_THOLD :
321
+ case R_WKUP_THOLD_HI :
322
+ case R_WKUP_THOLD_LO :
313
323
case R_WDOG_REGWEN :
314
324
case R_WDOG_CTRL :
315
325
case R_WDOG_BARK_THOLD :
@@ -318,11 +328,18 @@ static uint64_t ot_aon_timer_read(void *opaque, hwaddr addr, unsigned size)
318
328
case R_WKUP_CAUSE :
319
329
val32 = s -> regs [reg ];
320
330
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 : {
322
339
uint64_t now = ot_aon_timer_is_wkup_enabled (s ) ?
323
340
qemu_clock_get_ns (OT_VIRTUAL_CLOCK ) :
324
341
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 );
326
343
break ;
327
344
}
328
345
case R_WDOG_COUNT : {
@@ -384,19 +401,23 @@ static void ot_aon_timer_write(void *opaque, hwaddr addr, uint64_t value,
384
401
/* stop timer */
385
402
timer_del (s -> wkup_timer );
386
403
/* 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 ;
389
408
s -> wkup_origin_ns = now ;
390
409
}
391
410
}
392
411
break ;
393
412
}
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 ;
396
416
ot_aon_timer_rearm_wkup (s , false);
397
417
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 ;
400
421
ot_aon_timer_rearm_wkup (s , true);
401
422
break ;
402
423
case R_WDOG_REGWEN :
0 commit comments