1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#include "qemu/osdep.h"
30#include "qemu/log.h"
31#include "qemu/timer.h"
32#include "qapi/error.h"
33#include "trace.h"
34#include "hw/timer/sse-counter.h"
35#include "hw/sysbus.h"
36#include "hw/irq.h"
37#include "hw/registerfields.h"
38#include "hw/clock.h"
39#include "hw/qdev-clock.h"
40#include "migration/vmstate.h"
41
42
43REG32(CNTCR, 0x0)
44 FIELD(CNTCR, EN, 0, 1)
45 FIELD(CNTCR, HDBG, 1, 1)
46 FIELD(CNTCR, SCEN, 2, 1)
47 FIELD(CNTCR, INTRMASK, 3, 1)
48 FIELD(CNTCR, PSLVERRDIS, 4, 1)
49 FIELD(CNTCR, INTRCLR, 5, 1)
50
51
52
53
54
55#define CNTCR_VALID_MASK (R_CNTCR_EN_MASK | R_CNTCR_HDBG_MASK | \
56 R_CNTCR_SCEN_MASK | R_CNTCR_INTRMASK_MASK | \
57 R_CNTCR_PSLVERRDIS_MASK)
58REG32(CNTSR, 0x4)
59REG32(CNTCV_LO, 0x8)
60REG32(CNTCV_HI, 0xc)
61REG32(CNTSCR, 0x10)
62REG32(CNTID, 0x1c)
63 FIELD(CNTID, CNTSC, 0, 4)
64 FIELD(CNTID, CNTCS, 16, 1)
65 FIELD(CNTID, CNTSELCLK, 17, 2)
66 FIELD(CNTID, CNTSCR_OVR, 19, 1)
67REG32(CNTSCR0, 0xd0)
68REG32(CNTSCR1, 0xd4)
69
70
71REG32(STATUS_CNTCV_LO, 0x0)
72REG32(STATUS_CNTCV_HI, 0x4)
73
74
75REG32(PID4, 0xFD0)
76REG32(PID5, 0xFD4)
77REG32(PID6, 0xFD8)
78REG32(PID7, 0xFDC)
79REG32(PID0, 0xFE0)
80REG32(PID1, 0xFE4)
81REG32(PID2, 0xFE8)
82REG32(PID3, 0xFEC)
83REG32(CID0, 0xFF0)
84REG32(CID1, 0xFF4)
85REG32(CID2, 0xFF8)
86REG32(CID3, 0xFFC)
87
88
89static const int control_id[] = {
90 0x04, 0x00, 0x00, 0x00,
91 0xba, 0xb0, 0x0b, 0x00,
92 0x0d, 0xf0, 0x05, 0xb1,
93};
94
95static const int status_id[] = {
96 0x04, 0x00, 0x00, 0x00,
97 0xbb, 0xb0, 0x0b, 0x00,
98 0x0d, 0xf0, 0x05, 0xb1,
99};
100
101static void sse_counter_notify_users(SSECounter *s)
102{
103
104
105
106
107 notifier_list_notify(&s->notifier_list, NULL);
108}
109
110static bool sse_counter_enabled(SSECounter *s)
111{
112 return (s->cntcr & R_CNTCR_EN_MASK) != 0;
113}
114
115uint64_t sse_counter_tick_to_time(SSECounter *s, uint64_t tick)
116{
117 if (!sse_counter_enabled(s)) {
118 return UINT64_MAX;
119 }
120
121 tick -= s->ticks_then;
122
123 if (s->cntcr & R_CNTCR_SCEN_MASK) {
124
125 tick = muldiv64(tick, 0x01000000, s->cntscr0);
126 }
127
128 return s->ns_then + clock_ticks_to_ns(s->clk, tick);
129}
130
131void sse_counter_register_consumer(SSECounter *s, Notifier *notifier)
132{
133
134
135
136
137
138 notifier_list_add(&s->notifier_list, notifier);
139}
140
141uint64_t sse_counter_for_timestamp(SSECounter *s, uint64_t now)
142{
143
144 uint64_t ticks;
145
146 if (!sse_counter_enabled(s)) {
147
148 return s->ticks_then;
149 }
150
151 ticks = clock_ns_to_ticks(s->clk, now - s->ns_then);
152 if (s->cntcr & R_CNTCR_SCEN_MASK) {
153
154
155
156
157
158
159
160
161
162
163
164 ticks = muldiv64(ticks, s->cntscr0, 0x01000000);
165 }
166 return s->ticks_then + ticks;
167}
168
169static uint64_t sse_cntcv(SSECounter *s)
170{
171
172 return sse_counter_for_timestamp(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
173}
174
175static void sse_write_cntcv(SSECounter *s, uint32_t value, unsigned startbit)
176{
177
178
179
180
181 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
182 uint64_t cntcv = sse_counter_for_timestamp(s, now);
183
184 cntcv = deposit64(cntcv, startbit, 32, value);
185 s->ticks_then = cntcv;
186 s->ns_then = now;
187 sse_counter_notify_users(s);
188}
189
190static uint64_t sse_counter_control_read(void *opaque, hwaddr offset,
191 unsigned size)
192{
193 SSECounter *s = SSE_COUNTER(opaque);
194 uint64_t r;
195
196 switch (offset) {
197 case A_CNTCR:
198 r = s->cntcr;
199 break;
200 case A_CNTSR:
201
202
203
204
205
206 r = 0;
207 break;
208 case A_CNTCV_LO:
209 r = extract64(sse_cntcv(s), 0, 32);
210 break;
211 case A_CNTCV_HI:
212 r = extract64(sse_cntcv(s), 32, 32);
213 break;
214 case A_CNTID:
215
216
217
218
219
220
221 r = (1 << R_CNTID_CNTSELCLK_SHIFT) | (1 << R_CNTID_CNTSC_SHIFT);
222 break;
223 case A_CNTSCR:
224 case A_CNTSCR0:
225 r = s->cntscr0;
226 break;
227 case A_CNTSCR1:
228
229 r = 0;
230 break;
231 case A_PID4 ... A_CID3:
232 r = control_id[(offset - A_PID4) / 4];
233 break;
234 default:
235 qemu_log_mask(LOG_GUEST_ERROR,
236 "SSE System Counter control frame read: bad offset 0x%x",
237 (unsigned)offset);
238 r = 0;
239 break;
240 }
241
242 trace_sse_counter_control_read(offset, r, size);
243 return r;
244}
245
246static void sse_counter_control_write(void *opaque, hwaddr offset,
247 uint64_t value, unsigned size)
248{
249 SSECounter *s = SSE_COUNTER(opaque);
250
251 trace_sse_counter_control_write(offset, value, size);
252
253 switch (offset) {
254 case A_CNTCR:
255
256
257
258
259
260
261
262
263
264
265 value &= CNTCR_VALID_MASK;
266 if ((value ^ s->cntcr) & R_CNTCR_EN_MASK) {
267
268
269
270
271
272 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
273 s->ticks_then = sse_counter_for_timestamp(s, now);
274 s->ns_then = now;
275 sse_counter_notify_users(s);
276 }
277 s->cntcr = value;
278 break;
279 case A_CNTCV_LO:
280 sse_write_cntcv(s, value, 0);
281 break;
282 case A_CNTCV_HI:
283 sse_write_cntcv(s, value, 32);
284 break;
285 case A_CNTSCR:
286 case A_CNTSCR0:
287
288
289
290
291
292 s->cntscr0 = value;
293 break;
294 case A_CNTSCR1:
295
296 break;
297 case A_CNTSR:
298 case A_CNTID:
299 case A_PID4 ... A_CID3:
300 qemu_log_mask(LOG_GUEST_ERROR,
301 "SSE System Counter control frame: write to RO offset 0x%x\n",
302 (unsigned)offset);
303 break;
304 default:
305 qemu_log_mask(LOG_GUEST_ERROR,
306 "SSE System Counter control frame: write to bad offset 0x%x\n",
307 (unsigned)offset);
308 break;
309 }
310}
311
312static uint64_t sse_counter_status_read(void *opaque, hwaddr offset,
313 unsigned size)
314{
315 SSECounter *s = SSE_COUNTER(opaque);
316 uint64_t r;
317
318 switch (offset) {
319 case A_STATUS_CNTCV_LO:
320 r = extract64(sse_cntcv(s), 0, 32);
321 break;
322 case A_STATUS_CNTCV_HI:
323 r = extract64(sse_cntcv(s), 32, 32);
324 break;
325 case A_PID4 ... A_CID3:
326 r = status_id[(offset - A_PID4) / 4];
327 break;
328 default:
329 qemu_log_mask(LOG_GUEST_ERROR,
330 "SSE System Counter status frame read: bad offset 0x%x",
331 (unsigned)offset);
332 r = 0;
333 break;
334 }
335
336 trace_sse_counter_status_read(offset, r, size);
337 return r;
338}
339
340static void sse_counter_status_write(void *opaque, hwaddr offset,
341 uint64_t value, unsigned size)
342{
343 trace_sse_counter_status_write(offset, value, size);
344
345 switch (offset) {
346 case A_STATUS_CNTCV_LO:
347 case A_STATUS_CNTCV_HI:
348 case A_PID4 ... A_CID3:
349 qemu_log_mask(LOG_GUEST_ERROR,
350 "SSE System Counter status frame: write to RO offset 0x%x\n",
351 (unsigned)offset);
352 break;
353 default:
354 qemu_log_mask(LOG_GUEST_ERROR,
355 "SSE System Counter status frame: write to bad offset 0x%x\n",
356 (unsigned)offset);
357 break;
358 }
359}
360
361static const MemoryRegionOps sse_counter_control_ops = {
362 .read = sse_counter_control_read,
363 .write = sse_counter_control_write,
364 .endianness = DEVICE_LITTLE_ENDIAN,
365 .valid.min_access_size = 4,
366 .valid.max_access_size = 4,
367};
368
369static const MemoryRegionOps sse_counter_status_ops = {
370 .read = sse_counter_status_read,
371 .write = sse_counter_status_write,
372 .endianness = DEVICE_LITTLE_ENDIAN,
373 .valid.min_access_size = 4,
374 .valid.max_access_size = 4,
375};
376
377static void sse_counter_reset(DeviceState *dev)
378{
379 SSECounter *s = SSE_COUNTER(dev);
380
381 trace_sse_counter_reset();
382
383 s->cntcr = 0;
384 s->cntscr0 = 0x01000000;
385 s->ns_then = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
386 s->ticks_then = 0;
387}
388
389static void sse_clk_callback(void *opaque, ClockEvent event)
390{
391 SSECounter *s = SSE_COUNTER(opaque);
392 uint64_t now;
393
394 switch (event) {
395 case ClockPreUpdate:
396
397
398
399
400
401 if (sse_counter_enabled(s)) {
402 now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
403 s->ticks_then = sse_counter_for_timestamp(s, now);
404 s->ns_then = now;
405 }
406 break;
407 case ClockUpdate:
408 sse_counter_notify_users(s);
409 break;
410 default:
411 break;
412 }
413}
414
415static void sse_counter_init(Object *obj)
416{
417 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
418 SSECounter *s = SSE_COUNTER(obj);
419
420 notifier_list_init(&s->notifier_list);
421
422 s->clk = qdev_init_clock_in(DEVICE(obj), "CLK", sse_clk_callback, s,
423 ClockPreUpdate | ClockUpdate);
424 memory_region_init_io(&s->control_mr, obj, &sse_counter_control_ops,
425 s, "sse-counter-control", 0x1000);
426 memory_region_init_io(&s->status_mr, obj, &sse_counter_status_ops,
427 s, "sse-counter-status", 0x1000);
428 sysbus_init_mmio(sbd, &s->control_mr);
429 sysbus_init_mmio(sbd, &s->status_mr);
430}
431
432static void sse_counter_realize(DeviceState *dev, Error **errp)
433{
434 SSECounter *s = SSE_COUNTER(dev);
435
436 if (!clock_has_source(s->clk)) {
437 error_setg(errp, "SSE system counter: CLK must be connected");
438 return;
439 }
440}
441
442static const VMStateDescription sse_counter_vmstate = {
443 .name = "sse-counter",
444 .version_id = 1,
445 .minimum_version_id = 1,
446 .fields = (VMStateField[]) {
447 VMSTATE_CLOCK(clk, SSECounter),
448 VMSTATE_END_OF_LIST()
449 }
450};
451
452static void sse_counter_class_init(ObjectClass *klass, void *data)
453{
454 DeviceClass *dc = DEVICE_CLASS(klass);
455
456 dc->realize = sse_counter_realize;
457 dc->vmsd = &sse_counter_vmstate;
458 dc->reset = sse_counter_reset;
459}
460
461static const TypeInfo sse_counter_info = {
462 .name = TYPE_SSE_COUNTER,
463 .parent = TYPE_SYS_BUS_DEVICE,
464 .instance_size = sizeof(SSECounter),
465 .instance_init = sse_counter_init,
466 .class_init = sse_counter_class_init,
467};
468
469static void sse_counter_register_types(void)
470{
471 type_register_static(&sse_counter_info);
472}
473
474type_init(sse_counter_register_types);
475