xref: /freebsd/usr.sbin/bhyve/riscv/fdt.c (revision 7ac65902d8ba0a85e5fe95d097f7fbd52cbda12a)
17ab1a32cSRuslan Bukin /*-
27ab1a32cSRuslan Bukin  * SPDX-License-Identifier: BSD-2-Clause
37ab1a32cSRuslan Bukin  *
47ab1a32cSRuslan Bukin  * Copyright (c) 2022 The FreeBSD Foundation
5*7ac65902SRuslan Bukin  * Copyright (c) 2024-2025 Ruslan Bukin <br@bsdpad.com>
67ab1a32cSRuslan Bukin  *
77ab1a32cSRuslan Bukin  * This software was developed by Andrew Turner under sponsorship from
87ab1a32cSRuslan Bukin  * the FreeBSD Foundation.
97ab1a32cSRuslan Bukin  *
107ab1a32cSRuslan Bukin  * This software was developed by the University of Cambridge Computer
117ab1a32cSRuslan Bukin  * Laboratory (Department of Computer Science and Technology) under Innovate
127ab1a32cSRuslan Bukin  * UK project 105694, "Digital Security by Design (DSbD) Technology Platform
137ab1a32cSRuslan Bukin  * Prototype".
147ab1a32cSRuslan Bukin  *
157ab1a32cSRuslan Bukin  * Redistribution and use in source and binary forms, with or without
167ab1a32cSRuslan Bukin  * modification, are permitted provided that the following conditions
177ab1a32cSRuslan Bukin  * are met:
187ab1a32cSRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
197ab1a32cSRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
207ab1a32cSRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
217ab1a32cSRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
227ab1a32cSRuslan Bukin  *    documentation and/or other materials provided with the distribution.
237ab1a32cSRuslan Bukin  *
247ab1a32cSRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
257ab1a32cSRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
267ab1a32cSRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
277ab1a32cSRuslan Bukin  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
287ab1a32cSRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
297ab1a32cSRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
307ab1a32cSRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
317ab1a32cSRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
327ab1a32cSRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
337ab1a32cSRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347ab1a32cSRuslan Bukin  * SUCH DAMAGE.
357ab1a32cSRuslan Bukin  */
367ab1a32cSRuslan Bukin 
377ab1a32cSRuslan Bukin #include <sys/param.h>
387ab1a32cSRuslan Bukin 
397ab1a32cSRuslan Bukin #include <assert.h>
407ab1a32cSRuslan Bukin #include <errno.h>
417ab1a32cSRuslan Bukin #include <stdio.h>
427ab1a32cSRuslan Bukin #include <unistd.h>
437ab1a32cSRuslan Bukin 
447ab1a32cSRuslan Bukin #include <libfdt.h>
457ab1a32cSRuslan Bukin #include <vmmapi.h>
467ab1a32cSRuslan Bukin 
47*7ac65902SRuslan Bukin #include <machine/intr.h>
48*7ac65902SRuslan Bukin 
497ab1a32cSRuslan Bukin #include "config.h"
507ab1a32cSRuslan Bukin #include "bhyverun.h"
517ab1a32cSRuslan Bukin #include "fdt.h"
527ab1a32cSRuslan Bukin 
537ab1a32cSRuslan Bukin #define	SET_PROP_U32(prop, idx, val)	\
547ab1a32cSRuslan Bukin     ((uint32_t *)(prop))[(idx)] = cpu_to_fdt32(val)
557ab1a32cSRuslan Bukin #define	SET_PROP_U64(prop, idx, val)	\
567ab1a32cSRuslan Bukin     ((uint64_t *)(prop))[(idx)] = cpu_to_fdt64(val)
577ab1a32cSRuslan Bukin 
587ab1a32cSRuslan Bukin #define	IRQ_TYPE_LEVEL_HIGH	4
597ab1a32cSRuslan Bukin #define	IRQ_TYPE_LEVEL_LOW	8
607ab1a32cSRuslan Bukin 
617ab1a32cSRuslan Bukin static void *fdtroot;
627ab1a32cSRuslan Bukin static uint32_t aplic_phandle = 0;
63*7ac65902SRuslan Bukin static uint32_t *intc_phandles = NULL;
647ab1a32cSRuslan Bukin 
657ab1a32cSRuslan Bukin static uint32_t
assign_phandle(void * fdt)667ab1a32cSRuslan Bukin assign_phandle(void *fdt)
677ab1a32cSRuslan Bukin {
687ab1a32cSRuslan Bukin 	static uint32_t next_phandle = 1;
697ab1a32cSRuslan Bukin 	uint32_t phandle;
707ab1a32cSRuslan Bukin 
717ab1a32cSRuslan Bukin 	phandle = next_phandle;
727ab1a32cSRuslan Bukin 	next_phandle++;
737ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "phandle", phandle);
747ab1a32cSRuslan Bukin 
757ab1a32cSRuslan Bukin 	return (phandle);
767ab1a32cSRuslan Bukin }
777ab1a32cSRuslan Bukin 
787ab1a32cSRuslan Bukin static void
set_single_reg(void * fdt,uint64_t start,uint64_t len)797ab1a32cSRuslan Bukin set_single_reg(void *fdt, uint64_t start, uint64_t len)
807ab1a32cSRuslan Bukin {
817ab1a32cSRuslan Bukin 	void *reg;
827ab1a32cSRuslan Bukin 
837ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), &reg);
847ab1a32cSRuslan Bukin 	SET_PROP_U64(reg, 0, start);
857ab1a32cSRuslan Bukin 	SET_PROP_U64(reg, 1, len);
867ab1a32cSRuslan Bukin }
877ab1a32cSRuslan Bukin 
887ab1a32cSRuslan Bukin static void
add_cpu(void * fdt,int cpuid,const char * isa,uint32_t * intc_phandle)89*7ac65902SRuslan Bukin add_cpu(void *fdt, int cpuid, const char *isa, uint32_t *intc_phandle)
907ab1a32cSRuslan Bukin {
917ab1a32cSRuslan Bukin 	char node_name[16];
927ab1a32cSRuslan Bukin 
937ab1a32cSRuslan Bukin 	snprintf(node_name, sizeof(node_name), "cpu@%d", cpuid);
947ab1a32cSRuslan Bukin 
957ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, node_name);
967ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "device_type", "cpu");
977ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "riscv");
987ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "reg", cpuid);
99a7bf553dSRuslan Bukin 	fdt_property_string(fdt, "riscv,isa", isa);
1007ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "mmu-type", "riscv,sv39");
1017ab1a32cSRuslan Bukin 
1027ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "interrupt-controller");
103*7ac65902SRuslan Bukin 	*intc_phandle = assign_phandle(fdt);
1047ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#address-cells", 2);
1057ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#interrupt-cells", 1);
1067ab1a32cSRuslan Bukin 	fdt_property(fdt, "interrupt-controller", NULL, 0);
1077ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "riscv,cpu-intc");
1087ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
1097ab1a32cSRuslan Bukin 
1107ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
1117ab1a32cSRuslan Bukin }
1127ab1a32cSRuslan Bukin 
1137ab1a32cSRuslan Bukin static void
add_cpus(void * fdt,int ncpu,const char * isa)114a7bf553dSRuslan Bukin add_cpus(void *fdt, int ncpu, const char *isa)
1157ab1a32cSRuslan Bukin {
1167ab1a32cSRuslan Bukin 	int cpuid;
1177ab1a32cSRuslan Bukin 
1187ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "cpus");
1197ab1a32cSRuslan Bukin 	/* XXX: Needed given the root #address-cells? */
1207ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#address-cells", 1);
1217ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#size-cells", 0);
1229be0058eSRuslan Bukin 	/* TODO: take timebase from kernel? */
1239be0058eSRuslan Bukin 	fdt_property_u32(fdt, "timebase-frequency", 1000000);
1247ab1a32cSRuslan Bukin 
125*7ac65902SRuslan Bukin 	intc_phandles = malloc(sizeof(uint32_t) * ncpu);
126a7bf553dSRuslan Bukin 	for (cpuid = 0; cpuid < ncpu; cpuid++)
127*7ac65902SRuslan Bukin 		add_cpu(fdt, cpuid, isa, &intc_phandles[cpuid]);
128a7bf553dSRuslan Bukin 
1297ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
1307ab1a32cSRuslan Bukin }
1317ab1a32cSRuslan Bukin 
1327ab1a32cSRuslan Bukin int
fdt_init(struct vmctx * ctx,int ncpu,vm_paddr_t fdtaddr,vm_size_t fdtsize,const char * isa)133a7bf553dSRuslan Bukin fdt_init(struct vmctx *ctx, int ncpu, vm_paddr_t fdtaddr, vm_size_t fdtsize,
134a7bf553dSRuslan Bukin     const char *isa)
1357ab1a32cSRuslan Bukin {
1367ab1a32cSRuslan Bukin 	void *fdt;
1377ab1a32cSRuslan Bukin 	const char *bootargs;
1387ab1a32cSRuslan Bukin 
1397ab1a32cSRuslan Bukin 	fdt = paddr_guest2host(ctx, fdtaddr, fdtsize);
1407ab1a32cSRuslan Bukin 	if (fdt == NULL)
1417ab1a32cSRuslan Bukin 		return (EFAULT);
1427ab1a32cSRuslan Bukin 
1437ab1a32cSRuslan Bukin 	fdt_create(fdt, (int)fdtsize);
1447ab1a32cSRuslan Bukin 
1457ab1a32cSRuslan Bukin 	/* Add the memory reserve map (needed even if none is reserved) */
1467ab1a32cSRuslan Bukin 	fdt_finish_reservemap(fdt);
1477ab1a32cSRuslan Bukin 
1487ab1a32cSRuslan Bukin 	/* Create the root node */
1497ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "");
1507ab1a32cSRuslan Bukin 
1517ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "freebsd,bhyve");
1527ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#address-cells", 2);
1537ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#size-cells", 2);
1547ab1a32cSRuslan Bukin 
1557ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "chosen");
1567ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "stdout-path", "serial0:115200n8");
1577ab1a32cSRuslan Bukin 	bootargs = get_config_value("fdt.bootargs");
1587ab1a32cSRuslan Bukin 	if (bootargs != NULL)
1597ab1a32cSRuslan Bukin 		fdt_property_string(fdt, "bootargs", bootargs);
1607ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
1617ab1a32cSRuslan Bukin 
1627ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "memory");
1637ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "device_type", "memory");
1647ab1a32cSRuslan Bukin 	/* There is no lowmem on riscv. */
1657ab1a32cSRuslan Bukin 	assert(vm_get_lowmem_size(ctx) == 0);
1667ab1a32cSRuslan Bukin 	set_single_reg(fdt, vm_get_highmem_base(ctx), vm_get_highmem_size(ctx));
1677ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
1687ab1a32cSRuslan Bukin 
169a7bf553dSRuslan Bukin 	add_cpus(fdt, ncpu, isa);
1707ab1a32cSRuslan Bukin 
1717ab1a32cSRuslan Bukin 	/* Finalized by fdt_finalized(). */
1727ab1a32cSRuslan Bukin 	fdtroot = fdt;
1737ab1a32cSRuslan Bukin 
1747ab1a32cSRuslan Bukin 	return (0);
1757ab1a32cSRuslan Bukin }
1767ab1a32cSRuslan Bukin 
1777ab1a32cSRuslan Bukin void
fdt_add_aplic(uint64_t mem_base,uint64_t mem_size,int ncpu)178*7ac65902SRuslan Bukin fdt_add_aplic(uint64_t mem_base, uint64_t mem_size, int ncpu)
1797ab1a32cSRuslan Bukin {
1807ab1a32cSRuslan Bukin 	char node_name[32];
1817ab1a32cSRuslan Bukin 	void *fdt, *prop;
182*7ac65902SRuslan Bukin 	int i;
1837ab1a32cSRuslan Bukin 
1847ab1a32cSRuslan Bukin 	fdt = fdtroot;
1857ab1a32cSRuslan Bukin 
1867ab1a32cSRuslan Bukin 	snprintf(node_name, sizeof(node_name), "interrupt-controller@%lx",
1877ab1a32cSRuslan Bukin 	    (unsigned long)mem_base);
1887ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, node_name);
1897ab1a32cSRuslan Bukin 
1907ab1a32cSRuslan Bukin 	aplic_phandle = assign_phandle(fdt);
1917ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "riscv,aplic");
1927ab1a32cSRuslan Bukin 	fdt_property(fdt, "interrupt-controller", NULL, 0);
1937ab1a32cSRuslan Bukin #if notyet
1947ab1a32cSRuslan Bukin 	fdt_property(fdt, "msi-controller", NULL, 0);
1957ab1a32cSRuslan Bukin #endif
1967ab1a32cSRuslan Bukin 	/* XXX: Needed given the root #address-cells? */
1977ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#address-cells", 2);
1987ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#interrupt-cells", 2);
1997ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "reg", 2 * sizeof(uint64_t), &prop);
2007ab1a32cSRuslan Bukin 	SET_PROP_U64(prop, 0, mem_base);
2017ab1a32cSRuslan Bukin 	SET_PROP_U64(prop, 1, mem_size);
2027ab1a32cSRuslan Bukin 
203*7ac65902SRuslan Bukin 	assert(intc_phandles != NULL);
2047ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "interrupts-extended",
205*7ac65902SRuslan Bukin 	    2 * ncpu * sizeof(uint32_t), &prop);
206*7ac65902SRuslan Bukin 	for (i = 0; i < ncpu; i++) {
207*7ac65902SRuslan Bukin 		SET_PROP_U32(prop, i * 2 + 0, intc_phandles[i]);
208*7ac65902SRuslan Bukin 		SET_PROP_U32(prop, i * 2 + 1, IRQ_EXTERNAL_SUPERVISOR);
209*7ac65902SRuslan Bukin 	}
2107ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "riscv,num-sources", 63);
2117ab1a32cSRuslan Bukin 
2127ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
2137ab1a32cSRuslan Bukin 
2147ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
2157ab1a32cSRuslan Bukin }
2167ab1a32cSRuslan Bukin 
2177ab1a32cSRuslan Bukin void
fdt_add_uart(uint64_t uart_base,uint64_t uart_size,int intr)2187ab1a32cSRuslan Bukin fdt_add_uart(uint64_t uart_base, uint64_t uart_size, int intr)
2197ab1a32cSRuslan Bukin {
2207ab1a32cSRuslan Bukin 	void *fdt, *interrupts;
2217ab1a32cSRuslan Bukin 	char node_name[32];
2227ab1a32cSRuslan Bukin 
2237ab1a32cSRuslan Bukin 	assert(aplic_phandle != 0);
2247ab1a32cSRuslan Bukin 
2257ab1a32cSRuslan Bukin 	fdt = fdtroot;
2267ab1a32cSRuslan Bukin 
2277ab1a32cSRuslan Bukin 	snprintf(node_name, sizeof(node_name), "serial@%lx", uart_base);
2287ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, node_name);
2297ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "ns16550");
2307ab1a32cSRuslan Bukin 	set_single_reg(fdt, uart_base, uart_size);
23195b8b67fSRuslan Bukin 	fdt_property_u32(fdt, "clock-frequency", 3686400);
2327ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
2337ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "interrupts", 2 * sizeof(uint32_t),
2347ab1a32cSRuslan Bukin 	    &interrupts);
2357ab1a32cSRuslan Bukin 	SET_PROP_U32(interrupts, 0, intr);
2367ab1a32cSRuslan Bukin 	SET_PROP_U32(interrupts, 1, IRQ_TYPE_LEVEL_HIGH);
2377ab1a32cSRuslan Bukin 
2387ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
2397ab1a32cSRuslan Bukin 
2407ab1a32cSRuslan Bukin 	snprintf(node_name, sizeof(node_name), "/serial@%lx", uart_base);
2417ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "aliases");
2427ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "serial0", node_name);
2437ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
2447ab1a32cSRuslan Bukin }
2457ab1a32cSRuslan Bukin 
2467ab1a32cSRuslan Bukin void
fdt_add_pcie(int intrs[static4])2477ab1a32cSRuslan Bukin fdt_add_pcie(int intrs[static 4])
2487ab1a32cSRuslan Bukin {
2497ab1a32cSRuslan Bukin 	void *fdt, *prop;
2507ab1a32cSRuslan Bukin 	int slot, pin, intr, i;
2517ab1a32cSRuslan Bukin 
2527ab1a32cSRuslan Bukin 	assert(aplic_phandle != 0);
2537ab1a32cSRuslan Bukin 
2547ab1a32cSRuslan Bukin 	fdt = fdtroot;
2557ab1a32cSRuslan Bukin 
2567ab1a32cSRuslan Bukin 	fdt_begin_node(fdt, "pcie@1f0000000");
2577ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "compatible", "pci-host-ecam-generic");
2587ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#address-cells", 3);
2597ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#size-cells", 2);
2607ab1a32cSRuslan Bukin 	fdt_property_string(fdt, "device_type", "pci");
2617ab1a32cSRuslan Bukin 	fdt_property_u64(fdt, "bus-range", (0ul << 32) | 1);
2627ab1a32cSRuslan Bukin 	set_single_reg(fdt, 0xe0000000, 0x10000000);
2637ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "ranges",
2647ab1a32cSRuslan Bukin 	    2 * 7 * sizeof(uint32_t), &prop);
2657ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 0, 0x01000000);
2667ab1a32cSRuslan Bukin 
2677ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 1, 0);
2687ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 2, 0xdf000000);
2697ab1a32cSRuslan Bukin 
2707ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 3, 0);
2717ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 4, 0xdf000000);
2727ab1a32cSRuslan Bukin 
2737ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 5, 0);
2747ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 6, 0x01000000);
2757ab1a32cSRuslan Bukin 
2767ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 7, 0x02000000);
2777ab1a32cSRuslan Bukin 
2787ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 8, 0);
2797ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 9, 0xa0000000);
2807ab1a32cSRuslan Bukin 
2817ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 10, 0);
2827ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 11, 0xa0000000);
2837ab1a32cSRuslan Bukin 
2847ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 12, 0);
2857ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 13, 0x3f000000);
2867ab1a32cSRuslan Bukin 
2877ab1a32cSRuslan Bukin #if notyet
2887ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "msi-map", 4 * sizeof(uint32_t), &prop);
2897ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 0, 0);		/* RID base */
2907ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 1, aplic_phandle);	/* MSI parent */
2917ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 2, 0);		/* MSI base */
2927ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 3, 0x10000);		/* RID length */
2937ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "msi-parent", aplic_phandle);
2947ab1a32cSRuslan Bukin #endif
2957ab1a32cSRuslan Bukin 
2967ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "#interrupt-cells", 1);
2977ab1a32cSRuslan Bukin 	fdt_property_u32(fdt, "interrupt-parent", aplic_phandle);
2987ab1a32cSRuslan Bukin 
2997ab1a32cSRuslan Bukin 	/*
3007ab1a32cSRuslan Bukin 	 * Describe standard swizzled interrupts routing (pins rotated by one
3017ab1a32cSRuslan Bukin 	 * for each consecutive slot). Must match pci_irq_route().
3027ab1a32cSRuslan Bukin 	 */
3037ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "interrupt-map-mask",
3047ab1a32cSRuslan Bukin 	    4 * sizeof(uint32_t), &prop);
3057ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 0, 3 << 11);
3067ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 1, 0);
3077ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 2, 0);
3087ab1a32cSRuslan Bukin 	SET_PROP_U32(prop, 3, 7);
3097ab1a32cSRuslan Bukin 	fdt_property_placeholder(fdt, "interrupt-map",
3107ab1a32cSRuslan Bukin 	    16 * 9 * sizeof(uint32_t), &prop);
3117ab1a32cSRuslan Bukin 	for (i = 0; i < 16; ++i) {
3127ab1a32cSRuslan Bukin 		pin = i % 4;
3137ab1a32cSRuslan Bukin 		slot = i / 4;
3147ab1a32cSRuslan Bukin 		intr = intrs[(pin + slot) % 4];
3157ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 0, slot << 11);
3167ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 1, 0);
3177ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 2, 0);
3187ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 3, pin + 1);
3197ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 4, aplic_phandle);
3207ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 5, 0);
3217ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 6, 0);
3227ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 7, intr);
3237ab1a32cSRuslan Bukin 		SET_PROP_U32(prop, 10 * i + 8, IRQ_TYPE_LEVEL_HIGH);
3247ab1a32cSRuslan Bukin 	}
3257ab1a32cSRuslan Bukin 
3267ab1a32cSRuslan Bukin 	fdt_end_node(fdt);
3277ab1a32cSRuslan Bukin }
3287ab1a32cSRuslan Bukin 
3297ab1a32cSRuslan Bukin void
fdt_finalize(void)3307ab1a32cSRuslan Bukin fdt_finalize(void)
3317ab1a32cSRuslan Bukin {
3327ab1a32cSRuslan Bukin 	fdt_end_node(fdtroot);
3337ab1a32cSRuslan Bukin 
3347ab1a32cSRuslan Bukin 	fdt_finish(fdtroot);
335*7ac65902SRuslan Bukin 
336*7ac65902SRuslan Bukin 	free(intc_phandles);
3377ab1a32cSRuslan Bukin }
338