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 312There is an alternative syntax to the expanded form for overlays with phandle 313targets which makes the format similar to the one using in .dtsi include files. 314 315So for the &ocp target example above one can simply write: 316 317/dts-v1/; 318/plugin/; 319&ocp { 320 /* bar peripheral */ 321 bar { 322 compatible = "corp,bar"; 323 ... /* various properties and child nodes */ 324 } 325}; 326 327The resulting dtb object is identical. 328