1*4882a593SmuzhiyunDriver Model Compiled-in Device Tree / Platform Data 2*4882a593Smuzhiyun==================================================== 3*4882a593Smuzhiyun 4*4882a593Smuzhiyun 5*4882a593SmuzhiyunIntroduction 6*4882a593Smuzhiyun------------ 7*4882a593Smuzhiyun 8*4882a593SmuzhiyunDevice tree is the standard configuration method in U-Boot. It is used to 9*4882a593Smuzhiyundefine what devices are in the system and provide configuration information 10*4882a593Smuzhiyunto these devices. 11*4882a593Smuzhiyun 12*4882a593SmuzhiyunThe overhead of adding device tree access to U-Boot is fairly modest, 13*4882a593Smuzhiyunapproximately 3KB on Thumb 2 (plus the size of the DT itself). This means 14*4882a593Smuzhiyunthat in most cases it is best to use device tree for configuration. 15*4882a593Smuzhiyun 16*4882a593SmuzhiyunHowever there are some very constrained environments where U-Boot needs to 17*4882a593Smuzhiyunwork. These include SPL with severe memory limitations. For example, some 18*4882a593SmuzhiyunSoCs require a 16KB SPL image which must include a full MMC stack. In this 19*4882a593Smuzhiyuncase the overhead of device tree access may be too great. 20*4882a593Smuzhiyun 21*4882a593SmuzhiyunIt is possible to create platform data manually by defining C structures 22*4882a593Smuzhiyunfor it, and reference that data in a U_BOOT_DEVICE() declaration. This 23*4882a593Smuzhiyunbypasses the use of device tree completely, effectively creating a parallel 24*4882a593Smuzhiyunconfiguration mechanism. But it is an available option for SPL. 25*4882a593Smuzhiyun 26*4882a593SmuzhiyunAs an alternative, a new 'of-platdata' feature is provided. This converts the 27*4882a593Smuzhiyundevice tree contents into C code which can be compiled into the SPL binary. 28*4882a593SmuzhiyunThis saves the 3KB of code overhead and perhaps a few hundred more bytes due 29*4882a593Smuzhiyunto more efficient storage of the data. 30*4882a593Smuzhiyun 31*4882a593SmuzhiyunNote: Quite a bit of thought has gone into the design of this feature. 32*4882a593SmuzhiyunHowever it still has many rough edges and comments and suggestions are 33*4882a593Smuzhiyunstrongly encouraged! Quite possibly there is a much better approach. 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun 36*4882a593SmuzhiyunCaveats 37*4882a593Smuzhiyun------- 38*4882a593Smuzhiyun 39*4882a593SmuzhiyunThere are many problems with this features. It should only be used when 40*4882a593Smuzhiyunstrictly necessary. Notable problems include: 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun - Device tree does not describe data types. But the C code must define a 43*4882a593Smuzhiyun type for each property. These are guessed using heuristics which 44*4882a593Smuzhiyun are wrong in several fairly common cases. For example an 8-byte value 45*4882a593Smuzhiyun is considered to be a 2-item integer array, and is byte-swapped. A 46*4882a593Smuzhiyun boolean value that is not present means 'false', but cannot be 47*4882a593Smuzhiyun included in the structures since there is generally no mention of it 48*4882a593Smuzhiyun in the device tree file. 49*4882a593Smuzhiyun 50*4882a593Smuzhiyun - Naming of nodes and properties is automatic. This means that they follow 51*4882a593Smuzhiyun the naming in the device tree, which may result in C identifiers that 52*4882a593Smuzhiyun look a bit strange. 53*4882a593Smuzhiyun 54*4882a593Smuzhiyun - It is not possible to find a value given a property name. Code must use 55*4882a593Smuzhiyun the associated C member variable directly in the code. This makes 56*4882a593Smuzhiyun the code less robust in the face of device-tree changes. It also 57*4882a593Smuzhiyun makes it very unlikely that your driver code will be useful for more 58*4882a593Smuzhiyun than one SoC. Even if the code is common, each SoC will end up with 59*4882a593Smuzhiyun a different C struct name, and a likely a different format for the 60*4882a593Smuzhiyun platform data. 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun - The platform data is provided to drivers as a C structure. The driver 63*4882a593Smuzhiyun must use the same structure to access the data. Since a driver 64*4882a593Smuzhiyun normally also supports device tree it must use #ifdef to separate 65*4882a593Smuzhiyun out this code, since the structures are only available in SPL. 66*4882a593Smuzhiyun 67*4882a593Smuzhiyun 68*4882a593SmuzhiyunHow it works 69*4882a593Smuzhiyun------------ 70*4882a593Smuzhiyun 71*4882a593SmuzhiyunThe feature is enabled by CONFIG SPL_OF_PLATDATA. This is only available 72*4882a593Smuzhiyunin SPL and should be tested with: 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) 75*4882a593Smuzhiyun 76*4882a593SmuzhiyunA new tool called 'dtoc' converts a device tree file either into a set of 77*4882a593Smuzhiyunstruct declarations, one for each compatible node, or a set of 78*4882a593SmuzhiyunU_BOOT_DEVICE() declarations along with the actual platform data for each 79*4882a593Smuzhiyundevice. As an example, consider this MMC node: 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun sdmmc: dwmmc@ff0c0000 { 82*4882a593Smuzhiyun compatible = "rockchip,rk3288-dw-mshc"; 83*4882a593Smuzhiyun clock-freq-min-max = <400000 150000000>; 84*4882a593Smuzhiyun clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, 85*4882a593Smuzhiyun <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; 86*4882a593Smuzhiyun clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; 87*4882a593Smuzhiyun fifo-depth = <0x100>; 88*4882a593Smuzhiyun interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; 89*4882a593Smuzhiyun reg = <0xff0c0000 0x4000>; 90*4882a593Smuzhiyun bus-width = <4>; 91*4882a593Smuzhiyun cap-mmc-highspeed; 92*4882a593Smuzhiyun cap-sd-highspeed; 93*4882a593Smuzhiyun card-detect-delay = <200>; 94*4882a593Smuzhiyun disable-wp; 95*4882a593Smuzhiyun num-slots = <1>; 96*4882a593Smuzhiyun pinctrl-names = "default"; 97*4882a593Smuzhiyun pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>; 98*4882a593Smuzhiyun vmmc-supply = <&vcc_sd>; 99*4882a593Smuzhiyun status = "okay"; 100*4882a593Smuzhiyun u-boot,dm-pre-reloc; 101*4882a593Smuzhiyun }; 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun 104*4882a593SmuzhiyunSome of these properties are dropped by U-Boot under control of the 105*4882a593SmuzhiyunCONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce 106*4882a593Smuzhiyunthe following C struct declaration: 107*4882a593Smuzhiyun 108*4882a593Smuzhiyunstruct dtd_rockchip_rk3288_dw_mshc { 109*4882a593Smuzhiyun fdt32_t bus_width; 110*4882a593Smuzhiyun bool cap_mmc_highspeed; 111*4882a593Smuzhiyun bool cap_sd_highspeed; 112*4882a593Smuzhiyun fdt32_t card_detect_delay; 113*4882a593Smuzhiyun fdt32_t clock_freq_min_max[2]; 114*4882a593Smuzhiyun struct phandle_1_arg clocks[4]; 115*4882a593Smuzhiyun bool disable_wp; 116*4882a593Smuzhiyun fdt32_t fifo_depth; 117*4882a593Smuzhiyun fdt32_t interrupts[3]; 118*4882a593Smuzhiyun fdt32_t num_slots; 119*4882a593Smuzhiyun fdt32_t reg[2]; 120*4882a593Smuzhiyun fdt32_t vmmc_supply; 121*4882a593Smuzhiyun}; 122*4882a593Smuzhiyun 123*4882a593Smuzhiyunand the following device declaration: 124*4882a593Smuzhiyun 125*4882a593Smuzhiyunstatic struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = { 126*4882a593Smuzhiyun .fifo_depth = 0x100, 127*4882a593Smuzhiyun .cap_sd_highspeed = true, 128*4882a593Smuzhiyun .interrupts = {0x0, 0x20, 0x4}, 129*4882a593Smuzhiyun .clock_freq_min_max = {0x61a80, 0x8f0d180}, 130*4882a593Smuzhiyun .vmmc_supply = 0xb, 131*4882a593Smuzhiyun .num_slots = 0x1, 132*4882a593Smuzhiyun .clocks = {{&dtv_clock_controller_at_ff760000, 456}, 133*4882a593Smuzhiyun {&dtv_clock_controller_at_ff760000, 68}, 134*4882a593Smuzhiyun {&dtv_clock_controller_at_ff760000, 114}, 135*4882a593Smuzhiyun {&dtv_clock_controller_at_ff760000, 118}}, 136*4882a593Smuzhiyun .cap_mmc_highspeed = true, 137*4882a593Smuzhiyun .disable_wp = true, 138*4882a593Smuzhiyun .bus_width = 0x4, 139*4882a593Smuzhiyun .u_boot_dm_pre_reloc = true, 140*4882a593Smuzhiyun .reg = {0xff0c0000, 0x4000}, 141*4882a593Smuzhiyun .card_detect_delay = 0xc8, 142*4882a593Smuzhiyun}; 143*4882a593SmuzhiyunU_BOOT_DEVICE(dwmmc_at_ff0c0000) = { 144*4882a593Smuzhiyun .name = "rockchip_rk3288_dw_mshc", 145*4882a593Smuzhiyun .platdata = &dtv_dwmmc_at_ff0c0000, 146*4882a593Smuzhiyun .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000), 147*4882a593Smuzhiyun}; 148*4882a593Smuzhiyun 149*4882a593SmuzhiyunThe device is then instantiated at run-time and the platform data can be 150*4882a593Smuzhiyunaccessed using: 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun struct udevice *dev; 153*4882a593Smuzhiyun struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev); 154*4882a593Smuzhiyun 155*4882a593SmuzhiyunThis avoids the code overhead of converting the device tree data to 156*4882a593Smuzhiyunplatform data in the driver. The ofdata_to_platdata() method should 157*4882a593Smuzhiyuntherefore do nothing in such a driver. 158*4882a593Smuzhiyun 159*4882a593SmuzhiyunWhere a node has multiple compatible strings, a #define is used to make them 160*4882a593Smuzhiyunequivalent, e.g.: 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun#define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc 163*4882a593Smuzhiyun 164*4882a593Smuzhiyun 165*4882a593SmuzhiyunConverting of-platdata to a useful form 166*4882a593Smuzhiyun--------------------------------------- 167*4882a593Smuzhiyun 168*4882a593SmuzhiyunOf course it would be possible use the of-platdata directly in your driver 169*4882a593Smuzhiyunwhenever configuration information is required. However this meands that the 170*4882a593Smuzhiyundriver will not be able to support device tree, since the of-platdata 171*4882a593Smuzhiyunstructure is not available when device tree is used. It would make no sense 172*4882a593Smuzhiyunto use this structure if device tree were available, since the structure has 173*4882a593Smuzhiyunall the limitations metioned in caveats above. 174*4882a593Smuzhiyun 175*4882a593SmuzhiyunTherefore it is recommended that the of-platdata structure should be used 176*4882a593Smuzhiyunonly in the probe() method of your driver. It cannot be used in the 177*4882a593Smuzhiyunofdata_to_platdata() method since this is not called when platform data is 178*4882a593Smuzhiyunalready present. 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun 181*4882a593SmuzhiyunHow to structure your driver 182*4882a593Smuzhiyun---------------------------- 183*4882a593Smuzhiyun 184*4882a593SmuzhiyunDrivers should always support device tree as an option. The of-platdata 185*4882a593Smuzhiyunfeature is intended as a add-on to existing drivers. 186*4882a593Smuzhiyun 187*4882a593SmuzhiyunYour driver should convert the platdata struct in its probe() method. The 188*4882a593Smuzhiyunexisting device tree decoding logic should be kept in the 189*4882a593Smuzhiyunofdata_to_platdata() method and wrapped with #if. 190*4882a593Smuzhiyun 191*4882a593SmuzhiyunFor example: 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun #include <dt-structs.h> 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun struct mmc_platdata { 196*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) 197*4882a593Smuzhiyun /* Put this first since driver model will copy the data here */ 198*4882a593Smuzhiyun struct dtd_mmc dtplat; 199*4882a593Smuzhiyun #endif 200*4882a593Smuzhiyun /* 201*4882a593Smuzhiyun * Other fields can go here, to be filled in by decoding from 202*4882a593Smuzhiyun * the device tree (or the C structures when of-platdata is used). 203*4882a593Smuzhiyun */ 204*4882a593Smuzhiyun int fifo_depth; 205*4882a593Smuzhiyun }; 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun static int mmc_ofdata_to_platdata(struct udevice *dev) 208*4882a593Smuzhiyun { 209*4882a593Smuzhiyun #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA) 210*4882a593Smuzhiyun /* Decode the device tree data */ 211*4882a593Smuzhiyun struct mmc_platdata *plat = dev_get_platdata(dev); 212*4882a593Smuzhiyun const void *blob = gd->fdt_blob; 213*4882a593Smuzhiyun int node = dev_of_offset(dev); 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); 216*4882a593Smuzhiyun #endif 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun return 0; 219*4882a593Smuzhiyun } 220*4882a593Smuzhiyun 221*4882a593Smuzhiyun static int mmc_probe(struct udevice *dev) 222*4882a593Smuzhiyun { 223*4882a593Smuzhiyun struct mmc_platdata *plat = dev_get_platdata(dev); 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) 226*4882a593Smuzhiyun /* Decode the of-platdata from the C structures */ 227*4882a593Smuzhiyun struct dtd_mmc *dtplat = &plat->dtplat; 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun plat->fifo_depth = dtplat->fifo_depth; 230*4882a593Smuzhiyun #endif 231*4882a593Smuzhiyun /* Set up the device from the plat data */ 232*4882a593Smuzhiyun writel(plat->fifo_depth, ...) 233*4882a593Smuzhiyun } 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun static const struct udevice_id mmc_ids[] = { 236*4882a593Smuzhiyun { .compatible = "vendor,mmc" }, 237*4882a593Smuzhiyun { } 238*4882a593Smuzhiyun }; 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun U_BOOT_DRIVER(mmc_drv) = { 241*4882a593Smuzhiyun .name = "mmc", 242*4882a593Smuzhiyun .id = UCLASS_MMC, 243*4882a593Smuzhiyun .of_match = mmc_ids, 244*4882a593Smuzhiyun .ofdata_to_platdata = mmc_ofdata_to_platdata, 245*4882a593Smuzhiyun .probe = mmc_probe, 246*4882a593Smuzhiyun .priv_auto_alloc_size = sizeof(struct mmc_priv), 247*4882a593Smuzhiyun .platdata_auto_alloc_size = sizeof(struct mmc_platdata), 248*4882a593Smuzhiyun }; 249*4882a593Smuzhiyun 250*4882a593Smuzhiyun 251*4882a593SmuzhiyunIn the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is 252*4882a593Smuzhiyunstill used to allocate space for the platform data. This is different from 253*4882a593Smuzhiyunthe normal behaviour and is triggered by the use of of-platdata (strictly 254*4882a593Smuzhiyunspeaking it is a non-zero platdata_size which triggers this). 255*4882a593Smuzhiyun 256*4882a593SmuzhiyunThe of-platdata struct contents is copied from the C structure data to the 257*4882a593Smuzhiyunstart of the newly allocated area. In the case where device tree is used, 258*4882a593Smuzhiyunthe platform data is allocated, and starts zeroed. In this case the 259*4882a593Smuzhiyunofdata_to_platdata() method should still set up the platform data (and the 260*4882a593Smuzhiyunof-platdata struct will not be present). 261*4882a593Smuzhiyun 262*4882a593SmuzhiyunSPL must use either of-platdata or device tree. Drivers cannot use both at 263*4882a593Smuzhiyunthe same time, but they must support device tree. Supporting of-platdata is 264*4882a593Smuzhiyunoptional. 265*4882a593Smuzhiyun 266*4882a593SmuzhiyunThe device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled, 267*4882a593Smuzhiyunsince the device-tree access code is not compiled in. A corollary is that 268*4882a593Smuzhiyuna board can only move to using of-platdata if all the drivers it uses support 269*4882a593Smuzhiyunit. There would be little point in having some drivers require the device 270*4882a593Smuzhiyuntree data, since then libfdt would still be needed for those drivers and 271*4882a593Smuzhiyunthere would be no code-size benefit. 272*4882a593Smuzhiyun 273*4882a593SmuzhiyunInternals 274*4882a593Smuzhiyun--------- 275*4882a593Smuzhiyun 276*4882a593SmuzhiyunThe dt-structs.h file includes the generated file 277*4882a593Smuzhiyun(include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled. 278*4882a593SmuzhiyunOtherwise (such as in U-Boot proper) these structs are not available. This 279*4882a593Smuzhiyunprevents them being used inadvertently. All usage must be bracketed with 280*4882a593Smuzhiyun#if CONFIG_IS_ENABLED(SPL_OF_PLATDATA). 281*4882a593Smuzhiyun 282*4882a593SmuzhiyunThe dt-platdata.c file contains the device declarations and is is built in 283*4882a593Smuzhiyunspl/dt-platdata.c. 284*4882a593Smuzhiyun 285*4882a593SmuzhiyunSome phandles (thsoe that are recognised as such) are converted into 286*4882a593Smuzhiyunpoints to platform data. This pointer can potentially be used to access the 287*4882a593Smuzhiyunreferenced device (by searching for the pointer value). This feature is not 288*4882a593Smuzhiyunyet implemented, however. 289*4882a593Smuzhiyun 290*4882a593SmuzhiyunThe beginnings of a libfdt Python module are provided. So far this only 291*4882a593Smuzhiyunimplements a subset of the features. 292*4882a593Smuzhiyun 293*4882a593SmuzhiyunThe 'swig' tool is needed to build the libfdt Python module. If this is not 294*4882a593Smuzhiyunfound then the Python model is not used and a fallback is used instead, which 295*4882a593Smuzhiyunmakes use of fdtget. 296*4882a593Smuzhiyun 297*4882a593Smuzhiyun 298*4882a593SmuzhiyunCredits 299*4882a593Smuzhiyun------- 300*4882a593Smuzhiyun 301*4882a593SmuzhiyunThis is an implementation of an idea by Tom Rini <trini@konsulko.com>. 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun 304*4882a593SmuzhiyunFuture work 305*4882a593Smuzhiyun----------- 306*4882a593Smuzhiyun- Consider programmatically reading binding files instead of device tree 307*4882a593Smuzhiyun contents 308*4882a593Smuzhiyun- Complete the phandle feature 309*4882a593Smuzhiyun- Move to using a full Python libfdt module 310*4882a593Smuzhiyun 311*4882a593Smuzhiyun-- 312*4882a593SmuzhiyunSimon Glass <sjg@chromium.org> 313*4882a593SmuzhiyunGoogle, Inc 314*4882a593Smuzhiyun6/6/16 315*4882a593SmuzhiyunUpdated Independence Day 2016 316