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