13a0f31bcSJean-Christophe DUBOIS /* 23a0f31bcSJean-Christophe DUBOIS * SABRELITE Board System emulation. 33a0f31bcSJean-Christophe DUBOIS * 43a0f31bcSJean-Christophe DUBOIS * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> 53a0f31bcSJean-Christophe DUBOIS * 63a0f31bcSJean-Christophe DUBOIS * This code is licensed under the GPL, version 2 or later. 73a0f31bcSJean-Christophe DUBOIS * See the file `COPYING' in the top level directory. 83a0f31bcSJean-Christophe DUBOIS * 93a0f31bcSJean-Christophe DUBOIS * It (partially) emulates a sabrelite board, with a Freescale 103a0f31bcSJean-Christophe DUBOIS * i.MX6 SoC 113a0f31bcSJean-Christophe DUBOIS */ 123a0f31bcSJean-Christophe DUBOIS 133a0f31bcSJean-Christophe DUBOIS #include "qemu/osdep.h" 143a0f31bcSJean-Christophe DUBOIS #include "qapi/error.h" 153a0f31bcSJean-Christophe DUBOIS #include "hw/arm/fsl-imx6.h" 163a0f31bcSJean-Christophe DUBOIS #include "hw/boards.h" 17*a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 183a0f31bcSJean-Christophe DUBOIS #include "sysemu/sysemu.h" 193a0f31bcSJean-Christophe DUBOIS #include "qemu/error-report.h" 203a0f31bcSJean-Christophe DUBOIS #include "sysemu/qtest.h" 213a0f31bcSJean-Christophe DUBOIS 223a0f31bcSJean-Christophe DUBOIS typedef struct IMX6Sabrelite { 233a0f31bcSJean-Christophe DUBOIS FslIMX6State soc; 243a0f31bcSJean-Christophe DUBOIS MemoryRegion ram; 253a0f31bcSJean-Christophe DUBOIS } IMX6Sabrelite; 263a0f31bcSJean-Christophe DUBOIS 273a0f31bcSJean-Christophe DUBOIS static struct arm_boot_info sabrelite_binfo = { 283a0f31bcSJean-Christophe DUBOIS /* DDR memory start */ 293a0f31bcSJean-Christophe DUBOIS .loader_start = FSL_IMX6_MMDC_ADDR, 303a0f31bcSJean-Christophe DUBOIS /* No board ID, we boot from DT tree */ 313a0f31bcSJean-Christophe DUBOIS .board_id = -1, 323a0f31bcSJean-Christophe DUBOIS }; 333a0f31bcSJean-Christophe DUBOIS 343a0f31bcSJean-Christophe DUBOIS /* No need to do any particular setup for secondary boot */ 353a0f31bcSJean-Christophe DUBOIS static void sabrelite_write_secondary(ARMCPU *cpu, 363a0f31bcSJean-Christophe DUBOIS const struct arm_boot_info *info) 373a0f31bcSJean-Christophe DUBOIS { 383a0f31bcSJean-Christophe DUBOIS } 393a0f31bcSJean-Christophe DUBOIS 403a0f31bcSJean-Christophe DUBOIS /* Secondary cores are reset through SRC device */ 413a0f31bcSJean-Christophe DUBOIS static void sabrelite_reset_secondary(ARMCPU *cpu, 423a0f31bcSJean-Christophe DUBOIS const struct arm_boot_info *info) 433a0f31bcSJean-Christophe DUBOIS { 443a0f31bcSJean-Christophe DUBOIS } 453a0f31bcSJean-Christophe DUBOIS 463a0f31bcSJean-Christophe DUBOIS static void sabrelite_init(MachineState *machine) 473a0f31bcSJean-Christophe DUBOIS { 483a0f31bcSJean-Christophe DUBOIS IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1); 493a0f31bcSJean-Christophe DUBOIS Error *err = NULL; 503a0f31bcSJean-Christophe DUBOIS 513a0f31bcSJean-Christophe DUBOIS /* Check the amount of memory is compatible with the SOC */ 523a0f31bcSJean-Christophe DUBOIS if (machine->ram_size > FSL_IMX6_MMDC_SIZE) { 533a0f31bcSJean-Christophe DUBOIS error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)", 543a0f31bcSJean-Christophe DUBOIS machine->ram_size, FSL_IMX6_MMDC_SIZE); 553a0f31bcSJean-Christophe DUBOIS exit(1); 563a0f31bcSJean-Christophe DUBOIS } 573a0f31bcSJean-Christophe DUBOIS 58d0313798SPhilippe Mathieu-Daudé object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), 59d0313798SPhilippe Mathieu-Daudé TYPE_FSL_IMX6, &error_abort, NULL); 603a0f31bcSJean-Christophe DUBOIS 613a0f31bcSJean-Christophe DUBOIS object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); 623a0f31bcSJean-Christophe DUBOIS if (err != NULL) { 633a0f31bcSJean-Christophe DUBOIS error_report("%s", error_get_pretty(err)); 643a0f31bcSJean-Christophe DUBOIS exit(1); 653a0f31bcSJean-Christophe DUBOIS } 663a0f31bcSJean-Christophe DUBOIS 673a0f31bcSJean-Christophe DUBOIS memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram", 683a0f31bcSJean-Christophe DUBOIS machine->ram_size); 693a0f31bcSJean-Christophe DUBOIS memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, 703a0f31bcSJean-Christophe DUBOIS &s->ram); 713a0f31bcSJean-Christophe DUBOIS 723a0f31bcSJean-Christophe DUBOIS { 733a0f31bcSJean-Christophe DUBOIS /* 743a0f31bcSJean-Christophe DUBOIS * TODO: Ideally we would expose the chip select and spi bus on the 753a0f31bcSJean-Christophe DUBOIS * SoC object using alias properties; then we would not need to 763a0f31bcSJean-Christophe DUBOIS * directly access the underlying spi device object. 773a0f31bcSJean-Christophe DUBOIS */ 783a0f31bcSJean-Christophe DUBOIS /* Add the sst25vf016b NOR FLASH memory to first SPI */ 793a0f31bcSJean-Christophe DUBOIS Object *spi_dev; 803a0f31bcSJean-Christophe DUBOIS 813a0f31bcSJean-Christophe DUBOIS spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1"); 823a0f31bcSJean-Christophe DUBOIS if (spi_dev) { 833a0f31bcSJean-Christophe DUBOIS SSIBus *spi_bus; 843a0f31bcSJean-Christophe DUBOIS 853a0f31bcSJean-Christophe DUBOIS spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi"); 863a0f31bcSJean-Christophe DUBOIS if (spi_bus) { 873a0f31bcSJean-Christophe DUBOIS DeviceState *flash_dev; 8873bce518SPaolo Bonzini qemu_irq cs_line; 8973bce518SPaolo Bonzini DriveInfo *dinfo = drive_get_next(IF_MTD); 903a0f31bcSJean-Christophe DUBOIS 9173bce518SPaolo Bonzini flash_dev = ssi_create_slave_no_init(spi_bus, "sst25vf016b"); 9273bce518SPaolo Bonzini if (dinfo) { 9373bce518SPaolo Bonzini qdev_prop_set_drive(flash_dev, "drive", 9473bce518SPaolo Bonzini blk_by_legacy_dinfo(dinfo), 9573bce518SPaolo Bonzini &error_fatal); 963a0f31bcSJean-Christophe DUBOIS } 9773bce518SPaolo Bonzini qdev_init_nofail(flash_dev); 9873bce518SPaolo Bonzini 9973bce518SPaolo Bonzini cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); 10073bce518SPaolo Bonzini sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line); 1013a0f31bcSJean-Christophe DUBOIS } 1023a0f31bcSJean-Christophe DUBOIS } 1033a0f31bcSJean-Christophe DUBOIS } 1043a0f31bcSJean-Christophe DUBOIS 1053a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.ram_size = machine->ram_size; 1063a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.kernel_filename = machine->kernel_filename; 1073a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline; 1083a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.initrd_filename = machine->initrd_filename; 109cc7d44c2SLike Xu sabrelite_binfo.nb_cpus = machine->smp.cpus; 1103a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.secure_boot = true; 1113a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary; 1123a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; 1133a0f31bcSJean-Christophe DUBOIS 1143a0f31bcSJean-Christophe DUBOIS if (!qtest_enabled()) { 1153a0f31bcSJean-Christophe DUBOIS arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo); 1163a0f31bcSJean-Christophe DUBOIS } 1173a0f31bcSJean-Christophe DUBOIS } 1183a0f31bcSJean-Christophe DUBOIS 1193a0f31bcSJean-Christophe DUBOIS static void sabrelite_machine_init(MachineClass *mc) 1203a0f31bcSJean-Christophe DUBOIS { 1213a0f31bcSJean-Christophe DUBOIS mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)"; 1223a0f31bcSJean-Christophe DUBOIS mc->init = sabrelite_init; 1233a0f31bcSJean-Christophe DUBOIS mc->max_cpus = FSL_IMX6_NUM_CPUS; 1244672cbd7SPeter Maydell mc->ignore_memory_transaction_failures = true; 1253a0f31bcSJean-Christophe DUBOIS } 1263a0f31bcSJean-Christophe DUBOIS 1273a0f31bcSJean-Christophe DUBOIS DEFINE_MACHINE("sabrelite", sabrelite_machine_init) 128