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