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