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