dt-object-internal.txt revision 318102
1Device Tree Dynamic Object format internals
2-------------------------------------------
3
4The Device Tree for most platforms is a static representation of
5the hardware capabilities. This is insufficient for platforms
6that need to dynamically insert Device Tree fragments into the
7live tree.
8
9This document explains the the Device Tree object format and
10modifications made to the Device Tree compiler, which make it possible.
11
121. Simplified Problem Definition
13--------------------------------
14
15Assume 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
34We have a number of peripherals that after probing (using some undefined method)
35should result in different Device Tree configuration.
36
37We cannot boot with this static tree because due to the configuration of the
38foo platform there exist multiple conficting peripherals DT fragments.
39
40So 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
65While 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
94We note that the baz case is more complicated, since the baz peripheral needs to
95reference another node in the DT tree.
96
972. Device Tree Object Format Requirements
98-----------------------------------------
99
100Since the Device Tree is used for booting a number of very different hardware
101platforms it is imperative that we tread very carefully.
102
1032.a) No changes to the Device Tree binary format for the base tree. We cannot
104modify the tree format at all and all the information we require should be
105encoded using Device Tree itself. We can add nodes that can be safely ignored
106by both bootloaders and the kernel. The plugin dtbs are optionally tagged
107with a different magic number in the header but otherwise they're simple
108blobs.
109
1102.b) Changes to the DTS source format should be absolutely minimal, and should
111only be needed for the DT fragment definitions, and not the base boot DT.
112
1132.c) An explicit option should be used to instruct DTC to generate the required
114information needed for object resolution. Platforms that don't use the
115dynamic object format can safely ignore it.
116
1172.d) Finally, DT syntax changes should be kept to a minimum. It should be
118possible to express everything using the existing DT syntax.
119
1203. Implementation
121-----------------
122
123The basic unit of addressing in Device Tree is the phandle. Turns out it's
124relatively simple to extend the way phandles are generated and referenced
125so that it's possible to dynamically convert symbolic references (labels)
126to phandle values. This is a valid assumption as long as the author uses
127reference syntax and does not assign phandle values manually (which might
128be a problem with decompiled source files).
129
130We can roughly divide the operation into two steps.
131
1323.a) Compilation of the base board DTS file using the '-@' option
133generates a valid DT blob with an added __symbols__ node at the root node,
134containing a list of all nodes that are marked with a label.
135
136Using 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
159Notice that all the nodes that had a label have been recorded, and that
160phandles have been generated for them.
161
162This blob can be used to boot the board normally, the __symbols__ node will
163be safely ignored both by the bootloader and the kernel (the only loss will
164be a few bytes of memory and disk space).
165
166We generate a __symbols__ node to record nodes that had labels in the base
167tree (or subsequent loaded overlays) so that they can be matched up with
168references made to them in Device Tree objects.
169
1703.b) The Device Tree fragments must be compiled with the same option but they
171must also have a tag (/plugin/) that allows undefined references to nodes
172that are not present at compilation time to be recorded so that the runtime
173loader can fix them.
174
175So 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
193Note that there's a target property that specifies the location where the
194contents of the overlay node will be placed, and it references the node
195in 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
216No __symbols__ node has been generated (no label in bar.dts).
217Note that the target's ocp label is undefined, so the phandle
218value is filled with the illegal value '0xffffffff', while a __fixups__
219node has been generated, which marks the location in the tree where
220the label lookup should store the runtime phandle value of the ocp node.
221
222The 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
234Doing the same with the baz peripheral's DTS format is a little bit more
235involved, since baz contains references to local labels which require
236local 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
263Note 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
304This is similar to the bar case, but the reference of a local label by the
305baz node generates a __local_fixups__ entry that records the place that the
306local reference is being made. No matter how phandles are allocated from dtc
307the run time loader must apply an offset to each phandle in every dynamic
308DT object loaded. The __local_fixups__ node records the offset relative to the
309start of every local reference within that property so that the loader can apply
310the offset.
311