Skip to content

Commit 7230389

Browse files
FlyGoatphilmd
authored andcommitted
hw/mips/boston: Add FDT generator
Generate FDT on our own if no dtb argument supplied. Avoid introducing unused device in FDT with user supplied dtb. Signed-off-by: Jiaxun Yang <[email protected]> [PMD: Fix coding style] Signed-off-by: Philippe Mathieu-Daudé <[email protected]> Message-Id: <[email protected]>
1 parent 10e3f30 commit 7230389

File tree

1 file changed

+236
-9
lines changed

1 file changed

+236
-9
lines changed

hw/mips/boston.c

Lines changed: 236 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ typedef struct BostonState BostonState;
4949
DECLARE_INSTANCE_CHECKER(BostonState, BOSTON,
5050
TYPE_BOSTON)
5151

52+
#define FDT_IRQ_TYPE_NONE 0
53+
#define FDT_IRQ_TYPE_LEVEL_HIGH 4
54+
#define FDT_GIC_SHARED 0
55+
#define FDT_GIC_LOCAL 1
56+
#define FDT_BOSTON_CLK_SYS 1
57+
#define FDT_BOSTON_CLK_CPU 2
58+
#define FDT_PCI_IRQ_MAP_PINS 4
59+
#define FDT_PCI_IRQ_MAP_DESCS 6
60+
5261
struct BostonState {
5362
SysBusDevice parent_obj;
5463

@@ -437,6 +446,222 @@ xilinx_pcie_init(MemoryRegion *sys_mem, uint32_t bus_nr,
437446
return XILINX_PCIE_HOST(dev);
438447
}
439448

449+
450+
static void fdt_create_pcie(void *fdt, int gic_ph, int irq, hwaddr reg_base,
451+
hwaddr reg_size, hwaddr mmio_base, hwaddr mmio_size)
452+
{
453+
int i;
454+
char *name, *intc_name;
455+
uint32_t intc_ph;
456+
uint32_t interrupt_map[FDT_PCI_IRQ_MAP_PINS][FDT_PCI_IRQ_MAP_DESCS];
457+
458+
intc_ph = qemu_fdt_alloc_phandle(fdt);
459+
name = g_strdup_printf("/soc/pci@%" HWADDR_PRIx, reg_base);
460+
qemu_fdt_add_subnode(fdt, name);
461+
qemu_fdt_setprop_string(fdt, name, "compatible",
462+
"xlnx,axi-pcie-host-1.00.a");
463+
qemu_fdt_setprop_string(fdt, name, "device_type", "pci");
464+
qemu_fdt_setprop_cells(fdt, name, "reg", reg_base, reg_size);
465+
466+
qemu_fdt_setprop_cell(fdt, name, "#address-cells", 3);
467+
qemu_fdt_setprop_cell(fdt, name, "#size-cells", 2);
468+
qemu_fdt_setprop_cell(fdt, name, "#interrupt-cells", 1);
469+
470+
qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", gic_ph);
471+
qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_SHARED, irq,
472+
FDT_IRQ_TYPE_LEVEL_HIGH);
473+
474+
qemu_fdt_setprop_cells(fdt, name, "ranges", 0x02000000, 0, mmio_base,
475+
mmio_base, 0, mmio_size);
476+
qemu_fdt_setprop_cells(fdt, name, "bus-range", 0x00, 0xff);
477+
478+
479+
480+
intc_name = g_strdup_printf("%s/interrupt-controller", name);
481+
qemu_fdt_add_subnode(fdt, intc_name);
482+
qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
483+
qemu_fdt_setprop_cell(fdt, intc_name, "#address-cells", 0);
484+
qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
485+
qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_ph);
486+
487+
qemu_fdt_setprop_cells(fdt, name, "interrupt-map-mask", 0, 0, 0, 7);
488+
for (i = 0; i < FDT_PCI_IRQ_MAP_PINS; i++) {
489+
uint32_t *irqmap = interrupt_map[i];
490+
491+
irqmap[0] = cpu_to_be32(0);
492+
irqmap[1] = cpu_to_be32(0);
493+
irqmap[2] = cpu_to_be32(0);
494+
irqmap[3] = cpu_to_be32(i + 1);
495+
irqmap[4] = cpu_to_be32(intc_ph);
496+
irqmap[5] = cpu_to_be32(i + 1);
497+
}
498+
qemu_fdt_setprop(fdt, name, "interrupt-map",
499+
&interrupt_map, sizeof(interrupt_map));
500+
501+
g_free(intc_name);
502+
g_free(name);
503+
}
504+
505+
static const void *create_fdt(BostonState *s,
506+
const MemMapEntry *memmap, int *dt_size)
507+
{
508+
void *fdt;
509+
int cpu;
510+
MachineState *mc = s->mach;
511+
uint32_t platreg_ph, gic_ph, clk_ph;
512+
char *name, *gic_name, *platreg_name, *stdout_name;
513+
static const char * const syscon_compat[2] = {
514+
"img,boston-platform-regs", "syscon"
515+
};
516+
517+
fdt = create_device_tree(dt_size);
518+
if (!fdt) {
519+
error_report("create_device_tree() failed");
520+
exit(1);
521+
}
522+
523+
platreg_ph = qemu_fdt_alloc_phandle(fdt);
524+
gic_ph = qemu_fdt_alloc_phandle(fdt);
525+
clk_ph = qemu_fdt_alloc_phandle(fdt);
526+
527+
qemu_fdt_setprop_string(fdt, "/", "model", "img,boston");
528+
qemu_fdt_setprop_string(fdt, "/", "compatible", "img,boston");
529+
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x1);
530+
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x1);
531+
532+
533+
qemu_fdt_add_subnode(fdt, "/cpus");
534+
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
535+
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
536+
537+
for (cpu = 0; cpu < mc->smp.cpus; cpu++) {
538+
name = g_strdup_printf("/cpus/cpu@%d", cpu);
539+
qemu_fdt_add_subnode(fdt, name);
540+
qemu_fdt_setprop_string(fdt, name, "compatible", "img,mips");
541+
qemu_fdt_setprop_string(fdt, name, "status", "okay");
542+
qemu_fdt_setprop_cell(fdt, name, "reg", cpu);
543+
qemu_fdt_setprop_string(fdt, name, "device_type", "cpu");
544+
qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_CPU);
545+
g_free(name);
546+
}
547+
548+
qemu_fdt_add_subnode(fdt, "/soc");
549+
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
550+
qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
551+
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x1);
552+
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x1);
553+
554+
fdt_create_pcie(fdt, gic_ph, 2,
555+
memmap[BOSTON_PCIE0].base, memmap[BOSTON_PCIE0].size,
556+
memmap[BOSTON_PCIE0_MMIO].base, memmap[BOSTON_PCIE0_MMIO].size);
557+
558+
fdt_create_pcie(fdt, gic_ph, 1,
559+
memmap[BOSTON_PCIE1].base, memmap[BOSTON_PCIE1].size,
560+
memmap[BOSTON_PCIE1_MMIO].base, memmap[BOSTON_PCIE1_MMIO].size);
561+
562+
fdt_create_pcie(fdt, gic_ph, 0,
563+
memmap[BOSTON_PCIE2].base, memmap[BOSTON_PCIE2].size,
564+
memmap[BOSTON_PCIE2_MMIO].base, memmap[BOSTON_PCIE2_MMIO].size);
565+
566+
/* GIC with it's timer node */
567+
gic_name = g_strdup_printf("/soc/interrupt-controller@%" HWADDR_PRIx,
568+
memmap[BOSTON_GIC].base);
569+
qemu_fdt_add_subnode(fdt, gic_name);
570+
qemu_fdt_setprop_string(fdt, gic_name, "compatible", "mti,gic");
571+
qemu_fdt_setprop_cells(fdt, gic_name, "reg", memmap[BOSTON_GIC].base,
572+
memmap[BOSTON_GIC].size);
573+
qemu_fdt_setprop(fdt, gic_name, "interrupt-controller", NULL, 0);
574+
qemu_fdt_setprop_cell(fdt, gic_name, "#interrupt-cells", 3);
575+
qemu_fdt_setprop_cell(fdt, gic_name, "phandle", gic_ph);
576+
577+
name = g_strdup_printf("%s/timer", gic_name);
578+
qemu_fdt_add_subnode(fdt, name);
579+
qemu_fdt_setprop_string(fdt, name, "compatible", "mti,gic-timer");
580+
qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_LOCAL, 1,
581+
FDT_IRQ_TYPE_NONE);
582+
qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_CPU);
583+
g_free(name);
584+
g_free(gic_name);
585+
586+
/* CDMM node */
587+
name = g_strdup_printf("/soc/cdmm@%" HWADDR_PRIx, memmap[BOSTON_CDMM].base);
588+
qemu_fdt_add_subnode(fdt, name);
589+
qemu_fdt_setprop_string(fdt, name, "compatible", "mti,mips-cdmm");
590+
qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_CDMM].base,
591+
memmap[BOSTON_CDMM].size);
592+
g_free(name);
593+
594+
/* CPC node */
595+
name = g_strdup_printf("/soc/cpc@%" HWADDR_PRIx, memmap[BOSTON_CPC].base);
596+
qemu_fdt_add_subnode(fdt, name);
597+
qemu_fdt_setprop_string(fdt, name, "compatible", "mti,mips-cpc");
598+
qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_CPC].base,
599+
memmap[BOSTON_CPC].size);
600+
g_free(name);
601+
602+
/* platreg and it's clk node */
603+
platreg_name = g_strdup_printf("/soc/system-controller@%" HWADDR_PRIx,
604+
memmap[BOSTON_PLATREG].base);
605+
qemu_fdt_add_subnode(fdt, platreg_name);
606+
qemu_fdt_setprop_string_array(fdt, platreg_name, "compatible",
607+
(char **)&syscon_compat,
608+
ARRAY_SIZE(syscon_compat));
609+
qemu_fdt_setprop_cells(fdt, platreg_name, "reg",
610+
memmap[BOSTON_PLATREG].base,
611+
memmap[BOSTON_PLATREG].size);
612+
qemu_fdt_setprop_cell(fdt, platreg_name, "phandle", platreg_ph);
613+
614+
name = g_strdup_printf("%s/clock", platreg_name);
615+
qemu_fdt_add_subnode(fdt, name);
616+
qemu_fdt_setprop_string(fdt, name, "compatible", "img,boston-clock");
617+
qemu_fdt_setprop_cell(fdt, name, "#clock-cells", 1);
618+
qemu_fdt_setprop_cell(fdt, name, "phandle", clk_ph);
619+
g_free(name);
620+
g_free(platreg_name);
621+
622+
/* reboot node */
623+
name = g_strdup_printf("/soc/reboot");
624+
qemu_fdt_add_subnode(fdt, name);
625+
qemu_fdt_setprop_string(fdt, name, "compatible", "syscon-reboot");
626+
qemu_fdt_setprop_cell(fdt, name, "regmap", platreg_ph);
627+
qemu_fdt_setprop_cell(fdt, name, "offset", 0x10);
628+
qemu_fdt_setprop_cell(fdt, name, "mask", 0x10);
629+
g_free(name);
630+
631+
/* uart node */
632+
name = g_strdup_printf("/soc/uart@%" HWADDR_PRIx, memmap[BOSTON_UART].base);
633+
qemu_fdt_add_subnode(fdt, name);
634+
qemu_fdt_setprop_string(fdt, name, "compatible", "ns16550a");
635+
qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_UART].base,
636+
memmap[BOSTON_UART].size);
637+
qemu_fdt_setprop_cell(fdt, name, "reg-shift", 0x2);
638+
qemu_fdt_setprop_cell(fdt, name, "interrupt-parent", gic_ph);
639+
qemu_fdt_setprop_cells(fdt, name, "interrupts", FDT_GIC_SHARED, 3,
640+
FDT_IRQ_TYPE_LEVEL_HIGH);
641+
qemu_fdt_setprop_cells(fdt, name, "clocks", clk_ph, FDT_BOSTON_CLK_SYS);
642+
643+
qemu_fdt_add_subnode(fdt, "/chosen");
644+
stdout_name = g_strdup_printf("%s:115200", name);
645+
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", stdout_name);
646+
g_free(stdout_name);
647+
g_free(name);
648+
649+
/* lcd node */
650+
name = g_strdup_printf("/soc/lcd@%" HWADDR_PRIx, memmap[BOSTON_LCD].base);
651+
qemu_fdt_add_subnode(fdt, name);
652+
qemu_fdt_setprop_string(fdt, name, "compatible", "img,boston-lcd");
653+
qemu_fdt_setprop_cells(fdt, name, "reg", memmap[BOSTON_LCD].base,
654+
memmap[BOSTON_LCD].size);
655+
g_free(name);
656+
657+
name = g_strdup_printf("/memory@0");
658+
qemu_fdt_add_subnode(fdt, name);
659+
qemu_fdt_setprop_string(fdt, name, "device_type", "memory");
660+
g_free(name);
661+
662+
return fdt;
663+
}
664+
440665
static void boston_mach_init(MachineState *machine)
441666
{
442667
DeviceState *dev;
@@ -560,22 +785,24 @@ static void boston_mach_init(MachineState *machine)
560785
NULL, 0, EM_MIPS, 1, 0);
561786

562787
if (kernel_size) {
788+
int dt_size;
789+
g_autofree const void *dtb_file_data, *dtb_load_data;
563790
hwaddr dtb_paddr = QEMU_ALIGN_UP(kernel_high, 64 * KiB);
564791
hwaddr dtb_vaddr = cpu_mips_phys_to_kseg0(NULL, dtb_paddr);
565792

566793
s->kernel_entry = kernel_entry;
567794
if (machine->dtb) {
568-
int dt_size;
569-
g_autofree const void *dtb_file_data, *dtb_load_data;
570-
571795
dtb_file_data = load_device_tree(machine->dtb, &dt_size);
572-
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
573-
NULL, &dtb_vaddr);
574-
575-
/* Calculate real fdt size after filter */
576-
dt_size = fdt_totalsize(dtb_load_data);
577-
rom_add_blob_fixed("dtb", dtb_load_data, dt_size, dtb_paddr);
796+
} else {
797+
dtb_file_data = create_fdt(s, boston_memmap, &dt_size);
578798
}
799+
800+
dtb_load_data = boston_fdt_filter(s, dtb_file_data,
801+
NULL, &dtb_vaddr);
802+
803+
/* Calculate real fdt size after filter */
804+
dt_size = fdt_totalsize(dtb_load_data);
805+
rom_add_blob_fixed("dtb", dtb_load_data, dt_size, dtb_paddr);
579806
} else {
580807
/* Try to load file as FIT */
581808
fit_err = load_fit(&boston_fit_loader, machine->kernel_filename, s);

0 commit comments

Comments
 (0)