1*3a0f31bcSJean-Christophe DUBOIS /* 2*3a0f31bcSJean-Christophe DUBOIS * SABRELITE Board System emulation. 3*3a0f31bcSJean-Christophe DUBOIS * 4*3a0f31bcSJean-Christophe DUBOIS * Copyright (c) 2015 Jean-Christophe Dubois <jcd@tribudubois.net> 5*3a0f31bcSJean-Christophe DUBOIS * 6*3a0f31bcSJean-Christophe DUBOIS * This code is licensed under the GPL, version 2 or later. 7*3a0f31bcSJean-Christophe DUBOIS * See the file `COPYING' in the top level directory. 8*3a0f31bcSJean-Christophe DUBOIS * 9*3a0f31bcSJean-Christophe DUBOIS * It (partially) emulates a sabrelite board, with a Freescale 10*3a0f31bcSJean-Christophe DUBOIS * i.MX6 SoC 11*3a0f31bcSJean-Christophe DUBOIS */ 12*3a0f31bcSJean-Christophe DUBOIS 13*3a0f31bcSJean-Christophe DUBOIS #include "qemu/osdep.h" 14*3a0f31bcSJean-Christophe DUBOIS #include "qapi/error.h" 15*3a0f31bcSJean-Christophe DUBOIS #include "qemu-common.h" 16*3a0f31bcSJean-Christophe DUBOIS #include "hw/arm/fsl-imx6.h" 17*3a0f31bcSJean-Christophe DUBOIS #include "hw/boards.h" 18*3a0f31bcSJean-Christophe DUBOIS #include "sysemu/sysemu.h" 19*3a0f31bcSJean-Christophe DUBOIS #include "qemu/error-report.h" 20*3a0f31bcSJean-Christophe DUBOIS #include "sysemu/qtest.h" 21*3a0f31bcSJean-Christophe DUBOIS 22*3a0f31bcSJean-Christophe DUBOIS typedef struct IMX6Sabrelite { 23*3a0f31bcSJean-Christophe DUBOIS FslIMX6State soc; 24*3a0f31bcSJean-Christophe DUBOIS MemoryRegion ram; 25*3a0f31bcSJean-Christophe DUBOIS } IMX6Sabrelite; 26*3a0f31bcSJean-Christophe DUBOIS 27*3a0f31bcSJean-Christophe DUBOIS static struct arm_boot_info sabrelite_binfo = { 28*3a0f31bcSJean-Christophe DUBOIS /* DDR memory start */ 29*3a0f31bcSJean-Christophe DUBOIS .loader_start = FSL_IMX6_MMDC_ADDR, 30*3a0f31bcSJean-Christophe DUBOIS /* No board ID, we boot from DT tree */ 31*3a0f31bcSJean-Christophe DUBOIS .board_id = -1, 32*3a0f31bcSJean-Christophe DUBOIS }; 33*3a0f31bcSJean-Christophe DUBOIS 34*3a0f31bcSJean-Christophe DUBOIS /* No need to do any particular setup for secondary boot */ 35*3a0f31bcSJean-Christophe DUBOIS static void sabrelite_write_secondary(ARMCPU *cpu, 36*3a0f31bcSJean-Christophe DUBOIS const struct arm_boot_info *info) 37*3a0f31bcSJean-Christophe DUBOIS { 38*3a0f31bcSJean-Christophe DUBOIS } 39*3a0f31bcSJean-Christophe DUBOIS 40*3a0f31bcSJean-Christophe DUBOIS /* Secondary cores are reset through SRC device */ 41*3a0f31bcSJean-Christophe DUBOIS static void sabrelite_reset_secondary(ARMCPU *cpu, 42*3a0f31bcSJean-Christophe DUBOIS const struct arm_boot_info *info) 43*3a0f31bcSJean-Christophe DUBOIS { 44*3a0f31bcSJean-Christophe DUBOIS } 45*3a0f31bcSJean-Christophe DUBOIS 46*3a0f31bcSJean-Christophe DUBOIS static void sabrelite_init(MachineState *machine) 47*3a0f31bcSJean-Christophe DUBOIS { 48*3a0f31bcSJean-Christophe DUBOIS IMX6Sabrelite *s = g_new0(IMX6Sabrelite, 1); 49*3a0f31bcSJean-Christophe DUBOIS Error *err = NULL; 50*3a0f31bcSJean-Christophe DUBOIS 51*3a0f31bcSJean-Christophe DUBOIS /* Check the amount of memory is compatible with the SOC */ 52*3a0f31bcSJean-Christophe DUBOIS if (machine->ram_size > FSL_IMX6_MMDC_SIZE) { 53*3a0f31bcSJean-Christophe DUBOIS error_report("RAM size " RAM_ADDR_FMT " above max supported (%08x)", 54*3a0f31bcSJean-Christophe DUBOIS machine->ram_size, FSL_IMX6_MMDC_SIZE); 55*3a0f31bcSJean-Christophe DUBOIS exit(1); 56*3a0f31bcSJean-Christophe DUBOIS } 57*3a0f31bcSJean-Christophe DUBOIS 58*3a0f31bcSJean-Christophe DUBOIS object_initialize(&s->soc, sizeof(s->soc), TYPE_FSL_IMX6); 59*3a0f31bcSJean-Christophe DUBOIS object_property_add_child(OBJECT(machine), "soc", OBJECT(&s->soc), 60*3a0f31bcSJean-Christophe DUBOIS &error_abort); 61*3a0f31bcSJean-Christophe DUBOIS 62*3a0f31bcSJean-Christophe DUBOIS object_property_set_bool(OBJECT(&s->soc), true, "realized", &err); 63*3a0f31bcSJean-Christophe DUBOIS if (err != NULL) { 64*3a0f31bcSJean-Christophe DUBOIS error_report("%s", error_get_pretty(err)); 65*3a0f31bcSJean-Christophe DUBOIS exit(1); 66*3a0f31bcSJean-Christophe DUBOIS } 67*3a0f31bcSJean-Christophe DUBOIS 68*3a0f31bcSJean-Christophe DUBOIS memory_region_allocate_system_memory(&s->ram, NULL, "sabrelite.ram", 69*3a0f31bcSJean-Christophe DUBOIS machine->ram_size); 70*3a0f31bcSJean-Christophe DUBOIS memory_region_add_subregion(get_system_memory(), FSL_IMX6_MMDC_ADDR, 71*3a0f31bcSJean-Christophe DUBOIS &s->ram); 72*3a0f31bcSJean-Christophe DUBOIS 73*3a0f31bcSJean-Christophe DUBOIS { 74*3a0f31bcSJean-Christophe DUBOIS /* 75*3a0f31bcSJean-Christophe DUBOIS * TODO: Ideally we would expose the chip select and spi bus on the 76*3a0f31bcSJean-Christophe DUBOIS * SoC object using alias properties; then we would not need to 77*3a0f31bcSJean-Christophe DUBOIS * directly access the underlying spi device object. 78*3a0f31bcSJean-Christophe DUBOIS */ 79*3a0f31bcSJean-Christophe DUBOIS /* Add the sst25vf016b NOR FLASH memory to first SPI */ 80*3a0f31bcSJean-Christophe DUBOIS Object *spi_dev; 81*3a0f31bcSJean-Christophe DUBOIS 82*3a0f31bcSJean-Christophe DUBOIS spi_dev = object_resolve_path_component(OBJECT(&s->soc), "spi1"); 83*3a0f31bcSJean-Christophe DUBOIS if (spi_dev) { 84*3a0f31bcSJean-Christophe DUBOIS SSIBus *spi_bus; 85*3a0f31bcSJean-Christophe DUBOIS 86*3a0f31bcSJean-Christophe DUBOIS spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(spi_dev), "spi"); 87*3a0f31bcSJean-Christophe DUBOIS if (spi_bus) { 88*3a0f31bcSJean-Christophe DUBOIS DeviceState *flash_dev; 89*3a0f31bcSJean-Christophe DUBOIS 90*3a0f31bcSJean-Christophe DUBOIS flash_dev = ssi_create_slave(spi_bus, "sst25vf016b"); 91*3a0f31bcSJean-Christophe DUBOIS if (flash_dev) { 92*3a0f31bcSJean-Christophe DUBOIS qemu_irq cs_line = qdev_get_gpio_in_named(flash_dev, 93*3a0f31bcSJean-Christophe DUBOIS SSI_GPIO_CS, 0); 94*3a0f31bcSJean-Christophe DUBOIS sysbus_connect_irq(SYS_BUS_DEVICE(spi_dev), 1, cs_line); 95*3a0f31bcSJean-Christophe DUBOIS } 96*3a0f31bcSJean-Christophe DUBOIS } 97*3a0f31bcSJean-Christophe DUBOIS } 98*3a0f31bcSJean-Christophe DUBOIS } 99*3a0f31bcSJean-Christophe DUBOIS 100*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.ram_size = machine->ram_size; 101*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.kernel_filename = machine->kernel_filename; 102*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.kernel_cmdline = machine->kernel_cmdline; 103*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.initrd_filename = machine->initrd_filename; 104*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.nb_cpus = smp_cpus; 105*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.secure_boot = true; 106*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.write_secondary_boot = sabrelite_write_secondary; 107*3a0f31bcSJean-Christophe DUBOIS sabrelite_binfo.secondary_cpu_reset_hook = sabrelite_reset_secondary; 108*3a0f31bcSJean-Christophe DUBOIS 109*3a0f31bcSJean-Christophe DUBOIS if (!qtest_enabled()) { 110*3a0f31bcSJean-Christophe DUBOIS arm_load_kernel(&s->soc.cpu[0], &sabrelite_binfo); 111*3a0f31bcSJean-Christophe DUBOIS } 112*3a0f31bcSJean-Christophe DUBOIS } 113*3a0f31bcSJean-Christophe DUBOIS 114*3a0f31bcSJean-Christophe DUBOIS static void sabrelite_machine_init(MachineClass *mc) 115*3a0f31bcSJean-Christophe DUBOIS { 116*3a0f31bcSJean-Christophe DUBOIS mc->desc = "Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)"; 117*3a0f31bcSJean-Christophe DUBOIS mc->init = sabrelite_init; 118*3a0f31bcSJean-Christophe DUBOIS mc->max_cpus = FSL_IMX6_NUM_CPUS; 119*3a0f31bcSJean-Christophe DUBOIS } 120*3a0f31bcSJean-Christophe DUBOIS 121*3a0f31bcSJean-Christophe DUBOIS DEFINE_MACHINE("sabrelite", sabrelite_machine_init) 122