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