1 /* 2 * ARM Nested Vectored Interrupt Controller 3 * 4 * Copyright (c) 2006-2007 CodeSourcery. 5 * Written by Paul Brook 6 * 7 * This code is licenced under the GPL. 8 * 9 * The ARMv7M System controller is fairly tightly tied in with the 10 * NVIC. Much of that is also implemented here. 11 */ 12 13 #include "sysbus.h" 14 #include "qemu-timer.h" 15 #include "arm-misc.h" 16 17 /* 32 internal lines (16 used for system exceptions) plus 64 external 18 interrupt lines. */ 19 #define GIC_NIRQ 96 20 #define NCPU 1 21 #define NVIC 1 22 23 /* Only a single "CPU" interface is present. */ 24 static inline int 25 gic_get_current_cpu(void) 26 { 27 return 0; 28 } 29 30 static uint32_t nvic_readl(void *opaque, uint32_t offset); 31 static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); 32 33 #include "arm_gic.c" 34 35 typedef struct { 36 gic_state gic; 37 struct { 38 uint32_t control; 39 uint32_t reload; 40 int64_t tick; 41 QEMUTimer *timer; 42 } systick; 43 } nvic_state; 44 45 /* qemu timers run at 1GHz. We want something closer to 1MHz. */ 46 #define SYSTICK_SCALE 1000ULL 47 48 #define SYSTICK_ENABLE (1 << 0) 49 #define SYSTICK_TICKINT (1 << 1) 50 #define SYSTICK_CLKSOURCE (1 << 2) 51 #define SYSTICK_COUNTFLAG (1 << 16) 52 53 int system_clock_scale; 54 55 /* Conversion factor from qemu timer to SysTick frequencies. */ 56 static inline int64_t systick_scale(nvic_state *s) 57 { 58 if (s->systick.control & SYSTICK_CLKSOURCE) 59 return system_clock_scale; 60 else 61 return 1000; 62 } 63 64 static void systick_reload(nvic_state *s, int reset) 65 { 66 if (reset) 67 s->systick.tick = qemu_get_clock_ns(vm_clock); 68 s->systick.tick += (s->systick.reload + 1) * systick_scale(s); 69 qemu_mod_timer(s->systick.timer, s->systick.tick); 70 } 71 72 static void systick_timer_tick(void * opaque) 73 { 74 nvic_state *s = (nvic_state *)opaque; 75 s->systick.control |= SYSTICK_COUNTFLAG; 76 if (s->systick.control & SYSTICK_TICKINT) { 77 /* Trigger the interrupt. */ 78 armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); 79 } 80 if (s->systick.reload == 0) { 81 s->systick.control &= ~SYSTICK_ENABLE; 82 } else { 83 systick_reload(s, 0); 84 } 85 } 86 87 /* The external routines use the hardware vector numbering, ie. the first 88 IRQ is #16. The internal GIC routines use #32 as the first IRQ. */ 89 void armv7m_nvic_set_pending(void *opaque, int irq) 90 { 91 nvic_state *s = (nvic_state *)opaque; 92 if (irq >= 16) 93 irq += 16; 94 gic_set_pending_private(&s->gic, 0, irq); 95 } 96 97 /* Make pending IRQ active. */ 98 int armv7m_nvic_acknowledge_irq(void *opaque) 99 { 100 nvic_state *s = (nvic_state *)opaque; 101 uint32_t irq; 102 103 irq = gic_acknowledge_irq(&s->gic, 0); 104 if (irq == 1023) 105 hw_error("Interrupt but no vector\n"); 106 if (irq >= 32) 107 irq -= 16; 108 return irq; 109 } 110 111 void armv7m_nvic_complete_irq(void *opaque, int irq) 112 { 113 nvic_state *s = (nvic_state *)opaque; 114 if (irq >= 16) 115 irq += 16; 116 gic_complete_irq(&s->gic, 0, irq); 117 } 118 119 static uint32_t nvic_readl(void *opaque, uint32_t offset) 120 { 121 nvic_state *s = (nvic_state *)opaque; 122 uint32_t val; 123 int irq; 124 125 switch (offset) { 126 case 4: /* Interrupt Control Type. */ 127 return (GIC_NIRQ / 32) - 1; 128 case 0x10: /* SysTick Control and Status. */ 129 val = s->systick.control; 130 s->systick.control &= ~SYSTICK_COUNTFLAG; 131 return val; 132 case 0x14: /* SysTick Reload Value. */ 133 return s->systick.reload; 134 case 0x18: /* SysTick Current Value. */ 135 { 136 int64_t t; 137 if ((s->systick.control & SYSTICK_ENABLE) == 0) 138 return 0; 139 t = qemu_get_clock(vm_clock); 140 if (t >= s->systick.tick) 141 return 0; 142 val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1; 143 /* The interrupt in triggered when the timer reaches zero. 144 However the counter is not reloaded until the next clock 145 tick. This is a hack to return zero during the first tick. */ 146 if (val > s->systick.reload) 147 val = 0; 148 return val; 149 } 150 case 0x1c: /* SysTick Calibration Value. */ 151 return 10000; 152 case 0xd00: /* CPUID Base. */ 153 return cpu_single_env->cp15.c0_cpuid; 154 case 0xd04: /* Interrypt Control State. */ 155 /* VECTACTIVE */ 156 val = s->gic.running_irq[0]; 157 if (val == 1023) { 158 val = 0; 159 } else if (val >= 32) { 160 val -= 16; 161 } 162 /* RETTOBASE */ 163 if (s->gic.running_irq[0] == 1023 164 || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) { 165 val |= (1 << 11); 166 } 167 /* VECTPENDING */ 168 if (s->gic.current_pending[0] != 1023) 169 val |= (s->gic.current_pending[0] << 12); 170 /* ISRPENDING */ 171 for (irq = 32; irq < GIC_NIRQ; irq++) { 172 if (s->gic.irq_state[irq].pending) { 173 val |= (1 << 22); 174 break; 175 } 176 } 177 /* PENDSTSET */ 178 if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending) 179 val |= (1 << 26); 180 /* PENDSVSET */ 181 if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending) 182 val |= (1 << 28); 183 /* NMIPENDSET */ 184 if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending) 185 val |= (1 << 31); 186 return val; 187 case 0xd08: /* Vector Table Offset. */ 188 return cpu_single_env->v7m.vecbase; 189 case 0xd0c: /* Application Interrupt/Reset Control. */ 190 return 0xfa05000; 191 case 0xd10: /* System Control. */ 192 /* TODO: Implement SLEEPONEXIT. */ 193 return 0; 194 case 0xd14: /* Configuration Control. */ 195 /* TODO: Implement Configuration Control bits. */ 196 return 0; 197 case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ 198 irq = offset - 0xd14; 199 val = 0; 200 val = s->gic.priority1[irq++][0]; 201 val = s->gic.priority1[irq++][0] << 8; 202 val = s->gic.priority1[irq++][0] << 16; 203 val = s->gic.priority1[irq][0] << 24; 204 return val; 205 case 0xd24: /* System Handler Status. */ 206 val = 0; 207 if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); 208 if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1); 209 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); 210 if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7); 211 if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); 212 if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10); 213 if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); 214 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12); 215 if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); 216 if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14); 217 if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); 218 if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16); 219 if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); 220 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); 221 return val; 222 case 0xd28: /* Configurable Fault Status. */ 223 /* TODO: Implement Fault Status. */ 224 hw_error("Not implemented: Configurable Fault Status."); 225 return 0; 226 case 0xd2c: /* Hard Fault Status. */ 227 case 0xd30: /* Debug Fault Status. */ 228 case 0xd34: /* Mem Manage Address. */ 229 case 0xd38: /* Bus Fault Address. */ 230 case 0xd3c: /* Aux Fault Status. */ 231 /* TODO: Implement fault status registers. */ 232 goto bad_reg; 233 case 0xd40: /* PFR0. */ 234 return 0x00000030; 235 case 0xd44: /* PRF1. */ 236 return 0x00000200; 237 case 0xd48: /* DFR0. */ 238 return 0x00100000; 239 case 0xd4c: /* AFR0. */ 240 return 0x00000000; 241 case 0xd50: /* MMFR0. */ 242 return 0x00000030; 243 case 0xd54: /* MMFR1. */ 244 return 0x00000000; 245 case 0xd58: /* MMFR2. */ 246 return 0x00000000; 247 case 0xd5c: /* MMFR3. */ 248 return 0x00000000; 249 case 0xd60: /* ISAR0. */ 250 return 0x01141110; 251 case 0xd64: /* ISAR1. */ 252 return 0x02111000; 253 case 0xd68: /* ISAR2. */ 254 return 0x21112231; 255 case 0xd6c: /* ISAR3. */ 256 return 0x01111110; 257 case 0xd70: /* ISAR4. */ 258 return 0x01310102; 259 /* TODO: Implement debug registers. */ 260 default: 261 bad_reg: 262 hw_error("NVIC: Bad read offset 0x%x\n", offset); 263 } 264 } 265 266 static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) 267 { 268 nvic_state *s = (nvic_state *)opaque; 269 uint32_t oldval; 270 switch (offset) { 271 case 0x10: /* SysTick Control and Status. */ 272 oldval = s->systick.control; 273 s->systick.control &= 0xfffffff8; 274 s->systick.control |= value & 7; 275 if ((oldval ^ value) & SYSTICK_ENABLE) { 276 int64_t now = qemu_get_clock(vm_clock); 277 if (value & SYSTICK_ENABLE) { 278 if (s->systick.tick) { 279 s->systick.tick += now; 280 qemu_mod_timer(s->systick.timer, s->systick.tick); 281 } else { 282 systick_reload(s, 1); 283 } 284 } else { 285 qemu_del_timer(s->systick.timer); 286 s->systick.tick -= now; 287 if (s->systick.tick < 0) 288 s->systick.tick = 0; 289 } 290 } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { 291 /* This is a hack. Force the timer to be reloaded 292 when the reference clock is changed. */ 293 systick_reload(s, 1); 294 } 295 break; 296 case 0x14: /* SysTick Reload Value. */ 297 s->systick.reload = value; 298 break; 299 case 0x18: /* SysTick Current Value. Writes reload the timer. */ 300 systick_reload(s, 1); 301 s->systick.control &= ~SYSTICK_COUNTFLAG; 302 break; 303 case 0xd04: /* Interrupt Control State. */ 304 if (value & (1 << 31)) { 305 armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI); 306 } 307 if (value & (1 << 28)) { 308 armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); 309 } else if (value & (1 << 27)) { 310 s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0; 311 gic_update(&s->gic); 312 } 313 if (value & (1 << 26)) { 314 armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); 315 } else if (value & (1 << 25)) { 316 s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; 317 gic_update(&s->gic); 318 } 319 break; 320 case 0xd08: /* Vector Table Offset. */ 321 cpu_single_env->v7m.vecbase = value & 0xffffff80; 322 break; 323 case 0xd0c: /* Application Interrupt/Reset Control. */ 324 if ((value >> 16) == 0x05fa) { 325 if (value & 2) { 326 hw_error("VECTCLRACTIVE not implemented"); 327 } 328 if (value & 5) { 329 hw_error("System reset"); 330 } 331 } 332 break; 333 case 0xd10: /* System Control. */ 334 case 0xd14: /* Configuration Control. */ 335 /* TODO: Implement control registers. */ 336 goto bad_reg; 337 case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ 338 { 339 int irq; 340 irq = offset - 0xd14; 341 s->gic.priority1[irq++][0] = value & 0xff; 342 s->gic.priority1[irq++][0] = (value >> 8) & 0xff; 343 s->gic.priority1[irq++][0] = (value >> 16) & 0xff; 344 s->gic.priority1[irq][0] = (value >> 24) & 0xff; 345 gic_update(&s->gic); 346 } 347 break; 348 case 0xd24: /* System Handler Control. */ 349 /* TODO: Real hardware allows you to set/clear the active bits 350 under some circumstances. We don't implement this. */ 351 s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0; 352 s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0; 353 s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0; 354 break; 355 case 0xd28: /* Configurable Fault Status. */ 356 case 0xd2c: /* Hard Fault Status. */ 357 case 0xd30: /* Debug Fault Status. */ 358 case 0xd34: /* Mem Manage Address. */ 359 case 0xd38: /* Bus Fault Address. */ 360 case 0xd3c: /* Aux Fault Status. */ 361 goto bad_reg; 362 default: 363 bad_reg: 364 hw_error("NVIC: Bad write offset 0x%x\n", offset); 365 } 366 } 367 368 static void nvic_save(QEMUFile *f, void *opaque) 369 { 370 nvic_state *s = (nvic_state *)opaque; 371 372 qemu_put_be32(f, s->systick.control); 373 qemu_put_be32(f, s->systick.reload); 374 qemu_put_be64(f, s->systick.tick); 375 qemu_put_timer(f, s->systick.timer); 376 } 377 378 static int nvic_load(QEMUFile *f, void *opaque, int version_id) 379 { 380 nvic_state *s = (nvic_state *)opaque; 381 382 if (version_id != 1) 383 return -EINVAL; 384 385 s->systick.control = qemu_get_be32(f); 386 s->systick.reload = qemu_get_be32(f); 387 s->systick.tick = qemu_get_be64(f); 388 qemu_get_timer(f, s->systick.timer); 389 390 return 0; 391 } 392 393 static void armv7m_nvic_init(SysBusDevice *dev) 394 { 395 nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); 396 397 gic_init(&s->gic); 398 cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype); 399 s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); 400 register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); 401 } 402 403 static void armv7m_nvic_register_devices(void) 404 { 405 sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init); 406 } 407 408 device_init(armv7m_nvic_register_devices) 409