diff --git a/headers/os/drivers/bus/FDT.h b/headers/os/drivers/bus/FDT.h index e391a653d3..4e887a95ef 100644 --- a/headers/os/drivers/bus/FDT.h +++ b/headers/os/drivers/bus/FDT.h @@ -1,45 +1,31 @@ /* - * Copyright 2014, Ithamar R. Adema - * All rights reserved. Distributed under the terms of the MIT License. + * Copyright 2020-2021, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. */ - #ifndef _DRIVERS_BUS_FDT_H #define _DRIVERS_BUS_FDT_H -#include -#ifdef __cplusplus -extern "C" { -#endif +#include -typedef int fdt_device_node; -struct fdt_device_info { - const char *compatible; - status_t (*init)(struct fdt_module_info *fdt, fdt_device_node node, void *cookie); +struct fdt_bus; +struct fdt_device; + +struct fdt_bus_module_info { + driver_module_info info; + device_node* (*node_by_phandle)(fdt_bus* bus, int phandle); }; -struct fdt_module_info { - bus_manager_info binfo; - - // basic call for triggering callbacks for supported devices - // scans the whole FDT tree once and calls the info.init function - // when a matching device is found. - status_t (*setup_devices)(struct fdt_device_info *info, int count, void *cookie); - - // map physical "reg" range "index" of node "node", and return the virtual address in '*_address' - // and return the area ID or error if not able to. - area_id (*map_reg_range)(fdt_device_node node, int index, void **_address); - - // return entry "index" out of "interrupts" property for node "node", or a negative error code on failure. - int (*get_interrupt)(fdt_device_node node, int index); +struct fdt_device_module_info{ + driver_module_info info; + device_node* (*get_bus)(fdt_device* dev); + const char* (*get_name)(fdt_device* dev); + const void* (*get_prop)(fdt_device* dev, const char* name, int* len); + bool (*get_reg)(fdt_device* dev, uint32 ord, uint64* regs, uint64* len); + bool (*get_interrupt)(fdt_device* dev, uint32 ord, + device_node** interruptController, uint64* interrupt); }; -#define B_FDT_MODULE_NAME "bus_managers/fdt/v1" - - -#ifdef __cplusplus -} -#endif #endif // _DRIVERS_BUS_FDT_H diff --git a/src/add-ons/kernel/bus_managers/fdt/Jamfile b/src/add-ons/kernel/bus_managers/fdt/Jamfile index 92d5f99634..47688d218d 100644 --- a/src/add-ons/kernel/bus_managers/fdt/Jamfile +++ b/src/add-ons/kernel/bus_managers/fdt/Jamfile @@ -19,17 +19,15 @@ local earlyFDTHelpers = ; KernelAddon fdt : - fdt.cpp -# $(libFDTSources) + fdt_module.cpp + $(libFDTSources) ; BootStaticLibrary boot_fdt : - $(earlyFDTHelpers) $(libFDTSources) ; KernelStaticLibrary kernel_fdt : - $(earlyFDTHelpers) $(libFDTSources) ; diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt.cpp b/src/add-ons/kernel/bus_managers/fdt/fdt.cpp deleted file mode 100644 index 5a4fc2a9da..0000000000 --- a/src/add-ons/kernel/bus_managers/fdt/fdt.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2014, Ithamar R. Adema - * All rights reserved. Distributed under the terms of the MIT License. - */ - -#include -#include -#include - -#include // isprint -#include // snprintf - -extern "C" { -#include -#include -#include -}; - -extern void *gFDT; - -static status_t fdt_setup_devices(struct fdt_device_info *info, int count, void *cookie); - -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" -#define DA depth - 1, sTabTab - -static void -fdt_dump_value(const char *data, int32 len, int depth) -{ - char str[128]; - char astr[32]; - char *p; - int l; - int i; - - for (i = 0; i < len; ) { - p = str; - l = sizeof(str); - for (; i < len && (p == str || (i % 16 != 0)); i++) { - snprintf(p, l - 1, "%02x ", data[i]); - l -= strlen(p); - p += strlen(p); - astr[i % 16] = isprint(data[i]) ? data[i] : '.'; - astr[i % 16] = isprint(data[i]) ? data[i] : '.'; - astr[(i % 16) + 1] = '\0'; - } - dprintf(DS" %-48.48s %s\n", DA, str, astr); - } -} - -static int -fdt_debug_tree(int argc, char **argv) -{ - bool dump_props = false, dump_values = false; - - if (gFDT == NULL) { - dprintf("No fdt tree\n"); - return 0; - } - - dprintf("fdt tree:\n"); - - int node = -1; - int depth = 0; - while ((node = fdt_next_node(gFDT, node, &depth)) >= 0) { - dprintf(DS"node at %d: '%s'\n", DA, node, - fdt_get_name(gFDT, node, NULL)); - - if (dump_props) { - int prop, len; - const struct fdt_property *property; - prop = fdt_first_property_offset(gFDT, node); - while (prop >= 0) { - property = fdt_get_property_by_offset(gFDT, prop, &len); - if (property == NULL) { - dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); - break; - } - dprintf(DS" prop at %d: '%s', len %d\n", DA, prop, - fdt_string(gFDT, fdt32_to_cpu(property->nameoff)), - fdt32_to_cpu(property->len)); - - if (dump_values) - fdt_dump_value(property->data, fdt32_to_cpu(property->len), depth); - - prop = fdt_next_property_offset(gFDT, prop); - } - } - } - - return 0; -} - - -static int32 -bus_std_ops(int32 op, ...) -{ - switch (op) { - case B_MODULE_INIT: - if (gFDT == NULL || fdt_totalsize(gFDT) <= 0) - return B_BAD_DATA; - - add_debugger_command("fdt", &fdt_debug_tree, "Show Flattened Device Tree"); - break; - - case B_MODULE_UNINIT: - // Nothing to free, gFDT allocation is managed by kernel - break; - - default: - return EINVAL; - } - - return B_OK; -} - -static int -fdt_get_interrupt(fdt_device_node node, int index) -{ - const struct fdt_property *prop; - int lenp; - - prop = fdt_get_property(gFDT, node, "interrupts", &lenp); - if (prop == NULL) - return B_NAME_NOT_FOUND; - - int numRanges = lenp / sizeof(uint32); - if (index > numRanges) - return B_BAD_INDEX; - - return fdt32_to_cpu(((uint32*)prop->data)[index]); -} - -static area_id -fdt_map_reg_range(fdt_device_node node, int index, void **_address) -{ - char name[B_OS_NAME_LENGTH] = "ingo_asked_me_to_name_this"; - const struct fdt_property *prop; - int lenp; - - prop = fdt_get_property(gFDT, node, "reg", &lenp); - if (prop == NULL) - return B_NAME_NOT_FOUND; - - int numRanges = lenp / (sizeof(uint32) * 2); - if (index > numRanges) - return B_BAD_INDEX; - - //snprintf(name, sizeof(name), "%s_reg_%d", fdt_get_name(gFDT, node, NULL), index); - - uint32* regs = (uint32*)prop->data; - phys_addr_t rangeStart = (phys_addr_t)fdt32_to_cpu(regs[index*2]); - uint32 rangeSize = fdt32_to_cpu(regs[index*2+1]); - dprintf("fdt_map_reg_range: found reg range %p/%lu\n", (void*)rangeStart, rangeSize); - - return map_physical_memory(name, rangeStart, rangeSize, - 0, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)_address); -} - -static struct fdt_module_info sModuleInfo = { - // First the bus_manager_info: - { - { - "bus_managers/fdt/v1", - B_KEEP_LOADED, // Keep loaded, even if no driver requires it - bus_std_ops - }, - NULL // the rescan function - }, - - fdt_setup_devices, - fdt_map_reg_range, - fdt_get_interrupt, -}; - - -module_info *modules[] = { - (module_info *)&sModuleInfo, - NULL -}; - -static status_t -fdt_setup_devices(struct fdt_device_info *info, int count, void *cookie) -{ - int numDevs = 0; - - if (gFDT == NULL) - return B_NOT_INITIALIZED; - - int node = -1; - int depth = 0; - while ((node = fdt_next_node(gFDT, node, &depth)) >= 0) { - for (int i=0; i < count; i++) { - if (fdt_node_check_compatible(gFDT, node, info[i].compatible) == 0) { - status_t result = info[i].init(&sModuleInfo, node, cookie); - if (result != B_OK) { - // TODO handle return value from init somehow? - dprintf("fdt: device '%s' failed to initialize!\n", - fdt_get_name(gFDT, node, NULL)); - } else { - ++numDevs; - } - } - } - } - - return (numDevs <= 0) ? B_ENTRY_NOT_FOUND : B_OK; -} - - diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp b/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp new file mode 100644 index 0000000000..4dc5d0d2bd --- /dev/null +++ b/src/add-ons/kernel/bus_managers/fdt/fdt_module.cpp @@ -0,0 +1,475 @@ +/* + * Copyright 2014, Ithamar R. Adema + * All rights reserved. Distributed under the terms of the MIT License. + * + * Copyright 2015-2021, Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include +#include +#include +#include + +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +}; + + +//#define TRACE_FDT +#ifdef TRACE_FDT +#define TRACE(x...) dprintf(x) +#else +#define TRACE(x...) +#endif + + +extern void* gFDT; + +device_manager_info* gDeviceManager; + +extern fdt_bus_module_info gBusModule; +extern fdt_device_module_info gDeviceModule; + + +//#pragma mark - + + +struct fdt_bus { + device_node* node; + HashMap, device_node*> phandles; +}; + + +struct fdt_device { + device_node* node; + device_node* bus; +}; + + +static status_t +fdt_register_node(fdt_bus* bus, int node, device_node* parentDev, + device_node*& curDev) +{ + TRACE("%s('%s', %p)\n", __func__, fdt_get_name(gFDT, node, NULL), + parentDev); + + const void* prop; int propLen; + device_attr attrs[8]; + device_attr* attr = attrs; + + const char *name = fdt_get_name(gFDT, node, NULL); + + *attr++ = (device_attr) { B_DEVICE_BUS, B_STRING_TYPE, {string: "fdt"}}; + *attr++ = (device_attr) { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, + { string: (strcmp(name, "") != 0) ? name : "Root" } }; + *attr++ = (device_attr) { "fdt/node", B_UINT32_TYPE, {ui32: (uint32)node}}; + *attr++ = (device_attr) { "fdt/name", B_STRING_TYPE, {string: name}}; + + prop = fdt_getprop(gFDT, node, "device_type", &propLen); + if (prop != NULL) { + *attr++ = (device_attr) { "fdt/device_type", B_STRING_TYPE, + { string: (const char*)prop } }; + + prop = fdt_getprop(gFDT, node, "compatible", &propLen); + + if (prop != NULL) { + *attr++ = (device_attr){ "fdt/compatible", B_STRING_TYPE, + { string: (const char*)prop } }; + } + + *attr = {0}; + + status_t res = gDeviceManager->register_node(parentDev, + "bus_managers/fdt/driver_v1", attrs, NULL, &curDev); + + if (res < B_OK) + return res; + + prop = fdt_getprop(gFDT, node, "phandle", &propLen); + + if (prop != NULL) + bus->phandles.Put(fdt32_to_cpu(*(uint32_t*)prop), curDev); + + return B_OK; +} + + +static void +fdt_traverse(fdt_bus* bus, int &node, int &depth, device_node* parentDev) +{ + int curDepth = depth; +#if 0 + for (int i = 0; i < depth; i++) dprintf(" "); + dprintf("node('%s')\n", fdt_get_name(gFDT, node, NULL)); +#endif + device_node* curDev; + fdt_register_node(bus, node, parentDev, curDev); + + node = fdt_next_node(gFDT, node, &depth); + while (node >= 0 && depth == curDepth + 1) { + fdt_traverse(bus, node, depth, curDev); + } +} + + +//#pragma mark bus + +static int32 +fdt_bus_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + TRACE("fdt root init\n"); + return B_OK; + + case B_MODULE_UNINIT: + TRACE("fdt root uninit\n"); + return B_OK; + } + + return B_BAD_VALUE; +} + + +static float +fdt_bus_supports_device(device_node* parent) +{ + TRACE("fdt_bus_supports_device\n"); + + // make sure parent is really device root + const char* bus; + if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) + return B_ERROR; + + if (strcmp(bus, "root")) + return 0.0; + + return 1.0; +} + + +static status_t +fdt_bus_register_device(device_node* parent) +{ + TRACE("+fdt_bus_register_device\n"); + struct ScopeExit { + ScopeExit() {TRACE("-fdt_bus_register_device\n");} + } scopeExit; + + device_attr attrs[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "FDT"}}, + {B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_KEEP_DRIVER_LOADED}}, + {} + }; + + return gDeviceManager->register_node( + parent, "bus_managers/fdt/root/driver_v1", attrs, NULL, NULL); +} + + +static status_t +fdt_bus_init(device_node* node, void** cookie) +{ + TRACE("fdt_bus_init\n"); + + ObjectDeleter bus(new(std::nothrow) fdt_bus()); + if (!bus.IsSet()) + return B_NO_MEMORY; + + bus->node = node; + *cookie = bus.Detach(); + return B_OK; +} + + +static void +fdt_bus_uninit(void* cookie) +{ + TRACE("fdt_bus_uninit\n"); + + ObjectDeleter bus((fdt_bus*)cookie); +} + + +static status_t +fdt_bus_register_child_devices(void* cookie) +{ + TRACE("fdt_bus_register_child_devices\n"); + + fdt_bus* bus = (fdt_bus*)cookie; + + int node = -1, depth = -1; + node = fdt_next_node(gFDT, node, &depth); + fdt_traverse(bus, node, depth, bus->node); + + return B_OK; +} + + +device_node* +fdt_bus_node_by_phandle(fdt_bus* bus, int phandle) +{ + ASSERT(bus != NULL); + + device_node** devNode; + if (!bus->phandles.Get(phandle, devNode)) + return NULL; + + return *devNode; +} + + +//#pragma mark device + + +static status_t +fdt_device_std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + + return B_BAD_VALUE; +} + + +static status_t +fdt_device_init_driver(device_node* node, void** cookie) +{ + TRACE("fdt_device_init_driver()\n"); + + ObjectDeleter dev(new(std::nothrow) fdt_device()); + if (!dev.IsSet()) + return B_NO_MEMORY; + + dev->node = node; + + // get bus from parent node + DeviceNodePutter<&gDeviceManager> parent( + gDeviceManager->get_parent_node(node)); + driver_module_info* parentModule; + void* parentDev; + ASSERT(gDeviceManager->get_driver( + parent.Get(), &parentModule, &parentDev) >= B_OK); + if (parentModule == (driver_module_info*)&gDeviceModule) + dev->bus = ((fdt_device*)parentDev)->bus; + else if (parentModule == (driver_module_info*)&gBusModule) + dev->bus = parent.Get(); + else + panic("bad parent node"); + + *cookie = dev.Detach(); + return B_OK; +} + + +static void +fdt_device_uninit_driver(void* cookie) +{ + TRACE("fdt_device_uninit_driver()\n"); + ObjectDeleter dev((fdt_device*)cookie); +} + + +static status_t +fdt_device_register_child_devices(void* cookie) +{ + TRACE("fdt_device_register_child_devices()\n"); + return B_OK; +} + + +static device_node* +fdt_device_get_bus(fdt_device* dev) +{ + ASSERT(dev != NULL); + return dev->bus; +} + + +static const char* +fdt_device_get_name(fdt_device* dev) +{ + ASSERT(dev != NULL); + + uint32 fdtNode; + ASSERT(gDeviceManager->get_attr_uint32( + dev->node, "fdt/node", &fdtNode, false) >= B_OK); + + return fdt_get_name(gFDT, (int)fdtNode, NULL); +} + + +static const void* +fdt_device_get_prop(fdt_device* dev, const char* name, int* len) +{ + ASSERT(dev != NULL); + + uint32 fdtNode; + ASSERT(gDeviceManager->get_attr_uint32( + dev->node, "fdt/node", &fdtNode, false) >= B_OK); + + return fdt_getprop(gFDT, (int)fdtNode, name, len); +} + + +static bool +fdt_device_get_reg(fdt_device* dev, uint32 ord, uint64* regs, uint64* len) +{ + ASSERT(dev != NULL); + + uint32 fdtNode; + ASSERT(gDeviceManager->get_attr_uint32( + dev->node, "fdt/node", &fdtNode, false) >= B_OK); + + int propLen; + const void* prop = fdt_getprop(gFDT, (int)fdtNode, "reg", &propLen); + if (prop == NULL) + return false; + + // TODO: use '#address-cells', '#size-cells' in parent node to identify + // field sizes + + if ((ord + 1)*16 > (uint32)propLen) + return false; + + if (regs != NULL) + *regs = fdt64_to_cpu(*(((uint64*)prop) + 2*ord)); + + if (len != NULL) + *len = fdt64_to_cpu(*(((uint64*)prop) + 2*ord + 1)); + + return true; +} + + +static bool +fdt_device_get_interrupt(fdt_device* dev, uint32 ord, + device_node** interruptController, uint64* interrupt) +{ + ASSERT(dev != NULL); + + uint32 fdtNode; + ASSERT(gDeviceManager->get_attr_uint32( + dev->node, "fdt/node", &fdtNode, false) >= B_OK); + + // TODO: handle other interrupt encodings + int propLen; + const void* prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts-extended", + &propLen); + if (prop == NULL) { + prop = fdt_getprop(gFDT, (int)fdtNode, "interrupts", + &propLen); + if (prop == NULL) + return false; + + if ((ord + 1)*4 > (uint32)propLen) + return false; + + if (interrupt != NULL) + *interrupt = fdt32_to_cpu(*(((uint32*)prop) + ord)); + + if (interruptController != NULL) { + prop = fdt_getprop(gFDT, (int)fdtNode, "interrupt-parent", + &propLen); + if (prop != NULL && propLen == 4) { + uint32 phandle = fdt32_to_cpu(*(uint32*)prop); + + fdt_bus* bus; + ASSERT(gDeviceManager->get_driver( + dev->bus, NULL, (void**)&bus) >= B_OK); + + *interruptController = fdt_bus_node_by_phandle(bus, phandle); + } + } + return true; + } + + // TODO: use '#interrupt-cells' to identify field sizes + + if ((ord + 1)*8 > (uint32)propLen) + return false; + + if (interruptController != NULL) { + uint32 phandle = fdt32_to_cpu(*(((uint32*)prop) + 2*ord)); + + fdt_bus* bus; + ASSERT(gDeviceManager->get_driver( + dev->bus, NULL, (void**)&bus) >= B_OK); + + *interruptController = fdt_bus_node_by_phandle(bus, phandle); + } + + if (interrupt != NULL) + *interrupt = fdt32_to_cpu(*(((uint32*)prop) + 2*ord + 1)); + + return true; +} + + +//#pragma mark - + +fdt_bus_module_info gBusModule = { + { + { + "bus_managers/fdt/root/driver_v1", + 0, + fdt_bus_std_ops + }, + fdt_bus_supports_device, + fdt_bus_register_device, + fdt_bus_init, + fdt_bus_uninit, + fdt_bus_register_child_devices, + NULL, // rescan devices + NULL, // device removed + }, + fdt_bus_node_by_phandle, +}; + + +fdt_device_module_info gDeviceModule = { + { + { + "bus_managers/fdt/driver_v1", + 0, + fdt_device_std_ops + }, + + NULL, // supports device + NULL, // register device (our parent registered us) + fdt_device_init_driver, + fdt_device_uninit_driver, + fdt_device_register_child_devices, + NULL, // rescan devices + NULL, // device removed + }, + fdt_device_get_bus, + fdt_device_get_name, + fdt_device_get_prop, + fdt_device_get_reg, + fdt_device_get_interrupt, +}; + + +module_info* modules[] = { + (module_info*)&gBusModule, + (module_info*)&gDeviceModule, + NULL +}; + +module_dependency module_dependencies[] = { + { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager }, + { NULL } +}; diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_serial.cpp b/src/add-ons/kernel/bus_managers/fdt/fdt_serial.cpp deleted file mode 100644 index a2ba64832d..0000000000 --- a/src/add-ons/kernel/bus_managers/fdt/fdt_serial.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright 2012, François Revol, revol@free.fr. - * Distributed under the terms of the MIT License. - * - * Authors: - * François Revol, revol@free.fr - * Alexander von Gluck IV, kallisti5@unixzen.com - */ - -#include "fdt_serial.h" - -#include -#include -#include -#include -#include - -#include - -#if defined(__arm__) -#include -#endif - -extern "C" { -#include -#include -#include -}; - -#include "fdt_support.h" - - -//#define TRACE_SERIAL -#ifdef TRACE_SERIAL -# define TRACE(x...) dprintf("INIT: " x) -#else -# define TRACE(x...) ; -#endif - - -// If we dprintf before the UART is initalized there will be no output - -static DebugUART* -debug_uart_from_node(const void *fdt, int node) -{ - int len; - const void *prop; - phys_addr_t regs; - int32 clock = 0; - int32 speed = 0; - DebugUART *uart = NULL; - - if (node < 0 || fdt == NULL) - return NULL; - - // determine the MMIO address - regs = fdt_get_device_reg(fdt, node, false); - - if (regs == 0) { - TRACE("%s: FDT UART regs not found!\n", __func__); - return NULL; - } - - TRACE("serial: checking '%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); - TRACE("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); - TRACE("serial: speed %ld\n", speed); - } - - // 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 - || fdt_node_check_compatible(fdt, node, "snps,dw-apb-uart") == 0) { - TRACE("serial: Found 8250 serial UART!\n"); - uart = arch_get_uart_8250(regs, clock); - #if defined(__arm__) - } else if (fdt_node_check_compatible(fdt, node, "ti,omap3-uart") == 0 - || fdt_node_check_compatible(fdt, node, "ti,omap4-uart") == 0 - || fdt_node_check_compatible(fdt, node, "ti,omap5-uart") == 0 - || fdt_node_check_compatible(fdt, node, "ti,am3352-uart") == 0 - || fdt_node_check_compatible(fdt, node, "ti,am4372-uart") == 0 - || fdt_node_check_compatible(fdt, node, "ti,dra742-uart") == 0) { - // TODO: ti,am* and ti,dr* have some special quirks. - TRACE("serial: Found omap 8250 serial UART!\n"); - uart = arch_get_uart_8250_omap(regs, clock); - } else if (fdt_node_check_compatible(fdt, node, "arm,pl011") == 0 - || fdt_node_check_compatible(fdt, node, "arm,primecell") == 0) { - TRACE("serial: Found pl011 serial UART!\n"); - uart = arch_get_uart_pl011(regs, clock); - #endif - } - return uart; -} - - -DebugUART* -debug_uart_from_fdt(const void *fdt) -{ - int chosen_node; - int node; - int len; - const char *name; - const void *prop; - DebugUART *uart = NULL; - - if (fdt == NULL) { - TRACE("%s: No FDT found!\n", __func__); - return NULL; - } - - chosen_node = fdt_path_offset(fdt, "/chosen"); - if (chosen_node >= 0) { - prop = fdt_getprop(fdt, chosen_node, "stdout-path", &len); - if (prop && len > 0) { - node = fdt_path_offset(fdt, (const char*)prop); - uart = debug_uart_from_node(fdt, node); - } - if (uart == NULL) { - prop = fdt_getprop(fdt, chosen_node, "linux,stdout-path", &len); - if (prop && len > 0) { - node = fdt_path_offset(fdt, (const char*)prop); - uart = debug_uart_from_node(fdt, node); - } - } - - if (uart == NULL) { - // From what i've seen, stdout is generally an alias. - // we could check for "/..." in the prop, but not sure - // it's needed. If we *did* check for a prop starting - // with / we could make all three of these "the same" - prop = fdt_getprop(fdt, chosen_node, "stdout", &len); - if (prop && len > 0) { - name = fdt_get_alias(fdt, (const char*)prop); - if (name != NULL) { - node = fdt_path_offset(fdt, name); - uart = debug_uart_from_node(fdt, node); - } - } - } - - // Whoo-hoo! Bail. - if (uart != NULL) - return uart; - } - - // If we didn't find a /chosen serial device, lets search for some common aliases - char aliases[][8] = { - "serial", - "serial0", - "uart", - "uart0", - "serial1", - "serial2", - "serial3", - "uart1", - "uart2", - "uart3" - }; - - // For each known common serial alias, check it out and see if we have the - // needed driver for it. uart0 seems most common. - for (int index = 0; index < sizeof(aliases[0]) / sizeof(aliases); index++) { - name = fdt_get_alias(fdt, aliases[index]); - if (name == NULL) - continue; - - node = fdt_path_offset(fdt, name); - if (node < 0) { - TRACE("%s: FDT node not found!\n", __func__); - continue; - } - uart = debug_uart_from_node(fdt, node); - - // We found a valid serial device. bail. - if (uart != NULL) - break; - } - - // It would be nice if we had *some* communication mechanism here if uart is still - // NULL to warn the user that we couldn't find a serial port. - - return uart; -} diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_serial.h b/src/add-ons/kernel/bus_managers/fdt/fdt_serial.h deleted file mode 100644 index 18d6f98d63..0000000000 --- a/src/add-ons/kernel/bus_managers/fdt/fdt_serial.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2012-2015, Haiku, Inc. - * Distributed under the terms of the MIT License. - * - * Authors - * Alexander von Gluck IV, kallisti5@unixzen.com - */ -#ifndef __FDT_SERIAL_H -#define __FDT_SERIAL_H - - -#include -#include - - -DebugUART * debug_uart_from_fdt(const void *fdt); - - -#endif /*__FDT_SERIAL_H*/ diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_support.cpp b/src/add-ons/kernel/bus_managers/fdt/fdt_support.cpp deleted file mode 100644 index 22ec0735b3..0000000000 --- a/src/add-ons/kernel/bus_managers/fdt/fdt_support.cpp +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 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 -#include -#include -#include -#include - -extern "C" { -#include -#include -#include -}; - - -#define TRACE_FDT -#ifdef TRACE_FDT -# define TRACE(x...) dprintf(x) -#else -# 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" -#define DA depth - 1, sTabTab -#endif - - -#ifdef FDT_DUMP_PROP_VALUES -static void dump_hex(const char *data, int32 len, int depth) -{ - char str[128]; - char astr[32]; - char *p; - int l; - int i; - - for (i = 0; i < len; ) { - p = str; - l = sizeof(str); - for (; i < len && (p == str || (i % 16 != 0)); i++) { - snprintf(p, l - 1, "%02x ", data[i]); - l -= strlen(p); - p += strlen(p); - astr[i % 16] = isprint(data[i]) ? data[i] : '.'; - astr[i % 16] = isprint(data[i]) ? data[i] : '.'; - astr[(i % 16) + 1] = '\0'; - } - dprintf(DS" %-48.48s %s\n", DA, str, astr); - } -} -#endif - - -void dump_fdt(const void *fdt) -{ - int err; - - dprintf("FDT @ %p:\n", fdt); - - if (!fdt) - return; - - err = fdt_check_header(fdt); - if (err) { - dprintf("fdt error: %s\n", fdt_strerror(err)); - return; - } - - dprintf("fdt_totalsize: %d\n", fdt_totalsize(fdt)); - dprintf("fdt_off_dt_struct: %d\n", fdt_off_dt_struct(fdt)); - dprintf("fdt_off_dt_strings: %d\n", fdt_off_dt_strings(fdt)); - dprintf("fdt_off_mem_rsvmap: %d\n", fdt_off_mem_rsvmap(fdt)); - dprintf("fdt_version: %d\n", fdt_version(fdt)); - dprintf("fdt_last_comp_version: %d\n", fdt_last_comp_version(fdt)); - dprintf("fdt_boot_cpuid_phys: %d\n", fdt_boot_cpuid_phys(fdt)); - dprintf("fdt_size_dt_strings: %d\n", fdt_size_dt_strings(fdt)); - dprintf("fdt_size_dt_struct: %d\n", fdt_size_dt_struct(fdt)); - -#ifdef FDT_DUMP_NODES - dprintf("fdt tree:\n"); - - int node = -1; - int depth = 0; - while ((node = fdt_next_node(fdt, node, &depth)) >= 0) { - dprintf(DS"node at %d: '%s'\n", DA, node, - fdt_get_name(fdt, node, NULL)); -#ifdef FDT_DUMP_PROPS - int prop, len; - const struct fdt_property *property; - prop = fdt_first_property_offset(fdt, node); - while (prop >= 0) { - property = fdt_get_property_by_offset(fdt, prop, &len); - if (property == NULL) { - dprintf("getting prop at %d: %s\n", prop, fdt_strerror(len)); - break; - } - dprintf(DS" prop at %d: '%s', len %d\n", DA, prop, - fdt_string(fdt, fdt32_to_cpu(property->nameoff)), - fdt32_to_cpu(property->len)); -#ifdef FDT_DUMP_PROP_VALUES - dump_hex(property->data, fdt32_to_cpu(property->len), depth); -#endif - prop = fdt_next_property_offset(fdt, prop); - } -#endif - } -#endif -} - - -static uint64 -fdt_get_range_offset(const void* fdt, 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(fdt, node); - int32 examineNode = node; - uint64 pathOffset = 0x0; - - while (depth > 0) { - int len; - const void* prop; - prop = fdt_getprop(fdt, examineNode, "ranges", &len); - if (prop) { - int32 regAddressCells = 1; - int32 regSizeCells = 1; - fdt_get_cell_count(fdt, 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(fdt, examineNode); - depth = fdt_node_depth(fdt, parentNode); - examineNode = parentNode; - } - - TRACE("%s: range offset: 0x%" B_PRIx64 "\n", __func__, pathOffset); - - return pathOffset; -} - - -status_t -fdt_get_cell_count(const void* fdt, int node, - int32 &addressCells, int32 &sizeCells) -{ - // It would be nice if libfdt provided this. - - // Memory base addresses are provided in 32 or 64 bit flavors - // #address-cells and #size-cells matches the number of 32-bit 'cells' - // representing the length of the base address and size fields - - // TODO: assert !fdt || !pathOffset? - - int len; - if (node < 0) { - TRACE("%s: Invalid FDT node id provided!\n", __func__); - return B_ERROR; - } - - const void *prop; - prop = fdt_getprop(fdt, node, "#address-cells", &len); - if (prop && len == sizeof(uint32)) - addressCells = fdt32_to_cpu(*(uint32_t *)prop); - prop = fdt_getprop(fdt, node, "#size-cells", &len); - if (prop && len == sizeof(uint32)) - sizeCells = fdt32_to_cpu(*(uint32_t *)prop); - - // NOTE : Cells over 2 is possible in theory... - if (addressCells > 2 || sizeCells > 2) { - panic("%s: Unsupported FDT cell count detected.\n" - "Address Cells: %" B_PRId32 "; Size Cells: %" B_PRId32 - " (CPU > 64bit?).\n", __func__, addressCells, sizeCells); - return B_ERROR; - } - - return B_OK; -} - - -phys_addr_t -fdt_get_device_reg(const void* fdt, int node, bool physical) -{ - const void *prop = NULL; - int len; - uint64 baseDevice = 0x0; - - int32 regAddressCells = 1; - int32 regSizeCells = 1; - fdt_get_cell_count(fdt, node, regAddressCells, regSizeCells); - - // TODO: check for virtual-reg, and don't -= fdt_get_range_offset? - - // XXX: not sure #address-cells & #size-cells actually apply to virtual-reg - if (!physical) { - prop = fdt_getprop(fdt, node, "virtual-reg", &len); - if (prop != NULL) { - baseDevice = fdt32_to_cpu(*(uint32_t *)prop); - return baseDevice; - } - } - - prop = fdt_getprop(fdt, 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; - - // soc base address cells - if (regAddressCells == 2) - baseDevice = fdt64_to_cpu(*(uint64_t *)p); - else - baseDevice = fdt32_to_cpu(*(uint32_t *)p); - //p += regAddressCells; - - // subtract the range offset (X) on the parent node (ranges = X Y Z) - baseDevice -= fdt_get_range_offset(fdt, 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 void* fdt, const char* name) -{ - // Find device in FDT - 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(fdt, 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; -} - - -phys_addr_t -fdt_get_device_reg_byalias(const void* fdt, const char* 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(fdt, name); - return deviceReg; -} diff --git a/src/add-ons/kernel/bus_managers/fdt/fdt_support.h b/src/add-ons/kernel/bus_managers/fdt/fdt_support.h deleted file mode 100644 index 2202bcda9a..0000000000 --- a/src/add-ons/kernel/bus_managers/fdt/fdt_support.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2012-2015, Haiku, Inc. - * Distributed under the terms of the MIT License. - * - * Authors - * Alexander von Gluck IV, kallisti5@unixzen.com - */ -#ifndef __FDT_SUPPORT_H -#define __FDT_SUPPORT_H - - -#include - - -void dump_fdt(const void *fdt); -status_t fdt_get_cell_count(const void* fdt, int node, - int32 &addressCells, int32 &sizeCells); - -phys_addr_t fdt_get_device_reg(const void* fdt, int node, bool physical=true); -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*/