143e3346eSAndrew Jeffery /* 243e3346eSAndrew Jeffery * AST2400 SoC 343e3346eSAndrew Jeffery * 443e3346eSAndrew Jeffery * Andrew Jeffery <andrew@aj.id.au> 543e3346eSAndrew Jeffery * Jeremy Kerr <jk@ozlabs.org> 643e3346eSAndrew Jeffery * 743e3346eSAndrew Jeffery * Copyright 2016 IBM Corp. 843e3346eSAndrew Jeffery * 943e3346eSAndrew Jeffery * This code is licensed under the GPL version 2 or later. See 1043e3346eSAndrew Jeffery * the COPYING file in the top-level directory. 1143e3346eSAndrew Jeffery */ 1243e3346eSAndrew Jeffery 1343e3346eSAndrew Jeffery #include "qemu/osdep.h" 14da34e65cSMarkus Armbruster #include "qapi/error.h" 154771d756SPaolo Bonzini #include "qemu-common.h" 164771d756SPaolo Bonzini #include "cpu.h" 1743e3346eSAndrew Jeffery #include "exec/address-spaces.h" 1800442402SCédric Le Goater #include "hw/arm/aspeed_soc.h" 1943e3346eSAndrew Jeffery #include "hw/char/serial.h" 2003dd024fSPaolo Bonzini #include "qemu/log.h" 2116020011SCédric Le Goater #include "hw/i2c/aspeed_i2c.h" 2243e3346eSAndrew Jeffery 2343e3346eSAndrew Jeffery #define AST2400_UART_5_BASE 0x00184000 2443e3346eSAndrew Jeffery #define AST2400_IOMEM_SIZE 0x00200000 2543e3346eSAndrew Jeffery #define AST2400_IOMEM_BASE 0x1E600000 267c1c69bcSCédric Le Goater #define AST2400_SMC_BASE AST2400_IOMEM_BASE /* Legacy SMC */ 277c1c69bcSCédric Le Goater #define AST2400_FMC_BASE 0X1E620000 287c1c69bcSCédric Le Goater #define AST2400_SPI_BASE 0X1E630000 2943e3346eSAndrew Jeffery #define AST2400_VIC_BASE 0x1E6C0000 30c2da8a8bSCédric Le Goater #define AST2400_SDMC_BASE 0x1E6E0000 31334973bbSAndrew Jeffery #define AST2400_SCU_BASE 0x1E6E2000 3243e3346eSAndrew Jeffery #define AST2400_TIMER_BASE 0x1E782000 3316020011SCédric Le Goater #define AST2400_I2C_BASE 0x1E78A000 3443e3346eSAndrew Jeffery 35924ed163SCédric Le Goater #define AST2400_FMC_FLASH_BASE 0x20000000 36924ed163SCédric Le Goater #define AST2400_SPI_FLASH_BASE 0x30000000 37924ed163SCédric Le Goater 3843e3346eSAndrew Jeffery static const int uart_irqs[] = { 9, 32, 33, 34, 10 }; 3943e3346eSAndrew Jeffery static const int timer_irqs[] = { 16, 17, 18, 35, 36, 37, 38, 39, }; 4043e3346eSAndrew Jeffery 4143e3346eSAndrew Jeffery /* 4243e3346eSAndrew Jeffery * IO handlers: simply catch any reads/writes to IO addresses that aren't 4343e3346eSAndrew Jeffery * handled by a device mapping. 4443e3346eSAndrew Jeffery */ 4543e3346eSAndrew Jeffery 4643e3346eSAndrew Jeffery static uint64_t ast2400_io_read(void *p, hwaddr offset, unsigned size) 4743e3346eSAndrew Jeffery { 4843e3346eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " [%u]\n", 4943e3346eSAndrew Jeffery __func__, offset, size); 5043e3346eSAndrew Jeffery return 0; 5143e3346eSAndrew Jeffery } 5243e3346eSAndrew Jeffery 5343e3346eSAndrew Jeffery static void ast2400_io_write(void *opaque, hwaddr offset, uint64_t value, 5443e3346eSAndrew Jeffery unsigned size) 5543e3346eSAndrew Jeffery { 5643e3346eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx " <- 0x%" PRIx64 " [%u]\n", 5743e3346eSAndrew Jeffery __func__, offset, value, size); 5843e3346eSAndrew Jeffery } 5943e3346eSAndrew Jeffery 6043e3346eSAndrew Jeffery static const MemoryRegionOps ast2400_io_ops = { 6143e3346eSAndrew Jeffery .read = ast2400_io_read, 6243e3346eSAndrew Jeffery .write = ast2400_io_write, 6343e3346eSAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 6443e3346eSAndrew Jeffery }; 6543e3346eSAndrew Jeffery 6643e3346eSAndrew Jeffery static void ast2400_init(Object *obj) 6743e3346eSAndrew Jeffery { 6843e3346eSAndrew Jeffery AST2400State *s = AST2400(obj); 6943e3346eSAndrew Jeffery 7043e3346eSAndrew Jeffery s->cpu = cpu_arm_init("arm926"); 7143e3346eSAndrew Jeffery 7243e3346eSAndrew Jeffery object_initialize(&s->vic, sizeof(s->vic), TYPE_ASPEED_VIC); 7343e3346eSAndrew Jeffery object_property_add_child(obj, "vic", OBJECT(&s->vic), NULL); 7443e3346eSAndrew Jeffery qdev_set_parent_bus(DEVICE(&s->vic), sysbus_get_default()); 7543e3346eSAndrew Jeffery 7643e3346eSAndrew Jeffery object_initialize(&s->timerctrl, sizeof(s->timerctrl), TYPE_ASPEED_TIMER); 7743e3346eSAndrew Jeffery object_property_add_child(obj, "timerctrl", OBJECT(&s->timerctrl), NULL); 7843e3346eSAndrew Jeffery qdev_set_parent_bus(DEVICE(&s->timerctrl), sysbus_get_default()); 7916020011SCédric Le Goater 8016020011SCédric Le Goater object_initialize(&s->i2c, sizeof(s->i2c), TYPE_ASPEED_I2C); 8116020011SCédric Le Goater object_property_add_child(obj, "i2c", OBJECT(&s->i2c), NULL); 8216020011SCédric Le Goater qdev_set_parent_bus(DEVICE(&s->i2c), sysbus_get_default()); 83334973bbSAndrew Jeffery 84334973bbSAndrew Jeffery object_initialize(&s->scu, sizeof(s->scu), TYPE_ASPEED_SCU); 85334973bbSAndrew Jeffery object_property_add_child(obj, "scu", OBJECT(&s->scu), NULL); 86334973bbSAndrew Jeffery qdev_set_parent_bus(DEVICE(&s->scu), sysbus_get_default()); 87334973bbSAndrew Jeffery qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", 88334973bbSAndrew Jeffery AST2400_A0_SILICON_REV); 89334973bbSAndrew Jeffery object_property_add_alias(obj, "hw-strap1", OBJECT(&s->scu), 90334973bbSAndrew Jeffery "hw-strap1", &error_abort); 91334973bbSAndrew Jeffery object_property_add_alias(obj, "hw-strap2", OBJECT(&s->scu), 92334973bbSAndrew Jeffery "hw-strap2", &error_abort); 937c1c69bcSCédric Le Goater 947c1c69bcSCédric Le Goater object_initialize(&s->smc, sizeof(s->smc), "aspeed.smc.fmc"); 957c1c69bcSCédric Le Goater object_property_add_child(obj, "smc", OBJECT(&s->smc), NULL); 967c1c69bcSCédric Le Goater qdev_set_parent_bus(DEVICE(&s->smc), sysbus_get_default()); 977c1c69bcSCédric Le Goater 987c1c69bcSCédric Le Goater object_initialize(&s->spi, sizeof(s->spi), "aspeed.smc.spi"); 997c1c69bcSCédric Le Goater object_property_add_child(obj, "spi", OBJECT(&s->spi), NULL); 1007c1c69bcSCédric Le Goater qdev_set_parent_bus(DEVICE(&s->spi), sysbus_get_default()); 101c2da8a8bSCédric Le Goater 102c2da8a8bSCédric Le Goater object_initialize(&s->sdmc, sizeof(s->sdmc), TYPE_ASPEED_SDMC); 103c2da8a8bSCédric Le Goater object_property_add_child(obj, "sdmc", OBJECT(&s->sdmc), NULL); 104c2da8a8bSCédric Le Goater qdev_set_parent_bus(DEVICE(&s->sdmc), sysbus_get_default()); 105c2da8a8bSCédric Le Goater qdev_prop_set_uint32(DEVICE(&s->sdmc), "silicon-rev", 106c2da8a8bSCédric Le Goater AST2400_A0_SILICON_REV); 10743e3346eSAndrew Jeffery } 10843e3346eSAndrew Jeffery 10943e3346eSAndrew Jeffery static void ast2400_realize(DeviceState *dev, Error **errp) 11043e3346eSAndrew Jeffery { 11143e3346eSAndrew Jeffery int i; 11243e3346eSAndrew Jeffery AST2400State *s = AST2400(dev); 1137c1c69bcSCédric Le Goater Error *err = NULL, *local_err = NULL; 11443e3346eSAndrew Jeffery 11543e3346eSAndrew Jeffery /* IO space */ 11643e3346eSAndrew Jeffery memory_region_init_io(&s->iomem, NULL, &ast2400_io_ops, NULL, 11743e3346eSAndrew Jeffery "ast2400.io", AST2400_IOMEM_SIZE); 11843e3346eSAndrew Jeffery memory_region_add_subregion_overlap(get_system_memory(), AST2400_IOMEM_BASE, 11943e3346eSAndrew Jeffery &s->iomem, -1); 12043e3346eSAndrew Jeffery 12143e3346eSAndrew Jeffery /* VIC */ 12243e3346eSAndrew Jeffery object_property_set_bool(OBJECT(&s->vic), true, "realized", &err); 12343e3346eSAndrew Jeffery if (err) { 12443e3346eSAndrew Jeffery error_propagate(errp, err); 12543e3346eSAndrew Jeffery return; 12643e3346eSAndrew Jeffery } 12743e3346eSAndrew Jeffery sysbus_mmio_map(SYS_BUS_DEVICE(&s->vic), 0, AST2400_VIC_BASE); 12843e3346eSAndrew Jeffery sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 0, 12943e3346eSAndrew Jeffery qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_IRQ)); 13043e3346eSAndrew Jeffery sysbus_connect_irq(SYS_BUS_DEVICE(&s->vic), 1, 13143e3346eSAndrew Jeffery qdev_get_gpio_in(DEVICE(s->cpu), ARM_CPU_FIQ)); 13243e3346eSAndrew Jeffery 13343e3346eSAndrew Jeffery /* Timer */ 13443e3346eSAndrew Jeffery object_property_set_bool(OBJECT(&s->timerctrl), true, "realized", &err); 13543e3346eSAndrew Jeffery if (err) { 13643e3346eSAndrew Jeffery error_propagate(errp, err); 13743e3346eSAndrew Jeffery return; 13843e3346eSAndrew Jeffery } 13943e3346eSAndrew Jeffery sysbus_mmio_map(SYS_BUS_DEVICE(&s->timerctrl), 0, AST2400_TIMER_BASE); 14043e3346eSAndrew Jeffery for (i = 0; i < ARRAY_SIZE(timer_irqs); i++) { 14143e3346eSAndrew Jeffery qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->vic), timer_irqs[i]); 14243e3346eSAndrew Jeffery sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq); 14343e3346eSAndrew Jeffery } 14443e3346eSAndrew Jeffery 145334973bbSAndrew Jeffery /* SCU */ 146334973bbSAndrew Jeffery object_property_set_bool(OBJECT(&s->scu), true, "realized", &err); 147334973bbSAndrew Jeffery if (err) { 148334973bbSAndrew Jeffery error_propagate(errp, err); 149334973bbSAndrew Jeffery return; 150334973bbSAndrew Jeffery } 151334973bbSAndrew Jeffery sysbus_mmio_map(SYS_BUS_DEVICE(&s->scu), 0, AST2400_SCU_BASE); 152334973bbSAndrew Jeffery 15343e3346eSAndrew Jeffery /* UART - attach an 8250 to the IO space as our UART5 */ 15443e3346eSAndrew Jeffery if (serial_hds[0]) { 15543e3346eSAndrew Jeffery qemu_irq uart5 = qdev_get_gpio_in(DEVICE(&s->vic), uart_irqs[4]); 15643e3346eSAndrew Jeffery serial_mm_init(&s->iomem, AST2400_UART_5_BASE, 2, 15743e3346eSAndrew Jeffery uart5, 38400, serial_hds[0], DEVICE_LITTLE_ENDIAN); 15843e3346eSAndrew Jeffery } 15916020011SCédric Le Goater 16016020011SCédric Le Goater /* I2C */ 16116020011SCédric Le Goater object_property_set_bool(OBJECT(&s->i2c), true, "realized", &err); 16216020011SCédric Le Goater if (err) { 16316020011SCédric Le Goater error_propagate(errp, err); 16416020011SCédric Le Goater return; 16516020011SCédric Le Goater } 16616020011SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->i2c), 0, AST2400_I2C_BASE); 16716020011SCédric Le Goater sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), 0, 16816020011SCédric Le Goater qdev_get_gpio_in(DEVICE(&s->vic), 12)); 1697c1c69bcSCédric Le Goater 1707c1c69bcSCédric Le Goater /* SMC */ 1717c1c69bcSCédric Le Goater object_property_set_int(OBJECT(&s->smc), 1, "num-cs", &err); 1727c1c69bcSCédric Le Goater object_property_set_bool(OBJECT(&s->smc), true, "realized", &local_err); 1737c1c69bcSCédric Le Goater error_propagate(&err, local_err); 1747c1c69bcSCédric Le Goater if (err) { 1757c1c69bcSCédric Le Goater error_propagate(errp, err); 1767c1c69bcSCédric Le Goater return; 1777c1c69bcSCédric Le Goater } 1787c1c69bcSCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 0, AST2400_FMC_BASE); 179924ed163SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->smc), 1, AST2400_FMC_FLASH_BASE); 1807c1c69bcSCédric Le Goater sysbus_connect_irq(SYS_BUS_DEVICE(&s->smc), 0, 1817c1c69bcSCédric Le Goater qdev_get_gpio_in(DEVICE(&s->vic), 19)); 1827c1c69bcSCédric Le Goater 1837c1c69bcSCédric Le Goater /* SPI */ 1847c1c69bcSCédric Le Goater object_property_set_int(OBJECT(&s->spi), 1, "num-cs", &err); 1857c1c69bcSCédric Le Goater object_property_set_bool(OBJECT(&s->spi), true, "realized", &local_err); 1867c1c69bcSCédric Le Goater error_propagate(&err, local_err); 1877c1c69bcSCédric Le Goater if (err) { 1887c1c69bcSCédric Le Goater error_propagate(errp, err); 1897c1c69bcSCédric Le Goater return; 1907c1c69bcSCédric Le Goater } 1917c1c69bcSCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 0, AST2400_SPI_BASE); 192924ed163SCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi), 1, AST2400_SPI_FLASH_BASE); 193c2da8a8bSCédric Le Goater 194c2da8a8bSCédric Le Goater /* SDMC - SDRAM Memory Controller */ 195c2da8a8bSCédric Le Goater object_property_set_bool(OBJECT(&s->sdmc), true, "realized", &err); 196c2da8a8bSCédric Le Goater if (err) { 197c2da8a8bSCédric Le Goater error_propagate(errp, err); 198c2da8a8bSCédric Le Goater return; 199c2da8a8bSCédric Le Goater } 200c2da8a8bSCédric Le Goater sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdmc), 0, AST2400_SDMC_BASE); 20143e3346eSAndrew Jeffery } 20243e3346eSAndrew Jeffery 20343e3346eSAndrew Jeffery static void ast2400_class_init(ObjectClass *oc, void *data) 20443e3346eSAndrew Jeffery { 20543e3346eSAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(oc); 20643e3346eSAndrew Jeffery 20743e3346eSAndrew Jeffery dc->realize = ast2400_realize; 20843e3346eSAndrew Jeffery 20943e3346eSAndrew Jeffery /* 21043e3346eSAndrew Jeffery * Reason: creates an ARM CPU, thus use after free(), see 21143e3346eSAndrew Jeffery * arm_cpu_class_init() 21243e3346eSAndrew Jeffery */ 21343e3346eSAndrew Jeffery dc->cannot_destroy_with_object_finalize_yet = true; 21443e3346eSAndrew Jeffery } 21543e3346eSAndrew Jeffery 21643e3346eSAndrew Jeffery static const TypeInfo ast2400_type_info = { 21743e3346eSAndrew Jeffery .name = TYPE_AST2400, 21843e3346eSAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 21943e3346eSAndrew Jeffery .instance_size = sizeof(AST2400State), 22043e3346eSAndrew Jeffery .instance_init = ast2400_init, 22143e3346eSAndrew Jeffery .class_init = ast2400_class_init, 22243e3346eSAndrew Jeffery }; 22343e3346eSAndrew Jeffery 22443e3346eSAndrew Jeffery static void ast2400_register_types(void) 22543e3346eSAndrew Jeffery { 22643e3346eSAndrew Jeffery type_register_static(&ast2400_type_info); 22743e3346eSAndrew Jeffery } 22843e3346eSAndrew Jeffery 22943e3346eSAndrew Jeffery type_init(ast2400_register_types) 230