xref: /qemu/hw/timer/sse-counter.c (revision ba324b3f)
10d10df30SPeter Maydell /*
20d10df30SPeter Maydell  * Arm SSE Subsystem System Counter
30d10df30SPeter Maydell  *
40d10df30SPeter Maydell  * Copyright (c) 2020 Linaro Limited
50d10df30SPeter Maydell  * Written by Peter Maydell
60d10df30SPeter Maydell  *
70d10df30SPeter Maydell  * This program is free software; you can redistribute it and/or modify
80d10df30SPeter Maydell  * it under the terms of the GNU General Public License version 2 or
90d10df30SPeter Maydell  * (at your option) any later version.
100d10df30SPeter Maydell  */
110d10df30SPeter Maydell 
120d10df30SPeter Maydell /*
130d10df30SPeter Maydell  * This is a model of the "System counter" which is documented in
140d10df30SPeter Maydell  * the Arm SSE-123 Example Subsystem Technical Reference Manual:
150d10df30SPeter Maydell  * https://developer.arm.com/documentation/101370/latest/
160d10df30SPeter Maydell  *
170d10df30SPeter Maydell  * The system counter is a non-stop 64-bit up-counter. It provides
180d10df30SPeter Maydell  * this count value to other devices like the SSE system timer,
190d10df30SPeter Maydell  * which are driven by this system timestamp rather than directly
200d10df30SPeter Maydell  * from a clock. Internally to the counter the count is actually
210d10df30SPeter Maydell  * 88-bit precision (64.24 fixed point), with a programmable scale factor.
220d10df30SPeter Maydell  *
230d10df30SPeter Maydell  * The hardware has the optional feature that it supports dynamic
240d10df30SPeter Maydell  * clock switching, where two clock inputs are connected, and which
250d10df30SPeter Maydell  * one is used is selected via a CLKSEL input signal. Since the
260d10df30SPeter Maydell  * users of this device in QEMU don't use this feature, we only model
270d10df30SPeter Maydell  * the HWCLKSW=0 configuration.
280d10df30SPeter Maydell  */
290d10df30SPeter Maydell #include "qemu/osdep.h"
300d10df30SPeter Maydell #include "qemu/log.h"
310d10df30SPeter Maydell #include "qemu/timer.h"
320d10df30SPeter Maydell #include "qapi/error.h"
330d10df30SPeter Maydell #include "trace.h"
340d10df30SPeter Maydell #include "hw/timer/sse-counter.h"
350d10df30SPeter Maydell #include "hw/sysbus.h"
360d10df30SPeter Maydell #include "hw/registerfields.h"
370d10df30SPeter Maydell #include "hw/clock.h"
380d10df30SPeter Maydell #include "hw/qdev-clock.h"
390d10df30SPeter Maydell #include "migration/vmstate.h"
400d10df30SPeter Maydell 
410d10df30SPeter Maydell /* Registers in the control frame */
420d10df30SPeter Maydell REG32(CNTCR, 0x0)
430d10df30SPeter Maydell     FIELD(CNTCR, EN, 0, 1)
440d10df30SPeter Maydell     FIELD(CNTCR, HDBG, 1, 1)
450d10df30SPeter Maydell     FIELD(CNTCR, SCEN, 2, 1)
460d10df30SPeter Maydell     FIELD(CNTCR, INTRMASK, 3, 1)
470d10df30SPeter Maydell     FIELD(CNTCR, PSLVERRDIS, 4, 1)
480d10df30SPeter Maydell     FIELD(CNTCR, INTRCLR, 5, 1)
490d10df30SPeter Maydell /*
500d10df30SPeter Maydell  * Although CNTCR defines interrupt-related bits, the counter doesn't
510d10df30SPeter Maydell  * appear to actually have an interrupt output. So INTRCLR is
520d10df30SPeter Maydell  * effectively a RAZ/WI bit, as are the reserved bits [31:6].
530d10df30SPeter Maydell  */
540d10df30SPeter Maydell #define CNTCR_VALID_MASK (R_CNTCR_EN_MASK | R_CNTCR_HDBG_MASK | \
550d10df30SPeter Maydell                           R_CNTCR_SCEN_MASK | R_CNTCR_INTRMASK_MASK | \
560d10df30SPeter Maydell                           R_CNTCR_PSLVERRDIS_MASK)
570d10df30SPeter Maydell REG32(CNTSR, 0x4)
580d10df30SPeter Maydell REG32(CNTCV_LO, 0x8)
590d10df30SPeter Maydell REG32(CNTCV_HI, 0xc)
600d10df30SPeter Maydell REG32(CNTSCR, 0x10) /* Aliased with CNTSCR0 */
610d10df30SPeter Maydell REG32(CNTID, 0x1c)
620d10df30SPeter Maydell     FIELD(CNTID, CNTSC, 0, 4)
630d10df30SPeter Maydell     FIELD(CNTID, CNTCS, 16, 1)
640d10df30SPeter Maydell     FIELD(CNTID, CNTSELCLK, 17, 2)
650d10df30SPeter Maydell     FIELD(CNTID, CNTSCR_OVR, 19, 1)
660d10df30SPeter Maydell REG32(CNTSCR0, 0xd0)
670d10df30SPeter Maydell REG32(CNTSCR1, 0xd4)
680d10df30SPeter Maydell 
690d10df30SPeter Maydell /* Registers in the status frame */
700d10df30SPeter Maydell REG32(STATUS_CNTCV_LO, 0x0)
710d10df30SPeter Maydell REG32(STATUS_CNTCV_HI, 0x4)
720d10df30SPeter Maydell 
730d10df30SPeter Maydell /* Standard ID registers, present in both frames */
740d10df30SPeter Maydell REG32(PID4, 0xFD0)
750d10df30SPeter Maydell REG32(PID5, 0xFD4)
760d10df30SPeter Maydell REG32(PID6, 0xFD8)
770d10df30SPeter Maydell REG32(PID7, 0xFDC)
780d10df30SPeter Maydell REG32(PID0, 0xFE0)
790d10df30SPeter Maydell REG32(PID1, 0xFE4)
800d10df30SPeter Maydell REG32(PID2, 0xFE8)
810d10df30SPeter Maydell REG32(PID3, 0xFEC)
820d10df30SPeter Maydell REG32(CID0, 0xFF0)
830d10df30SPeter Maydell REG32(CID1, 0xFF4)
840d10df30SPeter Maydell REG32(CID2, 0xFF8)
850d10df30SPeter Maydell REG32(CID3, 0xFFC)
860d10df30SPeter Maydell 
870d10df30SPeter Maydell /* PID/CID values */
880d10df30SPeter Maydell static const int control_id[] = {
890d10df30SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
900d10df30SPeter Maydell     0xba, 0xb0, 0x0b, 0x00, /* PID0..PID3 */
910d10df30SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
920d10df30SPeter Maydell };
930d10df30SPeter Maydell 
940d10df30SPeter Maydell static const int status_id[] = {
950d10df30SPeter Maydell     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
960d10df30SPeter Maydell     0xbb, 0xb0, 0x0b, 0x00, /* PID0..PID3 */
970d10df30SPeter Maydell     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
980d10df30SPeter Maydell };
990d10df30SPeter Maydell 
sse_counter_notify_users(SSECounter * s)1000d10df30SPeter Maydell static void sse_counter_notify_users(SSECounter *s)
1010d10df30SPeter Maydell {
1020d10df30SPeter Maydell     /*
1030d10df30SPeter Maydell      * Notify users of the count timestamp that they may
1040d10df30SPeter Maydell      * need to recalculate.
1050d10df30SPeter Maydell      */
1060d10df30SPeter Maydell     notifier_list_notify(&s->notifier_list, NULL);
1070d10df30SPeter Maydell }
1080d10df30SPeter Maydell 
sse_counter_enabled(SSECounter * s)1090d10df30SPeter Maydell static bool sse_counter_enabled(SSECounter *s)
1100d10df30SPeter Maydell {
1110d10df30SPeter Maydell     return (s->cntcr & R_CNTCR_EN_MASK) != 0;
1120d10df30SPeter Maydell }
1130d10df30SPeter Maydell 
sse_counter_tick_to_time(SSECounter * s,uint64_t tick)1140d10df30SPeter Maydell uint64_t sse_counter_tick_to_time(SSECounter *s, uint64_t tick)
1150d10df30SPeter Maydell {
1160d10df30SPeter Maydell     if (!sse_counter_enabled(s)) {
1170d10df30SPeter Maydell         return UINT64_MAX;
1180d10df30SPeter Maydell     }
1190d10df30SPeter Maydell 
1200d10df30SPeter Maydell     tick -= s->ticks_then;
1210d10df30SPeter Maydell 
1220d10df30SPeter Maydell     if (s->cntcr & R_CNTCR_SCEN_MASK) {
1230d10df30SPeter Maydell         /* Adjust the tick count to account for the scale factor */
1240d10df30SPeter Maydell         tick = muldiv64(tick, 0x01000000, s->cntscr0);
1250d10df30SPeter Maydell     }
1260d10df30SPeter Maydell 
1270d10df30SPeter Maydell     return s->ns_then + clock_ticks_to_ns(s->clk, tick);
1280d10df30SPeter Maydell }
1290d10df30SPeter Maydell 
sse_counter_register_consumer(SSECounter * s,Notifier * notifier)1300d10df30SPeter Maydell void sse_counter_register_consumer(SSECounter *s, Notifier *notifier)
1310d10df30SPeter Maydell {
1320d10df30SPeter Maydell     /*
1330d10df30SPeter Maydell      * For the moment we assume that both we and the devices
1340d10df30SPeter Maydell      * which consume us last for the life of the simulation,
1350d10df30SPeter Maydell      * and so there is no mechanism for removing a notifier.
1360d10df30SPeter Maydell      */
1370d10df30SPeter Maydell     notifier_list_add(&s->notifier_list, notifier);
1380d10df30SPeter Maydell }
1390d10df30SPeter Maydell 
sse_counter_for_timestamp(SSECounter * s,uint64_t now)1400d10df30SPeter Maydell uint64_t sse_counter_for_timestamp(SSECounter *s, uint64_t now)
1410d10df30SPeter Maydell {
1420d10df30SPeter Maydell     /* Return the CNTCV value for a particular timestamp (clock ns value). */
1430d10df30SPeter Maydell     uint64_t ticks;
1440d10df30SPeter Maydell 
1450d10df30SPeter Maydell     if (!sse_counter_enabled(s)) {
1460d10df30SPeter Maydell         /* Counter is disabled and does not increment */
1470d10df30SPeter Maydell         return s->ticks_then;
1480d10df30SPeter Maydell     }
1490d10df30SPeter Maydell 
1500d10df30SPeter Maydell     ticks = clock_ns_to_ticks(s->clk, now - s->ns_then);
1510d10df30SPeter Maydell     if (s->cntcr & R_CNTCR_SCEN_MASK) {
1520d10df30SPeter Maydell         /*
1530d10df30SPeter Maydell          * Scaling is enabled. The CNTSCR value is the amount added to
1540d10df30SPeter Maydell          * the underlying 88-bit counter for every tick of the
1550d10df30SPeter Maydell          * underlying clock; CNTCV is the top 64 bits of that full
1560d10df30SPeter Maydell          * 88-bit value. Multiplying the tick count by CNTSCR tells us
1570d10df30SPeter Maydell          * how much the full 88-bit counter has moved on; we then
1580d10df30SPeter Maydell          * divide that by 0x01000000 to find out how much the 64-bit
1590d10df30SPeter Maydell          * visible portion has advanced. muldiv64() gives us the
1600d10df30SPeter Maydell          * necessary at-least-88-bit precision for the intermediate
1610d10df30SPeter Maydell          * result.
1620d10df30SPeter Maydell          */
1630d10df30SPeter Maydell         ticks = muldiv64(ticks, s->cntscr0, 0x01000000);
1640d10df30SPeter Maydell     }
1650d10df30SPeter Maydell     return s->ticks_then + ticks;
1660d10df30SPeter Maydell }
1670d10df30SPeter Maydell 
sse_cntcv(SSECounter * s)1680d10df30SPeter Maydell static uint64_t sse_cntcv(SSECounter *s)
1690d10df30SPeter Maydell {
1700d10df30SPeter Maydell     /* Return the CNTCV value for the current time */
1710d10df30SPeter Maydell     return sse_counter_for_timestamp(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
1720d10df30SPeter Maydell }
1730d10df30SPeter Maydell 
sse_write_cntcv(SSECounter * s,uint32_t value,unsigned startbit)1740d10df30SPeter Maydell static void sse_write_cntcv(SSECounter *s, uint32_t value, unsigned startbit)
1750d10df30SPeter Maydell {
1760d10df30SPeter Maydell     /*
1770d10df30SPeter Maydell      * Write one 32-bit half of the counter value; startbit is the
1780d10df30SPeter Maydell      * bit position of this half in the 64-bit word, either 0 or 32.
1790d10df30SPeter Maydell      */
1800d10df30SPeter Maydell     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1810d10df30SPeter Maydell     uint64_t cntcv = sse_counter_for_timestamp(s, now);
1820d10df30SPeter Maydell 
1830d10df30SPeter Maydell     cntcv = deposit64(cntcv, startbit, 32, value);
1840d10df30SPeter Maydell     s->ticks_then = cntcv;
1850d10df30SPeter Maydell     s->ns_then = now;
1860d10df30SPeter Maydell     sse_counter_notify_users(s);
1870d10df30SPeter Maydell }
1880d10df30SPeter Maydell 
sse_counter_control_read(void * opaque,hwaddr offset,unsigned size)1890d10df30SPeter Maydell static uint64_t sse_counter_control_read(void *opaque, hwaddr offset,
1900d10df30SPeter Maydell                                          unsigned size)
1910d10df30SPeter Maydell {
1920d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
1930d10df30SPeter Maydell     uint64_t r;
1940d10df30SPeter Maydell 
1950d10df30SPeter Maydell     switch (offset) {
1960d10df30SPeter Maydell     case A_CNTCR:
1970d10df30SPeter Maydell         r = s->cntcr;
1980d10df30SPeter Maydell         break;
1990d10df30SPeter Maydell     case A_CNTSR:
2000d10df30SPeter Maydell         /*
2010d10df30SPeter Maydell          * The only bit here is DBGH, indicating that the counter has been
2020d10df30SPeter Maydell          * halted via the Halt-on-Debug signal. We don't implement halting
2030d10df30SPeter Maydell          * debug, so the whole register always reads as zero.
2040d10df30SPeter Maydell          */
2050d10df30SPeter Maydell         r = 0;
2060d10df30SPeter Maydell         break;
2070d10df30SPeter Maydell     case A_CNTCV_LO:
2080d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 0, 32);
2090d10df30SPeter Maydell         break;
2100d10df30SPeter Maydell     case A_CNTCV_HI:
2110d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 32, 32);
2120d10df30SPeter Maydell         break;
2130d10df30SPeter Maydell     case A_CNTID:
2140d10df30SPeter Maydell         /*
2150d10df30SPeter Maydell          * For our implementation:
2160d10df30SPeter Maydell          *  - CNTSCR can only be written when CNTCR.EN == 0
2170d10df30SPeter Maydell          *  - HWCLKSW=0, so selected clock is always CLK0
2180d10df30SPeter Maydell          *  - counter scaling is implemented
2190d10df30SPeter Maydell          */
2200d10df30SPeter Maydell         r = (1 << R_CNTID_CNTSELCLK_SHIFT) | (1 << R_CNTID_CNTSC_SHIFT);
2210d10df30SPeter Maydell         break;
2220d10df30SPeter Maydell     case A_CNTSCR:
2230d10df30SPeter Maydell     case A_CNTSCR0:
2240d10df30SPeter Maydell         r = s->cntscr0;
2250d10df30SPeter Maydell         break;
2260d10df30SPeter Maydell     case A_CNTSCR1:
2270d10df30SPeter Maydell         /* If HWCLKSW == 0, CNTSCR1 is RAZ/WI */
2280d10df30SPeter Maydell         r = 0;
2290d10df30SPeter Maydell         break;
2300d10df30SPeter Maydell     case A_PID4 ... A_CID3:
2310d10df30SPeter Maydell         r = control_id[(offset - A_PID4) / 4];
2320d10df30SPeter Maydell         break;
2330d10df30SPeter Maydell     default:
2340d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
2350d10df30SPeter Maydell                       "SSE System Counter control frame read: bad offset 0x%x",
2360d10df30SPeter Maydell                       (unsigned)offset);
2370d10df30SPeter Maydell         r = 0;
2380d10df30SPeter Maydell         break;
2390d10df30SPeter Maydell     }
2400d10df30SPeter Maydell 
2410d10df30SPeter Maydell     trace_sse_counter_control_read(offset, r, size);
2420d10df30SPeter Maydell     return r;
2430d10df30SPeter Maydell }
2440d10df30SPeter Maydell 
sse_counter_control_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)2450d10df30SPeter Maydell static void sse_counter_control_write(void *opaque, hwaddr offset,
2460d10df30SPeter Maydell                                       uint64_t value, unsigned size)
2470d10df30SPeter Maydell {
2480d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
2490d10df30SPeter Maydell 
2500d10df30SPeter Maydell     trace_sse_counter_control_write(offset, value, size);
2510d10df30SPeter Maydell 
2520d10df30SPeter Maydell     switch (offset) {
2530d10df30SPeter Maydell     case A_CNTCR:
2540d10df30SPeter Maydell         /*
2550d10df30SPeter Maydell          * Although CNTCR defines interrupt-related bits, the counter doesn't
2560d10df30SPeter Maydell          * appear to actually have an interrupt output. So INTRCLR is
2570d10df30SPeter Maydell          * effectively a RAZ/WI bit, as are the reserved bits [31:6].
2580d10df30SPeter Maydell          * The documentation does not explicitly say so, but we assume
2590d10df30SPeter Maydell          * that changing the scale factor while the counter is enabled
2600d10df30SPeter Maydell          * by toggling CNTCR.SCEN has the same behaviour (making the counter
2610d10df30SPeter Maydell          * value UNKNOWN) as changing it by writing to CNTSCR, and so we
2620d10df30SPeter Maydell          * don't need to try to recalculate for that case.
2630d10df30SPeter Maydell          */
2640d10df30SPeter Maydell         value &= CNTCR_VALID_MASK;
2650d10df30SPeter Maydell         if ((value ^ s->cntcr) & R_CNTCR_EN_MASK) {
2660d10df30SPeter Maydell             /*
2670d10df30SPeter Maydell              * Whether the counter is being enabled or disabled, the
2680d10df30SPeter Maydell              * required action is the same: sync the (ns_then, ticks_then)
2690d10df30SPeter Maydell              * tuple.
2700d10df30SPeter Maydell              */
2710d10df30SPeter Maydell             uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
2720d10df30SPeter Maydell             s->ticks_then = sse_counter_for_timestamp(s, now);
2730d10df30SPeter Maydell             s->ns_then = now;
2740d10df30SPeter Maydell             sse_counter_notify_users(s);
2750d10df30SPeter Maydell         }
2760d10df30SPeter Maydell         s->cntcr = value;
2770d10df30SPeter Maydell         break;
2780d10df30SPeter Maydell     case A_CNTCV_LO:
2790d10df30SPeter Maydell         sse_write_cntcv(s, value, 0);
2800d10df30SPeter Maydell         break;
2810d10df30SPeter Maydell     case A_CNTCV_HI:
2820d10df30SPeter Maydell         sse_write_cntcv(s, value, 32);
2830d10df30SPeter Maydell         break;
2840d10df30SPeter Maydell     case A_CNTSCR:
2850d10df30SPeter Maydell     case A_CNTSCR0:
2860d10df30SPeter Maydell         /*
2870d10df30SPeter Maydell          * If the scale registers are changed when the counter is enabled,
2880d10df30SPeter Maydell          * the count value becomes UNKNOWN. So we don't try to recalculate
2890d10df30SPeter Maydell          * anything here but only do it on a write to CNTCR.EN.
2900d10df30SPeter Maydell          */
2910d10df30SPeter Maydell         s->cntscr0 = value;
2920d10df30SPeter Maydell         break;
2930d10df30SPeter Maydell     case A_CNTSCR1:
2940d10df30SPeter Maydell         /* If HWCLKSW == 0, CNTSCR1 is RAZ/WI */
2950d10df30SPeter Maydell         break;
2960d10df30SPeter Maydell     case A_CNTSR:
2970d10df30SPeter Maydell     case A_CNTID:
2980d10df30SPeter Maydell     case A_PID4 ... A_CID3:
2990d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
3000d10df30SPeter Maydell                       "SSE System Counter control frame: write to RO offset 0x%x\n",
3010d10df30SPeter Maydell                       (unsigned)offset);
3020d10df30SPeter Maydell         break;
3030d10df30SPeter Maydell     default:
3040d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
3050d10df30SPeter Maydell                       "SSE System Counter control frame: write to bad offset 0x%x\n",
3060d10df30SPeter Maydell                       (unsigned)offset);
3070d10df30SPeter Maydell         break;
3080d10df30SPeter Maydell     }
3090d10df30SPeter Maydell }
3100d10df30SPeter Maydell 
sse_counter_status_read(void * opaque,hwaddr offset,unsigned size)3110d10df30SPeter Maydell static uint64_t sse_counter_status_read(void *opaque, hwaddr offset,
3120d10df30SPeter Maydell                                         unsigned size)
3130d10df30SPeter Maydell {
3140d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
3150d10df30SPeter Maydell     uint64_t r;
3160d10df30SPeter Maydell 
3170d10df30SPeter Maydell     switch (offset) {
3180d10df30SPeter Maydell     case A_STATUS_CNTCV_LO:
3190d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 0, 32);
3200d10df30SPeter Maydell         break;
3210d10df30SPeter Maydell     case A_STATUS_CNTCV_HI:
3220d10df30SPeter Maydell         r = extract64(sse_cntcv(s), 32, 32);
3230d10df30SPeter Maydell         break;
3240d10df30SPeter Maydell     case A_PID4 ... A_CID3:
3250d10df30SPeter Maydell         r = status_id[(offset - A_PID4) / 4];
3260d10df30SPeter Maydell         break;
3270d10df30SPeter Maydell     default:
3280d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
3290d10df30SPeter Maydell                       "SSE System Counter status frame read: bad offset 0x%x",
3300d10df30SPeter Maydell                       (unsigned)offset);
3310d10df30SPeter Maydell         r = 0;
3320d10df30SPeter Maydell         break;
3330d10df30SPeter Maydell     }
3340d10df30SPeter Maydell 
3350d10df30SPeter Maydell     trace_sse_counter_status_read(offset, r, size);
3360d10df30SPeter Maydell     return r;
3370d10df30SPeter Maydell }
3380d10df30SPeter Maydell 
sse_counter_status_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)3390d10df30SPeter Maydell static void sse_counter_status_write(void *opaque, hwaddr offset,
3400d10df30SPeter Maydell                                      uint64_t value, unsigned size)
3410d10df30SPeter Maydell {
3420d10df30SPeter Maydell     trace_sse_counter_status_write(offset, value, size);
3430d10df30SPeter Maydell 
3440d10df30SPeter Maydell     switch (offset) {
3450d10df30SPeter Maydell     case A_STATUS_CNTCV_LO:
3460d10df30SPeter Maydell     case A_STATUS_CNTCV_HI:
3470d10df30SPeter Maydell     case A_PID4 ... A_CID3:
3480d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
3490d10df30SPeter Maydell                       "SSE System Counter status frame: write to RO offset 0x%x\n",
3500d10df30SPeter Maydell                       (unsigned)offset);
3510d10df30SPeter Maydell         break;
3520d10df30SPeter Maydell     default:
3530d10df30SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
3540d10df30SPeter Maydell                       "SSE System Counter status frame: write to bad offset 0x%x\n",
3550d10df30SPeter Maydell                       (unsigned)offset);
3560d10df30SPeter Maydell         break;
3570d10df30SPeter Maydell     }
3580d10df30SPeter Maydell }
3590d10df30SPeter Maydell 
3600d10df30SPeter Maydell static const MemoryRegionOps sse_counter_control_ops = {
3610d10df30SPeter Maydell     .read = sse_counter_control_read,
3620d10df30SPeter Maydell     .write = sse_counter_control_write,
3630d10df30SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
3640d10df30SPeter Maydell     .valid.min_access_size = 4,
3650d10df30SPeter Maydell     .valid.max_access_size = 4,
3660d10df30SPeter Maydell };
3670d10df30SPeter Maydell 
3680d10df30SPeter Maydell static const MemoryRegionOps sse_counter_status_ops = {
3690d10df30SPeter Maydell     .read = sse_counter_status_read,
3700d10df30SPeter Maydell     .write = sse_counter_status_write,
3710d10df30SPeter Maydell     .endianness = DEVICE_LITTLE_ENDIAN,
3720d10df30SPeter Maydell     .valid.min_access_size = 4,
3730d10df30SPeter Maydell     .valid.max_access_size = 4,
3740d10df30SPeter Maydell };
3750d10df30SPeter Maydell 
sse_counter_reset(DeviceState * dev)3760d10df30SPeter Maydell static void sse_counter_reset(DeviceState *dev)
3770d10df30SPeter Maydell {
3780d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(dev);
3790d10df30SPeter Maydell 
3800d10df30SPeter Maydell     trace_sse_counter_reset();
3810d10df30SPeter Maydell 
3820d10df30SPeter Maydell     s->cntcr = 0;
3830d10df30SPeter Maydell     s->cntscr0 = 0x01000000;
3840d10df30SPeter Maydell     s->ns_then = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
3850d10df30SPeter Maydell     s->ticks_then = 0;
3860d10df30SPeter Maydell }
3870d10df30SPeter Maydell 
sse_clk_callback(void * opaque,ClockEvent event)3880d10df30SPeter Maydell static void sse_clk_callback(void *opaque, ClockEvent event)
3890d10df30SPeter Maydell {
3900d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(opaque);
3910d10df30SPeter Maydell     uint64_t now;
3920d10df30SPeter Maydell 
3930d10df30SPeter Maydell     switch (event) {
3940d10df30SPeter Maydell     case ClockPreUpdate:
3950d10df30SPeter Maydell         /*
3960d10df30SPeter Maydell          * Before the clock period updates, set (ticks_then, ns_then)
3970d10df30SPeter Maydell          * to the current time and tick count (as calculated with
3980d10df30SPeter Maydell          * the old clock period).
3990d10df30SPeter Maydell          */
4000d10df30SPeter Maydell         if (sse_counter_enabled(s)) {
4010d10df30SPeter Maydell             now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
4020d10df30SPeter Maydell             s->ticks_then = sse_counter_for_timestamp(s, now);
4030d10df30SPeter Maydell             s->ns_then = now;
4040d10df30SPeter Maydell         }
4050d10df30SPeter Maydell         break;
4060d10df30SPeter Maydell     case ClockUpdate:
4070d10df30SPeter Maydell         sse_counter_notify_users(s);
4080d10df30SPeter Maydell         break;
4090d10df30SPeter Maydell     default:
4100d10df30SPeter Maydell         break;
4110d10df30SPeter Maydell     }
4120d10df30SPeter Maydell }
4130d10df30SPeter Maydell 
sse_counter_init(Object * obj)4140d10df30SPeter Maydell static void sse_counter_init(Object *obj)
4150d10df30SPeter Maydell {
4160d10df30SPeter Maydell     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
4170d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(obj);
4180d10df30SPeter Maydell 
4190d10df30SPeter Maydell     notifier_list_init(&s->notifier_list);
4200d10df30SPeter Maydell 
4210d10df30SPeter Maydell     s->clk = qdev_init_clock_in(DEVICE(obj), "CLK", sse_clk_callback, s,
4220d10df30SPeter Maydell                                 ClockPreUpdate | ClockUpdate);
4230d10df30SPeter Maydell     memory_region_init_io(&s->control_mr, obj, &sse_counter_control_ops,
4240d10df30SPeter Maydell                           s, "sse-counter-control", 0x1000);
4250d10df30SPeter Maydell     memory_region_init_io(&s->status_mr, obj, &sse_counter_status_ops,
4260d10df30SPeter Maydell                           s, "sse-counter-status", 0x1000);
4270d10df30SPeter Maydell     sysbus_init_mmio(sbd, &s->control_mr);
4280d10df30SPeter Maydell     sysbus_init_mmio(sbd, &s->status_mr);
4290d10df30SPeter Maydell }
4300d10df30SPeter Maydell 
sse_counter_realize(DeviceState * dev,Error ** errp)4310d10df30SPeter Maydell static void sse_counter_realize(DeviceState *dev, Error **errp)
4320d10df30SPeter Maydell {
4330d10df30SPeter Maydell     SSECounter *s = SSE_COUNTER(dev);
4340d10df30SPeter Maydell 
4350d10df30SPeter Maydell     if (!clock_has_source(s->clk)) {
4360d10df30SPeter Maydell         error_setg(errp, "SSE system counter: CLK must be connected");
4370d10df30SPeter Maydell         return;
4380d10df30SPeter Maydell     }
4390d10df30SPeter Maydell }
4400d10df30SPeter Maydell 
4410d10df30SPeter Maydell static const VMStateDescription sse_counter_vmstate = {
4420d10df30SPeter Maydell     .name = "sse-counter",
4430d10df30SPeter Maydell     .version_id = 1,
4440d10df30SPeter Maydell     .minimum_version_id = 1,
445*ba324b3fSRichard Henderson     .fields = (const VMStateField[]) {
4460d10df30SPeter Maydell         VMSTATE_CLOCK(clk, SSECounter),
4470d10df30SPeter Maydell         VMSTATE_END_OF_LIST()
4480d10df30SPeter Maydell     }
4490d10df30SPeter Maydell };
4500d10df30SPeter Maydell 
sse_counter_class_init(ObjectClass * klass,void * data)4510d10df30SPeter Maydell static void sse_counter_class_init(ObjectClass *klass, void *data)
4520d10df30SPeter Maydell {
4530d10df30SPeter Maydell     DeviceClass *dc = DEVICE_CLASS(klass);
4540d10df30SPeter Maydell 
4550d10df30SPeter Maydell     dc->realize = sse_counter_realize;
4560d10df30SPeter Maydell     dc->vmsd = &sse_counter_vmstate;
4570d10df30SPeter Maydell     dc->reset = sse_counter_reset;
4580d10df30SPeter Maydell }
4590d10df30SPeter Maydell 
4600d10df30SPeter Maydell static const TypeInfo sse_counter_info = {
4610d10df30SPeter Maydell     .name = TYPE_SSE_COUNTER,
4620d10df30SPeter Maydell     .parent = TYPE_SYS_BUS_DEVICE,
4630d10df30SPeter Maydell     .instance_size = sizeof(SSECounter),
4640d10df30SPeter Maydell     .instance_init = sse_counter_init,
4650d10df30SPeter Maydell     .class_init = sse_counter_class_init,
4660d10df30SPeter Maydell };
4670d10df30SPeter Maydell 
sse_counter_register_types(void)4680d10df30SPeter Maydell static void sse_counter_register_types(void)
4690d10df30SPeter Maydell {
4700d10df30SPeter Maydell     type_register_static(&sse_counter_info);
4710d10df30SPeter Maydell }
4720d10df30SPeter Maydell 
4730d10df30SPeter Maydell type_init(sse_counter_register_types);
474