[U-Boot] [PATCH v2 05/18] dm: Add callback to modify the device tree
Stefan Roese
sr at denx.de
Wed Jan 18 17:03:15 CET 2017
On 11.01.2017 16:00, Mario Six wrote:
> 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 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
Mario, thanks for the extensive documentation in this new version.
I would like to see some review comments from Simon (who is working
on a live DT as I've noticed just today) and perhaps others on this
patch.
Simon, could you please take a look at this?
Thanks,
Stefan
> ---
> 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 cc8aee7..e877bf9 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)
>
> @@ -1037,6 +1044,9 @@ static 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 0000000..70344bd
> --- /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 4b7d8b1..3f64eda 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 a8d833b..a64f249 100644
> --- a/include/common.h
> +++ b/include/common.h
> @@ -502,6 +502,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.9.0
>
Viele Grüße,
Stefan
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de
More information about the U-Boot
mailing list