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, uint32 addressCells, uint32 sizeCells) 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, addressCells, sizeCells, 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, addressCells, sizeCells, 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