This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new c4dbabb1bb drivers/devicetree: Add a set of commonly used FDT
utilities.
c4dbabb1bb is described below
commit c4dbabb1bb176cb7a126d000a23e8a26c41b982b
Author: Stuart Ianna <[email protected]>
AuthorDate: Wed May 8 12:17:33 2024 +1000
drivers/devicetree: Add a set of commonly used FDT utilities.
---
boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c | 2 +-
boards/arm64/qemu/qemu-armv8a/src/qemu_bringup.c | 2 +-
drivers/devicetree/fdt.c | 143 ++++++++++++++++++++++-
include/nuttx/fdt.h | 114 +++++++++++++++++-
4 files changed, 254 insertions(+), 7 deletions(-)
diff --git a/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c
b/boards/arm/qemu/qemu-armv7a/src/qemu_bringup.c
index 202c44065b..0fc675a2b3 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 cc096517d1..d5fdea9342 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 b0202eb894..6aa4c8a0fb 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 8a3208b2af..004a810cec 100644
--- a/include/nuttx/fdt.h
+++ b/include/nuttx/fdt.h
@@ -28,6 +28,7 @@
#include <nuttx/config.h>
#include <stdint.h>
+#include <stdbool.h>
#include <nuttx/compiler.h>
/****************************************************************************
@@ -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 */