1ff68dacbSPeter Maydell /* 2ff68dacbSPeter Maydell * ARMv7M SysTick timer 3ff68dacbSPeter Maydell * 4ff68dacbSPeter Maydell * Copyright (c) 2006-2007 CodeSourcery. 5ff68dacbSPeter Maydell * Written by Paul Brook 6ff68dacbSPeter Maydell * Copyright (c) 2017 Linaro Ltd 7ff68dacbSPeter Maydell * Written by Peter Maydell 8ff68dacbSPeter Maydell * 9ff68dacbSPeter Maydell * This code is licensed under the GPL (version 2 or later). 10ff68dacbSPeter Maydell */ 11ff68dacbSPeter Maydell 12ff68dacbSPeter Maydell #include "qemu/osdep.h" 13ff68dacbSPeter Maydell #include "hw/timer/armv7m_systick.h" 14*64552b6bSMarkus Armbruster #include "hw/irq.h" 15ff68dacbSPeter Maydell #include "hw/sysbus.h" 16ff68dacbSPeter Maydell #include "qemu/timer.h" 17ff68dacbSPeter Maydell #include "qemu/log.h" 180b8fa32fSMarkus Armbruster #include "qemu/module.h" 19ff68dacbSPeter Maydell #include "trace.h" 20ff68dacbSPeter Maydell 21ff68dacbSPeter Maydell /* qemu timers run at 1GHz. We want something closer to 1MHz. */ 22ff68dacbSPeter Maydell #define SYSTICK_SCALE 1000ULL 23ff68dacbSPeter Maydell 24ff68dacbSPeter Maydell #define SYSTICK_ENABLE (1 << 0) 25ff68dacbSPeter Maydell #define SYSTICK_TICKINT (1 << 1) 26ff68dacbSPeter Maydell #define SYSTICK_CLKSOURCE (1 << 2) 27ff68dacbSPeter Maydell #define SYSTICK_COUNTFLAG (1 << 16) 28ff68dacbSPeter Maydell 29ff68dacbSPeter Maydell int system_clock_scale; 30ff68dacbSPeter Maydell 31ff68dacbSPeter Maydell /* Conversion factor from qemu timer to SysTick frequencies. */ 32ff68dacbSPeter Maydell static inline int64_t systick_scale(SysTickState *s) 33ff68dacbSPeter Maydell { 34ff68dacbSPeter Maydell if (s->control & SYSTICK_CLKSOURCE) { 35ff68dacbSPeter Maydell return system_clock_scale; 36ff68dacbSPeter Maydell } else { 37ff68dacbSPeter Maydell return 1000; 38ff68dacbSPeter Maydell } 39ff68dacbSPeter Maydell } 40ff68dacbSPeter Maydell 41ff68dacbSPeter Maydell static void systick_reload(SysTickState *s, int reset) 42ff68dacbSPeter Maydell { 43ff68dacbSPeter Maydell /* The Cortex-M3 Devices Generic User Guide says that "When the 44ff68dacbSPeter Maydell * ENABLE bit is set to 1, the counter loads the RELOAD value from the 45ff68dacbSPeter Maydell * SYST RVR register and then counts down". So, we need to check the 46ff68dacbSPeter Maydell * ENABLE bit before reloading the value. 47ff68dacbSPeter Maydell */ 48ff68dacbSPeter Maydell trace_systick_reload(); 49ff68dacbSPeter Maydell 50ff68dacbSPeter Maydell if ((s->control & SYSTICK_ENABLE) == 0) { 51ff68dacbSPeter Maydell return; 52ff68dacbSPeter Maydell } 53ff68dacbSPeter Maydell 54ff68dacbSPeter Maydell if (reset) { 55ff68dacbSPeter Maydell s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 56ff68dacbSPeter Maydell } 57ff68dacbSPeter Maydell s->tick += (s->reload + 1) * systick_scale(s); 58ff68dacbSPeter Maydell timer_mod(s->timer, s->tick); 59ff68dacbSPeter Maydell } 60ff68dacbSPeter Maydell 61ff68dacbSPeter Maydell static void systick_timer_tick(void *opaque) 62ff68dacbSPeter Maydell { 63ff68dacbSPeter Maydell SysTickState *s = (SysTickState *)opaque; 64ff68dacbSPeter Maydell 65ff68dacbSPeter Maydell trace_systick_timer_tick(); 66ff68dacbSPeter Maydell 67ff68dacbSPeter Maydell s->control |= SYSTICK_COUNTFLAG; 68ff68dacbSPeter Maydell if (s->control & SYSTICK_TICKINT) { 69ff68dacbSPeter Maydell /* Tell the NVIC to pend the SysTick exception */ 70ff68dacbSPeter Maydell qemu_irq_pulse(s->irq); 71ff68dacbSPeter Maydell } 72ff68dacbSPeter Maydell if (s->reload == 0) { 73ff68dacbSPeter Maydell s->control &= ~SYSTICK_ENABLE; 74ff68dacbSPeter Maydell } else { 75ff68dacbSPeter Maydell systick_reload(s, 0); 76ff68dacbSPeter Maydell } 77ff68dacbSPeter Maydell } 78ff68dacbSPeter Maydell 799bed521eSPeter Maydell static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data, 809bed521eSPeter Maydell unsigned size, MemTxAttrs attrs) 81ff68dacbSPeter Maydell { 82ff68dacbSPeter Maydell SysTickState *s = opaque; 83ff68dacbSPeter Maydell uint32_t val; 84ff68dacbSPeter Maydell 859bed521eSPeter Maydell if (attrs.user) { 869bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 879bed521eSPeter Maydell return MEMTX_ERROR; 889bed521eSPeter Maydell } 899bed521eSPeter Maydell 90ff68dacbSPeter Maydell switch (addr) { 91ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 92ff68dacbSPeter Maydell val = s->control; 93ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 94ff68dacbSPeter Maydell break; 95ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 96ff68dacbSPeter Maydell val = s->reload; 97ff68dacbSPeter Maydell break; 98ff68dacbSPeter Maydell case 0x8: /* SysTick Current Value. */ 99ff68dacbSPeter Maydell { 100ff68dacbSPeter Maydell int64_t t; 101ff68dacbSPeter Maydell 102ff68dacbSPeter Maydell if ((s->control & SYSTICK_ENABLE) == 0) { 103ff68dacbSPeter Maydell val = 0; 104ff68dacbSPeter Maydell break; 105ff68dacbSPeter Maydell } 106ff68dacbSPeter Maydell t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 107ff68dacbSPeter Maydell if (t >= s->tick) { 108ff68dacbSPeter Maydell val = 0; 109ff68dacbSPeter Maydell break; 110ff68dacbSPeter Maydell } 111ff68dacbSPeter Maydell val = ((s->tick - (t + 1)) / systick_scale(s)) + 1; 112ff68dacbSPeter Maydell /* The interrupt in triggered when the timer reaches zero. 113ff68dacbSPeter Maydell However the counter is not reloaded until the next clock 114ff68dacbSPeter Maydell tick. This is a hack to return zero during the first tick. */ 115ff68dacbSPeter Maydell if (val > s->reload) { 116ff68dacbSPeter Maydell val = 0; 117ff68dacbSPeter Maydell } 118ff68dacbSPeter Maydell break; 119ff68dacbSPeter Maydell } 120ff68dacbSPeter Maydell case 0xc: /* SysTick Calibration Value. */ 121ff68dacbSPeter Maydell val = 10000; 122ff68dacbSPeter Maydell break; 123ff68dacbSPeter Maydell default: 124ff68dacbSPeter Maydell val = 0; 125ff68dacbSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 126ff68dacbSPeter Maydell "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 127ff68dacbSPeter Maydell break; 128ff68dacbSPeter Maydell } 129ff68dacbSPeter Maydell 130ff68dacbSPeter Maydell trace_systick_read(addr, val, size); 1319bed521eSPeter Maydell *data = val; 1329bed521eSPeter Maydell return MEMTX_OK; 133ff68dacbSPeter Maydell } 134ff68dacbSPeter Maydell 1359bed521eSPeter Maydell static MemTxResult systick_write(void *opaque, hwaddr addr, 1369bed521eSPeter Maydell uint64_t value, unsigned size, 1379bed521eSPeter Maydell MemTxAttrs attrs) 138ff68dacbSPeter Maydell { 139ff68dacbSPeter Maydell SysTickState *s = opaque; 140ff68dacbSPeter Maydell 1419bed521eSPeter Maydell if (attrs.user) { 1429bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 1439bed521eSPeter Maydell return MEMTX_ERROR; 1449bed521eSPeter Maydell } 1459bed521eSPeter Maydell 146ff68dacbSPeter Maydell trace_systick_write(addr, value, size); 147ff68dacbSPeter Maydell 148ff68dacbSPeter Maydell switch (addr) { 149ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 150ff68dacbSPeter Maydell { 151ff68dacbSPeter Maydell uint32_t oldval = s->control; 152ff68dacbSPeter Maydell 153ff68dacbSPeter Maydell s->control &= 0xfffffff8; 154ff68dacbSPeter Maydell s->control |= value & 7; 155ff68dacbSPeter Maydell if ((oldval ^ value) & SYSTICK_ENABLE) { 156ff68dacbSPeter Maydell int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 157ff68dacbSPeter Maydell if (value & SYSTICK_ENABLE) { 158ff68dacbSPeter Maydell if (s->tick) { 159ff68dacbSPeter Maydell s->tick += now; 160ff68dacbSPeter Maydell timer_mod(s->timer, s->tick); 161ff68dacbSPeter Maydell } else { 162ff68dacbSPeter Maydell systick_reload(s, 1); 163ff68dacbSPeter Maydell } 164ff68dacbSPeter Maydell } else { 165ff68dacbSPeter Maydell timer_del(s->timer); 166ff68dacbSPeter Maydell s->tick -= now; 167ff68dacbSPeter Maydell if (s->tick < 0) { 168ff68dacbSPeter Maydell s->tick = 0; 169ff68dacbSPeter Maydell } 170ff68dacbSPeter Maydell } 171ff68dacbSPeter Maydell } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 172ff68dacbSPeter Maydell /* This is a hack. Force the timer to be reloaded 173ff68dacbSPeter Maydell when the reference clock is changed. */ 174ff68dacbSPeter Maydell systick_reload(s, 1); 175ff68dacbSPeter Maydell } 176ff68dacbSPeter Maydell break; 177ff68dacbSPeter Maydell } 178ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 179ff68dacbSPeter Maydell s->reload = value; 180ff68dacbSPeter Maydell break; 181ff68dacbSPeter Maydell case 0x8: /* SysTick Current Value. Writes reload the timer. */ 182ff68dacbSPeter Maydell systick_reload(s, 1); 183ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 184ff68dacbSPeter Maydell break; 185ff68dacbSPeter Maydell default: 186ff68dacbSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 187ff68dacbSPeter Maydell "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); 188ff68dacbSPeter Maydell } 1899bed521eSPeter Maydell return MEMTX_OK; 190ff68dacbSPeter Maydell } 191ff68dacbSPeter Maydell 192ff68dacbSPeter Maydell static const MemoryRegionOps systick_ops = { 1939bed521eSPeter Maydell .read_with_attrs = systick_read, 1949bed521eSPeter Maydell .write_with_attrs = systick_write, 195ff68dacbSPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 196ff68dacbSPeter Maydell .valid.min_access_size = 4, 197ff68dacbSPeter Maydell .valid.max_access_size = 4, 198ff68dacbSPeter Maydell }; 199ff68dacbSPeter Maydell 200ff68dacbSPeter Maydell static void systick_reset(DeviceState *dev) 201ff68dacbSPeter Maydell { 202ff68dacbSPeter Maydell SysTickState *s = SYSTICK(dev); 203ff68dacbSPeter Maydell 204ff68dacbSPeter Maydell s->control = 0; 205ff68dacbSPeter Maydell s->reload = 0; 206ff68dacbSPeter Maydell s->tick = 0; 207ff68dacbSPeter Maydell timer_del(s->timer); 208ff68dacbSPeter Maydell } 209ff68dacbSPeter Maydell 210ff68dacbSPeter Maydell static void systick_instance_init(Object *obj) 211ff68dacbSPeter Maydell { 212ff68dacbSPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 213ff68dacbSPeter Maydell SysTickState *s = SYSTICK(obj); 214ff68dacbSPeter Maydell 215ff68dacbSPeter Maydell memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 216ff68dacbSPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 217ff68dacbSPeter Maydell sysbus_init_irq(sbd, &s->irq); 218ff68dacbSPeter Maydell s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); 219ff68dacbSPeter Maydell } 220ff68dacbSPeter Maydell 221ff68dacbSPeter Maydell static const VMStateDescription vmstate_systick = { 222ff68dacbSPeter Maydell .name = "armv7m_systick", 223ff68dacbSPeter Maydell .version_id = 1, 224ff68dacbSPeter Maydell .minimum_version_id = 1, 225ff68dacbSPeter Maydell .fields = (VMStateField[]) { 226ff68dacbSPeter Maydell VMSTATE_UINT32(control, SysTickState), 227ff68dacbSPeter Maydell VMSTATE_UINT32(reload, SysTickState), 228ff68dacbSPeter Maydell VMSTATE_INT64(tick, SysTickState), 229ff68dacbSPeter Maydell VMSTATE_TIMER_PTR(timer, SysTickState), 230ff68dacbSPeter Maydell VMSTATE_END_OF_LIST() 231ff68dacbSPeter Maydell } 232ff68dacbSPeter Maydell }; 233ff68dacbSPeter Maydell 234ff68dacbSPeter Maydell static void systick_class_init(ObjectClass *klass, void *data) 235ff68dacbSPeter Maydell { 236ff68dacbSPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 237ff68dacbSPeter Maydell 238ff68dacbSPeter Maydell dc->vmsd = &vmstate_systick; 239ff68dacbSPeter Maydell dc->reset = systick_reset; 240ff68dacbSPeter Maydell } 241ff68dacbSPeter Maydell 242ff68dacbSPeter Maydell static const TypeInfo armv7m_systick_info = { 243ff68dacbSPeter Maydell .name = TYPE_SYSTICK, 244ff68dacbSPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 245ff68dacbSPeter Maydell .instance_init = systick_instance_init, 246ff68dacbSPeter Maydell .instance_size = sizeof(SysTickState), 247ff68dacbSPeter Maydell .class_init = systick_class_init, 248ff68dacbSPeter Maydell }; 249ff68dacbSPeter Maydell 250ff68dacbSPeter Maydell static void armv7m_systick_register_types(void) 251ff68dacbSPeter Maydell { 252ff68dacbSPeter Maydell type_register_static(&armv7m_systick_info); 253ff68dacbSPeter Maydell } 254ff68dacbSPeter Maydell 255ff68dacbSPeter Maydell type_init(armv7m_systick_register_types) 256