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" 175c6e1a1cSPeter Maydell #include "hw/qdev-clock.h" 18ff68dacbSPeter Maydell #include "qemu/timer.h" 19ff68dacbSPeter Maydell #include "qemu/log.h" 200b8fa32fSMarkus Armbruster #include "qemu/module.h" 21a40e10f1SPeter Maydell #include "qapi/error.h" 22ff68dacbSPeter Maydell #include "trace.h" 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 29a40e10f1SPeter Maydell #define SYSCALIB_NOREF (1U << 31) 30a40e10f1SPeter Maydell #define SYSCALIB_SKEW (1U << 30) 31a40e10f1SPeter Maydell #define SYSCALIB_TENMS ((1U << 24) - 1) 32a40e10f1SPeter Maydell 33a40e10f1SPeter Maydell static void systick_set_period_from_clock(SysTickState *s) 34ff68dacbSPeter Maydell { 35a40e10f1SPeter Maydell /* 36a40e10f1SPeter Maydell * Set the ptimer period from whichever clock is selected. 37a40e10f1SPeter Maydell * Must be called from within a ptimer transaction block. 38a40e10f1SPeter Maydell */ 39ff68dacbSPeter Maydell if (s->control & SYSTICK_CLKSOURCE) { 40a40e10f1SPeter Maydell ptimer_set_period_from_clock(s->ptimer, s->cpuclk, 1); 41ff68dacbSPeter Maydell } else { 42a40e10f1SPeter Maydell ptimer_set_period_from_clock(s->ptimer, s->refclk, 1); 43ff68dacbSPeter Maydell } 44ff68dacbSPeter Maydell } 45ff68dacbSPeter Maydell 46ff68dacbSPeter Maydell static void systick_timer_tick(void *opaque) 47ff68dacbSPeter Maydell { 48ff68dacbSPeter Maydell SysTickState *s = (SysTickState *)opaque; 49ff68dacbSPeter Maydell 50ff68dacbSPeter Maydell trace_systick_timer_tick(); 51ff68dacbSPeter Maydell 52ff68dacbSPeter Maydell s->control |= SYSTICK_COUNTFLAG; 53ff68dacbSPeter Maydell if (s->control & SYSTICK_TICKINT) { 54ff68dacbSPeter Maydell /* Tell the NVIC to pend the SysTick exception */ 55ff68dacbSPeter Maydell qemu_irq_pulse(s->irq); 56ff68dacbSPeter Maydell } 5732bd322aSPeter Maydell if (ptimer_get_limit(s->ptimer) == 0) { 5832bd322aSPeter Maydell /* 5932bd322aSPeter Maydell * Timer expiry with SYST_RVR zero disables the timer 6032bd322aSPeter Maydell * (but doesn't clear SYST_CSR.ENABLE) 6132bd322aSPeter Maydell */ 6232bd322aSPeter Maydell ptimer_stop(s->ptimer); 63ff68dacbSPeter Maydell } 64ff68dacbSPeter Maydell } 65ff68dacbSPeter Maydell 669bed521eSPeter Maydell static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data, 679bed521eSPeter Maydell unsigned size, MemTxAttrs attrs) 68ff68dacbSPeter Maydell { 69ff68dacbSPeter Maydell SysTickState *s = opaque; 70ff68dacbSPeter Maydell uint32_t val; 71ff68dacbSPeter Maydell 729bed521eSPeter Maydell if (attrs.user) { 739bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 749bed521eSPeter Maydell return MEMTX_ERROR; 759bed521eSPeter Maydell } 769bed521eSPeter Maydell 77ff68dacbSPeter Maydell switch (addr) { 78ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 79ff68dacbSPeter Maydell val = s->control; 80ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 81ff68dacbSPeter Maydell break; 82ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 8332bd322aSPeter Maydell val = ptimer_get_limit(s->ptimer); 84ff68dacbSPeter Maydell break; 85ff68dacbSPeter Maydell case 0x8: /* SysTick Current Value. */ 8632bd322aSPeter Maydell val = ptimer_get_count(s->ptimer); 87ff68dacbSPeter Maydell break; 88ff68dacbSPeter Maydell case 0xc: /* SysTick Calibration Value. */ 89a40e10f1SPeter Maydell /* 90a40e10f1SPeter Maydell * In real hardware it is possible to make this register report 91a40e10f1SPeter Maydell * a different value from what the reference clock is actually 92a40e10f1SPeter Maydell * running at. We don't model that (which usually happens due 93a40e10f1SPeter Maydell * to integration errors in the real hardware) and instead always 94a40e10f1SPeter Maydell * report the theoretical correct value as described in the 95a40e10f1SPeter Maydell * knowledgebase article at 96a40e10f1SPeter Maydell * https://developer.arm.com/documentation/ka001325/latest 97a40e10f1SPeter Maydell * If necessary, we could implement an extra QOM property on this 98a40e10f1SPeter Maydell * device to force the STCALIB value to something different from 99a40e10f1SPeter Maydell * the "correct" value. 100a40e10f1SPeter Maydell */ 101a40e10f1SPeter Maydell if (!clock_has_source(s->refclk)) { 102a40e10f1SPeter Maydell val = SYSCALIB_NOREF; 103a40e10f1SPeter Maydell break; 104a40e10f1SPeter Maydell } 105a40e10f1SPeter Maydell val = clock_ns_to_ticks(s->refclk, 10 * SCALE_MS) - 1; 106a40e10f1SPeter Maydell val &= SYSCALIB_TENMS; 107a40e10f1SPeter Maydell if (clock_ticks_to_ns(s->refclk, val + 1) != 10 * SCALE_MS) { 108a40e10f1SPeter Maydell /* report that tick count does not yield exactly 10ms */ 109a40e10f1SPeter Maydell val |= SYSCALIB_SKEW; 110a40e10f1SPeter Maydell } 111ff68dacbSPeter Maydell break; 112ff68dacbSPeter Maydell default: 113ff68dacbSPeter Maydell val = 0; 114ff68dacbSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 115ff68dacbSPeter Maydell "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 116ff68dacbSPeter Maydell break; 117ff68dacbSPeter Maydell } 118ff68dacbSPeter Maydell 119ff68dacbSPeter Maydell trace_systick_read(addr, val, size); 1209bed521eSPeter Maydell *data = val; 1219bed521eSPeter Maydell return MEMTX_OK; 122ff68dacbSPeter Maydell } 123ff68dacbSPeter Maydell 1249bed521eSPeter Maydell static MemTxResult systick_write(void *opaque, hwaddr addr, 1259bed521eSPeter Maydell uint64_t value, unsigned size, 1269bed521eSPeter Maydell MemTxAttrs attrs) 127ff68dacbSPeter Maydell { 128ff68dacbSPeter Maydell SysTickState *s = opaque; 129ff68dacbSPeter Maydell 1309bed521eSPeter Maydell if (attrs.user) { 1319bed521eSPeter Maydell /* Generate BusFault for unprivileged accesses */ 1329bed521eSPeter Maydell return MEMTX_ERROR; 1339bed521eSPeter Maydell } 1349bed521eSPeter Maydell 135ff68dacbSPeter Maydell trace_systick_write(addr, value, size); 136ff68dacbSPeter Maydell 137ff68dacbSPeter Maydell switch (addr) { 138ff68dacbSPeter Maydell case 0x0: /* SysTick Control and Status. */ 139ff68dacbSPeter Maydell { 14032bd322aSPeter Maydell uint32_t oldval; 141ff68dacbSPeter Maydell 142a40e10f1SPeter Maydell if (!clock_has_source(s->refclk)) { 143a40e10f1SPeter Maydell /* This bit is always 1 if there is no external refclk */ 144a40e10f1SPeter Maydell value |= SYSTICK_CLKSOURCE; 145a40e10f1SPeter Maydell } 146a40e10f1SPeter Maydell 14732bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 14832bd322aSPeter Maydell oldval = s->control; 149ff68dacbSPeter Maydell s->control &= 0xfffffff8; 150ff68dacbSPeter Maydell s->control |= value & 7; 15132bd322aSPeter Maydell 15277cd9971SRichard Petri if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 15377cd9971SRichard Petri systick_set_period_from_clock(s); 15477cd9971SRichard Petri } 15577cd9971SRichard Petri 156ff68dacbSPeter Maydell if ((oldval ^ value) & SYSTICK_ENABLE) { 157ff68dacbSPeter Maydell if (value & SYSTICK_ENABLE) { 15832bd322aSPeter Maydell ptimer_run(s->ptimer, 0); 159ff68dacbSPeter Maydell } else { 16032bd322aSPeter Maydell ptimer_stop(s->ptimer); 161ff68dacbSPeter Maydell } 162a40e10f1SPeter Maydell } 16332bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 164ff68dacbSPeter Maydell break; 165ff68dacbSPeter Maydell } 166ff68dacbSPeter Maydell case 0x4: /* SysTick Reload Value. */ 16732bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 16832bd322aSPeter Maydell ptimer_set_limit(s->ptimer, value & 0xffffff, 0); 16932bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 170ff68dacbSPeter Maydell break; 17132bd322aSPeter Maydell case 0x8: /* SysTick Current Value. */ 17232bd322aSPeter Maydell /* 17332bd322aSPeter Maydell * Writing any value clears SYST_CVR to zero and clears 17432bd322aSPeter Maydell * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR 17532bd322aSPeter Maydell * on the next clock edge unless SYST_RVR is zero. 17632bd322aSPeter Maydell */ 17732bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 17832bd322aSPeter Maydell if (ptimer_get_limit(s->ptimer) == 0) { 17932bd322aSPeter Maydell ptimer_stop(s->ptimer); 18032bd322aSPeter Maydell } 18132bd322aSPeter Maydell ptimer_set_count(s->ptimer, 0); 182ff68dacbSPeter Maydell s->control &= ~SYSTICK_COUNTFLAG; 18332bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 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 20432bd322aSPeter Maydell ptimer_transaction_begin(s->ptimer); 205ff68dacbSPeter Maydell s->control = 0; 206a40e10f1SPeter Maydell if (!clock_has_source(s->refclk)) { 207a40e10f1SPeter Maydell /* This bit is always 1 if there is no external refclk */ 208a40e10f1SPeter Maydell s->control |= SYSTICK_CLKSOURCE; 209a40e10f1SPeter Maydell } 21032bd322aSPeter Maydell ptimer_stop(s->ptimer); 21132bd322aSPeter Maydell ptimer_set_count(s->ptimer, 0); 21232bd322aSPeter Maydell ptimer_set_limit(s->ptimer, 0, 0); 213a40e10f1SPeter Maydell systick_set_period_from_clock(s); 214a40e10f1SPeter Maydell ptimer_transaction_commit(s->ptimer); 215a40e10f1SPeter Maydell } 216a40e10f1SPeter Maydell 217a40e10f1SPeter Maydell static void systick_cpuclk_update(void *opaque, ClockEvent event) 218a40e10f1SPeter Maydell { 219a40e10f1SPeter Maydell SysTickState *s = SYSTICK(opaque); 220a40e10f1SPeter Maydell 221a40e10f1SPeter Maydell if (!(s->control & SYSTICK_CLKSOURCE)) { 222a40e10f1SPeter Maydell /* currently using refclk, we can ignore cpuclk changes */ 223a40e10f1SPeter Maydell } 224a40e10f1SPeter Maydell 225a40e10f1SPeter Maydell ptimer_transaction_begin(s->ptimer); 226a40e10f1SPeter Maydell ptimer_set_period_from_clock(s->ptimer, s->cpuclk, 1); 227a40e10f1SPeter Maydell ptimer_transaction_commit(s->ptimer); 228a40e10f1SPeter Maydell } 229a40e10f1SPeter Maydell 230a40e10f1SPeter Maydell static void systick_refclk_update(void *opaque, ClockEvent event) 231a40e10f1SPeter Maydell { 232a40e10f1SPeter Maydell SysTickState *s = SYSTICK(opaque); 233a40e10f1SPeter Maydell 234a40e10f1SPeter Maydell if (s->control & SYSTICK_CLKSOURCE) { 235a40e10f1SPeter Maydell /* currently using cpuclk, we can ignore refclk changes */ 236a40e10f1SPeter Maydell } 237a40e10f1SPeter Maydell 238a40e10f1SPeter Maydell ptimer_transaction_begin(s->ptimer); 239a40e10f1SPeter Maydell ptimer_set_period_from_clock(s->ptimer, s->refclk, 1); 24032bd322aSPeter Maydell ptimer_transaction_commit(s->ptimer); 241ff68dacbSPeter Maydell } 242ff68dacbSPeter Maydell 243ff68dacbSPeter Maydell static void systick_instance_init(Object *obj) 244ff68dacbSPeter Maydell { 245ff68dacbSPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 246ff68dacbSPeter Maydell SysTickState *s = SYSTICK(obj); 247ff68dacbSPeter Maydell 248ff68dacbSPeter Maydell memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 249ff68dacbSPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 250ff68dacbSPeter Maydell sysbus_init_irq(sbd, &s->irq); 2515c6e1a1cSPeter Maydell 252a40e10f1SPeter Maydell s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", 253a40e10f1SPeter Maydell systick_refclk_update, s, ClockUpdate); 254a40e10f1SPeter Maydell s->cpuclk = qdev_init_clock_in(DEVICE(obj), "cpuclk", 255a40e10f1SPeter Maydell systick_cpuclk_update, s, ClockUpdate); 256f3a508ebSPan Nengyuan } 257f3a508ebSPan Nengyuan 258f3a508ebSPan Nengyuan static void systick_realize(DeviceState *dev, Error **errp) 259f3a508ebSPan Nengyuan { 260f3a508ebSPan Nengyuan SysTickState *s = SYSTICK(dev); 26132bd322aSPeter Maydell s->ptimer = ptimer_init(systick_timer_tick, s, 26232bd322aSPeter Maydell PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | 26332bd322aSPeter Maydell PTIMER_POLICY_NO_COUNTER_ROUND_DOWN | 26432bd322aSPeter Maydell PTIMER_POLICY_NO_IMMEDIATE_RELOAD | 26532bd322aSPeter Maydell PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT); 266a40e10f1SPeter Maydell 267a40e10f1SPeter Maydell if (!clock_has_source(s->cpuclk)) { 268a40e10f1SPeter Maydell error_setg(errp, "systick: cpuclk must be connected"); 269a40e10f1SPeter Maydell return; 270a40e10f1SPeter Maydell } 271a40e10f1SPeter Maydell /* It's OK not to connect the refclk */ 272ff68dacbSPeter Maydell } 273ff68dacbSPeter Maydell 274ff68dacbSPeter Maydell static const VMStateDescription vmstate_systick = { 275ff68dacbSPeter Maydell .name = "armv7m_systick", 2765c6e1a1cSPeter Maydell .version_id = 3, 2775c6e1a1cSPeter Maydell .minimum_version_id = 3, 278ba324b3fSRichard Henderson .fields = (const VMStateField[]) { 2795c6e1a1cSPeter Maydell VMSTATE_CLOCK(refclk, SysTickState), 2805c6e1a1cSPeter Maydell VMSTATE_CLOCK(cpuclk, SysTickState), 281ff68dacbSPeter Maydell VMSTATE_UINT32(control, SysTickState), 282ff68dacbSPeter Maydell VMSTATE_INT64(tick, SysTickState), 28332bd322aSPeter Maydell VMSTATE_PTIMER(ptimer, SysTickState), 284ff68dacbSPeter Maydell VMSTATE_END_OF_LIST() 285ff68dacbSPeter Maydell } 286ff68dacbSPeter Maydell }; 287ff68dacbSPeter Maydell 288ff68dacbSPeter Maydell static void systick_class_init(ObjectClass *klass, void *data) 289ff68dacbSPeter Maydell { 290ff68dacbSPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 291ff68dacbSPeter Maydell 292ff68dacbSPeter Maydell dc->vmsd = &vmstate_systick; 293*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, systick_reset); 294f3a508ebSPan Nengyuan dc->realize = systick_realize; 295ff68dacbSPeter Maydell } 296ff68dacbSPeter Maydell 297ff68dacbSPeter Maydell static const TypeInfo armv7m_systick_info = { 298ff68dacbSPeter Maydell .name = TYPE_SYSTICK, 299ff68dacbSPeter Maydell .parent = TYPE_SYS_BUS_DEVICE, 300ff68dacbSPeter Maydell .instance_init = systick_instance_init, 301ff68dacbSPeter Maydell .instance_size = sizeof(SysTickState), 302ff68dacbSPeter Maydell .class_init = systick_class_init, 303ff68dacbSPeter Maydell }; 304ff68dacbSPeter Maydell 305ff68dacbSPeter Maydell static void armv7m_systick_register_types(void) 306ff68dacbSPeter Maydell { 307ff68dacbSPeter Maydell type_register_static(&armv7m_systick_info); 308ff68dacbSPeter Maydell } 309ff68dacbSPeter Maydell 310ff68dacbSPeter Maydell type_init(armv7m_systick_register_types) 311