xref: /qemu/hw/loongarch/virt-fdt-build.c (revision 09951f5a27a7f8633118c1808cf17e66b30c3c62)
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 
create_fdt(LoongArchVirtMachineState * lvms)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 
fdt_add_cpu_nodes(const LoongArchVirtMachineState * lvms)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 
fdt_add_memory_node(MachineState * ms,uint64_t base,uint64_t size,int node_id)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 
fdt_add_memory_nodes(MachineState * ms)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 
fdt_add_fw_cfg_node(const LoongArchVirtMachineState * lvms)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 
fdt_add_flash_node(LoongArchVirtMachineState * lvms)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 
fdt_add_cpuic_node(LoongArchVirtMachineState * lvms,uint32_t * cpuintc_phandle)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 
fdt_add_eiointc_node(LoongArchVirtMachineState * lvms,uint32_t * cpuintc_phandle,uint32_t * eiointc_phandle)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 
fdt_add_pch_pic_node(LoongArchVirtMachineState * lvms,uint32_t * eiointc_phandle,uint32_t * pch_pic_phandle)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 
fdt_add_pch_msi_node(LoongArchVirtMachineState * lvms,uint32_t * eiointc_phandle,uint32_t * pch_msi_phandle)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 
fdt_add_pcie_irq_map_node(const LoongArchVirtMachineState * lvms,char * nodename,uint32_t * pch_pic_phandle)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 
fdt_add_pcie_node(const LoongArchVirtMachineState * lvms,uint32_t * pch_pic_phandle,uint32_t * pch_msi_phandle)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 
fdt_add_uart_node(LoongArchVirtMachineState * lvms,uint32_t * pch_pic_phandle,hwaddr base,int irq,bool chosen)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 
fdt_add_rtc_node(LoongArchVirtMachineState * lvms,uint32_t * pch_pic_phandle)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 
fdt_add_ged_reset(LoongArchVirtMachineState * lvms)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 
virt_fdt_setup(LoongArchVirtMachineState * lvms)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     rom_add_blob_fixed_as("fdt", machine->fdt, lvms->fdt_size, FDT_BASE,
531*3754f985SBibo Mao                           &address_space_memory);
532*3754f985SBibo Mao     qemu_register_reset_nosnapshotload(qemu_fdt_randomize_seeds,
533*3754f985SBibo Mao             rom_ptr_for_as(&address_space_memory, FDT_BASE, lvms->fdt_size));
534*3754f985SBibo Mao }
535