xref: /openbmc/qemu/hw/timer/sse-counter.c (revision 6c769690)
1*0d10df30SPeter Maydell /*
2*0d10df30SPeter Maydell  * Arm SSE Subsystem System Counter
3*0d10df30SPeter Maydell  *
4*0d10df30SPeter Maydell  * Copyright (c) 2020 Linaro Limited
5*0d10df30SPeter Maydell  * Written by Peter Maydell
6*0d10df30SPeter Maydell  *
7*0d10df30SPeter Maydell  * This program is free software; you can redistribute it and/or modify
8*0d10df30SPeter Maydell  * it under the terms of the GNU General Public License version 2 or
9*0d10df30SPeter Maydell  * (at your option) any later version.
10*0d10df30SPeter Maydell  */
11*0d10df30SPeter Maydell 
12*0d10df30SPeter Maydell /*
13*0d10df30SPeter Maydell  * This is a model of the "System counter" which is documented in
14*0d10df30SPeter Maydell  * the Arm SSE-123 Example Subsystem Technical Reference Manual:
15*0d10df30SPeter Maydell  * https://developer.arm.com/documentation/101370/latest/
16*0d10df30SPeter Maydell  *
17*0d10df30SPeter Maydell  * The system counter is a non-stop 64-bit up-counter. It provides
18*0d10df30SPeter Maydell  * this count value to other devices like the SSE system timer,
19*0d10df30SPeter Maydell  * which are driven by this system timestamp rather than directly
20*0d10df30SPeter Maydell  * from a clock. Internally to the counter the count is actually
21*0d10df30SPeter Maydell  * 88-bit precision (64.24 fixed point), with a programmable scale factor.
22*0d10df30SPeter Maydell  *
23*0d10df30SPeter Maydell  * The hardware has the optional feature that it supports dynamic
24*0d10df30SPeter Maydell  * clock switching, where two clock inputs are connected, and which
25*0d10df30SPeter Maydell  * one is used is selected via a CLKSEL input signal. Since the
26*0d10df30SPeter Maydell  * users of this device in QEMU don't use this feature, we only model
27*0d10df30SPeter Maydell  * the HWCLKSW=0 configuration.
28*0d10df30SPeter Maydell  */
29*0d10df30SPeter Maydell #include "qemu/osdep.h"
30*0d10df30SPeter Maydell #include "qemu/log.h"
31*0d10df30SPeter Maydell #include "qemu/timer.h"
32*0d10df30SPeter Maydell #include "qapi/error.h"
33*0d10df30SPeter Maydell #include "trace.h"
34*0d10df30SPeter Maydell #include "hw/timer/sse-counter.h"
35*0d10df30SPeter Maydell #include "hw/sysbus.h"
36*0d10df30SPeter Maydell #include "hw/registerfields.h"
37*0d10df30SPeter Maydell #include "hw/clock.h"
38*0d10df30SPeter Maydell #include "hw/qdev-clock.h"
39*0d10df30SPeter Maydell #include "migration/vmstate.h"
40*0d10df30SPeter Maydell 
41*0d10df30SPeter Maydell /* Registers in the control frame */
42*0d10df30SPeter Maydell REG32(CNTCR, 0x0)
43*0d10df30SPeter Maydell     FIELD(CNTCR, EN, 0, 1)
44*0d10df30SPeter Maydell     FIELD(CNTCR, HDBG, 1, 1)
45*0d10df30SPeter Maydell     FIELD(CNTCR, SCEN, 2, 1)
46*0d10df30SPeter Maydell     FIELD(CNTCR, INTRMASK, 3, 1)
47*0d10df30SPeter Maydell     FIELD(CNTCR, PSLVERRDIS, 4, 1)
48*0d10df30SPeter Maydell     FIELD(CNTCR, INTRCLR, 5, 1)
49*0d10df30SPeter Maydell /*
50*0d10df30SPeter Maydell  * Although CNTCR defines interrupt-related bits, the counter doesn't
51*0d10df30SPeter Maydell  * appear to actually have an interrupt output. So INTRCLR is
52*0d10df30SPeter Maydell  * effectively a RAZ/WI bit, as are the reserved bits [31:6].
53*0d10df30SPeter Maydell  */
54*0d10df30SPeter Maydell #define CNTCR_VALID_MASK (R_CNTCR_EN_MASK | R_CNTCR_HDBG_MASK | \
55*0d10df30SPeter Maydell                           R_CNTCR_SCEN_MASK | R_CNTCR_INTRMASK_MASK | \
56*0d10df30SPeter Maydell                           R_CNTCR_PSLVERRDIS_MASK)
57*0d10df30SPeter Maydell REG32(CNTSR, 0x4)
58*0d10df30SPeter Maydell REG32(CNTCV_LO, 0x8)
59*0d10df30SPeter Maydell REG32(CNTCV_HI, 0xc)
60*0d10df30SPeter Maydell REG32(CNTSCR, 0x10) /* Aliased with CNTSCR0 */
61*0d10df30SPeter Maydell REG32(CNTID, 0x1c)
62*0d10df30SPeter Maydell     FIELD(CNTID, CNTSC, 0, 4)
63*0d10df30SPeter Maydell     FIELD(CNTID, CNTCS, 16, 1)
64*0d10df30SPeter Maydell     FIELD(CNTID, CNTSELCLK, 17, 2)
65*0d10df30SPeter Maydell     FIELD(CNTID, CNTSCR_OVR, 19, 1)
66*0d10df30SPeter Maydell REG32(CNTSCR0, 0xd0)
67*0d10df30SPeter Maydell REG32(CNTSCR1, 0xd4)
68*0d10df30SPeter Maydell 
69*0d10df30SPeter Maydell /* Registers in the status frame */
70*0d10df30SPeter Maydell REG32(STATUS_CNTCV_LO, 0x0)
71*0d10df30SPeter Maydell REG32(STATUS_CNTCV_HI, 0x4)
72*0d10df30SPeter Maydell 
73*0d10df30SPeter Maydell /* Standard ID registers, present in both frames */
74*0d10df30SPeter Maydell REG32(PID4, 0xFD0)
75*0d10df30SPeter Maydell REG32(PID5, 0xFD4)
76*0d10df30SPeter Maydell REG32(PID6, 0xFD8)
77*0d10df30SPeter Maydell REG32(PID7, 0xFDC)
78*0d10df30SPeter Maydell REG32(PID0, 0xFE0)
79*0d10df30SPeter Maydell REG32(PID1, 0xFE4)
80*0d10df30SPeter Maydell REG32(PID2, 0xFE8)
81*0d10df30SPeter Maydell REG32(PID3, 0xFEC)
82*0d10df30SPeter Maydell REG32(CID0, 0xFF0)
83*0d10df30SPeter Maydell REG32(CID1, 0xFF4)
84*0d10df30SPeter Maydell REG32(CID2, 0xFF8)
85*0d10df30SPeter Maydell REG32(CID3, 0xFFC)
86*0d10df30SPeter Maydell 
87*0d10df30SPeter Maydell /* PID/CID values */
88*0d10df30SPeter Maydell static const int control_id[] = {
89*0d10df30SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
90*0d10df30SPeter Maydell     0xba, 0xb0, 0x0b, 0x00, /* PID0..PID3 */
91*0d10df30SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
92*0d10df30SPeter Maydell };
93*0d10df30SPeter Maydell 
94*0d10df30SPeter Maydell static const int status_id[] = {
95*0d10df30SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
96*0d10df30SPeter Maydell     0xbb, 0xb0, 0x0b, 0x00, /* PID0..PID3 */
97*0d10df30SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
98*0d10df30SPeter Maydell };
99*0d10df30SPeter Maydell 
sse_counter_notify_users(SSECounter * s)100*0d10df30SPeter Maydell static void sse_counter_notify_users(SSECounter *s)
101*0d10df30SPeter Maydell {
102*0d10df30SPeter Maydell     /*
103*0d10df30SPeter Maydell      * Notify users of the count timestamp that they may
104*0d10df30SPeter Maydell      * need to recalculate.
105*0d10df30SPeter Maydell      */
106*0d10df30SPeter Maydell     notifier_list_notify(&s->notifier_list, NULL);
107*0d10df30SPeter Maydell }
108*0d10df30SPeter Maydell 
sse_counter_enabled(SSECounter * s)109*0d10df30SPeter Maydell static bool sse_counter_enabled(SSECounter *s)
110*0d10df30SPeter Maydell {
111*0d10df30SPeter Maydell     return (s->cntcr & R_CNTCR_EN_MASK) != 0;
112*0d10df30SPeter Maydell }
113*0d10df30SPeter Maydell 
sse_counter_tick_to_time(SSECounter * s,uint64_t tick)114*0d10df30SPeter Maydell uint64_t sse_counter_tick_to_time(SSECounter *s, uint64_t tick)
115*0d10df30SPeter Maydell {
116*0d10df30SPeter Maydell     if (!sse_counter_enabled(s)) {
117*0d10df30SPeter Maydell         return UINT64_MAX;
118*0d10df30SPeter Maydell     }
119*0d10df30SPeter Maydell 
120*0d10df30SPeter Maydell     tick -= s->ticks_then;
121*0d10df30SPeter Maydell 
122*0d10df30SPeter Maydell     if (s->cntcr & R_CNTCR_SCEN_MASK) {
123*0d10df30SPeter Maydell         /* Adjust the tick count to account for the scale factor */
124*0d10df30SPeter Maydell         tick = muldiv64(tick, 0x01000000, s->cntscr0);
125*0d10df30SPeter Maydell     }
126*0d10df30SPeter Maydell 
127*0d10df30SPeter Maydell     return s->ns_then + clock_ticks_to_ns(s->clk, tick);
128*0d10df30SPeter Maydell }
129*0d10df30SPeter Maydell 
sse_counter_register_consumer(SSECounter * s,Notifier * notifier)130*0d10df30SPeter Maydell void sse_counter_register_consumer(SSECounter *s, Notifier *notifier)
131*0d10df30SPeter Maydell {
132*0d10df30SPeter Maydell     /*
133*0d10df30SPeter Maydell      * For the moment we assume that both we and the devices
134*0d10df30SPeter Maydell      * which consume us last for the life of the simulation,
135*0d10df30SPeter Maydell      * and so there is no mechanism for removing a notifier.
136*0d10df30SPeter Maydell      */
137*0d10df30SPeter Maydell     notifier_list_add(&s->notifier_list, notifier);
138*0d10df30SPeter Maydell }
139*0d10df30SPeter Maydell 
sse_counter_for_timestamp(SSECounter * s,uint64_t now)140*0d10df30SPeter Maydell uint64_t sse_counter_for_timestamp(SSECounter *s, uint64_t now)
141*0d10df30SPeter Maydell {
142*0d10df30SPeter Maydell     /* Return the CNTCV value for a particular timestamp (clock ns value). */
143*0d10df30SPeter Maydell     uint64_t ticks;
144*0d10df30SPeter Maydell 
145*0d10df30SPeter Maydell     if (!sse_counter_enabled(s)) {
146*0d10df30SPeter Maydell         /* Counter is disabled and does not increment */
147*0d10df30SPeter Maydell         return s->ticks_then;
148*0d10df30SPeter Maydell     }
149*0d10df30SPeter Maydell 
150*0d10df30SPeter Maydell     ticks = clock_ns_to_ticks(s->clk, now - s->ns_then);
151*0d10df30SPeter Maydell     if (s->cntcr & R_CNTCR_SCEN_MASK) {
152*0d10df30SPeter Maydell         /*
153*0d10df30SPeter Maydell          * Scaling is enabled. The CNTSCR value is the amount added to
154*0d10df30SPeter Maydell          * the underlying 88-bit counter for every tick of the
155*0d10df30SPeter Maydell          * underlying clock; CNTCV is the top 64 bits of that full
156*0d10df30SPeter Maydell          * 88-bit value. Multiplying the tick count by CNTSCR tells us
157*0d10df30SPeter Maydell          * how much the full 88-bit counter has moved on; we then
158*0d10df30SPeter Maydell          * divide that by 0x01000000 to find out how much the 64-bit
159*0d10df30SPeter Maydell          * visible portion has advanced. muldiv64() gives us the
160*0d10df30SPeter Maydell          * necessary at-least-88-bit precision for the intermediate
161*0d10df30SPeter Maydell          * result.
162*0d10df30SPeter Maydell          */
163*0d10df30SPeter Maydell         ticks = muldiv64(ticks, s->cntscr0, 0x01000000);
164*0d10df30SPeter Maydell     }
165*0d10df30SPeter Maydell     return s->ticks_then + ticks;
166*0d10df30SPeter Maydell }
167*0d10df30SPeter Maydell 
sse_cntcv(SSECounter * s)168*0d10df30SPeter Maydell static uint64_t sse_cntcv(SSECounter *s)
169*0d10df30SPeter Maydell {
170*0d10df30SPeter Maydell     /* Return the CNTCV value for the current time */
171*0d10df30SPeter Maydell     return sse_counter_for_timestamp(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
172*0d10df30SPeter Maydell }
173*0d10df30SPeter Maydell 
sse_write_cntcv(SSECounter * s,uint32_t value,unsigned startbit)174*0d10df30SPeter Maydell static void sse_write_cntcv(SSECounter *s, uint32_t value, unsigned startbit)
175*0d10df30SPeter Maydell {
176*0d10df30SPeter Maydell     /*
177*0d10df30SPeter Maydell      * Write one 32-bit half of the counter value; startbit is the
178*0d10df30SPeter Maydell      * bit position of this half in the 64-bit word, either 0 or 32.
179*0d10df30SPeter Maydell      */
180*0d10df30SPeter Maydell     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
181*0d10df30SPeter Maydell     uint64_t cntcv = sse_counter_for_timestamp(s, now);
182*0d10df30SPeter Maydell 
183*0d10df30SPeter Maydell     cntcv = deposit64(cntcv, startbit, 32, value);
184*0d10df30SPeter Maydell     s->ticks_then = cntcv;
185*0d10df30SPeter Maydell     s->ns_then = now;
186*0d10df30SPeter Maydell     sse_counter_notify_users(s);
187*0d10df30SPeter Maydell }
188*0d10df30SPeter Maydell 
sse_counter_control_read(void * opaque,hwaddr offset,unsigned size)189*0d10df30SPeter Maydell static uint64_t sse_counter_control_read(void *opaque, hwaddr offset,
190*0d10df30SPeter Maydell                                          unsigned size)
191*0d10df30SPeter Maydell {
192*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
193*0d10df30SPeter Maydell     uint64_t r;
194*0d10df30SPeter Maydell 
195*0d10df30SPeter Maydell     switch (offset) {
196*0d10df30SPeter Maydell     case A_CNTCR:
197*0d10df30SPeter Maydell         r = s->cntcr;
198*0d10df30SPeter Maydell         break;
199*0d10df30SPeter Maydell     case A_CNTSR:
200*0d10df30SPeter Maydell         /*
201*0d10df30SPeter Maydell          * The only bit here is DBGH, indicating that the counter has been
202*0d10df30SPeter Maydell          * halted via the Halt-on-Debug signal. We don't implement halting
203*0d10df30SPeter Maydell          * debug, so the whole register always reads as zero.
204*0d10df30SPeter Maydell          */
205*0d10df30SPeter Maydell         r = 0;
206*0d10df30SPeter Maydell         break;
207*0d10df30SPeter Maydell     case A_CNTCV_LO:
208*0d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 0, 32);
209*0d10df30SPeter Maydell         break;
210*0d10df30SPeter Maydell     case A_CNTCV_HI:
211*0d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 32, 32);
212*0d10df30SPeter Maydell         break;
213*0d10df30SPeter Maydell     case A_CNTID:
214*0d10df30SPeter Maydell         /*
215*0d10df30SPeter Maydell          * For our implementation:
216*0d10df30SPeter Maydell          *  - CNTSCR can only be written when CNTCR.EN == 0
217*0d10df30SPeter Maydell          *  - HWCLKSW=0, so selected clock is always CLK0
218*0d10df30SPeter Maydell          *  - counter scaling is implemented
219*0d10df30SPeter Maydell          */
220*0d10df30SPeter Maydell         r = (1 << R_CNTID_CNTSELCLK_SHIFT) | (1 << R_CNTID_CNTSC_SHIFT);
221*0d10df30SPeter Maydell         break;
222*0d10df30SPeter Maydell     case A_CNTSCR:
223*0d10df30SPeter Maydell     case A_CNTSCR0:
224*0d10df30SPeter Maydell         r = s->cntscr0;
225*0d10df30SPeter Maydell         break;
226*0d10df30SPeter Maydell     case A_CNTSCR1:
227*0d10df30SPeter Maydell         /* If HWCLKSW == 0, CNTSCR1 is RAZ/WI */
228*0d10df30SPeter Maydell         r = 0;
229*0d10df30SPeter Maydell         break;
230*0d10df30SPeter Maydell     case A_PID4 ... A_CID3:
231*0d10df30SPeter Maydell         r = control_id[(offset - A_PID4) / 4];
232*0d10df30SPeter Maydell         break;
233*0d10df30SPeter Maydell     default:
234*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
235*0d10df30SPeter Maydell                       "SSE System Counter control frame read: bad offset 0x%x",
236*0d10df30SPeter Maydell                       (unsigned)offset);
237*0d10df30SPeter Maydell         r = 0;
238*0d10df30SPeter Maydell         break;
239*0d10df30SPeter Maydell     }
240*0d10df30SPeter Maydell 
241*0d10df30SPeter Maydell     trace_sse_counter_control_read(offset, r, size);
242*0d10df30SPeter Maydell     return r;
243*0d10df30SPeter Maydell }
244*0d10df30SPeter Maydell 
sse_counter_control_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)245*0d10df30SPeter Maydell static void sse_counter_control_write(void *opaque, hwaddr offset,
246*0d10df30SPeter Maydell                                       uint64_t value, unsigned size)
247*0d10df30SPeter Maydell {
248*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
249*0d10df30SPeter Maydell 
250*0d10df30SPeter Maydell     trace_sse_counter_control_write(offset, value, size);
251*0d10df30SPeter Maydell 
252*0d10df30SPeter Maydell     switch (offset) {
253*0d10df30SPeter Maydell     case A_CNTCR:
254*0d10df30SPeter Maydell         /*
255*0d10df30SPeter Maydell          * Although CNTCR defines interrupt-related bits, the counter doesn't
256*0d10df30SPeter Maydell          * appear to actually have an interrupt output. So INTRCLR is
257*0d10df30SPeter Maydell          * effectively a RAZ/WI bit, as are the reserved bits [31:6].
258*0d10df30SPeter Maydell          * The documentation does not explicitly say so, but we assume
259*0d10df30SPeter Maydell          * that changing the scale factor while the counter is enabled
260*0d10df30SPeter Maydell          * by toggling CNTCR.SCEN has the same behaviour (making the counter
261*0d10df30SPeter Maydell          * value UNKNOWN) as changing it by writing to CNTSCR, and so we
262*0d10df30SPeter Maydell          * don't need to try to recalculate for that case.
263*0d10df30SPeter Maydell          */
264*0d10df30SPeter Maydell         value &= CNTCR_VALID_MASK;
265*0d10df30SPeter Maydell         if ((value ^ s->cntcr) & R_CNTCR_EN_MASK) {
266*0d10df30SPeter Maydell             /*
267*0d10df30SPeter Maydell              * Whether the counter is being enabled or disabled, the
268*0d10df30SPeter Maydell              * required action is the same: sync the (ns_then, ticks_then)
269*0d10df30SPeter Maydell              * tuple.
270*0d10df30SPeter Maydell              */
271*0d10df30SPeter Maydell             uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
272*0d10df30SPeter Maydell             s->ticks_then = sse_counter_for_timestamp(s, now);
273*0d10df30SPeter Maydell             s->ns_then = now;
274*0d10df30SPeter Maydell             sse_counter_notify_users(s);
275*0d10df30SPeter Maydell         }
276*0d10df30SPeter Maydell         s->cntcr = value;
277*0d10df30SPeter Maydell         break;
278*0d10df30SPeter Maydell     case A_CNTCV_LO:
279*0d10df30SPeter Maydell         sse_write_cntcv(s, value, 0);
280*0d10df30SPeter Maydell         break;
281*0d10df30SPeter Maydell     case A_CNTCV_HI:
282*0d10df30SPeter Maydell         sse_write_cntcv(s, value, 32);
283*0d10df30SPeter Maydell         break;
284*0d10df30SPeter Maydell     case A_CNTSCR:
285*0d10df30SPeter Maydell     case A_CNTSCR0:
286*0d10df30SPeter Maydell         /*
287*0d10df30SPeter Maydell          * If the scale registers are changed when the counter is enabled,
288*0d10df30SPeter Maydell          * the count value becomes UNKNOWN. So we don't try to recalculate
289*0d10df30SPeter Maydell          * anything here but only do it on a write to CNTCR.EN.
290*0d10df30SPeter Maydell          */
291*0d10df30SPeter Maydell         s->cntscr0 = value;
292*0d10df30SPeter Maydell         break;
293*0d10df30SPeter Maydell     case A_CNTSCR1:
294*0d10df30SPeter Maydell         /* If HWCLKSW == 0, CNTSCR1 is RAZ/WI */
295*0d10df30SPeter Maydell         break;
296*0d10df30SPeter Maydell     case A_CNTSR:
297*0d10df30SPeter Maydell     case A_CNTID:
298*0d10df30SPeter Maydell     case A_PID4 ... A_CID3:
299*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
300*0d10df30SPeter Maydell                       "SSE System Counter control frame: write to RO offset 0x%x\n",
301*0d10df30SPeter Maydell                       (unsigned)offset);
302*0d10df30SPeter Maydell         break;
303*0d10df30SPeter Maydell     default:
304*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
305*0d10df30SPeter Maydell                       "SSE System Counter control frame: write to bad offset 0x%x\n",
306*0d10df30SPeter Maydell                       (unsigned)offset);
307*0d10df30SPeter Maydell         break;
308*0d10df30SPeter Maydell     }
309*0d10df30SPeter Maydell }
310*0d10df30SPeter Maydell 
sse_counter_status_read(void * opaque,hwaddr offset,unsigned size)311*0d10df30SPeter Maydell static uint64_t sse_counter_status_read(void *opaque, hwaddr offset,
312*0d10df30SPeter Maydell                                         unsigned size)
313*0d10df30SPeter Maydell {
314*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
315*0d10df30SPeter Maydell     uint64_t r;
316*0d10df30SPeter Maydell 
317*0d10df30SPeter Maydell     switch (offset) {
318*0d10df30SPeter Maydell     case A_STATUS_CNTCV_LO:
319*0d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 0, 32);
320*0d10df30SPeter Maydell         break;
321*0d10df30SPeter Maydell     case A_STATUS_CNTCV_HI:
322*0d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 32, 32);
323*0d10df30SPeter Maydell         break;
324*0d10df30SPeter Maydell     case A_PID4 ... A_CID3:
325*0d10df30SPeter Maydell         r = status_id[(offset - A_PID4) / 4];
326*0d10df30SPeter Maydell         break;
327*0d10df30SPeter Maydell     default:
328*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
329*0d10df30SPeter Maydell                       "SSE System Counter status frame read: bad offset 0x%x",
330*0d10df30SPeter Maydell                       (unsigned)offset);
331*0d10df30SPeter Maydell         r = 0;
332*0d10df30SPeter Maydell         break;
333*0d10df30SPeter Maydell     }
334*0d10df30SPeter Maydell 
335*0d10df30SPeter Maydell     trace_sse_counter_status_read(offset, r, size);
336*0d10df30SPeter Maydell     return r;
337*0d10df30SPeter Maydell }
338*0d10df30SPeter Maydell 
sse_counter_status_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)339*0d10df30SPeter Maydell static void sse_counter_status_write(void *opaque, hwaddr offset,
340*0d10df30SPeter Maydell                                      uint64_t value, unsigned size)
341*0d10df30SPeter Maydell {
342*0d10df30SPeter Maydell     trace_sse_counter_status_write(offset, value, size);
343*0d10df30SPeter Maydell 
344*0d10df30SPeter Maydell     switch (offset) {
345*0d10df30SPeter Maydell     case A_STATUS_CNTCV_LO:
346*0d10df30SPeter Maydell     case A_STATUS_CNTCV_HI:
347*0d10df30SPeter Maydell     case A_PID4 ... A_CID3:
348*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
349*0d10df30SPeter Maydell                       "SSE System Counter status frame: write to RO offset 0x%x\n",
350*0d10df30SPeter Maydell                       (unsigned)offset);
351*0d10df30SPeter Maydell         break;
352*0d10df30SPeter Maydell     default:
353*0d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
354*0d10df30SPeter Maydell                       "SSE System Counter status frame: write to bad offset 0x%x\n",
355*0d10df30SPeter Maydell                       (unsigned)offset);
356*0d10df30SPeter Maydell         break;
357*0d10df30SPeter Maydell     }
358*0d10df30SPeter Maydell }
359*0d10df30SPeter Maydell 
360*0d10df30SPeter Maydell static const MemoryRegionOps sse_counter_control_ops = {
361*0d10df30SPeter Maydell     .read = sse_counter_control_read,
362*0d10df30SPeter Maydell     .write = sse_counter_control_write,
363*0d10df30SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
364*0d10df30SPeter Maydell     .valid.min_access_size = 4,
365*0d10df30SPeter Maydell     .valid.max_access_size = 4,
366*0d10df30SPeter Maydell };
367*0d10df30SPeter Maydell 
368*0d10df30SPeter Maydell static const MemoryRegionOps sse_counter_status_ops = {
369*0d10df30SPeter Maydell     .read = sse_counter_status_read,
370*0d10df30SPeter Maydell     .write = sse_counter_status_write,
371*0d10df30SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
372*0d10df30SPeter Maydell     .valid.min_access_size = 4,
373*0d10df30SPeter Maydell     .valid.max_access_size = 4,
374*0d10df30SPeter Maydell };
375*0d10df30SPeter Maydell 
sse_counter_reset(DeviceState * dev)376*0d10df30SPeter Maydell static void sse_counter_reset(DeviceState *dev)
377*0d10df30SPeter Maydell {
378*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(dev);
379*0d10df30SPeter Maydell 
380*0d10df30SPeter Maydell     trace_sse_counter_reset();
381*0d10df30SPeter Maydell 
382*0d10df30SPeter Maydell     s->cntcr = 0;
383*0d10df30SPeter Maydell     s->cntscr0 = 0x01000000;
384*0d10df30SPeter Maydell     s->ns_then = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
385*0d10df30SPeter Maydell     s->ticks_then = 0;
386*0d10df30SPeter Maydell }
387*0d10df30SPeter Maydell 
sse_clk_callback(void * opaque,ClockEvent event)388*0d10df30SPeter Maydell static void sse_clk_callback(void *opaque, ClockEvent event)
389*0d10df30SPeter Maydell {
390*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
391*0d10df30SPeter Maydell     uint64_t now;
392*0d10df30SPeter Maydell 
393*0d10df30SPeter Maydell     switch (event) {
394*0d10df30SPeter Maydell     case ClockPreUpdate:
395*0d10df30SPeter Maydell         /*
396*0d10df30SPeter Maydell          * Before the clock period updates, set (ticks_then, ns_then)
397*0d10df30SPeter Maydell          * to the current time and tick count (as calculated with
398*0d10df30SPeter Maydell          * the old clock period).
399*0d10df30SPeter Maydell          */
400*0d10df30SPeter Maydell         if (sse_counter_enabled(s)) {
401*0d10df30SPeter Maydell             now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
402*0d10df30SPeter Maydell             s->ticks_then = sse_counter_for_timestamp(s, now);
403*0d10df30SPeter Maydell             s->ns_then = now;
404*0d10df30SPeter Maydell         }
405*0d10df30SPeter Maydell         break;
406*0d10df30SPeter Maydell     case ClockUpdate:
407*0d10df30SPeter Maydell         sse_counter_notify_users(s);
408*0d10df30SPeter Maydell         break;
409*0d10df30SPeter Maydell     default:
410*0d10df30SPeter Maydell         break;
411*0d10df30SPeter Maydell     }
412*0d10df30SPeter Maydell }
413*0d10df30SPeter Maydell 
sse_counter_init(Object * obj)414*0d10df30SPeter Maydell static void sse_counter_init(Object *obj)
415*0d10df30SPeter Maydell {
416*0d10df30SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
417*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(obj);
418*0d10df30SPeter Maydell 
419*0d10df30SPeter Maydell     notifier_list_init(&s->notifier_list);
420*0d10df30SPeter Maydell 
421*0d10df30SPeter Maydell     s->clk = qdev_init_clock_in(DEVICE(obj), "CLK", sse_clk_callback, s,
422*0d10df30SPeter Maydell                                 ClockPreUpdate | ClockUpdate);
423*0d10df30SPeter Maydell     memory_region_init_io(&s->control_mr, obj, &sse_counter_control_ops,
424*0d10df30SPeter Maydell                           s, "sse-counter-control", 0x1000);
425*0d10df30SPeter Maydell     memory_region_init_io(&s->status_mr, obj, &sse_counter_status_ops,
426*0d10df30SPeter Maydell                           s, "sse-counter-status", 0x1000);
427*0d10df30SPeter Maydell     sysbus_init_mmio(sbd, &s->control_mr);
428*0d10df30SPeter Maydell     sysbus_init_mmio(sbd, &s->status_mr);
429*0d10df30SPeter Maydell }
430*0d10df30SPeter Maydell 
sse_counter_realize(DeviceState * dev,Error ** errp)431*0d10df30SPeter Maydell static void sse_counter_realize(DeviceState *dev, Error **errp)
432*0d10df30SPeter Maydell {
433*0d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(dev);
434*0d10df30SPeter Maydell 
435*0d10df30SPeter Maydell     if (!clock_has_source(s->clk)) {
436*0d10df30SPeter Maydell         error_setg(errp, "SSE system counter: CLK must be connected");
437*0d10df30SPeter Maydell         return;
438*0d10df30SPeter Maydell     }
439*0d10df30SPeter Maydell }
440*0d10df30SPeter Maydell 
441*0d10df30SPeter Maydell static const VMStateDescription sse_counter_vmstate = {
442*0d10df30SPeter Maydell     .name = "sse-counter",
443*0d10df30SPeter Maydell     .version_id = 1,
444*0d10df30SPeter Maydell     .minimum_version_id = 1,
445*0d10df30SPeter Maydell     .fields = (VMStateField[]) {
446*0d10df30SPeter Maydell         VMSTATE_CLOCK(clk, SSECounter),
447*0d10df30SPeter Maydell         VMSTATE_END_OF_LIST()
448*0d10df30SPeter Maydell     }
449*0d10df30SPeter Maydell };
450*0d10df30SPeter Maydell 
sse_counter_class_init(ObjectClass * klass,void * data)451*0d10df30SPeter Maydell static void sse_counter_class_init(ObjectClass *klass, void *data)
452*0d10df30SPeter Maydell {
453*0d10df30SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
454*0d10df30SPeter Maydell 
455*0d10df30SPeter Maydell     dc->realize = sse_counter_realize;
456*0d10df30SPeter Maydell     dc->vmsd = &sse_counter_vmstate;
457*0d10df30SPeter Maydell     dc->reset = sse_counter_reset;
458*0d10df30SPeter Maydell }
459*0d10df30SPeter Maydell 
460*0d10df30SPeter Maydell static const TypeInfo sse_counter_info = {
461*0d10df30SPeter Maydell     .name = TYPE_SSE_COUNTER,
462*0d10df30SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
463*0d10df30SPeter Maydell     .instance_size = sizeof(SSECounter),
464*0d10df30SPeter Maydell     .instance_init = sse_counter_init,
465*0d10df30SPeter Maydell     .class_init = sse_counter_class_init,
466*0d10df30SPeter Maydell };
467*0d10df30SPeter Maydell 
sse_counter_register_types(void)468*0d10df30SPeter Maydell static void sse_counter_register_types(void)
469*0d10df30SPeter Maydell {
470*0d10df30SPeter Maydell     type_register_static(&sse_counter_info);
471*0d10df30SPeter Maydell }
472*0d10df30SPeter Maydell 
473*0d10df30SPeter Maydell type_init(sse_counter_register_types);
474