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