]> git.ipfire.org Git - people/ms/u-boot.git/blobdiff - libfdt/fdt_ro.c
Merge branch 'new-image' of git://www.denx.de/git/u-boot-testing
[people/ms/u-boot.git] / libfdt / fdt_ro.c
index 46d525db1453ad29caad64890039008a373754af..11d80d2fa249d8a6085888e48b44130d6f7ca531 100644 (file)
@@ -2,40 +2,67 @@
  * libfdt - Flat Device Tree manipulation
  * Copyright (C) 2006 David Gibson, IBM Corporation.
  *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
  *
- * This library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#include "config.h"
-#if CONFIG_OF_LIBFDT
-
 #include "libfdt_env.h"
 
+#ifndef USE_HOSTCC
 #include <fdt.h>
 #include <libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
 
 #include "libfdt_internal.h"
 
-#define CHECK_HEADER(fdt)      { \
-       int err; \
-       if ((err = fdt_check_header(fdt)) != 0) \
-               return err; \
-}
-
-static int offset_streq(const void *fdt, int offset,
-                       const char *s, int len)
+static int nodename_eq(const void *fdt, int offset,
+                      const char *s, int len)
 {
-       const char *p = fdt_offset_ptr(fdt, offset, len+1);
+       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
 
        if (! p)
                /* short match */
@@ -44,234 +71,63 @@ static int offset_streq(const void *fdt, int offset,
        if (memcmp(p, s, len) != 0)
                return 0;
 
-       if (p[len] != '\0')
+       if (p[len] == '\0')
+               return 1;
+       else if (!memchr(s, '@', len) && (p[len] == '@'))
+               return 1;
+       else
                return 0;
-
-       return 1;
-}
-
-/*
- * Checks if the property name matches.
- */
-static int prop_name_eq(const void *fdt, int offset, const char *name,
-                       struct fdt_property **prop, int *lenp)
-{
-       int namestroff, len;
-
-       *prop = fdt_offset_ptr_typed(fdt, offset, *prop);
-       if (! *prop)
-               return -FDT_ERR_BADSTRUCTURE;
-
-       namestroff = fdt32_to_cpu((*prop)->nameoff);
-       if (streq(fdt_string(fdt, namestroff), name)) {
-               len = fdt32_to_cpu((*prop)->len);
-               *prop = fdt_offset_ptr(fdt, offset,
-                                      sizeof(**prop) + len);
-               if (*prop) {
-                       if (lenp)
-                               *lenp = len;
-                       return 1;
-               } else
-                       return -FDT_ERR_BADSTRUCTURE;
-       }
-       return 0;
 }
 
-/*
- * Return a pointer to the string at the given string offset.
- */
-char *fdt_string(const void *fdt, int stroffset)
+const char *fdt_string(const void *fdt, int stroffset)
 {
        return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
 }
 
-/*
- * Check if the specified node is compatible by comparing the tokens
- * in its "compatible" property with the specified string:
- *
- *   nodeoffset - starting place of the node
- *   compat     - the string to match to one of the tokens in the
- *                "compatible" list.
- */
-int fdt_node_is_compatible(const void *fdt, int nodeoffset,
-                          const char *compat)
-{
-       const char* cp;
-       int cplen, len;
-
-       cp = fdt_getprop(fdt, nodeoffset, "compatible", &cplen);
-       if (cp == NULL)
-               return 0;
-       while (cplen > 0) {
-               if (strncmp(cp, compat, strlen(compat)) == 0)
-                       return 1;
-               len = strlen(cp) + 1;
-               cp += len;
-               cplen -= len;
-       }
-
-       return 0;
-}
-
-/*
- * Find a node by its device type property. On success, the offset of that
- * node is returned or an error code otherwise:
- *
- *   nodeoffset - the node to start searching from or 0, the node you pass
- *                will not be searched, only the next one will; typically,
- *                you pass 0 to start the search and then what the previous
- *                call returned.
- *   type       - the device type string to match against.
- */
-int fdt_find_node_by_type(const void *fdt, int nodeoffset, const char *type)
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-       int offset, nextoffset;
-       struct fdt_property *prop;
-       uint32_t tag;
-       int len, ret;
-
        CHECK_HEADER(fdt);
-
-       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADOFFSET;
-       if (nodeoffset)
-               nodeoffset = 0; /* start searching with next node */
-
-       while (1) {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
-
-               switch (tag) {
-               case FDT_BEGIN_NODE:
-                       nodeoffset = offset;
-                       break;
-
-               case FDT_PROP:
-                       if (nodeoffset == 0)
-                               break;
-                       ret = prop_name_eq(fdt, offset, "device_type",
-                                          &prop, &len);
-                       if (ret < 0)
-                               return ret;
-                       else if (ret > 0 &&
-                                strncmp(prop->data, type, len - 1) == 0)
-                           return nodeoffset;
-                       break;
-
-               case FDT_END_NODE:
-               case FDT_NOP:
-                       break;
-
-               case FDT_END:
-                       return -FDT_ERR_NOTFOUND;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       }
+       *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+       *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+       return 0;
 }
 
-/*
- * Find a node based on its device type and one of the tokens in its its
- * "compatible" property. On success, the offset of that node is returned
- * or an error code otherwise:
- *
- *   nodeoffset - the node to start searching from or 0, the node you pass
- *                will not be searched, only the next one will; typically,
- *                you pass 0 to start the search and then what the previous
- *                call returned.
- *   type       - the device type string to match against.
- *   compat     - the string to match to one of the tokens in the
- *                "compatible" list.
- */
-int fdt_find_compatible_node(const void *fdt, int nodeoffset,
-                            const char *type, const char *compat)
+int fdt_num_mem_rsv(const void *fdt)
 {
-       int offset;
-
-       offset = fdt_find_node_by_type(fdt, nodeoffset, type);
-       if (offset < 0 || fdt_node_is_compatible(fdt, offset, compat))
-               return offset;
+       int i = 0;
 
-       return -FDT_ERR_NOTFOUND;
+       while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+               i++;
+       return i;
 }
 
-/*
- * Return the node offset of the node specified by:
- *   parentoffset - starting place (0 to start at the root)
- *   name         - name being searched for
- *   namelen      - length of the name: typically strlen(name)
- *
- * Notes:
- *   If the start node has subnodes, the subnodes are _not_ searched for the
- *     requested name.
- */
-int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
                               const char *name, int namelen)
 {
-       int level = 0;
-       uint32_t tag;
-       int offset, nextoffset;
+       int depth;
 
        CHECK_HEADER(fdt);
 
-       tag = fdt_next_tag(fdt, parentoffset, &nextoffset, NULL);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADOFFSET;
-
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
-
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_TRUNCATED;
-
-               case FDT_BEGIN_NODE:
-                       level++;
-                       /*
-                        * If we are nested down levels, ignore the strings
-                        * until we get back to the proper level.
-                        */
-                       if (level != 1)
-                               continue;
-
-                       /* Return the offset if this is "our" string. */
-                       if (offset_streq(fdt, offset+FDT_TAGSIZE, name, namelen))
-                               return offset;
-                       break;
-
-               case FDT_END_NODE:
-                       level--;
-                       break;
-
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (level >= 0);
+       for (depth = 0;
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth < 0)
+                       return -FDT_ERR_NOTFOUND;
+               else if ((depth == 1)
+                        && nodename_eq(fdt, offset, name, namelen))
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error */
 }
 
-/*
- * See fdt_subnode_offset_namelen()
- */
 int fdt_subnode_offset(const void *fdt, int parentoffset,
                       const char *name)
 {
        return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
 }
 
-/*
- * Searches for the node corresponding to the given path and returns the
- * offset of that node.
- */
-int fdt_find_node_by_path(const void *fdt, const char *path)
+int fdt_path_offset(const void *fdt, const char *path)
 {
        const char *end = path + strlen(path);
        const char *p = path;
@@ -279,37 +135,21 @@ int fdt_find_node_by_path(const void *fdt, const char *path)
 
        CHECK_HEADER(fdt);
 
-       /* Paths must be absolute */
        if (*path != '/')
                return -FDT_ERR_BADPATH;
 
-       /* Handle the root path: root offset is 0 */
-       if (strcmp(path, "/") == 0)
-               return 0;
-
        while (*p) {
                const char *q;
 
-               /* Skip path separator(s) */
                while (*p == '/')
                        p++;
                if (! *p)
-                       return -FDT_ERR_BADPATH;
-
-               /*
-                * Find the next path separator.  The characters between
-                * p and q are the next segment of the the path to find.
-                */
+                       return offset;
                q = strchr(p, '/');
                if (! q)
                        q = end;
 
-               /*
-                * Find the offset corresponding to the this path segment.
-                */
                offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
-
-               /* Oops, error, abort abort abort */
                if (offset < 0)
                        return offset;
 
@@ -319,17 +159,37 @@ int fdt_find_node_by_path(const void *fdt, const char *path)
        return offset;
 }
 
-/*
- * Given the offset of a node and a name of a property in that node, return
- * a pointer to the property struct.
- */
-struct fdt_property *fdt_get_property(const void *fdt,
-                                     int nodeoffset,
-                                     const char *name, int *lenp)
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+       const struct fdt_node_header *nh;
+       int err;
+
+       if ((err = fdt_check_header(fdt)) != 0)
+               goto fail;
+
+       err = -FDT_ERR_BADOFFSET;
+       nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
+       if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
+               goto fail;
+
+       if (len)
+               *len = strlen(nh->name);
+
+       return nh->name;
+
+ fail:
+       if (len)
+               *len = err;
+       return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+                                           int nodeoffset,
+                                           const char *name, int *lenp)
 {
-       int level = 0;
        uint32_t tag;
-       struct fdt_property *prop;
+       const struct fdt_property *prop;
+       int namestroff;
        int offset, nextoffset;
        int err;
 
@@ -340,63 +200,59 @@ struct fdt_property *fdt_get_property(const void *fdt,
        if (nodeoffset % FDT_TAGSIZE)
                goto fail;
 
-       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset, NULL);
+       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
        if (tag != FDT_BEGIN_NODE)
                goto fail;
 
        do {
                offset = nextoffset;
 
-               tag = fdt_next_tag(fdt, offset, &nextoffset, NULL);
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
                switch (tag) {
                case FDT_END:
                        err = -FDT_ERR_TRUNCATED;
                        goto fail;
 
                case FDT_BEGIN_NODE:
-                       level++;
-                       break;
-
                case FDT_END_NODE:
-                       level--;
+               case FDT_NOP:
                        break;
 
                case FDT_PROP:
-                       /*
-                        * If we are nested down levels, ignore the strings
-                        * until we get back to the proper level.
-                        */
-                       if (level != 0)
-                               continue;
-
-                       err = prop_name_eq(fdt, offset, name, &prop, lenp);
-                       if (err > 0)
-                               return prop;
-                       else if (err < 0)
+                       err = -FDT_ERR_BADSTRUCTURE;
+                       prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
+                       if (! prop)
                                goto fail;
-                       break;
+                       namestroff = fdt32_to_cpu(prop->nameoff);
+                       if (streq(fdt_string(fdt, namestroff), name)) {
+                               /* Found it! */
+                               int len = fdt32_to_cpu(prop->len);
+                               prop = fdt_offset_ptr(fdt, offset,
+                                                     sizeof(*prop)+len);
+                               if (! prop)
+                                       goto fail;
+
+                               if (lenp)
+                                       *lenp = len;
 
-               case FDT_NOP:
+                               return prop;
+                       }
                        break;
 
                default:
                        err = -FDT_ERR_BADSTRUCTURE;
                        goto fail;
                }
-       } while (level >= 0);
+       } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
 
        err = -FDT_ERR_NOTFOUND;
-fail:
+ fail:
        if (lenp)
                *lenp = err;
        return NULL;
 }
 
-/*
- * Given the offset of a node and a name of a property in that node, return
- * a pointer to the property data (ONLY).
- */
-void *fdt_getprop(const void *fdt, int nodeoffset,
+const void *fdt_getprop(const void *fdt, int nodeoffset,
                  const char *name, int *lenp)
 {
        const struct fdt_property *prop;
@@ -405,132 +261,220 @@ void *fdt_getprop(const void *fdt, int nodeoffset,
        if (! prop)
                return NULL;
 
-       return (void *)prop->data;
+       return prop->data;
 }
 
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+       const uint32_t *php;
+       int len;
 
-uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset, char **namep)
+       php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+       if (!php || (len != sizeof(*php)))
+               return 0;
+
+       return fdt32_to_cpu(*php);
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 {
-       const uint32_t *tagp, *lenp;
-       uint32_t tag;
-       const char *p;
-
-       if (offset % FDT_TAGSIZE)
-               return -1;
-
-       tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
-       if (! tagp)
-               return FDT_END; /* premature end */
-       tag = fdt32_to_cpu(*tagp);
-       offset += FDT_TAGSIZE;
-
-       switch (tag) {
-       case FDT_BEGIN_NODE:
-               if(namep)
-                       *namep = fdt_offset_ptr(fdt, offset, 1);
-
-               /* skip name */
-               do {
-                       p = fdt_offset_ptr(fdt, offset++, 1);
-               } while (p && (*p != '\0'));
-               if (! p)
-                       return FDT_END;
-               break;
-       case FDT_PROP:
-               lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
-               if (! lenp)
-                       return FDT_END;
-               /*
-                * Get the property and set the namep to the name.
-                */
-               if(namep) {
-                       struct fdt_property *prop;
-
-                       prop = fdt_offset_ptr_typed(fdt, offset - FDT_TAGSIZE, prop);
-                       if (! prop)
-                               return -FDT_ERR_BADSTRUCTURE;
-                       *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+       int pdepth = 0, p = 0;
+       int offset, depth, namelen;
+       const char *name;
+
+       CHECK_HEADER(fdt);
+
+       if (buflen < 2)
+               return -FDT_ERR_NOSPACE;
+
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (pdepth < depth)
+                       continue; /* overflowed buffer */
+
+               while (pdepth > depth) {
+                       do {
+                               p--;
+                       } while (buf[p-1] != '/');
+                       pdepth--;
+               }
+
+               name = fdt_get_name(fdt, offset, &namelen);
+               if (!name)
+                       return namelen;
+               if ((p + namelen + 1) <= buflen) {
+                       memcpy(buf + p, name, namelen);
+                       p += namelen;
+                       buf[p++] = '/';
+                       pdepth++;
+               }
+
+               if (offset == nodeoffset) {
+                       if (pdepth < (depth + 1))
+                               return -FDT_ERR_NOSPACE;
+
+                       if (p > 1) /* special case so that root path is "/", not "" */
+                               p--;
+                       buf[p] = '\0';
+                       return p;
                }
-               /* skip name offset, length and value */
-               offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp);
-               break;
        }
 
-       if (nextoffset)
-               *nextoffset = ALIGN(offset, FDT_TAGSIZE);
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
 
-       return tag;
+       return offset; /* error from fdt_next_node() */
 }
 
-/*
- * Return the number of used reserve map entries and total slots available.
- */
-int fdt_num_reservemap(void *fdt, int *used, int *total)
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+                                int supernodedepth, int *nodedepth)
 {
-       struct fdt_reserve_entry *re;
-       int  start;
-       int  end;
-       int  err = fdt_check_header(fdt);
-
-       if (err != 0)
-               return err;
-
-       start = fdt_off_mem_rsvmap(fdt);
-
-       /*
-        * Convention is that the reserve map is before the dt_struct,
-        * but it does not have to be.
-        */
-       end = fdt_totalsize(fdt);
-       if (end > fdt_off_dt_struct(fdt))
-               end = fdt_off_dt_struct(fdt);
-       if (end > fdt_off_dt_strings(fdt))
-               end = fdt_off_dt_strings(fdt);
-
-       /*
-        * Since the reserved area list is zero terminated, you get one fewer.
-        */
-       if (total)
-               *total = ((end - start) / sizeof(struct fdt_reserve_entry)) - 1;
-
-       if (used) {
-               *used = 0;
-               while (start < end) {
-                       re = (struct fdt_reserve_entry *)(fdt + start);
-                       if (re->size == 0)
-                               return 0;       /* zero size terminates the list */
-
-                       *used += 1;
-                       start += sizeof(struct fdt_reserve_entry);
+       int offset, depth;
+       int supernodeoffset = -FDT_ERR_INTERNAL;
+
+       CHECK_HEADER(fdt);
+
+       if (supernodedepth < 0)
+               return -FDT_ERR_NOTFOUND;
+
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth == supernodedepth)
+                       supernodeoffset = offset;
+
+               if (offset == nodeoffset) {
+                       if (nodedepth)
+                               *nodedepth = depth;
+
+                       if (supernodedepth > depth)
+                               return -FDT_ERR_NOTFOUND;
+                       else
+                               return supernodeoffset;
                }
-               /*
-                * If we get here, there was no zero size termination.
-                */
-               return -FDT_ERR_BADLAYOUT;
        }
-       return 0;
+
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
+
+       return offset; /* error from fdt_next_node() */
 }
 
-/*
- * Return the nth reserve map entry.
- */
-int fdt_get_reservemap(void *fdt, int n, struct fdt_reserve_entry *re)
+int fdt_node_depth(const void *fdt, int nodeoffset)
 {
-       int  used;
-       int  total;
-       int  err;
+       int nodedepth;
+       int err;
 
-       err = fdt_num_reservemap(fdt, &used, &total);
-       if (err != 0)
-               return err;
+       err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+       if (err)
+               return (err < 0) ? err : -FDT_ERR_INTERNAL;
+       return nodedepth;
+}
 
-       if (n >= total)
-               return -FDT_ERR_NOSPACE;
-       if (re) {
-               *re = *(struct fdt_reserve_entry *)
-                       _fdt_offset_ptr(fdt, n * sizeof(struct fdt_reserve_entry));
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+       int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+       if (nodedepth < 0)
+               return nodedepth;
+       return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+                                           nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+                                 const char *propname,
+                                 const void *propval, int proplen)
+{
+       int offset;
+       const void *val;
+       int len;
+
+       CHECK_HEADER(fdt);
+
+       /* FIXME: The algorithm here is pretty horrible: we scan each
+        * property of a node in fdt_getprop(), then if that didn't
+        * find what we want, we scan over them again making our way
+        * to the next node.  Still it's the easiest to implement
+        * approach; performance can come later. */
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               val = fdt_getprop(fdt, offset, propname, &len);
+               if (val && (len == proplen)
+                   && (memcmp(val, propval, len) == 0))
+                       return offset;
+       }
+
+       return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+       if ((phandle == 0) || (phandle == -1))
+               return -FDT_ERR_BADPHANDLE;
+       phandle = cpu_to_fdt32(phandle);
+       return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
+                                            &phandle, sizeof(phandle));
+}
+
+int _stringlist_contains(const void *strlist, int listlen, const char *str)
+{
+       int len = strlen(str);
+       const void *p;
+
+       while (listlen >= len) {
+               if (memcmp(str, strlist, len+1) == 0)
+                       return 1;
+               p = memchr(strlist, '\0', listlen);
+               if (!p)
+                       return 0; /* malformed strlist.. */
+               listlen -= (p-strlist) + 1;
+               strlist = p + 1;
        }
        return 0;
 }
 
-#endif /* CONFIG_OF_LIBFDT */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+                             const char *compatible)
+{
+       const void *prop;
+       int len;
+
+       prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+       if (!prop)
+               return len;
+       if (_stringlist_contains(prop, len, compatible))
+               return 0;
+       else
+               return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+                                 const char *compatible)
+{
+       int offset, err;
+
+       CHECK_HEADER(fdt);
+
+       /* FIXME: The algorithm here is pretty horrible: we scan each
+        * property of a node in fdt_node_check_compatible(), then if
+        * that didn't find what we want, we scan over them again
+        * making our way to the next node.  Still it's the easiest to
+        * implement approach; performance can come later. */
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               err = fdt_node_check_compatible(fdt, offset, compatible);
+               if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+                       return err;
+               else if (err == 0)
+                       return offset;
+       }
+
+       return offset; /* error from fdt_next_node() */
+}