xref: /haiku/src/system/boot/platform/riscv/fdt.cpp (revision 715304011f420ba48e838a47a1b5151ab708f4eb)
1a182bd6eSX512 /*
2a182bd6eSX512  * Copyright 2021, Haiku, Inc.
3a182bd6eSX512  * Distributed under the terms of the MIT License.
4a182bd6eSX512  */
5a182bd6eSX512 
6a182bd6eSX512 
7a182bd6eSX512 #include "fdt.h"
8a182bd6eSX512 #include <SupportDefs.h>
9a182bd6eSX512 #include <ByteOrder.h>
10a182bd6eSX512 #include <KernelExport.h>
11a182bd6eSX512 #include <boot/stage2.h>
12*71530401SX512 #include <arch/generic/debug_uart_8250.h>
13*71530401SX512 #include <arch/riscv64/arch_uart_sifive.h>
14a182bd6eSX512 
15a182bd6eSX512 extern "C" {
16a182bd6eSX512 #include <libfdt.h>
17a182bd6eSX512 }
18a182bd6eSX512 
19a182bd6eSX512 #include "mmu.h"
20a182bd6eSX512 #include "graphics.h"
21a182bd6eSX512 #include "virtio.h"
22*71530401SX512 #include "Htif.h"
23*71530401SX512 #include "Clint.h"
24*71530401SX512 #include "FwCfg.h"
25a182bd6eSX512 
26a182bd6eSX512 
27a182bd6eSX512 void* gFdt = NULL;
28*71530401SX512 ClintRegs *volatile gClintRegs = NULL;
29*71530401SX512 
30*71530401SX512 static uint64 sTimerFrequrency = 10000000;
31*71530401SX512 
32*71530401SX512 static addr_range sPlic = {0};
33*71530401SX512 static addr_range sClint = {0};
34*71530401SX512 static uart_info sUart{};
35*71530401SX512 
36*71530401SX512 
37*71530401SX512 static bool
38*71530401SX512 HasFdtString(const char* prop, int size, const char* pattern)
39*71530401SX512 {
40*71530401SX512 	int patternLen = strlen(pattern);
41*71530401SX512 	const char* propEnd = prop + size;
42*71530401SX512 	while (propEnd - prop > 0) {
43*71530401SX512 		int curLen = strlen(prop);
44*71530401SX512 		if (curLen == patternLen && memcmp(prop, pattern, curLen + 1) == 0)
45*71530401SX512 			return true;
46*71530401SX512 		prop += curLen + 1;
47*71530401SX512 	}
48*71530401SX512 	return false;
49*71530401SX512 }
50*71530401SX512 
51*71530401SX512 
52*71530401SX512 static uint32
53*71530401SX512 GetInterrupt(const void* fdt, int node)
54*71530401SX512 {
55*71530401SX512 	if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", NULL)) {
56*71530401SX512 		return fdt32_to_cpu(*(prop + 1));
57*71530401SX512 	}
58*71530401SX512 	if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts", NULL)) {
59*71530401SX512 		return fdt32_to_cpu(*prop);
60*71530401SX512 	}
61*71530401SX512 	dprintf("[!] no interrupt field\n");
62*71530401SX512 	return 0;
63*71530401SX512 }
64a182bd6eSX512 
65a182bd6eSX512 
66a182bd6eSX512 static void
67*71530401SX512 HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells,
68*71530401SX512 	uint32 interruptCells /* from parent node */)
69a182bd6eSX512 {
70a182bd6eSX512 	// TODO: handle different field sizes
71a182bd6eSX512 
72*71530401SX512 	const char* name = fdt_get_name(fdt, node, NULL);
73*71530401SX512 	if (strcmp(name, "cpus") == 0) {
74*71530401SX512 		if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL))
75*71530401SX512 			sTimerFrequrency = fdt32_to_cpu(*prop);
76*71530401SX512 	}
77*71530401SX512 
78a182bd6eSX512 	const char* device_type = (const char*)fdt_getprop(fdt, node,
79a182bd6eSX512 		"device_type", NULL);
80a182bd6eSX512 	if (device_type != NULL && strcmp(device_type, "memory") == 0) {
81*71530401SX512 		gMemBase = (uint8*)fdt64_to_cpu(*((uint64*)fdt_getprop(fdt, node,
82a182bd6eSX512 			"reg", NULL) + 0));
83*71530401SX512 		gTotalMem = fdt64_to_cpu(*((uint64*)fdt_getprop(fdt, node,
84a182bd6eSX512 			"reg", NULL) + 1));
85a182bd6eSX512 		return;
86a182bd6eSX512 	}
87*71530401SX512 	int compatibleLen;
88a182bd6eSX512 	const char* compatible = (const char*)fdt_getprop(fdt, node,
89*71530401SX512 		"compatible", &compatibleLen);
90a182bd6eSX512 	if (compatible == NULL) return;
91*71530401SX512 	if (HasFdtString(compatible, compatibleLen, "riscv,clint0")) {
92*71530401SX512 		uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL);
93*71530401SX512 		sClint.start = fdt64_to_cpu(*(reg + 0));
94*71530401SX512 		sClint.size  = fdt64_to_cpu(*(reg + 1));
95*71530401SX512 		gClintRegs = (ClintRegs*)sClint.start;
96*71530401SX512 	} else if (HasFdtString(compatible, compatibleLen, "riscv,plic0")) {
97*71530401SX512 		uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL);
98*71530401SX512 		sPlic.start = fdt64_to_cpu(*(reg + 0));
99*71530401SX512 		sPlic.size  = fdt64_to_cpu(*(reg + 1));
100*71530401SX512 	} else if (HasFdtString(compatible, compatibleLen, "virtio,mmio")) {
101*71530401SX512 		uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL);
102a182bd6eSX512 		virtio_register(
103*71530401SX512 			fdt64_to_cpu(*(reg + 0)), fdt64_to_cpu(*(reg + 1)),
104*71530401SX512 			GetInterrupt(fdt, node));
105*71530401SX512 	} else if (
106*71530401SX512 		strcmp(sUart.kind, "") == 0 && (
107*71530401SX512 			HasFdtString(compatible, compatibleLen, "ns16550a") ||
108*71530401SX512 			HasFdtString(compatible, compatibleLen, "sifive,uart0"))
109*71530401SX512 	) {
110*71530401SX512 		if (HasFdtString(compatible, compatibleLen, "ns16550a"))
111*71530401SX512 			strcpy(sUart.kind, UART_KIND_8250);
112*71530401SX512 		else if (HasFdtString(compatible, compatibleLen, "sifive,uart0"))
113*71530401SX512 			strcpy(sUart.kind, UART_KIND_SIFIVE);
114*71530401SX512 
115*71530401SX512 		uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL);
116*71530401SX512 		sUart.regs.start = fdt64_to_cpu(*(reg + 0));
117*71530401SX512 		sUart.regs.size  = fdt64_to_cpu(*(reg + 1));
118*71530401SX512 		sUart.irq = GetInterrupt(fdt, node);
119*71530401SX512 		const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL);
120*71530401SX512 		sUart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop);
121*71530401SX512 	} else if (HasFdtString(compatible, compatibleLen, "qemu,fw-cfg-mmio")) {
122*71530401SX512 		gFwCfgRegs = (FwCfgRegs *volatile)
123*71530401SX512 			fdt64_to_cpu(*(uint64*)fdt_getprop(fdt, node, "reg", NULL));
124*71530401SX512 	} else if (HasFdtString(compatible, compatibleLen, "simple-framebuffer")) {
125*71530401SX512 		gFramebuf.colors = (uint32*)fdt64_to_cpu(
126*71530401SX512 			*(uint64*)fdt_getprop(fdt, node, "reg", NULL));
127a182bd6eSX512 		gFramebuf.stride = fdt32_to_cpu(
128*71530401SX512 			*(uint32*)fdt_getprop(fdt, node, "stride", NULL)) / 4;
129a182bd6eSX512 		gFramebuf.width = fdt32_to_cpu(
130*71530401SX512 			*(uint32*)fdt_getprop(fdt, node, "width", NULL));
131a182bd6eSX512 		gFramebuf.height = fdt32_to_cpu(
132*71530401SX512 			*(uint32*)fdt_getprop(fdt, node, "height", NULL));
133a182bd6eSX512 	}
134a182bd6eSX512 }
135a182bd6eSX512 
136a182bd6eSX512 
137a182bd6eSX512 void
138a182bd6eSX512 fdt_init(void* fdt)
139a182bd6eSX512 {
140a182bd6eSX512 	dprintf("FDT: %p\n", fdt);
141a182bd6eSX512 	gFdt = fdt;
142a182bd6eSX512 
143a182bd6eSX512 	int res = fdt_check_header(gFdt);
144a182bd6eSX512 	if (res != 0) {
145a182bd6eSX512 		panic("Invalid FDT: %s\n", fdt_strerror(res));
146a182bd6eSX512 	}
147a182bd6eSX512 
148a182bd6eSX512 	dprintf("FDT valid, size: %" B_PRIu32 "\n", fdt_totalsize(gFdt));
149a182bd6eSX512 
150a182bd6eSX512 	int node = -1;
151*71530401SX512 	int depth = -1;
152*71530401SX512 	while ((node = fdt_next_node(gFdt, node, &depth)) >= 0 && depth >= 0) {
153*71530401SX512 		HandleFdt(gFdt, node, 2, 2, 1);
154a182bd6eSX512 	}
155a182bd6eSX512 }
156a182bd6eSX512 
157a182bd6eSX512 
158a182bd6eSX512 void
159a182bd6eSX512 fdt_set_kernel_args()
160a182bd6eSX512 {
161c9d6d52bSAlexander von Gluck IV 	uint32_t fdtSize = fdt_totalsize(gFdt);
162c9d6d52bSAlexander von Gluck IV 
1634b5c7fe7SAlexander von Gluck IV 	// libfdt requires 8-byte alignment
1644b5c7fe7SAlexander von Gluck IV 	gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(fdtSize, 8);
165c9d6d52bSAlexander von Gluck IV 
166*71530401SX512 	if (gKernelArgs.arch_args.fdt != NULL)
167*71530401SX512 		memcpy(gKernelArgs.arch_args.fdt, gFdt, fdt_totalsize(gFdt));
168*71530401SX512 	else
169a182bd6eSX512 		panic("unable to malloc for FDT!\n");
170c9d6d52bSAlexander von Gluck IV 
171*71530401SX512 	gKernelArgs.arch_args.timerFrequency = sTimerFrequrency;
172*71530401SX512 
173*71530401SX512 	gKernelArgs.arch_args.htif.start = (addr_t)gHtifRegs;
174*71530401SX512 	gKernelArgs.arch_args.htif.size = sizeof(HtifRegs);
175*71530401SX512 
176*71530401SX512 	gKernelArgs.arch_args.plic  = sPlic;
177*71530401SX512 	gKernelArgs.arch_args.clint = sClint;
178*71530401SX512 	gKernelArgs.arch_args.uart  = sUart;
179a182bd6eSX512 }
180