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" 14d6454270SMarkus 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_timer_tick(void *opaque) 43ff68dacbSPeter Maydell { 44ff68dacbSPeter Maydell SysTickState *s = (SysTickState *)opaque; 45ff68dacbSPeter Maydell 46ff68dacbSPeter Maydell trace_systick_timer_tick(); 47ff68dacbSPeter Maydell 48ff68dacbSPeter Maydell s->control |= SYSTICK_COUNTFLAG; 49ff68dacbSPeter Maydell if (s->control & SYSTICK_TICKINT) { 50ff68dacbSPeter Maydell /* Tell the NVIC to pend the SysTick exception */ 51ff68dacbSPeter Maydell qemu_irq_pulse(s->irq); 52ff68dacbSPeter Maydell } 53*32bd322aSPeter Maydell if (ptimer_get_limit(s->ptimer) == 0) { 54*32bd322aSPeter Maydell /* 55*32bd322aSPeter Maydell * Timer expiry with SYST_RVR zero disables the timer 56*32bd322aSPeter Maydell * (but doesn't clear SYST_CSR.ENABLE) 57*32bd322aSPeter Maydell */ 58*32bd322aSPeter Maydell ptimer_stop(s->ptimer); 59ff68dacbSPeter Maydell } 60ff68dacbSPeter Maydell } 61ff68dacbSPeter Maydell 629bed521eSPeter Maydell static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data, 639bed521eSPeter Maydell unsigned size, MemTxAttrs attrs) 64ff68dacbSPeter Maydell { 65ff68dacbSPeter Maydell SysTickState *s = opaque; 66ff68dacbSPeter Maydell uint32_t val; 67ff68dacbSPeter Maydell 689bed521eSPeter Maydell if (attrs.user) { 699bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 709bed521eSPeter Maydell return MEMTX_ERROR; 719bed521eSPeter Maydell } 729bed521eSPeter Maydell 73ff68dacbSPeter Maydell switch (addr) { 74ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 75ff68dacbSPeter Maydell val = s->control; 76ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 77ff68dacbSPeter Maydell break; 78ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 79*32bd322aSPeter Maydell val = ptimer_get_limit(s->ptimer); 80ff68dacbSPeter Maydell break; 81ff68dacbSPeter Maydell case 0x8: /* SysTick Current Value. */ 82*32bd322aSPeter Maydell val = ptimer_get_count(s->ptimer); 83ff68dacbSPeter Maydell break; 84ff68dacbSPeter Maydell case 0xc: /* SysTick Calibration Value. */ 85ff68dacbSPeter Maydell val = 10000; 86ff68dacbSPeter Maydell break; 87ff68dacbSPeter Maydell default: 88ff68dacbSPeter Maydell val = 0; 89ff68dacbSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 90ff68dacbSPeter Maydell "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 91ff68dacbSPeter Maydell break; 92ff68dacbSPeter Maydell } 93ff68dacbSPeter Maydell 94ff68dacbSPeter Maydell trace_systick_read(addr, val, size); 959bed521eSPeter Maydell *data = val; 969bed521eSPeter Maydell return MEMTX_OK; 97ff68dacbSPeter Maydell } 98ff68dacbSPeter Maydell 999bed521eSPeter Maydell static MemTxResult systick_write(void *opaque, hwaddr addr, 1009bed521eSPeter Maydell uint64_t value, unsigned size, 1019bed521eSPeter Maydell MemTxAttrs attrs) 102ff68dacbSPeter Maydell { 103ff68dacbSPeter Maydell SysTickState *s = opaque; 104ff68dacbSPeter Maydell 1059bed521eSPeter Maydell if (attrs.user) { 1069bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 1079bed521eSPeter Maydell return MEMTX_ERROR; 1089bed521eSPeter Maydell } 1099bed521eSPeter Maydell 110ff68dacbSPeter Maydell trace_systick_write(addr, value, size); 111ff68dacbSPeter Maydell 112ff68dacbSPeter Maydell switch (addr) { 113ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 114ff68dacbSPeter Maydell { 115*32bd322aSPeter Maydell uint32_t oldval; 116ff68dacbSPeter Maydell 117*32bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 118*32bd322aSPeter Maydell oldval = s->control; 119ff68dacbSPeter Maydell s->control &= 0xfffffff8; 120ff68dacbSPeter Maydell s->control |= value & 7; 121*32bd322aSPeter Maydell 122ff68dacbSPeter Maydell if ((oldval ^ value) & SYSTICK_ENABLE) { 123ff68dacbSPeter Maydell if (value & SYSTICK_ENABLE) { 124*32bd322aSPeter Maydell /* 125*32bd322aSPeter Maydell * Always reload the period in case board code has 126*32bd322aSPeter Maydell * changed system_clock_scale. If we ever replace that 127*32bd322aSPeter Maydell * global with a more sensible API then we might be able 128*32bd322aSPeter Maydell * to set the period only when it actually changes. 129*32bd322aSPeter Maydell */ 130*32bd322aSPeter Maydell ptimer_set_period(s->ptimer, systick_scale(s)); 131*32bd322aSPeter Maydell ptimer_run(s->ptimer, 0); 132ff68dacbSPeter Maydell } else { 133*32bd322aSPeter Maydell ptimer_stop(s->ptimer); 134ff68dacbSPeter Maydell } 135ff68dacbSPeter Maydell } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 136*32bd322aSPeter Maydell ptimer_set_period(s->ptimer, systick_scale(s)); 137ff68dacbSPeter Maydell } 138*32bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 139ff68dacbSPeter Maydell break; 140ff68dacbSPeter Maydell } 141ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 142*32bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 143*32bd322aSPeter Maydell ptimer_set_limit(s->ptimer, value & 0xffffff, 0); 144*32bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 145ff68dacbSPeter Maydell break; 146*32bd322aSPeter Maydell case 0x8: /* SysTick Current Value. */ 147*32bd322aSPeter Maydell /* 148*32bd322aSPeter Maydell * Writing any value clears SYST_CVR to zero and clears 149*32bd322aSPeter Maydell * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR 150*32bd322aSPeter Maydell * on the next clock edge unless SYST_RVR is zero. 151*32bd322aSPeter Maydell */ 152*32bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 153*32bd322aSPeter Maydell if (ptimer_get_limit(s->ptimer) == 0) { 154*32bd322aSPeter Maydell ptimer_stop(s->ptimer); 155*32bd322aSPeter Maydell } 156*32bd322aSPeter Maydell ptimer_set_count(s->ptimer, 0); 157ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 158*32bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 159ff68dacbSPeter Maydell break; 160ff68dacbSPeter Maydell default: 161ff68dacbSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 162ff68dacbSPeter Maydell "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); 163ff68dacbSPeter Maydell } 1649bed521eSPeter Maydell return MEMTX_OK; 165ff68dacbSPeter Maydell } 166ff68dacbSPeter Maydell 167ff68dacbSPeter Maydell static const MemoryRegionOps systick_ops = { 1689bed521eSPeter Maydell .read_with_attrs = systick_read, 1699bed521eSPeter Maydell .write_with_attrs = systick_write, 170ff68dacbSPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 171ff68dacbSPeter Maydell .valid.min_access_size = 4, 172ff68dacbSPeter Maydell .valid.max_access_size = 4, 173ff68dacbSPeter Maydell }; 174ff68dacbSPeter Maydell 175ff68dacbSPeter Maydell static void systick_reset(DeviceState *dev) 176ff68dacbSPeter Maydell { 177ff68dacbSPeter Maydell SysTickState *s = SYSTICK(dev); 178ff68dacbSPeter Maydell 179c9ebc8c2SPeter Maydell /* 180c9ebc8c2SPeter Maydell * Forgetting to set system_clock_scale is always a board code 181c9ebc8c2SPeter Maydell * bug. We can't check this earlier because for some boards 182c9ebc8c2SPeter Maydell * (like stellaris) it is not yet configured at the point where 183c9ebc8c2SPeter Maydell * the systick device is realized. 184c9ebc8c2SPeter Maydell */ 185c9ebc8c2SPeter Maydell assert(system_clock_scale != 0); 186c9ebc8c2SPeter Maydell 187*32bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 188ff68dacbSPeter Maydell s->control = 0; 189*32bd322aSPeter Maydell ptimer_stop(s->ptimer); 190*32bd322aSPeter Maydell ptimer_set_count(s->ptimer, 0); 191*32bd322aSPeter Maydell ptimer_set_limit(s->ptimer, 0, 0); 192*32bd322aSPeter Maydell ptimer_set_period(s->ptimer, systick_scale(s)); 193*32bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 194ff68dacbSPeter Maydell } 195ff68dacbSPeter Maydell 196ff68dacbSPeter Maydell static void systick_instance_init(Object *obj) 197ff68dacbSPeter Maydell { 198ff68dacbSPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 199ff68dacbSPeter Maydell SysTickState *s = SYSTICK(obj); 200ff68dacbSPeter Maydell 201ff68dacbSPeter Maydell memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 202ff68dacbSPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 203ff68dacbSPeter Maydell sysbus_init_irq(sbd, &s->irq); 204f3a508ebSPan Nengyuan } 205f3a508ebSPan Nengyuan 206f3a508ebSPan Nengyuan static void systick_realize(DeviceState *dev, Error **errp) 207f3a508ebSPan Nengyuan { 208f3a508ebSPan Nengyuan SysTickState *s = SYSTICK(dev); 209*32bd322aSPeter Maydell s->ptimer = ptimer_init(systick_timer_tick, s, 210*32bd322aSPeter Maydell PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | 211*32bd322aSPeter Maydell PTIMER_POLICY_NO_COUNTER_ROUND_DOWN | 212*32bd322aSPeter Maydell PTIMER_POLICY_NO_IMMEDIATE_RELOAD | 213*32bd322aSPeter Maydell PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT); 214ff68dacbSPeter Maydell } 215ff68dacbSPeter Maydell 216ff68dacbSPeter Maydell static const VMStateDescription vmstate_systick = { 217ff68dacbSPeter Maydell .name = "armv7m_systick", 218*32bd322aSPeter Maydell .version_id = 2, 219*32bd322aSPeter Maydell .minimum_version_id = 2, 220ff68dacbSPeter Maydell .fields = (VMStateField[]) { 221ff68dacbSPeter Maydell VMSTATE_UINT32(control, SysTickState), 222ff68dacbSPeter Maydell VMSTATE_INT64(tick, SysTickState), 223*32bd322aSPeter Maydell VMSTATE_PTIMER(ptimer, SysTickState), 224ff68dacbSPeter Maydell VMSTATE_END_OF_LIST() 225ff68dacbSPeter Maydell } 226ff68dacbSPeter Maydell }; 227ff68dacbSPeter Maydell 228ff68dacbSPeter Maydell static void systick_class_init(ObjectClass *klass, void *data) 229ff68dacbSPeter Maydell { 230ff68dacbSPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 231ff68dacbSPeter Maydell 232ff68dacbSPeter Maydell dc->vmsd = &vmstate_systick; 233ff68dacbSPeter Maydell dc->reset = systick_reset; 234f3a508ebSPan Nengyuan dc->realize = systick_realize; 235ff68dacbSPeter Maydell } 236ff68dacbSPeter Maydell 237ff68dacbSPeter Maydell static const TypeInfo armv7m_systick_info = { 238ff68dacbSPeter Maydell .name = TYPE_SYSTICK, 239ff68dacbSPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 240ff68dacbSPeter Maydell .instance_init = systick_instance_init, 241ff68dacbSPeter Maydell .instance_size = sizeof(SysTickState), 242ff68dacbSPeter Maydell .class_init = systick_class_init, 243ff68dacbSPeter Maydell }; 244ff68dacbSPeter Maydell 245ff68dacbSPeter Maydell static void armv7m_systick_register_types(void) 246ff68dacbSPeter Maydell { 247ff68dacbSPeter Maydell type_register_static(&armv7m_systick_info); 248ff68dacbSPeter Maydell } 249ff68dacbSPeter Maydell 250ff68dacbSPeter Maydell type_init(armv7m_systick_register_types) 251