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> 1271530401SX512 #include <arch/generic/debug_uart_8250.h> 1371530401SX512 #include <arch/riscv64/arch_uart_sifive.h> 14*0d9b77a3SX512 #include <arch_cpu_defs.h> 15a182bd6eSX512 16a182bd6eSX512 extern "C" { 17a182bd6eSX512 #include <libfdt.h> 18a182bd6eSX512 } 19a182bd6eSX512 20a182bd6eSX512 #include "mmu.h" 21*0d9b77a3SX512 #include "smp.h" 22a182bd6eSX512 #include "graphics.h" 23a182bd6eSX512 #include "virtio.h" 2471530401SX512 #include "Htif.h" 2571530401SX512 #include "Clint.h" 2671530401SX512 #include "FwCfg.h" 27a182bd6eSX512 28a182bd6eSX512 29a182bd6eSX512 void* gFdt = NULL; 3071530401SX512 ClintRegs *volatile gClintRegs = NULL; 3171530401SX512 3271530401SX512 static uint64 sTimerFrequrency = 10000000; 3371530401SX512 3471530401SX512 static addr_range sPlic = {0}; 3571530401SX512 static addr_range sClint = {0}; 3671530401SX512 static uart_info sUart{}; 3771530401SX512 3871530401SX512 3971530401SX512 static bool 4071530401SX512 HasFdtString(const char* prop, int size, const char* pattern) 4171530401SX512 { 4271530401SX512 int patternLen = strlen(pattern); 4371530401SX512 const char* propEnd = prop + size; 4471530401SX512 while (propEnd - prop > 0) { 4571530401SX512 int curLen = strlen(prop); 4671530401SX512 if (curLen == patternLen && memcmp(prop, pattern, curLen + 1) == 0) 4771530401SX512 return true; 4871530401SX512 prop += curLen + 1; 4971530401SX512 } 5071530401SX512 return false; 5171530401SX512 } 5271530401SX512 5371530401SX512 54*0d9b77a3SX512 static bool 55*0d9b77a3SX512 GetReg(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, size_t idx, 56*0d9b77a3SX512 addr_range& range) 57*0d9b77a3SX512 { 58*0d9b77a3SX512 int propSize; 59*0d9b77a3SX512 const uint8* prop = (const uint8*)fdt_getprop(fdt, node, "reg", &propSize); 60*0d9b77a3SX512 if (prop == NULL) 61*0d9b77a3SX512 return false; 62*0d9b77a3SX512 63*0d9b77a3SX512 size_t entrySize = 4*(addressCells + sizeCells); 64*0d9b77a3SX512 if ((idx + 1)*entrySize > (size_t)propSize) 65*0d9b77a3SX512 return false; 66*0d9b77a3SX512 67*0d9b77a3SX512 prop += idx*entrySize; 68*0d9b77a3SX512 69*0d9b77a3SX512 switch (addressCells) { 70*0d9b77a3SX512 case 1: range.start = fdt32_to_cpu(*(uint32*)prop); prop += 4; break; 71*0d9b77a3SX512 case 2: range.start = fdt64_to_cpu(*(uint64*)prop); prop += 8; break; 72*0d9b77a3SX512 default: panic("unsupported addressCells"); 73*0d9b77a3SX512 } 74*0d9b77a3SX512 switch (sizeCells) { 75*0d9b77a3SX512 case 1: range.size = fdt32_to_cpu(*(uint32*)prop); prop += 4; break; 76*0d9b77a3SX512 case 2: range.size = fdt64_to_cpu(*(uint64*)prop); prop += 8; break; 77*0d9b77a3SX512 default: panic("unsupported sizeCells"); 78*0d9b77a3SX512 } 79*0d9b77a3SX512 return true; 80*0d9b77a3SX512 } 81*0d9b77a3SX512 82*0d9b77a3SX512 8371530401SX512 static uint32 8471530401SX512 GetInterrupt(const void* fdt, int node) 8571530401SX512 { 8671530401SX512 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", NULL)) { 8771530401SX512 return fdt32_to_cpu(*(prop + 1)); 8871530401SX512 } 8971530401SX512 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts", NULL)) { 9071530401SX512 return fdt32_to_cpu(*prop); 9171530401SX512 } 9271530401SX512 dprintf("[!] no interrupt field\n"); 9371530401SX512 return 0; 9471530401SX512 } 95a182bd6eSX512 96a182bd6eSX512 97a182bd6eSX512 static void 9871530401SX512 HandleFdt(const void* fdt, int node, uint32 addressCells, uint32 sizeCells, 9971530401SX512 uint32 interruptCells /* from parent node */) 100a182bd6eSX512 { 101a182bd6eSX512 // TODO: handle different field sizes 102a182bd6eSX512 10371530401SX512 const char* name = fdt_get_name(fdt, node, NULL); 10471530401SX512 if (strcmp(name, "cpus") == 0) { 10571530401SX512 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "timebase-frequency", NULL)) 10671530401SX512 sTimerFrequrency = fdt32_to_cpu(*prop); 10771530401SX512 } 10871530401SX512 109a182bd6eSX512 const char* device_type = (const char*)fdt_getprop(fdt, node, 110a182bd6eSX512 "device_type", NULL); 111a182bd6eSX512 if (device_type != NULL && strcmp(device_type, "memory") == 0) { 11271530401SX512 gMemBase = (uint8*)fdt64_to_cpu(*((uint64*)fdt_getprop(fdt, node, 113a182bd6eSX512 "reg", NULL) + 0)); 11471530401SX512 gTotalMem = fdt64_to_cpu(*((uint64*)fdt_getprop(fdt, node, 115a182bd6eSX512 "reg", NULL) + 1)); 116a182bd6eSX512 return; 117a182bd6eSX512 } 11871530401SX512 int compatibleLen; 119a182bd6eSX512 const char* compatible = (const char*)fdt_getprop(fdt, node, 12071530401SX512 "compatible", &compatibleLen); 121a182bd6eSX512 if (compatible == NULL) return; 12271530401SX512 if (HasFdtString(compatible, compatibleLen, "riscv,clint0")) { 12371530401SX512 uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL); 12471530401SX512 sClint.start = fdt64_to_cpu(*(reg + 0)); 12571530401SX512 sClint.size = fdt64_to_cpu(*(reg + 1)); 12671530401SX512 gClintRegs = (ClintRegs*)sClint.start; 12771530401SX512 } else if (HasFdtString(compatible, compatibleLen, "riscv,plic0")) { 128*0d9b77a3SX512 GetReg(fdt, node, addressCells, sizeCells, 0, sPlic); 129*0d9b77a3SX512 int propSize; 130*0d9b77a3SX512 if (uint32* prop = (uint32*)fdt_getprop(fdt, node, "interrupts-extended", &propSize)) { 131*0d9b77a3SX512 dprintf("PLIC contexts\n"); 132*0d9b77a3SX512 uint32 contextId = 0; 133*0d9b77a3SX512 for (uint32 *it = prop; (uint8_t*)it - (uint8_t*)prop < propSize; it += 2) { 134*0d9b77a3SX512 uint32 phandle = fdt32_to_cpu(*it); 135*0d9b77a3SX512 uint32 interrupt = fdt32_to_cpu(*(it + 1)); 136*0d9b77a3SX512 if (interrupt == sExternInt) { 137*0d9b77a3SX512 CpuInfo* cpuInfo = smp_find_cpu(phandle); 138*0d9b77a3SX512 dprintf(" context %" B_PRIu32 ": %" B_PRIu32 "\n", contextId, phandle); 139*0d9b77a3SX512 if (cpuInfo != NULL) { 140*0d9b77a3SX512 cpuInfo->plicContext = contextId; 141*0d9b77a3SX512 dprintf(" hartId: %" B_PRIu32 "\n", cpuInfo->hartId); 142*0d9b77a3SX512 } 143*0d9b77a3SX512 } 144*0d9b77a3SX512 contextId++; 145*0d9b77a3SX512 } 146*0d9b77a3SX512 } 14771530401SX512 } else if (HasFdtString(compatible, compatibleLen, "virtio,mmio")) { 14871530401SX512 uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL); 149a182bd6eSX512 virtio_register( 15071530401SX512 fdt64_to_cpu(*(reg + 0)), fdt64_to_cpu(*(reg + 1)), 15171530401SX512 GetInterrupt(fdt, node)); 15271530401SX512 } else if ( 15371530401SX512 strcmp(sUart.kind, "") == 0 && ( 15471530401SX512 HasFdtString(compatible, compatibleLen, "ns16550a") || 15571530401SX512 HasFdtString(compatible, compatibleLen, "sifive,uart0")) 15671530401SX512 ) { 15771530401SX512 if (HasFdtString(compatible, compatibleLen, "ns16550a")) 15871530401SX512 strcpy(sUart.kind, UART_KIND_8250); 15971530401SX512 else if (HasFdtString(compatible, compatibleLen, "sifive,uart0")) 16071530401SX512 strcpy(sUart.kind, UART_KIND_SIFIVE); 16171530401SX512 16271530401SX512 uint64* reg = (uint64*)fdt_getprop(fdt, node, "reg", NULL); 16371530401SX512 sUart.regs.start = fdt64_to_cpu(*(reg + 0)); 16471530401SX512 sUart.regs.size = fdt64_to_cpu(*(reg + 1)); 16571530401SX512 sUart.irq = GetInterrupt(fdt, node); 16671530401SX512 const void* prop = fdt_getprop(fdt, node, "clock-frequency", NULL); 16771530401SX512 sUart.clock = (prop == NULL) ? 0 : fdt32_to_cpu(*(uint32*)prop); 16871530401SX512 } else if (HasFdtString(compatible, compatibleLen, "qemu,fw-cfg-mmio")) { 16971530401SX512 gFwCfgRegs = (FwCfgRegs *volatile) 17071530401SX512 fdt64_to_cpu(*(uint64*)fdt_getprop(fdt, node, "reg", NULL)); 17171530401SX512 } else if (HasFdtString(compatible, compatibleLen, "simple-framebuffer")) { 17271530401SX512 gFramebuf.colors = (uint32*)fdt64_to_cpu( 17371530401SX512 *(uint64*)fdt_getprop(fdt, node, "reg", NULL)); 174a182bd6eSX512 gFramebuf.stride = fdt32_to_cpu( 17571530401SX512 *(uint32*)fdt_getprop(fdt, node, "stride", NULL)) / 4; 176a182bd6eSX512 gFramebuf.width = fdt32_to_cpu( 17771530401SX512 *(uint32*)fdt_getprop(fdt, node, "width", NULL)); 178a182bd6eSX512 gFramebuf.height = fdt32_to_cpu( 17971530401SX512 *(uint32*)fdt_getprop(fdt, node, "height", NULL)); 180a182bd6eSX512 } 181a182bd6eSX512 } 182a182bd6eSX512 183a182bd6eSX512 184a182bd6eSX512 void 185a182bd6eSX512 fdt_init(void* fdt) 186a182bd6eSX512 { 187a182bd6eSX512 dprintf("FDT: %p\n", fdt); 188a182bd6eSX512 gFdt = fdt; 189a182bd6eSX512 190a182bd6eSX512 int res = fdt_check_header(gFdt); 191a182bd6eSX512 if (res != 0) { 192a182bd6eSX512 panic("Invalid FDT: %s\n", fdt_strerror(res)); 193a182bd6eSX512 } 194a182bd6eSX512 195a182bd6eSX512 dprintf("FDT valid, size: %" B_PRIu32 "\n", fdt_totalsize(gFdt)); 196a182bd6eSX512 197a182bd6eSX512 int node = -1; 19871530401SX512 int depth = -1; 19971530401SX512 while ((node = fdt_next_node(gFdt, node, &depth)) >= 0 && depth >= 0) { 20071530401SX512 HandleFdt(gFdt, node, 2, 2, 1); 201a182bd6eSX512 } 202a182bd6eSX512 } 203a182bd6eSX512 204a182bd6eSX512 205a182bd6eSX512 void 206a182bd6eSX512 fdt_set_kernel_args() 207a182bd6eSX512 { 208c9d6d52bSAlexander von Gluck IV uint32_t fdtSize = fdt_totalsize(gFdt); 209c9d6d52bSAlexander von Gluck IV 2104b5c7fe7SAlexander von Gluck IV // libfdt requires 8-byte alignment 2114b5c7fe7SAlexander von Gluck IV gKernelArgs.arch_args.fdt = (void*)(addr_t)kernel_args_malloc(fdtSize, 8); 212c9d6d52bSAlexander von Gluck IV 21371530401SX512 if (gKernelArgs.arch_args.fdt != NULL) 21471530401SX512 memcpy(gKernelArgs.arch_args.fdt, gFdt, fdt_totalsize(gFdt)); 21571530401SX512 else 216a182bd6eSX512 panic("unable to malloc for FDT!\n"); 217c9d6d52bSAlexander von Gluck IV 21871530401SX512 gKernelArgs.arch_args.timerFrequency = sTimerFrequrency; 21971530401SX512 22071530401SX512 gKernelArgs.arch_args.htif.start = (addr_t)gHtifRegs; 22171530401SX512 gKernelArgs.arch_args.htif.size = sizeof(HtifRegs); 22271530401SX512 22371530401SX512 gKernelArgs.arch_args.plic = sPlic; 22471530401SX512 gKernelArgs.arch_args.clint = sClint; 22571530401SX512 gKernelArgs.arch_args.uart = sUart; 226a182bd6eSX512 } 227