xref: /haiku/src/system/boot/platform/efi/arch/riscv64/arch_dtb.cpp (revision 52f7c9389475e19fc21487b38064b4390eeb6fea)
1 /*
2  * Copyright 2019-2021 Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *   Alexander von Gluck IV <kallisti5@unixzen.com>
7  */
8 
9 #include <arch_cpu_defs.h>
10 #include <arch_dtb.h>
11 #include <arch_smp.h>
12 #include <boot/platform.h>
13 #include <boot/stage2.h>
14 
15 extern "C" {
16 #include <libfdt.h>
17 }
18 
19 #include "dtb.h"
20 
21 
22 uint32 gBootHart = 0;
23 static uint64 sTimerFrequency = 10000000;
24 
25 static addr_range sPlic = {0};
26 static addr_range sClint = {0};
27 
28 
29 void
30 arch_handle_fdt(const void* fdt, int node)
31 {
32 	const char* deviceType = (const char*)fdt_getprop(fdt, node,
33 		"device_type", NULL);
34 
35 	const char* name = fdt_get_name(fdt, node, NULL);
36 	if (strcmp(name, "chosen") == 0) {
37 		if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "boot-hartid", NULL))
38 			gBootHart = fdt32_to_cpu(*prop);
39 	} else if (strcmp(name, "cpus") == 0) {
40 		if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL))
41 			sTimerFrequency = fdt32_to_cpu(*prop);
42 	}
43 
44 	if (deviceType != NULL) {
45 		if (strcmp(deviceType, "cpu") == 0) {
46 			// TODO: improve incompatible CPU detection
47 			if (!(fdt_getprop(fdt, node, "mmu-type", NULL) != NULL))
48 				return;
49 
50 			platform_cpu_info* info;
51 			arch_smp_register_cpu(&info);
52 			if (info == NULL)
53 				return;
54 			info->id = fdt32_to_cpu(*(uint32*)fdt_getprop(fdt, node,
55 				"reg", NULL));
56 			dprintf("cpu\n");
57 			dprintf("  id: %" B_PRIu32 "\n", info->id);
58 
59 			int subNode = fdt_subnode_offset(fdt, node, "interrupt-controller");
60 			if (subNode < 0) {
61 				dprintf("  [!] no interrupt controller\n");
62 			} else {
63 				info->phandle = fdt_get_phandle(fdt, subNode);
64 				dprintf("  phandle: %" B_PRIu32 "\n", info->phandle);
65 			}
66 		}
67 	}
68 	int compatibleLen;
69 	const char* compatible = (const char*)fdt_getprop(fdt, node,
70 		"compatible", &compatibleLen);
71 
72 	if (compatible == NULL)
73 		return;
74 
75 	if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,clint0")) {
76 		dtb_get_reg(fdt, node, 0, sClint);
77 		return;
78 	}
79 
80 	if (dtb_has_fdt_string(compatible, compatibleLen, "riscv,plic0")
81 		|| dtb_has_fdt_string(compatible, compatibleLen, "sifive,plic-1.0.0")) {
82 		dtb_get_reg(fdt, node, 0, sPlic);
83 		int propSize;
84 		if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) {
85 			dprintf("PLIC contexts\n");
86 			uint32 contextId = 0;
87 			for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) {
88 				uint32 phandle = fdt32_to_cpu(*it);
89 				uint32 interrupt = fdt32_to_cpu(*(it + 1));
90 				if (interrupt == sExternInt) {
91 					platform_cpu_info* cpuInfo = arch_smp_find_cpu(phandle);
92 					dprintf("  context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle);
93 					if (cpuInfo != NULL) {
94 						cpuInfo->plicContext = contextId;
95 						dprintf("    cpu id: %" B_PRIu32 "\n", cpuInfo->id);
96 					}
97 				}
98 				contextId++;
99 			}
100 		}
101 		return;
102 	}
103 }
104 
105 
106 void
107 arch_dtb_set_kernel_args(void)
108 {
109 	dprintf("bootHart: %" B_PRIu32 "\n", gBootHart);
110 	dprintf("timerFrequency: %" B_PRIu64 "\n", sTimerFrequency);
111 	gKernelArgs.arch_args.timerFrequency = sTimerFrequency;
112 
113 //	gKernelArgs.arch_args.htif  = {.start = 0x40008000, .size = 0x10};
114 	gKernelArgs.arch_args.htif  = {.start = 0, .size = 0};
115 	gKernelArgs.arch_args.plic  = sPlic;
116 	gKernelArgs.arch_args.clint = sClint;
117 }
118