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