mirror of https://gitee.com/openkylin/qemu.git
Merge branch 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm
* 'arm-devs.for-upstream' of git://git.linaro.org/people/pmaydell/qemu-arm: hw/arm_gic: Remove stray hardcoded tab hw/arm_gic: gic_set_pending_private() is NVIC only hw/arm_gic: Use NVIC instead of LEGACY_INCLUDED_GIC define hw/arm_gic: Make gic_reset a sysbus reset function hw/arm11mpcore: Convert to using sysbus GIC device hw/exynos4210_gic: Convert to using sysbus GIC hw/realview_gic: switch to sysbus GIC hw/a9mpcore: Switch to using sysbus GIC hw/a15mpcore: switch to using sysbus GIC hw/arm_gic: Make the GIC its own sysbus device hw/arm_gic: Expose PPI inputs as gpio inputs hw/arm_gic: Move gic_get_current_cpu into arm_gic.c hw/arm_gic: Move NCPU definition to arm_gic.c hw/exynos4210_combiner.c: Drop excessive read/write access check. ARM: Exynos4210: Drop gic_cpu_write() after initialization. Fix bit test in Exynos4210 UART emulation to use & instead of &&
This commit is contained in:
commit
e92861ccb1
|
@ -366,6 +366,7 @@ obj-arm-y += cadence_uart.o
|
|||
obj-arm-y += cadence_ttc.o
|
||||
obj-arm-y += cadence_gem.o
|
||||
obj-arm-y += xilinx_zynq.o zynq_slcr.o
|
||||
obj-arm-y += arm_gic.o
|
||||
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
|
||||
obj-arm-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
|
||||
obj-arm-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
|
||||
|
|
|
@ -20,36 +20,38 @@
|
|||
|
||||
#include "sysbus.h"
|
||||
|
||||
/* Configuration for arm_gic.c:
|
||||
* max number of CPUs, how to ID current CPU
|
||||
*/
|
||||
#define NCPU 4
|
||||
|
||||
static inline int gic_get_current_cpu(void)
|
||||
{
|
||||
return cpu_single_env->cpu_index;
|
||||
}
|
||||
|
||||
#include "arm_gic.c"
|
||||
|
||||
/* A15MP private memory region. */
|
||||
|
||||
typedef struct A15MPPrivState {
|
||||
gic_state gic;
|
||||
SysBusDevice busdev;
|
||||
uint32_t num_cpu;
|
||||
uint32_t num_irq;
|
||||
MemoryRegion container;
|
||||
DeviceState *gic;
|
||||
} A15MPPrivState;
|
||||
|
||||
static void a15mp_priv_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
A15MPPrivState *s = (A15MPPrivState *)opaque;
|
||||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static int a15mp_priv_init(SysBusDevice *dev)
|
||||
{
|
||||
A15MPPrivState *s = FROM_SYSBUSGIC(A15MPPrivState, dev);
|
||||
A15MPPrivState *s = FROM_SYSBUS(A15MPPrivState, dev);
|
||||
SysBusDevice *busdev;
|
||||
|
||||
if (s->num_cpu > NCPU) {
|
||||
hw_error("a15mp_priv_init: num-cpu may not be more than %d\n", NCPU);
|
||||
}
|
||||
s->gic = qdev_create(NULL, "arm_gic");
|
||||
qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
|
||||
qdev_init_nofail(s->gic);
|
||||
busdev = sysbus_from_qdev(s->gic);
|
||||
|
||||
gic_init(&s->gic, s->num_cpu, s->num_irq);
|
||||
/* Pass through outbound IRQ lines from the GIC */
|
||||
sysbus_pass_irq(dev, busdev);
|
||||
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(&s->busdev.qdev, a15mp_priv_set_irq, s->num_irq - 32);
|
||||
|
||||
/* Memory map (addresses are offsets from PERIPHBASE):
|
||||
* 0x0000-0x0fff -- reserved
|
||||
|
@ -60,8 +62,10 @@ static int a15mp_priv_init(SysBusDevice *dev)
|
|||
* 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
|
||||
*/
|
||||
memory_region_init(&s->container, "a15mp-priv-container", 0x8000);
|
||||
memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
|
||||
memory_region_add_subregion(&s->container, 0x2000, &s->gic.cpuiomem[0]);
|
||||
memory_region_add_subregion(&s->container, 0x1000,
|
||||
sysbus_mmio_get_region(busdev, 0));
|
||||
memory_region_add_subregion(&s->container, 0x2000,
|
||||
sysbus_mmio_get_region(busdev, 1));
|
||||
|
||||
sysbus_init_mmio(dev, &s->container);
|
||||
return 0;
|
||||
|
@ -85,7 +89,7 @@ static void a15mp_priv_class_init(ObjectClass *klass, void *data)
|
|||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
|
||||
k->init = a15mp_priv_init;
|
||||
dc->props = a15mp_priv_properties;
|
||||
/* We currently have no savable state outside the common GIC state */
|
||||
/* We currently have no savable state */
|
||||
}
|
||||
|
||||
static TypeInfo a15mp_priv_info = {
|
||||
|
|
|
@ -10,32 +10,19 @@
|
|||
|
||||
#include "sysbus.h"
|
||||
|
||||
/* Configuration for arm_gic.c:
|
||||
* max number of CPUs, how to ID current CPU
|
||||
*/
|
||||
#define NCPU 4
|
||||
|
||||
static inline int
|
||||
gic_get_current_cpu(void)
|
||||
{
|
||||
return cpu_single_env->cpu_index;
|
||||
}
|
||||
|
||||
#include "arm_gic.c"
|
||||
|
||||
/* A9MP private memory region. */
|
||||
|
||||
typedef struct a9mp_priv_state {
|
||||
gic_state gic;
|
||||
SysBusDevice busdev;
|
||||
uint32_t scu_control;
|
||||
uint32_t scu_status;
|
||||
uint32_t old_timer_status[8];
|
||||
uint32_t num_cpu;
|
||||
qemu_irq *timer_irq;
|
||||
MemoryRegion scu_iomem;
|
||||
MemoryRegion ptimer_iomem;
|
||||
MemoryRegion container;
|
||||
DeviceState *mptimer;
|
||||
DeviceState *gic;
|
||||
uint32_t num_irq;
|
||||
} a9mp_priv_state;
|
||||
|
||||
|
@ -124,18 +111,9 @@ static const MemoryRegionOps a9_scu_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
|
||||
{
|
||||
a9mp_priv_state *s = (a9mp_priv_state *)opaque;
|
||||
if (level && !s->old_timer_status[irq]) {
|
||||
gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
|
||||
}
|
||||
s->old_timer_status[irq] = level;
|
||||
}
|
||||
|
||||
static void a9mp_priv_reset(DeviceState *dev)
|
||||
{
|
||||
a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
|
||||
a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, sysbus_from_qdev(dev));
|
||||
int i;
|
||||
s->scu_control = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
|
||||
|
@ -143,17 +121,29 @@ static void a9mp_priv_reset(DeviceState *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void a9mp_priv_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
a9mp_priv_state *s = (a9mp_priv_state *)opaque;
|
||||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static int a9mp_priv_init(SysBusDevice *dev)
|
||||
{
|
||||
a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
|
||||
SysBusDevice *busdev;
|
||||
a9mp_priv_state *s = FROM_SYSBUS(a9mp_priv_state, dev);
|
||||
SysBusDevice *busdev, *gicbusdev;
|
||||
int i;
|
||||
|
||||
if (s->num_cpu > NCPU) {
|
||||
hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
|
||||
}
|
||||
s->gic = qdev_create(NULL, "arm_gic");
|
||||
qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
|
||||
qdev_init_nofail(s->gic);
|
||||
gicbusdev = sysbus_from_qdev(s->gic);
|
||||
|
||||
gic_init(&s->gic, s->num_cpu, s->num_irq);
|
||||
/* Pass through outbound IRQ lines from the GIC */
|
||||
sysbus_pass_irq(dev, gicbusdev);
|
||||
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(&s->busdev.qdev, a9mp_priv_set_irq, s->num_irq - 32);
|
||||
|
||||
s->mptimer = qdev_create(NULL, "arm_mptimer");
|
||||
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
||||
|
@ -175,7 +165,8 @@ static int a9mp_priv_init(SysBusDevice *dev)
|
|||
memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
|
||||
memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
|
||||
/* GIC CPU interface */
|
||||
memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
|
||||
memory_region_add_subregion(&s->container, 0x100,
|
||||
sysbus_mmio_get_region(gicbusdev, 1));
|
||||
/* Note that the A9 exposes only the "timer/watchdog for this core"
|
||||
* memory region, not the "timer/watchdog for core X" ones 11MPcore has.
|
||||
*/
|
||||
|
@ -183,15 +174,20 @@ static int a9mp_priv_init(SysBusDevice *dev)
|
|||
sysbus_mmio_get_region(busdev, 0));
|
||||
memory_region_add_subregion(&s->container, 0x620,
|
||||
sysbus_mmio_get_region(busdev, 1));
|
||||
memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
|
||||
memory_region_add_subregion(&s->container, 0x1000,
|
||||
sysbus_mmio_get_region(gicbusdev, 0));
|
||||
|
||||
sysbus_init_mmio(dev, &s->container);
|
||||
|
||||
/* Wire up the interrupt from each watchdog and timer. */
|
||||
s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
|
||||
s, (s->num_cpu + 1) * 2);
|
||||
for (i = 0; i < s->num_cpu * 2; i++) {
|
||||
sysbus_connect_irq(busdev, i, s->timer_irq[i]);
|
||||
/* Wire up the interrupt from each watchdog and timer.
|
||||
* For each core the timer is PPI 29 and the watchdog PPI 30.
|
||||
*/
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
int ppibase = (s->num_irq - 32) + i * 32;
|
||||
sysbus_connect_irq(busdev, i * 2,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 29));
|
||||
sysbus_connect_irq(busdev, i * 2 + 1,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 30));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -10,28 +10,18 @@
|
|||
#include "sysbus.h"
|
||||
#include "qemu-timer.h"
|
||||
|
||||
#define NCPU 4
|
||||
|
||||
static inline int
|
||||
gic_get_current_cpu(void)
|
||||
{
|
||||
return cpu_single_env->cpu_index;
|
||||
}
|
||||
|
||||
#include "arm_gic.c"
|
||||
|
||||
/* MPCore private memory region. */
|
||||
|
||||
typedef struct mpcore_priv_state {
|
||||
gic_state gic;
|
||||
SysBusDevice busdev;
|
||||
uint32_t scu_control;
|
||||
int iomemtype;
|
||||
uint32_t old_timer_status[8];
|
||||
uint32_t num_cpu;
|
||||
qemu_irq *timer_irq;
|
||||
MemoryRegion iomem;
|
||||
MemoryRegion container;
|
||||
DeviceState *mptimer;
|
||||
DeviceState *gic;
|
||||
uint32_t num_irq;
|
||||
} mpcore_priv_state;
|
||||
|
||||
|
@ -81,18 +71,16 @@ static const MemoryRegionOps mpcore_scu_ops = {
|
|||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
|
||||
static void mpcore_priv_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
mpcore_priv_state *s = (mpcore_priv_state *)opaque;
|
||||
if (level && !s->old_timer_status[irq]) {
|
||||
gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
|
||||
}
|
||||
s->old_timer_status[irq] = level;
|
||||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static void mpcore_priv_map_setup(mpcore_priv_state *s)
|
||||
{
|
||||
int i;
|
||||
SysBusDevice *gicbusdev = sysbus_from_qdev(s->gic);
|
||||
SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
|
||||
memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
|
||||
memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
|
||||
|
@ -102,31 +90,47 @@ static void mpcore_priv_map_setup(mpcore_priv_state *s)
|
|||
*/
|
||||
for (i = 0; i < (s->num_cpu + 1); i++) {
|
||||
target_phys_addr_t offset = 0x100 + (i * 0x100);
|
||||
memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
|
||||
memory_region_add_subregion(&s->container, offset,
|
||||
sysbus_mmio_get_region(gicbusdev, i + 1));
|
||||
}
|
||||
/* Add the regions for timer and watchdog for "current CPU" and
|
||||
* for each specific CPU.
|
||||
*/
|
||||
s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
|
||||
s, (s->num_cpu + 1) * 2);
|
||||
for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
|
||||
/* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
|
||||
target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
|
||||
memory_region_add_subregion(&s->container, offset,
|
||||
sysbus_mmio_get_region(busdev, i));
|
||||
}
|
||||
memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
|
||||
/* Wire up the interrupt from each watchdog and timer. */
|
||||
for (i = 0; i < s->num_cpu * 2; i++) {
|
||||
sysbus_connect_irq(busdev, i, s->timer_irq[i]);
|
||||
memory_region_add_subregion(&s->container, 0x1000,
|
||||
sysbus_mmio_get_region(gicbusdev, 0));
|
||||
/* Wire up the interrupt from each watchdog and timer.
|
||||
* For each core the timer is PPI 29 and the watchdog PPI 30.
|
||||
*/
|
||||
for (i = 0; i < s->num_cpu; i++) {
|
||||
int ppibase = (s->num_irq - 32) + i * 32;
|
||||
sysbus_connect_irq(busdev, i * 2,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 29));
|
||||
sysbus_connect_irq(busdev, i * 2 + 1,
|
||||
qdev_get_gpio_in(s->gic, ppibase + 30));
|
||||
}
|
||||
}
|
||||
|
||||
static int mpcore_priv_init(SysBusDevice *dev)
|
||||
{
|
||||
mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
|
||||
mpcore_priv_state *s = FROM_SYSBUS(mpcore_priv_state, dev);
|
||||
|
||||
s->gic = qdev_create(NULL, "arm_gic");
|
||||
qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(s->gic, "num-irq", s->num_irq);
|
||||
qdev_init_nofail(s->gic);
|
||||
|
||||
/* Pass through outbound IRQ lines from the GIC */
|
||||
sysbus_pass_irq(dev, sysbus_from_qdev(s->gic));
|
||||
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(&s->busdev.qdev, mpcore_priv_set_irq, s->num_irq - 32);
|
||||
|
||||
gic_init(&s->gic, s->num_cpu, s->num_irq);
|
||||
s->mptimer = qdev_create(NULL, "arm_mptimer");
|
||||
qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
|
||||
qdev_init_nofail(s->mptimer);
|
||||
|
|
157
hw/arm_gic.c
157
hw/arm_gic.c
|
@ -8,13 +8,29 @@
|
|||
*/
|
||||
|
||||
/* This file contains implementation code for the RealView EB interrupt
|
||||
controller, MPCore distributed interrupt controller and ARMv7-M
|
||||
Nested Vectored Interrupt Controller. */
|
||||
* controller, MPCore distributed interrupt controller and ARMv7-M
|
||||
* Nested Vectored Interrupt Controller.
|
||||
* It is compiled in two ways:
|
||||
* (1) as a standalone file to produce a sysbus device which is a GIC
|
||||
* that can be used on the realview board and as one of the builtin
|
||||
* private peripherals for the ARM MP CPUs (11MPCore, A9, etc)
|
||||
* (2) by being directly #included into armv7m_nvic.c to produce the
|
||||
* armv7m_nvic device.
|
||||
*/
|
||||
|
||||
#include "sysbus.h"
|
||||
|
||||
/* Maximum number of possible interrupts, determined by the GIC architecture */
|
||||
#define GIC_MAXIRQ 1020
|
||||
/* First 32 are private to each CPU (SGIs and PPIs). */
|
||||
#define GIC_INTERNAL 32
|
||||
/* Maximum number of possible CPU interfaces, determined by GIC architecture */
|
||||
#ifdef NVIC
|
||||
#define NCPU 1
|
||||
#else
|
||||
#define NCPU 8
|
||||
#endif
|
||||
|
||||
//#define DEBUG_GIC
|
||||
|
||||
#ifdef DEBUG_GIC
|
||||
|
@ -50,7 +66,7 @@ typedef struct gic_irq_state
|
|||
unsigned trigger:1; /* nonzero = edge triggered. */
|
||||
} gic_irq_state;
|
||||
|
||||
#define ALL_CPU_MASK ((1 << NCPU) - 1)
|
||||
#define ALL_CPU_MASK ((unsigned)(((1 << NCPU) - 1)))
|
||||
#if NCPU > 1
|
||||
#define NUM_CPU(s) ((s)->num_cpu)
|
||||
#else
|
||||
|
@ -105,7 +121,7 @@ typedef struct gic_state
|
|||
int current_pending[NCPU];
|
||||
|
||||
#if NCPU > 1
|
||||
int num_cpu;
|
||||
uint32_t num_cpu;
|
||||
#endif
|
||||
|
||||
MemoryRegion iomem; /* Distributor */
|
||||
|
@ -119,6 +135,16 @@ typedef struct gic_state
|
|||
uint32_t num_irq;
|
||||
} gic_state;
|
||||
|
||||
static inline int gic_get_current_cpu(gic_state *s)
|
||||
{
|
||||
#if NCPU > 1
|
||||
if (s->num_cpu > 1) {
|
||||
return cpu_single_env->cpu_index;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO: Many places that call this routine could be optimized. */
|
||||
/* Update interrupt status after enabled or pending bits have been changed. */
|
||||
static void gic_update(gic_state *s)
|
||||
|
@ -134,7 +160,7 @@ static void gic_update(gic_state *s)
|
|||
cm = 1 << cpu;
|
||||
s->current_pending[cpu] = 1023;
|
||||
if (!s->enabled || !s->cpu_enabled[cpu]) {
|
||||
qemu_irq_lower(s->parent_irq[cpu]);
|
||||
qemu_irq_lower(s->parent_irq[cpu]);
|
||||
return;
|
||||
}
|
||||
best_prio = 0x100;
|
||||
|
@ -159,8 +185,8 @@ static void gic_update(gic_state *s)
|
|||
}
|
||||
}
|
||||
|
||||
static void __attribute__((unused))
|
||||
gic_set_pending_private(gic_state *s, int cpu, int irq)
|
||||
#ifdef NVIC
|
||||
static void gic_set_pending_private(gic_state *s, int cpu, int irq)
|
||||
{
|
||||
int cm = 1 << cpu;
|
||||
|
||||
|
@ -171,24 +197,45 @@ gic_set_pending_private(gic_state *s, int cpu, int irq)
|
|||
GIC_SET_PENDING(irq, cm);
|
||||
gic_update(s);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Process a change in an external IRQ input. */
|
||||
static void gic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
/* Meaning of the 'irq' parameter:
|
||||
* [0..N-1] : external interrupts
|
||||
* [N..N+31] : PPI (internal) interrupts for CPU 0
|
||||
* [N+32..N+63] : PPI (internal interrupts for CPU 1
|
||||
* ...
|
||||
*/
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
/* The first external input line is internal interrupt 32. */
|
||||
irq += GIC_INTERNAL;
|
||||
if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
|
||||
int cm, target;
|
||||
if (irq < (s->num_irq - GIC_INTERNAL)) {
|
||||
/* The first external input line is internal interrupt 32. */
|
||||
cm = ALL_CPU_MASK;
|
||||
irq += GIC_INTERNAL;
|
||||
target = GIC_TARGET(irq);
|
||||
} else {
|
||||
int cpu;
|
||||
irq -= (s->num_irq - GIC_INTERNAL);
|
||||
cpu = irq / GIC_INTERNAL;
|
||||
irq %= GIC_INTERNAL;
|
||||
cm = 1 << cpu;
|
||||
target = cm;
|
||||
}
|
||||
|
||||
if (level == GIC_TEST_LEVEL(irq, cm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (level) {
|
||||
GIC_SET_LEVEL(irq, ALL_CPU_MASK);
|
||||
if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, ALL_CPU_MASK)) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
|
||||
GIC_SET_PENDING(irq, GIC_TARGET(irq));
|
||||
GIC_SET_LEVEL(irq, cm);
|
||||
if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) {
|
||||
DPRINTF("Set %d pending mask %x\n", irq, target);
|
||||
GIC_SET_PENDING(irq, target);
|
||||
}
|
||||
} else {
|
||||
GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
|
||||
GIC_CLEAR_LEVEL(irq, cm);
|
||||
}
|
||||
gic_update(s);
|
||||
}
|
||||
|
@ -278,7 +325,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
|
|||
int cm;
|
||||
int mask;
|
||||
|
||||
cpu = gic_get_current_cpu();
|
||||
cpu = gic_get_current_cpu(s);
|
||||
cm = 1 << cpu;
|
||||
if (offset < 0x100) {
|
||||
#ifndef NVIC
|
||||
|
@ -413,7 +460,7 @@ static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
|
|||
int i;
|
||||
int cpu;
|
||||
|
||||
cpu = gic_get_current_cpu();
|
||||
cpu = gic_get_current_cpu(s);
|
||||
if (offset < 0x100) {
|
||||
#ifdef NVIC
|
||||
goto bad_reg;
|
||||
|
@ -575,7 +622,7 @@ static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
|
|||
int irq;
|
||||
int mask;
|
||||
|
||||
cpu = gic_get_current_cpu();
|
||||
cpu = gic_get_current_cpu(s);
|
||||
irq = value & 0x3ff;
|
||||
switch ((value >> 24) & 3) {
|
||||
case 0:
|
||||
|
@ -658,14 +705,14 @@ static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
|
|||
unsigned size)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
return gic_cpu_read(s, gic_get_current_cpu(), addr);
|
||||
return gic_cpu_read(s, gic_get_current_cpu(s), addr);
|
||||
}
|
||||
|
||||
static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
gic_state *s = (gic_state *)opaque;
|
||||
gic_cpu_write(s, gic_get_current_cpu(), addr, value);
|
||||
gic_cpu_write(s, gic_get_current_cpu(s), addr, value);
|
||||
}
|
||||
|
||||
/* Wrappers to read/write the GIC CPU interface for a specific CPU.
|
||||
|
@ -702,8 +749,9 @@ static const MemoryRegionOps gic_cpu_ops = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static void gic_reset(gic_state *s)
|
||||
static void gic_reset(DeviceState *dev)
|
||||
{
|
||||
gic_state *s = FROM_SYSBUS(gic_state, sysbus_from_qdev(dev));
|
||||
int i;
|
||||
memset(s->irq_state, 0, GIC_MAXIRQ * sizeof(gic_irq_state));
|
||||
for (i = 0 ; i < NUM_CPU(s); i++) {
|
||||
|
@ -813,6 +861,10 @@ static void gic_init(gic_state *s, int num_irq)
|
|||
|
||||
#if NCPU > 1
|
||||
s->num_cpu = num_cpu;
|
||||
if (s->num_cpu > NCPU) {
|
||||
hw_error("requested %u CPUs exceeds GIC maximum %d\n",
|
||||
num_cpu, NCPU);
|
||||
}
|
||||
#endif
|
||||
s->num_irq = num_irq + GIC_BASE_IRQ;
|
||||
if (s->num_irq > GIC_MAXIRQ) {
|
||||
|
@ -828,7 +880,18 @@ static void gic_init(gic_state *s, int num_irq)
|
|||
num_irq);
|
||||
}
|
||||
|
||||
qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - GIC_INTERNAL);
|
||||
i = s->num_irq - GIC_INTERNAL;
|
||||
#ifndef NVIC
|
||||
/* For the GIC, also expose incoming GPIO lines for PPIs for each CPU.
|
||||
* GPIO array layout is thus:
|
||||
* [0..N-1] SPIs
|
||||
* [N..N+31] PPIs for CPU 0
|
||||
* [N+32..N+63] PPIs for CPU 1
|
||||
* ...
|
||||
*/
|
||||
i += (GIC_INTERNAL * num_cpu);
|
||||
#endif
|
||||
qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, i);
|
||||
for (i = 0; i < NUM_CPU(s); i++) {
|
||||
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
|
||||
}
|
||||
|
@ -851,6 +914,54 @@ static void gic_init(gic_state *s, int num_irq)
|
|||
}
|
||||
#endif
|
||||
|
||||
gic_reset(s);
|
||||
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
|
||||
}
|
||||
|
||||
#ifndef NVIC
|
||||
|
||||
static int arm_gic_init(SysBusDevice *dev)
|
||||
{
|
||||
/* Device instance init function for the GIC sysbus device */
|
||||
int i;
|
||||
gic_state *s = FROM_SYSBUS(gic_state, dev);
|
||||
gic_init(s, s->num_cpu, s->num_irq);
|
||||
/* Distributor */
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
/* cpu interfaces (one for "current cpu" plus one per cpu) */
|
||||
for (i = 0; i <= NUM_CPU(s); i++) {
|
||||
sysbus_init_mmio(dev, &s->cpuiomem[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Property arm_gic_properties[] = {
|
||||
DEFINE_PROP_UINT32("num-cpu", gic_state, num_cpu, 1),
|
||||
DEFINE_PROP_UINT32("num-irq", gic_state, num_irq, 32),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void arm_gic_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
sbc->init = arm_gic_init;
|
||||
dc->props = arm_gic_properties;
|
||||
dc->reset = gic_reset;
|
||||
dc->no_user = 1;
|
||||
}
|
||||
|
||||
static TypeInfo arm_gic_info = {
|
||||
.name = "arm_gic",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(gic_state),
|
||||
.class_init = arm_gic_class_init,
|
||||
};
|
||||
|
||||
static void arm_gic_register_types(void)
|
||||
{
|
||||
type_register_static(&arm_gic_info);
|
||||
}
|
||||
|
||||
type_init(arm_gic_register_types)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,16 +15,8 @@
|
|||
#include "arm-misc.h"
|
||||
#include "exec-memory.h"
|
||||
|
||||
#define NCPU 1
|
||||
#define NVIC 1
|
||||
|
||||
/* Only a single "CPU" interface is present. */
|
||||
static inline int
|
||||
gic_get_current_cpu(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t nvic_readl(void *opaque, uint32_t offset);
|
||||
static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
|
||||
|
||||
|
@ -83,6 +75,14 @@ static void systick_timer_tick(void * opaque)
|
|||
}
|
||||
}
|
||||
|
||||
static void systick_reset(nvic_state *s)
|
||||
{
|
||||
s->systick.control = 0;
|
||||
s->systick.reload = 0;
|
||||
s->systick.tick = 0;
|
||||
qemu_del_timer(s->systick.timer);
|
||||
}
|
||||
|
||||
/* The external routines use the hardware vector numbering, ie. the first
|
||||
IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
|
||||
void armv7m_nvic_set_pending(void *opaque, int irq)
|
||||
|
@ -378,6 +378,13 @@ static const VMStateDescription vmstate_nvic = {
|
|||
}
|
||||
};
|
||||
|
||||
static void armv7m_nvic_reset(DeviceState *dev)
|
||||
{
|
||||
nvic_state *s = FROM_SYSBUSGIC(nvic_state, sysbus_from_qdev(dev));
|
||||
gic_reset(&s->gic.busdev.qdev);
|
||||
systick_reset(s);
|
||||
}
|
||||
|
||||
static int armv7m_nvic_init(SysBusDevice *dev)
|
||||
{
|
||||
nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
|
||||
|
@ -407,6 +414,7 @@ static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
|
|||
|
||||
sdc->init = armv7m_nvic_init;
|
||||
dc->vmsd = &vmstate_nvic;
|
||||
dc->reset = armv7m_nvic_reset;
|
||||
dc->props = armv7m_nvic_properties;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "sysemu.h"
|
||||
#include "sysbus.h"
|
||||
#include "arm-misc.h"
|
||||
#include "loader.h"
|
||||
#include "exynos4210.h"
|
||||
|
||||
#define EXYNOS4210_CHIPID_ADDR 0x10000000
|
||||
|
@ -64,6 +65,35 @@
|
|||
static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
|
||||
0x09, 0x00, 0x00, 0x00 };
|
||||
|
||||
void exynos4210_write_secondary(CPUARMState *env,
|
||||
const struct arm_boot_info *info)
|
||||
{
|
||||
int n;
|
||||
uint32_t smpboot[] = {
|
||||
0xe59f3024, /* ldr r3, External gic_cpu_if */
|
||||
0xe59f2024, /* ldr r2, Internal gic_cpu_if */
|
||||
0xe59f0024, /* ldr r0, startaddr */
|
||||
0xe3a01001, /* mov r1, #1 */
|
||||
0xe5821000, /* str r1, [r2] */
|
||||
0xe5831000, /* str r1, [r3] */
|
||||
0xe320f003, /* wfi */
|
||||
0xe5901000, /* ldr r1, [r0] */
|
||||
0xe1110001, /* tst r1, r1 */
|
||||
0x0afffffb, /* beq <wfi> */
|
||||
0xe12fff11, /* bx r1 */
|
||||
EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
|
||||
0, /* gic_cpu_if: base address of Internal GIC CPU interface */
|
||||
0 /* bootreg: Boot register address is held here */
|
||||
};
|
||||
smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
|
||||
smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
|
||||
for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
|
||||
smpboot[n] = tswap32(smpboot[n]);
|
||||
}
|
||||
rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
|
||||
info->smp_loader_start);
|
||||
}
|
||||
|
||||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
unsigned long ram_size)
|
||||
{
|
||||
|
|
|
@ -97,6 +97,9 @@ typedef struct Exynos4210State {
|
|||
MemoryRegion bootreg_mem;
|
||||
} Exynos4210State;
|
||||
|
||||
void exynos4210_write_secondary(CPUARMState *env,
|
||||
const struct arm_boot_info *info);
|
||||
|
||||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
|
||||
unsigned long ram_size);
|
||||
|
||||
|
|
|
@ -184,11 +184,6 @@ exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size)
|
|||
uint32_t reg_n; /* Register number inside the quad */
|
||||
uint32_t val;
|
||||
|
||||
if (s->external && (offset > 0x3c && offset != 0x100)) {
|
||||
hw_error("exynos4210.combiner: unallowed read access at offset 0x"
|
||||
TARGET_FMT_plx "\n", offset);
|
||||
}
|
||||
|
||||
req_quad_base_n = offset >> 4;
|
||||
grp_quad_base_n = req_quad_base_n << 2;
|
||||
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
|
||||
|
@ -281,11 +276,6 @@ static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset,
|
|||
uint32_t grp_quad_base_n; /* Base of group quad */
|
||||
uint32_t reg_n; /* Register number inside the quad */
|
||||
|
||||
if (s->external && (offset > 0x3c && offset != 0x100)) {
|
||||
hw_error("exynos4210.combiner: unallowed write access at offset 0x"
|
||||
TARGET_FMT_plx "\n", offset);
|
||||
}
|
||||
|
||||
req_quad_base_n = offset >> 4;
|
||||
grp_quad_base_n = req_quad_base_n << 2;
|
||||
reg_n = (offset - (req_quad_base_n << 4)) >> 2;
|
||||
|
|
|
@ -174,7 +174,6 @@ combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
|
|||
};
|
||||
|
||||
#define EXYNOS4210_GIC_NIRQ 160
|
||||
#define NCPU EXYNOS4210_NCPUS
|
||||
|
||||
#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
|
||||
#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
|
||||
|
@ -263,33 +262,44 @@ uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
|
|||
|
||||
/********* GIC part *********/
|
||||
|
||||
static inline int
|
||||
gic_get_current_cpu(void)
|
||||
{
|
||||
return cpu_single_env->cpu_index;
|
||||
}
|
||||
|
||||
#include "arm_gic.c"
|
||||
|
||||
typedef struct {
|
||||
gic_state gic;
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion cpu_container;
|
||||
MemoryRegion dist_container;
|
||||
MemoryRegion cpu_alias[NCPU];
|
||||
MemoryRegion dist_alias[NCPU];
|
||||
MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
|
||||
MemoryRegion dist_alias[EXYNOS4210_NCPUS];
|
||||
uint32_t num_cpu;
|
||||
DeviceState *gic;
|
||||
} Exynos4210GicState;
|
||||
|
||||
static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
Exynos4210GicState *s = (Exynos4210GicState *)opaque;
|
||||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static int exynos4210_gic_init(SysBusDevice *dev)
|
||||
{
|
||||
Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev);
|
||||
Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
|
||||
uint32_t i;
|
||||
const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
|
||||
const char dist_prefix[] = "exynos4210-gic-alias_dist";
|
||||
char cpu_alias_name[sizeof(cpu_prefix) + 3];
|
||||
char dist_alias_name[sizeof(cpu_prefix) + 3];
|
||||
SysBusDevice *busdev;
|
||||
|
||||
gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ);
|
||||
s->gic = qdev_create(NULL, "arm_gic");
|
||||
qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
|
||||
qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
|
||||
qdev_init_nofail(s->gic);
|
||||
busdev = sysbus_from_qdev(s->gic);
|
||||
|
||||
/* Pass through outbound IRQ lines from the GIC */
|
||||
sysbus_pass_irq(dev, busdev);
|
||||
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
|
||||
EXYNOS4210_GIC_NIRQ - 32);
|
||||
|
||||
memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
|
||||
EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
|
||||
|
@ -301,7 +311,7 @@ static int exynos4210_gic_init(SysBusDevice *dev)
|
|||
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
|
||||
memory_region_init_alias(&s->cpu_alias[i],
|
||||
cpu_alias_name,
|
||||
&s->gic.cpuiomem[0],
|
||||
sysbus_mmio_get_region(busdev, 1),
|
||||
0,
|
||||
EXYNOS4210_GIC_CPU_REGION_SIZE);
|
||||
memory_region_add_subregion(&s->cpu_container,
|
||||
|
@ -311,7 +321,7 @@ static int exynos4210_gic_init(SysBusDevice *dev)
|
|||
sprintf(dist_alias_name, "%s%x", dist_prefix, i);
|
||||
memory_region_init_alias(&s->dist_alias[i],
|
||||
dist_alias_name,
|
||||
&s->gic.iomem,
|
||||
sysbus_mmio_get_region(busdev, 0),
|
||||
0,
|
||||
EXYNOS4210_GIC_DIST_REGION_SIZE);
|
||||
memory_region_add_subregion(&s->dist_container,
|
||||
|
@ -321,8 +331,6 @@ static int exynos4210_gic_init(SysBusDevice *dev)
|
|||
sysbus_init_mmio(dev, &s->cpu_container);
|
||||
sysbus_init_mmio(dev, &s->dist_container);
|
||||
|
||||
gic_cpu_write(&s->gic, 1, 0, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -361,7 +369,7 @@ type_init(exynos4210_gic_register_types)
|
|||
typedef struct {
|
||||
SysBusDevice busdev;
|
||||
|
||||
qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */
|
||||
qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */
|
||||
uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
|
||||
} Exynos4210IRQGateState;
|
||||
|
||||
|
@ -426,7 +434,7 @@ static int exynos4210_irq_gate_init(SysBusDevice *dev)
|
|||
EXYNOS4210_IRQ_GATE_NINPUTS);
|
||||
|
||||
/* Connect SysBusDev irqs to device specific irqs */
|
||||
for (i = 0; i < NCPU; i++) {
|
||||
for (i = 0; i < EXYNOS4210_NCPUS; i++) {
|
||||
sysbus_init_irq(dev, &s->pic_irq[i]);
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,7 @@ static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
|
|||
uint32_t level = 0;
|
||||
uint32_t reg;
|
||||
|
||||
reg = (s->reg[I_(UFCON)] && UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
|
||||
reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
|
||||
UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
|
||||
|
||||
switch (s->channel) {
|
||||
|
@ -275,9 +275,9 @@ static void exynos4210_uart_update_irq(Exynos4210UartState *s)
|
|||
* The Tx interrupt is always requested if the number of data in the
|
||||
* transmit FIFO is smaller than the trigger level.
|
||||
*/
|
||||
if (s->reg[I_(UFCON)] && UFCON_FIFO_ENABLE) {
|
||||
if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
|
||||
|
||||
uint32_t count = (s->reg[I_(UFSTAT)] && UFSTAT_Tx_FIFO_COUNT) >>
|
||||
uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
|
||||
UFSTAT_Tx_FIFO_COUNT_SHIFT;
|
||||
|
||||
if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
|
||||
|
|
|
@ -70,6 +70,7 @@ static struct arm_boot_info exynos4_board_binfo = {
|
|||
.loader_start = EXYNOS4210_BASE_BOOT_ADDR,
|
||||
.smp_loader_start = EXYNOS4210_SMP_BOOT_ADDR,
|
||||
.nb_cpus = EXYNOS4210_NCPUS,
|
||||
.write_secondary_boot = exynos4210_write_secondary,
|
||||
};
|
||||
|
||||
static QEMUMachine exynos4_machines[EXYNOS4_NUM_OF_BOARDS];
|
||||
|
|
|
@ -9,39 +9,45 @@
|
|||
|
||||
#include "sysbus.h"
|
||||
|
||||
#define NCPU 1
|
||||
|
||||
/* Only a single "CPU" interface is present. */
|
||||
static inline int
|
||||
gic_get_current_cpu(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "arm_gic.c"
|
||||
|
||||
typedef struct {
|
||||
gic_state gic;
|
||||
SysBusDevice busdev;
|
||||
DeviceState *gic;
|
||||
MemoryRegion container;
|
||||
} RealViewGICState;
|
||||
|
||||
static void realview_gic_map_setup(RealViewGICState *s)
|
||||
static void realview_gic_set_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
memory_region_init(&s->container, "realview-gic-container", 0x2000);
|
||||
memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]);
|
||||
memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
|
||||
RealViewGICState *s = (RealViewGICState *)opaque;
|
||||
qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
|
||||
}
|
||||
|
||||
static int realview_gic_init(SysBusDevice *dev)
|
||||
{
|
||||
RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
|
||||
|
||||
RealViewGICState *s = FROM_SYSBUS(RealViewGICState, dev);
|
||||
SysBusDevice *busdev;
|
||||
/* The GICs on the RealView boards have a fixed nonconfigurable
|
||||
* number of interrupt lines, so we don't need to expose this as
|
||||
* a qdev property.
|
||||
*/
|
||||
gic_init(&s->gic, 96);
|
||||
realview_gic_map_setup(s);
|
||||
int numirq = 96;
|
||||
|
||||
s->gic = qdev_create(NULL, "arm_gic");
|
||||
qdev_prop_set_uint32(s->gic, "num-cpu", 1);
|
||||
qdev_prop_set_uint32(s->gic, "num-irq", numirq);
|
||||
qdev_init_nofail(s->gic);
|
||||
busdev = sysbus_from_qdev(s->gic);
|
||||
|
||||
/* Pass through outbound IRQ lines from the GIC */
|
||||
sysbus_pass_irq(dev, busdev);
|
||||
|
||||
/* Pass through inbound GPIO lines to the GIC */
|
||||
qdev_init_gpio_in(&s->busdev.qdev, realview_gic_set_irq, numirq - 32);
|
||||
|
||||
memory_region_init(&s->container, "realview-gic-container", 0x2000);
|
||||
memory_region_add_subregion(&s->container, 0,
|
||||
sysbus_mmio_get_region(busdev, 1));
|
||||
memory_region_add_subregion(&s->container, 0x1000,
|
||||
sysbus_mmio_get_region(busdev, 0));
|
||||
sysbus_init_mmio(dev, &s->container);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue