1*3754f985SBibo Mao /* SPDX-License-Identifier: GPL-2.0-or-later */ 2*3754f985SBibo Mao /* 3*3754f985SBibo Mao * Copyright (c) 2025 Loongson Technology Corporation Limited 4*3754f985SBibo Mao */ 5*3754f985SBibo Mao #include "qemu/osdep.h" 6*3754f985SBibo Mao #include "qemu/error-report.h" 7*3754f985SBibo Mao #include "qemu/guest-random.h" 8*3754f985SBibo Mao #include <libfdt.h> 9*3754f985SBibo Mao #include "hw/acpi/generic_event_device.h" 10*3754f985SBibo Mao #include "hw/core/sysbus-fdt.h" 11*3754f985SBibo Mao #include "hw/intc/loongarch_extioi.h" 12*3754f985SBibo Mao #include "hw/loader.h" 13*3754f985SBibo Mao #include "hw/loongarch/virt.h" 14*3754f985SBibo Mao #include "hw/pci-host/gpex.h" 15*3754f985SBibo Mao #include "hw/pci-host/ls7a.h" 16*3754f985SBibo Mao #include "system/device_tree.h" 17*3754f985SBibo Mao #include "system/reset.h" 18*3754f985SBibo Mao #include "target/loongarch/cpu.h" 19*3754f985SBibo Mao 20*3754f985SBibo Mao static void create_fdt(LoongArchVirtMachineState *lvms) 21*3754f985SBibo Mao { 22*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 23*3754f985SBibo Mao uint8_t rng_seed[32]; 24*3754f985SBibo Mao 25*3754f985SBibo Mao ms->fdt = create_device_tree(&lvms->fdt_size); 26*3754f985SBibo Mao if (!ms->fdt) { 27*3754f985SBibo Mao error_report("create_device_tree() failed"); 28*3754f985SBibo Mao exit(1); 29*3754f985SBibo Mao } 30*3754f985SBibo Mao 31*3754f985SBibo Mao /* Header */ 32*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, "/", "compatible", 33*3754f985SBibo Mao "linux,dummy-loongson3"); 34*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, "/", "#address-cells", 0x2); 35*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, "/", "#size-cells", 0x2); 36*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, "/chosen"); 37*3754f985SBibo Mao 38*3754f985SBibo Mao /* Pass seed to RNG */ 39*3754f985SBibo Mao qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); 40*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed)); 41*3754f985SBibo Mao } 42*3754f985SBibo Mao 43*3754f985SBibo Mao static void fdt_add_cpu_nodes(const LoongArchVirtMachineState *lvms) 44*3754f985SBibo Mao { 45*3754f985SBibo Mao int num; 46*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 47*3754f985SBibo Mao MachineClass *mc = MACHINE_GET_CLASS(ms); 48*3754f985SBibo Mao const CPUArchIdList *possible_cpus; 49*3754f985SBibo Mao LoongArchCPU *cpu; 50*3754f985SBibo Mao CPUState *cs; 51*3754f985SBibo Mao char *nodename, *map_path; 52*3754f985SBibo Mao 53*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, "/cpus"); 54*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#address-cells", 0x1); 55*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, "/cpus", "#size-cells", 0x0); 56*3754f985SBibo Mao 57*3754f985SBibo Mao /* cpu nodes */ 58*3754f985SBibo Mao possible_cpus = mc->possible_cpu_arch_ids(ms); 59*3754f985SBibo Mao for (num = 0; num < possible_cpus->len; num++) { 60*3754f985SBibo Mao cs = possible_cpus->cpus[num].cpu; 61*3754f985SBibo Mao if (cs == NULL) { 62*3754f985SBibo Mao continue; 63*3754f985SBibo Mao } 64*3754f985SBibo Mao 65*3754f985SBibo Mao nodename = g_strdup_printf("/cpus/cpu@%d", num); 66*3754f985SBibo Mao cpu = LOONGARCH_CPU(cs); 67*3754f985SBibo Mao 68*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 69*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "cpu"); 70*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 71*3754f985SBibo Mao cpu->dtb_compatible); 72*3754f985SBibo Mao if (possible_cpus->cpus[num].props.has_node_id) { 73*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", 74*3754f985SBibo Mao possible_cpus->cpus[num].props.node_id); 75*3754f985SBibo Mao } 76*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "reg", num); 77*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", 78*3754f985SBibo Mao qemu_fdt_alloc_phandle(ms->fdt)); 79*3754f985SBibo Mao g_free(nodename); 80*3754f985SBibo Mao } 81*3754f985SBibo Mao 82*3754f985SBibo Mao /*cpu map */ 83*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, "/cpus/cpu-map"); 84*3754f985SBibo Mao for (num = 0; num < possible_cpus->len; num++) { 85*3754f985SBibo Mao cs = possible_cpus->cpus[num].cpu; 86*3754f985SBibo Mao if (cs == NULL) { 87*3754f985SBibo Mao continue; 88*3754f985SBibo Mao } 89*3754f985SBibo Mao 90*3754f985SBibo Mao nodename = g_strdup_printf("/cpus/cpu@%d", num); 91*3754f985SBibo Mao if (ms->smp.threads > 1) { 92*3754f985SBibo Mao map_path = g_strdup_printf( 93*3754f985SBibo Mao "/cpus/cpu-map/socket%d/core%d/thread%d", 94*3754f985SBibo Mao num / (ms->smp.cores * ms->smp.threads), 95*3754f985SBibo Mao (num / ms->smp.threads) % ms->smp.cores, 96*3754f985SBibo Mao num % ms->smp.threads); 97*3754f985SBibo Mao } else { 98*3754f985SBibo Mao map_path = g_strdup_printf( 99*3754f985SBibo Mao "/cpus/cpu-map/socket%d/core%d", 100*3754f985SBibo Mao num / ms->smp.cores, 101*3754f985SBibo Mao num % ms->smp.cores); 102*3754f985SBibo Mao } 103*3754f985SBibo Mao qemu_fdt_add_path(ms->fdt, map_path); 104*3754f985SBibo Mao qemu_fdt_setprop_phandle(ms->fdt, map_path, "cpu", nodename); 105*3754f985SBibo Mao 106*3754f985SBibo Mao g_free(map_path); 107*3754f985SBibo Mao g_free(nodename); 108*3754f985SBibo Mao } 109*3754f985SBibo Mao } 110*3754f985SBibo Mao 111*3754f985SBibo Mao static void fdt_add_memory_node(MachineState *ms, 112*3754f985SBibo Mao uint64_t base, uint64_t size, int node_id) 113*3754f985SBibo Mao { 114*3754f985SBibo Mao char *nodename = g_strdup_printf("/memory@%" PRIx64, base); 115*3754f985SBibo Mao 116*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 117*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", base >> 32, base, 118*3754f985SBibo Mao size >> 32, size); 119*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "memory"); 120*3754f985SBibo Mao 121*3754f985SBibo Mao if (ms->numa_state && ms->numa_state->num_nodes) { 122*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "numa-node-id", node_id); 123*3754f985SBibo Mao } 124*3754f985SBibo Mao 125*3754f985SBibo Mao g_free(nodename); 126*3754f985SBibo Mao } 127*3754f985SBibo Mao 128*3754f985SBibo Mao static void fdt_add_memory_nodes(MachineState *ms) 129*3754f985SBibo Mao { 130*3754f985SBibo Mao hwaddr base, size, ram_size, gap; 131*3754f985SBibo Mao int i, nb_numa_nodes, nodes; 132*3754f985SBibo Mao NodeInfo *numa_info; 133*3754f985SBibo Mao 134*3754f985SBibo Mao ram_size = ms->ram_size; 135*3754f985SBibo Mao base = VIRT_LOWMEM_BASE; 136*3754f985SBibo Mao gap = VIRT_LOWMEM_SIZE; 137*3754f985SBibo Mao nodes = nb_numa_nodes = ms->numa_state->num_nodes; 138*3754f985SBibo Mao numa_info = ms->numa_state->nodes; 139*3754f985SBibo Mao if (!nodes) { 140*3754f985SBibo Mao nodes = 1; 141*3754f985SBibo Mao } 142*3754f985SBibo Mao 143*3754f985SBibo Mao for (i = 0; i < nodes; i++) { 144*3754f985SBibo Mao if (nb_numa_nodes) { 145*3754f985SBibo Mao size = numa_info[i].node_mem; 146*3754f985SBibo Mao } else { 147*3754f985SBibo Mao size = ram_size; 148*3754f985SBibo Mao } 149*3754f985SBibo Mao 150*3754f985SBibo Mao /* 151*3754f985SBibo Mao * memory for the node splited into two part 152*3754f985SBibo Mao * lowram: [base, +gap) 153*3754f985SBibo Mao * highram: [VIRT_HIGHMEM_BASE, +(len - gap)) 154*3754f985SBibo Mao */ 155*3754f985SBibo Mao if (size >= gap) { 156*3754f985SBibo Mao fdt_add_memory_node(ms, base, gap, i); 157*3754f985SBibo Mao size -= gap; 158*3754f985SBibo Mao base = VIRT_HIGHMEM_BASE; 159*3754f985SBibo Mao gap = ram_size - VIRT_LOWMEM_SIZE; 160*3754f985SBibo Mao } 161*3754f985SBibo Mao 162*3754f985SBibo Mao if (size) { 163*3754f985SBibo Mao fdt_add_memory_node(ms, base, size, i); 164*3754f985SBibo Mao base += size; 165*3754f985SBibo Mao gap -= size; 166*3754f985SBibo Mao } 167*3754f985SBibo Mao } 168*3754f985SBibo Mao } 169*3754f985SBibo Mao 170*3754f985SBibo Mao static void fdt_add_fw_cfg_node(const LoongArchVirtMachineState *lvms) 171*3754f985SBibo Mao { 172*3754f985SBibo Mao char *nodename; 173*3754f985SBibo Mao hwaddr base = VIRT_FWCFG_BASE; 174*3754f985SBibo Mao const MachineState *ms = MACHINE(lvms); 175*3754f985SBibo Mao 176*3754f985SBibo Mao nodename = g_strdup_printf("/fw_cfg@%" PRIx64, base); 177*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 178*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, 179*3754f985SBibo Mao "compatible", "qemu,fw-cfg-mmio"); 180*3754f985SBibo Mao qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 181*3754f985SBibo Mao 2, base, 2, 0x18); 182*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); 183*3754f985SBibo Mao g_free(nodename); 184*3754f985SBibo Mao } 185*3754f985SBibo Mao 186*3754f985SBibo Mao static void fdt_add_flash_node(LoongArchVirtMachineState *lvms) 187*3754f985SBibo Mao { 188*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 189*3754f985SBibo Mao char *nodename; 190*3754f985SBibo Mao MemoryRegion *flash_mem; 191*3754f985SBibo Mao 192*3754f985SBibo Mao hwaddr flash0_base; 193*3754f985SBibo Mao hwaddr flash0_size; 194*3754f985SBibo Mao 195*3754f985SBibo Mao hwaddr flash1_base; 196*3754f985SBibo Mao hwaddr flash1_size; 197*3754f985SBibo Mao 198*3754f985SBibo Mao flash_mem = pflash_cfi01_get_memory(lvms->flash[0]); 199*3754f985SBibo Mao flash0_base = flash_mem->addr; 200*3754f985SBibo Mao flash0_size = memory_region_size(flash_mem); 201*3754f985SBibo Mao 202*3754f985SBibo Mao flash_mem = pflash_cfi01_get_memory(lvms->flash[1]); 203*3754f985SBibo Mao flash1_base = flash_mem->addr; 204*3754f985SBibo Mao flash1_size = memory_region_size(flash_mem); 205*3754f985SBibo Mao 206*3754f985SBibo Mao nodename = g_strdup_printf("/flash@%" PRIx64, flash0_base); 207*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 208*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "cfi-flash"); 209*3754f985SBibo Mao qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 210*3754f985SBibo Mao 2, flash0_base, 2, flash0_size, 211*3754f985SBibo Mao 2, flash1_base, 2, flash1_size); 212*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "bank-width", 4); 213*3754f985SBibo Mao g_free(nodename); 214*3754f985SBibo Mao } 215*3754f985SBibo Mao 216*3754f985SBibo Mao static void fdt_add_cpuic_node(LoongArchVirtMachineState *lvms, 217*3754f985SBibo Mao uint32_t *cpuintc_phandle) 218*3754f985SBibo Mao { 219*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 220*3754f985SBibo Mao char *nodename; 221*3754f985SBibo Mao 222*3754f985SBibo Mao *cpuintc_phandle = qemu_fdt_alloc_phandle(ms->fdt); 223*3754f985SBibo Mao nodename = g_strdup_printf("/cpuic"); 224*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 225*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *cpuintc_phandle); 226*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 227*3754f985SBibo Mao "loongson,cpu-interrupt-controller"); 228*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 229*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); 230*3754f985SBibo Mao g_free(nodename); 231*3754f985SBibo Mao } 232*3754f985SBibo Mao 233*3754f985SBibo Mao static void fdt_add_eiointc_node(LoongArchVirtMachineState *lvms, 234*3754f985SBibo Mao uint32_t *cpuintc_phandle, 235*3754f985SBibo Mao uint32_t *eiointc_phandle) 236*3754f985SBibo Mao { 237*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 238*3754f985SBibo Mao char *nodename; 239*3754f985SBibo Mao hwaddr extioi_base = APIC_BASE; 240*3754f985SBibo Mao hwaddr extioi_size = EXTIOI_SIZE; 241*3754f985SBibo Mao 242*3754f985SBibo Mao *eiointc_phandle = qemu_fdt_alloc_phandle(ms->fdt); 243*3754f985SBibo Mao nodename = g_strdup_printf("/eiointc@%" PRIx64, extioi_base); 244*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 245*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *eiointc_phandle); 246*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 247*3754f985SBibo Mao "loongson,ls2k2000-eiointc"); 248*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 249*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 1); 250*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 251*3754f985SBibo Mao *cpuintc_phandle); 252*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupts", 3); 253*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, 254*3754f985SBibo Mao extioi_base, 0x0, extioi_size); 255*3754f985SBibo Mao g_free(nodename); 256*3754f985SBibo Mao } 257*3754f985SBibo Mao 258*3754f985SBibo Mao static void fdt_add_pch_pic_node(LoongArchVirtMachineState *lvms, 259*3754f985SBibo Mao uint32_t *eiointc_phandle, 260*3754f985SBibo Mao uint32_t *pch_pic_phandle) 261*3754f985SBibo Mao { 262*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 263*3754f985SBibo Mao char *nodename; 264*3754f985SBibo Mao hwaddr pch_pic_base = VIRT_PCH_REG_BASE; 265*3754f985SBibo Mao hwaddr pch_pic_size = VIRT_PCH_REG_SIZE; 266*3754f985SBibo Mao 267*3754f985SBibo Mao *pch_pic_phandle = qemu_fdt_alloc_phandle(ms->fdt); 268*3754f985SBibo Mao nodename = g_strdup_printf("/platic@%" PRIx64, pch_pic_base); 269*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 270*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_pic_phandle); 271*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 272*3754f985SBibo Mao "loongson,pch-pic-1.0"); 273*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0, 274*3754f985SBibo Mao pch_pic_base, 0, pch_pic_size); 275*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 276*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "#interrupt-cells", 2); 277*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 278*3754f985SBibo Mao *eiointc_phandle); 279*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,pic-base-vec", 0); 280*3754f985SBibo Mao g_free(nodename); 281*3754f985SBibo Mao } 282*3754f985SBibo Mao 283*3754f985SBibo Mao static void fdt_add_pch_msi_node(LoongArchVirtMachineState *lvms, 284*3754f985SBibo Mao uint32_t *eiointc_phandle, 285*3754f985SBibo Mao uint32_t *pch_msi_phandle) 286*3754f985SBibo Mao { 287*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 288*3754f985SBibo Mao char *nodename; 289*3754f985SBibo Mao hwaddr pch_msi_base = VIRT_PCH_MSI_ADDR_LOW; 290*3754f985SBibo Mao hwaddr pch_msi_size = VIRT_PCH_MSI_SIZE; 291*3754f985SBibo Mao 292*3754f985SBibo Mao *pch_msi_phandle = qemu_fdt_alloc_phandle(ms->fdt); 293*3754f985SBibo Mao nodename = g_strdup_printf("/msi@%" PRIx64, pch_msi_base); 294*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 295*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "phandle", *pch_msi_phandle); 296*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 297*3754f985SBibo Mao "loongson,pch-msi-1.0"); 298*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 299*3754f985SBibo Mao 0, pch_msi_base, 300*3754f985SBibo Mao 0, pch_msi_size); 301*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "interrupt-controller", NULL, 0); 302*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 303*3754f985SBibo Mao *eiointc_phandle); 304*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-base-vec", 305*3754f985SBibo Mao VIRT_PCH_PIC_IRQ_NUM); 306*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "loongson,msi-num-vecs", 307*3754f985SBibo Mao EXTIOI_IRQS - VIRT_PCH_PIC_IRQ_NUM); 308*3754f985SBibo Mao g_free(nodename); 309*3754f985SBibo Mao } 310*3754f985SBibo Mao 311*3754f985SBibo Mao static void fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState *lvms, 312*3754f985SBibo Mao char *nodename, 313*3754f985SBibo Mao uint32_t *pch_pic_phandle) 314*3754f985SBibo Mao { 315*3754f985SBibo Mao int pin, dev; 316*3754f985SBibo Mao uint32_t irq_map_stride = 0; 317*3754f985SBibo Mao uint32_t full_irq_map[PCI_NUM_PINS * PCI_NUM_PINS * 10] = {}; 318*3754f985SBibo Mao uint32_t *irq_map = full_irq_map; 319*3754f985SBibo Mao const MachineState *ms = MACHINE(lvms); 320*3754f985SBibo Mao 321*3754f985SBibo Mao /* 322*3754f985SBibo Mao * This code creates a standard swizzle of interrupts such that 323*3754f985SBibo Mao * each device's first interrupt is based on it's PCI_SLOT number. 324*3754f985SBibo Mao * (See pci_swizzle_map_irq_fn()) 325*3754f985SBibo Mao * 326*3754f985SBibo Mao * We only need one entry per interrupt in the table (not one per 327*3754f985SBibo Mao * possible slot) seeing the interrupt-map-mask will allow the table 328*3754f985SBibo Mao * to wrap to any number of devices. 329*3754f985SBibo Mao */ 330*3754f985SBibo Mao 331*3754f985SBibo Mao for (dev = 0; dev < PCI_NUM_PINS; dev++) { 332*3754f985SBibo Mao int devfn = dev * 0x8; 333*3754f985SBibo Mao 334*3754f985SBibo Mao for (pin = 0; pin < PCI_NUM_PINS; pin++) { 335*3754f985SBibo Mao int irq_nr = 16 + ((pin + PCI_SLOT(devfn)) % PCI_NUM_PINS); 336*3754f985SBibo Mao int i = 0; 337*3754f985SBibo Mao 338*3754f985SBibo Mao /* Fill PCI address cells */ 339*3754f985SBibo Mao irq_map[i] = cpu_to_be32(devfn << 8); 340*3754f985SBibo Mao i += 3; 341*3754f985SBibo Mao 342*3754f985SBibo Mao /* Fill PCI Interrupt cells */ 343*3754f985SBibo Mao irq_map[i] = cpu_to_be32(pin + 1); 344*3754f985SBibo Mao i += 1; 345*3754f985SBibo Mao 346*3754f985SBibo Mao /* Fill interrupt controller phandle and cells */ 347*3754f985SBibo Mao irq_map[i++] = cpu_to_be32(*pch_pic_phandle); 348*3754f985SBibo Mao irq_map[i++] = cpu_to_be32(irq_nr); 349*3754f985SBibo Mao 350*3754f985SBibo Mao if (!irq_map_stride) { 351*3754f985SBibo Mao irq_map_stride = i; 352*3754f985SBibo Mao } 353*3754f985SBibo Mao irq_map += irq_map_stride; 354*3754f985SBibo Mao } 355*3754f985SBibo Mao } 356*3754f985SBibo Mao 357*3754f985SBibo Mao 358*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "interrupt-map", full_irq_map, 359*3754f985SBibo Mao PCI_NUM_PINS * PCI_NUM_PINS * 360*3754f985SBibo Mao irq_map_stride * sizeof(uint32_t)); 361*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupt-map-mask", 362*3754f985SBibo Mao 0x1800, 0, 0, 0x7); 363*3754f985SBibo Mao } 364*3754f985SBibo Mao 365*3754f985SBibo Mao static void fdt_add_pcie_node(const LoongArchVirtMachineState *lvms, 366*3754f985SBibo Mao uint32_t *pch_pic_phandle, 367*3754f985SBibo Mao uint32_t *pch_msi_phandle) 368*3754f985SBibo Mao { 369*3754f985SBibo Mao char *nodename; 370*3754f985SBibo Mao hwaddr base_mmio = VIRT_PCI_MEM_BASE; 371*3754f985SBibo Mao hwaddr size_mmio = VIRT_PCI_MEM_SIZE; 372*3754f985SBibo Mao hwaddr base_pio = VIRT_PCI_IO_BASE; 373*3754f985SBibo Mao hwaddr size_pio = VIRT_PCI_IO_SIZE; 374*3754f985SBibo Mao hwaddr base_pcie = VIRT_PCI_CFG_BASE; 375*3754f985SBibo Mao hwaddr size_pcie = VIRT_PCI_CFG_SIZE; 376*3754f985SBibo Mao hwaddr base = base_pcie; 377*3754f985SBibo Mao const MachineState *ms = MACHINE(lvms); 378*3754f985SBibo Mao 379*3754f985SBibo Mao nodename = g_strdup_printf("/pcie@%" PRIx64, base); 380*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 381*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, 382*3754f985SBibo Mao "compatible", "pci-host-ecam-generic"); 383*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "device_type", "pci"); 384*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "#address-cells", 3); 385*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "#size-cells", 2); 386*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "linux,pci-domain", 0); 387*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "bus-range", 0, 388*3754f985SBibo Mao PCIE_MMCFG_BUS(VIRT_PCI_CFG_SIZE - 1)); 389*3754f985SBibo Mao qemu_fdt_setprop(ms->fdt, nodename, "dma-coherent", NULL, 0); 390*3754f985SBibo Mao qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 391*3754f985SBibo Mao 2, base_pcie, 2, size_pcie); 392*3754f985SBibo Mao qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "ranges", 393*3754f985SBibo Mao 1, FDT_PCI_RANGE_IOPORT, 2, VIRT_PCI_IO_OFFSET, 394*3754f985SBibo Mao 2, base_pio, 2, size_pio, 395*3754f985SBibo Mao 1, FDT_PCI_RANGE_MMIO, 2, base_mmio, 396*3754f985SBibo Mao 2, base_mmio, 2, size_mmio); 397*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "msi-map", 398*3754f985SBibo Mao 0, *pch_msi_phandle, 0, 0x10000); 399*3754f985SBibo Mao fdt_add_pcie_irq_map_node(lvms, nodename, pch_pic_phandle); 400*3754f985SBibo Mao g_free(nodename); 401*3754f985SBibo Mao } 402*3754f985SBibo Mao 403*3754f985SBibo Mao static void fdt_add_uart_node(LoongArchVirtMachineState *lvms, 404*3754f985SBibo Mao uint32_t *pch_pic_phandle, hwaddr base, 405*3754f985SBibo Mao int irq, bool chosen) 406*3754f985SBibo Mao { 407*3754f985SBibo Mao char *nodename; 408*3754f985SBibo Mao hwaddr size = VIRT_UART_SIZE; 409*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 410*3754f985SBibo Mao 411*3754f985SBibo Mao nodename = g_strdup_printf("/serial@%" PRIx64, base); 412*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 413*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", "ns16550a"); 414*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "reg", 0x0, base, 0x0, size); 415*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "clock-frequency", 100000000); 416*3754f985SBibo Mao if (chosen) { 417*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, "/chosen", "stdout-path", nodename); 418*3754f985SBibo Mao } 419*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", irq, 0x4); 420*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 421*3754f985SBibo Mao *pch_pic_phandle); 422*3754f985SBibo Mao g_free(nodename); 423*3754f985SBibo Mao } 424*3754f985SBibo Mao 425*3754f985SBibo Mao static void fdt_add_rtc_node(LoongArchVirtMachineState *lvms, 426*3754f985SBibo Mao uint32_t *pch_pic_phandle) 427*3754f985SBibo Mao { 428*3754f985SBibo Mao char *nodename; 429*3754f985SBibo Mao hwaddr base = VIRT_RTC_REG_BASE; 430*3754f985SBibo Mao hwaddr size = VIRT_RTC_LEN; 431*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 432*3754f985SBibo Mao 433*3754f985SBibo Mao nodename = g_strdup_printf("/rtc@%" PRIx64, base); 434*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, nodename); 435*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, nodename, "compatible", 436*3754f985SBibo Mao "loongson,ls7a-rtc"); 437*3754f985SBibo Mao qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg", 2, base, 2, size); 438*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts", 439*3754f985SBibo Mao VIRT_RTC_IRQ - VIRT_GSI_BASE , 0x4); 440*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, nodename, "interrupt-parent", 441*3754f985SBibo Mao *pch_pic_phandle); 442*3754f985SBibo Mao g_free(nodename); 443*3754f985SBibo Mao } 444*3754f985SBibo Mao 445*3754f985SBibo Mao static void fdt_add_ged_reset(LoongArchVirtMachineState *lvms) 446*3754f985SBibo Mao { 447*3754f985SBibo Mao char *name; 448*3754f985SBibo Mao uint32_t ged_handle; 449*3754f985SBibo Mao MachineState *ms = MACHINE(lvms); 450*3754f985SBibo Mao hwaddr base = VIRT_GED_REG_ADDR; 451*3754f985SBibo Mao hwaddr size = ACPI_GED_REG_COUNT; 452*3754f985SBibo Mao 453*3754f985SBibo Mao ged_handle = qemu_fdt_alloc_phandle(ms->fdt); 454*3754f985SBibo Mao name = g_strdup_printf("/ged@%" PRIx64, base); 455*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, name); 456*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon"); 457*3754f985SBibo Mao qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0x0, base, 0x0, size); 458*3754f985SBibo Mao /* 8 bit registers */ 459*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "reg-shift", 0); 460*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "reg-io-width", 1); 461*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "phandle", ged_handle); 462*3754f985SBibo Mao ged_handle = qemu_fdt_get_phandle(ms->fdt, name); 463*3754f985SBibo Mao g_free(name); 464*3754f985SBibo Mao 465*3754f985SBibo Mao name = g_strdup_printf("/reboot"); 466*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, name); 467*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-reboot"); 468*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); 469*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_RESET); 470*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_RESET_VALUE); 471*3754f985SBibo Mao g_free(name); 472*3754f985SBibo Mao 473*3754f985SBibo Mao name = g_strdup_printf("/poweroff"); 474*3754f985SBibo Mao qemu_fdt_add_subnode(ms->fdt, name); 475*3754f985SBibo Mao qemu_fdt_setprop_string(ms->fdt, name, "compatible", "syscon-poweroff"); 476*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "regmap", ged_handle); 477*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "offset", ACPI_GED_REG_SLEEP_CTL); 478*3754f985SBibo Mao qemu_fdt_setprop_cell(ms->fdt, name, "value", ACPI_GED_SLP_EN | 479*3754f985SBibo Mao (ACPI_GED_SLP_TYP_S5 << ACPI_GED_SLP_TYP_POS)); 480*3754f985SBibo Mao g_free(name); 481*3754f985SBibo Mao } 482*3754f985SBibo Mao 483*3754f985SBibo Mao void virt_fdt_setup(LoongArchVirtMachineState *lvms) 484*3754f985SBibo Mao { 485*3754f985SBibo Mao MachineState *machine = MACHINE(lvms); 486*3754f985SBibo Mao uint32_t cpuintc_phandle, eiointc_phandle, pch_pic_phandle, pch_msi_phandle; 487*3754f985SBibo Mao int i; 488*3754f985SBibo Mao 489*3754f985SBibo Mao create_fdt(lvms); 490*3754f985SBibo Mao fdt_add_cpu_nodes(lvms); 491*3754f985SBibo Mao fdt_add_memory_nodes(machine); 492*3754f985SBibo Mao fdt_add_fw_cfg_node(lvms); 493*3754f985SBibo Mao fdt_add_flash_node(lvms); 494*3754f985SBibo Mao 495*3754f985SBibo Mao /* Add cpu interrupt-controller */ 496*3754f985SBibo Mao fdt_add_cpuic_node(lvms, &cpuintc_phandle); 497*3754f985SBibo Mao /* Add Extend I/O Interrupt Controller node */ 498*3754f985SBibo Mao fdt_add_eiointc_node(lvms, &cpuintc_phandle, &eiointc_phandle); 499*3754f985SBibo Mao /* Add PCH PIC node */ 500*3754f985SBibo Mao fdt_add_pch_pic_node(lvms, &eiointc_phandle, &pch_pic_phandle); 501*3754f985SBibo Mao /* Add PCH MSI node */ 502*3754f985SBibo Mao fdt_add_pch_msi_node(lvms, &eiointc_phandle, &pch_msi_phandle); 503*3754f985SBibo Mao /* Add pcie node */ 504*3754f985SBibo Mao fdt_add_pcie_node(lvms, &pch_pic_phandle, &pch_msi_phandle); 505*3754f985SBibo Mao 506*3754f985SBibo Mao /* 507*3754f985SBibo Mao * Create uart fdt node in reverse order so that they appear 508*3754f985SBibo Mao * in the finished device tree lowest address first 509*3754f985SBibo Mao */ 510*3754f985SBibo Mao for (i = VIRT_UART_COUNT; i-- > 0;) { 511*3754f985SBibo Mao hwaddr base = VIRT_UART_BASE + i * VIRT_UART_SIZE; 512*3754f985SBibo Mao int irq = VIRT_UART_IRQ + i - VIRT_GSI_BASE; 513*3754f985SBibo Mao fdt_add_uart_node(lvms, &pch_pic_phandle, base, irq, i == 0); 514*3754f985SBibo Mao } 515*3754f985SBibo Mao 516*3754f985SBibo Mao fdt_add_rtc_node(lvms, &pch_pic_phandle); 517*3754f985SBibo Mao fdt_add_ged_reset(lvms); 518*3754f985SBibo Mao platform_bus_add_all_fdt_nodes(machine->fdt, "/platic", 519*3754f985SBibo Mao VIRT_PLATFORM_BUS_BASEADDRESS, 520*3754f985SBibo Mao VIRT_PLATFORM_BUS_SIZE, 521*3754f985SBibo Mao VIRT_PLATFORM_BUS_IRQ); 522*3754f985SBibo Mao 523*3754f985SBibo Mao /* 524*3754f985SBibo Mao * Since lowmem region starts from 0 and Linux kernel legacy start address 525*3754f985SBibo Mao * at 2 MiB, FDT base address is located at 1 MiB to avoid NULL pointer 526*3754f985SBibo Mao * access. FDT size limit with 1 MiB. 527*3754f985SBibo Mao * Put the FDT into the memory map as a ROM image: this will ensure 528*3754f985SBibo Mao * the FDT is copied again upon reset, even if addr points into RAM. 529*3754f985SBibo Mao */ 530*3754f985SBibo Mao qemu_fdt_dumpdtb(machine->fdt, lvms->fdt_size); 531*3754f985SBibo Mao rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE, 532*3754f985SBibo Mao &address_space_memory); 533*3754f985SBibo Mao qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds, 534*3754f985SBibo Mao rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size)); 535*3754f985SBibo Mao } 536