From fe19a9b18bebda78155e93dd841e1088999e22a4 Mon Sep 17 00:00:00 2001 From: Alexander von Gluck IV Date: Sat, 14 Mar 2015 13:01:32 -0500 Subject: [PATCH] arm/fdt: Add functions to get device bases by name + alias * Move more code into fdt_support * We now can query FDT registers based on name or alias * Return addr_t where it makes sense * Copyright change ok'ed by mmu_man --- .../kernel/platform/u-boot/fdt_support.h | 5 +- src/system/boot/arch/arm/arch_mmu.cpp | 98 +----------- .../kernel/platform/u-boot/fdt_support.cpp | 148 ++++++++++++++++-- 3 files changed, 143 insertions(+), 108 deletions(-) diff --git a/headers/private/kernel/platform/u-boot/fdt_support.h b/headers/private/kernel/platform/u-boot/fdt_support.h index 4427f332ac..5a5d5e4ed2 100644 --- a/headers/private/kernel/platform/u-boot/fdt_support.h +++ b/headers/private/kernel/platform/u-boot/fdt_support.h @@ -13,9 +13,10 @@ void dump_fdt(const void *fdt); -status_t fdt_get_cell_count(int32 pathOffset, - int32 &addressCells, int32 &sizeCells); +status_t fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells); +addr_t fdt_get_device_reg_byname(const char* name); +addr_t fdt_get_device_reg_byalias(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 b2469f8103..6e4a75b7af 100644 --- a/src/system/boot/arch/arm/arch_mmu.cpp +++ b/src/system/boot/arch/arm/arch_mmu.cpp @@ -645,101 +645,6 @@ find_physical_memory_ranges(uint64 &total) } -static uint64 -fdt_get_range_offset(int32 node) -{ - // Obtain the offset of the device by searching - // for the first ranges start in parents. - - // 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); - int32 examineNode = node; - uint64 pathOffset = 0x0; - - while (depth > 0) { - int len; - const void* prop; - prop = fdt_getprop(gFDT, examineNode, "ranges", &len); - if (prop) { - int32 regAddressCells = 1; - int32 regSizeCells = 1; - fdt_get_cell_count(examineNode, regAddressCells, regSizeCells); - - const uint32 *p = (const uint32 *)prop; - // All we are interested in is the start offset - if (regAddressCells == 2) - pathOffset = fdt64_to_cpu(*(uint64_t *)p); - else - pathOffset = fdt32_to_cpu(*(uint32_t *)p); - break; - } - int32 parentNode = fdt_parent_offset(gFDT, examineNode); - depth = fdt_node_depth(gFDT, parentNode); - examineNode = parentNode; - } - - dprintf("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); - - return pathOffset; -} - - -static status_t -fdt_get_device_base(const char* device) -{ - int node; - const void *prop; - int len; - - // Find device in FDT - node = fdt_path_offset(gFDT, device); - - int32 regAddressCells = 1; - int32 regSizeCells = 1; - fdt_get_cell_count(node, regAddressCells, regSizeCells); - - if (node < 0) { - dprintf("%s: %s not found in FDT!\n", __func__, device); - return B_ERROR; - } - - prop = fdt_getprop(gFDT, node, "reg", &len); - - if (prop < 0) { - dprintf("%s: reg property not found on device %s in FDT!\n", __func__, - device); - return B_ERROR; - } - - 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; - - // size - 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; - - baseDevice -= fdt_get_range_offset(node); - - dprintf("%s: %s found @ 0x%" B_PRIx64 " , size: 0x%" B_PRIx64 "\n", - __func__, device, baseDevice, size); - return B_OK; -} - - extern "C" void mmu_init(void) { @@ -767,7 +672,8 @@ mmu_init(void) } // XXX: A simple test. - fdt_get_device_base("/soc/gpio"); + fdt_get_device_reg_byname("/soc/gpio"); + fdt_get_device_reg_byalias("gpio"); // see if subpages are disabled if (mmu_read_C1() & (1 << 23)) diff --git a/src/system/kernel/platform/u-boot/fdt_support.cpp b/src/system/kernel/platform/u-boot/fdt_support.cpp index 2c0f8ea341..697abb75cc 100644 --- a/src/system/kernel/platform/u-boot/fdt_support.cpp +++ b/src/system/kernel/platform/u-boot/fdt_support.cpp @@ -1,8 +1,13 @@ /* - * Copyright 2012, François Revol, revol@free.fr. + * Copyright 2012-2015 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. + * + * Authors: + * François Revol, revol@free.fr + * Alexander von Gluck IV, kallisti5@unixzen.com */ + #include "fdt_support.h" #include @@ -17,18 +22,18 @@ extern "C" { #include }; -//#define TRACE_FDT + +#define TRACE_FDT #ifdef TRACE_FDT -# define TRACE(x) dprintf x +# define TRACE(x...) dprintf(x) #else -# define TRACE(x) ; +# define TRACE(x...) ; #endif //#define FDT_DUMP_NODES //#define FDT_DUMP_PROPS //#define FDT_DUMP_PROP_VALUES - #ifdef FDT_DUMP_NODES static const char *sTabTab = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; #define DS "%.*s" @@ -127,8 +132,49 @@ void dump_fdt(const void *fdt) } +static uint64 +fdt_get_range_offset(int32 node) +{ + // Obtain the offset of the device by searching + // for the first ranges start in parents. + + // 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); + int32 examineNode = node; + uint64 pathOffset = 0x0; + + while (depth > 0) { + int len; + const void* prop; + prop = fdt_getprop(gFDT, examineNode, "ranges", &len); + if (prop) { + int32 regAddressCells = 1; + int32 regSizeCells = 1; + fdt_get_cell_count(examineNode, regAddressCells, regSizeCells); + + const uint32 *p = (const uint32 *)prop; + // All we are interested in is the start offset + if (regAddressCells == 2) + pathOffset = fdt64_to_cpu(*(uint64_t *)p); + else + pathOffset = fdt32_to_cpu(*(uint32_t *)p); + break; + } + int32 parentNode = fdt_parent_offset(gFDT, examineNode); + depth = fdt_node_depth(gFDT, parentNode); + examineNode = parentNode; + } + + dprintf("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); + + return pathOffset; +} + + status_t -fdt_get_cell_count(int32 pathOffset, int32 &addressCells, int32 &sizeCells) +fdt_get_cell_count(int node, int32 &addressCells, int32 &sizeCells) { // It would be nice if libfdt provided this. @@ -139,16 +185,16 @@ fdt_get_cell_count(int32 pathOffset, int32 &addressCells, int32 &sizeCells) // TODO: assert !gFDT || !pathOffset? int len; - if (!pathOffset) { - TRACE(("%s: Invalid FDT pathOffset provided!\n", __func__)); + if (node < 0) { + TRACE("%s: Invalid FDT node id provided!\n", __func__); return B_ERROR; } const void *prop; - prop = fdt_getprop(gFDT, pathOffset, "#address-cells", &len); + prop = fdt_getprop(gFDT, node, "#address-cells", &len); if (prop && len == sizeof(uint32)) addressCells = fdt32_to_cpu(*(uint32_t *)prop); - prop = fdt_getprop(gFDT, pathOffset, "#size-cells", &len); + prop = fdt_getprop(gFDT, node, "#size-cells", &len); if (prop && len == sizeof(uint32)) sizeCells = fdt32_to_cpu(*(uint32_t *)prop); @@ -162,3 +208,85 @@ fdt_get_cell_count(int32 pathOffset, int32 &addressCells, int32 &sizeCells) return B_OK; } + + +static addr_t +fdt_get_device_reg(int node) +{ + const void *prop; + int len; + + int32 regAddressCells = 1; + int32 regSizeCells = 1; + fdt_get_cell_count(node, regAddressCells, regSizeCells); + + prop = fdt_getprop(gFDT, node, "reg", &len); + + if (!prop) { + dprintf("%s: reg property not found on node in FDT!\n", __func__); + return 0; + } + + 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; + + // 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; + + baseDevice -= fdt_get_range_offset(node); + + return (addr_t)baseDevice; +} + + +addr_t +fdt_get_device_reg_byname(const char* name) +{ + // Find device in FDT + int node = fdt_path_offset(gFDT, name); + + if (node < 0) { + dprintf("%s: %s not found in FDT!\n", __func__, name); + return 0; + } + + addr_t deviceReg = fdt_get_device_reg(node); + if (deviceReg > 0) { + //TRACE("%s: %s found @ 0x%" B_PRIx64 " , size: 0x%" B_PRIx64 "\n", + // __func__, name, deviceReg, size); + TRACE("%s: %s found @ 0x%" B_PRIxADDR "\n", __func__, name, deviceReg); + } else { + dprintf("%s: No valid reg entry on FDT device %s!\n", + __func__, name); + return 0; + } + return deviceReg; +} + + +addr_t +fdt_get_device_reg_byalias(const char* alias) +{ + const char* name = fdt_get_alias(gFDT, alias); + + if (name == NULL) { + dprintf("%s: No alias found for %s!\n", __func__, alias); + return 0; + } + + addr_t deviceReg = fdt_get_device_reg_byname(name); + return deviceReg; +}