]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - include/libfdt.h
karo: fdt: fix panel-dpi support
[karo-tx-uboot.git] / include / libfdt.h
index fc7f75b9ffa60b6bc23f44d39b59c4d0f4b7be3b..e48c21aced0288a4fca14b3dd6ac3e797691d676 100644 (file)
         * Should never be returned, if it is, it indicates a bug in
         * libfdt itself. */
 
-#define FDT_ERR_MAX            13
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS      14
+       /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+        * or similar property with a bad format or value */
+
+#define FDT_ERR_TOODEEP                15
+       /* FDT_ERR_TOODEEP: The depth of a node has exceeded the internal
+        * libfdt limit. This can happen if you have more than
+        * FDT_MAX_DEPTH nested nodes. */
+
+#define FDT_ERR_MAX            15
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -136,6 +146,53 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
 
 int fdt_next_node(const void *fdt, int offset, int *depth);
 
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt:       FDT blob
+ * @offset:    Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt:       FDT blob
+ * @offset:    Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_for_each_subnode - iterate over all subnodes of a parent
+ *
+ * This is actually a wrapper around a for loop and would be used like so:
+ *
+ *     fdt_for_each_subnode(fdt, node, parent) {
+ *             ...
+ *             use node
+ *             ...
+ *     }
+ *
+ * Note that this is implemented as a macro and node is used as iterator in
+ * the loop. It should therefore be a locally allocated variable. The parent
+ * variable on the other hand is never modified, so it can be constant or
+ * even a literal.
+ *
+ * @fdt:       FDT blob (const void *)
+ * @node:      child node (int)
+ * @parent:    parent node (int)
+ */
+#define fdt_for_each_subnode(fdt, node, parent)                \
+       for (node = fdt_first_subnode(fdt, parent);     \
+            node >= 0;                                 \
+            node = fdt_next_subnode(fdt, node))
+
 /**********************************************************************/
 /* General functions                                                  */
 /**********************************************************************/
@@ -582,7 +639,7 @@ const char *fdt_get_alias_namelen(const void *fdt,
  * value of the property named 'name' in the node /aliases.
  *
  * returns:
- *     a pointer to the expansion of the alias named 'name', of it exists
+ *     a pointer to the expansion of the alias named 'name', if it exists
  *     NULL, if the given alias or the /aliases node does not exist
  */
 const char *fdt_get_alias(const void *fdt, const char *name);
@@ -709,7 +766,7 @@ int fdt_parent_offset(const void *fdt, int nodeoffset);
  *     offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
  *                                            propval, proplen);
  *     while (offset != -FDT_ERR_NOTFOUND) {
- *             ... other code here ...
+ *             // other code here
  *             offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
  *                                                    propval, proplen);
  *     }
@@ -794,7 +851,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
  * idiom can be used:
  *     offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
  *     while (offset != -FDT_ERR_NOTFOUND) {
- *             ... other code here ...
+ *             // other code here
  *             offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
  *     }
  *
@@ -816,6 +873,124 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
                                  const char *compatible);
 
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_count_strings - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @node: offset of the node
+ * @property: name of the property containing the string list
+ * @return: the number of strings in the given property
+ */
+int fdt_count_strings(const void *fdt, int node, const char *property);
+
+/**
+ * fdt_find_string - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @node: offset of the node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ * @return: the index of the string or negative on error
+ */
+int fdt_find_string(const void *fdt, int node, const char *property,
+                   const char *string);
+
+/**
+ * fdt_get_string_index() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @node: offset of the node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @output: return location for the string
+ * @return: 0 if the string was found or a negative error code otherwise
+ */
+int fdt_get_string_index(const void *fdt, int node, const char *property,
+                        int index, const char **output);
+
+/**
+ * fdt_get_string() - obtain the first string in a string list
+ * @fdt: pointer to the device tree blob
+ * @node: offset of the node
+ * @property: name of the property containing the string list
+ * @output: return location for the string
+ * @return: 0 if the string was found or a negative error code otherwise
+ *
+ * This is a shortcut for:
+ *
+ *     fdt_get_string_index(fdt, node, property, 0, output).
+ */
+int fdt_get_string(const void *fdt, int node, const char *property,
+                  const char **output);
+
+/**********************************************************************/
+/* Read-only functions (addressing related)                           */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt.  IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS         4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ *     0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #address-cells property
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ *                  tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ *     0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid
+ *             #size-cells property
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
 /**********************************************************************/
 /* Write-in-place functions                                           */
 /**********************************************************************/
@@ -987,6 +1162,7 @@ int fdt_nop_node(void *fdt, int nodeoffset);
 /**********************************************************************/
 
 int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
 int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
 int fdt_finish_reservemap(void *fdt);
 int fdt_begin_node(void *fdt, const char *name);
@@ -1475,4 +1651,317 @@ int fdt_del_node(void *fdt, int nodeoffset);
 
 const char *fdt_strerror(int errval);
 
+/**
+ * fdt_remove_unused_strings() - Remove any unused strings from an FDT
+ *
+ * This creates a new device tree in @new with unused strings removed. The
+ * called can then use fdt_pack() to minimise the space consumed.
+ *
+ * @old:       Old device tree blog
+ * @new:       Place to put new device tree blob, which must be as large as
+ *             @old
+ * @return
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, corrupt device tree
+ *     -FDT_ERR_NOSPACE, out of space, which should not happen unless there
+ *             is something very wrong with the device tree input
+ */
+int fdt_remove_unused_strings(const void *old, void *new);
+
+struct fdt_region {
+       int offset;
+       int size;
+};
+
+/*
+ * Flags for fdt_find_regions()
+ *
+ * Add a region for the string table (always the last region)
+ */
+#define FDT_REG_ADD_STRING_TAB         (1 << 0)
+
+/*
+ * Add all supernodes of a matching node/property, useful for creating a
+ * valid subset tree
+ */
+#define FDT_REG_SUPERNODES             (1 << 1)
+
+/* Add the FDT_BEGIN_NODE tags of subnodes, including their names */
+#define FDT_REG_DIRECT_SUBNODES        (1 << 2)
+
+/* Add all subnodes of a matching node */
+#define FDT_REG_ALL_SUBNODES           (1 << 3)
+
+/* Add a region for the mem_rsvmap table (always the first region) */
+#define FDT_REG_ADD_MEM_RSVMAP         (1 << 4)
+
+/* Indicates what an fdt part is (node, property, value) */
+#define FDT_IS_NODE                    (1 << 0)
+#define FDT_IS_PROP                    (1 << 1)
+#define FDT_IS_VALUE                   (1 << 2)        /* not supported */
+#define FDT_IS_COMPAT                  (1 << 3)        /* used internally */
+#define FDT_NODE_HAS_PROP              (1 << 4)        /* node contains prop */
+
+#define FDT_ANY_GLOBAL         (FDT_IS_NODE | FDT_IS_PROP | FDT_IS_VALUE | \
+                                       FDT_IS_COMPAT)
+#define FDT_IS_ANY                     0x1f            /* all the above */
+
+/* We set a reasonable limit on the number of nested nodes */
+#define FDT_MAX_DEPTH                  32
+
+/* Decribes what we want to include from the current tag */
+enum want_t {
+       WANT_NOTHING,
+       WANT_NODES_ONLY,                /* No properties */
+       WANT_NODES_AND_PROPS,           /* Everything for one level */
+       WANT_ALL_NODES_AND_PROPS        /* Everything for all levels */
+};
+
+/* Keeps track of the state at parent nodes */
+struct fdt_subnode_stack {
+       int offset;             /* Offset of node */
+       enum want_t want;       /* The 'want' value here */
+       int included;           /* 1 if we included this node, 0 if not */
+};
+
+struct fdt_region_ptrs {
+       int depth;                      /* Current tree depth */
+       int done;                       /* What we have completed scanning */
+       enum want_t want;               /* What we are currently including */
+       char *end;                      /* Pointer to end of full node path */
+       int nextoffset;                 /* Next node offset to check */
+};
+
+/* The state of our finding algortihm */
+struct fdt_region_state {
+       struct fdt_subnode_stack stack[FDT_MAX_DEPTH];  /* node stack */
+       struct fdt_region *region;      /* Contains list of regions found */
+       int count;                      /* Numnber of regions found */
+       const void *fdt;                /* FDT blob */
+       int max_regions;                /* Maximum regions to find */
+       int can_merge;          /* 1 if we can merge with previous region */
+       int start;                      /* Start position of current region */
+       struct fdt_region_ptrs ptrs;    /* Pointers for what we are up to */
+};
+
+/**
+ * fdt_find_regions() - find regions in device tree
+ *
+ * Given a list of nodes to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ *
+ * Nodes which are given in 'inc' are included in the region list, as
+ * are the names of the immediate subnodes nodes (but not the properties
+ * or subnodes of those subnodes).
+ *
+ * For eaxample "/" means to include the root node, all root properties
+ * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter
+ * ensures that we capture the names of the subnodes. In a hashing situation
+ * it prevents the root node from changing at all Any change to non-excluded
+ * properties, names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too.
+ *
+ * The device tree header is not included in the list.
+ *
+ * @fdt:       Device tree to check
+ * @inc:       List of node paths to included
+ * @inc_count: Number of node paths in list
+ * @exc_prop:  List of properties names to exclude
+ * @exc_prop_count:    Number of properties in exclude list
+ * @region:    Returns list of regions
+ * @max_region:        Maximum length of region list
+ * @path:      Pointer to a temporary string for the function to use for
+ *             building path names
+ * @path_len:  Length of path, must be large enough to hold the longest
+ *             path in the tree
+ * @add_string_tab:    1 to add a region for the string table
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again.
+ */
+int fdt_find_regions(const void *fdt, char * const inc[], int inc_count,
+                    char * const exc_prop[], int exc_prop_count,
+                    struct fdt_region region[], int max_regions,
+                    char *path, int path_len, int add_string_tab);
+
+/**
+ * fdt_first_region() - find regions in device tree
+ *
+ * Given a nodes and properties to include and properties to exclude, find
+ * the regions of the device tree which describe those included parts.
+ *
+ * The use for this function is twofold. Firstly it provides a convenient
+ * way of performing a structure-aware grep of the tree. For example it is
+ * possible to grep for a node and get all the properties associated with
+ * that node. Trees can be subsetted easily, by specifying the nodes that
+ * are required, and then writing out the regions returned by this function.
+ * This is useful for small resource-constrained systems, such as boot
+ * loaders, which want to use an FDT but do not need to know about all of
+ * it.
+ *
+ * Secondly it makes it easy to hash parts of the tree and detect changes.
+ * The intent is to get a list of regions which will be invariant provided
+ * those parts are invariant. For example, if you request a list of regions
+ * for all nodes but exclude the property "data", then you will get the
+ * same region contents regardless of any change to "data" properties.
+ *
+ * This function can be used to produce a byte-stream to send to a hashing
+ * function to verify that critical parts of the FDT have not changed.
+ * Note that semantically null changes in order could still cause false
+ * hash misses. Such reordering might happen if the tree is regenerated
+ * from source, and nodes are reordered (the bytes-stream will be emitted
+ * in a different order and mnay hash functions will detect this). However
+ * if an existing tree is modified using libfdt functions, such as
+ * fdt_add_subnode() and fdt_setprop(), then this problem is avoided.
+ *
+ * The nodes/properties to include/exclude are defined by a function
+ * provided by the caller. This function is called for each node and
+ * property, and must return:
+ *
+ *    0 - to exclude this part
+ *    1 - to include this part
+ *   -1 - for FDT_IS_PROP only: no information is available, so include
+ *             if its containing node is included
+ *
+ * The last case is only used to deal with properties. Often a property is
+ * included if its containing node is included - this is the case where
+ * -1 is returned.. However if the property is specifically required to be
+ * included/excluded, then 0 or 1 can be returned. Note that including a
+ * property when the FDT_REG_SUPERNODES flag is given will force its
+ * containing node to be included since it is not valid to have a property
+ * that is not in a node.
+ *
+ * Using the information provided, the inclusion of a node can be controlled
+ * either by a node name or its compatible string, or any other property
+ * that the function can determine.
+ *
+ * As an example, including node "/" means to include the root node and all
+ * root properties. A flag provides a way of also including supernodes (of
+ * which there is none for the root node), and another flag includes
+ * immediate subnodes, so in this case we would get the FDT_BEGIN_NODE and
+ * FDT_END_NODE of all subnodes of /.
+ *
+ * The subnode feature helps in a hashing situation since it prevents the
+ * root node from changing at all. Any change to non-excluded properties,
+ * names of subnodes or number of subnodes would be detected.
+ *
+ * When used with FITs this provides the ability to hash and sign parts of
+ * the FIT based on different configurations in the FIT. Then it is
+ * impossible to change anything about that configuration (include images
+ * attached to the configuration), but it may be possible to add new
+ * configurations, new images or new signatures within the existing
+ * framework.
+ *
+ * Adding new properties to a device tree may result in the string table
+ * being extended (if the new property names are different from those
+ * already added). This function can optionally include a region for
+ * the string table so that this can be part of the hash too. This is always
+ * the last region.
+ *
+ * The FDT also has a mem_rsvmap table which can also be included, and is
+ * always the first region if so.
+ *
+ * The device tree header is not included in the region list. Since the
+ * contents of the FDT are changing (shrinking, often), the caller will need
+ * to regenerate the header anyway.
+ *
+ * @fdt:       Device tree to check
+ * @h_include: Function to call to determine whether to include a part or
+ *             not:
+ *
+ *             @priv: Private pointer as passed to fdt_find_regions()
+ *             @fdt: Pointer to FDT blob
+ *             @offset: Offset of this node / property
+ *             @type: Type of this part, FDT_IS_...
+ *             @data: Pointer to data (node name, property name, compatible
+ *                     string, value (not yet supported)
+ *             @size: Size of data, or 0 if none
+ *             @return 0 to exclude, 1 to include, -1 if no information is
+ *             available
+ * @priv:      Private pointer passed to h_include
+ * @region:    Returns list of regions, sorted by offset
+ * @max_regions: Maximum length of region list
+ * @path:      Pointer to a temporary string for the function to use for
+ *             building path names
+ * @path_len:  Length of path, must be large enough to hold the longest
+ *             path in the tree
+ * @flags:     Various flags that control the region algortihm, see
+ *             FDT_REG_...
+ * @return number of regions in list. If this is >max_regions then the
+ * region array was exhausted. You should increase max_regions and try
+ * the call again. Only the first max_regions elements are available in the
+ * array.
+ *
+ * On error a -ve value is return, which can be:
+ *
+ *     -FDT_ERR_BADSTRUCTURE (too deep or more END tags than BEGIN tags
+ *     -FDT_ERR_BADLAYOUT
+ *     -FDT_ERR_NOSPACE (path area is too small)
+ */
+int fdt_first_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info);
+
+/** fdt_next_region() - find next region
+ *
+ * See fdt_first_region() for full description. This function finds the
+ * next region according to the provided parameters, which must be the same
+ * as passed to fdt_first_region().
+ *
+ * This function can additionally return -FDT_ERR_NOTFOUND when there are no
+ * more regions
+ */
+int fdt_next_region(const void *fdt,
+               int (*h_include)(void *priv, const void *fdt, int offset,
+                                int type, const char *data, int size),
+               void *priv, struct fdt_region *region,
+               char *path, int path_len, int flags,
+               struct fdt_region_state *info);
+
+/**
+ * fdt_add_alias_regions() - find aliases that point to existing regions
+ *
+ * Once a device tree grep is complete some of the nodes will be present
+ * and some will have been dropped. This function checks all the alias nodes
+ * to figure out which points point to nodes which are still present. These
+ * aliases need to be kept, along with the nodes they reference.
+ *
+ * Given a list of regions function finds the aliases that still apply and
+ * adds more regions to the list for these. This function is called after
+ * fdt_next_region() has finished returning regions and requires the same
+ * state.
+ *
+ * @fdt:       Device tree file to reference
+ * @region:    List of regions that will be kept
+ * @count:     Number of regions
+ * @max_regions: Number of entries that can fit in @region
+ * @info:      Region state as returned from fdt_next_region()
+ * @return new number of regions in @region (i.e. count + the number added)
+ * or -FDT_ERR_NOSPACE if there was not enough space.
+ */
+int fdt_add_alias_regions(const void *fdt, struct fdt_region *region, int count,
+                         int max_regions, struct fdt_region_state *info);
+
 #endif /* _LIBFDT_H */