Live Tree
Live Tree
==================================
Introduction
------------
Traditionally U-Boot has used a 'flat' device tree. This means that it
reads directly from the device tree binary structure. It is called a flat
device tree because nodes are listed one after the other, with the
hierarchy detected by tags in the format.
This document describes U-Boot's support for a 'live' device tree, meaning
that the tree is loaded into a hierarchical data structure within U-Boot.
Motivation
----------
However the flat device tree does have some limitations. Adding new
properties can involve copying large amounts of data around to make room.
The overall tree has a fixed maximum size so sometimes the tree must be
rebuilt in a new location to create more space. Even if not adding new
properties or nodes, scanning the tree can be slow. For example, finding
the parent of a node is a slow process. Reading from nodes involves a
small amount parsing which takes a little time.
Driver model scans the entire device tree sequentially on start-up which
avoids the worst of the flat tree's limitations. But if the tree is to be
modified at run-time, a live tree is much faster. Even if no modification
is necessary, parsing the tree once and using a live tree from then on
seems to save a little time.
Implementation
--------------
The 'ofnode' type provides this. An ofnode can point to either a flat tree
node (when the live tree node is not yet set up) or a livetree node. The
caller of an ofnode function does not need to worry about these details.
The main users of the information in a device tree are drivers. These have
a 'struct udevice *' which is attached to a device tree node. Therefore it
makes sense to be able to read device tree properties using the
'struct udevice *', rather than having to obtain the ofnode first.
The 'dev_read_...()' interface provides this. It allows properties to be
easily read from the device tree using only a device pointer. Under the
hood it uses ofnode so it works with both flat and live device trees.
Enabling livetree
-----------------
Porting drivers
---------------
Many existing drivers use the fdtdec interface to read device tree
properties. This only works with a flat device tree. The drivers should be
converted to use the dev_read_() interface.
The dev_read_...() interface is more convenient and works with both the
flat and live device trees. See include/dm/read.h for a list of functions.
Where properties must be read from sub-nodes or other nodes, you must fall
back to using ofnode. For example, for old code like this:
ofnode subnode;
ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
freq = ofnode_read_u32(node, "spi-max-frequency", 500000);
...
}
Nodes have pointers to their first property, their parent, their first child
and their sibling. This allows nodes to be linked together in a hierarchical
tree.
Properties have pointers to the next property. This allows all properties of
a node to be linked together in a chain.
Some conversion functions are used internally. Generally these are not needed
for driver code. Note that they will not work if called in the wrong context.
For example it is invalid to call ofnode_to_no() when a flat tree is being
used. Similarly it is not possible to call ofnode_to_offset() on a livetree
node.
Phandles
--------
There is full phandle support for live tree. All functions make use of
struct ofnode_phandle_args, which has an ofnode within it. This supports both
livetree and flat tree transparently. See for example
ofnode_parse_phandle_with_args().
Reading addresses
-----------------
You should use dev_read_addr() and friends to read addresses from device-tree
nodes.
fdtdec
------
The existing fdtdec interface will eventually be retired. Please try to avoid
using it in new code.
Internal implementation
-----------------------
This optimisation means that without livetree enabled, the dev_read_...() and
ofnode interfaces do not noticeably add to code size.
Most livetree code comes directly from Linux and is modified as little as
possible. This is deliberate since this code is fairly stable and does what
we want. Some features (such as get/put) are not supported. Internal macros
take care of removing these features silently.
Within the of_access.c file there are pointers to the alias node, the chosen
node and the stdout-path alias.
Errors
------
With a flat device tree, libfdt errors are returned (e.g. -FDT_ERR_NOTFOUND).
For livetree normal 'errno' errors are returned (e.g. -ENOTFOUND). At present
the ofnode and dev_read_...() functions return either one or other type of
error. This is clearly not desirable. Once tests are added for all the
functions this can be tidied up.
Adding a new function for device-tree access involves the following steps:
- Add two dev_read() functions:
- inline version in the read.h header file, which calls an ofnode
function
- standard version in the read.c file (or perhaps another file), which
also calls an ofnode function
Future work
-----------
Live tree support was introduced in U-Boot 2017.07. There is still quite a bit
of work to do to flesh this out:
--
Simon Glass <[email protected]>
5-Aug-17