1 /* 2 * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP 3 * 4 * Copyright (c) 2006-2007 CodeSourcery. 5 * Copyright (c) 2011 Linaro Limited 6 * Written by Paul Brook, Peter Maydell 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License along 19 * with this program; if not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 #include "hw/timer/arm_mptimer.h" 23 #include "qemu/timer.h" 24 #include "qom/cpu.h" 25 26 /* This device implements the per-cpu private timer and watchdog block 27 * which is used in both the ARM11MPCore and Cortex-A9MP. 28 */ 29 30 static inline int get_current_cpu(ARMMPTimerState *s) 31 { 32 if (current_cpu->cpu_index >= s->num_cpu) { 33 hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n", 34 s->num_cpu, current_cpu->cpu_index); 35 } 36 return current_cpu->cpu_index; 37 } 38 39 static inline void timerblock_update_irq(TimerBlock *tb) 40 { 41 qemu_set_irq(tb->irq, tb->status && (tb->control & 4)); 42 } 43 44 /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ 45 static inline uint32_t timerblock_scale(TimerBlock *tb) 46 { 47 return (((tb->control >> 8) & 0xff) + 1) * 10; 48 } 49 50 static void timerblock_reload(TimerBlock *tb, int restart) 51 { 52 if (tb->count == 0) { 53 return; 54 } 55 if (restart) { 56 tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 57 } 58 tb->tick += (int64_t)tb->count * timerblock_scale(tb); 59 timer_mod(tb->timer, tb->tick); 60 } 61 62 static void timerblock_tick(void *opaque) 63 { 64 TimerBlock *tb = (TimerBlock *)opaque; 65 tb->status = 1; 66 if (tb->control & 2) { 67 tb->count = tb->load; 68 timerblock_reload(tb, 0); 69 } else { 70 tb->count = 0; 71 } 72 timerblock_update_irq(tb); 73 } 74 75 static uint64_t timerblock_read(void *opaque, hwaddr addr, 76 unsigned size) 77 { 78 TimerBlock *tb = (TimerBlock *)opaque; 79 int64_t val; 80 switch (addr) { 81 case 0: /* Load */ 82 return tb->load; 83 case 4: /* Counter. */ 84 if (((tb->control & 1) == 0) || (tb->count == 0)) { 85 return 0; 86 } 87 /* Slow and ugly, but hopefully won't happen too often. */ 88 val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 89 val /= timerblock_scale(tb); 90 if (val < 0) { 91 val = 0; 92 } 93 return val; 94 case 8: /* Control. */ 95 return tb->control; 96 case 12: /* Interrupt status. */ 97 return tb->status; 98 default: 99 return 0; 100 } 101 } 102 103 static void timerblock_write(void *opaque, hwaddr addr, 104 uint64_t value, unsigned size) 105 { 106 TimerBlock *tb = (TimerBlock *)opaque; 107 int64_t old; 108 switch (addr) { 109 case 0: /* Load */ 110 tb->load = value; 111 /* Fall through. */ 112 case 4: /* Counter. */ 113 if ((tb->control & 1) && tb->count) { 114 /* Cancel the previous timer. */ 115 timer_del(tb->timer); 116 } 117 tb->count = value; 118 if (tb->control & 1) { 119 timerblock_reload(tb, 1); 120 } 121 break; 122 case 8: /* Control. */ 123 old = tb->control; 124 tb->control = value; 125 if (value & 1) { 126 if ((old & 1) && (tb->count != 0)) { 127 /* Do nothing if timer is ticking right now. */ 128 break; 129 } 130 if (tb->control & 2) { 131 tb->count = tb->load; 132 } 133 timerblock_reload(tb, 1); 134 } else if (old & 1) { 135 /* Shutdown the timer. */ 136 timer_del(tb->timer); 137 } 138 break; 139 case 12: /* Interrupt status. */ 140 tb->status &= ~value; 141 timerblock_update_irq(tb); 142 break; 143 } 144 } 145 146 /* Wrapper functions to implement the "read timer/watchdog for 147 * the current CPU" memory regions. 148 */ 149 static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, 150 unsigned size) 151 { 152 ARMMPTimerState *s = (ARMMPTimerState *)opaque; 153 int id = get_current_cpu(s); 154 return timerblock_read(&s->timerblock[id], addr, size); 155 } 156 157 static void arm_thistimer_write(void *opaque, hwaddr addr, 158 uint64_t value, unsigned size) 159 { 160 ARMMPTimerState *s = (ARMMPTimerState *)opaque; 161 int id = get_current_cpu(s); 162 timerblock_write(&s->timerblock[id], addr, value, size); 163 } 164 165 static const MemoryRegionOps arm_thistimer_ops = { 166 .read = arm_thistimer_read, 167 .write = arm_thistimer_write, 168 .valid = { 169 .min_access_size = 4, 170 .max_access_size = 4, 171 }, 172 .endianness = DEVICE_NATIVE_ENDIAN, 173 }; 174 175 static const MemoryRegionOps timerblock_ops = { 176 .read = timerblock_read, 177 .write = timerblock_write, 178 .valid = { 179 .min_access_size = 4, 180 .max_access_size = 4, 181 }, 182 .endianness = DEVICE_NATIVE_ENDIAN, 183 }; 184 185 static void timerblock_reset(TimerBlock *tb) 186 { 187 tb->count = 0; 188 tb->load = 0; 189 tb->control = 0; 190 tb->status = 0; 191 tb->tick = 0; 192 if (tb->timer) { 193 timer_del(tb->timer); 194 } 195 } 196 197 static void arm_mptimer_reset(DeviceState *dev) 198 { 199 ARMMPTimerState *s = ARM_MPTIMER(dev); 200 int i; 201 202 for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) { 203 timerblock_reset(&s->timerblock[i]); 204 } 205 } 206 207 static void arm_mptimer_init(Object *obj) 208 { 209 ARMMPTimerState *s = ARM_MPTIMER(obj); 210 211 memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s, 212 "arm_mptimer_timer", 0x20); 213 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); 214 } 215 216 static void arm_mptimer_realize(DeviceState *dev, Error **errp) 217 { 218 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 219 ARMMPTimerState *s = ARM_MPTIMER(dev); 220 int i; 221 222 if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) { 223 error_setg(errp, "num-cpu must be between 1 and %d", 224 ARM_MPTIMER_MAX_CPUS); 225 return; 226 } 227 /* We implement one timer block per CPU, and expose multiple MMIO regions: 228 * * region 0 is "timer for this core" 229 * * region 1 is "timer for core 0" 230 * * region 2 is "timer for core 1" 231 * and so on. 232 * The outgoing interrupt lines are 233 * * timer for core 0 234 * * timer for core 1 235 * and so on. 236 */ 237 for (i = 0; i < s->num_cpu; i++) { 238 TimerBlock *tb = &s->timerblock[i]; 239 tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb); 240 sysbus_init_irq(sbd, &tb->irq); 241 memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, 242 "arm_mptimer_timerblock", 0x20); 243 sysbus_init_mmio(sbd, &tb->iomem); 244 } 245 } 246 247 static const VMStateDescription vmstate_timerblock = { 248 .name = "arm_mptimer_timerblock", 249 .version_id = 2, 250 .minimum_version_id = 2, 251 .fields = (VMStateField[]) { 252 VMSTATE_UINT32(count, TimerBlock), 253 VMSTATE_UINT32(load, TimerBlock), 254 VMSTATE_UINT32(control, TimerBlock), 255 VMSTATE_UINT32(status, TimerBlock), 256 VMSTATE_INT64(tick, TimerBlock), 257 VMSTATE_TIMER_PTR(timer, TimerBlock), 258 VMSTATE_END_OF_LIST() 259 } 260 }; 261 262 static const VMStateDescription vmstate_arm_mptimer = { 263 .name = "arm_mptimer", 264 .version_id = 2, 265 .minimum_version_id = 2, 266 .fields = (VMStateField[]) { 267 VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu, 268 2, vmstate_timerblock, TimerBlock), 269 VMSTATE_END_OF_LIST() 270 } 271 }; 272 273 static Property arm_mptimer_properties[] = { 274 DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), 275 DEFINE_PROP_END_OF_LIST() 276 }; 277 278 static void arm_mptimer_class_init(ObjectClass *klass, void *data) 279 { 280 DeviceClass *dc = DEVICE_CLASS(klass); 281 282 dc->realize = arm_mptimer_realize; 283 dc->vmsd = &vmstate_arm_mptimer; 284 dc->reset = arm_mptimer_reset; 285 dc->props = arm_mptimer_properties; 286 } 287 288 static const TypeInfo arm_mptimer_info = { 289 .name = TYPE_ARM_MPTIMER, 290 .parent = TYPE_SYS_BUS_DEVICE, 291 .instance_size = sizeof(ARMMPTimerState), 292 .instance_init = arm_mptimer_init, 293 .class_init = arm_mptimer_class_init, 294 }; 295 296 static void arm_mptimer_register_types(void) 297 { 298 type_register_static(&arm_mptimer_info); 299 } 300 301 type_init(arm_mptimer_register_types) 302