diff --git a/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c b/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c index 202c44065be..0fc675a2b39 100644 --- a/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c +++ b/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c @@ -70,7 +70,7 @@ static void register_virtio_devices_from_fdt(const void *fdt) break; } - addr = fdt_get_reg_base(fdt, offset); + addr = fdt_get_reg_base(fdt, offset, 0); irqnum = fdt_get_irq(fdt, offset, 1, QEMU_SPI_IRQ_BASE); if (addr > 0 && irqnum >= 0) { diff --git a/boards/arm64/qemu/qemu-armv8a/src/qemu_bringup.c b/boards/arm64/qemu/qemu-armv8a/src/qemu_bringup.c index cc096517d1e..d5fdea93423 100644 --- a/boards/arm64/qemu/qemu-armv8a/src/qemu_bringup.c +++ b/boards/arm64/qemu/qemu-armv8a/src/qemu_bringup.c @@ -70,7 +70,7 @@ static void register_virtio_devices_from_fdt(const void *fdt) break; } - addr = fdt_get_reg_base(fdt, offset); + addr = fdt_get_reg_base(fdt, offset, 0); irqnum = fdt_get_irq(fdt, offset, 1, QEMU_SPI_IRQ_BASE); if (addr > 0 && irqnum >= 0) { diff --git a/drivers/devicetree/fdt.c b/drivers/devicetree/fdt.c index b0202eb8947..6aa4c8a0fb8 100644 --- a/drivers/devicetree/fdt.c +++ b/drivers/devicetree/fdt.c @@ -122,15 +122,41 @@ uintptr_t fdt_ld_by_cells(FAR const void *value, int cells) } } -uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset) +uintptr_t fdt_get_reg_base_by_name(FAR const void *fdt, int offset, + const char *reg_name) +{ + uintptr_t addr = 0; + + int reg_index + = fdt_stringlist_search(fdt, offset, "reg-names", reg_name); + if (reg_index < 0) + { + return addr; + } + + return fdt_get_reg_base(fdt, offset, reg_index); +} + +uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset, int index) { FAR const void *reg; uintptr_t addr = 0; + int reg_length; - reg = fdt_getprop(fdt, offset, "reg", NULL); + /* Register cells contain a tuple of two values */ + + index *= 2; + + reg = fdt_getprop(fdt, offset, "reg", ®_length); if (reg != NULL) { - addr = fdt_ld_by_cells(reg, fdt_get_parent_address_cells(fdt, offset)); + if ((index * sizeof(uintptr_t)) > reg_length) + { + return addr; + } + + addr = fdt_ld_by_cells(reg + index * sizeof(uintptr_t), + fdt_get_parent_address_cells(fdt, offset)); } return addr; @@ -152,6 +178,115 @@ uintptr_t fdt_get_reg_size(FAR const void *fdt, int offset) uintptr_t fdt_get_reg_base_by_path(FAR const void *fdt, FAR const char *path) { - return fdt_get_reg_base(fdt, fdt_path_offset(fdt, path)); + return fdt_get_reg_base(fdt, fdt_path_offset(fdt, path), 0); } +bool fdt_device_is_available(FAR const void *fdt, int node) +{ + const char *status = fdt_getprop(fdt, node, "status", NULL); + if (!status) + { + return true; + } + + if (!strcmp(status, "ok") || !strcmp(status, "okay")) + { + return true; + } + + return false; +} + +const char *fdt_get_node_label(FAR const void *fdt, int node) +{ + int symbols_offset; + int property_offset; + int ret; + const char *property_name; + const char *label_name; + char path_buffer[CONFIG_PATH_MAX] = + { + 0 + }; + + symbols_offset = fdt_path_offset(fdt, "/__symbols__"); + if (symbols_offset < 0) + { + return NULL; + } + + ret = fdt_get_path(fdt, node, path_buffer, sizeof(path_buffer)); + if (ret < 0) + { + return NULL; + } + + fdt_for_each_property_offset(property_offset, fdt, symbols_offset) + { + property_name = fdt_getprop_by_offset( + fdt, property_offset, &label_name, NULL); + + /* The symbols section is a list of parameters in the format + * label_name = node_path. So the value of each property needs to be + * checked with the full path found earlier. + * + */ + + if (!strncmp(property_name, path_buffer, sizeof(path_buffer))) + { + return label_name; + } + } + + return NULL; +} + +uintptr_t fdt_get_clock_frequency(FAR const void *fdt, int offset) +{ + const void *pv; + uintptr_t clock_frequency = 0; + + pv = fdt_getprop(fdt, offset, "clock-frequency", NULL); + if (!pv) + { + return clock_frequency; + } + + clock_frequency = fdt_ld_by_cells(pv, + fdt_get_parent_address_cells(fdt, + offset)); + + return clock_frequency; +} + +uintptr_t fdt_get_clock_frequency_from_clocks(FAR const void *fdt, + int offset, + int index) +{ + const fdt32_t *pv; + fdt32_t clk_phandle; + int pv_offset; + uintptr_t clock_frequency = 0; + int clk_length; + + pv = fdt_getprop(fdt, offset, "clocks", &clk_length); + if (!pv) + { + return clock_frequency; + } + + if ((index * sizeof(fdt32_t)) > clk_length) + { + return clock_frequency; + } + + clk_phandle = fdt32_ld(pv + index); + + pv_offset = fdt_node_offset_by_phandle(fdt, clk_phandle); + if (pv_offset < 0) + { + return clock_frequency; + } + + return fdt_get_clock_frequency(fdt, pv_offset); +} diff --git a/include/nuttx/fdt.h b/include/nuttx/fdt.h index 8a3208b2afa..004a810cece 100644 --- a/include/nuttx/fdt.h +++ b/include/nuttx/fdt.h @@ -28,6 +28,7 @@ #include #include +#include #include /**************************************************************************** @@ -186,6 +187,31 @@ int fdt_get_parent_size_cells(FAR const void *fdt, int offset); uintptr_t fdt_ld_by_cells(FAR const void *value, int cells); +/**************************************************************************** + * Name: fdt_get_reg_base_by_name + * + * Description: + * Get the value of the "reg" property by its offset in the "reg-names" + * property + * + * Input Parameters: + * fdt - The pointer to the raw FDT. + * offset - The offset to the node. + * reg_name - The name of the register + * + * Returned Value: + * The register address determined by its name. Returns 0 if: + * - The reg-names property doesn't exist. + * - The reg property doesn't exits. + * - The reg-names property doesn't contain the "reg_name". + * - The offset combined with the size is larger than the width of the + * "reg" field + * + ****************************************************************************/ + +uintptr_t fdt_get_reg_base_by_name(FAR const void *fdt, int offset, + const char *reg_name); + /**************************************************************************** * Name: fdt_get_reg_base * @@ -195,13 +221,14 @@ uintptr_t fdt_ld_by_cells(FAR const void *value, int cells); * Input Parameters: * fdt - The pointer to the raw FDT. * offset - The offset of the node + * index - The index of the register in the reg field. * * Return: * The base address of the register space * ****************************************************************************/ -uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset); +uintptr_t fdt_get_reg_base(FAR const void *fdt, int offset, int index); /**************************************************************************** * Name: fdt_get_reg_size @@ -238,4 +265,89 @@ uintptr_t fdt_get_reg_size(FAR const void *fdt, int offset); uintptr_t fdt_get_reg_base_by_path(FAR const void *fdt, FAR const char *path); +/**************************************************************************** + * Name: fdt_device_is_available + * + * Description: + * Test if node contains the "status" property with field set to okay or + * ok. + * + * Input Parameters: + * fdt - The pointer to the raw FDT. + * offset - The offset to the node to query. + * + * Returned Value: + * true: The node contains the status propertry, and is set to okay or + * ok. + * false: The node contains the status propertry, but it is set to + * something other than ok or okay. + * Always returns true if the node doesn't contain a status property. + * + ****************************************************************************/ + +bool fdt_device_is_available(FAR const void * fdt, int offset); + +/**************************************************************************** + * Name: fdt_get_node_label + * + * Description: + * Get the label for a given node. The device tree must be compiled with + * the -@ option in order for the symbol table to be generated. + * + * Input Parameters: + * fdt - The pointer to the raw FDT. + * offset - The offset to the node to query. + * + * Returned Value: + * Node label if found. NULL is returned if no label if found for the given + * node. + * + ****************************************************************************/ + +const char *fdt_get_node_label(FAR const void *fdt, int offset); + +/**************************************************************************** + * Name: fdt_get_clock_frequency + * + * Description: + * Get the value of the "clock-frequency" value for the given node. + * + * Input Parameters: + * fdt - The pointer to the raw FDT. + * offset - The offset to the node to query. + * + * Returned Value: + * The value of the clock-frequency property of the node. Zero is + * returned if the node doesn't contain a clock-frequency property. + * + ****************************************************************************/ + +uintptr_t fdt_get_clock_frequency(FAR const void *fdt, int offset); + +/**************************************************************************** + * Name: fdt_get_clock_frequency_from_clocks + * + * Description: + * Get the "clock-frequency" property for the given node, using the phandle + * specified in the "clocks" property + * + * Input Parameters: + * fdt - The pointer to the raw FDT. + * node - The offset to the node to query. + * offset - The offset of the phandle in the clocks property + * + * Returned Value: + * The value of the clock-frequency property of the node, following the + * specified phandle in the "clocks"' property. Returns 0 if: + * - The node doesn't have a "clocks" property + * - The offset given is larger than the length of the "clocks" property + * - The phandle specified by the "clocks" property doesn't contain a + * "clock-frequency" property. + * + ****************************************************************************/ + +uintptr_t fdt_get_clock_frequency_from_clocks(FAR const void *fdt, + int offset, + int index); + #endif /* __INCLUDE_NUTTX_FDT_H */