1 /* 2 * Global peripheral timer block for ARM A9MP 3 * 4 * (C) 2013 Xilinx Inc. 5 * 6 * Written by François LEGAL 7 * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com> 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License 11 * as published by the Free Software Foundation; either version 12 * 2 of the License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License along 20 * with this program; if not, see <http://www.gnu.org/licenses/>. 21 */ 22 23 #include "qemu/osdep.h" 24 #include "hw/hw.h" 25 #include "hw/irq.h" 26 #include "hw/qdev-properties.h" 27 #include "hw/timer/a9gtimer.h" 28 #include "migration/vmstate.h" 29 #include "qapi/error.h" 30 #include "qemu/timer.h" 31 #include "qemu/bitops.h" 32 #include "qemu/log.h" 33 #include "qemu/module.h" 34 #include "hw/core/cpu.h" 35 #include "sysemu/qtest.h" 36 37 #ifndef A9_GTIMER_ERR_DEBUG 38 #define A9_GTIMER_ERR_DEBUG 0 39 #endif 40 41 #define DB_PRINT_L(level, ...) do { \ 42 if (A9_GTIMER_ERR_DEBUG > (level)) { \ 43 fprintf(stderr, ": %s: ", __func__); \ 44 fprintf(stderr, ## __VA_ARGS__); \ 45 } \ 46 } while (0) 47 48 #define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__) 49 50 static inline int a9_gtimer_get_current_cpu(A9GTimerState *s) 51 { 52 if (qtest_enabled()) { 53 return 0; 54 } 55 56 if (current_cpu->cpu_index >= s->num_cpu) { 57 hw_error("a9gtimer: num-cpu %d but this cpu is %d!\n", 58 s->num_cpu, current_cpu->cpu_index); 59 } 60 return current_cpu->cpu_index; 61 } 62 63 static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s) 64 { 65 uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT, 66 R_CONTROL_PRESCALER_LEN); 67 68 return (prescale + 1) * 10; 69 } 70 71 static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s) 72 { 73 A9GTimerUpdate ret; 74 75 ret.now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 76 ret.new = s->ref_counter + 77 (ret.now - s->cpu_ref_time) / a9_gtimer_get_conv(s); 78 return ret; 79 } 80 81 static void a9_gtimer_update(A9GTimerState *s, bool sync) 82 { 83 84 A9GTimerUpdate update = a9_gtimer_get_update(s); 85 int i; 86 int64_t next_cdiff = 0; 87 88 for (i = 0; i < s->num_cpu; ++i) { 89 A9GTimerPerCPU *gtb = &s->per_cpu[i]; 90 int64_t cdiff = 0; 91 92 if ((s->control & R_CONTROL_TIMER_ENABLE) && 93 (gtb->control & R_CONTROL_COMP_ENABLE)) { 94 /* R2p0+, where the compare function is >= */ 95 if (gtb->compare < update.new) { 96 DB_PRINT("Compare event happened for CPU %d\n", i); 97 gtb->status = 1; 98 if (gtb->control & R_CONTROL_AUTO_INCREMENT && gtb->inc) { 99 uint64_t inc = 100 QEMU_ALIGN_UP(update.new - gtb->compare, gtb->inc); 101 DB_PRINT("Auto incrementing timer compare by %" 102 PRId64 "\n", inc); 103 gtb->compare += inc; 104 } 105 } 106 cdiff = (int64_t)gtb->compare - (int64_t)update.new + 1; 107 if (cdiff > 0 && (cdiff < next_cdiff || !next_cdiff)) { 108 next_cdiff = cdiff; 109 } 110 } 111 112 qemu_set_irq(gtb->irq, 113 gtb->status && (gtb->control & R_CONTROL_IRQ_ENABLE)); 114 } 115 116 timer_del(s->timer); 117 if (next_cdiff) { 118 DB_PRINT("scheduling qemu_timer to fire again in %" 119 PRIx64 " cycles\n", next_cdiff); 120 timer_mod(s->timer, update.now + next_cdiff * a9_gtimer_get_conv(s)); 121 } 122 123 if (s->control & R_CONTROL_TIMER_ENABLE) { 124 s->counter = update.new; 125 } 126 127 if (sync) { 128 s->cpu_ref_time = update.now; 129 s->ref_counter = s->counter; 130 } 131 } 132 133 static void a9_gtimer_update_no_sync(void *opaque) 134 { 135 A9GTimerState *s = A9_GTIMER(opaque); 136 137 a9_gtimer_update(s, false); 138 } 139 140 static uint64_t a9_gtimer_read(void *opaque, hwaddr addr, unsigned size) 141 { 142 A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque; 143 A9GTimerState *s = gtb->parent; 144 A9GTimerUpdate update; 145 uint64_t ret = 0; 146 int shift = 0; 147 148 switch (addr) { 149 case R_COUNTER_HI: 150 shift = 32; 151 /* fallthrough */ 152 case R_COUNTER_LO: 153 update = a9_gtimer_get_update(s); 154 ret = extract64(update.new, shift, 32); 155 break; 156 case R_CONTROL: 157 ret = s->control | gtb->control; 158 break; 159 case R_INTERRUPT_STATUS: 160 ret = gtb->status; 161 break; 162 case R_COMPARATOR_HI: 163 shift = 32; 164 /* fallthrough */ 165 case R_COMPARATOR_LO: 166 ret = extract64(gtb->compare, shift, 32); 167 break; 168 case R_AUTO_INCREMENT: 169 ret = gtb->inc; 170 break; 171 default: 172 qemu_log_mask(LOG_GUEST_ERROR, "bad a9gtimer register: %x\n", 173 (unsigned)addr); 174 return 0; 175 } 176 177 DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, ret); 178 return ret; 179 } 180 181 static void a9_gtimer_write(void *opaque, hwaddr addr, uint64_t value, 182 unsigned size) 183 { 184 A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque; 185 A9GTimerState *s = gtb->parent; 186 int shift = 0; 187 188 DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, value); 189 190 switch (addr) { 191 case R_COUNTER_HI: 192 shift = 32; 193 /* fallthrough */ 194 case R_COUNTER_LO: 195 /* 196 * Keep it simple - ARM docco explicitly says to disable timer before 197 * modding it, so don't bother trying to do all the difficult on the fly 198 * timer modifications - (if they even work in real hardware??). 199 */ 200 if (s->control & R_CONTROL_TIMER_ENABLE) { 201 qemu_log_mask(LOG_GUEST_ERROR, "Cannot mod running ARM gtimer\n"); 202 return; 203 } 204 s->counter = deposit64(s->counter, shift, 32, value); 205 return; 206 case R_CONTROL: 207 a9_gtimer_update(s, (value ^ s->control) & R_CONTROL_NEEDS_SYNC); 208 gtb->control = value & R_CONTROL_BANKED; 209 s->control = value & ~R_CONTROL_BANKED; 210 break; 211 case R_INTERRUPT_STATUS: 212 a9_gtimer_update(s, false); 213 gtb->status &= ~value; 214 break; 215 case R_COMPARATOR_HI: 216 shift = 32; 217 /* fallthrough */ 218 case R_COMPARATOR_LO: 219 a9_gtimer_update(s, false); 220 gtb->compare = deposit64(gtb->compare, shift, 32, value); 221 break; 222 case R_AUTO_INCREMENT: 223 gtb->inc = value; 224 return; 225 default: 226 return; 227 } 228 229 a9_gtimer_update(s, false); 230 } 231 232 /* Wrapper functions to implement the "read global timer for 233 * the current CPU" memory regions. 234 */ 235 static uint64_t a9_gtimer_this_read(void *opaque, hwaddr addr, 236 unsigned size) 237 { 238 A9GTimerState *s = A9_GTIMER(opaque); 239 int id = a9_gtimer_get_current_cpu(s); 240 241 /* no \n so concatenates with message from read fn */ 242 DB_PRINT("CPU:%d:", id); 243 244 return a9_gtimer_read(&s->per_cpu[id], addr, size); 245 } 246 247 static void a9_gtimer_this_write(void *opaque, hwaddr addr, 248 uint64_t value, unsigned size) 249 { 250 A9GTimerState *s = A9_GTIMER(opaque); 251 int id = a9_gtimer_get_current_cpu(s); 252 253 /* no \n so concatenates with message from write fn */ 254 DB_PRINT("CPU:%d:", id); 255 256 a9_gtimer_write(&s->per_cpu[id], addr, value, size); 257 } 258 259 static const MemoryRegionOps a9_gtimer_this_ops = { 260 .read = a9_gtimer_this_read, 261 .write = a9_gtimer_this_write, 262 .valid = { 263 .min_access_size = 4, 264 .max_access_size = 4, 265 }, 266 .endianness = DEVICE_NATIVE_ENDIAN, 267 }; 268 269 static const MemoryRegionOps a9_gtimer_ops = { 270 .read = a9_gtimer_read, 271 .write = a9_gtimer_write, 272 .valid = { 273 .min_access_size = 4, 274 .max_access_size = 4, 275 }, 276 .endianness = DEVICE_NATIVE_ENDIAN, 277 }; 278 279 static void a9_gtimer_reset(DeviceState *dev) 280 { 281 A9GTimerState *s = A9_GTIMER(dev); 282 int i; 283 284 s->counter = 0; 285 s->control = 0; 286 287 for (i = 0; i < s->num_cpu; i++) { 288 A9GTimerPerCPU *gtb = &s->per_cpu[i]; 289 290 gtb->control = 0; 291 gtb->status = 0; 292 gtb->compare = 0; 293 gtb->inc = 0; 294 } 295 a9_gtimer_update(s, false); 296 } 297 298 static void a9_gtimer_realize(DeviceState *dev, Error **errp) 299 { 300 A9GTimerState *s = A9_GTIMER(dev); 301 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 302 int i; 303 304 if (s->num_cpu < 1 || s->num_cpu > A9_GTIMER_MAX_CPUS) { 305 error_setg(errp, "%s: num-cpu must be between 1 and %d", 306 __func__, A9_GTIMER_MAX_CPUS); 307 return; 308 } 309 310 memory_region_init_io(&s->iomem, OBJECT(dev), &a9_gtimer_this_ops, s, 311 "a9gtimer shared", 0x20); 312 sysbus_init_mmio(sbd, &s->iomem); 313 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s); 314 315 for (i = 0; i < s->num_cpu; i++) { 316 A9GTimerPerCPU *gtb = &s->per_cpu[i]; 317 318 gtb->parent = s; 319 sysbus_init_irq(sbd, >b->irq); 320 memory_region_init_io(>b->iomem, OBJECT(dev), &a9_gtimer_ops, gtb, 321 "a9gtimer per cpu", 0x20); 322 sysbus_init_mmio(sbd, >b->iomem); 323 } 324 } 325 326 static bool vmstate_a9_gtimer_control_needed(void *opaque) 327 { 328 A9GTimerState *s = opaque; 329 return s->control != 0; 330 } 331 332 static const VMStateDescription vmstate_a9_gtimer_per_cpu = { 333 .name = "arm.cortex-a9-global-timer.percpu", 334 .version_id = 1, 335 .minimum_version_id = 1, 336 .fields = (const VMStateField[]) { 337 VMSTATE_UINT32(control, A9GTimerPerCPU), 338 VMSTATE_UINT64(compare, A9GTimerPerCPU), 339 VMSTATE_UINT32(status, A9GTimerPerCPU), 340 VMSTATE_UINT32(inc, A9GTimerPerCPU), 341 VMSTATE_END_OF_LIST() 342 } 343 }; 344 345 static const VMStateDescription vmstate_a9_gtimer_control = { 346 .name = "arm.cortex-a9-global-timer.control", 347 .version_id = 1, 348 .minimum_version_id = 1, 349 .needed = vmstate_a9_gtimer_control_needed, 350 .fields = (const VMStateField[]) { 351 VMSTATE_UINT32(control, A9GTimerState), 352 VMSTATE_END_OF_LIST() 353 } 354 }; 355 356 static const VMStateDescription vmstate_a9_gtimer = { 357 .name = "arm.cortex-a9-global-timer", 358 .version_id = 1, 359 .minimum_version_id = 1, 360 .fields = (const VMStateField[]) { 361 VMSTATE_TIMER_PTR(timer, A9GTimerState), 362 VMSTATE_UINT64(counter, A9GTimerState), 363 VMSTATE_UINT64(ref_counter, A9GTimerState), 364 VMSTATE_UINT64(cpu_ref_time, A9GTimerState), 365 VMSTATE_STRUCT_VARRAY_UINT32(per_cpu, A9GTimerState, num_cpu, 366 1, vmstate_a9_gtimer_per_cpu, 367 A9GTimerPerCPU), 368 VMSTATE_END_OF_LIST() 369 }, 370 .subsections = (const VMStateDescription * const []) { 371 &vmstate_a9_gtimer_control, 372 NULL 373 } 374 }; 375 376 static Property a9_gtimer_properties[] = { 377 DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0), 378 DEFINE_PROP_END_OF_LIST() 379 }; 380 381 static void a9_gtimer_class_init(ObjectClass *klass, void *data) 382 { 383 DeviceClass *dc = DEVICE_CLASS(klass); 384 385 dc->realize = a9_gtimer_realize; 386 dc->vmsd = &vmstate_a9_gtimer; 387 dc->reset = a9_gtimer_reset; 388 device_class_set_props(dc, a9_gtimer_properties); 389 } 390 391 static const TypeInfo a9_gtimer_info = { 392 .name = TYPE_A9_GTIMER, 393 .parent = TYPE_SYS_BUS_DEVICE, 394 .instance_size = sizeof(A9GTimerState), 395 .class_init = a9_gtimer_class_init, 396 }; 397 398 static void a9_gtimer_register_types(void) 399 { 400 type_register_static(&a9_gtimer_info); 401 } 402 403 type_init(a9_gtimer_register_types) 404