diff options
author | Andrew Jeffery | 2016-03-16 18:06:00 +0100 |
---|---|---|
committer | Peter Maydell | 2016-03-16 18:42:18 +0100 |
commit | 43e3346e43f005500f1d2e44318bf8b28f0ba086 (patch) | |
tree | f8a22d6bfab6357ac474e203abfd45765ef9cf48 /hw | |
parent | hw/intc: Add (new) ASPEED VIC device model (diff) | |
download | qemu-43e3346e43f005500f1d2e44318bf8b28f0ba086.tar.gz qemu-43e3346e43f005500f1d2e44318bf8b28f0ba086.tar.xz qemu-43e3346e43f005500f1d2e44318bf8b28f0ba086.zip |
hw/arm: Add ASPEED AST2400 SoC model
While the ASPEED AST2400 SoC[1] has a broad range of capabilities this
implementation is minimal, comprising an ARM926 processor, ASPEED VIC
and timer devices, and a 8250 UART.
[1] http://www.aspeedtech.com/products.php?fPath=20&rId=376
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Message-id: 1458096317-25223-4-git-send-email-andrew@aj.id.au
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/arm/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/arm/ast2400.c | 137 |
2 files changed, 138 insertions, 0 deletions
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs index a711e4df61..f333b7f009 100644 --- a/hw/arm/Makefile.objs +++ b/hw/arm/Makefile.objs @@ -16,3 +16,4 @@ obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o obj-$(CONFIG_XLNX_ZYNQMP) += xlnx-zynqmp.o xlnx-ep108.o obj-$(CONFIG_FSL_IMX25) += fsl-imx25.o imx25_pdk.o obj-$(CONFIG_FSL_IMX31) += fsl-imx31.o kzm.o +obj-$(CONFIG_ASPEED_SOC) += ast2400.o diff --git a/hw/arm/ast2400.c b/hw/arm/ast2400.c new file mode 100644 index 0000000000..daa5518c92 --- /dev/null +++ b/hw/arm/ast2400.c @@ -0,0 +1,137 @@ +/* + * AST2400 SoC + * + * Andrew Jeffery <andrew@aj.id.au> + * Jeremy Kerr <jk@ozlabs.org> + * + * Copyright 2016 IBM Corp. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "exec/address-spaces.h" +#include "hw/arm/ast2400.h" +#include "hw/char/serial.h" + +#define AST2400_UART_5_BASE 0x00184000 +#define AST2400_IOMEM_SIZE 0x00200000 +#define AST2400_IOMEM_BASE 0x1E600000 +#define AST2400_VIC_BASE 0x1E6C0000 +#define AST2400_TIMER_BASE 0x1E782000 + +static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; +static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; + +/* + * IO handlers: simply catch any reads/writes to IO addresses that aren't + * handled by a device mapping. + */ + +static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", + __func__, offset, size); + return 0; +} + +static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, + unsigned size) +{ + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", + __func__, offset, value, size); +} + +static const MemoryRegionOps ast2400_io_ops = { + .read = ast2400_io_read, + .write = ast2400_io_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static void ast2400_init(Object *obj) +{ + AST2400State *s = AST2400(obj); + + s->cpu = cpu_arm_init("arm926"); + + object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); + object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); + qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); + + object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); + object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); + qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); +} + +static void ast2400_realize(DeviceState *dev, Error **errp) +{ + int i; + AST2400State *s = AST2400(dev); + Error *err = NULL; + + /* IO space */ + memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, + "ast2400.io", AST2400_IOMEM_SIZE); + memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, + &s->iomem, -1); + + /* VIC */ + object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, + qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); + + /* Timer */ + object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); + for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { + qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); + } + + /* UART - attach an 8250 to the IO space as our UART5 */ + if (serial_hds[0]) { + qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); + serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, + uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); + } +} + +static void ast2400_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = ast2400_realize; + + /* + * Reason: creates an ARM CPU, thus use after free(), see + * arm_cpu_class_init() + */ + dc->cannot_destroy_with_object_finalize_yet = true; +} + +static const TypeInfo ast2400_type_info = { + .name = TYPE_AST2400, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AST2400State), + .instance_init = ast2400_init, + .class_init = ast2400_class_init, +}; + +static void ast2400_register_types(void) +{ + type_register_static(&ast2400_type_info); +} + +type_init(ast2400_register_types) |