]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/dtc/Documentation/dt-object-internal.txt
MFV r341618:
[FreeBSD/FreeBSD.git] / contrib / dtc / Documentation / dt-object-internal.txt
1 Device Tree Dynamic Object format internals
2 -------------------------------------------
3
4 The Device Tree for most platforms is a static representation of
5 the hardware capabilities. This is insufficient for platforms
6 that need to dynamically insert Device Tree fragments into the
7 live tree.
8
9 This document explains the the Device Tree object format and
10 modifications made to the Device Tree compiler, which make it possible.
11
12 1. Simplified Problem Definition
13 --------------------------------
14
15 Assume we have a platform which boots using following simplified Device Tree.
16
17 ---- foo.dts -----------------------------------------------------------------
18         /* FOO platform */
19         / {
20                 compatible = "corp,foo";
21
22                 /* shared resources */
23                 res: res {
24                 };
25
26                 /* On chip peripherals */
27                 ocp: ocp {
28                         /* peripherals that are always instantiated */
29                         peripheral1 { ... };
30                 };
31         };
32 ---- foo.dts -----------------------------------------------------------------
33
34 We have a number of peripherals that after probing (using some undefined method)
35 should result in different Device Tree configuration.
36
37 We cannot boot with this static tree because due to the configuration of the
38 foo platform there exist multiple conficting peripherals DT fragments.
39
40 So for the bar peripheral we would have this:
41
42 ---- foo+bar.dts -------------------------------------------------------------
43         /* FOO platform + bar peripheral */
44         / {
45                 compatible = "corp,foo";
46
47                 /* shared resources */
48                 res: res {
49                 };
50
51                 /* On chip peripherals */
52                 ocp: ocp {
53                         /* peripherals that are always instantiated */
54                         peripheral1 { ... };
55
56                         /* bar peripheral */
57                         bar {
58                                 compatible = "corp,bar";
59                                 ... /* various properties and child nodes */
60                         };
61                 };
62         };
63 ---- foo+bar.dts -------------------------------------------------------------
64
65 While for the baz peripheral we would have this:
66
67 ---- foo+baz.dts -------------------------------------------------------------
68         /* FOO platform + baz peripheral */
69         / {
70                 compatible = "corp,foo";
71
72                 /* shared resources */
73                 res: res {
74                         /* baz resources */
75                         baz_res: res_baz { ... };
76                 };
77
78                 /* On chip peripherals */
79                 ocp: ocp {
80                         /* peripherals that are always instantiated */
81                         peripheral1 { ... };
82
83                         /* baz peripheral */
84                         baz {
85                                 compatible = "corp,baz";
86                                 /* reference to another point in the tree */
87                                 ref-to-res = <&baz_res>;
88                                 ... /* various properties and child nodes */
89                         };
90                 };
91         };
92 ---- foo+baz.dts -------------------------------------------------------------
93
94 We note that the baz case is more complicated, since the baz peripheral needs to
95 reference another node in the DT tree.
96
97 2. Device Tree Object Format Requirements
98 -----------------------------------------
99
100 Since the Device Tree is used for booting a number of very different hardware
101 platforms it is imperative that we tread very carefully.
102
103 2.a) No changes to the Device Tree binary format for the base tree. We cannot
104 modify the tree format at all and all the information we require should be
105 encoded using Device Tree itself. We can add nodes that can be safely ignored
106 by both bootloaders and the kernel. The plugin dtbs are optionally tagged
107 with a different magic number in the header but otherwise they're simple
108 blobs.
109
110 2.b) Changes to the DTS source format should be absolutely minimal, and should
111 only be needed for the DT fragment definitions, and not the base boot DT.
112
113 2.c) An explicit option should be used to instruct DTC to generate the required
114 information needed for object resolution. Platforms that don't use the
115 dynamic object format can safely ignore it.
116
117 2.d) Finally, DT syntax changes should be kept to a minimum. It should be
118 possible to express everything using the existing DT syntax.
119
120 3. Implementation
121 -----------------
122
123 The basic unit of addressing in Device Tree is the phandle. Turns out it's
124 relatively simple to extend the way phandles are generated and referenced
125 so that it's possible to dynamically convert symbolic references (labels)
126 to phandle values. This is a valid assumption as long as the author uses
127 reference syntax and does not assign phandle values manually (which might
128 be a problem with decompiled source files).
129
130 We can roughly divide the operation into two steps.
131
132 3.a) Compilation of the base board DTS file using the '-@' option
133 generates a valid DT blob with an added __symbols__ node at the root node,
134 containing a list of all nodes that are marked with a label.
135
136 Using the foo.dts file above the following node will be generated;
137
138 $ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
139 $ fdtdump foo.dtb
140 ...
141 / {
142         ...
143         res {
144                 ...
145                 phandle = <0x00000001>;
146                 ...
147         };
148         ocp {
149                 ...
150                 phandle = <0x00000002>;
151                 ...
152         };
153         __symbols__ {
154                 res="/res";
155                 ocp="/ocp";
156         };
157 };
158
159 Notice that all the nodes that had a label have been recorded, and that
160 phandles have been generated for them.
161
162 This blob can be used to boot the board normally, the __symbols__ node will
163 be safely ignored both by the bootloader and the kernel (the only loss will
164 be a few bytes of memory and disk space).
165
166 We generate a __symbols__ node to record nodes that had labels in the base
167 tree (or subsequent loaded overlays) so that they can be matched up with
168 references made to them in Device Tree objects.
169
170 3.b) The Device Tree fragments must be compiled with the same option but they
171 must also have a tag (/plugin/) that allows undefined references to nodes
172 that are not present at compilation time to be recorded so that the runtime
173 loader can fix them.
174
175 So the bar peripheral's DTS format would be of the form:
176
177 /dts-v1/;
178 /plugin/;       /* allow undefined references and record them */
179 / {
180         ....    /* various properties for loader use; i.e. part id etc. */
181         fragment@0 {
182                 target = <&ocp>;
183                 __overlay__ {
184                         /* bar peripheral */
185                         bar {
186                                 compatible = "corp,bar";
187                                 ... /* various properties and child nodes */
188                         }
189                 };
190         };
191 };
192
193 Note that there's a target property that specifies the location where the
194 contents of the overlay node will be placed, and it references the node
195 in the foo.dts file.
196
197 $ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
198 $ fdtdump bar.dtbo
199 ...
200 / {
201         ... /* properties */
202         fragment@0 {
203                 target = <0xffffffff>;
204                 __overlay__ {
205                         bar {
206                                 compatible = "corp,bar";
207                                 ... /* various properties and child nodes */
208                         }
209                 };
210         };
211         __fixups__ {
212             ocp = "/fragment@0:target:0";
213         };
214 };
215
216 No __symbols__ node has been generated (no label in bar.dts).
217 Note that the target's ocp label is undefined, so the phandle
218 value is filled with the illegal value '0xffffffff', while a __fixups__
219 node has been generated, which marks the location in the tree where
220 the label lookup should store the runtime phandle value of the ocp node.
221
222 The format of the __fixups__ node entry is
223
224   <label> = "<local-full-path>:<property-name>:<offset>" 
225             [, "<local-full-path>:<property-name>:<offset>"...];
226
227   <label>               Is the label we're referring
228   <local-full-path>     Is the full path of the node the reference is
229   <property-name>       Is the name of the property containing the
230                         reference
231   <offset>              The offset (in bytes) of where the property's
232                         phandle value is located.
233
234 Doing the same with the baz peripheral's DTS format is a little bit more
235 involved, since baz contains references to local labels which require
236 local fixups.
237
238 /dts-v1/;
239 /plugin/;       /* allow undefined label references and record them */
240 / {
241         ....    /* various properties for loader use; i.e. part id etc. */
242         fragment@0 {
243                 target = <&res>;
244                 __overlay__ {
245                         /* baz resources */
246                         baz_res: res_baz { ... };
247                 };
248         };
249         fragment@1 {
250                 target = <&ocp>;
251                 __overlay__ {
252                         /* baz peripheral */
253                         baz {
254                                 compatible = "corp,baz";
255                                 /* reference to another point in the tree */
256                                 ref-to-res = <&baz_res>;
257                                 ... /* various properties and child nodes */
258                         }
259                 };
260         };
261 };
262
263 Note that &bar_res reference.
264
265 $ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
266 $ fdtdump baz.dtbo
267 ...
268 / {
269         ... /* properties */
270         fragment@0 {
271                 target = <0xffffffff>;
272                 __overlay__ {
273                         res_baz {
274                                 ....
275                                 phandle = <0x00000001>;
276                         };
277                 };
278         };
279         fragment@1 {
280                 target = <0xffffffff>;
281                 __overlay__ {
282                         baz {
283                                 compatible = "corp,baz";
284                                 ... /* various properties and child nodes */
285                                 ref-to-res = <0x00000001>;
286                         }
287                 };
288         };
289         __fixups__ {
290                 res = "/fragment@0:target:0";
291                 ocp = "/fragment@1:target:0";
292         };
293         __local_fixups__ {
294                 fragment@1 {
295                         __overlay__ {
296                                 baz {
297                                         ref-to-res = <0>;
298                                 };
299                         };
300                 };
301         };
302 };
303
304 This is similar to the bar case, but the reference of a local label by the
305 baz node generates a __local_fixups__ entry that records the place that the
306 local reference is being made. No matter how phandles are allocated from dtc
307 the run time loader must apply an offset to each phandle in every dynamic
308 DT object loaded. The __local_fixups__ node records the offset relative to the
309 start of every local reference within that property so that the loader can apply
310 the offset.