| 1 | /* |
| 2 | * Arm SSE Subsystem System Counter |
| 3 | * |
| 4 | * Copyright (c) 2020 Linaro Limited |
| 5 | * Written by Peter Maydell |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License version 2 or |
| 9 | * (at your option) any later version. |
| 10 | */ |
| 11 | |
| 12 | /* |
| 13 | * This is a model of the "System counter" which is documented in |
| 14 | * the Arm SSE-123 Example Subsystem Technical Reference Manual: |
| 15 | * https://developer.arm.com/documentation/101370/latest/ |
| 16 | * |
| 17 | * QEMU interface: |
| 18 | * + Clock input "CLK": clock |
| 19 | * + sysbus MMIO region 0: the control register frame |
| 20 | * + sysbus MMIO region 1: the status register frame |
| 21 | * |
| 22 | * Consumers of the system counter's timestamp, such as the SSE |
| 23 | * System Timer device, can also use the APIs sse_counter_for_timestamp(), |
| 24 | * sse_counter_tick_to_time() and sse_counter_register_consumer() to |
| 25 | * interact with an instance of the System Counter. Generally the |
| 26 | * consumer device should have a QOM link property which the board |
| 27 | * code can set to the appropriate instance of the system counter. |
| 28 | */ |
| 29 | |
| 30 | #ifndef SSE_COUNTER_H |
| 31 | #define SSE_COUNTER_H |
| 32 | |
| 33 | #include "hw/core/sysbus.h" |
| 34 | #include "qom/object.h" |
| 35 | #include "qemu/notify.h" |
| 36 | |
| 37 | #define TYPE_SSE_COUNTER "sse-counter" |
| 38 | OBJECT_DECLARE_SIMPLE_TYPE(SSECounter, SSE_COUNTER) |
| 39 | |
| 40 | struct SSECounter { |
| 41 | /*< private >*/ |
| 42 | SysBusDevice parent_obj; |
| 43 | |
| 44 | /*< public >*/ |
| 45 | MemoryRegion control_mr; |
| 46 | MemoryRegion status_mr; |
| 47 | Clock *clk; |
| 48 | NotifierList notifier_list; |
| 49 | |
| 50 | uint32_t cntcr; |
| 51 | uint32_t cntscr0; |
| 52 | |
| 53 | /* |
| 54 | * These are used for handling clock frequency changes: they are a |
| 55 | * tuple of (QEMU_CLOCK_VIRTUAL timestamp, CNTCV at that time), |
| 56 | * taken when the clock frequency changes. sse_cntcv() needs them |
| 57 | * to calculate the current CNTCV. |
| 58 | */ |
| 59 | uint64_t ns_then; |
| 60 | uint64_t ticks_then; |
| 61 | }; |
| 62 | |
| 63 | /* |
| 64 | * These functions are the interface by which a consumer of |
| 65 | * the system timestamp (such as the SSE system timer device) |
| 66 | * can communicate with the SSECounter. |
| 67 | */ |
| 68 | |
| 69 | /** |
| 70 | * sse_counter_for_timestamp: |
| 71 | * @counter: SSECounter |
| 72 | * @ns: timestamp of QEMU_CLOCK_VIRTUAL in nanoseconds |
| 73 | * |
| 74 | * Returns the value of the timestamp counter at the specified |
| 75 | * point in time (assuming that no changes to scale factor, enable, etc |
| 76 | * happen in the meantime). |
| 77 | */ |
| 78 | uint64_t sse_counter_for_timestamp(SSECounter *counter, uint64_t ns); |
| 79 | |
| 80 | /** |
| 81 | * sse_counter_tick_to_time: |
| 82 | * @counter: SSECounter |
| 83 | * @tick: tick value |
| 84 | * |
| 85 | * Returns the time (a QEMU_CLOCK_VIRTUAL timestamp in nanoseconds) |
| 86 | * when the timestamp counter will reach the specified tick count. |
| 87 | * If the counter is not currently running, returns UINT64_MAX. |
| 88 | */ |
| 89 | uint64_t sse_counter_tick_to_time(SSECounter *counter, uint64_t tick); |
| 90 | |
| 91 | /** |
| 92 | * sse_counter_register_consumer: |
| 93 | * @counter: SSECounter |
| 94 | * @notifier: Notifier which is notified on counter changes |
| 95 | * |
| 96 | * Registers @notifier with the SSECounter. When the counter's |
| 97 | * configuration changes in a way that might invalidate information |
| 98 | * previously returned via sse_counter_for_timestamp() or |
| 99 | * sse_counter_tick_to_time(), the notifier will be called. |
| 100 | * Devices which consume the timestamp counter can use this as |
| 101 | * a cue to recalculate timer events. |
| 102 | */ |
| 103 | void sse_counter_register_consumer(SSECounter *counter, Notifier *notifier); |
| 104 | |
| 105 | #endif |