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