summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2017-08-16 14:22:23 +1000
committerChris Johns <chrisj@rtems.org>2017-08-20 11:11:46 +1000
commit6b7efdb2ed77760e3c68c5cf450a9620a1cd6562 (patch)
tree7af6121eedd638496f7dc8c2ad380e9917692f14
parentdev/i2c: Add I2C device support for FPGA Slave, LM25066A, TMP112, ADS1113, AD... (diff)
downloadrtems-6b7efdb2ed77760e3c68c5cf450a9620a1cd6562.tar.bz2
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.
-rw-r--r--cpukit/Makefile.am4
-rw-r--r--cpukit/libmisc/Makefile.am5
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c639
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h42
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt.c1191
-rw-r--r--cpukit/libmisc/rtems-fdt/rtems-fdt.h621
-rw-r--r--cpukit/preinstall.am8
7 files changed, 2510 insertions, 0 deletions
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 2c2f2e5cfb..8ccc1d4e9a 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 6772dd1673..786782931c 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 0000000000..9412b37750
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.c
@@ -0,0 +1,639 @@
+/*
+ * COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@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 0000000000..74e9a44aaf
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt-shell.h
@@ -0,0 +1,42 @@
+/*
+ * COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@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 0000000000..cbdb656fcc
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.c
@@ -0,0 +1,1191 @@
+/*
+ * COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@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 0000000000..ebc222e4c9
--- /dev/null
+++ b/cpukit/libmisc/rtems-fdt/rtems-fdt.h
@@ -0,0 +1,621 @@
+/*
+ * COPYRIGHT (c) 2013-2017 Chris Johns <chrisj@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 ef092946e2..7936de2ebb 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