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 | 34 | }; |
| 35 | 35 | void arm_load_kernel(CPUState *env, struct arm_boot_info *info); |
| 36 | 36 | |
| 37 | -/* armv7m_nvic.c */ | |
| 38 | - | |
| 39 | 37 | /* Multiplication factor to convert from system clock ticks to qemu timer |
| 40 | 38 | ticks. */ |
| 41 | 39 | extern int system_clock_scale; |
| 42 | -qemu_irq *armv7m_nvic_init(CPUState *env); | |
| 43 | 40 | |
| 44 | 41 | #endif /* !ARM_MISC_H */ | ... | ... |
hw/arm_gic.c
| ... | ... | @@ -32,6 +32,9 @@ static const uint8_t gic_id[] = |
| 32 | 32 | #define GIC_BASE_IRQ 0 |
| 33 | 33 | #endif |
| 34 | 34 | |
| 35 | +#define FROM_SYSBUSGIC(type, dev) \ | |
| 36 | + DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev)) | |
| 37 | + | |
| 35 | 38 | typedef struct gic_irq_state |
| 36 | 39 | { |
| 37 | 40 | /* ??? The documentation seems to imply the enable bits are global, even |
| ... | ... | @@ -74,6 +77,7 @@ typedef struct gic_irq_state |
| 74 | 77 | |
| 75 | 78 | typedef struct gic_state |
| 76 | 79 | { |
| 80 | + SysBusDevice busdev; | |
| 77 | 81 | qemu_irq parent_irq[NCPU]; |
| 78 | 82 | int enabled; |
| 79 | 83 | int cpu_enabled[NCPU]; |
| ... | ... | @@ -91,10 +95,7 @@ typedef struct gic_state |
| 91 | 95 | int running_priority[NCPU]; |
| 92 | 96 | int current_pending[NCPU]; |
| 93 | 97 | |
| 94 | - qemu_irq *in; | |
| 95 | -#ifdef NVIC | |
| 96 | - void *nvic; | |
| 97 | -#endif | |
| 98 | + int iomemtype; | |
| 98 | 99 | } gic_state; |
| 99 | 100 | |
| 100 | 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 | 364 | uint32_t addr; |
| 364 | 365 | addr = offset; |
| 365 | 366 | if (addr < 0x100 || addr > 0xd00) |
| 366 | - return nvic_readl(s->nvic, addr); | |
| 367 | + return nvic_readl(s, addr); | |
| 367 | 368 | #endif |
| 368 | 369 | val = gic_dist_readw(opaque, offset); |
| 369 | 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 | 524 | uint32_t addr; |
| 524 | 525 | addr = offset; |
| 525 | 526 | if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) { |
| 526 | - nvic_writel(s->nvic, addr, value); | |
| 527 | + nvic_writel(s, addr, value); | |
| 527 | 528 | return; |
| 528 | 529 | } |
| 529 | 530 | #endif |
| ... | ... | @@ -716,22 +717,16 @@ static int gic_load(QEMUFile *f, void *opaque, int version_id) |
| 716 | 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 | 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 | 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 | 730 | gic_reset(s); |
| 735 | 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 | * This code is licenced under the GPL. |
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | -#include "hw.h" | |
| 10 | +#include "sysbus.h" | |
| 11 | 11 | #include "arm-misc.h" |
| 12 | 12 | #include "sysemu.h" |
| 13 | 13 | |
| ... | ... | @@ -140,11 +140,15 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, |
| 140 | 140 | const char *kernel_filename, const char *cpu_model) |
| 141 | 141 | { |
| 142 | 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 | 147 | uint32_t pc; |
| 145 | 148 | int image_size; |
| 146 | 149 | uint64_t entry; |
| 147 | 150 | uint64_t lowaddr; |
| 151 | + int i; | |
| 148 | 152 | |
| 149 | 153 | flash_size *= 1024; |
| 150 | 154 | sram_size *= 1024; |
| ... | ... | @@ -176,7 +180,14 @@ qemu_irq *armv7m_init(int flash_size, int sram_size, |
| 176 | 180 | qemu_ram_alloc(sram_size) | IO_MEM_RAM); |
| 177 | 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 | 192 | image_size = load_elf(kernel_filename, 0, &entry, &lowaddr, NULL); |
| 182 | 193 | if (image_size < 0) { | ... | ... |
hw/armv7m_nvic.c
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | * NVIC. Much of that is also implemented here. |
| 11 | 11 | */ |
| 12 | 12 | |
| 13 | -#include "hw.h" | |
| 13 | +#include "sysbus.h" | |
| 14 | 14 | #include "qemu-timer.h" |
| 15 | 15 | #include "arm-misc.h" |
| 16 | 16 | |
| ... | ... | @@ -33,13 +33,13 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value); |
| 33 | 33 | #include "arm_gic.c" |
| 34 | 34 | |
| 35 | 35 | typedef struct { |
| 36 | + gic_state gic; | |
| 36 | 37 | struct { |
| 37 | 38 | uint32_t control; |
| 38 | 39 | uint32_t reload; |
| 39 | 40 | int64_t tick; |
| 40 | 41 | QEMUTimer *timer; |
| 41 | 42 | } systick; |
| 42 | - gic_state *gic; | |
| 43 | 43 | } nvic_state; |
| 44 | 44 | |
| 45 | 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 | 91 | nvic_state *s = (nvic_state *)opaque; |
| 92 | 92 | if (irq >= 16) |
| 93 | 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 | 97 | /* Make pending IRQ active. */ |
| ... | ... | @@ -100,7 +100,7 @@ int armv7m_nvic_acknowledge_irq(void *opaque) |
| 100 | 100 | nvic_state *s = (nvic_state *)opaque; |
| 101 | 101 | uint32_t irq; |
| 102 | 102 | |
| 103 | - irq = gic_acknowledge_irq(s->gic, 0); | |
| 103 | + irq = gic_acknowledge_irq(&s->gic, 0); | |
| 104 | 104 | if (irq == 1023) |
| 105 | 105 | hw_error("Interrupt but no vector\n"); |
| 106 | 106 | if (irq >= 32) |
| ... | ... | @@ -113,7 +113,7 @@ void armv7m_nvic_complete_irq(void *opaque, int irq) |
| 113 | 113 | nvic_state *s = (nvic_state *)opaque; |
| 114 | 114 | if (irq >= 16) |
| 115 | 115 | irq += 16; |
| 116 | - gic_complete_irq(s->gic, 0, irq); | |
| 116 | + gic_complete_irq(&s->gic, 0, irq); | |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | 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 | 153 | return cpu_single_env->cp15.c0_cpuid; |
| 154 | 154 | case 0xd04: /* Interrypt Control State. */ |
| 155 | 155 | /* VECTACTIVE */ |
| 156 | - val = s->gic->running_irq[0]; | |
| 156 | + val = s->gic.running_irq[0]; | |
| 157 | 157 | if (val == 1023) { |
| 158 | 158 | val = 0; |
| 159 | 159 | } else if (val >= 32) { |
| 160 | 160 | val -= 16; |
| 161 | 161 | } |
| 162 | 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 | 165 | val |= (1 << 11); |
| 166 | 166 | } |
| 167 | 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 | 170 | /* ISRPENDING */ |
| 171 | 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 | 173 | val |= (1 << 22); |
| 174 | 174 | break; |
| 175 | 175 | } |
| 176 | 176 | } |
| 177 | 177 | /* PENDSTSET */ |
| 178 | - if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending) | |
| 178 | + if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending) | |
| 179 | 179 | val |= (1 << 26); |
| 180 | 180 | /* PENDSVSET */ |
| 181 | - if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending) | |
| 181 | + if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending) | |
| 182 | 182 | val |= (1 << 28); |
| 183 | 183 | /* NMIPENDSET */ |
| 184 | - if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending) | |
| 184 | + if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending) | |
| 185 | 185 | val |= (1 << 31); |
| 186 | 186 | return val; |
| 187 | 187 | case 0xd08: /* Vector Table Offset. */ |
| ... | ... | @@ -197,27 +197,27 @@ static uint32_t nvic_readl(void *opaque, uint32_t offset) |
| 197 | 197 | case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority. */ |
| 198 | 198 | irq = offset - 0xd14; |
| 199 | 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 | 204 | return val; |
| 205 | 205 | case 0xd24: /* System Handler Status. */ |
| 206 | 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 | 221 | return val; |
| 222 | 222 | case 0xd28: /* Configurable Fault Status. */ |
| 223 | 223 | /* TODO: Implement Fault Status. */ |
| ... | ... | @@ -307,14 +307,14 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) |
| 307 | 307 | if (value & (1 << 28)) { |
| 308 | 308 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); |
| 309 | 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 | 313 | if (value & (1 << 26)) { |
| 314 | 314 | armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); |
| 315 | 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 | 319 | break; |
| 320 | 320 | case 0xd08: /* Vector Table Offset. */ |
| ... | ... | @@ -338,19 +338,19 @@ static void nvic_writel(void *opaque, uint32_t offset, uint32_t value) |
| 338 | 338 | { |
| 339 | 339 | int irq; |
| 340 | 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 | 347 | break; |
| 348 | 348 | case 0xd24: /* System Handler Control. */ |
| 349 | 349 | /* TODO: Real hardware allows you to set/clear the active bits |
| 350 | 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 | 354 | break; |
| 355 | 355 | case 0xd28: /* Configurable Fault Status. */ |
| 356 | 356 | case 0xd2c: /* Hard Fault Status. */ |
| ... | ... | @@ -390,19 +390,24 @@ static int nvic_load(QEMUFile *f, void *opaque, int version_id) |
| 390 | 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 | 401 | s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s); |
| 403 | 402 | if (env->v7m.nvic) |
| 404 | 403 | hw_error("CPU can only have one NVIC\n"); |
| 405 | 404 | env->v7m.nvic = s; |
| 406 | 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 | 7 | * This code is licenced under the GPL. |
| 8 | 8 | */ |
| 9 | 9 | |
| 10 | -#include "hw.h" | |
| 10 | +#include "sysbus.h" | |
| 11 | 11 | #include "qemu-timer.h" |
| 12 | -#include "primecell.h" | |
| 13 | 12 | |
| 14 | 13 | #define MPCORE_PRIV_BASE 0x10100000 |
| 15 | 14 | #define NCPU 4 |
| ... | ... | @@ -41,8 +40,9 @@ typedef struct { |
| 41 | 40 | } mpcore_timer_state; |
| 42 | 41 | |
| 43 | 42 | typedef struct mpcore_priv_state { |
| 44 | - gic_state *gic; | |
| 43 | + gic_state gic; | |
| 45 | 44 | uint32_t scu_control; |
| 45 | + int iomemtype; | |
| 46 | 46 | mpcore_timer_state timer[8]; |
| 47 | 47 | } mpcore_priv_state; |
| 48 | 48 | |
| ... | ... | @@ -51,7 +51,7 @@ typedef struct mpcore_priv_state { |
| 51 | 51 | static inline void mpcore_timer_update_irq(mpcore_timer_state *s) |
| 52 | 52 | { |
| 53 | 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 | 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 | 181 | } else { |
| 182 | 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 | 185 | } else if (offset < 0xb00) { |
| 186 | 186 | /* Timers. */ |
| 187 | 187 | if (offset < 0x700) { |
| ... | ... | @@ -224,7 +224,7 @@ static void mpcore_priv_write(void *opaque, target_phys_addr_t offset, |
| 224 | 224 | } else { |
| 225 | 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 | 228 | } else if (offset < 0xb00) { |
| 229 | 229 | /* Timers. */ |
| 230 | 230 | if (offset < 0x700) { |
| ... | ... | @@ -255,32 +255,34 @@ static CPUWriteMemoryFunc *mpcore_priv_writefn[] = { |
| 255 | 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 | 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 | 274 | for (i = 0; i < 8; i++) { |
| 273 | 275 | mpcore_timer_init(s, &s->timer[i], i); |
| 274 | 276 | } |
| 275 | - return s->gic->in; | |
| 276 | 277 | } |
| 277 | 278 | |
| 278 | 279 | /* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ |
| 279 | 280 | controllers. The output of these, plus some of the raw input lines |
| 280 | 281 | are fed into a single SMP-aware interrupt controller on the CPU. */ |
| 281 | 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 | 286 | } mpcore_rirq_state; |
| 285 | 287 | |
| 286 | 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 | 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 | 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 | 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 | 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 | 17 | /* pl080.c */ |
| 18 | 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 | 20 | /* arm_sysctl.c */ |
| 27 | 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 | 31 | { |
| 32 | 32 | CPUState *env; |
| 33 | 33 | ram_addr_t ram_offset; |
| 34 | - qemu_irq *pic; | |
| 35 | 34 | DeviceState *dev; |
| 35 | + qemu_irq *irqp; | |
| 36 | + qemu_irq pic[64]; | |
| 36 | 37 | PCIBus *pci_bus; |
| 37 | 38 | NICInfo *nd; |
| 38 | 39 | int n; |
| ... | ... | @@ -55,8 +56,8 @@ static void realview_init(ram_addr_t ram_size, |
| 55 | 56 | fprintf(stderr, "Unable to find CPU definition\n"); |
| 56 | 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 | 61 | if (n > 0) { |
| 61 | 62 | /* Set entry point for secondary CPUs. This assumes we're using |
| 62 | 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 | 77 | /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3 |
| 77 | 78 | is nIRQ (there are inconsistencies). However Linux 2.6.17 expects |
| 78 | 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 | 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 | 90 | sysbus_create_simple("pl050_keyboard", 0x10006000, pic[20]); | ... | ... |
hw/realview_gic.c
| ... | ... | @@ -7,8 +7,7 @@ |
| 7 | 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 | 12 | #define GIC_NIRQ 96 |
| 14 | 13 | #define NCPU 1 |
| ... | ... | @@ -22,6 +21,11 @@ gic_get_current_cpu(void) |
| 22 | 21 | |
| 23 | 22 | #include "arm_gic.c" |
| 24 | 23 | |
| 24 | +typedef struct { | |
| 25 | + gic_state gic; | |
| 26 | + int iomemtype; | |
| 27 | +} RealViewGICState; | |
| 28 | + | |
| 25 | 29 | static uint32_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset) |
| 26 | 30 | { |
| 27 | 31 | gic_state *s = (gic_state *)opaque; |
| ... | ... | @@ -47,16 +51,27 @@ static CPUWriteMemoryFunc *realview_gic_cpu_writefn[] = { |
| 47 | 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) | ... | ... |