[rtems commit] libmisc/rtems-fdt: Add RTEMS FDT wrapper and shell command to libmisc.

Chris Johns chrisj at rtems.org
Sun Aug 20 01:12:46 UTC 2017


Module:    rtems
Branch:    master
Commit:    6b7efdb2ed77760e3c68c5cf450a9620a1cd6562
Changeset: http://git.rtems.org/rtems/commit/?id=6b7efdb2ed77760e3c68c5cf450a9620a1cd6562

Author:    Chris Johns <chrisj at rtems.org>
Date:      Wed Aug 16 14:22:23 2017 +1000

libmisc/rtems-fdt: Add RTEMS FDT wrapper and shell command to libmisc.

- Provide application support for handling FDT blobs in RTEMS. This
  is useful when interfacing FPGA fabrics.
- Provide a shell command to list a blob as well as provide read
  and write access to addresses in the FTB.

Closes #3099.

---

 cpukit/Makefile.am                         |    4 +
 cpukit/libmisc/Makefile.am                 |    5 +
 cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c |  639 +++++++++++++++
 cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h |   42 +
 cpukit/libmisc/rtems-fdt/rtems-fdt.c       | 1191 ++++++++++++++++++++++++++++
 cpukit/libmisc/rtems-fdt/rtems-fdt.h       |  621 +++++++++++++++
 cpukit/preinstall.am                       |    8 +
 7 files changed, 2510 insertions(+)

diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 2c2f2e5..8ccc1d4 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -218,6 +218,10 @@ include_rtems_HEADERS += libmisc/devnull/devzero.h
 ## dumpbuf
 include_rtems_HEADERS += libmisc/dumpbuf/dumpbuf.h
 
+## rtemsfdt
+include_rtems_HEADERS += libmisc/rtems-fdt/rtems-fdt.h
+include_rtems_HEADERS += libmisc/rtems-fdt/rtems-fdt-shell.h
+
 ## monitor
 include_rtems_HEADERS += libmisc/monitor/monitor.h
 
diff --git a/cpukit/libmisc/Makefile.am b/cpukit/libmisc/Makefile.am
index 6772dd1..7867829 100644
--- a/cpukit/libmisc/Makefile.am
+++ b/cpukit/libmisc/Makefile.am
@@ -66,6 +66,11 @@ EXTRA_DIST += monitor/README
 noinst_LIBRARIES += libmw-fb.a
 libmw_fb_a_SOURCES = fb/mw_print.c fb/mw_uid.c fb/fb.h fb/mw_uid.h
 
+## rtems-fdt
+noinst_LIBRARIES += librtemsfdt.a
+librtemsfdt_a_SOURCES = rtems-fdt/rtems-fdt-shell.c rtems-fdt/rtems-fdt-shell.h \
+    rtems-fdt/rtems-fdt.c rtems-fdt/rtems-fdt.h
+
 ## mouse
 noinst_LIBRARIES += libmouse.a
 libmouse_a_SOURCES = mouse/mouse_parser.c mouse/serial_mouse.c
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c
new file mode 100644
index 0000000..9412b37
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c
@@ -0,0 +1,639 @@
+/*
+ *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_fdt
+ *
+ * @brief RTEMS Flattened Device Tree Shell Command
+ *
+ * Command to play with the memory in a FDT.
+ */
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <rtems/shell.h>
+#include <rtems/rtems-fdt-shell.h>
+
+/**
+ * The type of the shell handlers we have.
+ */
+typedef int (*rtems_fdt_shell_handler) (int argc, char *argv[]);
+
+/**
+ * Table of handlers we parse to invoke the command.
+ */
+typedef struct
+{
+  const char*             name;    /**< The sub-command's name. */
+  rtems_fdt_shell_handler handler; /**< The sub-command's handler. */
+  const char*             help;    /**< The sub-command's help. */
+} rtems_fdt_shell_cmd;
+
+/**
+ * The timeout for the test loop in seconds.
+ */
+static long rtems_fdt_test_timeout = 5;
+
+/**
+ * The FDT handle. Only one user of these command a time.
+ */
+static rtems_fdt_handle cmd_fdt_handle;
+
+static void
+rtems_fdt_write (uint32_t address, uint32_t value)
+{
+  volatile uint32_t* ap = (uint32_t*) address;
+  *ap = value;
+}
+
+static uint32_t
+rtems_fdt_read (uint32_t address)
+{
+  volatile uint32_t* ap = (uint32_t*) address;
+  return *ap;
+}
+
+static int
+rtems_fdt_wrong_number_of_args (void)
+{
+  printf ("error: wrong number of arguments\n");
+  return 1;
+}
+
+static int
+rtems_fdt_invalid_args (const char* arg)
+{
+  printf ("error: invalid argument: %s\n", arg);
+  return 1;
+}
+
+static int
+rtems_fdt_extra_args (const char* arg)
+{
+  printf ("error: extra argument is invalid: %s\n", arg);
+  return 1;
+}
+
+static int
+rtems_fdt_check_error (int errval, const char* message, const char* path)
+{
+  if (errval < 0)
+  {
+    if (path)
+      printf ("error: %s: %s: (%d) %s\n",
+              message, path, errval, rtems_fdt_strerror (errval));
+    else
+      printf ("error: %s: (%d) %s\n",
+              message, errval, rtems_fdt_strerror (errval));
+    return 1;
+  }
+  return 0;
+}
+
+static bool
+rtems_fdt_get_value32 (const char* path,
+                       const char* property,
+                       size_t      size,
+                       uint32_t*   value)
+{
+  const void* prop;
+  int         node;
+  int         length;
+
+  node = rtems_fdt_path_offset(&cmd_fdt_handle, path);
+  if (node < 0)
+  {
+    rtems_fdt_check_error (node, "path lookup", path);
+    return false;
+  }
+
+  prop = rtems_fdt_getprop(&cmd_fdt_handle, node, property, &length);
+  if (length < 0)
+  {
+    rtems_fdt_check_error (length, "get property", path);
+    return false;
+  }
+
+  if (length != sizeof (uint32_t))
+  {
+    printf ("error: property is not sizeof(uint32_t): %s\n", path);
+    return false;
+  }
+
+  *value = rtems_fdt_get_uint32 (prop);
+
+  return true;
+}
+
+static int
+rtems_fdt_shell_ld (int argc, char *argv[])
+{
+  if (argc != 2)
+    return rtems_fdt_wrong_number_of_args ();
+
+  return rtems_fdt_check_error (rtems_fdt_load (argv[1], &cmd_fdt_handle),
+                                "loading FTB", argv[1]);
+}
+
+static int
+rtems_fdt_shell_uld (int argc, char *argv[])
+{
+  if (argc != 2)
+    return rtems_fdt_wrong_number_of_args ();
+
+  return rtems_fdt_check_error (rtems_fdt_unload (&cmd_fdt_handle),
+                                "unloading FTB", argv[1]);
+}
+
+static int
+rtems_fdt_shell_ls (int argc, char *argv[])
+{
+  char*  path = NULL;
+  bool   recursive = false;
+  bool   long_path = false;
+  bool   debug = false;
+  int    arg = 1;
+  size_t path_len = 0;
+  int    num_entries = 0;
+  int    i = 0;
+
+  while (arg < argc)
+  {
+    if (argv[arg][0] == '-')
+    {
+      if (argv[arg][2] != 0)
+        return rtems_fdt_invalid_args (argv[arg]);
+
+      switch (argv[arg][1])
+      {
+        case 'l':
+          long_path = true;
+          break;
+        case 'r':
+          recursive = true;
+          break;
+        case 'd':
+          debug = true;
+          break;
+        default:
+          return rtems_fdt_invalid_args (argv[arg]);
+      }
+    }
+    else
+    {
+      if (path)
+        return rtems_fdt_extra_args (argv[arg]);
+      if (strcmp (argv[arg], "/") != 0)
+        path = argv[arg];
+    }
+    ++arg;
+  }
+
+  if (!path)
+  {
+    path = "";
+  }
+
+  /* Eliminate trailing slashes. */
+  path_len = strlen (path);
+
+  if (path_len > 0 && path[path_len - 1] == '/')
+      path_len--;
+
+  /* Loop through the entries, looking for matches. */
+  num_entries = rtems_fdt_num_entries(&cmd_fdt_handle);
+  printf("Total: %d\n", num_entries);
+  for (i = 0; i < num_entries; i++)
+  {
+    /* Add it to the result set. */
+    const char *name = rtems_fdt_entry_name(&cmd_fdt_handle, i);
+    size_t name_len = strlen(name);
+
+    if ((name_len > path_len) &&
+        ((strncmp (path, name, path_len) == 0) && (name[path_len] == '/')) &&
+        (recursive || (index(&name[path_len+1], '/') == 0)))
+    {
+      if (long_path)
+      {
+        printf ("%s", name);
+      }
+      else if (name_len != path_len)
+      {
+        printf ("%s", &name[path_len + 1]);
+      }
+
+      if (debug)
+      {
+        /* Get properties if we're in debug mode. */
+        int proplen = 0;
+        int offset = rtems_fdt_entry_offset(&cmd_fdt_handle, i);
+        const void *prop = rtems_fdt_getprop(&cmd_fdt_handle, offset, "reg", &proplen);
+        const void *prop2 = rtems_fdt_getprop(&cmd_fdt_handle, offset, "mask", &proplen);
+
+        if (prop)
+        {
+            printf(" addr 0x%08" PRIx32, *(uint32_t *)prop);
+        }
+
+        proplen = 0;
+        if (prop2)
+        {
+            printf(" mask 0x%08" PRIx32, *(uint32_t *)prop2);
+        }
+      }
+
+      printf("\n");
+    }
+  }
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_wr (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+  uint32_t value;
+
+  if ((argc < 3) || (argc > 4))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 3)
+  {
+    value = strtoul (argv[2], 0, 0);
+  }
+  else
+  {
+    offset = strtoul (argv[2], 0, 0);
+    value = strtoul (argv[3], 0, 0);
+  }
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  address += offset;
+
+  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 "\n", address, value);
+
+  rtems_fdt_write (address, value);
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_rd (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+
+  if ((argc < 1) || (argc > 3))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 3)
+    offset = strtoul (argv[2], 0, 0);
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  address += offset;
+
+  printf ("0x%08" PRIx32 " => 0x%08" PRIx32 "\n", address, rtems_fdt_read (address));
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_set (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+  uint32_t value;
+  int      mask_arg;
+  uint32_t mask;
+
+  if ((argc < 3) || (argc > 4))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 3)
+    mask_arg = 2;
+  else
+  {
+    offset = strtoul (argv[2], 0, 0);
+    mask_arg = 3;
+  }
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  if (isdigit (argv[mask_arg][0]))
+    mask = strtoul (argv[mask_arg], 0, 0);
+  else
+  {
+    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
+      return 1;
+  }
+
+  address += offset;
+  value = rtems_fdt_read (address);
+
+  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 " | 0x%08" PRIx32 "\n",
+          address, value | mask, value, mask);
+
+  rtems_fdt_write (address, value | mask);
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_cl (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+  uint32_t value;
+  int      mask_arg;
+  uint32_t mask;
+
+  if ((argc < 3) || (argc > 4))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 3)
+    mask_arg = 2;
+  else
+  {
+    offset = strtoul (argv[2], 0, 0);
+    mask_arg = 3;
+  }
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  if (isdigit (argv[mask_arg][0]))
+    mask = strtoul (argv[mask_arg], 0, 0);
+  else
+  {
+    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
+      return 1;
+  }
+
+  address += offset;
+  value = rtems_fdt_read (address);
+
+  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = 0x%08" PRIx32 \
+          " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")\n",
+          address, value & ~mask, value, mask, ~mask);
+
+  rtems_fdt_write (address, value & ~mask);
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_up (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+  uint32_t set;
+  uint32_t value;
+  int      mask_arg;
+  uint32_t mask;
+
+  if ((argc < 4) || (argc > 5))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 4)
+    mask_arg = 2;
+  else
+  {
+    offset = strtoul (argv[2], 0, 0);
+    mask_arg = 3;
+  }
+
+  set = strtoul (argv[mask_arg + 1], 0, 0);
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  if (isdigit (argv[mask_arg][0]))
+    mask = strtoul (argv[mask_arg], 0, 0);
+  else
+  {
+    if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
+      return 1;
+  }
+
+  address += offset;
+  value = rtems_fdt_read (address);
+
+  printf ("0x%08" PRIx32 " <= 0x%08" PRIx32 " = (0x%08" PRIx32 \
+          " & ~0x%08" PRIx32 " (0x%08" PRIx32 ")) | 0x%08" PRIx32 "\n",
+          address, (value & ~mask) | set, value, mask, ~mask, set);
+
+  rtems_fdt_write (address, (value & ~mask) | set);
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_tst (int argc, char *argv[])
+{
+  uint32_t address;
+  uint32_t offset = 0;
+  uint32_t test;
+  uint32_t value = 0;
+  int      mask_arg;
+  uint32_t mask;
+  time_t   start;
+
+  if ((argc < 4) || (argc > 5))
+    return rtems_fdt_wrong_number_of_args ();
+
+  if (argc == 4)
+    mask_arg = 2;
+  else
+  {
+    offset = strtoul (argv[2], 0, 0);
+    mask_arg = 3;
+  }
+
+  test = strtoul (argv[mask_arg + 1], 0, 0);
+
+  if (!rtems_fdt_get_value32 (argv[1], "reg", sizeof (uint32_t), &address))
+    return 1;
+
+  if (isdigit (argv[mask_arg][0]))
+    mask = strtoul (argv[mask_arg], 0, 0);
+  else
+  {
+     if (!rtems_fdt_get_value32 (argv[mask_arg], "mask", sizeof (uint32_t), &mask))
+      return 1;
+  }
+
+  address += offset;
+
+  start = time (NULL);
+
+  printf ("0x%08" PRIx32 " => (value & 0x%08" PRIx32 ") == 0x%08" PRIx32 \
+          " for %" PRIu32 " seconds\n",
+          address, mask, test, rtems_fdt_test_timeout);
+
+  while ((time (NULL) - start) < rtems_fdt_test_timeout)
+  {
+    int i;
+    for (i = 0; i < 10000; ++i)
+    {
+      value = rtems_fdt_read (address);
+      if ((value & mask) == test)
+        return 0;
+    }
+  }
+
+  printf ("0x%08" PRIx32 " => 0x%08" PRIx32 ": timeout\n", address, value);
+
+  return 1;
+}
+
+static int
+rtems_fdt_shell_nap (int argc, char *argv[])
+{
+  uint32_t time;
+
+  if (argc != 2)
+    return rtems_fdt_wrong_number_of_args ();
+
+  time = strtoul (argv[1], 0, 0);
+
+  if (time == 0)
+  {
+    printf ("error: 0 is not a valid time; check you have a valid number.\n");
+    return 1;
+  }
+
+  usleep (time * 1000);
+
+  return 0;
+}
+
+static int
+rtems_fdt_shell_to (int argc, char *argv[])
+{
+  uint32_t to;
+
+  if (argc == 1)
+  {
+    printf ("timeout: %" PRIu32 " seconds\n", rtems_fdt_test_timeout);
+    return 0;
+  }
+
+  if (argc != 2)
+    return rtems_fdt_wrong_number_of_args ();
+
+  to = strtoul (argv[1], 0, 0);
+
+  if (to == 0)
+  {
+    printf ("error: 0 is not a valid timeout; check you have a number.\n");
+    return 1;
+  }
+
+  rtems_fdt_test_timeout = to;
+
+  return 0;
+}
+
+static void
+rtems_fdt_shell_usage (const char* arg)
+{
+  printf ("%s: FDT Help\n", arg);
+  printf ("  %s [-hl] <command>\n", arg);
+  printf ("   where:\n");
+  printf ("     command: The FDT subcommand. See -l for a list plus help.\n");
+  printf ("     -h:      This help\n");
+  printf ("     -l:      The command list.\n");
+}
+
+static const rtems_fdt_shell_cmd table[] =
+{
+  { "ld",  rtems_fdt_shell_ld,  "<filename> : Load a FDT blob" },
+  { "uld", rtems_fdt_shell_uld, "Uload an FDT blob" },
+  { "ls",  rtems_fdt_shell_ls,  "<path> : List the nodes at the path and optionally below" },
+  { "wr",  rtems_fdt_shell_wr,  "<path> [<offset>] <value> : Write the value." },
+  { "rd",  rtems_fdt_shell_rd,  "<path> [<offset>] : Read the value." },
+  { "set", rtems_fdt_shell_set, "<path> [<offset>] <mask> : Set the mask bits" },
+  { "cl",  rtems_fdt_shell_cl,  "<path> [<offset>] <mask> : Clear the mask bits." },
+  { "up",  rtems_fdt_shell_up,  "<path> [<offset>] <mask> <value> : Update the mask bit with value" },
+  { "tst", rtems_fdt_shell_tst, "<path> [<offset>] <mask> <value> : Testing loop for masked value." },
+  { "nap", rtems_fdt_shell_nap, "<time> : Sleep for the time period. It is in milli-seconds." },
+  { "to",  rtems_fdt_shell_to,  "<value> : Set the test timeout (seconds)" },
+};
+
+#define RTEMS_FDT_COMMANDS (sizeof (table) / sizeof (const rtems_fdt_shell_cmd))
+
+static int
+rtems_fdt_shell_command (int argc, char* argv[])
+{
+  int    arg;
+  size_t t;
+
+  for (arg = 1; arg < argc; arg++)
+  {
+    if (argv[arg][0] != '-')
+      break;
+
+    switch (argv[arg][1])
+    {
+      case 'h':
+        rtems_fdt_shell_usage (argv[0]);
+        return 0;
+      case 'l':
+        printf ("%s: commands are:\n", argv[0]);
+        for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
+          printf ("  %-3s %s\n", table[t].name, table[t].help);
+        return 0;
+      default:
+        printf ("error: unknown option: %s\n", argv[arg]);
+        return 1;
+    }
+  }
+
+  if ((argc - arg) < 1)
+    printf ("error: you need to provide a command, try %s -h\n", argv[0]);
+  else
+  {
+    for (t = 0; t < RTEMS_FDT_COMMANDS; ++t)
+    {
+      if (strncmp (argv[arg], table[t].name, strlen (argv[arg])) == 0)
+      {
+        int r = table[t].handler (argc - arg, argv + 1);
+        return r;
+      }
+    }
+    printf ("error: command not found: %s (try -h)\n", argv[arg]);
+  }
+
+  return 1;
+}
+
+void
+rtems_fdt_add_shell_command(void)
+{
+  rtems_shell_add_cmd ("fdt", "mem",
+                       "Flattened device tree", rtems_fdt_shell_command);
+}
+
+rtems_fdt_handle*
+rtems_fdt_get_shell_handle (void)
+{
+  return &cmd_fdt_handle;
+}
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h
new file mode 100644
index 0000000..74e9a44
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h
@@ -0,0 +1,42 @@
+/*
+ *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_fdt
+ *
+ * @brief RTEMS Flattened Device Tree Shell Command
+ *
+ * Support for loading, managing and accessing FDT blobs in RTEMS.
+ */
+
+#if !defined (_RTEMS_FDT_SHELL_H_)
+#define _RTEMS_FDT_SHELL_H_
+
+#include <rtems/rtems-fdt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Add a shell command to access memory and registers associated with the DTF.
+ */
+void rtems_fdt_add_shell_command (void);
+
+/**
+ * Get a pointer to the handle. You can use this to load files or register
+ * blobs and have the shell command access them.
+ */
+rtems_fdt_handle* rtems_fdt_get_shell_handle (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.c b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
new file mode 100644
index 0000000..cbdb656
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
@@ -0,0 +1,1191 @@
+/*
+ *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <libfdt.h>
+#include <zlib.h>
+
+#include <rtems/rtems-fdt.h>
+#include <rtems/libio_.h>
+
+/**
+ * An index for quick access to the FDT by name or offset.
+ */
+
+typedef struct
+{
+  const char *             name;         /**< The full path of the FDT item. */
+  int                      offset;       /**< The offset of the item in the FDT blob. */
+} rtems_fdt_index_entry;
+
+typedef struct
+{
+  int                    num_entries;    /**< The number of entries in this index. */
+  rtems_fdt_index_entry* entries;        /**< An ordered set of entries which we
+                                          *  can binary search. */
+  char*                  names;          /**< Storage allocated for all the path names. */
+} rtems_fdt_index;
+
+
+/**
+ * A blob descriptor.
+ */
+struct rtems_fdt_blob
+{
+  rtems_chain_node node;        /**< The node's link in the chain. */
+  const void*      blob;        /**< The FDT blob. */
+  const char*      name;        /**< The name of the blob. */
+  int              refs;        /**< The number of active references of the blob. */
+  rtems_fdt_index  index;       /**< The index used for quick access to items in the blob. */
+};
+
+/**
+ * The global FDT data. This structure is allocated on the heap when the first
+ * call to load a FDT blob is made and released when all blobs have been
+ * unloaded..
+ */
+typedef struct
+{
+  rtems_id            lock;     /**< The FDT lock id */
+  rtems_chain_control blobs;    /**< List if loaded blobs. */
+  const char*         paths;    /**< Search paths for blobs. */
+} rtems_fdt_data;
+
+/**
+ * Semaphore configuration to create a mutex.
+ */
+#define RTEMS_MUTEX_ATTRIBS                                           \
+  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |                          \
+   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
+
+/**
+ * The FDT data.
+ */
+static rtems_fdt_data* fdt_data;
+
+static bool
+rtems_fdt_unlock (void)
+{
+  /*
+   * Not sure any error should be returned or an assert.
+   */
+  rtems_status_code sc;
+  sc = rtems_semaphore_release (fdt_data->lock);
+  if ((sc != RTEMS_SUCCESSFUL) && (errno == 0))
+  {
+    errno = EINVAL;
+    return false;
+  }
+  return true;
+}
+
+static bool
+rtems_fdt_data_init (void)
+{
+  /*
+   * Lock the FDT. We only create a lock if a call is made. First we test if a
+   * lock is present. If one is present we lock it. If not the libio lock is
+   * locked and we then test the lock again. If not present we create the lock
+   * then release libio lock.
+   */
+  if (!fdt_data)
+  {
+    rtems_libio_lock ();
+
+    if (!fdt_data)
+    {
+      rtems_status_code sc;
+      rtems_id          lock;
+
+      /*
+       * Always in the heap.
+       */
+      fdt_data = malloc (sizeof (rtems_fdt_data));
+      if (!fdt_data)
+      {
+        errno = ENOMEM;
+        return false;
+      }
+
+      *fdt_data = (rtems_fdt_data) { 0 };
+
+      /*
+       * Create the FDT lock.
+       */
+      sc = rtems_semaphore_create (rtems_build_name ('F', 'D', 'T', ' '),
+                                   1, RTEMS_MUTEX_ATTRIBS,
+                                   RTEMS_NO_PRIORITY, &lock);
+      if (sc != RTEMS_SUCCESSFUL)
+      {
+        free (fdt_data);
+        return false;
+      }
+
+      sc = rtems_semaphore_obtain (lock, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+      if (sc != RTEMS_SUCCESSFUL)
+      {
+        rtems_semaphore_delete (lock);
+        free (fdt_data);
+        return false;
+      }
+
+      fdt_data->lock = lock;
+
+      /*
+       * Initialise the blob list.
+       */
+      rtems_chain_initialize_empty (&fdt_data->blobs);
+    }
+
+    rtems_libio_unlock ();
+
+    rtems_fdt_unlock ();
+  }
+
+  return true;
+}
+
+static rtems_fdt_data*
+rtems_fdt_lock (void)
+{
+  rtems_status_code sc;
+
+  if (!rtems_fdt_data_init ())
+    return NULL;
+
+  sc = rtems_semaphore_obtain (fdt_data->lock,
+                               RTEMS_WAIT, RTEMS_NO_TIMEOUT);
+  if (sc != RTEMS_SUCCESSFUL)
+  {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  return fdt_data;
+}
+
+/**
+ * Create an index based on the contents of an FDT blob.
+ */
+static int
+rtems_fdt_init_index (rtems_fdt_handle* fdt, rtems_fdt_blob* blob)
+{
+  rtems_fdt_index_entry* entries = NULL;
+  int                    num_entries = 0;
+  int                    entry = 0;
+  size_t                 total_name_memory = 0;
+  char                   node_path[256];
+  int                    depth_path[32];
+  int                    start_offset = 0;
+  int                    start_depth = 0;
+  int                    offset = 0;
+  int                    depth = 0;
+  char*                  names = NULL;
+  char*                  names_pos = NULL;
+
+  /*
+   * Count the number of entries in the blob first.
+   */
+  memset(&node_path, 0, sizeof(node_path));
+  strcpy(node_path, "/");
+  depth_path[0] = strlen(node_path);
+
+  start_offset = fdt_path_offset(fdt->blob->blob, node_path);
+  if (start_offset < 0)
+  {
+    return start_offset;
+  }
+
+  start_offset = fdt_next_node(fdt->blob->blob, start_offset, &start_depth);
+  if (start_offset < 0)
+  {
+    return start_offset;
+  }
+
+  offset = start_offset;
+  depth = start_depth;
+
+  while (depth > 0)
+  {
+    /*
+     * Construct the node path name.
+     */
+    int         namelen = 0;
+    const char* name = fdt_get_name(blob->blob, offset, &namelen);
+    strncpy(&node_path[depth_path[depth-1]],
+            name,
+            sizeof(node_path) - depth_path[depth-1] - 1);
+
+    total_name_memory += strlen(node_path) + 1;
+    num_entries++;
+
+    if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
+    {
+      strcpy(&node_path[depth_path[depth-1] + namelen], "/");
+    }
+
+    depth_path[depth] = depth_path[depth-1] + namelen + 1;
+
+    /*
+     * Get the next node.
+     */
+    offset = fdt_next_node(fdt->blob->blob, offset, &depth);
+    if (offset < 0)
+    {
+      return offset;
+    }
+  }
+
+  /*
+   * Create the index.
+   */
+  entries = calloc(num_entries, sizeof(rtems_fdt_index_entry));
+  if (!entries)
+  {
+    return -RTEMS_FDT_ERR_NO_MEMORY;
+  }
+
+  names = calloc(1, total_name_memory);
+  if (!entries)
+  {
+    free(entries);
+    return -RTEMS_FDT_ERR_NO_MEMORY;
+  }
+
+  /*
+   * Populate the index.
+   */
+  offset = start_offset;
+  depth = start_depth;
+  entry = 0;
+  names_pos = names;
+
+  while (depth > 0)
+  {
+    /*
+     * Record this node in an entry.
+     */
+    int         namelen = 0;
+    const char* name = fdt_get_name(blob->blob, offset, &namelen);
+    strncpy(&node_path[depth_path[depth-1]],
+            name,
+            sizeof(node_path) - depth_path[depth-1] - 1);
+    strcpy(names_pos, node_path);
+
+    entries[entry].name = names_pos;
+    entries[entry].offset = offset;
+
+    names_pos += strlen(node_path) + 1;
+    entry++;
+
+    if (depth_path[depth-1] + namelen + 2 <= (int)sizeof(node_path))
+    {
+      strcpy(&node_path[depth_path[depth-1] + namelen], "/");
+    }
+
+    depth_path[depth] = depth_path[depth-1] + namelen + 1;
+
+    /*
+     * Get the next node.
+     */
+    offset = fdt_next_node(fdt->blob->blob, offset, &depth);
+    if (offset < 0)
+    {
+      free(entries);
+      free(names);
+      return offset;
+    }
+  }
+
+  fdt->blob->index.entries = entries;
+  fdt->blob->index.num_entries = num_entries;
+  fdt->blob->index.names = names;
+
+  return 0;
+}
+
+/**
+ * Release the contents of the index, freeing memory.
+ */
+static void
+rtems_fdt_release_index (rtems_fdt_index* index)
+{
+  if (index->entries)
+  {
+    free(index->entries);
+    free(index->names);
+
+    index->num_entries = 0;
+    index->entries = NULL;
+    index->names = NULL;
+  }
+}
+
+/**
+ * For a given FDT path, find the corresponding offset.
+ * Returns -1 if not found;
+ */
+static int
+rtems_fdt_index_find_by_name(rtems_fdt_index* index,
+                             const char*      name)
+{
+  int         min = 0;
+  int         max = index->num_entries;
+  char        path[256];
+  const char* cmp_name = name;
+
+  /*
+   * Handle trailing slash case.
+   */
+  int namelen = strlen(name);
+  if (namelen > 0 && name[namelen-1] == '/')
+  {
+    namelen--;
+
+    if (namelen >= (int)sizeof(path) - 1)
+    {
+      namelen = sizeof(path) - 1;
+    }
+
+    strncpy(path, name, namelen);
+    path[namelen] = 0;
+    cmp_name = path;
+  }
+
+  /* Binary search for the name. */
+  while (min < max)
+  {
+    int middle = (min + max) / 2;
+    int cmp = strcmp(cmp_name, index->entries[middle].name);
+    if (cmp < 0)
+    {
+      /* Look lower than here. */
+      max = middle;
+    }
+    else if (cmp > 0)
+    {
+      /* Look higher than here. */
+      min = middle + 1;
+    }
+    else
+    {
+      /* Found it. */
+      return index->entries[middle].offset;
+    }
+  }
+
+  /* Didn't find it. */
+  return -FDT_ERR_NOTFOUND;
+}
+
+/**
+ * For a given FDT offset, find the corresponding path name.
+ */
+static const char *
+rtems_fdt_index_find_name_by_offset(rtems_fdt_index* index,
+                                    int              offset)
+{
+  int min = 0;
+  int max = index->num_entries;
+
+  /*
+   * Binary search for the offset.
+   */
+  while (min < max)
+  {
+    int middle = (min + max) / 2;
+    if (offset < index->entries[middle].offset)
+    {
+      /* Look lower than here. */
+      max = middle;
+    }
+    else if (offset > index->entries[middle].offset)
+    {
+      /* Look higher than here. */
+      min = middle + 1;
+    }
+    else
+    {
+      /* Found it. */
+      return index->entries[middle].name;
+    }
+  }
+
+  /* Didn't find it. */
+  return NULL;
+}
+
+void
+rtems_fdt_init_handle (rtems_fdt_handle* handle)
+{
+  if (handle)
+    handle->blob = NULL;
+}
+
+void
+rtems_fdt_dup_handle (rtems_fdt_handle* from, rtems_fdt_handle* to)
+{
+  if (from && to)
+  {
+    (void) rtems_fdt_lock ();
+    to->blob = from->blob;
+    ++to->blob->refs;
+    rtems_fdt_unlock ();
+  }
+}
+
+void
+rtems_fdt_release_handle (rtems_fdt_handle* handle)
+{
+  if (handle && handle->blob)
+  {
+    rtems_fdt_data*   fdt;
+    rtems_chain_node* node;
+
+    fdt = rtems_fdt_lock ();
+
+    node = rtems_chain_first (&fdt->blobs);
+
+    while (!rtems_chain_is_tail (&fdt->blobs, node))
+    {
+      rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
+      if (handle->blob == blob)
+      {
+        if (blob->refs)
+          --blob->refs;
+        break;
+      }
+      node = rtems_chain_next (node);
+    }
+
+    rtems_fdt_unlock ();
+
+    handle->blob = NULL;
+  }
+}
+
+bool
+rtems_fdt_valid_handle (const rtems_fdt_handle* handle)
+{
+  if (handle && handle->blob)
+  {
+    rtems_fdt_data*   fdt;
+    rtems_chain_node* node;
+
+    fdt = rtems_fdt_lock ();
+
+    node = rtems_chain_first (&fdt->blobs);
+
+    while (!rtems_chain_is_tail (&fdt->blobs, node))
+    {
+      rtems_fdt_blob* blob = (rtems_fdt_blob*) node;
+      if (handle->blob == blob)
+      {
+        rtems_fdt_unlock ();
+        return true;
+      }
+      node = rtems_chain_next (node);
+    }
+
+    rtems_fdt_unlock ();
+  }
+
+  return false;
+}
+
+int
+rtems_fdt_find_path_offset (rtems_fdt_handle* handle, const char* path)
+{
+  rtems_fdt_data*   fdt;
+  rtems_chain_node* node;
+
+  rtems_fdt_release_handle (handle);
+
+  fdt = rtems_fdt_lock ();
+
+  node = rtems_chain_first (&fdt->blobs);
+
+  while (!rtems_chain_is_tail (&fdt->blobs, node))
+  {
+    rtems_fdt_handle temp_handle;
+    int              offset;
+
+    temp_handle.blob = (rtems_fdt_blob*) node;
+
+    offset = rtems_fdt_path_offset (&temp_handle, path);
+
+    if (offset >= 0)
+    {
+      ++temp_handle.blob->refs;
+      handle->blob = temp_handle.blob;
+      rtems_fdt_unlock ();
+      return offset;
+    }
+
+    node = rtems_chain_next (node);
+  }
+
+  rtems_fdt_unlock ();
+
+  return -FDT_ERR_NOTFOUND;
+}
+
+int
+rtems_fdt_load (const char* filename, rtems_fdt_handle* handle)
+{
+  rtems_fdt_data* fdt;
+  rtems_fdt_blob* blob;
+  size_t          bsize;
+  int             bf;
+  ssize_t         r;
+  size_t          name_len;
+  int             fe;
+  struct stat     sb;
+  uint8_t         gzip_id[2];
+  uint8_t*        cdata;
+  size_t          size;
+
+  rtems_fdt_release_handle (handle);
+
+  if (stat (filename, &sb) < 0)
+  {
+    return -RTEMS_FDT_ERR_NOT_FOUND;
+  }
+
+  bf = open(filename, O_RDONLY);
+  if (bf < 0)
+  {
+    return -RTEMS_FDT_ERR_READ_FAIL;
+  }
+
+  r = read(bf, &gzip_id, sizeof(gzip_id));
+  if (r < 0)
+  {
+    close(bf);
+    return -RTEMS_FDT_ERR_READ_FAIL;
+  }
+
+  if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
+  {
+    size_t offset;
+
+    cdata = malloc(sb.st_size);
+    if (!cdata)
+    {
+      close (bf);
+      return -RTEMS_FDT_ERR_NO_MEMORY;
+    }
+
+    if (lseek(bf, 0, SEEK_SET) < 0)
+    {
+      free(cdata);
+      close(bf);
+      return -RTEMS_FDT_ERR_READ_FAIL;
+    }
+
+    size = sb.st_size;
+    offset = 0;
+    while (size)
+    {
+      r = read(bf, cdata + offset, size);
+      if (r < 0)
+      {
+        free(cdata);
+        close(bf);
+        return -RTEMS_FDT_ERR_READ_FAIL;
+      }
+      size -= r;
+      offset += r;
+    }
+
+    offset = sb.st_size - 4;
+    bsize = ((cdata[offset + 3] << 24) | (cdata[offset + 2] << 16) |
+             (cdata[offset + 1] << 8) | cdata[offset + 0]);
+  }
+  else
+  {
+    cdata = NULL;
+    bsize = sb.st_size;
+  }
+
+  name_len = strlen (filename) + 1;
+
+  blob = malloc(sizeof (rtems_fdt_blob) + name_len + bsize);
+  if (!blob)
+  {
+    free(cdata);
+    close (bf);
+    return -RTEMS_FDT_ERR_NO_MEMORY;
+  }
+
+  blob->name = (const char*) (blob + 1);
+  blob->blob = blob->name + name_len + 1;
+
+  strcpy ((char*) blob->name, filename);
+
+  if ((gzip_id[0] == 0x1f) && (gzip_id[1] == 0x8b))
+  {
+    z_stream stream;
+    int      err;
+    stream.next_in = (Bytef*) cdata;
+    stream.avail_in = (uInt) sb.st_size;
+    stream.next_out = (void*) (blob->name + name_len + 1);
+    stream.avail_out = (uInt) bsize;
+    stream.zalloc = (alloc_func) 0;
+    stream.zfree = (free_func) 0;
+    err = inflateInit(&stream);
+    if (err == Z_OK)
+      err = inflateReset2(&stream, 31);
+    if (err == Z_OK)
+      err = inflate(&stream, Z_FINISH);
+    if ((err == Z_OK) || (err == Z_STREAM_END))
+      err = inflateEnd(&stream);
+    if ((err != Z_OK) || (bsize != stream.total_out))
+    {
+      free (blob);
+      free(cdata);
+      close (bf);
+      return -RTEMS_FDT_ERR_READ_FAIL;
+    }
+    free(cdata);
+    cdata = NULL;
+  }
+  else
+  {
+    char* buf = (char*) blob->name + name_len + 1;
+    size = bsize;
+    while (size)
+    {
+      r = read (bf, buf, size);
+      if (r < 0)
+      {
+        free (blob);
+        close (bf);
+        return -RTEMS_FDT_ERR_READ_FAIL;
+      }
+      r -= size;
+      buf += r;
+    }
+  }
+
+  fe = fdt_check_header(blob->blob);
+  if (fe < 0)
+  {
+    free (blob);
+    close (bf);
+    return fe;
+  }
+
+  fdt = rtems_fdt_lock ();
+
+  rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
+
+  blob->refs = 1;
+
+  rtems_fdt_unlock ();
+
+  handle->blob = blob;
+
+  fe = rtems_fdt_init_index(handle, blob);
+  if (fe < 0)
+  {
+    free (blob);
+    close (bf);
+    return fe;
+  }
+
+  return 0;
+}
+
+int
+rtems_fdt_register (const void* dtb, rtems_fdt_handle* handle)
+{
+  rtems_fdt_data* fdt;
+  rtems_fdt_blob* blob;
+  int             fe;
+
+  rtems_fdt_release_handle (handle);
+
+  fe = fdt_check_header(dtb);
+  if (fe < 0)
+  {
+    return fe;
+  }
+
+  blob = malloc(sizeof (rtems_fdt_blob));
+  if (!blob)
+  {
+    return -RTEMS_FDT_ERR_NO_MEMORY;
+  }
+
+  blob->blob = dtb;
+  blob->name = NULL;
+  fdt = rtems_fdt_lock ();
+
+  rtems_chain_append_unprotected (&fdt->blobs, &blob->node);
+
+  blob->refs = 1;
+
+  rtems_fdt_unlock ();
+
+  handle->blob = blob;
+
+  fe = rtems_fdt_init_index(handle, blob);
+  if (fe < 0)
+  {
+    free(blob);
+    return -RTEMS_FDT_ERR_NO_MEMORY;
+  }
+
+  return 0;
+}
+
+int
+rtems_fdt_unload (rtems_fdt_handle* handle)
+{
+  (void) rtems_fdt_lock ();
+
+  if (!rtems_fdt_valid_handle (handle))
+  {
+    rtems_fdt_unlock ();
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  }
+
+  if (handle->blob->refs > 1)
+  {
+    rtems_fdt_unlock ();
+    return -RTEMS_FDT_ERR_REFERENCED;
+  }
+
+  rtems_chain_extract_unprotected (&handle->blob->node);
+
+  free (handle->blob);
+
+  handle->blob = NULL;
+
+  rtems_fdt_unlock ();
+
+  rtems_fdt_release_index(&handle->blob->index);
+
+  return 0;
+}
+
+int
+rtems_fdt_num_mem_rsv (rtems_fdt_handle* handle)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_num_mem_rsv (handle->blob->blob);
+}
+
+int
+rtems_fdt_get_mem_rsv (rtems_fdt_handle* handle,
+                       int               n,
+                       uint64_t*         address,
+                       uint64_t*         size)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_get_mem_rsv (handle->blob->blob, n, address, size);
+}
+
+int
+rtems_fdt_subnode_offset_namelen (rtems_fdt_handle* handle,
+                                  int               parentoffset,
+                                  const char*       name,
+                                  int               namelen)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_subnode_offset_namelen (handle->blob->blob,
+                                     parentoffset,
+                                     name,
+                                     namelen);
+}
+
+int
+rtems_fdt_subnode_offset (rtems_fdt_handle* handle,
+                          int               parentoffset,
+                          const char*       name)
+{
+  char full_name[256];
+  const char *path;
+
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+
+  path = rtems_fdt_index_find_name_by_offset(&handle->blob->index, parentoffset);
+  snprintf(full_name, sizeof(full_name), "%s/%s", path, name);
+
+  return rtems_fdt_index_find_by_name(&handle->blob->index, full_name);
+}
+
+int
+rtems_fdt_path_offset (rtems_fdt_handle* handle, const char* path)
+{
+  return rtems_fdt_index_find_by_name(&handle->blob->index, path);
+}
+
+const char*
+rtems_fdt_get_name (rtems_fdt_handle* handle, int nodeoffset, int* length)
+{
+  if (!handle->blob)
+    return NULL;
+
+  const char *name = rtems_fdt_index_find_name_by_offset(&handle->blob->index, nodeoffset);
+  if (name && length)
+  {
+    *length = strlen(name);
+  }
+
+  return name;
+}
+
+const void*
+rtems_fdt_getprop_namelen (rtems_fdt_handle* handle,
+                           int               nodeoffset,
+                           const char*       name,
+                           int               namelen,
+                           int*              length)
+{
+  if (!handle->blob)
+    return NULL;
+  return fdt_getprop_namelen (handle->blob->blob,
+                              nodeoffset,
+                              name,
+                              namelen,
+                              length);
+}
+
+const void*
+rtems_fdt_getprop (rtems_fdt_handle* handle,
+                   int               nodeoffset,
+                   const char*       name,
+                   int*              length)
+{
+  if (!handle->blob)
+    return NULL;
+  return fdt_getprop (handle->blob->blob,
+                      nodeoffset,
+                      name,
+                      length);
+}
+
+uint32_t
+rtems_fdt_get_phandle (rtems_fdt_handle* handle, int nodeoffset)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_get_phandle (handle->blob->blob, nodeoffset);
+}
+
+const char*
+rtems_fdt_get_alias_namelen (rtems_fdt_handle* handle,
+                             const char*       name,
+                             int               namelen)
+{
+  if (!handle->blob)
+    return NULL;
+  return fdt_get_alias_namelen (handle->blob->blob, name, namelen);
+}
+
+const char*
+rtems_fdt_get_alias (rtems_fdt_handle* handle, const char* name)
+{
+  if (!handle->blob)
+    return NULL;
+  return fdt_get_alias (handle->blob->blob, name);
+}
+
+int
+rtems_fdt_get_path (rtems_fdt_handle* handle,
+                    int               nodeoffset,
+                    char*             buf,
+                    int               buflen)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_get_path (handle->blob->blob, nodeoffset, buf, buflen);
+}
+
+int
+rtems_fdt_supernode_atdepth_offset (rtems_fdt_handle* handle,
+                                    int               nodeoffset,
+                                    int               supernodedepth,
+                                    int*              nodedepth)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_supernode_atdepth_offset(handle,
+                                      nodeoffset,
+                                      supernodedepth,
+                                      nodedepth);
+}
+
+int
+rtems_fdt_node_depth (rtems_fdt_handle* handle, int nodeoffset)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_node_depth (handle->blob->blob, nodeoffset);
+}
+
+int
+rtems_fdt_parent_offset (rtems_fdt_handle* handle, int nodeoffset)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_parent_offset (handle->blob->blob, nodeoffset);
+}
+
+int
+rtems_fdt_node_offset_by_prop_value (rtems_fdt_handle* handle,
+                                     int               startoffset,
+                                     const char*       propname,
+                                     const void*       propval,
+                                     int               proplen)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_node_offset_by_prop_value (handle,
+                                        startoffset,
+                                        propname,
+                                        propval,
+                                        proplen);
+}
+
+int
+rtems_fdt_node_offset_by_phandle (rtems_fdt_handle* handle, uint32_t phandle)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_node_offset_by_phandle (handle->blob->blob, phandle);
+}
+
+int
+rtems_fdt_node_check_compatible (rtems_fdt_handle* handle,
+                                 int               nodeoffset,
+                                 const char*       compatible)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_node_check_compatible (handle, nodeoffset, compatible);
+}
+
+int
+rtems_fdt_node_offset_by_compatible (rtems_fdt_handle* handle,
+                                     int               startoffset,
+                                     const char*       compatible)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_node_offset_by_compatible (handle->blob->blob,
+                                        startoffset,
+                                        compatible);
+}
+
+int
+rtems_fdt_next_node (rtems_fdt_handle* handle, int offset, int* depth)
+{
+  if (!handle->blob)
+    return -RTEMS_FDT_ERR_INVALID_HANDLE;
+  return fdt_next_node (handle->blob->blob, offset, depth);
+}
+
+const char*
+rtems_fdt_strerror (int errval)
+{
+  const char* errors[] = {
+    "invalid handle",
+    "no memory",
+    "file not found",
+    "DTB read fail",
+    "blob has references"
+  };
+  if (errval > -RTEMS_FDT_ERR_RTEMS_MIN)
+    return fdt_strerror (errval);
+  if (errval < -RTEMS_FDT_ERR_MAX)
+    return "invalid error code";
+  return errors[(-errval) - RTEMS_FDT_ERR_RTEMS_MIN];
+}
+
+int
+rtems_fdt_prop_value(const char* const path,
+                     const char* const propname,
+                     void*             value,
+                     size_t*           size)
+{
+  rtems_fdt_handle fdt;
+  int              node;
+  const void*      prop;
+  int              length;
+
+  rtems_fdt_init_handle (&fdt);
+
+  node = rtems_fdt_find_path_offset (&fdt, path);
+  if (node < 0)
+    return node;
+
+  prop = rtems_fdt_getprop(&fdt, node, propname, &length);
+  if (length < 0)
+  {
+    rtems_fdt_release_handle (&fdt);
+    return length;
+  }
+
+  if (length > (int) *size)
+  {
+    rtems_fdt_release_handle (&fdt);
+    return RTEMS_FDT_ERR_BADPATH;
+  }
+
+  *size = length;
+
+  memcpy (value, prop, length);
+
+  return 0;
+}
+
+int
+rtems_fdt_prop_map(const char* const path,
+                   const char* const propname,
+                   const char* const names[],
+                   uint32_t*         values,
+                   size_t            count)
+{
+  rtems_fdt_handle fdt;
+  int              node;
+  size_t           item;
+
+  rtems_fdt_init_handle (&fdt);
+
+  node = rtems_fdt_find_path_offset (&fdt, path);
+  if (node < 0)
+    return node;
+
+  for (item = 0; item < count; item++)
+  {
+    const void*    prop;
+    const uint8_t* p;
+    int            length;
+    int            subnode;
+
+    subnode = rtems_fdt_subnode_offset (&fdt, node, names[item]);
+    if (subnode < 0)
+    {
+      rtems_fdt_release_handle (&fdt);
+      return subnode;
+    }
+
+    prop = rtems_fdt_getprop(&fdt, subnode, propname, &length);
+    if (length < 0)
+    {
+      rtems_fdt_release_handle (&fdt);
+      return length;
+    }
+
+    if (length != sizeof (uint32_t))
+    {
+      rtems_fdt_release_handle (&fdt);
+      return RTEMS_FDT_ERR_BADPATH;
+    }
+
+    p = prop;
+
+    values[item] = ((((uint32_t) p[0]) << 24) |
+                    (((uint32_t) p[1]) << 16) |
+                    (((uint32_t) p[2]) << 8)  |
+                    (uint32_t) p[3]);
+  }
+
+  return 0;
+}
+
+uint32_t
+rtems_fdt_get_uint32 (const void* prop)
+{
+  const uint8_t* p = prop;
+  uint32_t       value;
+  value = ((((uint32_t) p[0]) << 24) |
+           (((uint32_t) p[1]) << 16) |
+           (((uint32_t) p[2]) << 8)  |
+           (uint32_t) p[3]);
+  return value;
+}
+
+int
+rtems_fdt_get_value (const char* path,
+                     const char* property,
+                     size_t      size,
+                     uint32_t*   value)
+{
+  rtems_fdt_handle fdt;
+  const void*      prop;
+  int              node;
+  int              length;
+
+  rtems_fdt_init_handle (&fdt);
+
+  node = rtems_fdt_find_path_offset (&fdt, path);
+  if (node < 0)
+  {
+    rtems_fdt_release_handle (&fdt);
+    return node;
+  }
+
+  prop = rtems_fdt_getprop(&fdt, node, property, &length);
+  if (length < 0)
+  {
+    rtems_fdt_release_handle (&fdt);
+    return length;
+  }
+
+  if (length == sizeof (uint32_t))
+    *value = rtems_fdt_get_uint32 (prop);
+  else
+    *value = 0;
+
+  rtems_fdt_release_handle (&fdt);
+
+  return 0;
+}
+
+/**
+ * Get the number of entries in an FDT handle.
+ */
+int
+rtems_fdt_num_entries(rtems_fdt_handle* handle)
+{
+  return handle->blob->index.num_entries;
+}
+
+/**
+ * Get the numbered entry name. Note that the id isn't the same as
+ * the offset - it's numbered 0, 1, 2 ... num_entries-1
+ */
+const char *
+rtems_fdt_entry_name(rtems_fdt_handle* handle, int id)
+{
+  return handle->blob->index.entries[id].name;
+}
+
+/**
+ * Get the numbered entry offset. Note that the id isn't the same as
+ * the offset - it's numbered 0, 1, 2 ... num_entries-1
+ */
+int
+rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id)
+{
+  return handle->blob->index.entries[id].offset;
+}
diff --git a/cpukit/libmisc/rtems-fdt/rtems-fdt.h b/cpukit/libmisc/rtems-fdt/rtems-fdt.h
new file mode 100644
index 0000000..ebc222e
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.h
@@ -0,0 +1,621 @@
+/*
+ *  COPYRIGHT (c) 2013-2017 Chris Johns <chrisj at rtems.org>
+ *
+ *  The license and distribution terms for this file may be
+ *  found in the file LICENSE in this distribution or at
+ *  http://www.rtems.org/license/LICENSE.
+ *
+ *  Interface based on the libdft:
+ *    libfdt - Flat Device Tree manipulation
+ *    Copyright (C) 2006 David Gibson, IBM Corporation.
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems_fdt
+ *
+ * @brief RTEMS Flattened Device Tree
+ *
+ * Support for loading, managing and accessing FDT blobs in RTEMS.
+ */
+
+#if !defined (_RTEMS_FDT_H_)
+#define _RTEMS_FDT_H_
+
+#include <rtems.h>
+#include <rtems/chain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * A blob.
+ */
+struct rtems_fdt_blob;
+typedef struct rtems_fdt_blob rtems_fdt_blob;
+
+/**
+ * A blob handle is a way to manage access to the FDT blobs. The blob is
+ * referenced via the handle to allow searches across loaded DTB's to return
+ * the referenced DTB.
+ */
+typedef struct
+{
+  rtems_fdt_blob* blob;  /**< The blob the handle references. */
+} rtems_fdt_handle;
+
+/*
+ * The following are mappings to the standard FDT calls.
+ */
+
+/**
+ * RTEMS_FDT_ERR_NOTFOUND: The requested node or property does not exist
+ */
+#define RTEMS_FDT_ERR_NOTFOUND  1
+/**
+ * RTEMS_FDT_ERR_EXISTS: Attemped to create a node or property which already
+ * exists */
+#define RTEMS_FDT_ERR_EXISTS    2
+/**
+ * RTEMS_FDT_ERR_NOSPACE: Operation needed to expand the device tree, but its
+ * buffer did not have sufficient space to contain the expanded tree. Use
+ * rtems_fdt_open_into() to move the device tree to a buffer with more space.
+ */
+#define RTEMS_FDT_ERR_NOSPACE    3
+
+/* Error codes: codes for bad parameters */
+/**
+ * RTEMS_FDT_ERR_BADOFFSET: Function was passed a structure block offset which
+ * is out-of-bounds, or which points to an unsuitable part of the structure for
+ * the operation.
+ */
+#define RTEMS_FDT_ERR_BADOFFSET  4
+/**
+ * RTEMS_FDT_ERR_BADPATH: Function was passed a badly formatted path
+ * (e.g. missing a leading / for a function which requires an absolute path)
+*/
+#define RTEMS_FDT_ERR_BADPATH    5
+/**
+ * RTEMS_FDT_ERR_BADPHANDLE: Function was passed an invalid phandle value.
+ * phandle values of 0 and -1 are not permitted.
+ */
+#define RTEMS_FDT_ERR_BADPHANDLE  6
+/**
+ * RTEMS_FDT_ERR_BADSTATE: Function was passed an incomplete device tree
+ * created by the sequential-write functions, which is not sufficiently
+ * complete for the requested operation.
+ */
+#define RTEMS_FDT_ERR_BADSTATE  7
+
+/* Error codes: codes for bad device tree blobs */
+
+/**
+ * RTEMS_FDT_ERR_TRUNCATED: Structure block of the given device tree ends
+ * without an RTEMS_FDT_END tag.
+ */
+#define RTEMS_FDT_ERR_TRUNCATED  8
+/**
+ * RTEMS_FDT_ERR_BADMAGIC: Given "device tree" appears not to be a device tree
+ * at all - it is missing the flattened device tree magic number.
+ */
+#define RTEMS_FDT_ERR_BADMAGIC  9
+/** RTEMS_FDT_ERR_BADVERSION: Given device tree has a version which can't be
+ * handled by the requested operation.  For read-write functions, this may mean
+ * that rtems_fdt_open_into() is required to convert the tree to the expected
+ * version.
+ */
+#define RTEMS_FDT_ERR_BADVERSION  10
+/**
+ * RTEMS_FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt structure block
+ * or other serious error (e.g. misnested nodes, or subnodes preceding
+ * properties).
+ */
+#define RTEMS_FDT_ERR_BADSTRUCTURE  11
+/**
+ * RTEMS_FDT_ERR_BADLAYOUT: For read-write functions, the given device tree has
+ * it's sub-blocks in an order that the function can't handle (memory reserve
+ * map, then structure, then strings).  Use rtems_fdt_open_into() to reorganize
+ * the tree into a form suitable for the read-write operations.
+ */
+#define RTEMS_FDT_ERR_BADLAYOUT  12
+/**
+ * "Can't happen" error indicating a bug in libfdt
+ */
+#define RTEMS_FDT_ERR_INTERNAL  13
+
+/* RTEMS error codes. */
+
+/**
+ * Invalid handle.
+ */
+#define RTEMS_FDT_ERR_INVALID_HANDLE 100
+/**
+ * No memory.
+ */
+#define RTEMS_FDT_ERR_NO_MEMORY      101
+/**
+ * File not found.
+ */
+#define RTEMS_FDT_ERR_NOT_FOUND      102
+/**
+ * Cannot read the DTB into memory.
+ */
+#define RTEMS_FDT_ERR_READ_FAIL      103
+/**
+ * The blob cannot be unloaded as it is referenced.
+ */
+#define RTEMS_FDT_ERR_REFERENCED     104
+
+#define RTEMS_FDT_ERR_RTEMS_MIN      100
+#define RTEMS_FDT_ERR_MAX            104
+
+/**
+ * Initialise a handle to a default state.
+ *
+ * @param handle The handle to initialise.
+ */
+void rtems_fdt_init_handle (rtems_fdt_handle* handle);
+
+/**
+ * Duplicate a handle. The copy must be released.
+ *
+ * @param from Duplicate from this handle.
+ * @param to   Duplicate to this handle.
+ */
+void rtems_fdt_dup_handle (rtems_fdt_handle* from, rtems_fdt_handle* to);
+
+/**
+ * Release a blob from a handle and clear it.
+ *
+ * @param handle The handle to check.
+ */
+void rtems_fdt_release_handle (rtems_fdt_handle* handle);
+
+/**
+ * Check if a handle had a valid blob assigned.
+ *
+ * @param handle The handle to check.
+ * @retval true The handle has a valid blob.
+ * @retval false The handle does not have a valid blob.
+ */
+bool rtems_fdt_valid_handle (const rtems_fdt_handle* handle);
+
+/**
+ * Find a tree node by its full path looking across of loaded blobs.. Each path
+ * component may omit the unit address portion, but the results of this are
+ * undefined if any such path component is ambiguous (that is if there are
+ * multiple nodes at the relevant level matching the given component,
+ * differentiated only by unit address).
+ *
+ * If the handle points to a valid blob it is release and the search starts
+ * from the first blob.
+ *
+ * @param handle The FDT handle assigned to the blob if found else left invalid.
+ * @param path Full path of the node to locate.
+ * @param int If less than 0 an error code else the node offset is returned.
+ */
+int rtems_fdt_find_path_offset (rtems_fdt_handle* handle, const char* path);
+
+/**
+ * Load a device tree blob or DTB file into memory and register it on the chain
+ * of blobs.
+ *
+ * @param filename The name of the blob file to load.
+ * @param handle The handle returns the reference to the blob once load.
+ * @return int If less than 0 it is an error code else it is the blob descriptor.
+ */
+int rtems_fdt_load (const char* const filename, rtems_fdt_handle* handle);
+
+/**
+ * Register a device tree blob or DTB on to the chain of blobs.
+ *
+ * @param blob_desc A pointer to the blob.
+ * @param handle The handle returns the reference to the blob once load.
+ * @return int If less than 0 it is an error code else it is the blob descriptor.
+ */
+int rtems_fdt_register (const void* blob, rtems_fdt_handle* handle);
+
+/**
+ * Unload a device tree blob or DTB file and release any memory allocated when
+ * loading. The blob is removed from the list of registered.
+ *
+ * @param blob_desc A valid blob descriptor.
+ * @return int If less than 0 it is an error code else 0 is return on success.
+ */
+int rtems_fdt_unload (rtems_fdt_handle* handle);
+
+/**
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * @param blob_desc A valid blob descriptor.
+ * @return int The number of entries.
+ */
+int rtems_fdt_num_mem_rsv (rtems_fdt_handle* handle);
+
+/**
+ * Retrieve one memory reserve map entry. On success, *address and *size will
+ * contain the address and size of the n-th reserve map entry from the device
+ * tree blob, in native-endian format.
+ *
+ * @param blob_desc A valid blob descriptor.
+ * @param address Pointer to 64-bit variables to hold the addresses.
+ * @param size Pointer to 64-bit variables to hold the size.
+ * @return int If less than 0 it is an error code else 0 is returned on
+ *             success.
+ */
+int rtems_fdt_get_mem_rsv (rtems_fdt_handle* handle,
+                           int               n,
+                           uint64_t*         address,
+                           uint64_t*         size);
+
+/**
+ * Find a subnode based on substring. Identical to rtems_fdt_subnode_offset(),
+ * but only examine the first namelen characters of name for matching the
+ * subnode name. This is useful for finding subnodes based on a portion of a
+ * larger string, such as a full path.
+ *
+ * @param blob_desc A valid blob descriptor.
+ * @param arentoffset Structure block offset of a node
+ * @param name Name of the subnode to locate.
+ * @param namelen Number of characters of name to consider.
+ * @return int If less than 0 it is an error code else the node offset is
+ *             returned.
+ */
+int rtems_fdt_subnode_offset_namelen (rtems_fdt_handle* handle,
+                                      int               parentoffset,
+                                      const char* const name,
+                                      int               namelen);
+
+/**
+ * Find a subnode of a given node at structure block offset parentoffset with
+ * the given name. The name may include a unit address, in which case
+ * rtems_fdt_subnode_offset() will find the subnode with that unit address, or
+ * the unit address may be omitted, in which case rtems_fdt_subnode_offset()
+ * will find an arbitrary subnode whose name excluding unit address matches the
+ * given name.
+ *
+ * @param blob_desc A valid blob descriptor.
+ * @param parentoffset Structure block offset of a node.
+ * @param name The name of the subnode to locate.
+ * @return int If less than 0 it is an error code else the subnode offset is
+ *             returned.
+ */
+int rtems_fdt_subnode_offset (rtems_fdt_handle* handle,
+                              int               parentoffset,
+                              const char* const name);
+
+/**
+ * Find a tree node by its full path. Each path component may omit the unit
+ * address portion, but the results of this are undefined if any such path
+ * component is ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit address).
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param path Full path of the node to locate.
+ * @param int If less than 0 an error code else the node offset is returned.
+ */
+int rtems_fdt_path_offset (rtems_fdt_handle* handle, const char* path);
+
+/**
+ * Retrieve the name of a given node (including unit address) of the device
+ * tree node at structure block offset @nodeoffset.  If @length is non-NULL,
+ * the length of this name is also returned, in the integer pointed to by
+ * @length.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset Structure block offset of the starting node.
+ * @param length Pointer to an integer variable (will be overwritten) or NULL.
+ * @return const char* The node's name on success or NULL on error. The length
+ *                     if non-NULL will hold the error code.
+ */
+const char* rtems_fdt_get_name (rtems_fdt_handle* handle,
+                                int               nodeoffset,
+                                int*              length);
+
+/**
+ * Get property value based on substring. Identical to rtems_fdt_getprop(), but
+ * only examine the first namelen characters of name for matching the property
+ * name.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset Offset of the node whose property to find
+ * @param name The name of the property to find
+ * @param namelen The number of characters of name to consider
+ * @param length A pointer to an integer variable (will be overwritten) or
+ *               NULL.
+ * @return const void* The node's property on success or NULL on error. The
+ *                     length if non-NULL will hold the error code.
+ */
+const void *rtems_fdt_getprop_namelen (rtems_fdt_handle* handle,
+                                       int               nodeoffset,
+                                       const char* const name,
+                                       int               namelen,
+                                       int*              length);
+
+/**
+ * Retrieve the value of a given property. Retrieves a pointer to the value of
+ * the property named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).  If lenp
+ * is non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by @length.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of the node whose property to find.
+ * @param name The name of the property to find.
+ * @param length A pointer to an integer variable (will be overwritten) or
+ *               NULL.
+ * @return const void* The node's property on success or NULL on error. The
+ *                     length if non-NULL will hold the error code.
+ */
+const void *rtems_fdt_getprop (rtems_fdt_handle* handle,
+                               int               nodeoffset,
+                               const char* const name,
+                               int*              length);
+
+/**
+ * Retrieve the phandle of a given of the device tree node at structure block
+ * offset nodeoffset.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @oaram nodeoffset The structure block offset of the node.
+ * return uint32_t The phandle of the node at nodeoffset, on success (!= 0, !=
+ *                  -1) 0, if the node has no phandle, or another error occurs.
+ */
+uint32_t rtems_fdt_get_phandle (rtems_fdt_handle* handle, int nodeoffset);
+
+/**
+ * Get alias based on substring. Identical to rtems_fdt_get_alias(), but only
+ * examine the first namelen characters of name for matching the alias name.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param name The name of the alias th look up.
+ * @param namelen The number of characters of name to consider.
+ * @return const char* The alias or NULL.
+ */
+const char *rtems_fdt_get_alias_namelen (rtems_fdt_handle* handle,
+                                         const char* const name,
+                                         int               namelen);
+
+/**
+ * Retreive the path referenced by a given alias. That is, the value of the
+ * property named 'name' in the node /aliases.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param name The name of the alias to look up.
+ * @return const char* A pointer to the expansion of the alias named 'name', of
+ *                     it exists NULL, if the given alias or the /aliases node
+ *                     does not exist
+ */
+const char* rtems_fdt_get_alias (rtems_fdt_handle* handle, const char* name);
+
+/**
+ * Determine the full path of a node. This function is expensive, as it must
+ * scan the device tree structure from the start to nodeoffset. It computes the
+ * full path of the node at offset nodeoffset, and records that path in the
+ * buffer at buf.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of the node whose path to find.
+ * @param buf A character buffer to contain the returned path (will be
+ *            overwritten)
+ * @param buflen The size of the character buffer at buf.
+ * @return int 0 on success of an error code.
+ */
+int rtems_fdt_get_path (rtems_fdt_handle* handle,
+                        int               nodeoffset,
+                        char*             buf,
+                        int               buflen);
+
+/**
+ * Find a specific ancestor of a node at a specific depth from the root (where
+ * the root itself has depth 0, its immediate subnodes depth 1 and so forth).
+ * So rtems_fdt_supernode_atdepth_offset(blob, nodeoffset, 0, NULL); will
+ * always return 0, the offset of the root node. If the node at nodeoffset has
+ * depth D, then:
+ *  rtems_fdt_supernode_atdepth_offset(blob, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of the node whose parent to find.
+ * @param supernodedepth The depth of the ancestor to find.
+ * @oaram nodedepth The pointer to an integer variable (will be overwritten) or
+ *                  NULL
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_supernode_atdepth_offset (rtems_fdt_handle* handle,
+                                        int               nodeoffset,
+                                        int               supernodedepth,
+                                        int*              nodedepth);
+
+/**
+ * Find the depth of a given node. The root node has depth 0, its immediate
+ * subnodes depth 1 and so forth.
+ *
+ * @note This function is expensive, as it must scan the device tree structure
+ * from the start to nodeoffset.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of the node whose parent to find.
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_node_depth (rtems_fdt_handle* handle, int nodeoffset);
+
+/**
+ * Find the parent of a given node. This funciton locates the parent node of a
+ * given node (that is, it finds the offset of the node which contains the node
+ * at nodeoffset as a subnode).
+ *
+ * @note This function is expensive, as it must scan the device tree structure
+ * from the start to nodeoffset, *twice*.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of the node whose parent to find.
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_parent_offset (rtems_fdt_handle* handle, int nodeoffset);
+
+/**
+ * Find nodes with a given property value. This funtion returns the offset of
+ * the first node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if startoffset
+ * is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following idiom can
+ * be used:
+ *  offset = rtemsfdt_node_offset_by_prop_value(blob, -1, propname,
+ *                                              propval, proplen);
+ *  while (offset != -RTEMS_FDT_ERR_NOTFOUND) {
+ *    // other code here
+ *    offset = rtems_fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *                                                 propval, proplen);
+ *  }
+ *
+ * @note The -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param startoffset Only find nodes after this offset.
+ * @param propname The property name to check.
+ * @param propval The property value to search for.
+ * @param proplen The length of the value in propval.
+ * @return int The structure block offset of the located node (>= 0,
+ *             >startoffset), on success and an error code is less
+ *             than 0.
+ */
+int rtems_fdt_node_offset_by_prop_value (rtems_fdt_handle* handle,
+                                         int               startoffset,
+                                         const char* const propname,
+                                         const void*       propval,
+                                         int               proplen);
+
+/**
+ * Find the node with a given phandle returning the offset of the node which
+ * has the given phandle value. If there is more than one node in the tree
+ * with the given phandle (an invalid tree), results are undefined.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param phandle The phandle value.
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_node_offset_by_phandle (rtems_fdt_handle* handle,
+                                      uint32_t          phandle);
+
+/**
+ * Check a node's compatible property returning 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements, it
+ * returns non-zero otherwise, or on error.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param nodeoffset The offset of a tree node.
+ * @param compatible The string to match against.
+ * @retval 0, if the node has a 'compatible' property listing the given string.
+ * @retval 1, if the node has a 'compatible' property, but it does not list the
+ *            given string
+ */
+int rtems_fdt_node_check_compatible (rtems_fdt_handle* handle,
+                                     int               nodeoffset,
+                                     const char* const compatible);
+
+/**
+ * Find nodes with a given 'compatible' value returning the offset of the first
+ * node after startoffset, which has a 'compatible' property which lists the
+ * given compatible string; or if startoffset is -1, the very first such node
+ * in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following idiom can
+ * be used:
+ *
+ *  offset = rtems_fdt_node_offset_by_compatible(blob, -1, compatible);
+ *  while (offset != -RTEMS_FDT_ERR_NOTFOUND) {
+ *    // other code here
+ *    offset = rtems_fdt_node_offset_by_compatible(blob, offset, compatible);
+ *  }
+ *
+ * @note The -1 in the first call to the function, if 0 is used here instead,
+ * the function will never locate the root node, even if it matches the
+ * criterion.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param startoffset Only find nodes after this offset.
+ * @param compatible The 'compatible' string to match against.
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_node_offset_by_compatible(rtems_fdt_handle* handle,
+                                        int               startoffset,
+                                        const char*       compatible);
+
+/**
+ * Traverse to the next node.
+ *
+ * @param handle The FDT handle to the current blob.
+ * @param offset The offset in the blob to start looking for the next node.
+ * @param depth Pointer to return the depth the node is.
+ * @return int If less than 0 an error else the node offset.
+ */
+int rtems_fdt_next_node (rtems_fdt_handle* handle, int offset, int* depth);
+
+/**
+ * Return an error string given an error value.
+ *
+ * @param errval The error value.
+ * @return const char* The error string.
+ */
+const char* rtems_fdt_strerror (int errval);
+
+/**
+ * Return a property given a path.
+ */
+int rtems_fdt_prop_value(const char* const path,
+                         const char* const propname,
+                         void*             value,
+                         size_t*           size);
+
+/**
+ * Create a map given a path the property name and the names of the subnodes of
+ * the path.
+ */
+int rtems_fdt_prop_map (const char* const path,
+                        const char* const propname,
+                        const char* const names[],
+                        uint32_t*         values,
+                        size_t            count);
+
+/*
+ * Get a value given a path and a property.
+ */
+int rtems_fdt_get_value (const char* const path,
+                         const char* const property,
+                         size_t            size,
+                         uint32_t*         value);
+
+/**
+ * Get the number of entries in an FDT handle.
+ */
+int rtems_fdt_num_entries(rtems_fdt_handle* handle);
+
+/**
+ * Get the numbered entry name. Note that the id isn't the same as
+ * the offset - it's numbered 0, 1, 2 ... num_entries-1
+ */
+const char *rtems_fdt_entry_name(rtems_fdt_handle* handle, int id);
+
+/**
+ * Get the numbered entry offset. Note that the id isn't the same as
+ * the offset - it's numbered 0, 1, 2 ... num_entries-1
+ */
+int rtems_fdt_entry_offset(rtems_fdt_handle* handle, int id);
+
+/*
+ * Helper function to convert the void* property result to a 32bit unsigned int.
+ */
+uint32_t rtems_fdt_get_uint32 (const void* prop);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
index ef09294..7936de2 100644
--- a/cpukit/preinstall.am
+++ b/cpukit/preinstall.am
@@ -516,6 +516,14 @@ $(PROJECT_INCLUDE)/rtems/dumpbuf.h: libmisc/dumpbuf/dumpbuf.h $(PROJECT_INCLUDE)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/dumpbuf.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/dumpbuf.h
 
+$(PROJECT_INCLUDE)/rtems/rtems-fdt.h: libmisc/rtems-fdt/rtems-fdt.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-fdt.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-fdt.h
+
+$(PROJECT_INCLUDE)/rtems/rtems-fdt-shell.h: libmisc/rtems-fdt/rtems-fdt-shell.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-fdt-shell.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-fdt-shell.h
+
 $(PROJECT_INCLUDE)/rtems/monitor.h: libmisc/monitor/monitor.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
 	$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/monitor.h
 PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/monitor.h



More information about the vc mailing list