xref: /haiku/src/system/boot/platform/riscv/fdt.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
1 /*
2  * Copyright 2021, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "fdt.h"
8 #include <SupportDefs.h>
9 #include <ByteOrder.h>
10 #include <KernelExport.h>
11 #include <boot/stage2.h>
12 
13 extern "C" {
14 #include <libfdt.h>
15 }
16 
17 #include "mmu.h"
18 #include "graphics.h"
19 #include "virtio.h"
20 
21 
22 void* gFdt = NULL;
23 
24 
25 static void
26 HandleFdt(const void* fdt, int node, uint32_t addressCells, uint32_t sizeCells,
27 	uint32_t interruptCells /* from parent node */)
28 {
29 	// TODO: handle different field sizes
30 
31 	const char* device_type = (const char*)fdt_getprop(fdt, node,
32 		"device_type", NULL);
33 	if (device_type != NULL && strcmp(device_type, "memory") == 0) {
34 		gMemBase = (uint8*)fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node,
35 			"reg", NULL) + 0));
36 		gTotalMem = fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node,
37 			"reg", NULL) + 1));
38 		return;
39 	}
40 	const char* compatible = (const char*)fdt_getprop(fdt, node,
41 		"compatible", NULL);
42 	if (compatible == NULL) return;
43 	if (strcmp(compatible, "virtio,mmio") == 0) {
44 		virtio_register(
45 			fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, "reg", NULL) + 0)),
46 			fdt64_to_cpu(*((uint64_t*)fdt_getprop(fdt, node, "reg", NULL) + 1)),
47 			fdt32_to_cpu(*((uint32_t*)fdt_getprop(fdt, node,
48 				"interrupts-extended", NULL) + 1))
49 		);
50 	} else if (strcmp(compatible, "simple-framebuffer") == 0) {
51 		gFramebuf.colors = (uint32_t*)fdt64_to_cpu(
52 			*(uint64_t*)fdt_getprop(fdt, node, "reg", NULL));
53 		gFramebuf.stride = fdt32_to_cpu(
54 			*(uint32_t*)fdt_getprop(fdt, node, "stride", NULL)) / 4;
55 		gFramebuf.width = fdt32_to_cpu(
56 			*(uint32_t*)fdt_getprop(fdt, node, "width", NULL));
57 		gFramebuf.height = fdt32_to_cpu(
58 			*(uint32_t*)fdt_getprop(fdt, node, "height", NULL));
59 	}
60 }
61 
62 
63 void
64 fdt_init(void* fdt)
65 {
66 	dprintf("FDT: %p\n", fdt);
67 	gFdt = fdt;
68 
69 	int res = fdt_check_header(gFdt);
70 	if (res != 0) {
71 		panic("Invalid FDT: %s\n", fdt_strerror(res));
72 	}
73 
74 	dprintf("FDT valid, size: %" B_PRIu32 "\n", fdt_totalsize(gFdt));
75 
76 	int node = -1;
77 	int depth = 0;
78 	while ((node = fdt_next_node(gFdt, node, &depth)) >= 0) {
79 		HandleFdt(gFdt, node, 2, 2, 2);
80 	}
81 }
82 
83 
84 void
85 fdt_set_kernel_args()
86 {
87 	uint32_t fdtSize = fdt_totalsize(gFdt);
88 
89 	// libfdt requires 8-byte alignment
90 	gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(fdtSize, 8);
91 
92 	if (gKernelArgs.arch_args.fdt != NULL) {
93 		memcpy(gKernelArgs.arch_args.fdt, gFdt, fdtSize);
94 	} else
95 		panic("unable to malloc for FDT!\n");
96 
97 	dprintf("FDT getting passed to kernel @ %p\n", (void*)gKernelArgs.arch_args.fdt.Pointer());
98 }
99