Skip to content

Commit

Permalink
hw/arm/exynos4210: Fix DMA initialization
Browse files Browse the repository at this point in the history
First parameter to exynos4210_get_irq() is not the SPI port number,
but the interrupt group number. Interrupt groups are 20 for mdma
and 21 for pdma. Interrupts are not inverted. Controllers support 32
events (pdma) or 31 events (mdma). Events must all be routed to a single
interrupt line. Set other parameters as documented in Exynos4210 datasheet,
section 8 (DMA controller).

Fixes: 59520dc ("hw/arm/exynos4210: Add DMA support for the Exynos4210")
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Message-id: 20200123052540.6132-4-linux@roeck-us.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
  • Loading branch information
groeck authored and pm215 committed Jan 23, 2020
1 parent ddf59e9 commit dab15fb
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 8 deletions.
51 changes: 43 additions & 8 deletions hw/arm/exynos4210.c
Expand Up @@ -166,17 +166,36 @@ static uint64_t exynos4210_calc_affinity(int cpu)
return (0x9 << ARM_AFF1_SHIFT) | cpu;
}

static void pl330_create(uint32_t base, qemu_irq irq, int nreq)
static void pl330_create(uint32_t base, qemu_or_irq *orgate, qemu_irq irq,
int nreq, int nevents, int width)
{
SysBusDevice *busdev;
DeviceState *dev;
int i;

dev = qdev_create(NULL, "pl330");
qdev_prop_set_uint8(dev, "num_events", nevents);
qdev_prop_set_uint8(dev, "num_chnls", 8);
qdev_prop_set_uint8(dev, "num_periph_req", nreq);

qdev_prop_set_uint8(dev, "wr_cap", 4);
qdev_prop_set_uint8(dev, "wr_q_dep", 8);
qdev_prop_set_uint8(dev, "rd_cap", 4);
qdev_prop_set_uint8(dev, "rd_q_dep", 8);
qdev_prop_set_uint8(dev, "data_width", width);
qdev_prop_set_uint16(dev, "data_buffer_dep", width);
qdev_init_nofail(dev);
busdev = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(busdev, 0, base);
sysbus_connect_irq(busdev, 0, irq);

object_property_set_int(OBJECT(orgate), nevents + 1, "num-lines",
&error_abort);
object_property_set_bool(OBJECT(orgate), true, "realized", &error_abort);

for (i = 0; i < nevents + 1; i++) {
sysbus_connect_irq(busdev, i, qdev_get_gpio_in(DEVICE(orgate), i));
}
qdev_connect_gpio_out(DEVICE(orgate), 0, irq);
}

static void exynos4210_realize(DeviceState *socdev, Error **errp)
Expand Down Expand Up @@ -431,12 +450,27 @@ static void exynos4210_realize(DeviceState *socdev, Error **errp)
s->irq_table[exynos4210_get_irq(28, 3)]);

/*** DMA controllers ***/
pl330_create(EXYNOS4210_PL330_BASE0_ADDR,
qemu_irq_invert(s->irq_table[exynos4210_get_irq(35, 1)]), 32);
pl330_create(EXYNOS4210_PL330_BASE1_ADDR,
qemu_irq_invert(s->irq_table[exynos4210_get_irq(36, 1)]), 32);
pl330_create(EXYNOS4210_PL330_BASE2_ADDR,
qemu_irq_invert(s->irq_table[exynos4210_get_irq(34, 1)]), 1);
pl330_create(EXYNOS4210_PL330_BASE0_ADDR, &s->pl330_irq_orgate[0],
s->irq_table[exynos4210_get_irq(21, 0)], 32, 32, 32);
pl330_create(EXYNOS4210_PL330_BASE1_ADDR, &s->pl330_irq_orgate[1],
s->irq_table[exynos4210_get_irq(21, 1)], 32, 32, 32);
pl330_create(EXYNOS4210_PL330_BASE2_ADDR, &s->pl330_irq_orgate[2],
s->irq_table[exynos4210_get_irq(20, 1)], 1, 31, 64);
}

static void exynos4210_init(Object *obj)
{
Exynos4210State *s = EXYNOS4210_SOC(obj);
int i;

for (i = 0; i < ARRAY_SIZE(s->pl330_irq_orgate); i++) {
char *name = g_strdup_printf("pl330-irq-orgate%d", i);
qemu_or_irq *orgate = &s->pl330_irq_orgate[i];

object_initialize_child(obj, name, orgate, sizeof(*orgate),
TYPE_OR_IRQ, &error_abort, NULL);
g_free(name);
}
}

static void exynos4210_class_init(ObjectClass *klass, void *data)
Expand All @@ -450,6 +484,7 @@ static const TypeInfo exynos4210_info = {
.name = TYPE_EXYNOS4210_SOC,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(Exynos4210State),
.instance_init = exynos4210_init,
.class_init = exynos4210_class_init,
};

Expand Down
4 changes: 4 additions & 0 deletions include/hw/arm/exynos4210.h
Expand Up @@ -24,6 +24,7 @@
#ifndef EXYNOS4210_H
#define EXYNOS4210_H

#include "hw/or-irq.h"
#include "hw/sysbus.h"
#include "target/arm/cpu-qom.h"

Expand Down Expand Up @@ -74,6 +75,8 @@

#define EXYNOS4210_I2C_NUMBER 9

#define EXYNOS4210_NUM_DMA 3

typedef struct Exynos4210Irq {
qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ];
Expand All @@ -97,6 +100,7 @@ typedef struct Exynos4210State {
MemoryRegion boot_secondary;
MemoryRegion bootreg_mem;
I2CBus *i2c_if[EXYNOS4210_I2C_NUMBER];
qemu_or_irq pl330_irq_orgate[EXYNOS4210_NUM_DMA];
} Exynos4210State;

#define TYPE_EXYNOS4210_SOC "exynos4210"
Expand Down

0 comments on commit dab15fb

Please sign in to comment.