[U-Boot] [PATCH 1/3 v3] dm: Add callback to modify the device tree

Mario Six mario.six at gdsys.cc
Wed Feb 22 15:07:22 UTC 2017


Certain boards come in different variations by way of utilizing daughter
boards, for example. These boards might contain additional chips, which
are added to the main board's busses, e.g. I2C.

The device tree support for such boards would either, quite naturally,
employ the overlay mechanism to add such chips to the tree, or would use
one large default device tree, and delete the devices that are actually
not present.

Regardless of approach, even on the U-Boot level, a modification of the
device tree is a prerequisite to have such modular families of boards
supported properly.

Therefore, we add an option to make the U-Boot device tree (the actual
copy later used by the driver model) writeable, and add a callback
method that allows boards to modify the device tree at an early stage,
at which, hopefully, also the application of device tree overlays will
be possible.

Signed-off-by: Mario Six <mario.six at gdsys.cc>
---
Changes in v3:

None

Changes in v2:

* Switched from usage of globally writeable global data pointer to a locally
  writeable pointer passed to board_fix_fdt
* Added comments for board_fix_fdt in include/common.h
* Added documentation for pre-relocation device tree manipulation
---
 common/board_f.c               |  10 ++++
 doc/driver-model/fdt-fixup.txt | 132 +++++++++++++++++++++++++++++++++++++++++
 dts/Kconfig                    |  10 ++++
 include/common.h               |   1 +
 4 files changed, 153 insertions(+)
 create mode 100644 doc/driver-model/fdt-fixup.txt

diff --git a/common/board_f.c b/common/board_f.c
index ae6cd8528c..00d0b81d22 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -767,6 +767,13 @@ static int setup_reloc(void)
 	return 0;
 }

+#ifdef CONFIG_OF_BOARD_FIXUP
+static int fix_fdt(void)
+{
+	return board_fix_fdt((void *)gd->fdt_blob);
+}
+#endif
+
 /* ARM calls relocate_code from its crt0.S */
 #if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
 		!CONFIG_IS_ENABLED(X86_64)
@@ -1028,6 +1035,9 @@ static const init_fnc_t init_sequence_f[] = {
 #ifdef CONFIG_SYS_EXTBDINFO
 	setup_board_extra,
 #endif
+#ifdef CONFIG_OF_BOARD_FIXUP
+	fix_fdt,
+#endif
 	INIT_FUNC_WATCHDOG_RESET
 	reloc_fdt,
 	setup_reloc,
diff --git a/doc/driver-model/fdt-fixup.txt b/doc/driver-model/fdt-fixup.txt
new file mode 100644
index 0000000000..70344bd2c3
--- /dev/null
+++ b/doc/driver-model/fdt-fixup.txt
@@ -0,0 +1,132 @@
+Pre-relocation device tree manipulation
+=======================================
+
+Contents:
+
+1. Purpose
+2. Implementation
+3. Example
+4. Work to be done
+
+1. Purpose
+----------
+
+In certain markets, it is beneficial for manufacturers of embedded devices to
+offer certain ranges of products, where the functionality of the devices within
+one series either don't differ greatly from another, or can be thought of as
+"extensions" of each other, where one device only differs from another in the
+addition of a small number of features (e.g. an additional output connector).
+
+To realize this in hardware, one method is to have a motherboard, and several
+possible daughter boards that can be attached to this mother board. Different
+daughter boards then either offer the slightly different functionality, or the
+addition of the daughter board to the device realizes the "extension" of
+functionality to the device described previously.
+
+For the software, we obviously want to reuse components for all these
+variations of the device. This means that the software somehow needs to cope
+with the situation that certain ICs may or may not be present on any given
+system, depending on which daughter boards are connected to the motherboard.
+
+In the Linux kernel, one possible solution to this problem is to employ the
+device tree overlay mechanism: There exists one "base" device tree, which
+features only the components guaranteed to exist in all varieties of the
+device. At the start of the kernel, the presence and type of the daughter
+boards is then detected, and the corresponding device tree overlays are applied
+to support the components on the daughter boards.
+
+Note that the components present on every variety of the board must, of course,
+provide a way to find out if and which daughter boards are installed for this
+mechanism to work.
+
+In the U-Boot boot loader, support for device tree overlays has recently been
+integrated, and is used on some boards to alter the device tree that is later
+passed to Linux. But since U-Boot's driver model, which is device tree-based as
+well, is being used in more and more drivers, the same problem of altering the
+device tree starts cropping up in U-Boot itself as well.
+
+An additional problem with the device tree in U-Boot is that it is read-only,
+and the current mechanisms don't allow easy manipulation of the device tree
+after the driver model has been initialized. While migrating to a live device
+tree (at least after the relocation) would greatly simplify the solution of
+this problem, it is a non-negligible task to implement it, an a interim
+solution is needed to address the problem at least in the medium-term.
+
+Hence, we propose a solution to this problem by offering a board-specific
+call-back function, which is passed a writeable pointer to the device tree.
+This function is called before the device tree is relocated, and specifically
+before the main U-Boot's driver model is instantiated, hence the main U-Boot
+"sees" all modifications to the device tree made in this function. Furthermore,
+we have the pre-relocation driver model at our disposal at this stage, which
+means that we can query the hardware for the existence and variety of the
+components easily.
+
+2. Implementation
+-----------------
+
+To take advantage of the pre-relocation device tree manipulation mechanism,
+boards have to implement the function board_fix_fdt, which has the following
+signature:
+
+int board_fix_fdt (void *rw_fdt_blob)
+
+The passed-in void pointer is a writeable pointer to the device tree, which can
+be used to manipulate the device tree using e.g. functions from
+include/fdt_support.h. The return value should either be 0 in case of
+successful execution of the device tree manipulation or something else for a
+failure. Note that returning a non-null value from the function will
+unrecoverably halt the boot process, as with any function from init_sequence_f
+(in common/board_f.c).
+
+Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the function
+to be called:
+
+Device Tree Control
+-> [*] Board-specific manipulation of Device Tree
+
++----------------------------------------------------------+
+| WARNING: The actual manipulation of the device tree has  |
+| to be the _last_ set of operations in board_fix_fdt!     |
+| Since the pre-relocation driver model does not adapt to  |
+| changes made to the device tree either, its references   |
+| into the device tree will be invalid after manipulating  |
+| it, and unpredictable behavior might occur when          |
+| functions that rely on them are executed!                |
++----------------------------------------------------------+
+
+Hence, the recommended layout of the board_fixup_fdt call-back function is the
+following:
+
+int board_fix_fdt(void *rw_fdt_blob)
+{
+	/* Collect information about device's hardware and store them in e.g.
+	   local variables */
+
+	/* Do device tree manipulation using the values previously collected */
+
+	/* Return 0 on successful manipulation and non-zero otherwise */
+}
+
+If this convention is kept, both an "additive" approach, meaning that nodes for
+detected components are added to the device tree, as well as a "subtractive"
+approach, meaning that nodes for absent components are removed from the tree,
+as well as a combination of both approaches should work.
+
+3. Example
+----------
+
+The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features a
+board_fix_fdt function, in which six GPIO expanders (which might be present or
+not, since they are on daughter boards) on a I2C bus are queried for, and
+subsequently deactivated in the device tree if they are not present.
+
+Note that the dm_i2c_simple_probe function does not use the device tree, hence
+it is safe to call it after the tree has already been manipulated.
+
+4. Work to be done
+------------------
+
+* The application of device tree overlay should be possible in board_fixup_fdt,
+  but has not been tested at this stage.
+
+2017-01-06, Mario Six <mario.six at gdsys.cc>
diff --git a/dts/Kconfig b/dts/Kconfig
index 4b7d8b15cc..3f64eda619 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -14,6 +14,16 @@ config OF_CONTROL
 	  This feature provides for run-time configuration of U-Boot
 	  via a flattened device tree.

+config OF_BOARD_FIXUP
+	bool "Board-specific manipulation of Device Tree"
+	help
+	  In certain circumstances it is necessary to be able to modify
+	  U-Boot's device tree (e.g. to delete device from it). This option
+	  make the Device Tree writeable and provides a board-specific
+	  "board_fix_fdt" callback (called during pre-relocation time), which
+	  enables the board initialization to modifiy the Device Tree. The
+	  modified copy is subsequently used by U-Boot after relocation.
+
 config SPL_OF_CONTROL
 	bool "Enable run-time configuration via Device Tree in SPL"
 	depends on SPL && OF_CONTROL
diff --git a/include/common.h b/include/common.h
index fbbc2cbc52..2cbbd5a60c 100644
--- a/include/common.h
+++ b/include/common.h
@@ -497,6 +497,7 @@ extern ssize_t spi_write (uchar *, int, uchar *, int);

 /* $(BOARD)/$(BOARD).c */
 int board_early_init_f (void);
+int board_fix_fdt (void *rw_fdt_blob); /* manipulate the U-Boot fdt before its relocation */
 int board_late_init (void);
 int board_postclk_init (void); /* after clocks/timebase, before env/serial */
 int board_early_init_r (void);
--
2.11.0



More information about the U-Boot mailing list