aboutsummaryrefslogtreecommitdiff
path: root/doc/driver-model/of-plat.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/driver-model/of-plat.rst')
-rw-r--r--doc/driver-model/of-plat.rst359
1 files changed, 0 insertions, 359 deletions
diff --git a/doc/driver-model/of-plat.rst b/doc/driver-model/of-plat.rst
deleted file mode 100644
index 4ef2fe6..0000000
--- a/doc/driver-model/of-plat.rst
+++ /dev/null
@@ -1,359 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0+
-
-Compiled-in Device Tree / Platform Data
-=======================================
-
-
-Introduction
-------------
-
-Device tree is the standard configuration method in U-Boot. It is used to
-define what devices are in the system and provide configuration information
-to these devices.
-
-The overhead of adding device tree access to U-Boot is fairly modest,
-approximately 3KB on Thumb 2 (plus the size of the DT itself). This means
-that in most cases it is best to use device tree for configuration.
-
-However there are some very constrained environments where U-Boot needs to
-work. These include SPL with severe memory limitations. For example, some
-SoCs require a 16KB SPL image which must include a full MMC stack. In this
-case the overhead of device tree access may be too great.
-
-It is possible to create platform data manually by defining C structures
-for it, and reference that data in a U_BOOT_DRVINFO() declaration. This
-bypasses the use of device tree completely, effectively creating a parallel
-configuration mechanism. But it is an available option for SPL.
-
-As an alternative, a new 'of-platdata' feature is provided. This converts the
-device tree contents into C code which can be compiled into the SPL binary.
-This saves the 3KB of code overhead and perhaps a few hundred more bytes due
-to more efficient storage of the data.
-
-Note: Quite a bit of thought has gone into the design of this feature.
-However it still has many rough edges and comments and suggestions are
-strongly encouraged! Quite possibly there is a much better approach.
-
-
-Caveats
--------
-
-There are many problems with this features. It should only be used when
-strictly necessary. Notable problems include:
-
- - Device tree does not describe data types. But the C code must define a
- type for each property. These are guessed using heuristics which
- are wrong in several fairly common cases. For example an 8-byte value
- is considered to be a 2-item integer array, and is byte-swapped. A
- boolean value that is not present means 'false', but cannot be
- included in the structures since there is generally no mention of it
- in the device tree file.
-
- - Naming of nodes and properties is automatic. This means that they follow
- the naming in the device tree, which may result in C identifiers that
- look a bit strange.
-
- - It is not possible to find a value given a property name. Code must use
- the associated C member variable directly in the code. This makes
- the code less robust in the face of device-tree changes. It also
- makes it very unlikely that your driver code will be useful for more
- than one SoC. Even if the code is common, each SoC will end up with
- a different C struct name, and a likely a different format for the
- platform data.
-
- - The platform data is provided to drivers as a C structure. The driver
- must use the same structure to access the data. Since a driver
- normally also supports device tree it must use #ifdef to separate
- out this code, since the structures are only available in SPL.
-
-
-How it works
-------------
-
-The feature is enabled by CONFIG OF_PLATDATA. This is only available in
-SPL/TPL and should be tested with:
-
-.. code-block:: c
-
- #if CONFIG_IS_ENABLED(OF_PLATDATA)
-
-A new tool called 'dtoc' converts a device tree file either into a set of
-struct declarations, one for each compatible node, and a set of
-U_BOOT_DRVINFO() declarations along with the actual platform data for each
-device. As an example, consider this MMC node:
-
-.. code-block:: none
-
- sdmmc: dwmmc@ff0c0000 {
- compatible = "rockchip,rk3288-dw-mshc";
- clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
- <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
- clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
- fifo-depth = <0x100>;
- interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
- reg = <0xff0c0000 0x4000>;
- bus-width = <4>;
- cap-mmc-highspeed;
- cap-sd-highspeed;
- card-detect-delay = <200>;
- disable-wp;
- num-slots = <1>;
- pinctrl-names = "default";
- pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
- vmmc-supply = <&vcc_sd>;
- status = "okay";
- u-boot,dm-pre-reloc;
- };
-
-
-Some of these properties are dropped by U-Boot under control of the
-CONFIG_OF_SPL_REMOVE_PROPS option. The rest are processed. This will produce
-the following C struct declaration:
-
-.. code-block:: c
-
- struct dtd_rockchip_rk3288_dw_mshc {
- fdt32_t bus_width;
- bool cap_mmc_highspeed;
- bool cap_sd_highspeed;
- fdt32_t card_detect_delay;
- fdt32_t clock_freq_min_max[2];
- struct phandle_1_arg clocks[4];
- bool disable_wp;
- fdt32_t fifo_depth;
- fdt32_t interrupts[3];
- fdt32_t num_slots;
- fdt32_t reg[2];
- fdt32_t vmmc_supply;
- };
-
-and the following device declarations:
-
-.. code-block:: c
-
- /* Node /clock-controller@ff760000 index 0 */
- ...
-
- /* Node /dwmmc@ff0c0000 index 2 */
- static struct dtd_rockchip_rk3288_dw_mshc dtv_dwmmc_at_ff0c0000 = {
- .fifo_depth = 0x100,
- .cap_sd_highspeed = true,
- .interrupts = {0x0, 0x20, 0x4},
- .clock_freq_min_max = {0x61a80, 0x8f0d180},
- .vmmc_supply = 0xb,
- .num_slots = 0x1,
- .clocks = {{0, 456},
- {0, 68},
- {0, 114},
- {0, 118}},
- .cap_mmc_highspeed = true,
- .disable_wp = true,
- .bus_width = 0x4,
- .u_boot_dm_pre_reloc = true,
- .reg = {0xff0c0000, 0x4000},
- .card_detect_delay = 0xc8,
- };
-
- U_BOOT_DRVINFO(dwmmc_at_ff0c0000) = {
- .name = "rockchip_rk3288_dw_mshc",
- .plat = &dtv_dwmmc_at_ff0c0000,
- .plat_size = sizeof(dtv_dwmmc_at_ff0c0000),
- .parent_idx = -1,
- };
-
-The device is then instantiated at run-time and the platform data can be
-accessed using:
-
-.. code-block:: c
-
- struct udevice *dev;
- struct dtd_rockchip_rk3288_dw_mshc *plat = dev_get_plat(dev);
-
-This avoids the code overhead of converting the device tree data to
-platform data in the driver. The of_to_plat() method should
-therefore do nothing in such a driver.
-
-Note that for the platform data to be matched with a driver, the 'name'
-property of the U_BOOT_DRVINFO() declaration has to match a driver declared
-via U_BOOT_DRIVER(). This effectively means that a U_BOOT_DRIVER() with a
-'name' corresponding to the devicetree 'compatible' string (after converting
-it to a valid name for C) is needed, so a dedicated driver is required for
-each 'compatible' string.
-
-In order to make this a bit more flexible DM_DRIVER_ALIAS macro can be
-used to declare an alias for a driver name, typically a 'compatible' string.
-This macro produces no code, but it is by dtoc tool.
-
-The parent_idx is the index of the parent driver_info structure within its
-linker list (instantiated by the U_BOOT_DRVINFO() macro). This is used to support
-dev_get_parent().
-
-During the build process dtoc parses both U_BOOT_DRIVER and DM_DRIVER_ALIAS
-to build a list of valid driver names and driver aliases. If the 'compatible'
-string used for a device does not not match a valid driver name, it will be
-checked against the list of driver aliases in order to get the right driver
-name to use. If in this step there is no match found a warning is issued to
-avoid run-time failures.
-
-Where a node has multiple compatible strings, a #define is used to make them
-equivalent, e.g.:
-
-.. code-block:: c
-
- #define dtd_rockchip_rk3299_dw_mshc dtd_rockchip_rk3288_dw_mshc
-
-
-Converting of-platdata to a useful form
----------------------------------------
-
-Of course it would be possible to use the of-platdata directly in your driver
-whenever configuration information is required. However this means that the
-driver will not be able to support device tree, since the of-platdata
-structure is not available when device tree is used. It would make no sense
-to use this structure if device tree were available, since the structure has
-all the limitations metioned in caveats above.
-
-Therefore it is recommended that the of-platdata structure should be used
-only in the probe() method of your driver. It cannot be used in the
-of_to_plat() method since this is not called when platform data is
-already present.
-
-
-How to structure your driver
-----------------------------
-
-Drivers should always support device tree as an option. The of-platdata
-feature is intended as a add-on to existing drivers.
-
-Your driver should convert the plat struct in its probe() method. The
-existing device tree decoding logic should be kept in the
-of_to_plat() method and wrapped with #if.
-
-For example:
-
-.. code-block:: c
-
- #include <dt-structs.h>
-
- struct mmc_plat {
- #if CONFIG_IS_ENABLED(OF_PLATDATA)
- /* Put this first since driver model will copy the data here */
- struct dtd_mmc dtplat;
- #endif
- /*
- * Other fields can go here, to be filled in by decoding from
- * the device tree (or the C structures when of-platdata is used).
- */
- int fifo_depth;
- };
-
- static int mmc_of_to_plat(struct udevice *dev)
- {
- #if !CONFIG_IS_ENABLED(OF_PLATDATA)
- /* Decode the device tree data */
- struct mmc_plat *plat = dev_get_plat(dev);
- const void *blob = gd->fdt_blob;
- int node = dev_of_offset(dev);
-
- plat->fifo_depth = fdtdec_get_int(blob, node, "fifo-depth", 0);
- #endif
-
- return 0;
- }
-
- static int mmc_probe(struct udevice *dev)
- {
- struct mmc_plat *plat = dev_get_plat(dev);
-
- #if CONFIG_IS_ENABLED(OF_PLATDATA)
- /* Decode the of-platdata from the C structures */
- struct dtd_mmc *dtplat = &plat->dtplat;
-
- plat->fifo_depth = dtplat->fifo_depth;
- #endif
- /* Set up the device from the plat data */
- writel(plat->fifo_depth, ...)
- }
-
- static const struct udevice_id mmc_ids[] = {
- { .compatible = "vendor,mmc" },
- { }
- };
-
- U_BOOT_DRIVER(mmc_drv) = {
- .name = "mmc_drv",
- .id = UCLASS_MMC,
- .of_match = mmc_ids,
- .of_to_plat = mmc_of_to_plat,
- .probe = mmc_probe,
- .priv_auto = sizeof(struct mmc_priv),
- .plat_auto = sizeof(struct mmc_plat),
- };
-
- DM_DRIVER_ALIAS(mmc_drv, vendor_mmc) /* matches compatible string */
-
-Note that struct mmc_plat is defined in the C file, not in a header. This
-is to avoid needing to include dt-structs.h in a header file. The idea is to
-keep the use of each of-platdata struct to the smallest possible code area.
-There is just one driver C file for each struct, that can convert from the
-of-platdata struct to the standard one used by the driver.
-
-In the case where SPL_OF_PLATDATA is enabled, plat_auto is
-still used to allocate space for the platform data. This is different from
-the normal behaviour and is triggered by the use of of-platdata (strictly
-speaking it is a non-zero plat_size which triggers this).
-
-The of-platdata struct contents is copied from the C structure data to the
-start of the newly allocated area. In the case where device tree is used,
-the platform data is allocated, and starts zeroed. In this case the
-of_to_plat() method should still set up the platform data (and the
-of-platdata struct will not be present).
-
-SPL must use either of-platdata or device tree. Drivers cannot use both at
-the same time, but they must support device tree. Supporting of-platdata is
-optional.
-
-The device tree becomes in accessible when CONFIG_SPL_OF_PLATDATA is enabled,
-since the device-tree access code is not compiled in. A corollary is that
-a board can only move to using of-platdata if all the drivers it uses support
-it. There would be little point in having some drivers require the device
-tree data, since then libfdt would still be needed for those drivers and
-there would be no code-size benefit.
-
-Internals
----------
-
-The dt-structs.h file includes the generated file
-(include/generated//dt-structs.h) if CONFIG_SPL_OF_PLATDATA is enabled.
-Otherwise (such as in U-Boot proper) these structs are not available. This
-prevents them being used inadvertently. All usage must be bracketed with
-#if CONFIG_IS_ENABLED(OF_PLATDATA).
-
-The dt-plat.c file contains the device declarations and is is built in
-spl/dt-plat.c.
-
-The dm_populate_phandle_data() function that was previous needed has now been
-removed, since dtoc can address the drivers directly from dt-plat.c and does
-not need to fix up things at runtime.
-
-The pylibfdt Python module is used to access the devicetree.
-
-
-Credits
--------
-
-This is an implementation of an idea by Tom Rini <trini@konsulko.com>.
-
-
-Future work
------------
-- Consider programmatically reading binding files instead of device tree
- contents
-
-
-.. Simon Glass <sjg@chromium.org>
-.. Google, Inc
-.. 6/6/16
-.. Updated Independence Day 2016
-.. Updated 1st October 2020