ARM: Exynos4210 IRQ: Introduce new IRQ gate functionality.
New IRQ gate consists of n_in input qdev gpio lines and one output sysbus IRQ line. The output IRQ level is formed as OR between all gpio inputs. Signed-off-by: Evgeny Voevodin <e.voevodin@samsung.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
							parent
							
								
									8aca521512
								
							
						
					
					
						commit
						61558e7a75
					
				| 
						 | 
				
			
			@ -97,11 +97,11 @@ void exynos4210_write_secondary(ARMCPU *cpu,
 | 
			
		|||
Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
 | 
			
		||||
        unsigned long ram_size)
 | 
			
		||||
{
 | 
			
		||||
    qemu_irq cpu_irq[4];
 | 
			
		||||
    int n;
 | 
			
		||||
    qemu_irq cpu_irq[EXYNOS4210_NCPUS];
 | 
			
		||||
    int i, n;
 | 
			
		||||
    Exynos4210State *s = g_new(Exynos4210State, 1);
 | 
			
		||||
    qemu_irq *irqp;
 | 
			
		||||
    qemu_irq gate_irq[EXYNOS4210_IRQ_GATE_NINPUTS];
 | 
			
		||||
    qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
 | 
			
		||||
    unsigned long mem_size;
 | 
			
		||||
    DeviceState *dev;
 | 
			
		||||
    SysBusDevice *busdev;
 | 
			
		||||
| 
						 | 
				
			
			@ -128,16 +128,18 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
 | 
			
		|||
    s->irq_table = exynos4210_init_irq(&s->irqs);
 | 
			
		||||
 | 
			
		||||
    /* IRQ Gate */
 | 
			
		||||
    dev = qdev_create(NULL, "exynos4210.irq_gate");
 | 
			
		||||
    qdev_init_nofail(dev);
 | 
			
		||||
    /* Get IRQ Gate input in gate_irq */
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
 | 
			
		||||
        gate_irq[n] = qdev_get_gpio_in(dev, n);
 | 
			
		||||
    }
 | 
			
		||||
    busdev = sysbus_from_qdev(dev);
 | 
			
		||||
    /* Connect IRQ Gate output to cpu_irq */
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
 | 
			
		||||
        sysbus_connect_irq(busdev, n, cpu_irq[n]);
 | 
			
		||||
    for (i = 0; i < EXYNOS4210_NCPUS; i++) {
 | 
			
		||||
        dev = qdev_create(NULL, "exynos4210.irq_gate");
 | 
			
		||||
        qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
 | 
			
		||||
        qdev_init_nofail(dev);
 | 
			
		||||
        /* Get IRQ Gate input in gate_irq */
 | 
			
		||||
        for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
 | 
			
		||||
            gate_irq[i][n] = qdev_get_gpio_in(dev, n);
 | 
			
		||||
        }
 | 
			
		||||
        busdev = sysbus_from_qdev(dev);
 | 
			
		||||
 | 
			
		||||
        /* Connect IRQ Gate output to cpu_irq */
 | 
			
		||||
        sysbus_connect_irq(busdev, 0, cpu_irq[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Private memory region and Internal GIC */
 | 
			
		||||
| 
						 | 
				
			
			@ -147,7 +149,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
 | 
			
		|||
    busdev = sysbus_from_qdev(dev);
 | 
			
		||||
    sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
 | 
			
		||||
        sysbus_connect_irq(busdev, n, gate_irq[n * 2]);
 | 
			
		||||
        sysbus_connect_irq(busdev, n, gate_irq[n][0]);
 | 
			
		||||
    }
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
 | 
			
		||||
        s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +168,7 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
 | 
			
		|||
    /* Map Distributer interface */
 | 
			
		||||
    sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_NCPUS; n++) {
 | 
			
		||||
        sysbus_connect_irq(busdev, n, gate_irq[n * 2 + 1]);
 | 
			
		||||
        sysbus_connect_irq(busdev, n, gate_irq[n][1]);
 | 
			
		||||
    }
 | 
			
		||||
    for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
 | 
			
		||||
        s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,7 +56,7 @@
 | 
			
		|||
/*
 | 
			
		||||
 * exynos4210 IRQ subsystem stub definitions.
 | 
			
		||||
 */
 | 
			
		||||
#define EXYNOS4210_IRQ_GATE_NINPUTS 8
 | 
			
		||||
#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
 | 
			
		||||
 | 
			
		||||
#define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ  64
 | 
			
		||||
#define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ  16
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -362,61 +362,64 @@ static void exynos4210_gic_register_types(void)
 | 
			
		|||
 | 
			
		||||
type_init(exynos4210_gic_register_types)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * IRQGate struct.
 | 
			
		||||
 * IRQ Gate represents OR gate between GICs to pass IRQ to PIC.
 | 
			
		||||
/* IRQ OR Gate struct.
 | 
			
		||||
 *
 | 
			
		||||
 * This device models an OR gate. There are n_in input qdev gpio lines and one
 | 
			
		||||
 * output sysbus IRQ line. The output IRQ level is formed as OR between all
 | 
			
		||||
 * gpio inputs.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    SysBusDevice busdev;
 | 
			
		||||
 | 
			
		||||
    qemu_irq pic_irq[EXYNOS4210_NCPUS]; /* output IRQs to PICs */
 | 
			
		||||
    uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */
 | 
			
		||||
    uint32_t n_in;      /* inputs amount */
 | 
			
		||||
    uint32_t *level;    /* input levels */
 | 
			
		||||
    qemu_irq out;       /* output IRQ */
 | 
			
		||||
} Exynos4210IRQGateState;
 | 
			
		||||
 | 
			
		||||
static Property exynos4210_irq_gate_properties[] = {
 | 
			
		||||
    DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
 | 
			
		||||
    DEFINE_PROP_END_OF_LIST(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const VMStateDescription vmstate_exynos4210_irq_gate = {
 | 
			
		||||
    .name = "exynos4210.irq_gate",
 | 
			
		||||
    .version_id = 1,
 | 
			
		||||
    .minimum_version_id = 1,
 | 
			
		||||
    .minimum_version_id_old = 1,
 | 
			
		||||
    .version_id = 2,
 | 
			
		||||
    .minimum_version_id = 2,
 | 
			
		||||
    .minimum_version_id_old = 2,
 | 
			
		||||
    .fields = (VMStateField[]) {
 | 
			
		||||
        VMSTATE_UINT32_ARRAY(gpio_level, Exynos4210IRQGateState,
 | 
			
		||||
                EXYNOS4210_IRQ_GATE_NINPUTS),
 | 
			
		||||
        VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
 | 
			
		||||
        VMSTATE_END_OF_LIST()
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Process a change in an external IRQ input.  */
 | 
			
		||||
/* Process a change in IRQ input. */
 | 
			
		||||
static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
 | 
			
		||||
{
 | 
			
		||||
    Exynos4210IRQGateState *s =
 | 
			
		||||
            (Exynos4210IRQGateState *)opaque;
 | 
			
		||||
    uint32_t odd, even;
 | 
			
		||||
    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
 | 
			
		||||
    if (irq & 1) {
 | 
			
		||||
        odd = irq;
 | 
			
		||||
        even = irq & ~1;
 | 
			
		||||
    } else {
 | 
			
		||||
        even = irq;
 | 
			
		||||
        odd = irq | 1;
 | 
			
		||||
    assert(irq < s->n_in);
 | 
			
		||||
 | 
			
		||||
    s->level[irq] = level;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->n_in; i++) {
 | 
			
		||||
        if (s->level[i] >= 1) {
 | 
			
		||||
            qemu_irq_raise(s->out);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert(irq < EXYNOS4210_IRQ_GATE_NINPUTS);
 | 
			
		||||
    s->gpio_level[irq] = level;
 | 
			
		||||
 | 
			
		||||
    if (s->gpio_level[odd] >= 1 || s->gpio_level[even] >= 1) {
 | 
			
		||||
        qemu_irq_raise(s->pic_irq[even >> 1]);
 | 
			
		||||
    } else {
 | 
			
		||||
        qemu_irq_lower(s->pic_irq[even >> 1]);
 | 
			
		||||
    }
 | 
			
		||||
    qemu_irq_lower(s->out);
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void exynos4210_irq_gate_reset(DeviceState *d)
 | 
			
		||||
{
 | 
			
		||||
    Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)d;
 | 
			
		||||
    Exynos4210IRQGateState *s =
 | 
			
		||||
            DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
 | 
			
		||||
 | 
			
		||||
    memset(&s->gpio_level, 0, sizeof(s->gpio_level));
 | 
			
		||||
    memset(s->level, 0, s->n_in * sizeof(*s->level));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -424,19 +427,15 @@ static void exynos4210_irq_gate_reset(DeviceState *d)
 | 
			
		|||
 */
 | 
			
		||||
static int exynos4210_irq_gate_init(SysBusDevice *dev)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
    Exynos4210IRQGateState *s =
 | 
			
		||||
            FROM_SYSBUS(Exynos4210IRQGateState, dev);
 | 
			
		||||
    Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev);
 | 
			
		||||
 | 
			
		||||
    /* Allocate general purpose input signals and connect a handler to each of
 | 
			
		||||
     * them */
 | 
			
		||||
    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler,
 | 
			
		||||
            EXYNOS4210_IRQ_GATE_NINPUTS);
 | 
			
		||||
    qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in);
 | 
			
		||||
 | 
			
		||||
    /* Connect SysBusDev irqs to device specific irqs */
 | 
			
		||||
    for (i = 0; i < EXYNOS4210_NCPUS; i++) {
 | 
			
		||||
        sysbus_init_irq(dev, &s->pic_irq[i]);
 | 
			
		||||
    }
 | 
			
		||||
    s->level = g_malloc0(s->n_in * sizeof(*s->level));
 | 
			
		||||
 | 
			
		||||
    sysbus_init_irq(dev, &s->out);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -449,6 +448,7 @@ static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
 | 
			
		|||
    k->init = exynos4210_irq_gate_init;
 | 
			
		||||
    dc->reset = exynos4210_irq_gate_reset;
 | 
			
		||||
    dc->vmsd = &vmstate_exynos4210_irq_gate;
 | 
			
		||||
    dc->props = exynos4210_irq_gate_properties;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static TypeInfo exynos4210_irq_gate_info = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue