armv7m_systick.c (9375B)
1/* 2 * ARMv7M SysTick timer 3 * 4 * Copyright (c) 2006-2007 CodeSourcery. 5 * Written by Paul Brook 6 * Copyright (c) 2017 Linaro Ltd 7 * Written by Peter Maydell 8 * 9 * This code is licensed under the GPL (version 2 or later). 10 */ 11 12#include "qemu/osdep.h" 13#include "hw/timer/armv7m_systick.h" 14#include "migration/vmstate.h" 15#include "hw/irq.h" 16#include "hw/sysbus.h" 17#include "hw/qdev-clock.h" 18#include "qemu/timer.h" 19#include "qemu/log.h" 20#include "qemu/module.h" 21#include "qapi/error.h" 22#include "trace.h" 23 24#define SYSTICK_ENABLE (1 << 0) 25#define SYSTICK_TICKINT (1 << 1) 26#define SYSTICK_CLKSOURCE (1 << 2) 27#define SYSTICK_COUNTFLAG (1 << 16) 28 29#define SYSCALIB_NOREF (1U << 31) 30#define SYSCALIB_SKEW (1U << 30) 31#define SYSCALIB_TENMS ((1U << 24) - 1) 32 33static void systick_set_period_from_clock(SysTickState *s) 34{ 35 /* 36 * Set the ptimer period from whichever clock is selected. 37 * Must be called from within a ptimer transaction block. 38 */ 39 if (s->control & SYSTICK_CLKSOURCE) { 40 ptimer_set_period_from_clock(s->ptimer, s->cpuclk, 1); 41 } else { 42 ptimer_set_period_from_clock(s->ptimer, s->refclk, 1); 43 } 44} 45 46static void systick_timer_tick(void *opaque) 47{ 48 SysTickState *s = (SysTickState *)opaque; 49 50 trace_systick_timer_tick(); 51 52 s->control |= SYSTICK_COUNTFLAG; 53 if (s->control & SYSTICK_TICKINT) { 54 /* Tell the NVIC to pend the SysTick exception */ 55 qemu_irq_pulse(s->irq); 56 } 57 if (ptimer_get_limit(s->ptimer) == 0) { 58 /* 59 * Timer expiry with SYST_RVR zero disables the timer 60 * (but doesn't clear SYST_CSR.ENABLE) 61 */ 62 ptimer_stop(s->ptimer); 63 } 64} 65 66static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data, 67 unsigned size, MemTxAttrs attrs) 68{ 69 SysTickState *s = opaque; 70 uint32_t val; 71 72 if (attrs.user) { 73 /* Generate BusFault for unprivileged accesses */ 74 return MEMTX_ERROR; 75 } 76 77 switch (addr) { 78 case 0x0: /* SysTick Control and Status. */ 79 val = s->control; 80 s->control &= ~SYSTICK_COUNTFLAG; 81 break; 82 case 0x4: /* SysTick Reload Value. */ 83 val = ptimer_get_limit(s->ptimer); 84 break; 85 case 0x8: /* SysTick Current Value. */ 86 val = ptimer_get_count(s->ptimer); 87 break; 88 case 0xc: /* SysTick Calibration Value. */ 89 /* 90 * In real hardware it is possible to make this register report 91 * a different value from what the reference clock is actually 92 * running at. We don't model that (which usually happens due 93 * to integration errors in the real hardware) and instead always 94 * report the theoretical correct value as described in the 95 * knowledgebase article at 96 * https://developer.arm.com/documentation/ka001325/latest 97 * If necessary, we could implement an extra QOM property on this 98 * device to force the STCALIB value to something different from 99 * the "correct" value. 100 */ 101 if (!clock_has_source(s->refclk)) { 102 val = SYSCALIB_NOREF; 103 break; 104 } 105 val = clock_ns_to_ticks(s->refclk, 10 * SCALE_MS) - 1; 106 val &= SYSCALIB_TENMS; 107 if (clock_ticks_to_ns(s->refclk, val + 1) != 10 * SCALE_MS) { 108 /* report that tick count does not yield exactly 10ms */ 109 val |= SYSCALIB_SKEW; 110 } 111 break; 112 default: 113 val = 0; 114 qemu_log_mask(LOG_GUEST_ERROR, 115 "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 116 break; 117 } 118 119 trace_systick_read(addr, val, size); 120 *data = val; 121 return MEMTX_OK; 122} 123 124static MemTxResult systick_write(void *opaque, hwaddr addr, 125 uint64_t value, unsigned size, 126 MemTxAttrs attrs) 127{ 128 SysTickState *s = opaque; 129 130 if (attrs.user) { 131 /* Generate BusFault for unprivileged accesses */ 132 return MEMTX_ERROR; 133 } 134 135 trace_systick_write(addr, value, size); 136 137 switch (addr) { 138 case 0x0: /* SysTick Control and Status. */ 139 { 140 uint32_t oldval; 141 142 if (!clock_has_source(s->refclk)) { 143 /* This bit is always 1 if there is no external refclk */ 144 value |= SYSTICK_CLKSOURCE; 145 } 146 147 ptimer_transaction_begin(s->ptimer); 148 oldval = s->control; 149 s->control &= 0xfffffff8; 150 s->control |= value & 7; 151 152 if ((oldval ^ value) & SYSTICK_ENABLE) { 153 if (value & SYSTICK_ENABLE) { 154 ptimer_run(s->ptimer, 0); 155 } else { 156 ptimer_stop(s->ptimer); 157 } 158 } 159 160 if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 161 systick_set_period_from_clock(s); 162 } 163 ptimer_transaction_commit(s->ptimer); 164 break; 165 } 166 case 0x4: /* SysTick Reload Value. */ 167 ptimer_transaction_begin(s->ptimer); 168 ptimer_set_limit(s->ptimer, value & 0xffffff, 0); 169 ptimer_transaction_commit(s->ptimer); 170 break; 171 case 0x8: /* SysTick Current Value. */ 172 /* 173 * Writing any value clears SYST_CVR to zero and clears 174 * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR 175 * on the next clock edge unless SYST_RVR is zero. 176 */ 177 ptimer_transaction_begin(s->ptimer); 178 if (ptimer_get_limit(s->ptimer) == 0) { 179 ptimer_stop(s->ptimer); 180 } 181 ptimer_set_count(s->ptimer, 0); 182 s->control &= ~SYSTICK_COUNTFLAG; 183 ptimer_transaction_commit(s->ptimer); 184 break; 185 default: 186 qemu_log_mask(LOG_GUEST_ERROR, 187 "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); 188 } 189 return MEMTX_OK; 190} 191 192static const MemoryRegionOps systick_ops = { 193 .read_with_attrs = systick_read, 194 .write_with_attrs = systick_write, 195 .endianness = DEVICE_NATIVE_ENDIAN, 196 .valid.min_access_size = 4, 197 .valid.max_access_size = 4, 198}; 199 200static void systick_reset(DeviceState *dev) 201{ 202 SysTickState *s = SYSTICK(dev); 203 204 ptimer_transaction_begin(s->ptimer); 205 s->control = 0; 206 if (!clock_has_source(s->refclk)) { 207 /* This bit is always 1 if there is no external refclk */ 208 s->control |= SYSTICK_CLKSOURCE; 209 } 210 ptimer_stop(s->ptimer); 211 ptimer_set_count(s->ptimer, 0); 212 ptimer_set_limit(s->ptimer, 0, 0); 213 systick_set_period_from_clock(s); 214 ptimer_transaction_commit(s->ptimer); 215} 216 217static void systick_cpuclk_update(void *opaque, ClockEvent event) 218{ 219 SysTickState *s = SYSTICK(opaque); 220 221 if (!(s->control & SYSTICK_CLKSOURCE)) { 222 /* currently using refclk, we can ignore cpuclk changes */ 223 } 224 225 ptimer_transaction_begin(s->ptimer); 226 ptimer_set_period_from_clock(s->ptimer, s->cpuclk, 1); 227 ptimer_transaction_commit(s->ptimer); 228} 229 230static void systick_refclk_update(void *opaque, ClockEvent event) 231{ 232 SysTickState *s = SYSTICK(opaque); 233 234 if (s->control & SYSTICK_CLKSOURCE) { 235 /* currently using cpuclk, we can ignore refclk changes */ 236 } 237 238 ptimer_transaction_begin(s->ptimer); 239 ptimer_set_period_from_clock(s->ptimer, s->refclk, 1); 240 ptimer_transaction_commit(s->ptimer); 241} 242 243static void systick_instance_init(Object *obj) 244{ 245 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 246 SysTickState *s = SYSTICK(obj); 247 248 memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 249 sysbus_init_mmio(sbd, &s->iomem); 250 sysbus_init_irq(sbd, &s->irq); 251 252 s->refclk = qdev_init_clock_in(DEVICE(obj), "refclk", 253 systick_refclk_update, s, ClockUpdate); 254 s->cpuclk = qdev_init_clock_in(DEVICE(obj), "cpuclk", 255 systick_cpuclk_update, s, ClockUpdate); 256} 257 258static void systick_realize(DeviceState *dev, Error **errp) 259{ 260 SysTickState *s = SYSTICK(dev); 261 s->ptimer = ptimer_init(systick_timer_tick, s, 262 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | 263 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN | 264 PTIMER_POLICY_NO_IMMEDIATE_RELOAD | 265 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT); 266 267 if (!clock_has_source(s->cpuclk)) { 268 error_setg(errp, "systick: cpuclk must be connected"); 269 return; 270 } 271 /* It's OK not to connect the refclk */ 272} 273 274static const VMStateDescription vmstate_systick = { 275 .name = "armv7m_systick", 276 .version_id = 3, 277 .minimum_version_id = 3, 278 .fields = (VMStateField[]) { 279 VMSTATE_CLOCK(refclk, SysTickState), 280 VMSTATE_CLOCK(cpuclk, SysTickState), 281 VMSTATE_UINT32(control, SysTickState), 282 VMSTATE_INT64(tick, SysTickState), 283 VMSTATE_PTIMER(ptimer, SysTickState), 284 VMSTATE_END_OF_LIST() 285 } 286}; 287 288static void systick_class_init(ObjectClass *klass, void *data) 289{ 290 DeviceClass *dc = DEVICE_CLASS(klass); 291 292 dc->vmsd = &vmstate_systick; 293 dc->reset = systick_reset; 294 dc->realize = systick_realize; 295} 296 297static const TypeInfo armv7m_systick_info = { 298 .name = TYPE_SYSTICK, 299 .parent = TYPE_SYS_BUS_DEVICE, 300 .instance_init = systick_instance_init, 301 .instance_size = sizeof(SysTickState), 302 .class_init = systick_class_init, 303}; 304 305static void armv7m_systick_register_types(void) 306{ 307 type_register_static(&armv7m_systick_info); 308} 309 310type_init(armv7m_systick_register_types)