hrev48948 adds 2 changesets to branch 'master' old head: 7b1ea45c346bba1844fc4f10cfd8ae9776c97dbd new head: c6a4fee57959c986091fcd52f2096b28b98456e2 overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=c6a4fee57959+%5E7b1ea45c346b ---------------------------------------------------------------------------- 3d02d66b03ba: rpi2: Begin using internal FDT c6a4fee57959: loader/u-boot: Use FDT serial info to create uart * drop my fdt tests * we have to call fdt parsing code *after* cpu_init (why?) * pass fdt pointer to all FDT support calls to avoid confusion once we get into the kernel land * look for PL011 compatible uart and use it * Add some saftey checks to serial putc code to avoid null* * fdt_node_check_compatible returns 0 on success not 1 * fdt_get_device_reg needs to add the SOC base to the result * fdt_get_device_reg might need to add the second range cell instead of reg? [ Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 9 files changed, 132 insertions(+), 71 deletions(-) build/jam/board/rpi2/BoardSetup | 11 +-- .../private/kernel/platform/u-boot/fdt_serial.h | 19 +++++ .../private/kernel/platform/u-boot/fdt_support.h | 9 +-- src/system/boot/arch/arm/arch_mmu.cpp | 6 +- src/system/boot/platform/u-boot/serial.cpp | 28 +++++--- src/system/boot/platform/u-boot/start.cpp | 9 ++- src/system/kernel/arch/arm/arch_uart_pl011.cpp | 2 - src/system/kernel/platform/u-boot/fdt_serial.cpp | 44 ++++++++---- .../kernel/platform/u-boot/fdt_support.cpp | 75 ++++++++++++-------- ############################################################################ Commit: 3d02d66b03baa18929cefde69b10466c06692922 URL: http://cgit.haiku-os.org/haiku/commit/?id=3d02d66b03ba Author: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> Date: Sat Mar 28 19:33:58 2015 UTC rpi2: Begin using internal FDT ---------------------------------------------------------------------------- diff --git a/build/jam/board/rpi2/BoardSetup b/build/jam/board/rpi2/BoardSetup index f81b6d8..8bbeab4 100644 --- a/build/jam/board/rpi2/BoardSetup +++ b/build/jam/board/rpi2/BoardSetup @@ -1,7 +1,7 @@ # Raspberry Pi 2 board-specific definitions HAIKU_BOARD_DESCRIPTION = "Raspberry Pi 2" ; -HAIKU_BOOT_PLATFORM = u-boot ; +HAIKU_BOARD_FDT_NAME = "rpi2" ; # # Various hardcoded addresses @@ -26,19 +26,19 @@ HAIKU_BOARD_FIRMWARE_URL = https://github.com/raspberrypi/firmware/raw/master/bo bootcodeFile = [ DownloadFile bootcode.bin : $(HAIKU_BOARD_FIRMWARE_URL)/bootcode.bin ] ; startFile = [ DownloadFile start.elf : $(HAIKU_BOARD_FIRMWARE_URL)/start.elf ] ; licenseFile = [ DownloadFile LICENCE.broadcom : $(HAIKU_BOARD_FIRMWARE_URL)/LICENCE.broadcom ] ; -# TODO: Find rpi2 FDT, bring in-tree -fdtFile = [ DownloadFile bcm2836-rpi-2-b.dtb : $(HAIKU_BOARD_FIRMWARE_URL)/bcm2709-rpi-2-b.dtb ] ; + +local fdtBinary = [ FDirName $(HAIKU_OUTPUT_DIR) $(HAIKU_BOARD_FDT_NAME).dtb ] ; +CompileDTS $(fdtBinary) : [ FDirName $(HAIKU_TOP) src data dts arch arm $(HAIKU_BOARD_FDT_NAME).dts ] ; HAIKU_BOARD_FIRMWARE_FILES = $(bootcodeFile) $(startFile) $(licenseFile) - $(fdtFile) ; HAIKU_BOARD_SDIMAGE_UBOOT_SCRIPT_NAME = boot.scr ; HAIKU_BOARD_SDIMAGE_UBOOT_SCRIPT = "\ -fatload mmc 0 ${fdt_addr_r} bcm2836-rpi-2-b.dtb \ +fatload mmc 0 ${fdt_addr_r} $(HAIKU_BOARD_FDT_NAME).dtb \ fdt addr ${fdt_addr_r} \ fatload mmc 0 ${ramdisk_addr_r} haiku-floppyboot.tgz.ub \ fatload mmc 0 ${kernel_addr_r} haiku_loader_linux.ub \ @@ -48,6 +48,7 @@ HAIKU_BOARD_SDIMAGE_FAT_SIZE = 32 ; HAIKU_BOARD_SDIMAGE_FILES = $(HAIKU_BOARD_FIRMWARE_FILES) $(configFile) + $(fdtBinary) $(ubootFile) haiku_loader_linux.ub haiku-floppyboot.tgz.ub ############################################################################ Revision: hrev48948 Commit: c6a4fee57959c986091fcd52f2096b28b98456e2 URL: http://cgit.haiku-os.org/haiku/commit/?id=c6a4fee57959 Author: Alexander von Gluck IV <kallisti5@xxxxxxxxxxx> Date: Sat Mar 28 20:52:16 2015 UTC loader/u-boot: Use FDT serial info to create uart * drop my fdt tests * we have to call fdt parsing code *after* cpu_init (why?) * pass fdt pointer to all FDT support calls to avoid confusion once we get into the kernel land * look for PL011 compatible uart and use it * Add some saftey checks to serial putc code to avoid null* * fdt_node_check_compatible returns 0 on success not 1 * fdt_get_device_reg needs to add the SOC base to the result * fdt_get_device_reg might need to add the second range cell instead of reg? ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/platform/u-boot/fdt_serial.h b/headers/private/kernel/platform/u-boot/fdt_serial.h new file mode 100644 index 0000000..18d6f98 --- /dev/null +++ b/headers/private/kernel/platform/u-boot/fdt_serial.h @@ -0,0 +1,19 @@ +/* + * Copyright 2012-2015, Haiku, Inc. + * Distributed under the terms of the MIT License. + * + * Authors + * Alexander von Gluck IV, kallisti5@xxxxxxxxxxx + */ +#ifndef __FDT_SERIAL_H +#define __FDT_SERIAL_H + + +#include <KernelExport.h> +#include <arch/generic/debug_uart.h> + + +DebugUART * debug_uart_from_fdt(const void *fdt); + + +#endif /*__FDT_SERIAL_H*/ diff --git a/headers/private/kernel/platform/u-boot/fdt_support.h b/headers/private/kernel/platform/u-boot/fdt_support.h index c2d5a89..84a4642 100644 --- a/headers/private/kernel/platform/u-boot/fdt_support.h +++ b/headers/private/kernel/platform/u-boot/fdt_support.h @@ -13,11 +13,12 @@ void dump_fdt(const void *fdt); -status_t fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells); +status_t fdt_get_cell_count(const void* fdt, int node, + int32 &addressCells, int32 &sizeCells); -phys_addr_t fdt_get_device_reg(int node); -phys_addr_t fdt_get_device_reg_byname(const char* name); -phys_addr_t fdt_get_device_reg_byalias(const char* alias); +phys_addr_t fdt_get_device_reg(const void* fdt, int node); +phys_addr_t fdt_get_device_reg_byname(const void* fdt, const char* name); +phys_addr_t fdt_get_device_reg_byalias(const void* fdt, const char* alias); #endif /*__FDT_SUPPORT_H*/ diff --git a/src/system/boot/arch/arm/arch_mmu.cpp b/src/system/boot/arch/arm/arch_mmu.cpp index 6e4a75b..35ea106 100644 --- a/src/system/boot/arch/arm/arch_mmu.cpp +++ b/src/system/boot/arch/arm/arch_mmu.cpp @@ -600,7 +600,7 @@ find_physical_memory_ranges(uint64 &total) int32 regAddressCells = 1; int32 regSizeCells = 1; - fdt_get_cell_count(node, regAddressCells, regSizeCells); + fdt_get_cell_count(gFDT, node, regAddressCells, regSizeCells); prop = fdt_getprop(gFDT, node, "reg", &len); if (prop == NULL) { @@ -671,10 +671,6 @@ mmu_init(void) dprintf("total physical memory = %" B_PRId64 "MB\n", total / (1024 * 1024)); } - // XXX: A simple test. - fdt_get_device_reg_byname("/soc/gpio"); - fdt_get_device_reg_byalias("gpio"); - // see if subpages are disabled if (mmu_read_C1() & (1 << 23)) sSmallPageType = ARM_MMU_L2_TYPE_SMALLNEW; diff --git a/src/system/boot/platform/u-boot/serial.cpp b/src/system/boot/platform/u-boot/serial.cpp index 8a33fd3..fd57e86 100644 --- a/src/system/boot/platform/u-boot/serial.cpp +++ b/src/system/boot/platform/u-boot/serial.cpp @@ -2,17 +2,23 @@ * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx. * Distributed under the terms of the MIT License. * - * Copyright 2012, Alexander von Gluck, kallisti5@xxxxxxxxxxx + * Copyright 2012-2015, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@xxxxxxxxxxxxxxxx + * Alexander von Gluck IV, kallisti5@xxxxxxxxxxx */ #include "serial.h" -#include <debug_uart_8250.h> +#include <arch/generic/debug_uart_8250.h> + #if defined(__ARM__) -#include <arch_uart_pl011.h> +#include <arch/arm/arch_uart_pl011.h> #endif + #include <board_config.h> #include <boot/platform.h> #include <arch/cpu.h> @@ -26,8 +32,8 @@ extern "C" { #include <libfdt_env.h> }; +#include "fdt_serial.h" -extern "C" DebugUART *debug_uart_from_fdt(const void *fdt); DebugUART* gUART; @@ -39,6 +45,9 @@ static uint32 sBufferPosition; static void serial_putc(char c) { + if (gUART == NULL || sSerialEnabled <= 0) + return; + gUART->PutChar(c); } @@ -46,6 +55,9 @@ serial_putc(char c) extern "C" int serial_getc(bool wait) { + if (gUART == NULL || sSerialEnabled <= 0) + return 0; + return gUART->GetChar(wait); } @@ -112,16 +124,16 @@ serial_init(const void *fdt) // first try with hints from the FDT gUART = debug_uart_from_fdt(fdt); -#ifdef BOARD_UART_DEBUG - // fallback to hardcoded board UART + // fallback to known board UARTs + #if defined(BOARD_UART_DEBUG) && defined(BOARD_UART_CLOCK) if (gUART == NULL) { - #if defined(BOARD_UART_PL011) + #ifdef BOARD_UART_PL011 gUART = arch_get_uart_pl011(BOARD_UART_DEBUG, BOARD_UART_CLOCK); #else gUART = arch_get_uart_8250(BOARD_UART_DEBUG, BOARD_UART_CLOCK); #endif } -#endif + #endif if (gUART == NULL) return; diff --git a/src/system/boot/platform/u-boot/start.cpp b/src/system/boot/platform/u-boot/start.cpp index b459782..2a0aba9 100644 --- a/src/system/boot/platform/u-boot/start.cpp +++ b/src/system/boot/platform/u-boot/start.cpp @@ -214,16 +214,19 @@ start_gen(int argc, const char **argv, struct image_header *uimage, void *fdt) gFDT = args.platform.fdt_data; } + // We have to cpu_init *before* calling FDT functions + cpu_init(); + #if defined(__ARM__) arch_mailbox_init(); #endif - serial_init(gFDT); + console_init(); + serial_init(gFDT); + // initialize the OpenFirmware wrapper of_init(NULL); - cpu_init(); - // if we get passed an FDT, check /chosen for initrd and bootargs if (gFDT != NULL) { int node = fdt_path_offset(gFDT, "/chosen"); diff --git a/src/system/kernel/arch/arm/arch_uart_pl011.cpp b/src/system/kernel/arch/arm/arch_uart_pl011.cpp index 0794324..ef38694 100644 --- a/src/system/kernel/arch/arm/arch_uart_pl011.cpp +++ b/src/system/kernel/arch/arm/arch_uart_pl011.cpp @@ -11,9 +11,7 @@ #include <arch/arm/reg.h> #include <arch/generic/debug_uart.h> #include <arch/arm/arch_uart_pl011.h> -//#include <board_config.h> #include <new> -//#include <target/debugconfig.h> #define PL01x_DR 0x00 // Data read or written diff --git a/src/system/kernel/platform/u-boot/fdt_serial.cpp b/src/system/kernel/platform/u-boot/fdt_serial.cpp index e1059b4..810eed9 100644 --- a/src/system/kernel/platform/u-boot/fdt_serial.cpp +++ b/src/system/kernel/platform/u-boot/fdt_serial.cpp @@ -1,17 +1,26 @@ /* * Copyright 2012, François Revol, revol@xxxxxxx. * Distributed under the terms of the MIT License. + * + * Authors: + * François Revol, revol@xxxxxxx + * Alexander von Gluck IV, kallisti5@xxxxxxxxxxx */ +#include "fdt_serial.h" + #include <KernelExport.h> #include <ByteOrder.h> #include <ctype.h> #include <stdio.h> #include <sys/cdefs.h> -#include <arch/generic/debug_uart.h> #include <arch/generic/debug_uart_8250.h> +#ifdef __ARM__ +#include <arch/arm/arch_uart_pl011.h> +#endif + extern "C" { #include <fdt.h> #include <libfdt.h> @@ -21,14 +30,13 @@ extern "C" { #include "fdt_support.h" -extern "C" DebugUART *debug_uart_from_fdt(const void *fdt); +// If we dprintf before the UART is initalized there will be no output -DebugUART * +DebugUART* debug_uart_from_fdt(const void *fdt) { const char *name; - //const char *type; int node; int len; phys_addr_t regs; @@ -52,36 +60,45 @@ debug_uart_from_fdt(const void *fdt) return NULL; node = fdt_path_offset(fdt, name); - //dprintf("serial: using '%s', node %d\n", name, node); + if (node < 0) return NULL; // determine the MMIO address - regs = fdt_get_device_reg(node); + regs = fdt_get_device_reg(fdt, node); if (regs == 0) return NULL; + dprintf("serial: using '%s', node %d @ %" B_PRIxPHYSADDR "\n", + name, node, regs); + // get the UART clock rate prop = fdt_getprop(fdt, node, "clock-frequency", &len); if (prop && len == 4) { clock = fdt32_to_cpu(*(uint32_t *)prop); - //dprintf("serial: clock %ld\n", clock); + dprintf("serial: clock %ld\n", clock); } // get current speed (XXX: not yet passed over) prop = fdt_getprop(fdt, node, "current-speed", &len); if (prop && len == 4) { speed = fdt32_to_cpu(*(uint32_t *)prop); - //dprintf("serial: speed %ld\n", speed); + dprintf("serial: speed %ld\n", speed); } - if (fdt_node_check_compatible(fdt, node, "ns16550a") == 1 - || fdt_node_check_compatible(fdt, node, "ns16550") == 1) { + // fdt_node_check_compatible returns 0 on match. + + if (fdt_node_check_compatible(fdt, node, "ns16550a") == 0 + || fdt_node_check_compatible(fdt, node, "ns16550") == 0) { + dprintf("serial: Found 8250 serial UART!\n"); uart = arch_get_uart_8250(regs, clock); - //dprintf("serial: using 8250\n"); - // XXX:assume speed is already set - (void)speed; + #ifdef __ARM__ + } else if (fdt_node_check_compatible(fdt, node, "arm,pl011") == 0 + || fdt_node_check_compatible(fdt, node, "arm,primecell") == 0) { + dprintf("serial: Found pl011 serial UART!\n"); + uart = arch_get_uart_pl011(regs, clock); + #endif } else { // TODO: handle more UART types return NULL; @@ -89,4 +106,3 @@ debug_uart_from_fdt(const void *fdt) return uart; } - diff --git a/src/system/kernel/platform/u-boot/fdt_support.cpp b/src/system/kernel/platform/u-boot/fdt_support.cpp index ad789a1..c34b666 100644 --- a/src/system/kernel/platform/u-boot/fdt_support.cpp +++ b/src/system/kernel/platform/u-boot/fdt_support.cpp @@ -133,7 +133,7 @@ void dump_fdt(const void *fdt) static uint64 -fdt_get_range_offset(int32 node) +fdt_get_range_offset(const void* fdt, int32 node) { // Obtain the offset of the device by searching // for the first ranges start in parents. @@ -141,18 +141,18 @@ fdt_get_range_offset(int32 node) // It could be possible that there are multiple // offset ranges in several parents + children. // Lets hope that no system designer is that insane. - int depth = fdt_node_depth(gFDT, node); + int depth = fdt_node_depth(fdt, node); int32 examineNode = node; uint64 pathOffset = 0x0; while (depth > 0) { int len; const void* prop; - prop = fdt_getprop(gFDT, examineNode, "ranges", &len); + prop = fdt_getprop(fdt, examineNode, "ranges", &len); if (prop) { int32 regAddressCells = 1; int32 regSizeCells = 1; - fdt_get_cell_count(examineNode, regAddressCells, regSizeCells); + fdt_get_cell_count(fdt, examineNode, regAddressCells, regSizeCells); const uint32 *p = (const uint32 *)prop; // All we are interested in is the start offset @@ -162,19 +162,20 @@ fdt_get_range_offset(int32 node) pathOffset = fdt32_to_cpu(*(uint32_t *)p); break; } - int32 parentNode = fdt_parent_offset(gFDT, examineNode); - depth = fdt_node_depth(gFDT, parentNode); + int32 parentNode = fdt_parent_offset(fdt, examineNode); + depth = fdt_node_depth(fdt, parentNode); examineNode = parentNode; } - dprintf("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); + TRACE("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); return pathOffset; } status_t -fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells) +fdt_get_cell_count(const void* fdt, int node, + int32 &addressCells, int32 &sizeCells) { // It would be nice if libfdt provided this. @@ -182,7 +183,7 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells) // #address-cells and #size-cells matches the number of 32-bit 'cells' // representing the length of the base address and size fields - // TODO: assert !gFDT || !pathOffset? + // TODO: assert !fdt || !pathOffset? int len; if (node < 0) { @@ -191,10 +192,10 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells) } const void *prop; - prop = fdt_getprop(gFDT, node, "#address-cells", &len); + prop = fdt_getprop(fdt, node, "#address-cells", &len); if (prop && len == sizeof(uint32)) addressCells = fdt32_to_cpu(*(uint32_t *)prop); - prop = fdt_getprop(gFDT, node, "#size-cells", &len); + prop = fdt_getprop(fdt, node, "#size-cells", &len); if (prop && len == sizeof(uint32)) sizeCells = fdt32_to_cpu(*(uint32_t *)prop); @@ -211,18 +212,18 @@ fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells) phys_addr_t -fdt_get_device_reg(int node) +fdt_get_device_reg(const void* fdt, int node) { const void *prop; int len; int32 regAddressCells = 1; int32 regSizeCells = 1; - fdt_get_cell_count(node, regAddressCells, regSizeCells); + fdt_get_cell_count(fdt, node, regAddressCells, regSizeCells); // TODO: check for virtual-reg, and don't -= fdt_get_range_offset? - prop = fdt_getprop(gFDT, node, "reg", &len); + prop = fdt_getprop(fdt, node, "reg", &len); if (!prop) { dprintf("%s: reg property not found on node in FDT!\n", __func__); @@ -231,41 +232,55 @@ fdt_get_device_reg(int node) const uint32 *p = (const uint32 *)prop; uint64 baseDevice = 0x0; - uint64 size = 0x0; // soc base address cells if (regAddressCells == 2) baseDevice = fdt64_to_cpu(*(uint64_t *)p); else baseDevice = fdt32_to_cpu(*(uint32_t *)p); - p += regAddressCells; + //p += regAddressCells; - // size (atm, we don't pass this back :-\) - if (regSizeCells == 2) - size = fdt64_to_cpu(*(uint64_t *)p); - else if (regSizeCells == 1) - size = fdt32_to_cpu(*(uint32_t *)p); - // we can have 0 size cells - //p += regSizeCells; + // subtract the range offset (X) on the parent node (ranges = X Y Z) + baseDevice -= fdt_get_range_offset(fdt, node); - baseDevice -= fdt_get_range_offset(node); + // find the start of the parent (X) and add to base (regs = X Y) + int parentNode = fdt_parent_offset(fdt, node); + if (!parentNode) + return baseDevice; + + fdt_get_cell_count(fdt, parentNode, regAddressCells, regSizeCells); + prop = fdt_getprop(fdt, parentNode, "reg", &len); + + if (!prop) + return baseDevice; + p = (const uint32 *)prop; + + uint64 parentReg = 0x0; + // soc base address cells + if (regAddressCells == 2) + parentReg = fdt64_to_cpu(*(uint64_t *)p); + else + parentReg = fdt32_to_cpu(*(uint32_t *)p); + + // add parent reg base to property + baseDevice += parentReg; return baseDevice; } phys_addr_t -fdt_get_device_reg_byname(const char* name) +fdt_get_device_reg_byname(const void* fdt, const char* name) { // Find device in FDT - int node = fdt_path_offset(gFDT, name); + int node = fdt_path_offset(fdt, name); if (node < 0) { dprintf("%s: %s not found in FDT!\n", __func__, name); return 0; } - addr_t deviceReg = fdt_get_device_reg(node); + addr_t deviceReg = fdt_get_device_reg(fdt, node); if (deviceReg > 0) { //TRACE("%s: %s found @ 0x%" B_PRIx64 " , size: 0x%" B_PRIx64 "\n", // __func__, name, deviceReg, size); @@ -280,15 +295,15 @@ fdt_get_device_reg_byname(const char* name) phys_addr_t -fdt_get_device_reg_byalias(const char* alias) +fdt_get_device_reg_byalias(const void* fdt, const char* alias) { - const char* name = fdt_get_alias(gFDT, alias); + const char* name = fdt_get_alias(fdt, alias); if (name == NULL) { dprintf("%s: No alias found for %s!\n", __func__, alias); return 0; } - phys_addr_t deviceReg = fdt_get_device_reg_byname(name); + phys_addr_t deviceReg = fdt_get_device_reg_byname(fdt, name); return deviceReg; }