2 * ARM Nested Vectored Interrupt Controller
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
9 * The ARMv7M System controller is fairly tightly tied in with the
10 * NVIC. Much of that is also implemented here.
14 #include "qemu-timer.h"
16 #include "exec-memory.h"
20 static uint32_t nvic_readl(void *opaque
, uint32_t offset
);
21 static void nvic_writel(void *opaque
, uint32_t offset
, uint32_t value
);
33 MemoryRegion sysregmem
;
34 MemoryRegion gic_iomem_alias
;
35 MemoryRegion container
;
39 static const uint8_t nvic_id
[] = {
40 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
43 /* qemu timers run at 1GHz. We want something closer to 1MHz. */
44 #define SYSTICK_SCALE 1000ULL
46 #define SYSTICK_ENABLE (1 << 0)
47 #define SYSTICK_TICKINT (1 << 1)
48 #define SYSTICK_CLKSOURCE (1 << 2)
49 #define SYSTICK_COUNTFLAG (1 << 16)
51 int system_clock_scale
;
53 /* Conversion factor from qemu timer to SysTick frequencies. */
54 static inline int64_t systick_scale(nvic_state
*s
)
56 if (s
->systick
.control
& SYSTICK_CLKSOURCE
)
57 return system_clock_scale
;
62 static void systick_reload(nvic_state
*s
, int reset
)
65 s
->systick
.tick
= qemu_get_clock_ns(vm_clock
);
66 s
->systick
.tick
+= (s
->systick
.reload
+ 1) * systick_scale(s
);
67 qemu_mod_timer(s
->systick
.timer
, s
->systick
.tick
);
70 static void systick_timer_tick(void * opaque
)
72 nvic_state
*s
= (nvic_state
*)opaque
;
73 s
->systick
.control
|= SYSTICK_COUNTFLAG
;
74 if (s
->systick
.control
& SYSTICK_TICKINT
) {
75 /* Trigger the interrupt. */
76 armv7m_nvic_set_pending(s
, ARMV7M_EXCP_SYSTICK
);
78 if (s
->systick
.reload
== 0) {
79 s
->systick
.control
&= ~SYSTICK_ENABLE
;
85 static void systick_reset(nvic_state
*s
)
87 s
->systick
.control
= 0;
88 s
->systick
.reload
= 0;
90 qemu_del_timer(s
->systick
.timer
);
93 /* The external routines use the hardware vector numbering, ie. the first
94 IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
95 void armv7m_nvic_set_pending(void *opaque
, int irq
)
97 nvic_state
*s
= (nvic_state
*)opaque
;
100 gic_set_pending_private(&s
->gic
, 0, irq
);
103 /* Make pending IRQ active. */
104 int armv7m_nvic_acknowledge_irq(void *opaque
)
106 nvic_state
*s
= (nvic_state
*)opaque
;
109 irq
= gic_acknowledge_irq(&s
->gic
, 0);
111 hw_error("Interrupt but no vector\n");
117 void armv7m_nvic_complete_irq(void *opaque
, int irq
)
119 nvic_state
*s
= (nvic_state
*)opaque
;
122 gic_complete_irq(&s
->gic
, 0, irq
);
125 static uint32_t nvic_readl(void *opaque
, uint32_t offset
)
127 nvic_state
*s
= (nvic_state
*)opaque
;
132 case 4: /* Interrupt Control Type. */
133 return (s
->num_irq
/ 32) - 1;
134 case 0x10: /* SysTick Control and Status. */
135 val
= s
->systick
.control
;
136 s
->systick
.control
&= ~SYSTICK_COUNTFLAG
;
138 case 0x14: /* SysTick Reload Value. */
139 return s
->systick
.reload
;
140 case 0x18: /* SysTick Current Value. */
143 if ((s
->systick
.control
& SYSTICK_ENABLE
) == 0)
145 t
= qemu_get_clock_ns(vm_clock
);
146 if (t
>= s
->systick
.tick
)
148 val
= ((s
->systick
.tick
- (t
+ 1)) / systick_scale(s
)) + 1;
149 /* The interrupt in triggered when the timer reaches zero.
150 However the counter is not reloaded until the next clock
151 tick. This is a hack to return zero during the first tick. */
152 if (val
> s
->systick
.reload
)
156 case 0x1c: /* SysTick Calibration Value. */
158 case 0xd00: /* CPUID Base. */
159 return cpu_single_env
->cp15
.c0_cpuid
;
160 case 0xd04: /* Interrypt Control State. */
162 val
= s
->gic
.running_irq
[0];
165 } else if (val
>= 32) {
169 if (s
->gic
.running_irq
[0] == 1023
170 || s
->gic
.last_active
[s
->gic
.running_irq
[0]][0] == 1023) {
174 if (s
->gic
.current_pending
[0] != 1023)
175 val
|= (s
->gic
.current_pending
[0] << 12);
177 for (irq
= 32; irq
< s
->num_irq
; irq
++) {
178 if (s
->gic
.irq_state
[irq
].pending
) {
184 if (s
->gic
.irq_state
[ARMV7M_EXCP_SYSTICK
].pending
)
187 if (s
->gic
.irq_state
[ARMV7M_EXCP_PENDSV
].pending
)
190 if (s
->gic
.irq_state
[ARMV7M_EXCP_NMI
].pending
)
193 case 0xd08: /* Vector Table Offset. */
194 return cpu_single_env
->v7m
.vecbase
;
195 case 0xd0c: /* Application Interrupt/Reset Control. */
197 case 0xd10: /* System Control. */
198 /* TODO: Implement SLEEPONEXIT. */
200 case 0xd14: /* Configuration Control. */
201 /* TODO: Implement Configuration Control bits. */
203 case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
204 irq
= offset
- 0xd14;
206 val
|= s
->gic
.priority1
[irq
++][0];
207 val
|= s
->gic
.priority1
[irq
++][0] << 8;
208 val
|= s
->gic
.priority1
[irq
++][0] << 16;
209 val
|= s
->gic
.priority1
[irq
][0] << 24;
211 case 0xd24: /* System Handler Status. */
213 if (s
->gic
.irq_state
[ARMV7M_EXCP_MEM
].active
) val
|= (1 << 0);
214 if (s
->gic
.irq_state
[ARMV7M_EXCP_BUS
].active
) val
|= (1 << 1);
215 if (s
->gic
.irq_state
[ARMV7M_EXCP_USAGE
].active
) val
|= (1 << 3);
216 if (s
->gic
.irq_state
[ARMV7M_EXCP_SVC
].active
) val
|= (1 << 7);
217 if (s
->gic
.irq_state
[ARMV7M_EXCP_DEBUG
].active
) val
|= (1 << 8);
218 if (s
->gic
.irq_state
[ARMV7M_EXCP_PENDSV
].active
) val
|= (1 << 10);
219 if (s
->gic
.irq_state
[ARMV7M_EXCP_SYSTICK
].active
) val
|= (1 << 11);
220 if (s
->gic
.irq_state
[ARMV7M_EXCP_USAGE
].pending
) val
|= (1 << 12);
221 if (s
->gic
.irq_state
[ARMV7M_EXCP_MEM
].pending
) val
|= (1 << 13);
222 if (s
->gic
.irq_state
[ARMV7M_EXCP_BUS
].pending
) val
|= (1 << 14);
223 if (s
->gic
.irq_state
[ARMV7M_EXCP_SVC
].pending
) val
|= (1 << 15);
224 if (s
->gic
.irq_state
[ARMV7M_EXCP_MEM
].enabled
) val
|= (1 << 16);
225 if (s
->gic
.irq_state
[ARMV7M_EXCP_BUS
].enabled
) val
|= (1 << 17);
226 if (s
->gic
.irq_state
[ARMV7M_EXCP_USAGE
].enabled
) val
|= (1 << 18);
228 case 0xd28: /* Configurable Fault Status. */
229 /* TODO: Implement Fault Status. */
230 hw_error("Not implemented: Configurable Fault Status.");
232 case 0xd2c: /* Hard Fault Status. */
233 case 0xd30: /* Debug Fault Status. */
234 case 0xd34: /* Mem Manage Address. */
235 case 0xd38: /* Bus Fault Address. */
236 case 0xd3c: /* Aux Fault Status. */
237 /* TODO: Implement fault status registers. */
239 case 0xd40: /* PFR0. */
241 case 0xd44: /* PRF1. */
243 case 0xd48: /* DFR0. */
245 case 0xd4c: /* AFR0. */
247 case 0xd50: /* MMFR0. */
249 case 0xd54: /* MMFR1. */
251 case 0xd58: /* MMFR2. */
253 case 0xd5c: /* MMFR3. */
255 case 0xd60: /* ISAR0. */
257 case 0xd64: /* ISAR1. */
259 case 0xd68: /* ISAR2. */
261 case 0xd6c: /* ISAR3. */
263 case 0xd70: /* ISAR4. */
265 /* TODO: Implement debug registers. */
268 hw_error("NVIC: Bad read offset 0x%x\n", offset
);
272 static void nvic_writel(void *opaque
, uint32_t offset
, uint32_t value
)
274 nvic_state
*s
= (nvic_state
*)opaque
;
277 case 0x10: /* SysTick Control and Status. */
278 oldval
= s
->systick
.control
;
279 s
->systick
.control
&= 0xfffffff8;
280 s
->systick
.control
|= value
& 7;
281 if ((oldval
^ value
) & SYSTICK_ENABLE
) {
282 int64_t now
= qemu_get_clock_ns(vm_clock
);
283 if (value
& SYSTICK_ENABLE
) {
284 if (s
->systick
.tick
) {
285 s
->systick
.tick
+= now
;
286 qemu_mod_timer(s
->systick
.timer
, s
->systick
.tick
);
288 systick_reload(s
, 1);
291 qemu_del_timer(s
->systick
.timer
);
292 s
->systick
.tick
-= now
;
293 if (s
->systick
.tick
< 0)
296 } else if ((oldval
^ value
) & SYSTICK_CLKSOURCE
) {
297 /* This is a hack. Force the timer to be reloaded
298 when the reference clock is changed. */
299 systick_reload(s
, 1);
302 case 0x14: /* SysTick Reload Value. */
303 s
->systick
.reload
= value
;
305 case 0x18: /* SysTick Current Value. Writes reload the timer. */
306 systick_reload(s
, 1);
307 s
->systick
.control
&= ~SYSTICK_COUNTFLAG
;
309 case 0xd04: /* Interrupt Control State. */
310 if (value
& (1 << 31)) {
311 armv7m_nvic_set_pending(s
, ARMV7M_EXCP_NMI
);
313 if (value
& (1 << 28)) {
314 armv7m_nvic_set_pending(s
, ARMV7M_EXCP_PENDSV
);
315 } else if (value
& (1 << 27)) {
316 s
->gic
.irq_state
[ARMV7M_EXCP_PENDSV
].pending
= 0;
319 if (value
& (1 << 26)) {
320 armv7m_nvic_set_pending(s
, ARMV7M_EXCP_SYSTICK
);
321 } else if (value
& (1 << 25)) {
322 s
->gic
.irq_state
[ARMV7M_EXCP_SYSTICK
].pending
= 0;
326 case 0xd08: /* Vector Table Offset. */
327 cpu_single_env
->v7m
.vecbase
= value
& 0xffffff80;
329 case 0xd0c: /* Application Interrupt/Reset Control. */
330 if ((value
>> 16) == 0x05fa) {
332 hw_error("VECTCLRACTIVE not implemented");
335 hw_error("System reset");
339 case 0xd10: /* System Control. */
340 case 0xd14: /* Configuration Control. */
341 /* TODO: Implement control registers. */
343 case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */
346 irq
= offset
- 0xd14;
347 s
->gic
.priority1
[irq
++][0] = value
& 0xff;
348 s
->gic
.priority1
[irq
++][0] = (value
>> 8) & 0xff;
349 s
->gic
.priority1
[irq
++][0] = (value
>> 16) & 0xff;
350 s
->gic
.priority1
[irq
][0] = (value
>> 24) & 0xff;
354 case 0xd24: /* System Handler Control. */
355 /* TODO: Real hardware allows you to set/clear the active bits
356 under some circumstances. We don't implement this. */
357 s
->gic
.irq_state
[ARMV7M_EXCP_MEM
].enabled
= (value
& (1 << 16)) != 0;
358 s
->gic
.irq_state
[ARMV7M_EXCP_BUS
].enabled
= (value
& (1 << 17)) != 0;
359 s
->gic
.irq_state
[ARMV7M_EXCP_USAGE
].enabled
= (value
& (1 << 18)) != 0;
361 case 0xd28: /* Configurable Fault Status. */
362 case 0xd2c: /* Hard Fault Status. */
363 case 0xd30: /* Debug Fault Status. */
364 case 0xd34: /* Mem Manage Address. */
365 case 0xd38: /* Bus Fault Address. */
366 case 0xd3c: /* Aux Fault Status. */
368 case 0xf00: /* Software Triggered Interrupt Register */
369 if ((value
& 0x1ff) < s
->num_irq
) {
370 gic_set_pending_private(&s
->gic
, 0, value
& 0x1ff);
375 hw_error("NVIC: Bad write offset 0x%x\n", offset
);
379 static uint64_t nvic_sysreg_read(void *opaque
, target_phys_addr_t addr
,
382 /* At the moment we only support the ID registers for byte/word access.
383 * This is not strictly correct as a few of the other registers also
386 uint32_t offset
= addr
;
387 if (offset
>= 0xfe0) {
391 return nvic_id
[(offset
- 0xfe0) >> 2];
394 return nvic_readl(opaque
, offset
);
396 hw_error("NVIC: Bad read of size %d at offset 0x%x\n", size
, offset
);
399 static void nvic_sysreg_write(void *opaque
, target_phys_addr_t addr
,
400 uint64_t value
, unsigned size
)
402 uint32_t offset
= addr
;
404 nvic_writel(opaque
, offset
, value
);
407 hw_error("NVIC: Bad write of size %d at offset 0x%x\n", size
, offset
);
410 static const MemoryRegionOps nvic_sysreg_ops
= {
411 .read
= nvic_sysreg_read
,
412 .write
= nvic_sysreg_write
,
413 .endianness
= DEVICE_NATIVE_ENDIAN
,
416 static const VMStateDescription vmstate_nvic
= {
417 .name
= "armv7m_nvic",
419 .minimum_version_id
= 1,
420 .minimum_version_id_old
= 1,
421 .fields
= (VMStateField
[]) {
422 VMSTATE_UINT32(systick
.control
, nvic_state
),
423 VMSTATE_UINT32(systick
.reload
, nvic_state
),
424 VMSTATE_INT64(systick
.tick
, nvic_state
),
425 VMSTATE_TIMER(systick
.timer
, nvic_state
),
426 VMSTATE_END_OF_LIST()
430 static void armv7m_nvic_reset(DeviceState
*dev
)
432 nvic_state
*s
= FROM_SYSBUSGIC(nvic_state
, sysbus_from_qdev(dev
));
433 gic_reset(&s
->gic
.busdev
.qdev
);
434 /* Common GIC reset resets to disabled; the NVIC doesn't have
435 * per-CPU interfaces so mark our non-existent CPU interface
436 * as enabled by default.
438 s
->gic
.cpu_enabled
[0] = 1;
439 /* The NVIC as a whole is always enabled. */
444 static int armv7m_nvic_init(SysBusDevice
*dev
)
446 nvic_state
*s
= FROM_SYSBUSGIC(nvic_state
, dev
);
448 /* The NVIC always has only one CPU */
450 gic_init(&s
->gic
, s
->num_irq
);
451 /* The NVIC and system controller register area looks like this:
452 * 0..0xff : system control registers, including systick
453 * 0x100..0xcff : GIC-like registers
454 * 0xd00..0xfff : system control registers
455 * We use overlaying to put the GIC like registers
456 * over the top of the system control register region.
458 memory_region_init(&s
->container
, "nvic", 0x1000);
459 /* The system register region goes at the bottom of the priority
460 * stack as it covers the whole page.
462 memory_region_init_io(&s
->sysregmem
, &nvic_sysreg_ops
, s
,
463 "nvic_sysregs", 0x1000);
464 memory_region_add_subregion(&s
->container
, 0, &s
->sysregmem
);
465 /* Alias the GIC region so we can get only the section of it
466 * we need, and layer it on top of the system register region.
468 memory_region_init_alias(&s
->gic_iomem_alias
, "nvic-gic", &s
->gic
.iomem
,
470 memory_region_add_subregion_overlap(&s
->container
, 0x100, &s
->gic
.iomem
, 1);
471 /* Map the whole thing into system memory at the location required
472 * by the v7M architecture.
474 memory_region_add_subregion(get_system_memory(), 0xe000e000, &s
->container
);
475 s
->systick
.timer
= qemu_new_timer_ns(vm_clock
, systick_timer_tick
, s
);
479 static Property armv7m_nvic_properties
[] = {
480 /* The ARM v7m may have anything from 0 to 496 external interrupt
481 * IRQ lines. We default to 64. Other boards may differ and should
482 * set this property appropriately.
484 DEFINE_PROP_UINT32("num-irq", nvic_state
, num_irq
, 64),
485 DEFINE_PROP_END_OF_LIST(),
488 static void armv7m_nvic_class_init(ObjectClass
*klass
, void *data
)
490 DeviceClass
*dc
= DEVICE_CLASS(klass
);
491 SysBusDeviceClass
*sdc
= SYS_BUS_DEVICE_CLASS(klass
);
493 sdc
->init
= armv7m_nvic_init
;
494 dc
->vmsd
= &vmstate_nvic
;
495 dc
->reset
= armv7m_nvic_reset
;
496 dc
->props
= armv7m_nvic_properties
;
499 static TypeInfo armv7m_nvic_info
= {
500 .name
= "armv7m_nvic",
501 .parent
= TYPE_SYS_BUS_DEVICE
,
502 .instance_size
= sizeof(nvic_state
),
503 .class_init
= armv7m_nvic_class_init
,
506 static void armv7m_nvic_register_types(void)
508 type_register_static(&armv7m_nvic_info
);
511 type_init(armv7m_nvic_register_types
)