Commit 1269625177f120d659f66b18de4b532b16c44561
1 parent
b979d3d4c5
Exists in
v2017.01-smarct4x
and in
28 other branches
dm: Update the of-platdata README for the new features
Revise the content based on the v2 additions. This is kept as a separate patch to avoid confusing those who have already reviewed the v1 series. Signed-off-by: Simon Glass <sjg@chromium.org> Suggested-by: Tom Rini <trini@konsulko.com>
Showing 1 changed file with 76 additions and 34 deletions Side-by-side Diff
doc/driver-model/of-plat.txt
| ... | ... | @@ -19,24 +19,28 @@ |
| 19 | 19 | case the overhead of device tree access may be too great. |
| 20 | 20 | |
| 21 | 21 | It is possible to create platform data manually by defining C structures |
| 22 | -for it, and referencing that data in a U_BOOT_DEVICE() declaration. This | |
| 23 | -bypasses the use of device tree completely, but is an available option for | |
| 24 | -SPL. | |
| 22 | +for it, and reference that data in a U_BOOT_DEVICE() declaration. This | |
| 23 | +bypasses the use of device tree completely, effectively creating a parallel | |
| 24 | +configuration mechanism. But it is an available option for SPL. | |
| 25 | 25 | |
| 26 | -As an alternative, a new 'of-platdata' feature is provided. This converts | |
| 26 | +As an alternative, a new 'of-platdata' feature is provided. This converts the | |
| 27 | 27 | device tree contents into C code which can be compiled into the SPL binary. |
| 28 | 28 | This saves the 3KB of code overhead and perhaps a few hundred more bytes due |
| 29 | 29 | to more efficient storage of the data. |
| 30 | 30 | |
| 31 | +Note: Quite a bit of thought has gone into the design of this feature. | |
| 32 | +However it still has many rough edges and comments and suggestions are | |
| 33 | +strongly encouraged! Quite possibly there is a much better approach. | |
| 31 | 34 | |
| 35 | + | |
| 32 | 36 | Caveats |
| 33 | 37 | ------- |
| 34 | 38 | |
| 35 | 39 | There are many problems with this features. It should only be used when |
| 36 | -stricly necessary. Notable problems include: | |
| 40 | +strictly necessary. Notable problems include: | |
| 37 | 41 | |
| 38 | - - Device tree does not describe data types but the C code must define a | |
| 39 | - type for each property. Thesee are guessed using heuristics which | |
| 42 | + - Device tree does not describe data types. But the C code must define a | |
| 43 | + type for each property. These are guessed using heuristics which | |
| 40 | 44 | are wrong in several fairly common cases. For example an 8-byte value |
| 41 | 45 | is considered to be a 2-item integer array, and is byte-swapped. A |
| 42 | 46 | boolean value that is not present means 'false', but cannot be |
| 43 | 47 | |
| ... | ... | @@ -45,14 +49,15 @@ |
| 45 | 49 | |
| 46 | 50 | - Naming of nodes and properties is automatic. This means that they follow |
| 47 | 51 | the naming in the device tree, which may result in C identifiers that |
| 48 | - look a bit strange | |
| 52 | + look a bit strange. | |
| 49 | 53 | |
| 50 | 54 | - It is not possible to find a value given a property name. Code must use |
| 51 | 55 | the associated C member variable directly in the code. This makes |
| 52 | 56 | the code less robust in the face of device-tree changes. It also |
| 53 | 57 | makes it very unlikely that your driver code will be useful for more |
| 54 | 58 | than one SoC. Even if the code is common, each SoC will end up with |
| 55 | - a different C struct and format for the platform data. | |
| 59 | + a different C struct name, and a likely a different format for the | |
| 60 | + platform data. | |
| 56 | 61 | |
| 57 | 62 | - The platform data is provided to drivers as a C structure. The driver |
| 58 | 63 | must use the same structure to access the data. Since a driver |
| ... | ... | @@ -112,7 +117,6 @@ |
| 112 | 117 | fdt32_t interrupts[3]; |
| 113 | 118 | fdt32_t num_slots; |
| 114 | 119 | fdt32_t reg[2]; |
| 115 | - bool u_boot_dm_pre_reloc; | |
| 116 | 120 | fdt32_t vmmc_supply; |
| 117 | 121 | }; |
| 118 | 122 | |
| ... | ... | @@ -125,7 +129,10 @@ |
| 125 | 129 | .clock_freq_min_max = {0x61a80, 0x8f0d180}, |
| 126 | 130 | .vmmc_supply = 0xb, |
| 127 | 131 | .num_slots = 0x1, |
| 128 | - .clocks = {{&dtv_clock_controller_at_ff760000, 456}, {&dtv_clock_controller_at_ff760000, 68}, {&dtv_clock_controller_at_ff760000, 114}, {&dtv_clock_controller_at_ff760000, 118}}, | |
| 132 | + .clocks = {{&dtv_clock_controller_at_ff760000, 456}, | |
| 133 | + {&dtv_clock_controller_at_ff760000, 68}, | |
| 134 | + {&dtv_clock_controller_at_ff760000, 114}, | |
| 135 | + {&dtv_clock_controller_at_ff760000, 118}}, | |
| 129 | 136 | .cap_mmc_highspeed = true, |
| 130 | 137 | .disable_wp = true, |
| 131 | 138 | .bus_width = 0x4, |
| ... | ... | @@ -136,6 +143,7 @@ |
| 136 | 143 | U_BOOT_DEVICE(dwmmc_at_ff0c0000) = { |
| 137 | 144 | .name = "rockchip_rk3288_dw_mshc", |
| 138 | 145 | .platdata = &dtv_dwmmc_at_ff0c0000, |
| 146 | + .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000), | |
| 139 | 147 | }; |
| 140 | 148 | |
| 141 | 149 | The device is then instantiated at run-time and the platform data can be |
| 142 | 150 | |
| ... | ... | @@ -149,15 +157,31 @@ |
| 149 | 157 | therefore do nothing in such a driver. |
| 150 | 158 | |
| 151 | 159 | |
| 160 | +Converting of-platdata to a useful form | |
| 161 | +--------------------------------------- | |
| 162 | + | |
| 163 | +Of course it would be possible use the of-platdata directly in your driver | |
| 164 | +whenever configuration information is required. However this meands that the | |
| 165 | +driver will not be able to support device tree, since the of-platdata | |
| 166 | +structure is not available when device tree is used. It would make no sense | |
| 167 | +to use this structure if device tree were available, since the structure has | |
| 168 | +all the limitations metioned in caveats above. | |
| 169 | + | |
| 170 | +Therefore it is recommended that the of-platdata structure should be used | |
| 171 | +only in the probe() method of your driver. It cannot be used in the | |
| 172 | +ofdata_to_platdata() method since this is not called when platform data is | |
| 173 | +already present. | |
| 174 | + | |
| 175 | + | |
| 152 | 176 | How to structure your driver |
| 153 | 177 | ---------------------------- |
| 154 | 178 | |
| 155 | 179 | Drivers should always support device tree as an option. The of-platdata |
| 156 | 180 | feature is intended as a add-on to existing drivers. |
| 157 | 181 | |
| 158 | -Your driver should directly access the platdata struct in its probe() | |
| 159 | -method. The existing device tree decoding logic should be kept in the | |
| 160 | -ofdata_to_platdata() and wrapped with #ifdef. | |
| 182 | +Your driver should convert the platdata struct in its probe() method. The | |
| 183 | +existing device tree decoding logic should be kept in the | |
| 184 | +ofdata_to_platdata() method and wrapped with #if. | |
| 161 | 185 | |
| 162 | 186 | For example: |
| 163 | 187 | |
| 164 | 188 | |
| ... | ... | @@ -165,13 +189,12 @@ |
| 165 | 189 | |
| 166 | 190 | struct mmc_platdata { |
| 167 | 191 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) |
| 168 | - /* Put this first */ | |
| 192 | + /* Put this first since driver model will copy the data here */ | |
| 169 | 193 | struct dtd_mmc dtplat; |
| 170 | 194 | #endif |
| 171 | 195 | /* |
| 172 | 196 | * Other fields can go here, to be filled in by decoding from |
| 173 | - * the device tree. They will point to random memory in the | |
| 174 | - * of-plat case. | |
| 197 | + * the device tree (or the C structures when of-platdata is used). | |
| 175 | 198 | */ |
| 176 | 199 | int fifo_depth; |
| 177 | 200 | }; |
| ... | ... | @@ -179,6 +202,7 @@ |
| 179 | 202 | static int mmc_ofdata_to_platdata(struct udevice *dev) |
| 180 | 203 | { |
| 181 | 204 | #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA) |
| 205 | + /* Decode the device tree data */ | |
| 182 | 206 | struct mmc_platdata *plat = dev_get_platdata(dev); |
| 183 | 207 | const void *blob = gd->fdt_blob; |
| 184 | 208 | int node = dev->of_offset; |
| 185 | 209 | |
| 186 | 210 | |
| 187 | 211 | |
| ... | ... | @@ -192,15 +216,15 @@ |
| 192 | 216 | static int mmc_probe(struct udevice *dev) |
| 193 | 217 | { |
| 194 | 218 | struct mmc_platdata *plat = dev_get_platdata(dev); |
| 219 | + | |
| 195 | 220 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) |
| 221 | + /* Decode the of-platdata from the C structures */ | |
| 196 | 222 | struct dtd_mmc *dtplat = &plat->dtplat; |
| 197 | 223 | |
| 198 | - /* Set up the device from the dtplat data */ | |
| 199 | - writel(dtplat->fifo_depth, ...) | |
| 200 | - #else | |
| 224 | + plat->fifo_depth = dtplat->fifo_depth; | |
| 225 | + #endif | |
| 201 | 226 | /* Set up the device from the plat data */ |
| 202 | 227 | writel(plat->fifo_depth, ...) |
| 203 | - #endif | |
| 204 | 228 | } |
| 205 | 229 | |
| 206 | 230 | static const struct udevice_id mmc_ids[] = { |
| 207 | 231 | |
| 208 | 232 | |
| 209 | 233 | |
| 210 | 234 | |
| ... | ... | @@ -220,23 +244,35 @@ |
| 220 | 244 | |
| 221 | 245 | |
| 222 | 246 | In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is |
| 223 | -ignored, and the platform data points to the C structure data. In the case | |
| 224 | -where device tree is used, the platform data is allocated, and starts | |
| 225 | -zeroed. In this case the ofdata_to_platdata() method should set up the | |
| 226 | -platform data. | |
| 247 | +still used to allocate space for the platform data. This is different from | |
| 248 | +the normal behaviour and is triggered by the use of of-platdata (strictly | |
| 249 | +speaking it is a non-zero platdata_size which triggers this). | |
| 227 | 250 | |
| 228 | -SPL must use either of-platdata or device tree. Drivers cannot use both. | |
| 229 | -The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled, | |
| 230 | -since the device-tree access code is not compiled in. | |
| 251 | +The of-platdata struct contents is copied from the C structure data to the | |
| 252 | +start of the newly allocated area. In the case where device tree is used, | |
| 253 | +the platform data is allocated, and starts zeroed. In this case the | |
| 254 | +ofdata_to_platdata() method should still set up the platform data (and the | |
| 255 | +of-platdata struct will not be present). | |
| 231 | 256 | |
| 257 | +SPL must use either of-platdata or device tree. Drivers cannot use both at | |
| 258 | +the same time, but they must support device tree. Supporting of-platdata is | |
| 259 | +optional. | |
| 232 | 260 | |
| 261 | +The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled, | |
| 262 | +since the device-tree access code is not compiled in. A corollary is that | |
| 263 | +a board can only move to using of-platdata if all the drivers it uses support | |
| 264 | +it. There would be little point in having some drivers require the device | |
| 265 | +tree data, since then libfdt would still be needed for those drivers and | |
| 266 | +there would be no code-size benefit. | |
| 267 | + | |
| 233 | 268 | Internals |
| 234 | 269 | --------- |
| 235 | 270 | |
| 236 | 271 | The dt-structs.h file includes the generated file |
| 237 | 272 | (include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled. |
| 238 | 273 | Otherwise (such as in U-Boot proper) these structs are not available. This |
| 239 | -prevents them being used inadvertently. | |
| 274 | +prevents them being used inadvertently. All usage must be bracketed with | |
| 275 | +#if CONFIG_IS_ENABLED(SPL_OF_PLATDATA). | |
| 240 | 276 | |
| 241 | 277 | The dt-platdata.c file contains the device declarations and is is built in |
| 242 | 278 | spl/dt-platdata.c. |
| 243 | 279 | |
| 244 | 280 | |
| 245 | 281 | |
| 246 | 282 | |
| 247 | 283 | |
| 248 | 284 | |
| ... | ... | @@ -249,21 +285,27 @@ |
| 249 | 285 | The beginnings of a libfdt Python module are provided. So far this only |
| 250 | 286 | implements a subset of the features. |
| 251 | 287 | |
| 252 | -The 'swig' tool is needed to build the libfdt Python module. | |
| 288 | +The 'swig' tool is needed to build the libfdt Python module. If this is not | |
| 289 | +found then the Python model is not used and a fallback is used instead, which | |
| 290 | +makes use of fdtget. | |
| 253 | 291 | |
| 254 | 292 | |
| 293 | +Credits | |
| 294 | +------- | |
| 295 | + | |
| 296 | +This is an implementation of an idea by Tom Rini <trini@konsulko.com>. | |
| 297 | + | |
| 298 | + | |
| 255 | 299 | Future work |
| 256 | 300 | ----------- |
| 257 | -- Add unit tests | |
| 258 | -- Add a sandbox_spl functional test | |
| 259 | 301 | - Consider programmatically reading binding files instead of device tree |
| 260 | 302 | contents |
| 261 | -- Drop the device tree data from the SPL image | |
| 262 | 303 | - Complete the phandle feature |
| 263 | -- Get this running on a Rockchip board | |
| 264 | 304 | - Move to using a full Python libfdt module |
| 265 | 305 | |
| 266 | 306 | -- |
| 267 | 307 | Simon Glass <sjg@chromium.org> |
| 308 | +Google, Inc | |
| 268 | 309 | 6/6/16 |
| 310 | +Updated Independence Day 2016 |