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 "qemu-common.h" 15 #include "hw/sysbus.h" 16 #include "qemu/timer.h" 17 #include "qemu/log.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 uint64_t systick_read(void *opaque, hwaddr addr, unsigned size) 79 { 80 SysTickState *s = opaque; 81 uint32_t val; 82 83 switch (addr) { 84 case 0x0: /* SysTick Control and Status. */ 85 val = s->control; 86 s->control &= ~SYSTICK_COUNTFLAG; 87 break; 88 case 0x4: /* SysTick Reload Value. */ 89 val = s->reload; 90 break; 91 case 0x8: /* SysTick Current Value. */ 92 { 93 int64_t t; 94 95 if ((s->control & SYSTICK_ENABLE) == 0) { 96 val = 0; 97 break; 98 } 99 t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 100 if (t >= s->tick) { 101 val = 0; 102 break; 103 } 104 val = ((s->tick - (t + 1)) / systick_scale(s)) + 1; 105 /* The interrupt in triggered when the timer reaches zero. 106 However the counter is not reloaded until the next clock 107 tick. This is a hack to return zero during the first tick. */ 108 if (val > s->reload) { 109 val = 0; 110 } 111 break; 112 } 113 case 0xc: /* SysTick Calibration Value. */ 114 val = 10000; 115 break; 116 default: 117 val = 0; 118 qemu_log_mask(LOG_GUEST_ERROR, 119 "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr); 120 break; 121 } 122 123 trace_systick_read(addr, val, size); 124 return val; 125 } 126 127 static void systick_write(void *opaque, hwaddr addr, 128 uint64_t value, unsigned size) 129 { 130 SysTickState *s = opaque; 131 132 trace_systick_write(addr, value, size); 133 134 switch (addr) { 135 case 0x0: /* SysTick Control and Status. */ 136 { 137 uint32_t oldval = s->control; 138 139 s->control &= 0xfffffff8; 140 s->control |= value & 7; 141 if ((oldval ^ value) & SYSTICK_ENABLE) { 142 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 143 if (value & SYSTICK_ENABLE) { 144 if (s->tick) { 145 s->tick += now; 146 timer_mod(s->timer, s->tick); 147 } else { 148 systick_reload(s, 1); 149 } 150 } else { 151 timer_del(s->timer); 152 s->tick -= now; 153 if (s->tick < 0) { 154 s->tick = 0; 155 } 156 } 157 } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 158 /* This is a hack. Force the timer to be reloaded 159 when the reference clock is changed. */ 160 systick_reload(s, 1); 161 } 162 break; 163 } 164 case 0x4: /* SysTick Reload Value. */ 165 s->reload = value; 166 break; 167 case 0x8: /* SysTick Current Value. Writes reload the timer. */ 168 systick_reload(s, 1); 169 s->control &= ~SYSTICK_COUNTFLAG; 170 break; 171 default: 172 qemu_log_mask(LOG_GUEST_ERROR, 173 "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr); 174 } 175 } 176 177 static const MemoryRegionOps systick_ops = { 178 .read = systick_read, 179 .write = systick_write, 180 .endianness = DEVICE_NATIVE_ENDIAN, 181 .valid.min_access_size = 4, 182 .valid.max_access_size = 4, 183 }; 184 185 static void systick_reset(DeviceState *dev) 186 { 187 SysTickState *s = SYSTICK(dev); 188 189 s->control = 0; 190 s->reload = 0; 191 s->tick = 0; 192 timer_del(s->timer); 193 } 194 195 static void systick_instance_init(Object *obj) 196 { 197 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 198 SysTickState *s = SYSTICK(obj); 199 200 memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0); 201 sysbus_init_mmio(sbd, &s->iomem); 202 sysbus_init_irq(sbd, &s->irq); 203 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s); 204 } 205 206 static const VMStateDescription vmstate_systick = { 207 .name = "armv7m_systick", 208 .version_id = 1, 209 .minimum_version_id = 1, 210 .fields = (VMStateField[]) { 211 VMSTATE_UINT32(control, SysTickState), 212 VMSTATE_UINT32(reload, SysTickState), 213 VMSTATE_INT64(tick, SysTickState), 214 VMSTATE_TIMER_PTR(timer, SysTickState), 215 VMSTATE_END_OF_LIST() 216 } 217 }; 218 219 static void systick_class_init(ObjectClass *klass, void *data) 220 { 221 DeviceClass *dc = DEVICE_CLASS(klass); 222 223 dc->vmsd = &vmstate_systick; 224 dc->reset = systick_reset; 225 } 226 227 static const TypeInfo armv7m_systick_info = { 228 .name = TYPE_SYSTICK, 229 .parent = TYPE_SYS_BUS_DEVICE, 230 .instance_init = systick_instance_init, 231 .instance_size = sizeof(SysTickState), 232 .class_init = systick_class_init, 233 }; 234 235 static void armv7m_systick_register_types(void) 236 { 237 type_register_static(&armv7m_systick_info); 238 } 239 240 type_init(armv7m_systick_register_types) 241