]>
Commit | Line | Data |
---|---|---|
39782afb SG |
1 | Driver Model Compiled-in Device Tree / Platform Data |
2 | ==================================================== | |
3 | ||
4 | ||
5 | Introduction | |
6 | ------------ | |
7 | ||
8 | Device tree is the standard configuration method in U-Boot. It is used to | |
9 | define what devices are in the system and provide configuration information | |
10 | to these devices. | |
11 | ||
12 | The overhead of adding device tree access to U-Boot is fairly modest, | |
13 | approximately 3KB on Thumb 2 (plus the size of the DT itself). This means | |
14 | that in most cases it is best to use device tree for configuration. | |
15 | ||
16 | However there are some very constrained environments where U-Boot needs to | |
17 | work. These include SPL with severe memory limitations. For example, some | |
18 | SoCs require a 16KB SPL image which must include a full MMC stack. In this | |
19 | case the overhead of device tree access may be too great. | |
20 | ||
21 | It is possible to create platform data manually by defining C structures | |
12696251 SG |
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. | |
39782afb | 25 | |
12696251 | 26 | As an alternative, a new 'of-platdata' feature is provided. This converts the |
39782afb SG |
27 | device tree contents into C code which can be compiled into the SPL binary. |
28 | This saves the 3KB of code overhead and perhaps a few hundred more bytes due | |
29 | to more efficient storage of the data. | |
30 | ||
12696251 SG |
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. | |
34 | ||
39782afb SG |
35 | |
36 | Caveats | |
37 | ------- | |
38 | ||
39 | There are many problems with this features. It should only be used when | |
12696251 | 40 | strictly necessary. Notable problems include: |
39782afb | 41 | |
12696251 SG |
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 | |
39782afb SG |
44 | are wrong in several fairly common cases. For example an 8-byte value |
45 | is considered to be a 2-item integer array, and is byte-swapped. A | |
46 | boolean value that is not present means 'false', but cannot be | |
47 | included in the structures since there is generally no mention of it | |
48 | in the device tree file. | |
49 | ||
50 | - Naming of nodes and properties is automatic. This means that they follow | |
51 | the naming in the device tree, which may result in C identifiers that | |
12696251 | 52 | look a bit strange. |
39782afb SG |
53 | |
54 | - It is not possible to find a value given a property name. Code must use | |
55 | the associated C member variable directly in the code. This makes | |
56 | the code less robust in the face of device-tree changes. It also | |
57 | makes it very unlikely that your driver code will be useful for more | |
58 | than one SoC. Even if the code is common, each SoC will end up with | |
12696251 SG |
59 | a different C struct name, and a likely a different format for the |
60 | platform data. | |
39782afb SG |
61 | |
62 | - The platform data is provided to drivers as a C structure. The driver | |
63 | must use the same structure to access the data. Since a driver | |
64 | normally also supports device tree it must use #ifdef to separate | |
65 | out this code, since the structures are only available in SPL. | |
66 | ||
67 | ||
68 | How it works | |
69 | ------------ | |
70 | ||
71 | The feature is enabled by CONFIG SPL_OF_PLATDATA. This is only available | |
72 | in SPL and should be tested with: | |
73 | ||
74 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) | |
75 | ||
76 | A new tool called 'dtoc' converts a device tree file either into a set of | |
77 | struct declarations, one for each compatible node, or a set of | |
78 | U_BOOT_DEVICE() declarations along with the actual platform data for each | |
79 | device. As an example, consider this MMC node: | |
80 | ||
81 | sdmmc: dwmmc@ff0c0000 { | |
82 | compatible = "rockchip,rk3288-dw-mshc"; | |
83 | clock-freq-min-max = <400000 150000000>; | |
84 | clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>, | |
85 | <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>; | |
86 | clock-names = "biu", "ciu", "ciu_drv", "ciu_sample"; | |
87 | fifo-depth = <0x100>; | |
88 | interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; | |
89 | reg = <0xff0c0000 0x4000>; | |
90 | bus-width = <4>; | |
91 | cap-mmc-highspeed; | |
92 | cap-sd-highspeed; | |
93 | card-detect-delay = <200>; | |
94 | disable-wp; | |
95 | num-slots = <1>; | |
96 | pinctrl-names = "default"; | |
97 | pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>; | |
98 | vmmc-supply = <&vcc_sd>; | |
99 | status = "okay"; | |
100 | u-boot,dm-pre-reloc; | |
101 | }; | |
102 | ||
103 | ||
104 | Some of these properties are dropped by U-Boot under control of the | |
105 | CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce | |
106 | the following C struct declaration: | |
107 | ||
108 | struct dtd_rockchip_rk3288_dw_mshc { | |
109 | fdt32_t bus_width; | |
110 | bool cap_mmc_highspeed; | |
111 | bool cap_sd_highspeed; | |
112 | fdt32_t card_detect_delay; | |
113 | fdt32_t clock_freq_min_max[2]; | |
114 | struct phandle_2_cell clocks[4]; | |
115 | bool disable_wp; | |
116 | fdt32_t fifo_depth; | |
117 | fdt32_t interrupts[3]; | |
118 | fdt32_t num_slots; | |
119 | fdt32_t reg[2]; | |
39782afb SG |
120 | fdt32_t vmmc_supply; |
121 | }; | |
122 | ||
123 | and the following device declaration: | |
124 | ||
125 | static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = { | |
126 | .fifo_depth = 0x100, | |
127 | .cap_sd_highspeed = true, | |
128 | .interrupts = {0x0, 0x20, 0x4}, | |
129 | .clock_freq_min_max = {0x61a80, 0x8f0d180}, | |
130 | .vmmc_supply = 0xb, | |
131 | .num_slots = 0x1, | |
12696251 SG |
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}}, | |
39782afb SG |
136 | .cap_mmc_highspeed = true, |
137 | .disable_wp = true, | |
138 | .bus_width = 0x4, | |
139 | .u_boot_dm_pre_reloc = true, | |
140 | .reg = {0xff0c0000, 0x4000}, | |
141 | .card_detect_delay = 0xc8, | |
142 | }; | |
143 | U_BOOT_DEVICE(dwmmc_at_ff0c0000) = { | |
144 | .name = "rockchip_rk3288_dw_mshc", | |
145 | .platdata = &dtv_dwmmc_at_ff0c0000, | |
12696251 | 146 | .platdata_size = sizeof(dtv_dwmmc_at_ff0c0000), |
39782afb SG |
147 | }; |
148 | ||
149 | The device is then instantiated at run-time and the platform data can be | |
150 | accessed using: | |
151 | ||
152 | struct udevice *dev; | |
153 | struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_platdata(dev); | |
154 | ||
155 | This avoids the code overhead of converting the device tree data to | |
156 | platform data in the driver. The ofdata_to_platdata() method should | |
157 | therefore do nothing in such a driver. | |
158 | ||
159 | ||
12696251 SG |
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 | ||
39782afb SG |
176 | How to structure your driver |
177 | ---------------------------- | |
178 | ||
179 | Drivers should always support device tree as an option. The of-platdata | |
180 | feature is intended as a add-on to existing drivers. | |
181 | ||
12696251 SG |
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. | |
39782afb SG |
185 | |
186 | For example: | |
187 | ||
188 | #include <dt-structs.h> | |
189 | ||
190 | struct mmc_platdata { | |
191 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) | |
12696251 | 192 | /* Put this first since driver model will copy the data here */ |
39782afb SG |
193 | struct dtd_mmc dtplat; |
194 | #endif | |
195 | /* | |
196 | * Other fields can go here, to be filled in by decoding from | |
12696251 | 197 | * the device tree (or the C structures when of-platdata is used). |
39782afb SG |
198 | */ |
199 | int fifo_depth; | |
200 | }; | |
201 | ||
202 | static int mmc_ofdata_to_platdata(struct udevice *dev) | |
203 | { | |
204 | #if !CONFIG_IS_ENABLED(SPL_OF_PLATDATA) | |
12696251 | 205 | /* Decode the device tree data */ |
39782afb SG |
206 | struct mmc_platdata *plat = dev_get_platdata(dev); |
207 | const void *blob = gd->fdt_blob; | |
e160f7d4 | 208 | int node = dev_of_offset(dev); |
39782afb SG |
209 | |
210 | plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0); | |
211 | #endif | |
212 | ||
213 | return 0; | |
214 | } | |
215 | ||
216 | static int mmc_probe(struct udevice *dev) | |
217 | { | |
218 | struct mmc_platdata *plat = dev_get_platdata(dev); | |
12696251 | 219 | |
39782afb | 220 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA) |
12696251 | 221 | /* Decode the of-platdata from the C structures */ |
39782afb SG |
222 | struct dtd_mmc *dtplat = &plat->dtplat; |
223 | ||
12696251 SG |
224 | plat->fifo_depth = dtplat->fifo_depth; |
225 | #endif | |
39782afb SG |
226 | /* Set up the device from the plat data */ |
227 | writel(plat->fifo_depth, ...) | |
39782afb SG |
228 | } |
229 | ||
230 | static const struct udevice_id mmc_ids[] = { | |
231 | { .compatible = "vendor,mmc" }, | |
232 | { } | |
233 | }; | |
234 | ||
235 | U_BOOT_DRIVER(mmc_drv) = { | |
236 | .name = "mmc", | |
237 | .id = UCLASS_MMC, | |
238 | .of_match = mmc_ids, | |
239 | .ofdata_to_platdata = mmc_ofdata_to_platdata, | |
240 | .probe = mmc_probe, | |
241 | .priv_auto_alloc_size = sizeof(struct mmc_priv), | |
242 | .platdata_auto_alloc_size = sizeof(struct mmc_platdata), | |
243 | }; | |
244 | ||
245 | ||
246 | In the case where SPL_OF_PLATDATA is enabled, platdata_auto_alloc_size is | |
12696251 SG |
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). | |
39782afb | 250 | |
12696251 SG |
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). | |
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. | |
39782afb | 260 | |
12696251 SG |
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. | |
39782afb SG |
267 | |
268 | Internals | |
269 | --------- | |
270 | ||
271 | The dt-structs.h file includes the generated file | |
272 | (include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled. | |
273 | Otherwise (such as in U-Boot proper) these structs are not available. This | |
12696251 SG |
274 | prevents them being used inadvertently. All usage must be bracketed with |
275 | #if CONFIG_IS_ENABLED(SPL_OF_PLATDATA). | |
39782afb SG |
276 | |
277 | The dt-platdata.c file contains the device declarations and is is built in | |
278 | spl/dt-platdata.c. | |
279 | ||
280 | Some phandles (thsoe that are recognised as such) are converted into | |
281 | points to platform data. This pointer can potentially be used to access the | |
282 | referenced device (by searching for the pointer value). This feature is not | |
283 | yet implemented, however. | |
284 | ||
285 | The beginnings of a libfdt Python module are provided. So far this only | |
286 | implements a subset of the features. | |
287 | ||
12696251 SG |
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. | |
291 | ||
292 | ||
293 | Credits | |
294 | ------- | |
295 | ||
296 | This is an implementation of an idea by Tom Rini <trini@konsulko.com>. | |
39782afb SG |
297 | |
298 | ||
299 | Future work | |
300 | ----------- | |
39782afb SG |
301 | - Consider programmatically reading binding files instead of device tree |
302 | contents | |
39782afb | 303 | - Complete the phandle feature |
39782afb SG |
304 | - Move to using a full Python libfdt module |
305 | ||
306 | -- | |
307 | Simon Glass <sjg@chromium.org> | |
12696251 | 308 | Google, Inc |
39782afb | 309 | 6/6/16 |
12696251 | 310 | Updated Independence Day 2016 |