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