]>
Commit | Line | Data |
---|---|---|
2a792753 | 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@gdsys.cc> |