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", &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 */

Reply via email to