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