diff options
author | Fabien Chouteau <chouteau@adacore.com> | 2019-02-12 18:38:39 +0100 |
---|---|---|
committer | Palmer Dabbelt <palmer@sifive.com> | 2019-05-24 11:58:30 -0700 |
commit | 30efbf330a45fc5b83457037927151adafc397ed (patch) | |
tree | 89111532c51d904f467ed1d879c239a775d5a43c /hw/riscv/sifive_e.c | |
parent | a7b21f6762a2d6ec08106d8a7ccb11829914523f (diff) | |
download | qemu-30efbf330a45fc5b83457037927151adafc397ed.zip qemu-30efbf330a45fc5b83457037927151adafc397ed.tar.gz qemu-30efbf330a45fc5b83457037927151adafc397ed.tar.bz2 |
SiFive RISC-V GPIO Device
QEMU model of the GPIO device on the SiFive E300 series SOCs.
The pins are not used by a board definition yet, however this
implementation can already be used to trigger GPIO interrupts from the
software by configuring a pin as both output and input.
Signed-off-by: Fabien Chouteau <chouteau@adacore.com>
Reviewed-by: Palmer Dabbelt <palmer@sifive.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
Diffstat (limited to 'hw/riscv/sifive_e.c')
-rw-r--r-- | hw/riscv/sifive_e.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index b1cd113..80ac56f 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -146,11 +146,15 @@ static void riscv_sifive_e_soc_init(Object *obj) &error_abort); object_property_set_int(OBJECT(&s->cpus), smp_cpus, "num-harts", &error_abort); + sysbus_init_child_obj(obj, "riscv.sifive.e.gpio0", + &s->gpio, sizeof(s->gpio), + TYPE_SIFIVE_GPIO); } static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) { const struct MemmapEntry *memmap = sifive_e_memmap; + Error *err = NULL; SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); @@ -184,8 +188,28 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon", memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); sifive_prci_create(memmap[SIFIVE_E_PRCI].base); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.gpio0", - memmap[SIFIVE_E_GPIO0].base, memmap[SIFIVE_E_GPIO0].size); + + /* GPIO */ + + object_property_set_bool(OBJECT(&s->gpio), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + + /* Map GPIO registers */ + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_E_GPIO0].base); + + /* Pass all GPIOs to the SOC layer so they are available to the board */ + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); + + /* Connect GPIO interrupts to the PLIC */ + for (int i = 0; i < 32; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, + qdev_get_gpio_in(DEVICE(s->plic), + SIFIVE_E_GPIO0_IRQ0 + i)); + } + sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base, serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ)); sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0", |