/* * Arm SSE Subsystem System Counter * * Copyright (c) 2020 Linaro Limited * Written by Peter Maydell * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 or * (at your option) any later version. */ /* * This is a model of the "System counter" which is documented in * the Arm SSE-123 Example Subsystem Technical Reference Manual: * https://developer.arm.com/documentation/101370/latest/ * * QEMU interface: * + Clock input "CLK": clock * + sysbus MMIO region 0: the control register frame * + sysbus MMIO region 1: the status register frame * * Consumers of the system counter's timestamp, such as the SSE * System Timer device, can also use the APIs sse_counter_for_timestamp(), * sse_counter_tick_to_time() and sse_counter_register_consumer() to * interact with an instance of the System Counter. Generally the * consumer device should have a QOM link property which the board * code can set to the appropriate instance of the system counter. */ #ifndef SSE_COUNTER_H #define SSE_COUNTER_H #include "hw/sysbus.h" #include "qom/object.h" #include "qemu/notify.h" #define TYPE_SSE_COUNTER "sse-counter" OBJECT_DECLARE_SIMPLE_TYPE(SSECounter, SSE_COUNTER) struct SSECounter { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ MemoryRegion control_mr; MemoryRegion status_mr; Clock *clk; NotifierList notifier_list; uint32_t cntcr; uint32_t cntscr0; /* * These are used for handling clock frequency changes: they are a * tuple of (QEMU_CLOCK_VIRTUAL timestamp, CNTCV at that time), * taken when the clock frequency changes. sse_cntcv() needs them * to calculate the current CNTCV. */ uint64_t ns_then; uint64_t ticks_then; }; /* * These functions are the interface by which a consumer of * the system timestamp (such as the SSE system timer device) * can communicate with the SSECounter. */ /** * sse_counter_for_timestamp: * @counter: SSECounter * @ns: timestamp of QEMU_CLOCK_VIRTUAL in nanoseconds * * Returns the value of the timestamp counter at the specified * point in time (assuming that no changes to scale factor, enable, etc * happen in the meantime). */ uint64_t sse_counter_for_timestamp(SSECounter *counter, uint64_t ns); /** * sse_counter_tick_to_time: * @counter: SSECounter * @tick: tick value * * Returns the time (a QEMU_CLOCK_VIRTUAL timestamp in nanoseconds) * when the timestamp counter will reach the specified tick count. * If the counter is not currently running, returns UINT64_MAX. */ uint64_t sse_counter_tick_to_time(SSECounter *counter, uint64_t tick); /** * sse_counter_register_consumer: * @counter: SSECounter * @notifier: Notifier which is notified on counter changes * * Registers @notifier with the SSECounter. When the counter's * configuration changes in a way that might invalidate information * previously returned via sse_counter_for_timestamp() or * sse_counter_tick_to_time(), the notifier will be called. * Devices which consume the timestamp counter can use this as * a cue to recalculate timer events. */ void sse_counter_register_consumer(SSECounter *counter, Notifier *notifier); #endif