Commit fe7e8758d0abfb6953b5e4f5a1af17ea1598a2bb
1 parent
0027b06d
ARM GIC qdev conversion
Signed-off-by: Paul Brook <paul@codesourcery.com>
Showing
8 changed files
with
168 additions
and
124 deletions
hw/arm-misc.h
| @@ -34,11 +34,8 @@ struct arm_boot_info { | @@ -34,11 +34,8 @@ struct arm_boot_info { | ||
| 34 | }; | 34 | }; |
| 35 | void arm_load_kernel(CPUState *env, struct arm_boot_info *info); | 35 | void arm_load_kernel(CPUState *env, struct arm_boot_info *info); |
| 36 | 36 | ||
| 37 | -/* armv7m_nvic.c */ | ||
| 38 | - | ||
| 39 | /* Multiplication factor to convert from system clock ticks to qemu timer | 37 | /* Multiplication factor to convert from system clock ticks to qemu timer |
| 40 | ticks. */ | 38 | ticks. */ |
| 41 | extern int system_clock_scale; | 39 | extern int system_clock_scale; |
| 42 | -qemu_irq *armv7m_nvic_init(CPUState *env); | ||
| 43 | 40 | ||
| 44 | #endif /* !ARM_MISC_H */ | 41 | #endif /* !ARM_MISC_H */ |
hw/arm_gic.c
| @@ -32,6 +32,9 @@ static const uint8_t gic_id[] = | @@ -32,6 +32,9 @@ static const uint8_t gic_id[] = | ||
| 32 | #define GIC_BASE_IRQ 0 | 32 | #define GIC_BASE_IRQ 0 |
| 33 | #endif | 33 | #endif |
| 34 | 34 | ||
| 35 | +#define FROM_SYSBUSGIC(type, dev) \ | ||
| 36 | + DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev)) | ||
| 37 | + | ||
| 35 | typedef struct gic_irq_state | 38 | typedef struct gic_irq_state |
| 36 | { | 39 | { |
| 37 | /* ??? The documentation seems to imply the enable bits are global, even | 40 | /* ??? The documentation seems to imply the enable bits are global, even |
| @@ -74,6 +77,7 @@ typedef struct gic_irq_state | @@ -74,6 +77,7 @@ typedef struct gic_irq_state | ||
| 74 | 77 | ||
| 75 | typedef struct gic_state | 78 | typedef struct gic_state |
| 76 | { | 79 | { |
| 80 | + SysBusDevice busdev; | ||
| 77 | qemu_irq parent_irq[NCPU]; | 81 | qemu_irq parent_irq[NCPU]; |
| 78 | int enabled; | 82 | int enabled; |
| 79 | int cpu_enabled[NCPU]; | 83 | int cpu_enabled[NCPU]; |
| @@ -91,10 +95,7 @@ typedef struct gic_state | @@ -91,10 +95,7 @@ typedef struct gic_state | ||
| 91 | int running_priority[NCPU]; | 95 | int running_priority[NCPU]; |
| 92 | int current_pending[NCPU]; | 96 | int current_pending[NCPU]; |
| 93 | 97 | ||
| 94 | - qemu_irq *in; | ||
| 95 | -#ifdef NVIC | ||
| 96 | - void *nvic; | ||
| 97 | -#endif | 98 | + int iomemtype; |
| 98 | } gic_state; | 99 | } gic_state; |
| 99 | 100 | ||
| 100 | /* TODO: Many places that call this routine could be optimized. */ | 101 | /* TODO: Many places that call this routine could be optimized. */ |
| @@ -363,7 +364,7 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) | @@ -363,7 +364,7 @@ static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset) | ||
| 363 | uint32_t addr; | 364 | uint32_t addr; |
| 364 | addr = offset; | 365 | addr = offset; |
| 365 | if (addr < 0x100 || addr > 0xd00) | 366 | if (addr < 0x100 || addr > 0xd00) |
| 366 | - return nvic_readl(s->nvic, addr); | 367 | + return nvic_readl(s, addr); |
| 367 | #endif | 368 | #endif |
| 368 | val = gic_dist_readw(opaque, offset); | 369 | val = gic_dist_readw(opaque, offset); |
| 369 | val |= gic_dist_readw(opaque, offset + 2) << 16; | 370 | val |= gic_dist_readw(opaque, offset + 2) << 16; |
| @@ -523,7 +524,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset, | @@ -523,7 +524,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset, | ||
| 523 | uint32_t addr; | 524 | uint32_t addr; |
| 524 | addr = offset; | 525 | addr = offset; |
| 525 | if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { | 526 | if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { |
| 526 | - nvic_writel(s->nvic, addr, value); | 527 | + nvic_writel(s, addr, value); |
| 527 | return; | 528 | return; |
| 528 | } | 529 | } |
| 529 | #endif | 530 | #endif |
| @@ -716,22 +717,16 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) | @@ -716,22 +717,16 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) | ||
| 716 | return 0; | 717 | return 0; |
| 717 | } | 718 | } |
| 718 | 719 | ||
| 719 | -static gic_state *gic_init(uint32_t dist_base, qemu_irq *parent_irq) | 720 | +static void gic_init(gic_state *s) |
| 720 | { | 721 | { |
| 721 | - gic_state *s; | ||
| 722 | - int iomemtype; | ||
| 723 | int i; | 722 | int i; |
| 724 | 723 | ||
| 725 | - s = (gic_state *)qemu_mallocz(sizeof(gic_state)); | ||
| 726 | - s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); | 724 | + qdev_init_irq_sink(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32); |
| 727 | for (i = 0; i < NCPU; i++) { | 725 | for (i = 0; i < NCPU; i++) { |
| 728 | - s->parent_irq[i] = parent_irq[i]; | 726 | + sysbus_init_irq(&s->busdev, &s->parent_irq[i]); |
| 729 | } | 727 | } |
| 730 | - iomemtype = cpu_register_io_memory(0, gic_dist_readfn, | ||
| 731 | - gic_dist_writefn, s); | ||
| 732 | - cpu_register_physical_memory(dist_base, 0x00001000, | ||
| 733 | - iomemtype); | 728 | + s->iomemtype = cpu_register_io_memory(0, gic_dist_readfn, |
| 729 | + gic_dist_writefn, s); | ||
| 734 | gic_reset(s); | 730 | gic_reset(s); |
| 735 | register_savevm("arm_gic", -1, 1, gic_save, gic_load, s); | 731 | register_savevm("arm_gic", -1, 1, gic_save, gic_load, s); |
| 736 | - return s; | ||
| 737 | } | 732 | } |
hw/armv7m.c
| @@ -7,7 +7,7 @@ | @@ -7,7 +7,7 @@ | ||
| 7 | * This code is licenced under the GPL. | 7 | * This code is licenced under the GPL. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | -#include "hw.h" | 10 | +#include "sysbus.h" |
| 11 | #include "arm-misc.h" | 11 | #include "arm-misc.h" |
| 12 | #include "sysemu.h" | 12 | #include "sysemu.h" |
| 13 | 13 | ||
| @@ -140,11 +140,15 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, | @@ -140,11 +140,15 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, | ||
| 140 | const char *kernel_filename, const char *cpu_model) | 140 | const char *kernel_filename, const char *cpu_model) |
| 141 | { | 141 | { |
| 142 | CPUState *env; | 142 | CPUState *env; |
| 143 | - qemu_irq *pic; | 143 | + DeviceState *nvic; |
| 144 | + /* FIXME: make this local state. */ | ||
| 145 | + static qemu_irq pic[64]; | ||
| 146 | + qemu_irq *cpu_pic; | ||
| 144 | uint32_t pc; | 147 | uint32_t pc; |
| 145 | int image_size; | 148 | int image_size; |
| 146 | uint64_t entry; | 149 | uint64_t entry; |
| 147 | uint64_t lowaddr; | 150 | uint64_t lowaddr; |
| 151 | + int i; | ||
| 148 | 152 | ||
| 149 | flash_size *= 1024; | 153 | flash_size *= 1024; |
| 150 | sram_size *= 1024; | 154 | sram_size *= 1024; |
| @@ -176,7 +180,14 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, | @@ -176,7 +180,14 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, | ||
| 176 | qemu_ram_alloc(sram_size) | IO_MEM_RAM); | 180 | qemu_ram_alloc(sram_size) | IO_MEM_RAM); |
| 177 | armv7m_bitband_init(); | 181 | armv7m_bitband_init(); |
| 178 | 182 | ||
| 179 | - pic = armv7m_nvic_init(env); | 183 | + nvic = qdev_create(NULL, "armv7m_nvic"); |
| 184 | + qdev_set_prop_ptr(nvic, "cpu", env); | ||
| 185 | + qdev_init(nvic); | ||
| 186 | + cpu_pic = arm_pic_init_cpu(env); | ||
| 187 | + sysbus_connect_irq(sysbus_from_qdev(nvic), 0, cpu_pic[ARM_PIC_CPU_IRQ]); | ||
| 188 | + for (i = 0; i < 64; i++) { | ||
| 189 | + pic[i] = qdev_get_irq_sink(nvic, i); | ||
| 190 | + } | ||
| 180 | 191 | ||
| 181 | image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL); | 192 | image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL); |
| 182 | if (image_size < 0) { | 193 | if (image_size < 0) { |
hw/armv7m_nvic.c
| @@ -10,7 +10,7 @@ | @@ -10,7 +10,7 @@ | ||
| 10 | * NVIC. Much of that is also implemented here. | 10 | * NVIC. Much of that is also implemented here. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | -#include "hw.h" | 13 | +#include "sysbus.h" |
| 14 | #include "qemu-timer.h" | 14 | #include "qemu-timer.h" |
| 15 | #include "arm-misc.h" | 15 | #include "arm-misc.h" |
| 16 | 16 | ||
| @@ -33,13 +33,13 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); | @@ -33,13 +33,13 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); | ||
| 33 | #include "arm_gic.c" | 33 | #include "arm_gic.c" |
| 34 | 34 | ||
| 35 | typedef struct { | 35 | typedef struct { |
| 36 | + gic_state gic; | ||
| 36 | struct { | 37 | struct { |
| 37 | uint32_t control; | 38 | uint32_t control; |
| 38 | uint32_t reload; | 39 | uint32_t reload; |
| 39 | int64_t tick; | 40 | int64_t tick; |
| 40 | QEMUTimer *timer; | 41 | QEMUTimer *timer; |
| 41 | } systick; | 42 | } systick; |
| 42 | - gic_state *gic; | ||
| 43 | } nvic_state; | 43 | } nvic_state; |
| 44 | 44 | ||
| 45 | /* qemu timers run at 1GHz. We want something closer to 1MHz. */ | 45 | /* qemu timers run at 1GHz. We want something closer to 1MHz. */ |
| @@ -91,7 +91,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq) | @@ -91,7 +91,7 @@ void armv7m_nvic_set_pending(void *opaque, int irq) | ||
| 91 | nvic_state *s = (nvic_state *)opaque; | 91 | nvic_state *s = (nvic_state *)opaque; |
| 92 | if (irq >= 16) | 92 | if (irq >= 16) |
| 93 | irq += 16; | 93 | irq += 16; |
| 94 | - gic_set_pending_private(s->gic, 0, irq); | 94 | + gic_set_pending_private(&s->gic, 0, irq); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | /* Make pending IRQ active. */ | 97 | /* Make pending IRQ active. */ |
| @@ -100,7 +100,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque) | @@ -100,7 +100,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque) | ||
| 100 | nvic_state *s = (nvic_state *)opaque; | 100 | nvic_state *s = (nvic_state *)opaque; |
| 101 | uint32_t irq; | 101 | uint32_t irq; |
| 102 | 102 | ||
| 103 | - irq = gic_acknowledge_irq(s->gic, 0); | 103 | + irq = gic_acknowledge_irq(&s->gic, 0); |
| 104 | if (irq == 1023) | 104 | if (irq == 1023) |
| 105 | hw_error("Interrupt but no vector\n"); | 105 | hw_error("Interrupt but no vector\n"); |
| 106 | if (irq >= 32) | 106 | if (irq >= 32) |
| @@ -113,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) | @@ -113,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) | ||
| 113 | nvic_state *s = (nvic_state *)opaque; | 113 | nvic_state *s = (nvic_state *)opaque; |
| 114 | if (irq >= 16) | 114 | if (irq >= 16) |
| 115 | irq += 16; | 115 | irq += 16; |
| 116 | - gic_complete_irq(s->gic, 0, irq); | 116 | + gic_complete_irq(&s->gic, 0, irq); |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | static uint32_t nvic_readl(void *opaque, uint32_t offset) | 119 | static uint32_t nvic_readl(void *opaque, uint32_t offset) |
| @@ -153,35 +153,35 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) | @@ -153,35 +153,35 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) | ||
| 153 | return cpu_single_env->cp15.c0_cpuid; | 153 | return cpu_single_env->cp15.c0_cpuid; |
| 154 | case 0xd04: /* Interrypt Control State. */ | 154 | case 0xd04: /* Interrypt Control State. */ |
| 155 | /* VECTACTIVE */ | 155 | /* VECTACTIVE */ |
| 156 | - val = s->gic->running_irq[0]; | 156 | + val = s->gic.running_irq[0]; |
| 157 | if (val == 1023) { | 157 | if (val == 1023) { |
| 158 | val = 0; | 158 | val = 0; |
| 159 | } else if (val >= 32) { | 159 | } else if (val >= 32) { |
| 160 | val -= 16; | 160 | val -= 16; |
| 161 | } | 161 | } |
| 162 | /* RETTOBASE */ | 162 | /* RETTOBASE */ |
| 163 | - if (s->gic->running_irq[0] == 1023 | ||
| 164 | - || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) { | 163 | + if (s->gic.running_irq[0] == 1023 |
| 164 | + || s->gic.last_active[s->gic.running_irq[0]][0] == 1023) { | ||
| 165 | val |= (1 << 11); | 165 | val |= (1 << 11); |
| 166 | } | 166 | } |
| 167 | /* VECTPENDING */ | 167 | /* VECTPENDING */ |
| 168 | - if (s->gic->current_pending[0] != 1023) | ||
| 169 | - val |= (s->gic->current_pending[0] << 12); | 168 | + if (s->gic.current_pending[0] != 1023) |
| 169 | + val |= (s->gic.current_pending[0] << 12); | ||
| 170 | /* ISRPENDING */ | 170 | /* ISRPENDING */ |
| 171 | for (irq = 32; irq < GIC_NIRQ; irq++) { | 171 | for (irq = 32; irq < GIC_NIRQ; irq++) { |
| 172 | - if (s->gic->irq_state[irq].pending) { | 172 | + if (s->gic.irq_state[irq].pending) { |
| 173 | val |= (1 << 22); | 173 | val |= (1 << 22); |
| 174 | break; | 174 | break; |
| 175 | } | 175 | } |
| 176 | } | 176 | } |
| 177 | /* PENDSTSET */ | 177 | /* PENDSTSET */ |
| 178 | - if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending) | 178 | + if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending) |
| 179 | val |= (1 << 26); | 179 | val |= (1 << 26); |
| 180 | /* PENDSVSET */ | 180 | /* PENDSVSET */ |
| 181 | - if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending) | 181 | + if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending) |
| 182 | val |= (1 << 28); | 182 | val |= (1 << 28); |
| 183 | /* NMIPENDSET */ | 183 | /* NMIPENDSET */ |
| 184 | - if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending) | 184 | + if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending) |
| 185 | val |= (1 << 31); | 185 | val |= (1 << 31); |
| 186 | return val; | 186 | return val; |
| 187 | case 0xd08: /* Vector Table Offset. */ | 187 | case 0xd08: /* Vector Table Offset. */ |
| @@ -197,27 +197,27 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) | @@ -197,27 +197,27 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) | ||
| 197 | case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ | 197 | case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ |
| 198 | irq = offset - 0xd14; | 198 | irq = offset - 0xd14; |
| 199 | val = 0; | 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; | 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; | 204 | return val; |
| 205 | case 0xd24: /* System Handler Status. */ | 205 | case 0xd24: /* System Handler Status. */ |
| 206 | val = 0; | 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); | 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; | 221 | return val; |
| 222 | case 0xd28: /* Configurable Fault Status. */ | 222 | case 0xd28: /* Configurable Fault Status. */ |
| 223 | /* TODO: Implement Fault Status. */ | 223 | /* TODO: Implement Fault Status. */ |
| @@ -307,14 +307,14 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) | @@ -307,14 +307,14 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) | ||
| 307 | if (value & (1 << 28)) { | 307 | if (value & (1 << 28)) { |
| 308 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); | 308 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); |
| 309 | } else if (value & (1 << 27)) { | 309 | } else if (value & (1 << 27)) { |
| 310 | - s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0; | ||
| 311 | - gic_update(s->gic); | 310 | + s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0; |
| 311 | + gic_update(&s->gic); | ||
| 312 | } | 312 | } |
| 313 | if (value & (1 << 26)) { | 313 | if (value & (1 << 26)) { |
| 314 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); | 314 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); |
| 315 | } else if (value & (1 << 25)) { | 315 | } else if (value & (1 << 25)) { |
| 316 | - s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; | ||
| 317 | - gic_update(s->gic); | 316 | + s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0; |
| 317 | + gic_update(&s->gic); | ||
| 318 | } | 318 | } |
| 319 | break; | 319 | break; |
| 320 | case 0xd08: /* Vector Table Offset. */ | 320 | case 0xd08: /* Vector Table Offset. */ |
| @@ -338,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) | @@ -338,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) | ||
| 338 | { | 338 | { |
| 339 | int irq; | 339 | int irq; |
| 340 | irq = offset - 0xd14; | 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); | 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 | } | 346 | } |
| 347 | break; | 347 | break; |
| 348 | case 0xd24: /* System Handler Control. */ | 348 | case 0xd24: /* System Handler Control. */ |
| 349 | /* TODO: Real hardware allows you to set/clear the active bits | 349 | /* TODO: Real hardware allows you to set/clear the active bits |
| 350 | under some circumstances. We don't implement this. */ | 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; | 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; | 354 | break; |
| 355 | case 0xd28: /* Configurable Fault Status. */ | 355 | case 0xd28: /* Configurable Fault Status. */ |
| 356 | case 0xd2c: /* Hard Fault Status. */ | 356 | case 0xd2c: /* Hard Fault Status. */ |
| @@ -390,19 +390,24 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id) | @@ -390,19 +390,24 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id) | ||
| 390 | return 0; | 390 | return 0; |
| 391 | } | 391 | } |
| 392 | 392 | ||
| 393 | -qemu_irq *armv7m_nvic_init(CPUState *env) | 393 | +static void armv7m_nvic_init(SysBusDevice *dev) |
| 394 | { | 394 | { |
| 395 | - nvic_state *s; | ||
| 396 | - qemu_irq *parent; | 395 | + nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev); |
| 396 | + CPUState *env; | ||
| 397 | 397 | ||
| 398 | - parent = arm_pic_init_cpu(env); | ||
| 399 | - s = (nvic_state *)qemu_mallocz(sizeof(nvic_state)); | ||
| 400 | - s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]); | ||
| 401 | - s->gic->nvic = s; | 398 | + env = qdev_get_prop_ptr(&dev->qdev, "cpu"); |
| 399 | + gic_init(&s->gic); | ||
| 400 | + cpu_register_physical_memory(0xe000e000, 0x1000, s->gic.iomemtype); | ||
| 402 | s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); | 401 | s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); |
| 403 | if (env->v7m.nvic) | 402 | if (env->v7m.nvic) |
| 404 | hw_error("CPU can only have one NVIC\n"); | 403 | hw_error("CPU can only have one NVIC\n"); |
| 405 | env->v7m.nvic = s; | 404 | env->v7m.nvic = s; |
| 406 | register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); | 405 | register_savevm("armv7m_nvic", -1, 1, nvic_save, nvic_load, s); |
| 407 | - return s->gic->in; | ||
| 408 | } | 406 | } |
| 407 | + | ||
| 408 | +static void armv7m_nvic_register_devices(void) | ||
| 409 | +{ | ||
| 410 | + sysbus_register_dev("armv7m_nvic", sizeof(nvic_state), armv7m_nvic_init); | ||
| 411 | +} | ||
| 412 | + | ||
| 413 | +device_init(armv7m_nvic_register_devices) |
hw/mpcore.c
| @@ -7,9 +7,8 @@ | @@ -7,9 +7,8 @@ | ||
| 7 | * This code is licenced under the GPL. | 7 | * This code is licenced under the GPL. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | -#include "hw.h" | 10 | +#include "sysbus.h" |
| 11 | #include "qemu-timer.h" | 11 | #include "qemu-timer.h" |
| 12 | -#include "primecell.h" | ||
| 13 | 12 | ||
| 14 | #define MPCORE_PRIV_BASE 0x10100000 | 13 | #define MPCORE_PRIV_BASE 0x10100000 |
| 15 | #define NCPU 4 | 14 | #define NCPU 4 |
| @@ -41,8 +40,9 @@ typedef struct { | @@ -41,8 +40,9 @@ typedef struct { | ||
| 41 | } mpcore_timer_state; | 40 | } mpcore_timer_state; |
| 42 | 41 | ||
| 43 | typedef struct mpcore_priv_state { | 42 | typedef struct mpcore_priv_state { |
| 44 | - gic_state *gic; | 43 | + gic_state gic; |
| 45 | uint32_t scu_control; | 44 | uint32_t scu_control; |
| 45 | + int iomemtype; | ||
| 46 | mpcore_timer_state timer[8]; | 46 | mpcore_timer_state timer[8]; |
| 47 | } mpcore_priv_state; | 47 | } mpcore_priv_state; |
| 48 | 48 | ||
| @@ -51,7 +51,7 @@ typedef struct mpcore_priv_state { | @@ -51,7 +51,7 @@ typedef struct mpcore_priv_state { | ||
| 51 | static inline void mpcore_timer_update_irq(mpcore_timer_state *s) | 51 | static inline void mpcore_timer_update_irq(mpcore_timer_state *s) |
| 52 | { | 52 | { |
| 53 | if (s->status & ~s->old_status) { | 53 | if (s->status & ~s->old_status) { |
| 54 | - gic_set_pending_private(s->mpcore->gic, s->id >> 1, 29 + (s->id & 1)); | 54 | + gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1)); |
| 55 | } | 55 | } |
| 56 | s->old_status = s->status; | 56 | s->old_status = s->status; |
| 57 | } | 57 | } |
| @@ -181,7 +181,7 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) | @@ -181,7 +181,7 @@ static uint32_t mpcore_priv_read(void *opaque, target_phys_addr_t offset) | ||
| 181 | } else { | 181 | } else { |
| 182 | id = (offset - 0x200) >> 8; | 182 | id = (offset - 0x200) >> 8; |
| 183 | } | 183 | } |
| 184 | - return gic_cpu_read(s->gic, id, offset & 0xff); | 184 | + return gic_cpu_read(&s->gic, id, offset & 0xff); |
| 185 | } else if (offset < 0xb00) { | 185 | } else if (offset < 0xb00) { |
| 186 | /* Timers. */ | 186 | /* Timers. */ |
| 187 | if (offset < 0x700) { | 187 | if (offset < 0x700) { |
| @@ -224,7 +224,7 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, | @@ -224,7 +224,7 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, | ||
| 224 | } else { | 224 | } else { |
| 225 | id = (offset - 0x200) >> 8; | 225 | id = (offset - 0x200) >> 8; |
| 226 | } | 226 | } |
| 227 | - gic_cpu_write(s->gic, id, offset & 0xff, value); | 227 | + gic_cpu_write(&s->gic, id, offset & 0xff, value); |
| 228 | } else if (offset < 0xb00) { | 228 | } else if (offset < 0xb00) { |
| 229 | /* Timers. */ | 229 | /* Timers. */ |
| 230 | if (offset < 0x700) { | 230 | if (offset < 0x700) { |
| @@ -255,32 +255,34 @@ static CPUWriteMemoryFunc *mpcore_priv_writefn[] = { | @@ -255,32 +255,34 @@ static CPUWriteMemoryFunc *mpcore_priv_writefn[] = { | ||
| 255 | mpcore_priv_write | 255 | mpcore_priv_write |
| 256 | }; | 256 | }; |
| 257 | 257 | ||
| 258 | +static void mpcore_priv_map(SysBusDevice *dev, target_phys_addr_t base) | ||
| 259 | +{ | ||
| 260 | + mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); | ||
| 261 | + cpu_register_physical_memory(base, 0x1000, s->iomemtype); | ||
| 262 | + cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype); | ||
| 263 | +} | ||
| 258 | 264 | ||
| 259 | -static qemu_irq *mpcore_priv_init(uint32_t base, qemu_irq *pic_irq) | 265 | +static void mpcore_priv_init(SysBusDevice *dev) |
| 260 | { | 266 | { |
| 261 | - mpcore_priv_state *s; | ||
| 262 | - int iomemtype; | 267 | + mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev); |
| 263 | int i; | 268 | int i; |
| 264 | 269 | ||
| 265 | - s = (mpcore_priv_state *)qemu_mallocz(sizeof(mpcore_priv_state)); | ||
| 266 | - s->gic = gic_init(base + 0x1000, pic_irq); | ||
| 267 | - if (!s->gic) | ||
| 268 | - return NULL; | ||
| 269 | - iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn, | ||
| 270 | - mpcore_priv_writefn, s); | ||
| 271 | - cpu_register_physical_memory(base, 0x00001000, iomemtype); | 270 | + gic_init(&s->gic); |
| 271 | + s->iomemtype = cpu_register_io_memory(0, mpcore_priv_readfn, | ||
| 272 | + mpcore_priv_writefn, s); | ||
| 273 | + sysbus_init_mmio_cb(dev, 0x2000, mpcore_priv_map); | ||
| 272 | for (i = 0; i < 8; i++) { | 274 | for (i = 0; i < 8; i++) { |
| 273 | mpcore_timer_init(s, &s->timer[i], i); | 275 | mpcore_timer_init(s, &s->timer[i], i); |
| 274 | } | 276 | } |
| 275 | - return s->gic->in; | ||
| 276 | } | 277 | } |
| 277 | 278 | ||
| 278 | /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ | 279 | /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ |
| 279 | controllers. The output of these, plus some of the raw input lines | 280 | controllers. The output of these, plus some of the raw input lines |
| 280 | are fed into a single SMP-aware interrupt controller on the CPU. */ | 281 | are fed into a single SMP-aware interrupt controller on the CPU. */ |
| 281 | typedef struct { | 282 | typedef struct { |
| 282 | - qemu_irq *cpuic; | ||
| 283 | - qemu_irq *rvic[4]; | 283 | + SysBusDevice busdev; |
| 284 | + qemu_irq cpuic[32]; | ||
| 285 | + qemu_irq rvic[4][64]; | ||
| 284 | } mpcore_rirq_state; | 286 | } mpcore_rirq_state; |
| 285 | 287 | ||
| 286 | /* Map baseboard IRQs onto CPU IRQ lines. */ | 288 | /* Map baseboard IRQs onto CPU IRQ lines. */ |
| @@ -307,17 +309,36 @@ static void mpcore_rirq_set_irq(void *opaque, int irq, int level) | @@ -307,17 +309,36 @@ static void mpcore_rirq_set_irq(void *opaque, int irq, int level) | ||
| 307 | } | 309 | } |
| 308 | } | 310 | } |
| 309 | 311 | ||
| 310 | -qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq) | 312 | +static void realview_mpcore_init(SysBusDevice *dev) |
| 311 | { | 313 | { |
| 312 | - mpcore_rirq_state *s; | 314 | + mpcore_rirq_state *s = FROM_SYSBUS(mpcore_rirq_state, dev); |
| 315 | + DeviceState *gic; | ||
| 316 | + DeviceState *priv; | ||
| 313 | int n; | 317 | int n; |
| 318 | + int i; | ||
| 314 | 319 | ||
| 320 | + priv = sysbus_create_simple("arm11mpcore_priv", MPCORE_PRIV_BASE, NULL); | ||
| 321 | + sysbus_pass_irq(dev, sysbus_from_qdev(priv)); | ||
| 322 | + for (i = 0; i < 32; i++) { | ||
| 323 | + s->cpuic[i] = qdev_get_irq_sink(priv, i); | ||
| 324 | + } | ||
| 315 | /* ??? IRQ routing is hardcoded to "normal" mode. */ | 325 | /* ??? IRQ routing is hardcoded to "normal" mode. */ |
| 316 | - s = qemu_mallocz(sizeof(mpcore_rirq_state)); | ||
| 317 | - s->cpuic = mpcore_priv_init(MPCORE_PRIV_BASE, cpu_irq); | ||
| 318 | for (n = 0; n < 4; n++) { | 326 | for (n = 0; n < 4; n++) { |
| 319 | - s->rvic[n] = realview_gic_init(0x10040000 + n * 0x10000, | ||
| 320 | - s->cpuic[10 + n]); | 327 | + gic = sysbus_create_simple("realview_gic", 0x10040000 + n * 0x10000, |
| 328 | + s->cpuic[10 + n]); | ||
| 329 | + for (i = 0; i < 64; i++) { | ||
| 330 | + s->rvic[n][i] = qdev_get_irq_sink(gic, i); | ||
| 331 | + } | ||
| 321 | } | 332 | } |
| 322 | - return qemu_allocate_irqs(mpcore_rirq_set_irq, s, 64); | 333 | + qdev_init_irq_sink(&dev->qdev, mpcore_rirq_set_irq, 64); |
| 323 | } | 334 | } |
| 335 | + | ||
| 336 | +static void mpcore_register_devices(void) | ||
| 337 | +{ | ||
| 338 | + sysbus_register_dev("realview_mpcore", sizeof(mpcore_rirq_state), | ||
| 339 | + realview_mpcore_init); | ||
| 340 | + sysbus_register_dev("arm11mpcore_priv", sizeof(mpcore_priv_state), | ||
| 341 | + mpcore_priv_init); | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | +device_init(mpcore_register_devices) |
hw/primecell.h
| @@ -17,12 +17,6 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); | @@ -17,12 +17,6 @@ qemu_irq *pl061_init(uint32_t base, qemu_irq irq, qemu_irq **out); | ||
| 17 | /* pl080.c */ | 17 | /* pl080.c */ |
| 18 | void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); | 18 | void *pl080_init(uint32_t base, qemu_irq irq, int nchannels); |
| 19 | 19 | ||
| 20 | -/* realview_gic.c */ | ||
| 21 | -qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq); | ||
| 22 | - | ||
| 23 | -/* mpcore.c */ | ||
| 24 | -extern qemu_irq *mpcore_irq_init(qemu_irq *cpu_irq); | ||
| 25 | - | ||
| 26 | /* arm_sysctl.c */ | 20 | /* arm_sysctl.c */ |
| 27 | void arm_sysctl_init(uint32_t base, uint32_t sys_id); | 21 | void arm_sysctl_init(uint32_t base, uint32_t sys_id); |
| 28 | 22 |
hw/realview.c
| @@ -31,8 +31,9 @@ static void realview_init(ram_addr_t ram_size, | @@ -31,8 +31,9 @@ static void realview_init(ram_addr_t ram_size, | ||
| 31 | { | 31 | { |
| 32 | CPUState *env; | 32 | CPUState *env; |
| 33 | ram_addr_t ram_offset; | 33 | ram_addr_t ram_offset; |
| 34 | - qemu_irq *pic; | ||
| 35 | DeviceState *dev; | 34 | DeviceState *dev; |
| 35 | + qemu_irq *irqp; | ||
| 36 | + qemu_irq pic[64]; | ||
| 36 | PCIBus *pci_bus; | 37 | PCIBus *pci_bus; |
| 37 | NICInfo *nd; | 38 | NICInfo *nd; |
| 38 | int n; | 39 | int n; |
| @@ -55,8 +56,8 @@ static void realview_init(ram_addr_t ram_size, | @@ -55,8 +56,8 @@ static void realview_init(ram_addr_t ram_size, | ||
| 55 | fprintf(stderr, "Unable to find CPU definition\n"); | 56 | fprintf(stderr, "Unable to find CPU definition\n"); |
| 56 | exit(1); | 57 | exit(1); |
| 57 | } | 58 | } |
| 58 | - pic = arm_pic_init_cpu(env); | ||
| 59 | - cpu_irq[n] = pic[ARM_PIC_CPU_IRQ]; | 59 | + irqp = arm_pic_init_cpu(env); |
| 60 | + cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ]; | ||
| 60 | if (n > 0) { | 61 | if (n > 0) { |
| 61 | /* Set entry point for secondary CPUs. This assumes we're using | 62 | /* Set entry point for secondary CPUs. This assumes we're using |
| 62 | the init code from arm_boot.c. Real hardware resets all CPUs | 63 | the init code from arm_boot.c. Real hardware resets all CPUs |
| @@ -76,9 +77,14 @@ static void realview_init(ram_addr_t ram_size, | @@ -76,9 +77,14 @@ static void realview_init(ram_addr_t ram_size, | ||
| 76 | /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 | 77 | /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 |
| 77 | is nIRQ (there are inconsistencies). However Linux 2.6.17 expects | 78 | is nIRQ (there are inconsistencies). However Linux 2.6.17 expects |
| 78 | GIC1 to be nIRQ and ignores all the others, so do that for now. */ | 79 | GIC1 to be nIRQ and ignores all the others, so do that for now. */ |
| 79 | - pic = realview_gic_init(0x10040000, cpu_irq[0]); | 80 | + dev = sysbus_create_simple("realview_gic", 0x10040000, cpu_irq[0]); |
| 80 | } else { | 81 | } else { |
| 81 | - pic = mpcore_irq_init(cpu_irq); | 82 | + dev = sysbus_create_varargs("realview_mpcore", -1, |
| 83 | + cpu_irq[0], cpu_irq[1], cpu_irq[2], | ||
| 84 | + cpu_irq[3], NULL); | ||
| 85 | + } | ||
| 86 | + for (n = 0; n < 64; n++) { | ||
| 87 | + pic[n] = qdev_get_irq_sink(dev, n); | ||
| 82 | } | 88 | } |
| 83 | 89 | ||
| 84 | sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); | 90 | sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); |
hw/realview_gic.c
| @@ -7,8 +7,7 @@ | @@ -7,8 +7,7 @@ | ||
| 7 | * This code is licenced under the GPL. | 7 | * This code is licenced under the GPL. |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | -#include "hw.h" | ||
| 11 | -#include "primecell.h" | 10 | +#include "sysbus.h" |
| 12 | 11 | ||
| 13 | #define GIC_NIRQ 96 | 12 | #define GIC_NIRQ 96 |
| 14 | #define NCPU 1 | 13 | #define NCPU 1 |
| @@ -22,6 +21,11 @@ gic_get_current_cpu(void) | @@ -22,6 +21,11 @@ gic_get_current_cpu(void) | ||
| 22 | 21 | ||
| 23 | #include "arm_gic.c" | 22 | #include "arm_gic.c" |
| 24 | 23 | ||
| 24 | +typedef struct { | ||
| 25 | + gic_state gic; | ||
| 26 | + int iomemtype; | ||
| 27 | +} RealViewGICState; | ||
| 28 | + | ||
| 25 | static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset) | 29 | static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset) |
| 26 | { | 30 | { |
| 27 | gic_state *s = (gic_state *)opaque; | 31 | gic_state *s = (gic_state *)opaque; |
| @@ -47,16 +51,27 @@ static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = { | @@ -47,16 +51,27 @@ static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = { | ||
| 47 | realview_gic_cpu_write | 51 | realview_gic_cpu_write |
| 48 | }; | 52 | }; |
| 49 | 53 | ||
| 50 | -qemu_irq *realview_gic_init(uint32_t base, qemu_irq parent_irq) | 54 | +static void realview_gic_map(SysBusDevice *dev, target_phys_addr_t base) |
| 51 | { | 55 | { |
| 52 | - gic_state *s; | ||
| 53 | - int iomemtype; | 56 | + RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); |
| 57 | + cpu_register_physical_memory(base, 0x1000, s->iomemtype); | ||
| 58 | + cpu_register_physical_memory(base + 0x1000, 0x1000, s->gic.iomemtype); | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +static void realview_gic_init(SysBusDevice *dev) | ||
| 62 | +{ | ||
| 63 | + RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev); | ||
| 54 | 64 | ||
| 55 | - s = gic_init(base + 0x1000, &parent_irq); | ||
| 56 | - if (!s) | ||
| 57 | - return NULL; | ||
| 58 | - iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn, | ||
| 59 | - realview_gic_cpu_writefn, s); | ||
| 60 | - cpu_register_physical_memory(base, 0x00001000, iomemtype); | ||
| 61 | - return s->in; | 65 | + gic_init(&s->gic); |
| 66 | + s->iomemtype = cpu_register_io_memory(0, realview_gic_cpu_readfn, | ||
| 67 | + realview_gic_cpu_writefn, s); | ||
| 68 | + sysbus_init_mmio_cb(dev, 0x2000, realview_gic_map); | ||
| 62 | } | 69 | } |
| 70 | + | ||
| 71 | +static void realview_gic_register_devices(void) | ||
| 72 | +{ | ||
| 73 | + sysbus_register_dev("realview_gic", sizeof(RealViewGICState), | ||
| 74 | + realview_gic_init); | ||
| 75 | +} | ||
| 76 | + | ||
| 77 | +device_init(realview_gic_register_devices) |