1.. SPDX-License-Identifier: GPL-2.0+ 2.. 2017-01-06, Mario Six <mario.six@gdsys.cc> 3 4Pre-relocation device tree manipulation 5======================================= 6 7Purpose 8------- 9 10In certain markets, it is beneficial for manufacturers of embedded devices to 11offer certain ranges of products, where the functionality of the devices within 12one series either don't differ greatly from another, or can be thought of as 13"extensions" of each other, where one device only differs from another in the 14addition of a small number of features (e.g. an additional output connector). 15 16To realize this in hardware, one method is to have a motherboard, and several 17possible daughter boards that can be attached to this mother board. Different 18daughter boards then either offer the slightly different functionality, or the 19addition of the daughter board to the device realizes the "extension" of 20functionality to the device described previously. 21 22For the software, we obviously want to reuse components for all these 23variations of the device. This means that the software somehow needs to cope 24with the situation that certain ICs may or may not be present on any given 25system, depending on which daughter boards are connected to the motherboard. 26 27In the Linux kernel, one possible solution to this problem is to employ the 28device tree overlay mechanism: There exists one "base" device tree, which 29features only the components guaranteed to exist in all varieties of the 30device. At the start of the kernel, the presence and type of the daughter 31boards is then detected, and the corresponding device tree overlays are applied 32to support the components on the daughter boards. 33 34Note that the components present on every variety of the board must, of course, 35provide a way to find out if and which daughter boards are installed for this 36mechanism to work. 37 38In the U-Boot boot loader, support for device tree overlays has recently been 39integrated, and is used on some boards to alter the device tree that is later 40passed to Linux. But since U-Boot's driver model, which is device tree-based as 41well, is being used in more and more drivers, the same problem of altering the 42device tree starts cropping up in U-Boot itself as well. 43 44An additional problem with the device tree in U-Boot is that it is read-only, 45and the current mechanisms don't allow easy manipulation of the device tree 46after the driver model has been initialized. While migrating to a live device 47tree (at least after the relocation) would greatly simplify the solution of 48this problem, it is a non-negligible task to implement it, an a interim 49solution is needed to address the problem at least in the medium-term. 50 51Hence, we propose a solution to this problem by offering a board-specific 52call-back function, which is passed a writeable pointer to the device tree. 53This function is called before the device tree is relocated, and specifically 54before the main U-Boot's driver model is instantiated, hence the main U-Boot 55"sees" all modifications to the device tree made in this function. Furthermore, 56we have the pre-relocation driver model at our disposal at this stage, which 57means that we can query the hardware for the existence and variety of the 58components easily. 59 60Implementation 61-------------- 62 63To take advantage of the pre-relocation device tree manipulation mechanism, 64boards have to implement the function board_fix_fdt, which has the following 65signature: 66 67.. code-block:: c 68 69 int board_fix_fdt (void *rw_fdt_blob) 70 71The passed-in void pointer is a writeable pointer to the device tree, which can 72be used to manipulate the device tree using e.g. functions from 73include/fdt_support.h. The return value should either be 0 in case of 74successful execution of the device tree manipulation or something else for a 75failure. Note that returning a non-null value from the function will 76unrecoverably halt the boot process, as with any function from init_sequence_f 77(in common/board_f.c). 78 79Furthermore, the Kconfig option OF_BOARD_FIXUP has to be set for the function 80to be called:: 81 82 Device Tree Control 83 -> [*] Board-specific manipulation of Device Tree 84 85+----------------------------------------------------------+ 86| WARNING: The actual manipulation of the device tree has | 87| to be the _last_ set of operations in board_fix_fdt! | 88| Since the pre-relocation driver model does not adapt to | 89| changes made to the device tree either, its references | 90| into the device tree will be invalid after manipulating | 91| it, and unpredictable behavior might occur when | 92| functions that rely on them are executed! | 93+----------------------------------------------------------+ 94 95Hence, the recommended layout of the board_fixup_fdt call-back function is the 96following: 97 98.. code-block:: c 99 100 int board_fix_fdt(void *rw_fdt_blob) 101 { 102 /* 103 * Collect information about device's hardware and store 104 * them in e.g. local variables 105 */ 106 107 /* Do device tree manipulation using the values previously collected */ 108 109 /* Return 0 on successful manipulation and non-zero otherwise */ 110 } 111 112If this convention is kept, both an "additive" approach, meaning that nodes for 113detected components are added to the device tree, as well as a "subtractive" 114approach, meaning that nodes for absent components are removed from the tree, 115as well as a combination of both approaches should work. 116 117Example 118------- 119 120The controlcenterdc board (board/gdsys/a38x/controlcenterdc.c) features a 121board_fix_fdt function, in which six GPIO expanders (which might be present or 122not, since they are on daughter boards) on a I2C bus are queried for, and 123subsequently deactivated in the device tree if they are not present. 124 125Note that the dm_i2c_simple_probe function does not use the device tree, hence 126it is safe to call it after the tree has already been manipulated. 127 128Work to be done 129--------------- 130 131* The application of device tree overlay should be possible in board_fixup_fdt, 132 but has not been tested at this stage. 133