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 "qemu/osdep.h" 23 #include "hw/ptimer.h" 24 #include "hw/timer/arm_mptimer.h" 25 #include "qapi/error.h" 26 #include "qemu/main-loop.h" 27 #include "qemu/module.h" 28 #include "qom/cpu.h" 29 30 #define PTIMER_POLICY \ 31 (PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | \ 32 PTIMER_POLICY_CONTINUOUS_TRIGGER | \ 33 PTIMER_POLICY_NO_IMMEDIATE_TRIGGER | \ 34 PTIMER_POLICY_NO_IMMEDIATE_RELOAD | \ 35 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN) 36 37 /* This device implements the per-cpu private timer and watchdog block 38 * which is used in both the ARM11MPCore and Cortex-A9MP. 39 */ 40 41 static inline int get_current_cpu(ARMMPTimerState *s) 42 { 43 int cpu_id = current_cpu ? current_cpu->cpu_index : 0; 44 45 if (cpu_id >= s->num_cpu) { 46 hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n", 47 s->num_cpu, cpu_id); 48 } 49 50 return cpu_id; 51 } 52 53 static inline void timerblock_update_irq(TimerBlock *tb) 54 { 55 qemu_set_irq(tb->irq, tb->status && (tb->control & 4)); 56 } 57 58 /* Return conversion factor from mpcore timer ticks to qemu timer ticks. */ 59 static inline uint32_t timerblock_scale(uint32_t control) 60 { 61 return (((control >> 8) & 0xff) + 1) * 10; 62 } 63 64 static inline void timerblock_set_count(struct ptimer_state *timer, 65 uint32_t control, uint64_t *count) 66 { 67 /* PTimer would trigger interrupt for periodic timer when counter set 68 * to 0, MPtimer under certain condition only. 69 */ 70 if ((control & 3) == 3 && (control & 0xff00) == 0 && *count == 0) { 71 *count = ptimer_get_limit(timer); 72 } 73 ptimer_set_count(timer, *count); 74 } 75 76 static inline void timerblock_run(struct ptimer_state *timer, 77 uint32_t control, uint32_t load) 78 { 79 if ((control & 1) && ((control & 0xff00) || load != 0)) { 80 ptimer_run(timer, !(control & 2)); 81 } 82 } 83 84 static void timerblock_tick(void *opaque) 85 { 86 TimerBlock *tb = (TimerBlock *)opaque; 87 /* Periodic timer with load = 0 and prescaler != 0 would re-trigger 88 * IRQ after one period, otherwise it either stops or wraps around. 89 */ 90 if ((tb->control & 2) && (tb->control & 0xff00) == 0 && 91 ptimer_get_limit(tb->timer) == 0) { 92 ptimer_stop(tb->timer); 93 } 94 tb->status = 1; 95 timerblock_update_irq(tb); 96 } 97 98 static uint64_t timerblock_read(void *opaque, hwaddr addr, 99 unsigned size) 100 { 101 TimerBlock *tb = (TimerBlock *)opaque; 102 switch (addr) { 103 case 0: /* Load */ 104 return ptimer_get_limit(tb->timer); 105 case 4: /* Counter. */ 106 return ptimer_get_count(tb->timer); 107 case 8: /* Control. */ 108 return tb->control; 109 case 12: /* Interrupt status. */ 110 return tb->status; 111 default: 112 return 0; 113 } 114 } 115 116 static void timerblock_write(void *opaque, hwaddr addr, 117 uint64_t value, unsigned size) 118 { 119 TimerBlock *tb = (TimerBlock *)opaque; 120 uint32_t control = tb->control; 121 switch (addr) { 122 case 0: /* Load */ 123 /* Setting load to 0 stops the timer without doing the tick if 124 * prescaler = 0. 125 */ 126 if ((control & 1) && (control & 0xff00) == 0 && value == 0) { 127 ptimer_stop(tb->timer); 128 } 129 ptimer_set_limit(tb->timer, value, 1); 130 timerblock_run(tb->timer, control, value); 131 break; 132 case 4: /* Counter. */ 133 /* Setting counter to 0 stops the one-shot timer, or periodic with 134 * load = 0, without doing the tick if prescaler = 0. 135 */ 136 if ((control & 1) && (control & 0xff00) == 0 && value == 0 && 137 (!(control & 2) || ptimer_get_limit(tb->timer) == 0)) { 138 ptimer_stop(tb->timer); 139 } 140 timerblock_set_count(tb->timer, control, &value); 141 timerblock_run(tb->timer, control, value); 142 break; 143 case 8: /* Control. */ 144 if ((control & 3) != (value & 3)) { 145 ptimer_stop(tb->timer); 146 } 147 if ((control & 0xff00) != (value & 0xff00)) { 148 ptimer_set_period(tb->timer, timerblock_scale(value)); 149 } 150 if (value & 1) { 151 uint64_t count = ptimer_get_count(tb->timer); 152 /* Re-load periodic timer counter if needed. */ 153 if ((value & 2) && count == 0) { 154 timerblock_set_count(tb->timer, value, &count); 155 } 156 timerblock_run(tb->timer, value, count); 157 } 158 tb->control = value; 159 break; 160 case 12: /* Interrupt status. */ 161 tb->status &= ~value; 162 timerblock_update_irq(tb); 163 break; 164 } 165 } 166 167 /* Wrapper functions to implement the "read timer/watchdog for 168 * the current CPU" memory regions. 169 */ 170 static uint64_t arm_thistimer_read(void *opaque, hwaddr addr, 171 unsigned size) 172 { 173 ARMMPTimerState *s = (ARMMPTimerState *)opaque; 174 int id = get_current_cpu(s); 175 return timerblock_read(&s->timerblock[id], addr, size); 176 } 177 178 static void arm_thistimer_write(void *opaque, hwaddr addr, 179 uint64_t value, unsigned size) 180 { 181 ARMMPTimerState *s = (ARMMPTimerState *)opaque; 182 int id = get_current_cpu(s); 183 timerblock_write(&s->timerblock[id], addr, value, size); 184 } 185 186 static const MemoryRegionOps arm_thistimer_ops = { 187 .read = arm_thistimer_read, 188 .write = arm_thistimer_write, 189 .valid = { 190 .min_access_size = 4, 191 .max_access_size = 4, 192 }, 193 .endianness = DEVICE_NATIVE_ENDIAN, 194 }; 195 196 static const MemoryRegionOps timerblock_ops = { 197 .read = timerblock_read, 198 .write = timerblock_write, 199 .valid = { 200 .min_access_size = 4, 201 .max_access_size = 4, 202 }, 203 .endianness = DEVICE_NATIVE_ENDIAN, 204 }; 205 206 static void timerblock_reset(TimerBlock *tb) 207 { 208 tb->control = 0; 209 tb->status = 0; 210 if (tb->timer) { 211 ptimer_stop(tb->timer); 212 ptimer_set_limit(tb->timer, 0, 1); 213 ptimer_set_period(tb->timer, timerblock_scale(0)); 214 } 215 } 216 217 static void arm_mptimer_reset(DeviceState *dev) 218 { 219 ARMMPTimerState *s = ARM_MPTIMER(dev); 220 int i; 221 222 for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) { 223 timerblock_reset(&s->timerblock[i]); 224 } 225 } 226 227 static void arm_mptimer_init(Object *obj) 228 { 229 ARMMPTimerState *s = ARM_MPTIMER(obj); 230 231 memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s, 232 "arm_mptimer_timer", 0x20); 233 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); 234 } 235 236 static void arm_mptimer_realize(DeviceState *dev, Error **errp) 237 { 238 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 239 ARMMPTimerState *s = ARM_MPTIMER(dev); 240 int i; 241 242 if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) { 243 error_setg(errp, "num-cpu must be between 1 and %d", 244 ARM_MPTIMER_MAX_CPUS); 245 return; 246 } 247 /* We implement one timer block per CPU, and expose multiple MMIO regions: 248 * * region 0 is "timer for this core" 249 * * region 1 is "timer for core 0" 250 * * region 2 is "timer for core 1" 251 * and so on. 252 * The outgoing interrupt lines are 253 * * timer for core 0 254 * * timer for core 1 255 * and so on. 256 */ 257 for (i = 0; i < s->num_cpu; i++) { 258 TimerBlock *tb = &s->timerblock[i]; 259 QEMUBH *bh = qemu_bh_new(timerblock_tick, tb); 260 tb->timer = ptimer_init(bh, PTIMER_POLICY); 261 sysbus_init_irq(sbd, &tb->irq); 262 memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, 263 "arm_mptimer_timerblock", 0x20); 264 sysbus_init_mmio(sbd, &tb->iomem); 265 } 266 } 267 268 static const VMStateDescription vmstate_timerblock = { 269 .name = "arm_mptimer_timerblock", 270 .version_id = 3, 271 .minimum_version_id = 3, 272 .fields = (VMStateField[]) { 273 VMSTATE_UINT32(control, TimerBlock), 274 VMSTATE_UINT32(status, TimerBlock), 275 VMSTATE_PTIMER(timer, TimerBlock), 276 VMSTATE_END_OF_LIST() 277 } 278 }; 279 280 static const VMStateDescription vmstate_arm_mptimer = { 281 .name = "arm_mptimer", 282 .version_id = 3, 283 .minimum_version_id = 3, 284 .fields = (VMStateField[]) { 285 VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu, 286 3, vmstate_timerblock, TimerBlock), 287 VMSTATE_END_OF_LIST() 288 } 289 }; 290 291 static Property arm_mptimer_properties[] = { 292 DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), 293 DEFINE_PROP_END_OF_LIST() 294 }; 295 296 static void arm_mptimer_class_init(ObjectClass *klass, void *data) 297 { 298 DeviceClass *dc = DEVICE_CLASS(klass); 299 300 dc->realize = arm_mptimer_realize; 301 dc->vmsd = &vmstate_arm_mptimer; 302 dc->reset = arm_mptimer_reset; 303 dc->props = arm_mptimer_properties; 304 } 305 306 static const TypeInfo arm_mptimer_info = { 307 .name = TYPE_ARM_MPTIMER, 308 .parent = TYPE_SYS_BUS_DEVICE, 309 .instance_size = sizeof(ARMMPTimerState), 310 .instance_init = arm_mptimer_init, 311 .class_init = arm_mptimer_class_init, 312 }; 313 314 static void arm_mptimer_register_types(void) 315 { 316 type_register_static(&arm_mptimer_info); 317 } 318 319 type_init(arm_mptimer_register_types) 320