@@ -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
new file mode 100644
@@ -0,0 +1,208 @@
+/*
+ * ASPEED AST2400
+ *
+ * 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/arm.h"
+#include "hw/boards.h"
+#include "hw/char/serial.h"
+#include "hw/sysbus.h"
+#include "hw/intc/aspeed_vic.h"
+#include "hw/timer/aspeed_timer.h"
+#include "target-arm/cpu.h"
+#include "trace.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
+#define AST2400_SDRAM_BASE 0x40000000
+
+static const int uart_irqs[] = { 9, 32, 33, 34, 10 };
+static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, };
+
+static struct arm_boot_info ast2400_binfo = {
+ .loader_start = AST2400_SDRAM_BASE,
+ .board_id = 0,
+ .nb_cpus = 1,
+};
+
+/*
+ * IO handlers: simply catch any reads/writes to IO addresses that aren't
+ * handled by a device mapping.
+ */
+
+static uint64_t ast2400_soc_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_soc_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_soc_io_ops = {
+ .read = ast2400_soc_io_read,
+ .write = ast2400_soc_io_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+typedef struct AST2400SOCState {
+ /*< private >*/
+ DeviceState parent;
+
+ /*< public >*/
+ ARMCPU *cpu;
+ MemoryRegion iomem;
+ AspeedVICState vic;
+ AspeedTimerCtrlState timerctrl;
+} AST2400SOCState;
+
+#define TYPE_AST2400_SOC "ast2400-soc"
+#define AST2400_SOC(obj) OBJECT_CHECK(AST2400SOCState, (obj), TYPE_AST2400_SOC)
+
+static void ast2400_soc_init(Object *obj)
+{
+ AST2400SOCState *s = AST2400_SOC(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_soc_realize(DeviceState *dev, Error **errp)
+{
+ int i;
+ AST2400SOCState *s = AST2400_SOC(dev);
+ Error *err = NULL;
+
+ /* IO space */
+ memory_region_init_io(&s->iomem, NULL, &ast2400_soc_io_ops, NULL,
+ "ast2400.io", AST2400_IOMEM_SIZE);
+ memory_region_add_subregion(get_system_memory(), AST2400_IOMEM_BASE,
+ &s->iomem);
+
+ /* 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_soc_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ dc->realize = ast2400_soc_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_soc_type_info = {
+ .name = TYPE_AST2400_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(AST2400SOCState),
+ .instance_init = ast2400_soc_init,
+ .class_init = ast2400_soc_class_init,
+};
+
+static void ast2400_soc_register_types(void)
+{
+ type_register_static(&ast2400_soc_type_info);
+}
+
+type_init(ast2400_soc_register_types)
+
+typedef struct AST2400State {
+ AST2400SOCState soc;
+ MemoryRegion ram;
+} AST2400State;
+
+static void ast2400_init(MachineState *machine)
+{
+ AST2400State *ast2400;
+
+ ast2400 = g_new0(AST2400State, 1);
+ object_initialize(&ast2400->soc, (sizeof(ast2400->soc)), TYPE_AST2400_SOC);
+ object_property_add_child(OBJECT(machine), "soc", OBJECT(&ast2400->soc),
+ &error_abort);
+
+ memory_region_allocate_system_memory(&ast2400->ram, NULL, "ram",
+ ram_size);
+ memory_region_add_subregion(get_system_memory(), AST2400_SDRAM_BASE,
+ &ast2400->ram);
+ object_property_add_const_link(OBJECT(&ast2400->soc), "ram",
+ OBJECT(&ast2400->ram), &error_abort);
+ object_property_set_bool(OBJECT(&ast2400->soc), true, "realized",
+ &error_abort);
+
+ ast2400_binfo.kernel_filename = machine->kernel_filename;
+ ast2400_binfo.initrd_filename = machine->initrd_filename;
+ ast2400_binfo.kernel_cmdline = machine->kernel_cmdline;
+ ast2400_binfo.ram_size = ram_size;
+ arm_load_kernel(ARM_CPU(first_cpu), &ast2400_binfo);
+}
+
+static void ast2400_machine_init(MachineClass *mc)
+{
+ mc->desc = "ASPEED AST2400 BMC (ARM926EJ-S)";
+ mc->init = ast2400_init;
+ mc->max_cpus = 1;
+ mc->no_sdcard = 1;
+ mc->no_floppy = 1;
+ mc->no_cdrom = 1;
+ mc->no_sdcard = 1;
+ mc->no_parallel = 1;
+}
+
+DEFINE_MACHINE("ast2400", ast2400_machine_init);
Adds an AST2400 ARM machine[1], based around an AST2400 SOC containing an ARM926 processor, ASPEED VIC and timer devices, and a 8250 UART. The new machine type is functional enough to boot an aspeed_defconfig Linux kernel to userspace. [1] http://www.aspeedtech.com/products.php?fPath=20&rId=376 Signed-off-by: Andrew Jeffery <andrew@aj.id.au> --- Since v2: * Implement a SOC model to move code out from the machine definition * Rework the machine to better use QOM * Include qemu/osdep.h * Revert back to qemu_log_mask(LOG_UNIMP, ...) in IO handlers Since v1: hw/arm/Makefile.objs | 1 + hw/arm/ast2400.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 hw/arm/ast2400.c