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