static void fdt_add_gem_nodes(VersalVirt *s) { uint64_t addrs[] = { MM_GEM1, MM_GEM0 }; unsigned int irqs[] = { VERSAL_GEM1_IRQ_0, VERSAL_GEM0_IRQ_0 }; const char clocknames[] = "pclk\0hclk\0tx_clk\0rx_clk"; const char compat_gem[] = "cdns,zynqmp-gem\0cdns,gem"; int i; for (i = 0; i < ARRAY_SIZE(addrs); i++) { char *name = g_strdup_printf("/ethernet@%" PRIx64, addrs[i]); qemu_fdt_add_subnode(s->fdt, name); fdt_add_fixed_link_nodes(s, name, s->phandle.ethernet_phy[i]); qemu_fdt_setprop_string(s->fdt, name, "phy-mode", "rgmii-id"); qemu_fdt_setprop_cell(s->fdt, name, "phy-handle", s->phandle.ethernet_phy[i]); qemu_fdt_setprop_cells(s->fdt, name, "clocks", s->phandle.clk_25Mhz, s->phandle.clk_25Mhz, s->phandle.clk_25Mhz, s->phandle.clk_25Mhz); qemu_fdt_setprop(s->fdt, name, "clock-names", clocknames, sizeof(clocknames)); qemu_fdt_setprop_cells(s->fdt, name, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irqs[i], GIC_FDT_IRQ_FLAGS_LEVEL_HI, GIC_FDT_IRQ_TYPE_SPI, irqs[i], GIC_FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, addrs[i], 2, 0x1000); qemu_fdt_setprop(s->fdt, name, "compatible", compat_gem, sizeof(compat_gem)); qemu_fdt_setprop_cell(s->fdt, name, "#address-cells", 1); qemu_fdt_setprop_cell(s->fdt, name, "#size-cells", 0); g_free(name); } }
static int add_virtio_mmio_node(void *fdt, uint32_t acells, uint32_t scells, hwaddr addr, hwaddr size, uint32_t intc, int irq) { /* Add a virtio_mmio node to the device tree blob: * virtio_mmio@ADDRESS { * compatible = "virtio,mmio"; * reg = <ADDRESS, SIZE>; * interrupt-parent = <&intc>; * interrupts = <0, irq, 1>; * } * (Note that the format of the interrupts property is dependent on the * interrupt controller that interrupt-parent points to; these are for * the ARM GIC and indicate an SPI interrupt, rising-edge-triggered.) */ int rc; char *nodename = g_strdup_printf("/virtio_mmio@%" PRIx64, addr); rc = qemu_fdt_add_subnode(fdt, nodename); rc |= qemu_fdt_setprop_string(fdt, nodename, "compatible", "virtio,mmio"); rc |= qemu_fdt_setprop_sized_cells(fdt, nodename, "reg", acells, addr, scells, size); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", intc); qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 0, irq, 1); g_free(nodename); if (rc) { return -1; } return 0; }
static void fdt_add_uart_nodes(VersalVirt *s) { uint64_t addrs[] = { MM_UART1, MM_UART0 }; unsigned int irqs[] = { VERSAL_UART1_IRQ_0, VERSAL_UART0_IRQ_0 }; const char compat[] = "arm,pl011\0arm,sbsa-uart"; const char clocknames[] = "uartclk\0apb_pclk"; int i; for (i = 0; i < ARRAY_SIZE(addrs); i++) { char *name = g_strdup_printf("/uart@%" PRIx64, addrs[i]); qemu_fdt_add_subnode(s->fdt, name); qemu_fdt_setprop_cell(s->fdt, name, "current-speed", 115200); qemu_fdt_setprop_cells(s->fdt, name, "clocks", s->phandle.clk_125Mhz, s->phandle.clk_125Mhz); qemu_fdt_setprop(s->fdt, name, "clock-names", clocknames, sizeof(clocknames)); qemu_fdt_setprop_cells(s->fdt, name, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irqs[i], GIC_FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, addrs[i], 2, 0x1000); qemu_fdt_setprop(s->fdt, name, "compatible", compat, sizeof(compat)); qemu_fdt_setprop(s->fdt, name, "u-boot,dm-pre-reloc", NULL, 0); if (addrs[i] == MM_UART0) { /* Select UART0. */ qemu_fdt_setprop_string(s->fdt, "/chosen", "stdout-path", name); } g_free(name); } }
static void fdt_add_gic_nodes(VersalVirt *s) { char *nodename; nodename = g_strdup_printf("/gic@%x", MM_GIC_APU_DIST_MAIN); qemu_fdt_add_subnode(s->fdt, nodename); qemu_fdt_setprop_cell(s->fdt, nodename, "phandle", s->phandle.gic); qemu_fdt_setprop_cells(s->fdt, nodename, "interrupts", GIC_FDT_IRQ_TYPE_PPI, VERSAL_GIC_MAINT_IRQ, GIC_FDT_IRQ_FLAGS_LEVEL_HI); qemu_fdt_setprop(s->fdt, nodename, "interrupt-controller", NULL, 0); qemu_fdt_setprop_sized_cells(s->fdt, nodename, "reg", 2, MM_GIC_APU_DIST_MAIN, 2, MM_GIC_APU_DIST_MAIN_SIZE, 2, MM_GIC_APU_REDIST_0, 2, MM_GIC_APU_REDIST_0_SIZE); qemu_fdt_setprop_cell(s->fdt, nodename, "#interrupt-cells", 3); qemu_fdt_setprop_string(s->fdt, nodename, "compatible", "arm,gic-v3"); g_free(nodename); }
static const void *boston_fdt_filter(void *opaque, const void *fdt_orig, const void *match_data, hwaddr *load_addr) { BostonState *s = BOSTON(opaque); MachineState *machine = s->mach; const char *cmdline; int err; void *fdt; size_t fdt_sz, ram_low_sz, ram_high_sz; fdt_sz = fdt_totalsize(fdt_orig) * 2; fdt = g_malloc0(fdt_sz); err = fdt_open_into(fdt_orig, fdt, fdt_sz); if (err) { fprintf(stderr, "unable to open FDT\n"); return NULL; } cmdline = (machine->kernel_cmdline && machine->kernel_cmdline[0]) ? machine->kernel_cmdline : " "; err = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); if (err < 0) { fprintf(stderr, "couldn't set /chosen/bootargs\n"); return NULL; } ram_low_sz = MIN(256 * M_BYTE, machine->ram_size); ram_high_sz = machine->ram_size - ram_low_sz; qemu_fdt_setprop_sized_cells(fdt, "/memory@0", "reg", 1, 0x00000000, 1, ram_low_sz, 1, 0x90000000, 1, ram_high_sz); fdt = g_realloc(fdt, fdt_totalsize(fdt)); qemu_fdt_dumpdtb(fdt, fdt_sz); s->fdt_base = *load_addr; return fdt; }
static void create_virtio_regions(VersalVirt *s) { int virtio_mmio_size = 0x200; int i; for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) { char *name = g_strdup_printf("virtio%d", i);; hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size; int irq = VERSAL_RSVD_IRQ_FIRST + i; MemoryRegion *mr; DeviceState *dev; qemu_irq pic_irq; pic_irq = qdev_get_gpio_in(DEVICE(&s->soc.fpd.apu.gic), irq); dev = qdev_create(NULL, "virtio-mmio"); object_property_add_child(OBJECT(&s->soc), name, OBJECT(dev), &error_fatal); qdev_init_nofail(dev); sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, pic_irq); mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); memory_region_add_subregion(&s->soc.mr_ps, base, mr); g_free(name); } for (i = 0; i < NUM_VIRTIO_TRANSPORT; i++) { hwaddr base = MM_TOP_RSVD + i * virtio_mmio_size; int irq = VERSAL_RSVD_IRQ_FIRST + i; char *name = g_strdup_printf("/virtio_mmio@%" PRIx64, base); qemu_fdt_add_subnode(s->fdt, name); qemu_fdt_setprop(s->fdt, name, "dma-coherent", NULL, 0); qemu_fdt_setprop_cells(s->fdt, name, "interrupts", GIC_FDT_IRQ_TYPE_SPI, irq, GIC_FDT_IRQ_FLAGS_EDGE_LO_HI); qemu_fdt_setprop_sized_cells(s->fdt, name, "reg", 2, base, 2, virtio_mmio_size); qemu_fdt_setprop_string(s->fdt, name, "compatible", "virtio,mmio"); g_free(name); } }
static void fdt_add_memory_nodes(VersalVirt *s, void *fdt, uint64_t ram_size) { /* Describes the various split DDR access regions. */ static const struct { uint64_t base; uint64_t size; } addr_ranges[] = { { MM_TOP_DDR, MM_TOP_DDR_SIZE }, { MM_TOP_DDR_2, MM_TOP_DDR_2_SIZE }, { MM_TOP_DDR_3, MM_TOP_DDR_3_SIZE }, { MM_TOP_DDR_4, MM_TOP_DDR_4_SIZE } }; uint64_t mem_reg_prop[8] = {0}; uint64_t size = ram_size; Error *err = NULL; char *name; int i; fdt_nop_memory_nodes(fdt, &err); if (err) { error_report_err(err); return; } name = g_strdup_printf("/memory@%x", MM_TOP_DDR); for (i = 0; i < ARRAY_SIZE(addr_ranges) && size; i++) { uint64_t mapsize; mapsize = size < addr_ranges[i].size ? size : addr_ranges[i].size; mem_reg_prop[i * 2] = addr_ranges[i].base; mem_reg_prop[i * 2 + 1] = mapsize; size -= mapsize; } qemu_fdt_add_subnode(fdt, name); qemu_fdt_setprop_string(fdt, name, "device_type", "memory"); switch (i) { case 1: qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem_reg_prop[0], 2, mem_reg_prop[1]); break; case 2: qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem_reg_prop[0], 2, mem_reg_prop[1], 2, mem_reg_prop[2], 2, mem_reg_prop[3]); break; case 3: qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem_reg_prop[0], 2, mem_reg_prop[1], 2, mem_reg_prop[2], 2, mem_reg_prop[3], 2, mem_reg_prop[4], 2, mem_reg_prop[5]); break; case 4: qemu_fdt_setprop_sized_cells(fdt, name, "reg", 2, mem_reg_prop[0], 2, mem_reg_prop[1], 2, mem_reg_prop[2], 2, mem_reg_prop[3], 2, mem_reg_prop[4], 2, mem_reg_prop[5], 2, mem_reg_prop[6], 2, mem_reg_prop[7]); break; default: g_assert_not_reached(); } g_free(name); }