1314985SgonzoDevice Tree Dynamic Object format internals
2314985Sgonzo-------------------------------------------
3314985Sgonzo
4314985SgonzoThe Device Tree for most platforms is a static representation of
5314985Sgonzothe hardware capabilities. This is insufficient for platforms
6314985Sgonzothat need to dynamically insert Device Tree fragments into the
7314985Sgonzolive tree.
8314985Sgonzo
9314985SgonzoThis document explains the the Device Tree object format and
10314985Sgonzomodifications made to the Device Tree compiler, which make it possible.
11314985Sgonzo
12314985Sgonzo1. Simplified Problem Definition
13314985Sgonzo--------------------------------
14314985Sgonzo
15314985SgonzoAssume we have a platform which boots using following simplified Device Tree.
16314985Sgonzo
17314985Sgonzo---- foo.dts -----------------------------------------------------------------
18314985Sgonzo	/* FOO platform */
19314985Sgonzo	/ {
20314985Sgonzo		compatible = "corp,foo";
21314985Sgonzo
22314985Sgonzo		/* shared resources */
23314985Sgonzo		res: res {
24314985Sgonzo		};
25314985Sgonzo
26314985Sgonzo		/* On chip peripherals */
27314985Sgonzo		ocp: ocp {
28314985Sgonzo			/* peripherals that are always instantiated */
29314985Sgonzo			peripheral1 { ... };
30314985Sgonzo		};
31314985Sgonzo	};
32314985Sgonzo---- foo.dts -----------------------------------------------------------------
33314985Sgonzo
34314985SgonzoWe have a number of peripherals that after probing (using some undefined method)
35314985Sgonzoshould result in different Device Tree configuration.
36314985Sgonzo
37314985SgonzoWe cannot boot with this static tree because due to the configuration of the
38314985Sgonzofoo platform there exist multiple conficting peripherals DT fragments.
39314985Sgonzo
40314985SgonzoSo for the bar peripheral we would have this:
41314985Sgonzo
42314985Sgonzo---- foo+bar.dts -------------------------------------------------------------
43314985Sgonzo	/* FOO platform + bar peripheral */
44314985Sgonzo	/ {
45314985Sgonzo		compatible = "corp,foo";
46314985Sgonzo
47314985Sgonzo		/* shared resources */
48314985Sgonzo		res: res {
49314985Sgonzo		};
50314985Sgonzo
51314985Sgonzo		/* On chip peripherals */
52314985Sgonzo		ocp: ocp {
53314985Sgonzo			/* peripherals that are always instantiated */
54314985Sgonzo			peripheral1 { ... };
55314985Sgonzo
56314985Sgonzo			/* bar peripheral */
57314985Sgonzo			bar {
58314985Sgonzo				compatible = "corp,bar";
59314985Sgonzo				... /* various properties and child nodes */
60314985Sgonzo			};
61314985Sgonzo		};
62314985Sgonzo	};
63314985Sgonzo---- foo+bar.dts -------------------------------------------------------------
64314985Sgonzo
65314985SgonzoWhile for the baz peripheral we would have this:
66314985Sgonzo
67314985Sgonzo---- foo+baz.dts -------------------------------------------------------------
68314985Sgonzo	/* FOO platform + baz peripheral */
69314985Sgonzo	/ {
70314985Sgonzo		compatible = "corp,foo";
71314985Sgonzo
72314985Sgonzo		/* shared resources */
73314985Sgonzo		res: res {
74314985Sgonzo			/* baz resources */
75314985Sgonzo			baz_res: res_baz { ... };
76314985Sgonzo		};
77314985Sgonzo
78314985Sgonzo		/* On chip peripherals */
79314985Sgonzo		ocp: ocp {
80314985Sgonzo			/* peripherals that are always instantiated */
81314985Sgonzo			peripheral1 { ... };
82314985Sgonzo
83314985Sgonzo			/* baz peripheral */
84314985Sgonzo			baz {
85314985Sgonzo				compatible = "corp,baz";
86314985Sgonzo				/* reference to another point in the tree */
87314985Sgonzo				ref-to-res = <&baz_res>;
88314985Sgonzo				... /* various properties and child nodes */
89314985Sgonzo			};
90314985Sgonzo		};
91314985Sgonzo	};
92314985Sgonzo---- foo+baz.dts -------------------------------------------------------------
93314985Sgonzo
94314985SgonzoWe note that the baz case is more complicated, since the baz peripheral needs to
95314985Sgonzoreference another node in the DT tree.
96314985Sgonzo
97314985Sgonzo2. Device Tree Object Format Requirements
98314985Sgonzo-----------------------------------------
99314985Sgonzo
100314985SgonzoSince the Device Tree is used for booting a number of very different hardware
101314985Sgonzoplatforms it is imperative that we tread very carefully.
102314985Sgonzo
103314985Sgonzo2.a) No changes to the Device Tree binary format for the base tree. We cannot
104314985Sgonzomodify the tree format at all and all the information we require should be
105314985Sgonzoencoded using Device Tree itself. We can add nodes that can be safely ignored
106314985Sgonzoby both bootloaders and the kernel. The plugin dtbs are optionally tagged
107314985Sgonzowith a different magic number in the header but otherwise they're simple
108314985Sgonzoblobs.
109314985Sgonzo
110314985Sgonzo2.b) Changes to the DTS source format should be absolutely minimal, and should
111314985Sgonzoonly be needed for the DT fragment definitions, and not the base boot DT.
112314985Sgonzo
113314985Sgonzo2.c) An explicit option should be used to instruct DTC to generate the required
114314985Sgonzoinformation needed for object resolution. Platforms that don't use the
115314985Sgonzodynamic object format can safely ignore it.
116314985Sgonzo
117314985Sgonzo2.d) Finally, DT syntax changes should be kept to a minimum. It should be
118314985Sgonzopossible to express everything using the existing DT syntax.
119314985Sgonzo
120314985Sgonzo3. Implementation
121314985Sgonzo-----------------
122314985Sgonzo
123314985SgonzoThe basic unit of addressing in Device Tree is the phandle. Turns out it's
124314985Sgonzorelatively simple to extend the way phandles are generated and referenced
125314985Sgonzoso that it's possible to dynamically convert symbolic references (labels)
126314985Sgonzoto phandle values. This is a valid assumption as long as the author uses
127314985Sgonzoreference syntax and does not assign phandle values manually (which might
128314985Sgonzobe a problem with decompiled source files).
129314985Sgonzo
130314985SgonzoWe can roughly divide the operation into two steps.
131314985Sgonzo
132314985Sgonzo3.a) Compilation of the base board DTS file using the '-@' option
133314985Sgonzogenerates a valid DT blob with an added __symbols__ node at the root node,
134314985Sgonzocontaining a list of all nodes that are marked with a label.
135314985Sgonzo
136314985SgonzoUsing the foo.dts file above the following node will be generated;
137314985Sgonzo
138314985Sgonzo$ dtc -@ -O dtb -o foo.dtb -b 0 foo.dts
139314985Sgonzo$ fdtdump foo.dtb
140314985Sgonzo...
141314985Sgonzo/ {
142314985Sgonzo	...
143314985Sgonzo	res {
144314985Sgonzo		...
145314985Sgonzo		phandle = <0x00000001>;
146314985Sgonzo		...
147314985Sgonzo	};
148314985Sgonzo	ocp {
149314985Sgonzo		...
150314985Sgonzo		phandle = <0x00000002>;
151314985Sgonzo		...
152314985Sgonzo	};
153314985Sgonzo	__symbols__ {
154314985Sgonzo		res="/res";
155314985Sgonzo		ocp="/ocp";
156314985Sgonzo	};
157314985Sgonzo};
158314985Sgonzo
159314985SgonzoNotice that all the nodes that had a label have been recorded, and that
160314985Sgonzophandles have been generated for them.
161314985Sgonzo
162314985SgonzoThis blob can be used to boot the board normally, the __symbols__ node will
163314985Sgonzobe safely ignored both by the bootloader and the kernel (the only loss will
164314985Sgonzobe a few bytes of memory and disk space).
165314985Sgonzo
166314985SgonzoWe generate a __symbols__ node to record nodes that had labels in the base
167314985Sgonzotree (or subsequent loaded overlays) so that they can be matched up with
168314985Sgonzoreferences made to them in Device Tree objects.
169314985Sgonzo
170314985Sgonzo3.b) The Device Tree fragments must be compiled with the same option but they
171314985Sgonzomust also have a tag (/plugin/) that allows undefined references to nodes
172314985Sgonzothat are not present at compilation time to be recorded so that the runtime
173314985Sgonzoloader can fix them.
174314985Sgonzo
175314985SgonzoSo the bar peripheral's DTS format would be of the form:
176314985Sgonzo
177314985Sgonzo/dts-v1/;
178314985Sgonzo/plugin/;	/* allow undefined references and record them */
179314985Sgonzo/ {
180314985Sgonzo	....	/* various properties for loader use; i.e. part id etc. */
181314985Sgonzo	fragment@0 {
182314985Sgonzo		target = <&ocp>;
183314985Sgonzo		__overlay__ {
184314985Sgonzo			/* bar peripheral */
185314985Sgonzo			bar {
186314985Sgonzo				compatible = "corp,bar";
187314985Sgonzo				... /* various properties and child nodes */
188314985Sgonzo			}
189314985Sgonzo		};
190314985Sgonzo	};
191314985Sgonzo};
192314985Sgonzo
193314985SgonzoNote that there's a target property that specifies the location where the
194314985Sgonzocontents of the overlay node will be placed, and it references the node
195314985Sgonzoin the foo.dts file.
196314985Sgonzo
197314985Sgonzo$ dtc -@ -O dtb -o bar.dtbo -b 0 bar.dts
198314985Sgonzo$ fdtdump bar.dtbo
199314985Sgonzo...
200314985Sgonzo/ {
201314985Sgonzo	... /* properties */
202314985Sgonzo	fragment@0 {
203314985Sgonzo		target = <0xffffffff>;
204314985Sgonzo		__overlay__ {
205314985Sgonzo			bar {
206314985Sgonzo				compatible = "corp,bar";
207314985Sgonzo				... /* various properties and child nodes */
208314985Sgonzo			}
209314985Sgonzo		};
210314985Sgonzo	};
211314985Sgonzo	__fixups__ {
212314985Sgonzo	    ocp = "/fragment@0:target:0";
213314985Sgonzo	};
214314985Sgonzo};
215314985Sgonzo
216314985SgonzoNo __symbols__ node has been generated (no label in bar.dts).
217314985SgonzoNote that the target's ocp label is undefined, so the phandle
218314985Sgonzovalue is filled with the illegal value '0xffffffff', while a __fixups__
219314985Sgonzonode has been generated, which marks the location in the tree where
220314985Sgonzothe label lookup should store the runtime phandle value of the ocp node.
221314985Sgonzo
222314985SgonzoThe format of the __fixups__ node entry is
223314985Sgonzo
224314985Sgonzo  <label> = "<local-full-path>:<property-name>:<offset>" 
225314985Sgonzo	    [, "<local-full-path>:<property-name>:<offset>"...];
226314985Sgonzo
227314985Sgonzo  <label> 		Is the label we're referring
228314985Sgonzo  <local-full-path>	Is the full path of the node the reference is
229314985Sgonzo  <property-name>	Is the name of the property containing the
230314985Sgonzo			reference
231314985Sgonzo  <offset>		The offset (in bytes) of where the property's
232314985Sgonzo			phandle value is located.
233314985Sgonzo
234314985SgonzoDoing the same with the baz peripheral's DTS format is a little bit more
235314985Sgonzoinvolved, since baz contains references to local labels which require
236314985Sgonzolocal fixups.
237314985Sgonzo
238314985Sgonzo/dts-v1/;
239314985Sgonzo/plugin/;	/* allow undefined label references and record them */
240314985Sgonzo/ {
241314985Sgonzo	....	/* various properties for loader use; i.e. part id etc. */
242314985Sgonzo	fragment@0 {
243314985Sgonzo		target = <&res>;
244314985Sgonzo		__overlay__ {
245314985Sgonzo			/* baz resources */
246314985Sgonzo			baz_res: res_baz { ... };
247314985Sgonzo		};
248314985Sgonzo	};
249314985Sgonzo	fragment@1 {
250314985Sgonzo		target = <&ocp>;
251314985Sgonzo		__overlay__ {
252314985Sgonzo			/* baz peripheral */
253314985Sgonzo			baz {
254314985Sgonzo				compatible = "corp,baz";
255314985Sgonzo				/* reference to another point in the tree */
256314985Sgonzo				ref-to-res = <&baz_res>;
257314985Sgonzo				... /* various properties and child nodes */
258314985Sgonzo			}
259314985Sgonzo		};
260314985Sgonzo	};
261314985Sgonzo};
262314985Sgonzo
263314985SgonzoNote that &bar_res reference.
264314985Sgonzo
265314985Sgonzo$ dtc -@ -O dtb -o baz.dtbo -b 0 baz.dts
266314985Sgonzo$ fdtdump baz.dtbo
267314985Sgonzo...
268314985Sgonzo/ {
269314985Sgonzo	... /* properties */
270314985Sgonzo	fragment@0 {
271314985Sgonzo		target = <0xffffffff>;
272314985Sgonzo		__overlay__ {
273314985Sgonzo			res_baz {
274314985Sgonzo				....
275314985Sgonzo				phandle = <0x00000001>;
276314985Sgonzo			};
277314985Sgonzo		};
278314985Sgonzo	};
279314985Sgonzo	fragment@1 {
280314985Sgonzo		target = <0xffffffff>;
281314985Sgonzo		__overlay__ {
282314985Sgonzo			baz {
283314985Sgonzo				compatible = "corp,baz";
284314985Sgonzo				... /* various properties and child nodes */
285314985Sgonzo				ref-to-res = <0x00000001>;
286314985Sgonzo			}
287314985Sgonzo		};
288314985Sgonzo	};
289314985Sgonzo	__fixups__ {
290314985Sgonzo		res = "/fragment@0:target:0";
291314985Sgonzo		ocp = "/fragment@1:target:0";
292314985Sgonzo	};
293314985Sgonzo	__local_fixups__ {
294314985Sgonzo		fragment@1 {
295314985Sgonzo			__overlay__ {
296314985Sgonzo				baz {
297314985Sgonzo					ref-to-res = <0>;
298314985Sgonzo				};
299314985Sgonzo			};
300314985Sgonzo		};
301314985Sgonzo	};
302314985Sgonzo};
303314985Sgonzo
304314985SgonzoThis is similar to the bar case, but the reference of a local label by the
305314985Sgonzobaz node generates a __local_fixups__ entry that records the place that the
306314985Sgonzolocal reference is being made. No matter how phandles are allocated from dtc
307314985Sgonzothe run time loader must apply an offset to each phandle in every dynamic
308314985SgonzoDT object loaded. The __local_fixups__ node records the offset relative to the
309314985Sgonzostart of every local reference within that property so that the loader can apply
310314985Sgonzothe offset.
311