104331d0bSMichael Clark /* 204331d0bSMichael Clark * QEMU RISC-V VirtIO Board 304331d0bSMichael Clark * 404331d0bSMichael Clark * Copyright (c) 2017 SiFive, Inc. 504331d0bSMichael Clark * 604331d0bSMichael Clark * RISC-V machine with 16550a UART and VirtIO MMIO 704331d0bSMichael Clark * 804331d0bSMichael Clark * This program is free software; you can redistribute it and/or modify it 904331d0bSMichael Clark * under the terms and conditions of the GNU General Public License, 1004331d0bSMichael Clark * version 2 or later, as published by the Free Software Foundation. 1104331d0bSMichael Clark * 1204331d0bSMichael Clark * This program is distributed in the hope it will be useful, but WITHOUT 1304331d0bSMichael Clark * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1404331d0bSMichael Clark * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 1504331d0bSMichael Clark * more details. 1604331d0bSMichael Clark * 1704331d0bSMichael Clark * You should have received a copy of the GNU General Public License along with 1804331d0bSMichael Clark * this program. If not, see <http://www.gnu.org/licenses/>. 1904331d0bSMichael Clark */ 2004331d0bSMichael Clark 2104331d0bSMichael Clark #include "qemu/osdep.h" 224bf46af7SPhilippe Mathieu-Daudé #include "qemu/units.h" 2304331d0bSMichael Clark #include "qemu/error-report.h" 2404331d0bSMichael Clark #include "qapi/error.h" 2504331d0bSMichael Clark #include "hw/boards.h" 2604331d0bSMichael Clark #include "hw/loader.h" 2704331d0bSMichael Clark #include "hw/sysbus.h" 2871eb522cSAlistair Francis #include "hw/qdev-properties.h" 2904331d0bSMichael Clark #include "hw/char/serial.h" 3004331d0bSMichael Clark #include "target/riscv/cpu.h" 3104331d0bSMichael Clark #include "hw/riscv/riscv_hart.h" 3204331d0bSMichael Clark #include "hw/riscv/virt.h" 330ac24d56SAlistair Francis #include "hw/riscv/boot.h" 3418df0b46SAnup Patel #include "hw/riscv/numa.h" 35cc63a182SAnup Patel #include "hw/intc/riscv_aclint.h" 3684fcf3c1SBin Meng #include "hw/intc/sifive_plic.h" 37a4b84608SBin Meng #include "hw/misc/sifive_test.h" 3804331d0bSMichael Clark #include "chardev/char.h" 3904331d0bSMichael Clark #include "sysemu/device_tree.h" 4046517dd4SMarkus Armbruster #include "sysemu/sysemu.h" 416d56e396SAlistair Francis #include "hw/pci/pci.h" 426d56e396SAlistair Francis #include "hw/pci-host/gpex.h" 43c346749eSAsherah Connor #include "hw/display/ramfb.h" 4404331d0bSMichael Clark 4573261285SBin Meng static const MemMapEntry virt_memmap[] = { 4604331d0bSMichael Clark [VIRT_DEBUG] = { 0x0, 0x100 }, 479eb8b14aSBin Meng [VIRT_MROM] = { 0x1000, 0xf000 }, 485aec3247SMichael Clark [VIRT_TEST] = { 0x100000, 0x1000 }, 4967b5ef30SAnup Patel [VIRT_RTC] = { 0x101000, 0x1000 }, 5004331d0bSMichael Clark [VIRT_CLINT] = { 0x2000000, 0x10000 }, 51*954886eaSAnup Patel [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, 522c44bbf3SBin Meng [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, 5318df0b46SAnup Patel [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, 5404331d0bSMichael Clark [VIRT_UART0] = { 0x10000000, 0x100 }, 5504331d0bSMichael Clark [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, 560489348dSAsherah Connor [VIRT_FW_CFG] = { 0x10100000, 0x18 }, 576911fde4SAlistair Francis [VIRT_FLASH] = { 0x20000000, 0x4000000 }, 586d56e396SAlistair Francis [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, 592c44bbf3SBin Meng [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, 602c44bbf3SBin Meng [VIRT_DRAM] = { 0x80000000, 0x0 }, 6104331d0bSMichael Clark }; 6204331d0bSMichael Clark 6319800265SBin Meng /* PCIe high mmio is fixed for RV32 */ 6419800265SBin Meng #define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL 6519800265SBin Meng #define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) 6619800265SBin Meng 6719800265SBin Meng /* PCIe high mmio for RV64, size is fixed but base depends on top of RAM */ 6819800265SBin Meng #define VIRT64_HIGH_PCIE_MMIO_SIZE (16 * GiB) 6919800265SBin Meng 7019800265SBin Meng static MemMapEntry virt_high_pcie_memmap; 7119800265SBin Meng 7271eb522cSAlistair Francis #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) 7371eb522cSAlistair Francis 7471eb522cSAlistair Francis static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, 7571eb522cSAlistair Francis const char *name, 7671eb522cSAlistair Francis const char *alias_prop_name) 7771eb522cSAlistair Francis { 7871eb522cSAlistair Francis /* 7971eb522cSAlistair Francis * Create a single flash device. We use the same parameters as 8071eb522cSAlistair Francis * the flash devices on the ARM virt board. 8171eb522cSAlistair Francis */ 82df707969SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_PFLASH_CFI01); 8371eb522cSAlistair Francis 8471eb522cSAlistair Francis qdev_prop_set_uint64(dev, "sector-length", VIRT_FLASH_SECTOR_SIZE); 8571eb522cSAlistair Francis qdev_prop_set_uint8(dev, "width", 4); 8671eb522cSAlistair Francis qdev_prop_set_uint8(dev, "device-width", 2); 8771eb522cSAlistair Francis qdev_prop_set_bit(dev, "big-endian", false); 8871eb522cSAlistair Francis qdev_prop_set_uint16(dev, "id0", 0x89); 8971eb522cSAlistair Francis qdev_prop_set_uint16(dev, "id1", 0x18); 9071eb522cSAlistair Francis qdev_prop_set_uint16(dev, "id2", 0x00); 9171eb522cSAlistair Francis qdev_prop_set_uint16(dev, "id3", 0x00); 9271eb522cSAlistair Francis qdev_prop_set_string(dev, "name", name); 9371eb522cSAlistair Francis 94d2623129SMarkus Armbruster object_property_add_child(OBJECT(s), name, OBJECT(dev)); 9571eb522cSAlistair Francis object_property_add_alias(OBJECT(s), alias_prop_name, 96d2623129SMarkus Armbruster OBJECT(dev), "drive"); 9771eb522cSAlistair Francis 9871eb522cSAlistair Francis return PFLASH_CFI01(dev); 9971eb522cSAlistair Francis } 10071eb522cSAlistair Francis 10171eb522cSAlistair Francis static void virt_flash_create(RISCVVirtState *s) 10271eb522cSAlistair Francis { 10371eb522cSAlistair Francis s->flash[0] = virt_flash_create1(s, "virt.flash0", "pflash0"); 10471eb522cSAlistair Francis s->flash[1] = virt_flash_create1(s, "virt.flash1", "pflash1"); 10571eb522cSAlistair Francis } 10671eb522cSAlistair Francis 10771eb522cSAlistair Francis static void virt_flash_map1(PFlashCFI01 *flash, 10871eb522cSAlistair Francis hwaddr base, hwaddr size, 10971eb522cSAlistair Francis MemoryRegion *sysmem) 11071eb522cSAlistair Francis { 11171eb522cSAlistair Francis DeviceState *dev = DEVICE(flash); 11271eb522cSAlistair Francis 1134cdd0a77SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(size, VIRT_FLASH_SECTOR_SIZE)); 11471eb522cSAlistair Francis assert(size / VIRT_FLASH_SECTOR_SIZE <= UINT32_MAX); 11571eb522cSAlistair Francis qdev_prop_set_uint32(dev, "num-blocks", size / VIRT_FLASH_SECTOR_SIZE); 1163c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 11771eb522cSAlistair Francis 11871eb522cSAlistair Francis memory_region_add_subregion(sysmem, base, 11971eb522cSAlistair Francis sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 12071eb522cSAlistair Francis 0)); 12171eb522cSAlistair Francis } 12271eb522cSAlistair Francis 12371eb522cSAlistair Francis static void virt_flash_map(RISCVVirtState *s, 12471eb522cSAlistair Francis MemoryRegion *sysmem) 12571eb522cSAlistair Francis { 12671eb522cSAlistair Francis hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; 12771eb522cSAlistair Francis hwaddr flashbase = virt_memmap[VIRT_FLASH].base; 12871eb522cSAlistair Francis 12971eb522cSAlistair Francis virt_flash_map1(s->flash[0], flashbase, flashsize, 13071eb522cSAlistair Francis sysmem); 13171eb522cSAlistair Francis virt_flash_map1(s->flash[1], flashbase + flashsize, flashsize, 13271eb522cSAlistair Francis sysmem); 13371eb522cSAlistair Francis } 13471eb522cSAlistair Francis 1356d56e396SAlistair Francis static void create_pcie_irq_map(void *fdt, char *nodename, 1366d56e396SAlistair Francis uint32_t plic_phandle) 1376d56e396SAlistair Francis { 1386d56e396SAlistair Francis int pin, dev; 1396d56e396SAlistair Francis uint32_t 1406d56e396SAlistair Francis full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {}; 1416d56e396SAlistair Francis uint32_t *irq_map = full_irq_map; 1426d56e396SAlistair Francis 1436d56e396SAlistair Francis /* This code creates a standard swizzle of interrupts such that 1446d56e396SAlistair Francis * each device's first interrupt is based on it's PCI_SLOT number. 1456d56e396SAlistair Francis * (See pci_swizzle_map_irq_fn()) 1466d56e396SAlistair Francis * 1476d56e396SAlistair Francis * We only need one entry per interrupt in the table (not one per 1486d56e396SAlistair Francis * possible slot) seeing the interrupt-map-mask will allow the table 1496d56e396SAlistair Francis * to wrap to any number of devices. 1506d56e396SAlistair Francis */ 1516d56e396SAlistair Francis for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { 1526d56e396SAlistair Francis int devfn = dev * 0x8; 1536d56e396SAlistair Francis 1546d56e396SAlistair Francis for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { 1556d56e396SAlistair Francis int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); 1566d56e396SAlistair Francis int i = 0; 1576d56e396SAlistair Francis 1586d56e396SAlistair Francis irq_map[i] = cpu_to_be32(devfn << 8); 1596d56e396SAlistair Francis 1606d56e396SAlistair Francis i += FDT_PCI_ADDR_CELLS; 1616d56e396SAlistair Francis irq_map[i] = cpu_to_be32(pin + 1); 1626d56e396SAlistair Francis 1636d56e396SAlistair Francis i += FDT_PCI_INT_CELLS; 1646d56e396SAlistair Francis irq_map[i++] = cpu_to_be32(plic_phandle); 1656d56e396SAlistair Francis 1666d56e396SAlistair Francis i += FDT_PLIC_ADDR_CELLS; 1676d56e396SAlistair Francis irq_map[i] = cpu_to_be32(irq_nr); 1686d56e396SAlistair Francis 1696d56e396SAlistair Francis irq_map += FDT_INT_MAP_WIDTH; 1706d56e396SAlistair Francis } 1716d56e396SAlistair Francis } 1726d56e396SAlistair Francis 1736d56e396SAlistair Francis qemu_fdt_setprop(fdt, nodename, "interrupt-map", 1746d56e396SAlistair Francis full_irq_map, sizeof(full_irq_map)); 1756d56e396SAlistair Francis 1766d56e396SAlistair Francis qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", 1776d56e396SAlistair Francis 0x1800, 0, 0, 0x7); 1786d56e396SAlistair Francis } 1796d56e396SAlistair Francis 1800ffc1a95SAnup Patel static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, 1810ffc1a95SAnup Patel char *clust_name, uint32_t *phandle, 1820ffc1a95SAnup Patel bool is_32_bit, uint32_t *intc_phandles) 18304331d0bSMichael Clark { 1840ffc1a95SAnup Patel int cpu; 1850ffc1a95SAnup Patel uint32_t cpu_phandle; 18618df0b46SAnup Patel MachineState *mc = MACHINE(s); 1870ffc1a95SAnup Patel char *name, *cpu_name, *core_name, *intc_name; 18818df0b46SAnup Patel 18918df0b46SAnup Patel for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { 1900ffc1a95SAnup Patel cpu_phandle = (*phandle)++; 19118df0b46SAnup Patel 19218df0b46SAnup Patel cpu_name = g_strdup_printf("/cpus/cpu@%d", 19318df0b46SAnup Patel s->soc[socket].hartid_base + cpu); 1940ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, cpu_name); 1950ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, cpu_name, "mmu-type", 1960ffc1a95SAnup Patel (is_32_bit) ? "riscv,sv32" : "riscv,sv48"); 19718df0b46SAnup Patel name = riscv_isa_string(&s->soc[socket].harts[cpu]); 1980ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, cpu_name, "riscv,isa", name); 19918df0b46SAnup Patel g_free(name); 2000ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, cpu_name, "compatible", "riscv"); 2010ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, cpu_name, "status", "okay"); 2020ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, cpu_name, "reg", 20318df0b46SAnup Patel s->soc[socket].hartid_base + cpu); 2040ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, cpu_name, "device_type", "cpu"); 2050ffc1a95SAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, cpu_name, socket); 2060ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, cpu_name, "phandle", cpu_phandle); 2070ffc1a95SAnup Patel 2080ffc1a95SAnup Patel intc_phandles[cpu] = (*phandle)++; 20918df0b46SAnup Patel 21018df0b46SAnup Patel intc_name = g_strdup_printf("%s/interrupt-controller", cpu_name); 2110ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, intc_name); 2120ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, intc_name, "phandle", 2130ffc1a95SAnup Patel intc_phandles[cpu]); 2140ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, intc_name, "compatible", 21518df0b46SAnup Patel "riscv,cpu-intc"); 2160ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, intc_name, "interrupt-controller", NULL, 0); 2170ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, intc_name, "#interrupt-cells", 1); 21818df0b46SAnup Patel 21918df0b46SAnup Patel core_name = g_strdup_printf("%s/core%d", clust_name, cpu); 2200ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, core_name); 2210ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, core_name, "cpu", cpu_phandle); 22218df0b46SAnup Patel 22318df0b46SAnup Patel g_free(core_name); 22418df0b46SAnup Patel g_free(intc_name); 22518df0b46SAnup Patel g_free(cpu_name); 22628a4df97SAtish Patra } 2270ffc1a95SAnup Patel } 2280ffc1a95SAnup Patel 2290ffc1a95SAnup Patel static void create_fdt_socket_memory(RISCVVirtState *s, 2300ffc1a95SAnup Patel const MemMapEntry *memmap, int socket) 2310ffc1a95SAnup Patel { 2320ffc1a95SAnup Patel char *mem_name; 2330ffc1a95SAnup Patel uint64_t addr, size; 2340ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 23528a4df97SAtish Patra 23618df0b46SAnup Patel addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(mc, socket); 23718df0b46SAnup Patel size = riscv_socket_mem_size(mc, socket); 23818df0b46SAnup Patel mem_name = g_strdup_printf("/memory@%lx", (long)addr); 2390ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, mem_name); 2400ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, mem_name, "reg", 24118df0b46SAnup Patel addr >> 32, addr, size >> 32, size); 2420ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, mem_name, "device_type", "memory"); 2430ffc1a95SAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, mem_name, socket); 24418df0b46SAnup Patel g_free(mem_name); 2450ffc1a95SAnup Patel } 24604331d0bSMichael Clark 2470ffc1a95SAnup Patel static void create_fdt_socket_clint(RISCVVirtState *s, 2480ffc1a95SAnup Patel const MemMapEntry *memmap, int socket, 2490ffc1a95SAnup Patel uint32_t *intc_phandles) 2500ffc1a95SAnup Patel { 2510ffc1a95SAnup Patel int cpu; 2520ffc1a95SAnup Patel char *clint_name; 2530ffc1a95SAnup Patel uint32_t *clint_cells; 2540ffc1a95SAnup Patel unsigned long clint_addr; 2550ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 2560ffc1a95SAnup Patel static const char * const clint_compat[2] = { 2570ffc1a95SAnup Patel "sifive,clint0", "riscv,clint0" 2580ffc1a95SAnup Patel }; 2590ffc1a95SAnup Patel 2600ffc1a95SAnup Patel clint_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); 2610ffc1a95SAnup Patel 2620ffc1a95SAnup Patel for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { 2630ffc1a95SAnup Patel clint_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); 2640ffc1a95SAnup Patel clint_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_SOFT); 2650ffc1a95SAnup Patel clint_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); 2660ffc1a95SAnup Patel clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER); 2670ffc1a95SAnup Patel } 2680ffc1a95SAnup Patel 2690ffc1a95SAnup Patel clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); 27018df0b46SAnup Patel clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); 2710ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, clint_name); 2720ffc1a95SAnup Patel qemu_fdt_setprop_string_array(mc->fdt, clint_name, "compatible", 2730ffc1a95SAnup Patel (char **)&clint_compat, 2740ffc1a95SAnup Patel ARRAY_SIZE(clint_compat)); 2750ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, clint_name, "reg", 27618df0b46SAnup Patel 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); 2770ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, clint_name, "interrupts-extended", 27818df0b46SAnup Patel clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); 2790ffc1a95SAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, clint_name, socket); 28018df0b46SAnup Patel g_free(clint_name); 28118df0b46SAnup Patel 2820ffc1a95SAnup Patel g_free(clint_cells); 2830ffc1a95SAnup Patel } 2840ffc1a95SAnup Patel 285*954886eaSAnup Patel static void create_fdt_socket_aclint(RISCVVirtState *s, 286*954886eaSAnup Patel const MemMapEntry *memmap, int socket, 287*954886eaSAnup Patel uint32_t *intc_phandles) 288*954886eaSAnup Patel { 289*954886eaSAnup Patel int cpu; 290*954886eaSAnup Patel char *name; 291*954886eaSAnup Patel unsigned long addr; 292*954886eaSAnup Patel uint32_t aclint_cells_size; 293*954886eaSAnup Patel uint32_t *aclint_mswi_cells; 294*954886eaSAnup Patel uint32_t *aclint_sswi_cells; 295*954886eaSAnup Patel uint32_t *aclint_mtimer_cells; 296*954886eaSAnup Patel MachineState *mc = MACHINE(s); 297*954886eaSAnup Patel 298*954886eaSAnup Patel aclint_mswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); 299*954886eaSAnup Patel aclint_mtimer_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); 300*954886eaSAnup Patel aclint_sswi_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2); 301*954886eaSAnup Patel 302*954886eaSAnup Patel for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { 303*954886eaSAnup Patel aclint_mswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); 304*954886eaSAnup Patel aclint_mswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_SOFT); 305*954886eaSAnup Patel aclint_mtimer_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); 306*954886eaSAnup Patel aclint_mtimer_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_TIMER); 307*954886eaSAnup Patel aclint_sswi_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]); 308*954886eaSAnup Patel aclint_sswi_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_SOFT); 309*954886eaSAnup Patel } 310*954886eaSAnup Patel aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2; 311*954886eaSAnup Patel 312*954886eaSAnup Patel addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); 313*954886eaSAnup Patel name = g_strdup_printf("/soc/mswi@%lx", addr); 314*954886eaSAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 315*954886eaSAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-mswi"); 316*954886eaSAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 317*954886eaSAnup Patel 0x0, addr, 0x0, RISCV_ACLINT_SWI_SIZE); 318*954886eaSAnup Patel qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", 319*954886eaSAnup Patel aclint_mswi_cells, aclint_cells_size); 320*954886eaSAnup Patel qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); 321*954886eaSAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); 322*954886eaSAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); 323*954886eaSAnup Patel g_free(name); 324*954886eaSAnup Patel 325*954886eaSAnup Patel addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + 326*954886eaSAnup Patel (memmap[VIRT_CLINT].size * socket); 327*954886eaSAnup Patel name = g_strdup_printf("/soc/mtimer@%lx", addr); 328*954886eaSAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 329*954886eaSAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", 330*954886eaSAnup Patel "riscv,aclint-mtimer"); 331*954886eaSAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 332*954886eaSAnup Patel 0x0, addr + RISCV_ACLINT_DEFAULT_MTIME, 333*954886eaSAnup Patel 0x0, memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE - 334*954886eaSAnup Patel RISCV_ACLINT_DEFAULT_MTIME, 335*954886eaSAnup Patel 0x0, addr + RISCV_ACLINT_DEFAULT_MTIMECMP, 336*954886eaSAnup Patel 0x0, RISCV_ACLINT_DEFAULT_MTIME); 337*954886eaSAnup Patel qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", 338*954886eaSAnup Patel aclint_mtimer_cells, aclint_cells_size); 339*954886eaSAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); 340*954886eaSAnup Patel g_free(name); 341*954886eaSAnup Patel 342*954886eaSAnup Patel addr = memmap[VIRT_ACLINT_SSWI].base + 343*954886eaSAnup Patel (memmap[VIRT_ACLINT_SSWI].size * socket); 344*954886eaSAnup Patel name = g_strdup_printf("/soc/sswi@%lx", addr); 345*954886eaSAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 346*954886eaSAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "riscv,aclint-sswi"); 347*954886eaSAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 348*954886eaSAnup Patel 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size); 349*954886eaSAnup Patel qemu_fdt_setprop(mc->fdt, name, "interrupts-extended", 350*954886eaSAnup Patel aclint_sswi_cells, aclint_cells_size); 351*954886eaSAnup Patel qemu_fdt_setprop(mc->fdt, name, "interrupt-controller", NULL, 0); 352*954886eaSAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 0); 353*954886eaSAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, name, socket); 354*954886eaSAnup Patel g_free(name); 355*954886eaSAnup Patel 356*954886eaSAnup Patel g_free(aclint_mswi_cells); 357*954886eaSAnup Patel g_free(aclint_mtimer_cells); 358*954886eaSAnup Patel g_free(aclint_sswi_cells); 359*954886eaSAnup Patel } 360*954886eaSAnup Patel 3610ffc1a95SAnup Patel static void create_fdt_socket_plic(RISCVVirtState *s, 3620ffc1a95SAnup Patel const MemMapEntry *memmap, int socket, 3630ffc1a95SAnup Patel uint32_t *phandle, uint32_t *intc_phandles, 3640ffc1a95SAnup Patel uint32_t *plic_phandles) 3650ffc1a95SAnup Patel { 3660ffc1a95SAnup Patel int cpu; 3670ffc1a95SAnup Patel char *plic_name; 3680ffc1a95SAnup Patel uint32_t *plic_cells; 3690ffc1a95SAnup Patel unsigned long plic_addr; 3700ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 3710ffc1a95SAnup Patel static const char * const plic_compat[2] = { 3720ffc1a95SAnup Patel "sifive,plic-1.0.0", "riscv,plic0" 3730ffc1a95SAnup Patel }; 3740ffc1a95SAnup Patel 3750ffc1a95SAnup Patel plic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 4); 3760ffc1a95SAnup Patel 3770ffc1a95SAnup Patel for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) { 3780ffc1a95SAnup Patel plic_cells[cpu * 4 + 0] = cpu_to_be32(intc_phandles[cpu]); 3790ffc1a95SAnup Patel plic_cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); 3800ffc1a95SAnup Patel plic_cells[cpu * 4 + 2] = cpu_to_be32(intc_phandles[cpu]); 3810ffc1a95SAnup Patel plic_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); 3820ffc1a95SAnup Patel } 3830ffc1a95SAnup Patel 3840ffc1a95SAnup Patel plic_phandles[socket] = (*phandle)++; 38518df0b46SAnup Patel plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); 38618df0b46SAnup Patel plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); 3870ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, plic_name); 3880ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, plic_name, 38918df0b46SAnup Patel "#address-cells", FDT_PLIC_ADDR_CELLS); 3900ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, plic_name, 39118df0b46SAnup Patel "#interrupt-cells", FDT_PLIC_INT_CELLS); 3920ffc1a95SAnup Patel qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible", 3930ffc1a95SAnup Patel (char **)&plic_compat, 3940ffc1a95SAnup Patel ARRAY_SIZE(plic_compat)); 3950ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, plic_name, "interrupt-controller", NULL, 0); 3960ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, plic_name, "interrupts-extended", 39718df0b46SAnup Patel plic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); 3980ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, plic_name, "reg", 39918df0b46SAnup Patel 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); 4000ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, plic_name, "riscv,ndev", VIRTIO_NDEV); 4010ffc1a95SAnup Patel riscv_socket_fdt_write_id(mc, mc->fdt, plic_name, socket); 4020ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, plic_name, "phandle", 4030ffc1a95SAnup Patel plic_phandles[socket]); 40418df0b46SAnup Patel g_free(plic_name); 40518df0b46SAnup Patel 40618df0b46SAnup Patel g_free(plic_cells); 4070ffc1a95SAnup Patel } 4080ffc1a95SAnup Patel 4090ffc1a95SAnup Patel static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, 4100ffc1a95SAnup Patel bool is_32_bit, uint32_t *phandle, 4110ffc1a95SAnup Patel uint32_t *irq_mmio_phandle, 4120ffc1a95SAnup Patel uint32_t *irq_pcie_phandle, 4130ffc1a95SAnup Patel uint32_t *irq_virtio_phandle) 4140ffc1a95SAnup Patel { 4150ffc1a95SAnup Patel int socket; 4160ffc1a95SAnup Patel char *clust_name; 4170ffc1a95SAnup Patel uint32_t *intc_phandles; 4180ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 4190ffc1a95SAnup Patel uint32_t xplic_phandles[MAX_NODES]; 4200ffc1a95SAnup Patel 4210ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, "/cpus"); 4220ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/cpus", "timebase-frequency", 4230ffc1a95SAnup Patel RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ); 4240ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#size-cells", 0x0); 4250ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/cpus", "#address-cells", 0x1); 4260ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, "/cpus/cpu-map"); 4270ffc1a95SAnup Patel 4280ffc1a95SAnup Patel for (socket = (riscv_socket_count(mc) - 1); socket >= 0; socket--) { 4290ffc1a95SAnup Patel clust_name = g_strdup_printf("/cpus/cpu-map/cluster%d", socket); 4300ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, clust_name); 4310ffc1a95SAnup Patel 4320ffc1a95SAnup Patel intc_phandles = g_new0(uint32_t, s->soc[socket].num_harts); 4330ffc1a95SAnup Patel 4340ffc1a95SAnup Patel create_fdt_socket_cpus(s, socket, clust_name, phandle, 4350ffc1a95SAnup Patel is_32_bit, intc_phandles); 4360ffc1a95SAnup Patel 4370ffc1a95SAnup Patel create_fdt_socket_memory(s, memmap, socket); 4380ffc1a95SAnup Patel 439*954886eaSAnup Patel if (s->have_aclint) { 440*954886eaSAnup Patel create_fdt_socket_aclint(s, memmap, socket, intc_phandles); 441*954886eaSAnup Patel } else { 4420ffc1a95SAnup Patel create_fdt_socket_clint(s, memmap, socket, intc_phandles); 443*954886eaSAnup Patel } 4440ffc1a95SAnup Patel 4450ffc1a95SAnup Patel create_fdt_socket_plic(s, memmap, socket, phandle, 4460ffc1a95SAnup Patel intc_phandles, xplic_phandles); 4470ffc1a95SAnup Patel 4480ffc1a95SAnup Patel g_free(intc_phandles); 44918df0b46SAnup Patel g_free(clust_name); 45004331d0bSMichael Clark } 45118df0b46SAnup Patel 45218df0b46SAnup Patel for (socket = 0; socket < riscv_socket_count(mc); socket++) { 45318df0b46SAnup Patel if (socket == 0) { 4540ffc1a95SAnup Patel *irq_mmio_phandle = xplic_phandles[socket]; 4550ffc1a95SAnup Patel *irq_virtio_phandle = xplic_phandles[socket]; 4560ffc1a95SAnup Patel *irq_pcie_phandle = xplic_phandles[socket]; 45718df0b46SAnup Patel } 45818df0b46SAnup Patel if (socket == 1) { 4590ffc1a95SAnup Patel *irq_virtio_phandle = xplic_phandles[socket]; 4600ffc1a95SAnup Patel *irq_pcie_phandle = xplic_phandles[socket]; 46118df0b46SAnup Patel } 46218df0b46SAnup Patel if (socket == 2) { 4630ffc1a95SAnup Patel *irq_pcie_phandle = xplic_phandles[socket]; 46418df0b46SAnup Patel } 46518df0b46SAnup Patel } 46618df0b46SAnup Patel 4670ffc1a95SAnup Patel riscv_socket_fdt_write_distance_matrix(mc, mc->fdt); 4680ffc1a95SAnup Patel } 4690ffc1a95SAnup Patel 4700ffc1a95SAnup Patel static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, 4710ffc1a95SAnup Patel uint32_t irq_virtio_phandle) 4720ffc1a95SAnup Patel { 4730ffc1a95SAnup Patel int i; 4740ffc1a95SAnup Patel char *name; 4750ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 47604331d0bSMichael Clark 47704331d0bSMichael Clark for (i = 0; i < VIRTIO_COUNT; i++) { 47818df0b46SAnup Patel name = g_strdup_printf("/soc/virtio_mmio@%lx", 47904331d0bSMichael Clark (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); 4800ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 4810ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "virtio,mmio"); 4820ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 48304331d0bSMichael Clark 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, 48404331d0bSMichael Clark 0x0, memmap[VIRT_VIRTIO].size); 4850ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", 4860ffc1a95SAnup Patel irq_virtio_phandle); 4870ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i); 48818df0b46SAnup Patel g_free(name); 48904331d0bSMichael Clark } 4900ffc1a95SAnup Patel } 4910ffc1a95SAnup Patel 4920ffc1a95SAnup Patel static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, 4930ffc1a95SAnup Patel uint32_t irq_pcie_phandle) 4940ffc1a95SAnup Patel { 4950ffc1a95SAnup Patel char *name; 4960ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 49704331d0bSMichael Clark 49818df0b46SAnup Patel name = g_strdup_printf("/soc/pci@%lx", 4996d56e396SAlistair Francis (long) memmap[VIRT_PCIE_ECAM].base); 5000ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5010ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "#address-cells", 5020ffc1a95SAnup Patel FDT_PCI_ADDR_CELLS); 5030ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "#interrupt-cells", 5040ffc1a95SAnup Patel FDT_PCI_INT_CELLS); 5050ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "#size-cells", 0x2); 5060ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", 5070ffc1a95SAnup Patel "pci-host-ecam-generic"); 5080ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "device_type", "pci"); 5090ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "linux,pci-domain", 0); 5100ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "bus-range", 0, 51118df0b46SAnup Patel memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); 5120ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, name, "dma-coherent", NULL, 0); 5130ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 0, 51418df0b46SAnup Patel memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size); 5150ffc1a95SAnup Patel qemu_fdt_setprop_sized_cells(mc->fdt, name, "ranges", 5166d56e396SAlistair Francis 1, FDT_PCI_RANGE_IOPORT, 2, 0, 5176d56e396SAlistair Francis 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, 5186d56e396SAlistair Francis 1, FDT_PCI_RANGE_MMIO, 5196d56e396SAlistair Francis 2, memmap[VIRT_PCIE_MMIO].base, 52019800265SBin Meng 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, 52119800265SBin Meng 1, FDT_PCI_RANGE_MMIO_64BIT, 52219800265SBin Meng 2, virt_high_pcie_memmap.base, 52319800265SBin Meng 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); 52419800265SBin Meng 5250ffc1a95SAnup Patel create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle); 52618df0b46SAnup Patel g_free(name); 5270ffc1a95SAnup Patel } 5286d56e396SAlistair Francis 5290ffc1a95SAnup Patel static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, 5300ffc1a95SAnup Patel uint32_t *phandle) 5310ffc1a95SAnup Patel { 5320ffc1a95SAnup Patel char *name; 5330ffc1a95SAnup Patel uint32_t test_phandle; 5340ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 5350ffc1a95SAnup Patel 5360ffc1a95SAnup Patel test_phandle = (*phandle)++; 53718df0b46SAnup Patel name = g_strdup_printf("/soc/test@%lx", 53804331d0bSMichael Clark (long)memmap[VIRT_TEST].base); 5390ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5409c0fb20cSPalmer Dabbelt { 5412cc04550SBin Meng static const char * const compat[3] = { 5422cc04550SBin Meng "sifive,test1", "sifive,test0", "syscon" 5432cc04550SBin Meng }; 5440ffc1a95SAnup Patel qemu_fdt_setprop_string_array(mc->fdt, name, "compatible", 5450ffc1a95SAnup Patel (char **)&compat, ARRAY_SIZE(compat)); 5469c0fb20cSPalmer Dabbelt } 5470ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 5480ffc1a95SAnup Patel 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size); 5490ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "phandle", test_phandle); 5500ffc1a95SAnup Patel test_phandle = qemu_fdt_get_phandle(mc->fdt, name); 55118df0b46SAnup Patel g_free(name); 5520e404da0SAnup Patel 55318df0b46SAnup Patel name = g_strdup_printf("/soc/reboot"); 5540ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5550ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-reboot"); 5560ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); 5570ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0); 5580ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_RESET); 55918df0b46SAnup Patel g_free(name); 5600e404da0SAnup Patel 56118df0b46SAnup Patel name = g_strdup_printf("/soc/poweroff"); 5620ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5630ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "syscon-poweroff"); 5640ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "regmap", test_phandle); 5650ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "offset", 0x0); 5660ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "value", FINISHER_PASS); 56718df0b46SAnup Patel g_free(name); 5680ffc1a95SAnup Patel } 5690ffc1a95SAnup Patel 5700ffc1a95SAnup Patel static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, 5710ffc1a95SAnup Patel uint32_t irq_mmio_phandle) 5720ffc1a95SAnup Patel { 5730ffc1a95SAnup Patel char *name; 5740ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 57504331d0bSMichael Clark 57618df0b46SAnup Patel name = g_strdup_printf("/soc/uart@%lx", (long)memmap[VIRT_UART0].base); 5770ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5780ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", "ns16550a"); 5790ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 58004331d0bSMichael Clark 0x0, memmap[VIRT_UART0].base, 58104331d0bSMichael Clark 0x0, memmap[VIRT_UART0].size); 5820ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400); 5830ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle); 5840ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ); 58504331d0bSMichael Clark 5860ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, "/chosen"); 5870ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name); 58818df0b46SAnup Patel g_free(name); 5890ffc1a95SAnup Patel } 5900ffc1a95SAnup Patel 5910ffc1a95SAnup Patel static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, 5920ffc1a95SAnup Patel uint32_t irq_mmio_phandle) 5930ffc1a95SAnup Patel { 5940ffc1a95SAnup Patel char *name; 5950ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 59671eb522cSAlistair Francis 59718df0b46SAnup Patel name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); 5980ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, name); 5990ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, name, "compatible", 6000ffc1a95SAnup Patel "google,goldfish-rtc"); 6010ffc1a95SAnup Patel qemu_fdt_setprop_cells(mc->fdt, name, "reg", 6020ffc1a95SAnup Patel 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); 6030ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", 6040ffc1a95SAnup Patel irq_mmio_phandle); 6050ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ); 60618df0b46SAnup Patel g_free(name); 6070ffc1a95SAnup Patel } 6080ffc1a95SAnup Patel 6090ffc1a95SAnup Patel static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) 6100ffc1a95SAnup Patel { 6110ffc1a95SAnup Patel char *name; 6120ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 6130ffc1a95SAnup Patel hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; 6140ffc1a95SAnup Patel hwaddr flashbase = virt_memmap[VIRT_FLASH].base; 61567b5ef30SAnup Patel 61658bde469SBin Meng name = g_strdup_printf("/flash@%" PRIx64, flashbase); 617c65d7080SAlex Bennée qemu_fdt_add_subnode(mc->fdt, name); 618c65d7080SAlex Bennée qemu_fdt_setprop_string(mc->fdt, name, "compatible", "cfi-flash"); 619c65d7080SAlex Bennée qemu_fdt_setprop_sized_cells(mc->fdt, name, "reg", 62071eb522cSAlistair Francis 2, flashbase, 2, flashsize, 62171eb522cSAlistair Francis 2, flashbase + flashsize, 2, flashsize); 622c65d7080SAlex Bennée qemu_fdt_setprop_cell(mc->fdt, name, "bank-width", 4); 62318df0b46SAnup Patel g_free(name); 6240ffc1a95SAnup Patel } 6250ffc1a95SAnup Patel 6260ffc1a95SAnup Patel static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, 6270ffc1a95SAnup Patel uint64_t mem_size, const char *cmdline, bool is_32_bit) 6280ffc1a95SAnup Patel { 6290ffc1a95SAnup Patel MachineState *mc = MACHINE(s); 6300ffc1a95SAnup Patel uint32_t phandle = 1, irq_mmio_phandle = 1; 6310ffc1a95SAnup Patel uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; 6320ffc1a95SAnup Patel 6330ffc1a95SAnup Patel if (mc->dtb) { 6340ffc1a95SAnup Patel mc->fdt = load_device_tree(mc->dtb, &s->fdt_size); 6350ffc1a95SAnup Patel if (!mc->fdt) { 6360ffc1a95SAnup Patel error_report("load_device_tree() failed"); 6370ffc1a95SAnup Patel exit(1); 6380ffc1a95SAnup Patel } 6390ffc1a95SAnup Patel goto update_bootargs; 6400ffc1a95SAnup Patel } else { 6410ffc1a95SAnup Patel mc->fdt = create_device_tree(&s->fdt_size); 6420ffc1a95SAnup Patel if (!mc->fdt) { 6430ffc1a95SAnup Patel error_report("create_device_tree() failed"); 6440ffc1a95SAnup Patel exit(1); 6450ffc1a95SAnup Patel } 6460ffc1a95SAnup Patel } 6470ffc1a95SAnup Patel 6480ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, "/", "model", "riscv-virtio,qemu"); 6490ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, "/", "compatible", "riscv-virtio"); 6500ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/", "#size-cells", 0x2); 6510ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/", "#address-cells", 0x2); 6520ffc1a95SAnup Patel 6530ffc1a95SAnup Patel qemu_fdt_add_subnode(mc->fdt, "/soc"); 6540ffc1a95SAnup Patel qemu_fdt_setprop(mc->fdt, "/soc", "ranges", NULL, 0); 6550ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, "/soc", "compatible", "simple-bus"); 6560ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/soc", "#size-cells", 0x2); 6570ffc1a95SAnup Patel qemu_fdt_setprop_cell(mc->fdt, "/soc", "#address-cells", 0x2); 6580ffc1a95SAnup Patel 6590ffc1a95SAnup Patel create_fdt_sockets(s, memmap, is_32_bit, &phandle, 6600ffc1a95SAnup Patel &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle); 6610ffc1a95SAnup Patel 6620ffc1a95SAnup Patel create_fdt_virtio(s, memmap, irq_virtio_phandle); 6630ffc1a95SAnup Patel 6640ffc1a95SAnup Patel create_fdt_pcie(s, memmap, irq_pcie_phandle); 6650ffc1a95SAnup Patel 6660ffc1a95SAnup Patel create_fdt_reset(s, memmap, &phandle); 6670ffc1a95SAnup Patel 6680ffc1a95SAnup Patel create_fdt_uart(s, memmap, irq_mmio_phandle); 6690ffc1a95SAnup Patel 6700ffc1a95SAnup Patel create_fdt_rtc(s, memmap, irq_mmio_phandle); 6710ffc1a95SAnup Patel 6720ffc1a95SAnup Patel create_fdt_flash(s, memmap); 6734e1e3003SAnup Patel 6744e1e3003SAnup Patel update_bootargs: 6754e1e3003SAnup Patel if (cmdline) { 6760ffc1a95SAnup Patel qemu_fdt_setprop_string(mc->fdt, "/chosen", "bootargs", cmdline); 6774e1e3003SAnup Patel } 67804331d0bSMichael Clark } 67904331d0bSMichael Clark 6806d56e396SAlistair Francis static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, 6816d56e396SAlistair Francis hwaddr ecam_base, hwaddr ecam_size, 6826d56e396SAlistair Francis hwaddr mmio_base, hwaddr mmio_size, 68319800265SBin Meng hwaddr high_mmio_base, 68419800265SBin Meng hwaddr high_mmio_size, 6856d56e396SAlistair Francis hwaddr pio_base, 6862fa3c7b6SBin Meng DeviceState *plic) 6876d56e396SAlistair Francis { 6886d56e396SAlistair Francis DeviceState *dev; 6896d56e396SAlistair Francis MemoryRegion *ecam_alias, *ecam_reg; 69019800265SBin Meng MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; 6916d56e396SAlistair Francis qemu_irq irq; 6926d56e396SAlistair Francis int i; 6936d56e396SAlistair Francis 6943e80f690SMarkus Armbruster dev = qdev_new(TYPE_GPEX_HOST); 6956d56e396SAlistair Francis 6963c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 6976d56e396SAlistair Francis 6986d56e396SAlistair Francis ecam_alias = g_new0(MemoryRegion, 1); 6996d56e396SAlistair Francis ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); 7006d56e396SAlistair Francis memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", 7016d56e396SAlistair Francis ecam_reg, 0, ecam_size); 7026d56e396SAlistair Francis memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias); 7036d56e396SAlistair Francis 7046d56e396SAlistair Francis mmio_alias = g_new0(MemoryRegion, 1); 7056d56e396SAlistair Francis mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); 7066d56e396SAlistair Francis memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", 7076d56e396SAlistair Francis mmio_reg, mmio_base, mmio_size); 7086d56e396SAlistair Francis memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); 7096d56e396SAlistair Francis 71019800265SBin Meng /* Map high MMIO space */ 71119800265SBin Meng high_mmio_alias = g_new0(MemoryRegion, 1); 71219800265SBin Meng memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", 71319800265SBin Meng mmio_reg, high_mmio_base, high_mmio_size); 71419800265SBin Meng memory_region_add_subregion(get_system_memory(), high_mmio_base, 71519800265SBin Meng high_mmio_alias); 71619800265SBin Meng 7176d56e396SAlistair Francis sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); 7186d56e396SAlistair Francis 7196d56e396SAlistair Francis for (i = 0; i < GPEX_NUM_IRQS; i++) { 7206d56e396SAlistair Francis irq = qdev_get_gpio_in(plic, PCIE_IRQ + i); 7216d56e396SAlistair Francis 7226d56e396SAlistair Francis sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); 7236d56e396SAlistair Francis gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); 7246d56e396SAlistair Francis } 7256d56e396SAlistair Francis 7266d56e396SAlistair Francis return dev; 7276d56e396SAlistair Francis } 7286d56e396SAlistair Francis 7290489348dSAsherah Connor static FWCfgState *create_fw_cfg(const MachineState *mc) 7300489348dSAsherah Connor { 7310489348dSAsherah Connor hwaddr base = virt_memmap[VIRT_FW_CFG].base; 7320489348dSAsherah Connor hwaddr size = virt_memmap[VIRT_FW_CFG].size; 7330489348dSAsherah Connor FWCfgState *fw_cfg; 7340489348dSAsherah Connor char *nodename; 7350489348dSAsherah Connor 7360489348dSAsherah Connor fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, 7370489348dSAsherah Connor &address_space_memory); 7380489348dSAsherah Connor fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)mc->smp.cpus); 7390489348dSAsherah Connor 7400489348dSAsherah Connor nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); 7410489348dSAsherah Connor qemu_fdt_add_subnode(mc->fdt, nodename); 7420489348dSAsherah Connor qemu_fdt_setprop_string(mc->fdt, nodename, 7430489348dSAsherah Connor "compatible", "qemu,fw-cfg-mmio"); 7440489348dSAsherah Connor qemu_fdt_setprop_sized_cells(mc->fdt, nodename, "reg", 7450489348dSAsherah Connor 2, base, 2, size); 7460489348dSAsherah Connor qemu_fdt_setprop(mc->fdt, nodename, "dma-coherent", NULL, 0); 7470489348dSAsherah Connor g_free(nodename); 7480489348dSAsherah Connor return fw_cfg; 7490489348dSAsherah Connor } 7500489348dSAsherah Connor 75133fcedfaSPeter Maydell /* 75233fcedfaSPeter Maydell * Return the per-socket PLIC hart topology configuration string 75333fcedfaSPeter Maydell * (caller must free with g_free()) 75433fcedfaSPeter Maydell */ 75533fcedfaSPeter Maydell static char *plic_hart_config_string(int hart_count) 75633fcedfaSPeter Maydell { 75733fcedfaSPeter Maydell g_autofree const char **vals = g_new(const char *, hart_count + 1); 75833fcedfaSPeter Maydell int i; 75933fcedfaSPeter Maydell 76033fcedfaSPeter Maydell for (i = 0; i < hart_count; i++) { 76133fcedfaSPeter Maydell vals[i] = VIRT_PLIC_HART_CONFIG; 76233fcedfaSPeter Maydell } 76333fcedfaSPeter Maydell vals[i] = NULL; 76433fcedfaSPeter Maydell 76533fcedfaSPeter Maydell /* g_strjoinv() obliges us to cast away const here */ 76633fcedfaSPeter Maydell return g_strjoinv(",", (char **)vals); 76733fcedfaSPeter Maydell } 76833fcedfaSPeter Maydell 769b2a3a071SBin Meng static void virt_machine_init(MachineState *machine) 77004331d0bSMichael Clark { 77173261285SBin Meng const MemMapEntry *memmap = virt_memmap; 772cdfc19e4SAlistair Francis RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); 77304331d0bSMichael Clark MemoryRegion *system_memory = get_system_memory(); 77404331d0bSMichael Clark MemoryRegion *main_mem = g_new(MemoryRegion, 1); 7755aec3247SMichael Clark MemoryRegion *mask_rom = g_new(MemoryRegion, 1); 77618df0b46SAnup Patel char *plic_hart_config, *soc_name; 7772738b3b5SAlistair Francis target_ulong start_addr = memmap[VIRT_DRAM].base; 77838bc4e34SAlistair Francis target_ulong firmware_end_addr, kernel_start_addr; 77966b1205bSAtish Patra uint32_t fdt_load_addr; 780dc144fe1SAtish Patra uint64_t kernel_entry; 78118df0b46SAnup Patel DeviceState *mmio_plic, *virtio_plic, *pcie_plic; 78233fcedfaSPeter Maydell int i, base_hartid, hart_count; 78304331d0bSMichael Clark 78418df0b46SAnup Patel /* Check socket count limit */ 78518df0b46SAnup Patel if (VIRT_SOCKETS_MAX < riscv_socket_count(machine)) { 78618df0b46SAnup Patel error_report("number of sockets/nodes should be less than %d", 78718df0b46SAnup Patel VIRT_SOCKETS_MAX); 78818df0b46SAnup Patel exit(1); 78918df0b46SAnup Patel } 79018df0b46SAnup Patel 79118df0b46SAnup Patel /* Initialize sockets */ 79218df0b46SAnup Patel mmio_plic = virtio_plic = pcie_plic = NULL; 79318df0b46SAnup Patel for (i = 0; i < riscv_socket_count(machine); i++) { 79418df0b46SAnup Patel if (!riscv_socket_check_hartids(machine, i)) { 79518df0b46SAnup Patel error_report("discontinuous hartids in socket%d", i); 79618df0b46SAnup Patel exit(1); 79718df0b46SAnup Patel } 79818df0b46SAnup Patel 79918df0b46SAnup Patel base_hartid = riscv_socket_first_hartid(machine, i); 80018df0b46SAnup Patel if (base_hartid < 0) { 80118df0b46SAnup Patel error_report("can't find hartid base for socket%d", i); 80218df0b46SAnup Patel exit(1); 80318df0b46SAnup Patel } 80418df0b46SAnup Patel 80518df0b46SAnup Patel hart_count = riscv_socket_hart_count(machine, i); 80618df0b46SAnup Patel if (hart_count < 0) { 80718df0b46SAnup Patel error_report("can't find hart count for socket%d", i); 80818df0b46SAnup Patel exit(1); 80918df0b46SAnup Patel } 81018df0b46SAnup Patel 81118df0b46SAnup Patel soc_name = g_strdup_printf("soc%d", i); 81218df0b46SAnup Patel object_initialize_child(OBJECT(machine), soc_name, &s->soc[i], 81375a6ed87SMarkus Armbruster TYPE_RISCV_HART_ARRAY); 81418df0b46SAnup Patel g_free(soc_name); 81518df0b46SAnup Patel object_property_set_str(OBJECT(&s->soc[i]), "cpu-type", 81618df0b46SAnup Patel machine->cpu_type, &error_abort); 81718df0b46SAnup Patel object_property_set_int(OBJECT(&s->soc[i]), "hartid-base", 81818df0b46SAnup Patel base_hartid, &error_abort); 81918df0b46SAnup Patel object_property_set_int(OBJECT(&s->soc[i]), "num-harts", 82018df0b46SAnup Patel hart_count, &error_abort); 82118df0b46SAnup Patel sysbus_realize(SYS_BUS_DEVICE(&s->soc[i]), &error_abort); 82218df0b46SAnup Patel 82318df0b46SAnup Patel /* Per-socket CLINT */ 824b8fb878aSAnup Patel riscv_aclint_swi_create( 82518df0b46SAnup Patel memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, 826b8fb878aSAnup Patel base_hartid, hart_count, false); 827b8fb878aSAnup Patel riscv_aclint_mtimer_create( 828b8fb878aSAnup Patel memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size + 829b8fb878aSAnup Patel RISCV_ACLINT_SWI_SIZE, 830b8fb878aSAnup Patel RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, 831b8fb878aSAnup Patel RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, 832b8fb878aSAnup Patel RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); 83318df0b46SAnup Patel 834*954886eaSAnup Patel /* Per-socket ACLINT SSWI */ 835*954886eaSAnup Patel if (s->have_aclint) { 836*954886eaSAnup Patel riscv_aclint_swi_create( 837*954886eaSAnup Patel memmap[VIRT_ACLINT_SSWI].base + 838*954886eaSAnup Patel i * memmap[VIRT_ACLINT_SSWI].size, 839*954886eaSAnup Patel base_hartid, hart_count, true); 840*954886eaSAnup Patel } 841*954886eaSAnup Patel 84218df0b46SAnup Patel /* Per-socket PLIC hart topology configuration string */ 84333fcedfaSPeter Maydell plic_hart_config = plic_hart_config_string(hart_count); 84418df0b46SAnup Patel 84518df0b46SAnup Patel /* Per-socket PLIC */ 84618df0b46SAnup Patel s->plic[i] = sifive_plic_create( 84718df0b46SAnup Patel memmap[VIRT_PLIC].base + i * memmap[VIRT_PLIC].size, 848f436ecc3SAlistair Francis plic_hart_config, hart_count, base_hartid, 84918df0b46SAnup Patel VIRT_PLIC_NUM_SOURCES, 85018df0b46SAnup Patel VIRT_PLIC_NUM_PRIORITIES, 85118df0b46SAnup Patel VIRT_PLIC_PRIORITY_BASE, 85218df0b46SAnup Patel VIRT_PLIC_PENDING_BASE, 85318df0b46SAnup Patel VIRT_PLIC_ENABLE_BASE, 85418df0b46SAnup Patel VIRT_PLIC_ENABLE_STRIDE, 85518df0b46SAnup Patel VIRT_PLIC_CONTEXT_BASE, 85618df0b46SAnup Patel VIRT_PLIC_CONTEXT_STRIDE, 85718df0b46SAnup Patel memmap[VIRT_PLIC].size); 85818df0b46SAnup Patel g_free(plic_hart_config); 85918df0b46SAnup Patel 86018df0b46SAnup Patel /* Try to use different PLIC instance based device type */ 86118df0b46SAnup Patel if (i == 0) { 86218df0b46SAnup Patel mmio_plic = s->plic[i]; 86318df0b46SAnup Patel virtio_plic = s->plic[i]; 86418df0b46SAnup Patel pcie_plic = s->plic[i]; 86518df0b46SAnup Patel } 86618df0b46SAnup Patel if (i == 1) { 86718df0b46SAnup Patel virtio_plic = s->plic[i]; 86818df0b46SAnup Patel pcie_plic = s->plic[i]; 86918df0b46SAnup Patel } 87018df0b46SAnup Patel if (i == 2) { 87118df0b46SAnup Patel pcie_plic = s->plic[i]; 87218df0b46SAnup Patel } 87318df0b46SAnup Patel } 87404331d0bSMichael Clark 875cfeb8a17SBin Meng if (riscv_is_32bit(&s->soc[0])) { 876cfeb8a17SBin Meng #if HOST_LONG_BITS == 64 877cfeb8a17SBin Meng /* limit RAM size in a 32-bit system */ 878cfeb8a17SBin Meng if (machine->ram_size > 10 * GiB) { 879cfeb8a17SBin Meng machine->ram_size = 10 * GiB; 880cfeb8a17SBin Meng error_report("Limiting RAM size to 10 GiB"); 881cfeb8a17SBin Meng } 882cfeb8a17SBin Meng #endif 88319800265SBin Meng virt_high_pcie_memmap.base = VIRT32_HIGH_PCIE_MMIO_BASE; 88419800265SBin Meng virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; 88519800265SBin Meng } else { 88619800265SBin Meng virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; 88719800265SBin Meng virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; 88819800265SBin Meng virt_high_pcie_memmap.base = 88919800265SBin Meng ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); 890cfeb8a17SBin Meng } 891cfeb8a17SBin Meng 89204331d0bSMichael Clark /* register system main memory (actual RAM) */ 89304331d0bSMichael Clark memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", 89404331d0bSMichael Clark machine->ram_size, &error_fatal); 89504331d0bSMichael Clark memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, 89604331d0bSMichael Clark main_mem); 89704331d0bSMichael Clark 89804331d0bSMichael Clark /* create device tree */ 8999d011430SAlistair Francis create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline, 900a8259b53SAlistair Francis riscv_is_32bit(&s->soc[0])); 90104331d0bSMichael Clark 90204331d0bSMichael Clark /* boot rom */ 9035aec3247SMichael Clark memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", 9045aec3247SMichael Clark memmap[VIRT_MROM].size, &error_fatal); 9055aec3247SMichael Clark memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, 9065aec3247SMichael Clark mask_rom); 90704331d0bSMichael Clark 908a8259b53SAlistair Francis if (riscv_is_32bit(&s->soc[0])) { 9099d011430SAlistair Francis firmware_end_addr = riscv_find_and_load_firmware(machine, 910a0acd0a1SBin Meng RISCV32_BIOS_BIN, start_addr, NULL); 9119d011430SAlistair Francis } else { 9129d011430SAlistair Francis firmware_end_addr = riscv_find_and_load_firmware(machine, 913a0acd0a1SBin Meng RISCV64_BIOS_BIN, start_addr, NULL); 9149d011430SAlistair Francis } 915b3042223SAlistair Francis 91604331d0bSMichael Clark if (machine->kernel_filename) { 917a8259b53SAlistair Francis kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], 91838bc4e34SAlistair Francis firmware_end_addr); 91938bc4e34SAlistair Francis 92038bc4e34SAlistair Francis kernel_entry = riscv_load_kernel(machine->kernel_filename, 92138bc4e34SAlistair Francis kernel_start_addr, NULL); 92204331d0bSMichael Clark 92304331d0bSMichael Clark if (machine->initrd_filename) { 92404331d0bSMichael Clark hwaddr start; 9250ac24d56SAlistair Francis hwaddr end = riscv_load_initrd(machine->initrd_filename, 92604331d0bSMichael Clark machine->ram_size, kernel_entry, 92704331d0bSMichael Clark &start); 928c65d7080SAlex Bennée qemu_fdt_setprop_cell(machine->fdt, "/chosen", 92904331d0bSMichael Clark "linux,initrd-start", start); 930c65d7080SAlex Bennée qemu_fdt_setprop_cell(machine->fdt, "/chosen", "linux,initrd-end", 93104331d0bSMichael Clark end); 93204331d0bSMichael Clark } 933dc144fe1SAtish Patra } else { 934dc144fe1SAtish Patra /* 935dc144fe1SAtish Patra * If dynamic firmware is used, it doesn't know where is the next mode 936dc144fe1SAtish Patra * if kernel argument is not set. 937dc144fe1SAtish Patra */ 938dc144fe1SAtish Patra kernel_entry = 0; 93904331d0bSMichael Clark } 94004331d0bSMichael Clark 9412738b3b5SAlistair Francis if (drive_get(IF_PFLASH, 0, 0)) { 9422738b3b5SAlistair Francis /* 9432738b3b5SAlistair Francis * Pflash was supplied, let's overwrite the address we jump to after 9442738b3b5SAlistair Francis * reset to the base of the flash. 9452738b3b5SAlistair Francis */ 9462738b3b5SAlistair Francis start_addr = virt_memmap[VIRT_FLASH].base; 9472738b3b5SAlistair Francis } 9482738b3b5SAlistair Francis 9490489348dSAsherah Connor /* 9500489348dSAsherah Connor * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the device 9510489348dSAsherah Connor * tree cannot be altered and we get FDT_ERR_NOSPACE. 9520489348dSAsherah Connor */ 9530489348dSAsherah Connor s->fw_cfg = create_fw_cfg(machine); 9540489348dSAsherah Connor rom_set_fw(s->fw_cfg); 9550489348dSAsherah Connor 95666b1205bSAtish Patra /* Compute the fdt load address in dram */ 95766b1205bSAtish Patra fdt_load_addr = riscv_load_fdt(memmap[VIRT_DRAM].base, 958c65d7080SAlex Bennée machine->ram_size, machine->fdt); 95943cf723aSAtish Patra /* load the reset vector */ 960a8259b53SAlistair Francis riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, 9613ed2b8acSAlistair Francis virt_memmap[VIRT_MROM].base, 962dc144fe1SAtish Patra virt_memmap[VIRT_MROM].size, kernel_entry, 963c65d7080SAlex Bennée fdt_load_addr, machine->fdt); 96404331d0bSMichael Clark 96518df0b46SAnup Patel /* SiFive Test MMIO device */ 96604331d0bSMichael Clark sifive_test_create(memmap[VIRT_TEST].base); 96704331d0bSMichael Clark 96818df0b46SAnup Patel /* VirtIO MMIO devices */ 96904331d0bSMichael Clark for (i = 0; i < VIRTIO_COUNT; i++) { 97004331d0bSMichael Clark sysbus_create_simple("virtio-mmio", 97104331d0bSMichael Clark memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, 97218df0b46SAnup Patel qdev_get_gpio_in(DEVICE(virtio_plic), VIRTIO_IRQ + i)); 97304331d0bSMichael Clark } 97404331d0bSMichael Clark 9756d56e396SAlistair Francis gpex_pcie_init(system_memory, 9766d56e396SAlistair Francis memmap[VIRT_PCIE_ECAM].base, 9776d56e396SAlistair Francis memmap[VIRT_PCIE_ECAM].size, 9786d56e396SAlistair Francis memmap[VIRT_PCIE_MMIO].base, 9796d56e396SAlistair Francis memmap[VIRT_PCIE_MMIO].size, 98019800265SBin Meng virt_high_pcie_memmap.base, 98119800265SBin Meng virt_high_pcie_memmap.size, 9826d56e396SAlistair Francis memmap[VIRT_PCIE_PIO].base, 9832fa3c7b6SBin Meng DEVICE(pcie_plic)); 9846d56e396SAlistair Francis 98504331d0bSMichael Clark serial_mm_init(system_memory, memmap[VIRT_UART0].base, 98618df0b46SAnup Patel 0, qdev_get_gpio_in(DEVICE(mmio_plic), UART0_IRQ), 399193, 9879bca0edbSPeter Maydell serial_hd(0), DEVICE_LITTLE_ENDIAN); 988b6aa6cedSMichael Clark 98967b5ef30SAnup Patel sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, 99018df0b46SAnup Patel qdev_get_gpio_in(DEVICE(mmio_plic), RTC_IRQ)); 99167b5ef30SAnup Patel 99271eb522cSAlistair Francis virt_flash_create(s); 99371eb522cSAlistair Francis 99471eb522cSAlistair Francis for (i = 0; i < ARRAY_SIZE(s->flash); i++) { 99571eb522cSAlistair Francis /* Map legacy -drive if=pflash to machine properties */ 99671eb522cSAlistair Francis pflash_cfi01_legacy_drive(s->flash[i], 99771eb522cSAlistair Francis drive_get(IF_PFLASH, 0, i)); 99871eb522cSAlistair Francis } 99971eb522cSAlistair Francis virt_flash_map(s, system_memory); 100004331d0bSMichael Clark } 100104331d0bSMichael Clark 1002b2a3a071SBin Meng static void virt_machine_instance_init(Object *obj) 100304331d0bSMichael Clark { 1004cdfc19e4SAlistair Francis } 1005cdfc19e4SAlistair Francis 1006*954886eaSAnup Patel static bool virt_get_aclint(Object *obj, Error **errp) 1007*954886eaSAnup Patel { 1008*954886eaSAnup Patel MachineState *ms = MACHINE(obj); 1009*954886eaSAnup Patel RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); 1010*954886eaSAnup Patel 1011*954886eaSAnup Patel return s->have_aclint; 1012*954886eaSAnup Patel } 1013*954886eaSAnup Patel 1014*954886eaSAnup Patel static void virt_set_aclint(Object *obj, bool value, Error **errp) 1015*954886eaSAnup Patel { 1016*954886eaSAnup Patel MachineState *ms = MACHINE(obj); 1017*954886eaSAnup Patel RISCVVirtState *s = RISCV_VIRT_MACHINE(ms); 1018*954886eaSAnup Patel 1019*954886eaSAnup Patel s->have_aclint = value; 1020*954886eaSAnup Patel } 1021*954886eaSAnup Patel 1022b2a3a071SBin Meng static void virt_machine_class_init(ObjectClass *oc, void *data) 1023cdfc19e4SAlistair Francis { 1024cdfc19e4SAlistair Francis MachineClass *mc = MACHINE_CLASS(oc); 1025cdfc19e4SAlistair Francis 1026cdfc19e4SAlistair Francis mc->desc = "RISC-V VirtIO board"; 1027b2a3a071SBin Meng mc->init = virt_machine_init; 102818df0b46SAnup Patel mc->max_cpus = VIRT_CPUS_MAX; 102909fe1712SAlistair Francis mc->default_cpu_type = TYPE_RISCV_CPU_BASE; 1030acead54cSBin Meng mc->pci_allow_0_address = true; 103118df0b46SAnup Patel mc->possible_cpu_arch_ids = riscv_numa_possible_cpu_arch_ids; 103218df0b46SAnup Patel mc->cpu_index_to_instance_props = riscv_numa_cpu_index_to_props; 103318df0b46SAnup Patel mc->get_default_cpu_node_id = riscv_numa_get_default_cpu_node_id; 103418df0b46SAnup Patel mc->numa_mem_supported = true; 1035c346749eSAsherah Connor 1036c346749eSAsherah Connor machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); 1037*954886eaSAnup Patel 1038*954886eaSAnup Patel object_class_property_add_bool(oc, "aclint", virt_get_aclint, 1039*954886eaSAnup Patel virt_set_aclint); 1040*954886eaSAnup Patel object_class_property_set_description(oc, "aclint", 1041*954886eaSAnup Patel "Set on/off to enable/disable " 1042*954886eaSAnup Patel "emulating ACLINT devices"); 104304331d0bSMichael Clark } 104404331d0bSMichael Clark 1045b2a3a071SBin Meng static const TypeInfo virt_machine_typeinfo = { 1046cdfc19e4SAlistair Francis .name = MACHINE_TYPE_NAME("virt"), 1047cdfc19e4SAlistair Francis .parent = TYPE_MACHINE, 1048b2a3a071SBin Meng .class_init = virt_machine_class_init, 1049b2a3a071SBin Meng .instance_init = virt_machine_instance_init, 1050cdfc19e4SAlistair Francis .instance_size = sizeof(RISCVVirtState), 1051cdfc19e4SAlistair Francis }; 1052cdfc19e4SAlistair Francis 1053b2a3a071SBin Meng static void virt_machine_init_register_types(void) 1054cdfc19e4SAlistair Francis { 1055b2a3a071SBin Meng type_register_static(&virt_machine_typeinfo); 1056cdfc19e4SAlistair Francis } 1057cdfc19e4SAlistair Francis 1058b2a3a071SBin Meng type_init(virt_machine_init_register_types) 1059