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