Quellcode durchsuchen

Merge tag 'dm-pull-26mar21-take2' of git://git.denx.de/u-boot-dm into next

dtoc support for of-platdata-inst
driver model support for of-platdata-inst
support of-platdata-inst on x86 / coral
binman support for exapanded entries
binman convert docs to reST
ti-sysc fix for duplicate uclass driver
patman minor improvements
pylibfdt build only if needed
correct obscure CI error with OF_PLATDATA_INST
Tom Rini vor 3 Jahren
Ursprung
Commit
9c7335e4e6
100 geänderte Dateien mit 2655 neuen und 913 gelöschten Zeilen
  1. 4 1
      .azure-pipelines.yml
  2. 9 1
      .gitlab-ci.yml
  3. 15 3
      Makefile
  4. 0 1
      arch/sandbox/cpu/os.c
  5. 8 0
      arch/sandbox/cpu/u-boot-spl.lds
  6. 9 9
      arch/sandbox/dts/sandbox.dtsi
  7. 3 2
      arch/sandbox/dts/test.dts
  8. 24 0
      arch/sandbox/include/asm/clk.h
  9. 15 0
      arch/sandbox/include/asm/i2c.h
  10. 24 0
      arch/sandbox/include/asm/rtc.h
  11. 2 0
      arch/x86/cpu/apollolake/Kconfig
  12. 1 1
      arch/x86/cpu/apollolake/pmc.c
  13. 1 0
      arch/x86/cpu/apollolake/punit.c
  14. 3 2
      arch/x86/cpu/intel_common/itss.c
  15. 8 0
      arch/x86/cpu/u-boot-spl.lds
  16. 5 5
      arch/x86/dts/chromebook_coral.dts
  17. 1 1
      arch/x86/dts/reset.dtsi
  18. 2 15
      arch/x86/dts/u-boot.dtsi
  19. 1 0
      arch/x86/lib/tpl.c
  20. 7 0
      board/sandbox/MAINTAINERS
  21. 1 0
      board/sandbox/sandbox.c
  22. 24 0
      common/spl/Kconfig
  23. 1 0
      configs/chromebook_coral_defconfig
  24. 231 0
      configs/sandbox_noinst_defconfig
  25. 3 0
      configs/sandbox_spl_defconfig
  26. 2 2
      doc/arch/x86.rst
  27. 0 0
      doc/develop/driver-model/bind.rst
  28. 0 0
      doc/develop/driver-model/debugging.rst
  29. 0 0
      doc/develop/driver-model/design.rst
  30. 0 0
      doc/develop/driver-model/ethernet.rst
  31. 0 0
      doc/develop/driver-model/fdt-fixup.rst
  32. 0 0
      doc/develop/driver-model/fs_firmware_loader.rst
  33. 0 0
      doc/develop/driver-model/i2c-howto.rst
  34. 4 0
      doc/develop/driver-model/index.rst
  35. 0 0
      doc/develop/driver-model/livetree.rst
  36. 0 0
      doc/develop/driver-model/migration.rst
  37. 913 0
      doc/develop/driver-model/of-plat.rst
  38. 1 0
      doc/develop/driver-model/pci-info.rst
  39. 0 0
      doc/develop/driver-model/pmic-framework.rst
  40. 0 0
      doc/develop/driver-model/remoteproc-framework.rst
  41. 0 0
      doc/develop/driver-model/serial-howto.rst
  42. 0 0
      doc/develop/driver-model/soc-framework.rst
  43. 0 0
      doc/develop/driver-model/spi-howto.rst
  44. 0 0
      doc/develop/driver-model/usb-info.rst
  45. 10 0
      doc/develop/index.rst
  46. 1 0
      doc/develop/package/binman.rst
  47. 1 0
      doc/develop/package/entries.rst
  48. 19 0
      doc/develop/package/index.rst
  49. 4 0
      doc/develop/uefi/index.rst
  50. 0 0
      doc/develop/uefi/iscsi.rst
  51. 0 0
      doc/develop/uefi/u-boot_on_efi.rst
  52. 0 0
      doc/develop/uefi/uefi.rst
  53. 0 359
      doc/driver-model/of-plat.rst
  54. 0 23
      doc/index.rst
  55. 8 0
      doc/usage/fit.rst
  56. 1 0
      doc/usage/index.rst
  57. 0 6
      drivers/bus/ti-sysc.c
  58. 1 1
      drivers/clk/clk-uclass.c
  59. 10 4
      drivers/clk/clk_fixed_rate.c
  60. 33 7
      drivers/clk/clk_sandbox.c
  61. 0 6
      drivers/clk/clk_sandbox_test.c
  62. 72 39
      drivers/core/device.c
  63. 2 2
      drivers/core/of_addr.c
  64. 70 15
      drivers/core/root.c
  65. 5 2
      drivers/core/uclass.c
  66. 0 2
      drivers/i2c/Makefile
  67. 18 16
      drivers/i2c/i2c-emul-uclass.c
  68. 1 1
      drivers/misc/irq-uclass.c
  69. 9 2
      drivers/misc/test_drv.c
  70. 1 0
      drivers/mmc/Kconfig
  71. 1 2
      drivers/mmc/fsl_esdhc_imx.c
  72. 1 20
      drivers/rtc/i2c_rtc_emul.c
  73. 13 0
      drivers/rtc/sandbox_rtc.c
  74. 81 2
      dts/Kconfig
  75. 24 2
      include/asm-generic/global_data.h
  76. 3 0
      include/asm-generic/sections.h
  77. 93 0
      include/dm/device-internal.h
  78. 89 19
      include/dm/device.h
  79. 0 15
      include/dm/platdata.h
  80. 3 0
      include/dm/root.h
  81. 5 0
      include/dm/test.h
  82. 52 0
      include/dm/uclass-internal.h
  83. 31 0
      include/dm/uclass.h
  84. 9 0
      include/dm/util.h
  85. 2 0
      include/dt-structs.h
  86. 15 0
      include/i2c.h
  87. 12 0
      include/linker_lists.h
  88. 5 0
      include/linux/clk-provider.h
  89. 35 13
      scripts/Makefile.spl
  90. 9 3
      scripts/dtc/pylibfdt/Makefile
  91. 1 1
      test/cmd/setexpr.c
  92. 16 16
      test/dm/of_platdata.c
  93. 3 3
      test/dm/test-fdt.c
  94. 1 1
      test/print_ut.c
  95. 4 0
      test/run
  96. 19 11
      test/test-main.c
  97. 1 0
      tools/binman/README.rst
  98. 515 268
      tools/binman/binman.rst
  99. 4 1
      tools/binman/cmdline.py
  100. 20 8
      tools/binman/control.py

+ 4 - 1
.azure-pipelines.yml

@@ -148,7 +148,7 @@ jobs:
           export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl
           export PYTHONPATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt
           export PATH=${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}
-          ./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w sandbox_spl
+          ./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w --board sandbox_spl
           ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test
           ./tools/buildman/buildman -t
           ./tools/dtoc/dtoc -t
@@ -187,6 +187,9 @@ jobs:
         sandbox_spl:
           TEST_PY_BD: "sandbox_spl"
           TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
+        sandbox_noinst:
+          TEST_PY_BD: "sandbox_noinst"
+          TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
         sandbox_flattree:
           TEST_PY_BD: "sandbox_flattree"
         evb_ast2500:

+ 9 - 1
.gitlab-ci.yml

@@ -168,7 +168,8 @@ Run binman, buildman, dtoc, Kconfig and patman testsuites:
       export UBOOT_TRAVIS_BUILD_DIR=/tmp/sandbox_spl;
       export PYTHONPATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc/pylibfdt";
       export PATH="${UBOOT_TRAVIS_BUILD_DIR}/scripts/dtc:${PATH}";
-      ./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w sandbox_spl;
+      ./tools/buildman/buildman -T0 -o ${UBOOT_TRAVIS_BUILD_DIR} -w
+        --board sandbox_spl;
       ./tools/binman/binman --toolpath ${UBOOT_TRAVIS_BUILD_DIR}/tools test;
       ./tools/buildman/buildman -t;
       ./tools/dtoc/dtoc -t;
@@ -204,6 +205,13 @@ sandbox_spl test.py:
     TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
   <<: *buildman_and_testpy_dfn
 
+sandbox_noinst_test.py:
+  tags: [ 'all' ]
+  variables:
+    TEST_PY_BD: "sandbox_noinst"
+    TEST_PY_TEST_SPEC: "test_ofplatdata or test_handoff or test_spl"
+  <<: *buildman_and_testpy_dfn
+
 evb-ast2500 test.py:
   tags: [ 'all' ]
   variables:

+ 15 - 3
Makefile

@@ -17,9 +17,13 @@ NAME =
 # o Look for make include files relative to root of kernel src
 MAKEFLAGS += -rR --include-dir=$(CURDIR)
 
-# Determine host architecture
+# Determine target architecture for the sandbox
 include include/host_arch.h
-MK_ARCH="${shell uname -m}"
+ifeq ("", "$(CROSS_COMPILE)")
+  MK_ARCH="${shell uname -m}"
+else
+  MK_ARCH="${shell echo $(CROSS_COMPILE) | sed -n 's/^\s*\([^\/]*\/\)*\([^-]*\)-\S*/\2/p'}"
+endif
 unexport HOST_ARCH
 ifeq ("x86_64", $(MK_ARCH))
   export HOST_ARCH=$(HOST_ARCH_X86_64)
@@ -27,7 +31,7 @@ else ifneq (,$(findstring $(MK_ARCH), "i386" "i486" "i586" "i686"))
   export HOST_ARCH=$(HOST_ARCH_X86)
 else ifneq (,$(findstring $(MK_ARCH), "aarch64" "armv8l"))
   export HOST_ARCH=$(HOST_ARCH_AARCH64)
-else ifeq ("armv7l", $(MK_ARCH))
+else ifneq (,$(findstring $(MK_ARCH), "arm" "armv7" "armv7l"))
   export HOST_ARCH=$(HOST_ARCH_ARM)
 else ifeq ("riscv32", $(MK_ARCH))
   export HOST_ARCH=$(HOST_ARCH_RISCV32)
@@ -1328,6 +1332,11 @@ u-boot.ldr:	u-boot
 # Use 'make BINMAN_DEBUG=1' to enable debugging
 # Use 'make BINMAN_VERBOSE=3' to set vebosity level
 default_dt := $(if $(DEVICE_TREE),$(DEVICE_TREE),$(CONFIG_DEFAULT_DEVICE_TREE))
+
+# Tell binman whether we have a devicetree for SPL and TPL
+have_spl_dt := $(if $(CONFIG_SPL_OF_PLATDATA),,$(CONFIG_SPL_OF_CONTROL))
+have_tpl_dt := $(if $(CONFIG_TPL_OF_PLATDATA),,$(CONFIG_TPL_OF_CONTROL))
+
 quiet_cmd_binman = BINMAN  $@
 cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
                 --toolpath $(objtree)/tools \
@@ -1338,6 +1347,9 @@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \
 		-a atf-bl31-path=${BL31} \
 		-a default-dt=$(default_dt) \
 		-a scp-path=$(SCP) \
+		-a spl-bss-pad=$(if $(CONFIG_SPL_SEPARATE_BSS),,1) \
+		-a tpl-bss-pad=$(if $(CONFIG_TPL_SEPARATE_BSS),,1) \
+		-a spl-dtb=$(have_spl_dt) -a tpl-dtb=$(have_tpl_dt) \
 		$(BINMAN_$(@F))
 
 OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex

+ 0 - 1
arch/sandbox/cpu/os.c

@@ -845,7 +845,6 @@ int os_spl_to_uboot(const char *fname)
 {
 	struct sandbox_state *state = state_get_current();
 
-	printf("%s\n", __func__);
 	/* U-Boot will delete ram buffer after read: "--rm_memory"*/
 	state->ram_buf_rm = true;
 	return os_jump_to_file(fname);

+ 8 - 0
arch/sandbox/cpu/u-boot-spl.lds

@@ -13,6 +13,14 @@ SECTIONS
 		KEEP(*(SORT(.u_boot_list*)));
 	}
 
+	/* Private data for devices with OF_PLATDATA_RT */
+	. = ALIGN(4);
+	.priv_data : {
+		__priv_data_start = .;
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*)))
+		__priv_data_end = .;
+	}
+
 	__u_boot_sandbox_option_start = .;
 	_u_boot_sandbox_getopt : { KEEP(*(.u_boot_sandbox_getopt)) }
 	__u_boot_sandbox_option_end = .;

+ 9 - 9
arch/sandbox/dts/sandbox.dtsi

@@ -31,7 +31,7 @@
 
 	clk_fixed: clk-fixed {
 		u-boot,dm-pre-reloc;
-		compatible = "fixed-clock";
+		compatible = "sandbox,fixed-clock";
 		#clock-cells = <0>;
 		clock-frequency = <1234>;
 	};
@@ -101,15 +101,19 @@
 		};
 
 		i2c_emul: emul {
+			u-boot,dm-pre-reloc;
 			reg = <0xff>;
 			compatible = "sandbox,i2c-emul-parent";
 			emul_eeprom: emul-eeprom {
 				compatible = "sandbox,i2c-eeprom";
 				sandbox,filename = "i2c.bin";
 				sandbox,size = <256>;
+				#emul-cells = <0>;
 			};
 			emul0: emul0 {
-				compatible = "sandbox,i2c-rtc";
+				u-boot,dm-pre-reloc;
+				compatible = "sandbox,i2c-rtc-emul";
+				#emul-cells = <0>;
 			};
 		};
 	};
@@ -260,14 +264,10 @@
 		stringarray = "pre-proper";
 	};
 
-	test-bus {
-		compatible = "simple-bus";
+	spl-test7 {
 		u-boot,dm-spl;
-		spl-test7 {
-			u-boot,dm-spl;
-			compatible = "sandbox,spl-test";
-			stringarray = "spl";
-		};
+		compatible = "sandbox,spl-test";
+		stringarray = "spl";
 	};
 
 	square {

+ 3 - 2
arch/sandbox/dts/test.dts

@@ -604,10 +604,10 @@
 				sandbox,size = <256>;
 			};
 			emul0: emul0 {
-				compatible = "sandbox,i2c-rtc";
+				compatible = "sandbox,i2c-rtc-emul";
 			};
 			emul1: emull {
-				compatible = "sandbox,i2c-rtc";
+				compatible = "sandbox,i2c-rtc-emul";
 			};
 		};
 
@@ -1402,3 +1402,4 @@
 };
 
 #include "sandbox_pmic.dtsi"
+#include "cros-ec-keyboard.dtsi"

+ 24 - 0
arch/sandbox/include/asm/clk.h

@@ -7,6 +7,9 @@
 #define __SANDBOX_CLK_H
 
 #include <common.h>
+#include <clk.h>
+#include <dt-structs.h>
+#include <linux/clk-provider.h>
 
 struct udevice;
 
@@ -45,6 +48,27 @@ enum sandbox_clk_test_id {
 
 #define SANDBOX_CLK_TEST_NON_DEVM_COUNT SANDBOX_CLK_TEST_ID_DEVM1
 
+struct sandbox_clk_priv {
+	bool probed;
+	ulong rate[SANDBOX_CLK_ID_COUNT];
+	bool enabled[SANDBOX_CLK_ID_COUNT];
+	bool requested[SANDBOX_CLK_ID_COUNT];
+};
+
+struct sandbox_clk_test {
+	struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
+	struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
+	struct clk_bulk bulk;
+};
+
+/* Platform data for the sandbox fixed-rate clock driver */
+struct sandbox_clk_fixed_rate_plat {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_sandbox_fixed_clock dtplat;
+#endif
+	struct clk_fixed_rate fixed;
+};
+
 /**
  * sandbox_clk_query_rate - Query the current rate of a sandbox clock.
  *

+ 15 - 0
arch/sandbox/include/asm/i2c.h

@@ -11,4 +11,19 @@ struct sandbox_i2c_priv {
 	bool test_mode;
 };
 
+/**
+ * struct i2c_emul_uc_plat - information about the emulator for this device
+ *
+ * This is used by devices in UCLASS_I2C_EMUL to record information about the
+ * device being emulated. It is accessible with dev_get_uclass_plat()
+ *
+ * @dev: Device being emulated
+ * @idx: of-platdata index, set up by the device's bind() method if of-platdata
+ *	is in use
+ */
+struct i2c_emul_uc_plat {
+	struct udevice *dev;
+	int idx;
+};
+
 #endif /* __asn_i2c_h */

+ 24 - 0
arch/sandbox/include/asm/rtc.h

@@ -9,6 +9,8 @@
 #ifndef __asm_rtc_h
 #define __asm_rtc_h
 
+#include <dt-structs.h>
+
 /* Register numbers in the sandbox RTC */
 enum {
 	REG_SEC		= 5,
@@ -29,4 +31,26 @@ enum {
 	REG_COUNT	= 0x80,
 };
 
+/**
+ * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
+ *
+ * @base_time:		Base system time when RTC device was bound
+ * @offset:		RTC offset from current system time
+ * @use_system_time:	true to use system time, false to use @base_time
+ * @reg:		Register values
+ */
+struct sandbox_i2c_rtc_plat_data {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct dtd_sandbox_i2c_rtc_emul dtplat;
+#endif
+	long base_time;
+	long offset;
+	bool use_system_time;
+	u8 reg[REG_COUNT];
+};
+
+struct sandbox_i2c_rtc {
+	unsigned int offset_secs;
+};
+
 #endif

+ 2 - 0
arch/x86/cpu/apollolake/Kconfig

@@ -21,6 +21,8 @@ config INTEL_APOLLOLAKE
 	select INTEL_GMA_SWSMISCI
 	select ACPI_GNVS_EXTERNAL
 	select TPL_OF_PLATDATA_PARENT
+	select TPL_OF_PLATDATA_INST
+	select TPL_READ_ONLY
 	imply ENABLE_MRC_CACHE
 	imply AHCI_PCI
 	imply SCSI

+ 1 - 1
arch/x86/cpu/apollolake/pmc.c

@@ -9,8 +9,8 @@
 #define LOG_CATEGORY UCLASS_ACPI_PMC
 
 #include <common.h>
-#include <dt-structs.h>
 #include <dm.h>
+#include <dt-structs.h>
 #include <log.h>
 #include <spl.h>
 #include <acpi/acpi_s3.h>

+ 1 - 0
arch/x86/cpu/apollolake/punit.c

@@ -93,4 +93,5 @@ U_BOOT_DRIVER(intel_apl_punit) = {
 	.id		= UCLASS_SYSCON,
 	.of_match	= apl_syscon_ids,
 	.probe		= apl_punit_probe,
+	DM_HEADER(<asm/cpu.h>)    /* for X86_SYSCON_PUNIT */
 };

+ 3 - 2
arch/x86/cpu/intel_common/itss.c

@@ -153,8 +153,9 @@ static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
 
 static int itss_bind(struct udevice *dev)
 {
-	/* This is not set with of-platdata, so set it manually */
-	if (CONFIG_IS_ENABLED(OF_PLATDATA))
+	/* This is not set with basic of-platdata, so set it manually */
+	if (CONFIG_IS_ENABLED(OF_PLATDATA) &&
+	    !CONFIG_IS_ENABLED(OF_PLATDATA_INST))
 		dev->driver_data = X86_IRQT_ITSS;
 
 	return 0;

+ 8 - 0
arch/x86/cpu/u-boot-spl.lds

@@ -32,6 +32,14 @@ SECTIONS
 	. = ALIGN(4);
 	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
 
+	. = ALIGN(4);
+
+	.priv_data : {
+		__priv_data_start = .;
+		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.priv_data*)))
+		__priv_data_end = .;
+	}
+
 	. = ALIGN(4);
 	.data : { *(.data*) }
 

+ 5 - 5
arch/x86/dts/chromebook_coral.dts

@@ -100,7 +100,7 @@
 	clk: clock {
 		compatible = "intel,apl-clk";
 		#clock-cells = <1>;
-		u-boot,dm-pre-reloc;
+		u-boot,dm-pre-proper;
 	};
 
 	cpus {
@@ -141,7 +141,7 @@
 	};
 
 	acpi_gpe: general-purpose-events {
-		u-boot,dm-pre-reloc;
+		u-boot,dm-pre-proper;
 		reg = <IOMAP_ACPI_BASE IOMAP_ACPI_SIZE>;
 		compatible = "intel,acpi-gpe";
 		interrupt-controller;
@@ -423,7 +423,7 @@
 			compatible = "intel,apl-i2c", "snps,designware-i2c-pci";
 			reg = <0x0200b210 0 0 0 0>;
 			early-regs = <IOMAP_I2C2_BASE 0x1000>;
-			u-boot,dm-pre-reloc;
+			u-boot,dm-pre-proper;
 			#address-cells = <1>;
 			#size-cells = <0>;
 			clock-frequency = <400000>;
@@ -434,7 +434,7 @@
 			tpm: tpm@50 {
 				reg = <0x50>;
 				compatible = "google,cr50";
-				u-boot,dm-pre-reloc;
+				u-boot,dm-pre-proper;
 				u-boot,i2c-offset-len = <0>;
 				ready-gpios = <&gpio_n 28 GPIO_ACTIVE_LOW>;
 				interrupts-extended = <&acpi_gpe GPIO_28_IRQ
@@ -1233,5 +1233,5 @@
 &rtc {
 	#address-cells = <1>;
 	#size-cells = <0>;
-	u-boot,dm-pre-reloc;
+	u-boot,dm-pre-proper;
 };

+ 1 - 1
arch/x86/dts/reset.dtsi

@@ -1,6 +1,6 @@
 / {
 	reset: reset {
 		compatible = "x86,reset";
-		u-boot,dm-pre-reloc;
+		u-boot,dm-pre-proper;
 	};
 };

+ 2 - 15
arch/x86/dts/u-boot.dtsi

@@ -38,20 +38,11 @@
 	};
 #endif
 	spl {
-		type = "section";
+		type = "u-boot-spl";
 		offset = <CONFIG_X86_OFFSET_SPL>;
-		u-boot-spl {
-		};
-		u-boot-spl-dtb {
-		};
 	};
 	u-boot {
-		type = "section";
 		offset = <CONFIG_X86_OFFSET_U_BOOT>;
-		u-boot-nodtb {
-		};
-		u-boot-dtb {
-		};
 	};
 #elif defined(CONFIG_SPL)
 	u-boot-spl-with-ucode-ptr {
@@ -64,11 +55,7 @@
 		offset = <CONFIG_X86_OFFSET_U_BOOT>;
 	};
 #else
-# ifdef CONFIG_SPL
-	u-boot {
-		offset = <CONFIG_SYS_TEXT_BASE>;
-	};
-# elif defined(CONFIG_HAVE_MICROCODE)
+# ifdef CONFIG_HAVE_MICROCODE
 	/* If there is no SPL then we need to put microcode in U-Boot */
 	u-boot-with-ucode-ptr {
 		offset = <CONFIG_X86_OFFSET_U_BOOT>;

+ 1 - 0
arch/x86/lib/tpl.c

@@ -150,5 +150,6 @@ U_BOOT_DRIVER(pci_x86) = {
 	.name	= "pci_x86",
 	.id	= UCLASS_SIMPLE_BUS,
 	.of_match = of_match_ptr(tpl_fake_pci_ids),
+	DM_PHASE(tpl)
 };
 #endif

+ 7 - 0
board/sandbox/MAINTAINERS

@@ -20,6 +20,13 @@ F:	board/sandbox/
 F:	include/configs/sandbox_spl.h
 F:	configs/sandbox_spl_defconfig
 
+SANDBOX NOINST BOARD
+M:	Simon Glass <sjg@chromium.org>
+S:	Maintained
+F:	board/sandbox/
+F:	include/configs/sandbox_spl.h
+F:	configs/sandbox_noinst_defconfig
+
 SANDBOX FLAT TREE BOARD
 M:	Simon Glass <sjg@chromium.org>
 S:	Maintained

+ 1 - 0
board/sandbox/sandbox.c

@@ -48,6 +48,7 @@ unsigned long timer_read_counter(void)
 static enum env_location env_locations[] = {
 	ENVL_NOWHERE,
 	ENVL_EXT4,
+	ENVL_FAT,
 };
 
 enum env_location env_get_location(enum env_operation op, int prio)

+ 24 - 0
common/spl/Kconfig

@@ -276,6 +276,19 @@ config SPL_SEPARATE_BSS
 	  location is used. Normally we put the device tree at the end of BSS
 	  but with this option enabled, it goes at _image_binary_end.
 
+config SPL_READ_ONLY
+	bool
+	depends on SPL_OF_PLATDATA
+	# Bind cannot be supported because the udevice structs are in read-only
+	# memory so we cannot update the linked lists.
+	select SPL_OF_PLATDATA_NO_BIND
+	select SPL_OF_PLATDATA_RT
+	help
+	  Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
+	  section of memory. This means that of-platdata must make a copy (in
+	  writeable memory) of anything it wants to modify, such as
+	  device-private data.
+
 config SPL_BANNER_PRINT
 	bool "Enable output of the SPL banner 'U-Boot SPL ...'"
 	default y
@@ -1440,6 +1453,17 @@ config TPL_STACK
 	  The address of the initial stack-pointer for the TPL stage.
 	  Usually this will be the (aligned) top-of-stack.
 
+config TPL_READ_ONLY
+	bool
+	depends on TPL_OF_PLATDATA
+	select TPL_OF_PLATDATA_NO_BIND
+	select TPL_OF_PLATDATA_RT
+	help
+	  Some platforms (e.g. x86 Apollo Lake) load SPL into a read-only
+	  section of memory. This means that of-platdata must make a copy (in
+	  writeable memory) of anything it wants to modify, such as
+	  device-private data.
+
 config TPL_BOOTROM_SUPPORT
         bool "Support returning to the BOOTROM (from TPL)"
 	help

+ 1 - 0
configs/chromebook_coral_defconfig

@@ -73,6 +73,7 @@ CONFIG_MAC_PARTITION=y
 CONFIG_ISO_PARTITION=y
 CONFIG_EFI_PARTITION=y
 # CONFIG_SPL_EFI_PARTITION is not set
+CONFIG_OF_SPL_REMOVE_PROPS="clocks clock-names interrupt-parent interrupts linux-name acpi,name acpi,path u-boot,acpi-dsdt-order u-boot,acpi-ssdt-order"
 CONFIG_ENV_OVERWRITE=y
 CONFIG_REGMAP=y
 CONFIG_SYSCON=y

+ 231 - 0
configs/sandbox_noinst_defconfig

@@ -0,0 +1,231 @@
+CONFIG_SYS_TEXT_BASE=0x200000
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_SYS_MEMTEST_START=0x00100000
+CONFIG_SYS_MEMTEST_END=0x00101000
+CONFIG_ENV_SIZE=0x2000
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000
+CONFIG_SPL=y
+CONFIG_BOOTSTAGE_STASH_ADDR=0x0
+CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+CONFIG_SANDBOX_SPL=y
+CONFIG_DEBUG_UART=y
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_SPL_LOAD_FIT=y
+# CONFIG_USE_SPL_FIT_GENERATOR is not set
+CONFIG_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
+CONFIG_BOOTSTAGE_FDT=y
+CONFIG_BOOTSTAGE_STASH=y
+CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
+CONFIG_CONSOLE_RECORD=y
+CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_HANDOFF=y
+CONFIG_SPL_BOARD_INIT=y
+CONFIG_SPL_ENV_SUPPORT=y
+CONFIG_SPL_I2C_SUPPORT=y
+CONFIG_SPL_RTC_SUPPORT=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_HELLO=y
+# CONFIG_CMD_ELF is not set
+CONFIG_CMD_ASKENV=y
+CONFIG_CMD_GREPENV=y
+CONFIG_CMD_ERASEENV=y
+CONFIG_CMD_ENV_CALLBACK=y
+CONFIG_CMD_ENV_FLAGS=y
+CONFIG_CMD_NVEDIT_INFO=y
+CONFIG_CMD_NVEDIT_LOAD=y
+CONFIG_CMD_NVEDIT_SELECT=y
+CONFIG_LOOPW=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MX_CYCLIC=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_DEMO=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_GPT=y
+CONFIG_CMD_IDE=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_OSD=y
+CONFIG_CMD_PCI=y
+CONFIG_CMD_REMOTEPROC=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_USB=y
+CONFIG_BOOTP_DNS2=y
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTPSRV=y
+CONFIG_CMD_RARP=y
+CONFIG_CMD_CDP=y
+CONFIG_CMD_SNTP=y
+CONFIG_CMD_DNS=y
+CONFIG_CMD_LINK_LOCAL=y
+CONFIG_CMD_BMP=y
+CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_SOUND=y
+CONFIG_CMD_QFW=y
+CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
+CONFIG_CMD_CBFS=y
+CONFIG_CMD_CRAMFS=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_MAC_PARTITION=y
+CONFIG_AMIGA_PARTITION=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_HOSTFILE=y
+CONFIG_SPL_OF_PLATDATA=y
+CONFIG_ENV_IS_NOWHERE=y
+CONFIG_ENV_IS_IN_EXT4=y
+CONFIG_ENV_EXT4_INTERFACE="host"
+CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0"
+CONFIG_BOOTP_SEND_HOSTNAME=y
+CONFIG_NETCONSOLE=y
+CONFIG_IP_DEFRAG=y
+CONFIG_SPL_DM=y
+CONFIG_DM_DMA=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_DEVRES=y
+CONFIG_DEBUG_DEVRES=y
+# CONFIG_SPL_SIMPLE_BUS is not set
+CONFIG_ADC=y
+CONFIG_ADC_SANDBOX=y
+CONFIG_AXI=y
+CONFIG_AXI_SANDBOX=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_DEMO=y
+CONFIG_DM_DEMO_SIMPLE=y
+CONFIG_DM_DEMO_SHAPE=y
+CONFIG_SPL_FIRMWARE=y
+CONFIG_GPIO_HOG=y
+CONFIG_PM8916_GPIO=y
+CONFIG_SANDBOX_GPIO=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_I2C_CROS_EC_LDO=y
+CONFIG_DM_I2C_GPIO=y
+CONFIG_SYS_I2C_SANDBOX=y
+CONFIG_I2C_MUX=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_CROS_EC_KEYB=y
+CONFIG_I8042_KEYB=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_DM_MAILBOX=y
+CONFIG_SANDBOX_MBOX=y
+CONFIG_MISC=y
+CONFIG_CROS_EC=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_LPC=y
+CONFIG_CROS_EC_SANDBOX=y
+CONFIG_CROS_EC_SPI=y
+CONFIG_IRQ=y
+CONFIG_P2SB=y
+CONFIG_PWRSEQ=y
+CONFIG_SPL_PWRSEQ=y
+CONFIG_MMC_SANDBOX=y
+CONFIG_SPI_FLASH_SANDBOX=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
+CONFIG_NVME=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_PCI_SANDBOX=y
+CONFIG_PHY=y
+CONFIG_PHY_SANDBOX=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_SANDBOX=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_ACT8846=y
+CONFIG_DM_PMIC_PFUZE100=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_DM_PMIC_MC34708=y
+CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_RK8XX=y
+CONFIG_PMIC_S2MPS11=y
+CONFIG_DM_PMIC_SANDBOX=y
+CONFIG_PMIC_S5M8767=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_DM_REGULATOR=y
+CONFIG_REGULATOR_ACT8846=y
+CONFIG_DM_REGULATOR_PFUZE100=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_REGULATOR_RK8XX=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_DM_REGULATOR_SANDBOX=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_DM_PWM=y
+CONFIG_PWM_SANDBOX=y
+CONFIG_RAM=y
+CONFIG_REMOTEPROC_SANDBOX=y
+CONFIG_DM_RESET=y
+CONFIG_SANDBOX_RESET=y
+CONFIG_DM_RTC=y
+CONFIG_SPL_DM_RTC=y
+CONFIG_SANDBOX_SERIAL=y
+CONFIG_SOUND=y
+CONFIG_SOUND_SANDBOX=y
+CONFIG_SOC_DEVICE=y
+CONFIG_SANDBOX_SPI=y
+CONFIG_SPMI=y
+CONFIG_SPMI_SANDBOX=y
+CONFIG_SYSINFO=y
+CONFIG_SYSINFO_SANDBOX=y
+CONFIG_SYSRESET=y
+CONFIG_SPL_SYSRESET=y
+CONFIG_TIMER=y
+CONFIG_TIMER_EARLY=y
+CONFIG_SANDBOX_TIMER=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EMUL=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_DM_VIDEO=y
+CONFIG_CONSOLE_ROTATION=y
+CONFIG_CONSOLE_TRUETYPE=y
+CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
+CONFIG_VIDEO_SANDBOX_SDL=y
+CONFIG_OSD=y
+CONFIG_SANDBOX_OSD=y
+CONFIG_SPLASH_SCREEN_ALIGN=y
+CONFIG_VIDEO_BMP_RLE8=y
+CONFIG_FS_CBFS=y
+CONFIG_FS_CRAMFS=y
+# CONFIG_SPL_USE_TINY_PRINTF is not set
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_RSA_VERIFY_WITH_PKEY=y
+CONFIG_TPM=y
+CONFIG_LZ4=y
+CONFIG_ERRNO_STR=y
+CONFIG_UNIT_TEST=y
+CONFIG_SPL_UNIT_TEST=y
+CONFIG_UT_TIME=y
+CONFIG_UT_DM=y

+ 3 - 0
configs/sandbox_spl_defconfig

@@ -7,6 +7,7 @@ CONFIG_SYS_MEMTEST_END=0x00101000
 CONFIG_ENV_SIZE=0x2000
 CONFIG_SPL_SERIAL_SUPPORT=y
 CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_SPL_SYS_MALLOC_F_LEN=0x8000
 CONFIG_SPL=y
 CONFIG_BOOTSTAGE_STASH_ADDR=0x0
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
@@ -87,6 +88,7 @@ CONFIG_OF_CONTROL=y
 CONFIG_SPL_OF_CONTROL=y
 CONFIG_OF_HOSTFILE=y
 CONFIG_SPL_OF_PLATDATA=y
+CONFIG_SPL_OF_PLATDATA_INST=y
 CONFIG_ENV_IS_NOWHERE=y
 CONFIG_ENV_IS_IN_EXT4=y
 CONFIG_ENV_EXT4_INTERFACE="host"
@@ -102,6 +104,7 @@ CONFIG_SYSCON=y
 CONFIG_SPL_SYSCON=y
 CONFIG_DEVRES=y
 CONFIG_DEBUG_DEVRES=y
+# CONFIG_SPL_SIMPLE_BUS is not set
 CONFIG_ADC=y
 CONFIG_ADC_SANDBOX=y
 CONFIG_AXI=y

+ 2 - 2
doc/arch/x86.rst

@@ -709,8 +709,8 @@ to load a 'u-boot-payload.efi', see below test logs on QEMU.
   No controllers found
   Hit any key to stop autoboot:  0
 
-See :doc:`../uefi/u-boot_on_efi` and :doc:`../uefi/uefi` for details of
-EFI support in U-Boot.
+See :doc:`../develop/uefi/u-boot_on_efi` and :doc:`../develop/uefi/uefi` for
+details of EFI support in U-Boot.
 
 Chain-loading
 -------------

+ 0 - 0
doc/driver-model/bind.rst → doc/develop/driver-model/bind.rst


+ 0 - 0
doc/driver-model/debugging.rst → doc/develop/driver-model/debugging.rst


+ 0 - 0
doc/driver-model/design.rst → doc/develop/driver-model/design.rst


+ 0 - 0
doc/driver-model/ethernet.rst → doc/develop/driver-model/ethernet.rst


+ 0 - 0
doc/driver-model/fdt-fixup.rst → doc/develop/driver-model/fdt-fixup.rst


+ 0 - 0
doc/driver-model/fs_firmware_loader.rst → doc/develop/driver-model/fs_firmware_loader.rst


+ 0 - 0
doc/driver-model/i2c-howto.rst → doc/develop/driver-model/i2c-howto.rst


+ 4 - 0
doc/driver-model/index.rst → doc/develop/driver-model/index.rst

@@ -3,6 +3,10 @@
 Driver Model
 ============
 
+The following holds information on the U-Boot device driver framework:
+driver-model, including the design details of itself and several driver
+subsystems
+
 .. toctree::
    :maxdepth: 2
 

+ 0 - 0
doc/driver-model/livetree.rst → doc/develop/driver-model/livetree.rst


+ 0 - 0
doc/driver-model/migration.rst → doc/develop/driver-model/migration.rst


+ 913 - 0
doc/develop/driver-model/of-plat.rst

@@ -0,0 +1,913 @@
+.. 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 devicetree 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 devicetree 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 devicetree 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 devicetree completely, effectively creating a parallel
+configuration mechanism. But it is an available option for SPL.
+
+As an alternative, the 'of-platdata' feature is provided. This converts the
+devicetree 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.
+
+
+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 tool called 'dtoc' converts a devicetree 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 devicetree 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, the `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 is used by dtoc tool. It must be located in the
+same file as its associated driver, ideally just after it.
+
+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, dtoc generates a `#define` 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 devicetree, since the of-platdata
+structure is not available when devicetree is used. It would make no sense
+to use this structure if devicetree were available, since the structure has
+all the limitations metioned in caveats below.
+
+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 devicetree 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 devicetree 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 devicetree (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 devicetree 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 devicetree 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 devicetree. Drivers cannot use both at
+the same time, but they must support devicetree. Supporting of-platdata is
+optional.
+
+The devicetree becomes inaccessible when CONFIG_SPL_OF_PLATDATA is enabled,
+since the devicetree 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.
+
+
+Build-time instantiation
+------------------------
+
+Even with of-platdata there is a fair amount of code required in driver model.
+It is possible to have U-Boot handle the instantiation of devices at build-time,
+so avoiding the need for the `device_bind()` code and some parts of
+`device_probe()`.
+
+The feature is enabled by CONFIG_OF_PLATDATA_INST.
+
+Here is an example device, as generated by dtoc::
+
+   /*
+    * Node /serial index 6
+    * driver sandbox_serial parent root_driver
+   */
+
+   #include <asm/serial.h>
+   struct sandbox_serial_plat __attribute__ ((section (".priv_data")))
+      _sandbox_serial_plat_serial = {
+      .dtplat = {
+         .sandbox_text_colour   = "cyan",
+      },
+   };
+   #include <asm/serial.h>
+   u8 _sandbox_serial_priv_serial[sizeof(struct sandbox_serial_priv)]
+      __attribute__ ((section (".priv_data")));
+   #include <serial.h>
+   u8 _sandbox_serial_uc_priv_serial[sizeof(struct serial_dev_priv)]
+      __attribute__ ((section (".priv_data")));
+
+   DM_DEVICE_INST(serial) = {
+      .driver     = DM_DRIVER_REF(sandbox_serial),
+      .name       = "sandbox_serial",
+      .plat_      = &_sandbox_serial_plat_serial,
+      .priv_      = _sandbox_serial_priv_serial,
+      .uclass     = DM_UCLASS_REF(serial),
+      .uclass_priv_ = _sandbox_serial_uc_priv_serial,
+      .uclass_node   = {
+         .prev = &DM_UCLASS_REF(serial)->dev_head,
+         .next = &DM_UCLASS_REF(serial)->dev_head,
+      },
+      .child_head   = {
+         .prev = &DM_DEVICE_REF(serial)->child_head,
+         .next = &DM_DEVICE_REF(serial)->child_head,
+      },
+      .sibling_node   = {
+         .prev = &DM_DEVICE_REF(i2c_at_0)->sibling_node,
+         .next = &DM_DEVICE_REF(spl_test)->sibling_node,
+      },
+      .seq_ = 0,
+   };
+
+Here is part of the driver, for reference::
+
+   static const struct udevice_id sandbox_serial_ids[] = {
+      { .compatible = "sandbox,serial" },
+      { }
+   };
+
+   U_BOOT_DRIVER(sandbox_serial) = {
+      .name   = "sandbox_serial",
+      .id   = UCLASS_SERIAL,
+      .of_match    = sandbox_serial_ids,
+      .of_to_plat  = sandbox_serial_of_to_plat,
+      .plat_auto   = sizeof(struct sandbox_serial_plat),
+      .priv_auto   = sizeof(struct sandbox_serial_priv),
+      .probe = sandbox_serial_probe,
+      .remove = sandbox_serial_remove,
+      .ops   = &sandbox_serial_ops,
+      .flags = DM_FLAG_PRE_RELOC,
+   };
+
+
+The `DM_DEVICE_INST()` macro declares a struct udevice so you can see that the
+members are from that struct. The private data is declared immediately above,
+as `_sandbox_serial_priv_serial`, so there is no need for run-time memory
+allocation. The #include lines are generated as well, since dtoc searches the
+U-Boot source code for the definition of `struct sandbox_serial_priv` and adds
+the relevant header so that the code will compile without errors.
+
+The `plat_` member is set to the dtv data which is declared immediately above
+the device. This is similar to how it would look without of-platdata-inst, but
+node that the `dtplat` member inside is part of the wider
+`_sandbox_serial_plat_serial` struct. This is because the driver declares its
+own platform data, and the part generated by dtoc can only be a portion of it.
+The `dtplat` part is always first in the struct. If the device has no
+`.plat_auto` field, then a simple dtv struct can be used as with this example::
+
+   static struct dtd_sandbox_clk dtv_clk_sbox = {
+      .assigned_clock_rates   = 0x141,
+      .assigned_clocks   = {0x7, 0x3},
+   };
+
+   #include <asm/clk.h>
+   u8 _sandbox_clk_priv_clk_sbox[sizeof(struct sandbox_clk_priv)]
+      __attribute__ ((section (".priv_data")));
+
+   DM_DEVICE_INST(clk_sbox) = {
+      .driver    = DM_DRIVER_REF(sandbox_clk),
+      .name      = "sandbox_clk",
+      .plat_     = &dtv_clk_sbox,
+
+Here is part of the driver, for reference::
+
+   static const struct udevice_id sandbox_clk_ids[] = {
+      { .compatible = "sandbox,clk" },
+      { }
+   };
+
+   U_BOOT_DRIVER(sandbox_clk) = {
+      .name       = "sandbox_clk",
+      .id         = UCLASS_CLK,
+      .of_match   = sandbox_clk_ids,
+      .ops        = &sandbox_clk_ops,
+      .probe      = sandbox_clk_probe,
+      .priv_auto  = sizeof(struct sandbox_clk_priv),
+   };
+
+
+You can see that `dtv_clk_sbox` just has the devicetree contents and there is
+no need for the `dtplat` separation, since the driver has no platform data of
+its own, besides that provided by the devicetree (i.e. no `.plat_auto` field).
+
+The doubly linked lists are handled by explicitly declaring the value of each
+node, as you can see with the `.prev` and `.next` values in the example above.
+Since dtoc knows the order of devices it can link them into the appropriate
+lists correctly.
+
+One of the features of driver model is the ability for a uclass to have a
+small amount of private data for each device in that uclass. This is used to
+provide a generic data structure that the uclass can use for all devices, thus
+allowing generic features to be implemented in common code. An example is I2C,
+which stores the bus speed there.
+
+Similarly, parent devices can have data associated with each of their children.
+This is used to provide information common to all children of a particular bus.
+For an I2C bus, this is used to store the I2C address of each child on the bus.
+
+This is all handled automatically by dtoc::
+
+   #include <asm/i2c.h>
+   u8 _sandbox_i2c_priv_i2c_at_0[sizeof(struct sandbox_i2c_priv)]
+      __attribute__ ((section (".priv_data")));
+   #include <i2c.h>
+   u8 _sandbox_i2c_uc_priv_i2c_at_0[sizeof(struct dm_i2c_bus)]
+      __attribute__ ((section (".priv_data")));
+
+   DM_DEVICE_INST(i2c_at_0) = {
+      .driver      = DM_DRIVER_REF(sandbox_i2c),
+      .name      = "sandbox_i2c",
+      .plat_   = &dtv_i2c_at_0,
+      .priv_      = _sandbox_i2c_priv_i2c_at_0,
+      .uclass   = DM_UCLASS_REF(i2c),
+      .uclass_priv_ = _sandbox_i2c_uc_priv_i2c_at_0,
+     ...
+
+Part of driver, for reference::
+
+   static const struct udevice_id sandbox_i2c_ids[] = {
+      { .compatible = "sandbox,i2c" },
+      { }
+   };
+
+   U_BOOT_DRIVER(sandbox_i2c) = {
+      .name   = "sandbox_i2c",
+      .id   = UCLASS_I2C,
+      .of_match = sandbox_i2c_ids,
+      .ops   = &sandbox_i2c_ops,
+      .priv_auto   = sizeof(struct sandbox_i2c_priv),
+   };
+
+Part of I2C uclass, for reference::
+
+   UCLASS_DRIVER(i2c) = {
+      .id         = UCLASS_I2C,
+      .name       = "i2c",
+      .flags      = DM_UC_FLAG_SEQ_ALIAS,
+      .post_bind  = i2c_post_bind,
+      .pre_probe  = i2c_pre_probe,
+      .post_probe = i2c_post_probe,
+      .per_device_auto   = sizeof(struct dm_i2c_bus),
+      .per_child_plat_auto   = sizeof(struct dm_i2c_chip),
+      .child_post_bind = i2c_child_post_bind,
+   };
+
+Here, `_sandbox_i2c_uc_priv_i2c_at_0` is required by the uclass but is declared
+in the device, as required by driver model. The required header file is included
+so that the code will compile without errors. A similar mechanism is used for
+child devices, but is not shown by this example.
+
+It would not be that useful to avoid binding devices but still need to allocate
+uclasses at runtime. So dtoc generates uclass instances as well::
+
+   struct list_head uclass_head = {
+      .prev = &DM_UCLASS_REF(serial)->sibling_node,
+      .next = &DM_UCLASS_REF(clk)->sibling_node,
+   };
+
+   DM_UCLASS_INST(clk) = {
+      .uc_drv      = DM_UCLASS_DRIVER_REF(clk),
+      .sibling_node   = {
+         .prev = &uclass_head,
+         .next = &DM_UCLASS_REF(i2c)->sibling_node,
+      },
+      .dev_head   = {
+         .prev = &DM_DEVICE_REF(clk_sbox)->uclass_node,
+         .next = &DM_DEVICE_REF(clk_fixed)->uclass_node,
+      },
+   };
+
+At the top is the list head. Driver model uses this on start-up, instead of
+creating its own.
+
+Below that are a set of `DM_UCLASS_INST()` macros, each declaring a
+`struct uclass`. The doubly linked lists work as for devices.
+
+All private data is placed into a `.priv_data` section so that it is contiguous
+in the resulting output binary.
+
+
+Indexes
+-------
+
+U-Boot stores drivers, devices and many other things in linker_list structures.
+These are sorted by name, so dtoc knows the order that they will appear when
+the linker runs. Each driver_info / udevice is referenced by its index in the
+linker_list array, called 'idx' in the code.
+
+When CONFIG_OF_PLATDATA_INST is enabled, idx is the udevice index, otherwise it
+is the driver_info index. In either case, indexes are used to reference devices
+using device_get_by_ofplat_idx(). This allows phandles to work as expected.
+
+
+Phases
+------
+
+U-Boot operates in several phases, typically TPL, SPL and U-Boot proper.
+The latter does not use dtoc.
+
+In some rare cases different drivers are used for two phases. For example,
+in TPL it may not be necessary to use the full PCI subsystem, so a simple
+driver can be used instead.
+
+This works in the build system simply by compiling in one driver or the
+other (e.g. PCI driver + uclass for SPL; simple_bus for TPL). But dtoc has
+no way of knowing which code is compiled in for which phase, since it does
+not inspect Makefiles or dependency graphs.
+
+So to make this work for dtoc, we need to be able to explicitly mark
+drivers with their phase. This is done by adding a macro to the driver::
+
+   /* code in tpl.c only compiled into TPL */
+   U_BOOT_DRIVER(pci_x86) = {
+      .name   = "pci_x86",
+      .id   = UCLASS_SIMPLE_BUS,
+      .of_match = of_match_ptr(tpl_fake_pci_ids),
+      DM_PHASE(tpl)
+   };
+
+
+   /* code in pci_x86.c compiled into SPL and U-Boot proper */
+   U_BOOT_DRIVER(pci_x86) = {
+      .name   = "pci_x86",
+      .id   = UCLASS_PCI,
+      .of_match = pci_x86_ids,
+      .ops   = &pci_x86_ops,
+   };
+
+
+Notice that the second driver has the same name but no DM_PHASE(), so it will be
+used for SPL and U-Boot.
+
+Note also that this only affects the code generated by dtoc. You still need to
+make sure that only the required driver is build into each phase.
+
+
+Header files
+------------
+
+With OF_PLATDATA_INST, dtoc must include the correct header file in the
+generated code for any structs that are used, so that the code will compile.
+For example, if `struct ns16550_plat` is used, the code must include the
+`ns16550.h` header file.
+
+Typically dtoc can detect the header file needed for a driver by looking
+for the structs that it uses. For example, if a driver as a `.priv_auto`
+that uses `struct ns16550_plat`, then dtoc can search header files for the
+definition of that struct and use the file.
+
+In some cases, enums are used in drivers, typically with the `.data` field
+of `struct udevice_id`. Since dtoc does not support searching for these,
+you must use the `DM_HDR()` macro to tell dtoc which header to use. This works
+as a macro included in the driver definition::
+
+   static const struct udevice_id apl_syscon_ids[] = {
+      { .compatible = "intel,apl-punit", .data = X86_SYSCON_PUNIT },
+      { }
+   };
+
+   U_BOOT_DRIVER(intel_apl_punit) = {
+      .name       = "intel_apl_punit",
+      .id         = UCLASS_SYSCON,
+      .of_match   = apl_syscon_ids,
+      .probe      = apl_punit_probe,
+      DM_HEADER(<asm/cpu.h>)    /* for X86_SYSCON_PUNIT */
+   };
+
+
+
+Caveats
+-------
+
+There are various complications with this feature which mean it should only
+be used when strictly necessary, i.e. in SPL with limited memory. Notable
+caveats 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 devicetree file.
+
+   - Naming of nodes and properties is automatic. This means that they follow
+     the naming in the devicetree, 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 devicetree changes. To avoid having
+     a second struct with similar members and names you need to explicitly
+     declare it as an alias with `DM_DRIVER_ALIAS()`.
+
+   - 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 devicetree it must use `#ifdef` to separate
+     out this code, since the structures are only available in SPL. This could
+     be fixed fairly easily by making the structs available outside SPL, so
+     that `IS_ENABLED()` could be used.
+
+   - With CONFIG_OF_PLATDATA_INST all binding happens at build-time, meaning
+     that (by default) it is not possible to call `device_bind()` from C code.
+     This means that all devices must have an associated devicetree node and
+     compatible string. For example if a GPIO device currently creates child
+     devices in its `bind()` method, it will not work with
+     CONFIG_OF_PLATDATA_INST. Arguably this is bad practice anyway and the
+     devicetree binding should be updated to declare compatible strings for
+     the child devices. It is possible to disable OF_PLATDATA_NO_BIND but this
+     is not recommended since it increases code size.
+
+
+Internals
+---------
+
+Generated files
+```````````````
+
+When enabled, dtoc generates the following five files:
+
+include/generated/dt-decl.h (OF_PLATDATA_INST only)
+   Contains declarations for all drivers, devices and uclasses. This allows
+   any `struct udevice`, `struct driver` or `struct uclass` to be located by its
+   name
+
+include/generated/dt-structs-gen.h
+   Contains the struct definitions for the devicetree nodes that are used. This
+   is the same as without OF_PLATDATA_INST
+
+spl/dts/dt-plat.c (only with !OF_PLATDATA_INST)
+   Contains the `U_BOOT_DRVINFO()` declarations that U-Boot uses to bind devices
+   at start-up. See above for an example
+
+spl/dts/dt-device.c (only with OF_PLATDATA_INST)
+   Contains `DM_DEVICE_INST()` declarations for each device that can be used at
+   run-time. These are declared in the file along with any private/platform data
+   that they use. Every device has an idx, as above. Since each device must be
+   part of a double-linked list, the nodes are declared in the code as well.
+
+spl/dts/dt-uclass.c (only with OF_PLATDATA_INST)
+   Contains `DM_UCLASS_INST()` declarations for each uclass that can be used at
+   run-time. These are declared in the file along with any private data
+   associated with the uclass itself (the `.priv_auto` member). Since each
+   uclass must be part of a double-linked list, the nodes are declared in the
+   code as well.
+
+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.
+
+
+CONFIG options
+``````````````
+
+Several CONFIG options are used to control the behaviour of of-platdata, all
+available for both SPL and TPL:
+
+OF_PLATDATA
+   This is the main option which enables the of-platdata feature
+
+OF_PLATDATA_PARENT
+   This allows `device_get_parent()` to work. Without this, all devices exist as
+   direct children of the root node. This option is highly desirable (if not
+   always absolutely essential) for buses such as I2C.
+
+OF_PLATDATA_INST
+   This controls the instantiation of devices at build time. With it disabled,
+   only `U_BOOT_DRVINFO()` records are created, with U-Boot handling the binding
+   in `device_bind()` on start-up. With it enabled, only `DM_DEVICE_INST()` and
+   `DM_UCLASS_INST()` records are created, and `device_bind()` is not needed at
+   runtime.
+
+OF_PLATDATA_NO_BIND
+   This controls whether `device_bind()` is supported. It is enabled by default
+   with OF_PLATDATA_INST since code-size reduction is really the main point of
+   the feature. It can be disabled if needed but is not likely to be supported
+   in the long term.
+
+OF_PLATDATA_DRIVER_RT
+   This controls whether the `struct driver_rt` records are used by U-Boot.
+   Normally when a device is bound, U-Boot stores the device pointer in one of
+   these records. There is one for every `struct driver_info` in the system,
+   i.e. one for every device that is bound from those records. It provides a
+   way to locate a device in the code and is used by
+   `device_get_by_ofplat_idx()`. This option is always enabled with of-platdata,
+   provided OF_PLATDATA_INST is not. In that case the records are useless since
+   we don't have any `struct driver_info` records.
+
+OF_PLATDATA_RT
+   This controls whether the `struct udevice_rt` records are used by U-Boot.
+   It moves the updatable fields from `struct udevice` (currently only `flags`)
+   into a separate structure, allowing the records to be kept in read-only
+   memory. It is generally enabled if OF_PLATDATA_INST is enabled. This option
+   also controls whether the private data is used in situ, or first copied into
+   an allocated region. Again this is to allow the private data declared by
+   dtoc-generated code to be in read-only memory. Note that access to private
+   data must be done via accessor functions, such as `dev_get_priv()`, so that
+   the relocation is handled.
+
+READ_ONLY
+   This indicates that the data generated by dtoc should not be modified. Only
+   a few fields actually do get changed in U-Boot, such as device flags. This
+   option causes those to move into an allocated space (see OF_PLATDATA_RT).
+   Also, since updating doubly linked lists is generally impossible when some of
+   the nodes cannot be updated, OF_PLATDATA_NO_BIND is enabled.
+
+Data structures
+```````````````
+
+A few extra data structures are used with of-platdata:
+
+`struct udevice_rt`
+   Run-time information for devices. When OF_PLATDATA_RT is enabled, this holds
+   the flags for each device, so that `struct udevice` can remain unchanged by
+   U-Boot, and potentially reside in read-only memory. Access to flags is then
+   via functions like `dev_get_flags()` and `dev_or_flags()`. This data
+   structure is allocated on start-up, where the private data is also copied.
+   All flags values start at 0 and any changes are handled by `dev_or_flags()`
+   and `dev_bic_flags()`. It would be more correct for the flags to be set to
+   `DM_FLAG_BOUND`, or perhaps `DM_FLAG_BOUND | DM_FLAG_ALLOC_PDATA`, but since
+   there is no code to bind/unbind devices and no code to allocate/free
+   private data / platform data, it doesn't matter.
+
+`struct driver_rt`
+   Run-time information for `struct driver_info` records. When
+   OF_PLATDATA_DRIVER_RT is enabled, this holds a pointer to the device
+   created by each record. This is needed so that is it possible to locate a
+   device from C code. Specifically, the code can use `DM_DRVINFO_GET(name)` to
+   get a reference to a particular `struct driver_info`, with `name` being the
+   name of the devicetree node. This is very convenient. It is also fast, since
+   no    searching or string comparison is needed. This data structure is
+   allocated    on start-up, filled out by `device_bind()` and used by
+   `device_get_by_ofplat_idx()`.
+
+Other changes
+`````````````
+
+Some other changes are made with of-platdata:
+
+Accessor functions
+   Accessing private / platform data via functions such as `dev_get_priv()` has
+   always been encouraged. With OF_PLATDATA_RT this is essential, since the
+   `priv_` and `plat_`  (etc.) values point to the data generated by dtoc, not
+   the read-write copy that is sometimes made on start-up. Changing the
+   private / platform data  pointers has always been discouraged (the API is
+   marked internal) but with OF_PLATDATA_RT this is not currently supported in
+   general, since it assumes that all such pointers point to the relocated data.
+   Note also that the renaming of struct members to have a trailing underscore
+   was partly done to make people aware that they should not be accessed
+   directly.
+
+`gd->uclass_root_s`
+   Normally U-Boot sets up the head of the uclass list here and makes
+   `gd->uclass_root` point to it. With OF_PLATDATA_INST, dtoc generates a
+   declaration of `uclass_head` in `dt-uclass.c` since it needs to link the
+   head node into the list. In that case, `gd->uclass_root_s` is not used and
+   U-Boot just makes `gd->uclass_root` point to `uclass_head`.
+
+`gd->dm_driver_rt`
+   This holds a pointer to a list of `struct driver_rt` records, one for each
+   `struct driver_info`. The list is in alphabetical order by the name used
+   in `U_BOOT_DRVINFO(name)` and indexed by idx, with the first record having
+   an index of 0. It is only used if OF_PLATDATA_INST is not enabled. This is
+   accessed via macros so that it can be used inside IS_ENABLED(), rather than
+   requiring #ifdefs in the C code when it is not present.
+
+`gd->dm_udevice_rt`
+   This holds a pointer to a list of `struct udevice_rt` records, one for each
+   `struct udevice`. The list is in alphabetical order by the name used
+   in `DM_DEVICE_INST(name)` (a C version of the devicetree node) and indexed by
+   idx, with the first record having an index of 0. It is only used if
+   OF_PLATDATA_INST is enabled. This is accessed via macros so that it can be
+   used inside `IS_ENABLED()`, rather than requiring #ifdefs in the C code when
+   it is not present.
+
+`gd->dm_priv_base`
+   When OF_PLATDATA_RT is enabled, the private/platform data for each device is
+   copied into an allocated region by U-Boot on start-up. This points to that
+   region. All calls to accessor functions (e.g. `dev_get_priv()`) then
+   translate from the pointer provided by the caller (assumed to lie between
+   `__priv_data_start` and `__priv_data_end`) to the new allocated region. This
+   member is accessed via macros so that it can be used inside IS_ENABLED(),
+   rather than required #ifdefs in the C code when it is not present.
+
+`struct udevice->flags_`
+   When OF_PLATDATA_RT is enabled, device flags are no-longer part of
+   `struct udevice`, but are instead kept in `struct udevice_rt`, as described
+   above. Flags are accessed via functions, such as `dev_get_flags()` and
+   `dev_or_flags()`.
+
+`struct udevice->node_`
+   When OF_PLATDATA is enabled, there is no devicetree at runtime, so no need
+   for this field. It is removed, just to save space.
+
+`DM_PHASE`
+   This macro is used to indicate which phase of U-Boot a driver is intended
+   for. See above for details.
+
+`DM_HDR`
+   This macro is used to indicate which header file dtoc should use to allow
+   a driver declaration to compile correctly. See above for details.
+
+`device_get_by_ofplat_idx()`
+   There used to be a function called `device_get_by_driver_info()` which
+   looked up a `struct driver_info` pointer and returned the `struct udevice`
+   that was created from it. It was only available for use with of-platdata.
+   This has been removed in favour of `device_get_by_ofplat_idx()` which uses
+   `idx`, the index of the `struct driver_info` or `struct udevice` in the
+   linker_list. Similarly, the `struct phandle_0_arg` (etc.) structs have been
+   updated to use this index instead of a pointer to `struct driver_info`.
+
+`DM_DRVINFO_GET`
+   This has been removed since we now use indexes to obtain a driver from
+   `struct phandle_0_arg` and the like.
+
+Two-pass binding
+   The original of-platdata tried to order `U_BOOT_DRVINFO()` in the generated
+   files so as to have parents declared ahead of children. This was convenient
+   as it avoided any special code in U-Boot. With OF_PLATDATA_INST this does
+   not work as the idx value relies on using alphabetical order for everything,
+   so that dtoc and U-Boot's linker_lists agree on the idx value. Devices are
+   then bound in order of idx, having no regard to parent/child relationships.
+   For this reason, device binding now hapens in multiple passes, with parents
+   being bound before their children. This is important so that children can
+   find their parents in the bind() method if needed.
+
+Root device
+   The root device is generally bound by U-Boot but with OF_PLATDATA_INST it
+   cannot be, since binding needs to be done at build time. So in this case
+   dtoc sets up a root device using `DM_DEVICE_INST()` in `dt-device.c` and
+   U-Boot makes use of that. When OF_PLATDATA_INST is not enabled, U-Boot
+   generally ignores the root node and does not create a `U_BOOT_DRVINFO()`
+   record for it. This means that the idx numbers used by `struct driver_info`
+   (when OF_PLATDATA_INST is disabled) and the idx numbers used by
+   `struct udevice` (when OF_PLATDATA_INST is enabled) differ, since one has a
+   root node and the other does not. This does not actually matter, since only
+   one of them is actually used for any particular build, but it is worth
+   keeping in mind if comparing index values and switching OF_PLATDATA_INST on
+   and off.
+
+`__priv_data_start` and `__priv_data_end`
+   The private/platform data declared by dtoc is all collected together in
+   a linker section and these symbols mark the start and end of it. This allows
+   U-Boot to relocate the area to a new location if needed (with
+   OF_PLATDATA_RT)
+
+`dm_priv_to_rw()`
+   This function converts a private- or platform-data pointer value generated by
+   dtoc into one that can be used by U-Boot. It is a NOP unless OF_PLATDATA_RT
+   is enabled, in which case it translates the address to the relocated
+   region. See above for more information.
+
+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 devicetree
+  contents
+- Allow IS_ENABLED() to be used in the C code instead of #if
+
+
+.. Simon Glass <sjg@chromium.org>
+.. Google, Inc
+.. 6/6/16
+.. Updated Independence Day 2016
+.. Updated 1st October 2020
+.. Updated 5th February 2021

+ 1 - 0
doc/driver-model/pci-info.rst → doc/develop/driver-model/pci-info.rst

@@ -125,6 +125,7 @@ emulator driver. For example::
 		compatible = "sandbox,pci-emul-parent";
 		emul_1f: emul@1f,0 {
 			compatible = "sandbox,swap-case";
+			#emul-cells = <0>;
 		};
 	};
 

+ 0 - 0
doc/driver-model/pmic-framework.rst → doc/develop/driver-model/pmic-framework.rst


+ 0 - 0
doc/driver-model/remoteproc-framework.rst → doc/develop/driver-model/remoteproc-framework.rst


+ 0 - 0
doc/driver-model/serial-howto.rst → doc/develop/driver-model/serial-howto.rst


+ 0 - 0
doc/driver-model/soc-framework.rst → doc/develop/driver-model/soc-framework.rst


+ 0 - 0
doc/driver-model/spi-howto.rst → doc/develop/driver-model/spi-howto.rst


+ 0 - 0
doc/driver-model/usb-info.rst → doc/develop/driver-model/usb-info.rst


+ 10 - 0
doc/develop/index.rst

@@ -10,9 +10,11 @@ Implementation
    :maxdepth: 1
 
    commands
+   driver-model/index
    global_data
    logging
    menus
+   uefi/index
    version
 
 Debugging
@@ -24,6 +26,14 @@ Debugging
    crash_dumps
    trace
 
+Packaging
+---------
+
+.. toctree::
+   :maxdepth: 1
+
+   package/index
+
 Testing
 -------
 

+ 1 - 0
doc/develop/package/binman.rst

@@ -0,0 +1 @@
+../../../tools/binman/binman.rst

+ 1 - 0
doc/develop/package/entries.rst

@@ -0,0 +1 @@
+../../../tools/binman/entries.rst

+ 19 - 0
doc/develop/package/index.rst

@@ -0,0 +1,19 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Package U-Boot
+==============
+
+U-Boot uses Flat Image Tree (FIT) as a standard file format for packaging
+images that it it reads and boots. Documentation about FIT is available at
+doc/uImage.FIT
+
+U-Boot also provides binman for cases not covered by FIT. Examples include
+initial execution (since FIT itself does not have an executable header) and
+dealing with device boundaries, such as the read-only/read-write separation in
+SPI flash.
+
+
+.. toctree::
+   :maxdepth: 2
+
+   binman

+ 4 - 0
doc/uefi/index.rst → doc/develop/uefi/index.rst

@@ -3,6 +3,10 @@
 Unified Extensible Firmware (UEFI)
 ==================================
 
+U-Boot provides an implementation of the UEFI API allowing to run UEFI
+compliant software like Linux, GRUB, and iPXE. Furthermore U-Boot itself
+can be run an UEFI payload.
+
 .. toctree::
    :maxdepth: 2
 

+ 0 - 0
doc/uefi/iscsi.rst → doc/develop/uefi/iscsi.rst


+ 0 - 0
doc/uefi/u-boot_on_efi.rst → doc/develop/uefi/u-boot_on_efi.rst


+ 0 - 0
doc/uefi/uefi.rst → doc/develop/uefi/uefi.rst


+ 0 - 359
doc/driver-model/of-plat.rst

@@ -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

+ 0 - 23
doc/index.rst

@@ -38,29 +38,6 @@ want to contribute to U-Boot.
 
    develop/index
 
-Unified Extensible Firmware (UEFI)
-----------------------------------
-
-U-Boot provides an implementation of the UEFI API allowing to run UEFI
-compliant software like Linux, GRUB, and iPXE. Furthermore U-Boot itself
-can be run an UEFI payload.
-
-.. toctree::
-   :maxdepth: 2
-
-   uefi/index
-
-Driver-Model documentation
---------------------------
-
-The following holds information on the U-Boot device driver framework:
-driver-model, including the design details of itself and several driver
-subsystems.
-
-.. toctree::
-   :maxdepth: 2
-
-   driver-model/index
 
 U-Boot API documentation
 ------------------------

+ 8 - 0
doc/usage/fit.rst

@@ -0,0 +1,8 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Flat Image Tree (FIT)
+=====================
+
+U-Boot uses Flat Image Tree (FIT) as a standard file format for packaging
+images that it it reads and boots. Documentation about FIT is available at
+doc/uImage.FIT

+ 1 - 0
doc/usage/index.rst

@@ -5,6 +5,7 @@ Use U-Boot
    :maxdepth: 1
 
    fdt_overlays
+   fit
    netconsole
    partitions
 

+ 0 - 6
drivers/bus/ti-sysc.c

@@ -148,12 +148,6 @@ clocks_err:
 	return err;
 }
 
-UCLASS_DRIVER(ti_sysc) = {
-	.id = UCLASS_SIMPLE_BUS,
-	.name = "ti_sysc",
-	.post_bind = dm_scan_fdt_dev
-};
-
 U_BOOT_DRIVER(ti_sysc) = {
 	.name = "ti_sysc",
 	.id = UCLASS_SIMPLE_BUS,

+ 1 - 1
drivers/clk/clk-uclass.c

@@ -39,7 +39,7 @@ int clk_get_by_driver_info(struct udevice *dev, struct phandle_1_arg *cells,
 {
 	int ret;
 
-	ret = device_get_by_driver_info_idx(cells->idx, &clk->dev);
+	ret = device_get_by_ofplat_idx(cells->idx, &clk->dev);
 	if (ret)
 		return ret;
 	clk->id = cells->arg[0];

+ 10 - 4
drivers/clk/clk_fixed_rate.c

@@ -25,18 +25,24 @@ const struct clk_ops clk_fixed_rate_ops = {
 	.enable = dummy_enable,
 };
 
-static int clk_fixed_rate_of_to_plat(struct udevice *dev)
+void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
+				    struct clk_fixed_rate *plat)
 {
-	struct clk *clk = &to_clk_fixed_rate(dev)->clk;
+	struct clk *clk = &plat->clk;
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
-	to_clk_fixed_rate(dev)->fixed_rate =
-		dev_read_u32_default(dev, "clock-frequency", 0);
+	plat->fixed_rate = dev_read_u32_default(dev, "clock-frequency", 0);
 #endif
 	/* Make fixed rate clock accessible from higher level struct clk */
 	/* FIXME: This is not allowed */
 	dev_set_uclass_priv(dev, clk);
+
 	clk->dev = dev;
 	clk->enable_count = 0;
+}
+
+static int clk_fixed_rate_of_to_plat(struct udevice *dev)
+{
+	clk_fixed_rate_ofdata_to_plat_(dev, to_clk_fixed_rate(dev));
 
 	return 0;
 }

+ 33 - 7
drivers/clk/clk_sandbox.c

@@ -9,13 +9,7 @@
 #include <errno.h>
 #include <malloc.h>
 #include <asm/clk.h>
-
-struct sandbox_clk_priv {
-	bool probed;
-	ulong rate[SANDBOX_CLK_ID_COUNT];
-	bool enabled[SANDBOX_CLK_ID_COUNT];
-	bool requested[SANDBOX_CLK_ID_COUNT];
-};
+#include <linux/clk-provider.h>
 
 static ulong sandbox_clk_get_rate(struct clk *clk)
 {
@@ -178,3 +172,35 @@ int sandbox_clk_query_requested(struct udevice *dev, int id)
 		return -EINVAL;
 	return priv->requested[id];
 }
+
+int clk_fixed_rate_of_to_plat(struct udevice *dev)
+{
+	struct clk_fixed_rate *cplat;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct sandbox_clk_fixed_rate_plat *plat = dev_get_plat(dev);
+
+	cplat = &plat->fixed;
+	cplat->fixed_rate = plat->dtplat.clock_frequency;
+#else
+	cplat = to_clk_fixed_rate(dev);
+#endif
+	clk_fixed_rate_ofdata_to_plat_(dev, cplat);
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_clk_fixed_rate_match[] = {
+	{ .compatible = "sandbox,fixed-clock" },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_fixed_clock) = {
+	.name = "sandbox_fixed_clock",
+	.id = UCLASS_CLK,
+	.of_match = sandbox_clk_fixed_rate_match,
+	.of_to_plat = clk_fixed_rate_of_to_plat,
+	.plat_auto = sizeof(struct sandbox_clk_fixed_rate_plat),
+	.ops = &clk_fixed_rate_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};

+ 0 - 6
drivers/clk/clk_sandbox_test.c

@@ -11,12 +11,6 @@
 #include <dm/device_compat.h>
 #include <linux/err.h>
 
-struct sandbox_clk_test {
-	struct clk clks[SANDBOX_CLK_TEST_NON_DEVM_COUNT];
-	struct clk *clkps[SANDBOX_CLK_TEST_ID_COUNT];
-	struct clk_bulk bulk;
-};
-
 static const char * const sandbox_clk_test_names[] = {
 	[SANDBOX_CLK_TEST_ID_FIXED] = "fixed",
 	[SANDBOX_CLK_TEST_ID_SPI] = "spi",

+ 72 - 39
drivers/core/device.c

@@ -45,6 +45,9 @@ static int device_bind_common(struct udevice *parent, const struct driver *drv,
 	bool auto_seq = true;
 	void *ptr;
 
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND))
+		return -ENOSYS;
+
 	if (devp)
 		*devp = NULL;
 	if (!name)
@@ -395,26 +398,31 @@ int device_of_to_plat(struct udevice *dev)
 	if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
 		return 0;
 
-	/* Ensure all parents have ofdata */
-	if (dev->parent) {
-		ret = device_of_to_plat(dev->parent);
+	/*
+	 * This is not needed if binding is disabled, since data is allocated
+	 * at build time.
+	 */
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA_NO_BIND)) {
+		/* Ensure all parents have ofdata */
+		if (dev->parent) {
+			ret = device_of_to_plat(dev->parent);
+			if (ret)
+				goto fail;
+
+			/*
+			 * The device might have already been probed during
+			 * the call to device_probe() on its parent device
+			 * (e.g. PCI bridge devices). Test the flags again
+			 * so that we don't mess up the device.
+			 */
+			if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
+				return 0;
+		}
+
+		ret = device_alloc_priv(dev);
 		if (ret)
 			goto fail;
-
-		/*
-		 * The device might have already been probed during
-		 * the call to device_probe() on its parent device
-		 * (e.g. PCI bridge devices). Test the flags again
-		 * so that we don't mess up the device.
-		 */
-		if (dev_get_flags(dev) & DM_FLAG_PLATDATA_VALID)
-			return 0;
 	}
-
-	ret = device_alloc_priv(dev);
-	if (ret)
-		goto fail;
-
 	drv = dev->driver;
 	assert(drv);
 
@@ -592,7 +600,7 @@ void *dev_get_plat(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->plat_;
+	return dm_priv_to_rw(dev->plat_);
 }
 
 void *dev_get_parent_plat(const struct udevice *dev)
@@ -602,7 +610,7 @@ void *dev_get_parent_plat(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->parent_plat_;
+	return dm_priv_to_rw(dev->parent_plat_);
 }
 
 void *dev_get_uclass_plat(const struct udevice *dev)
@@ -612,7 +620,7 @@ void *dev_get_uclass_plat(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->uclass_plat_;
+	return dm_priv_to_rw(dev->uclass_plat_);
 }
 
 void *dev_get_priv(const struct udevice *dev)
@@ -622,7 +630,7 @@ void *dev_get_priv(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->priv_;
+	return dm_priv_to_rw(dev->priv_);
 }
 
 void *dev_get_uclass_priv(const struct udevice *dev)
@@ -632,7 +640,7 @@ void *dev_get_uclass_priv(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->uclass_priv_;
+	return dm_priv_to_rw(dev->uclass_priv_);
 }
 
 void *dev_get_parent_priv(const struct udevice *dev)
@@ -642,7 +650,7 @@ void *dev_get_parent_priv(const struct udevice *dev)
 		return NULL;
 	}
 
-	return dev->parent_priv_;
+	return dm_priv_to_rw(dev->parent_priv_);
 }
 
 static int device_get_device_tail(struct udevice *dev, int ret,
@@ -803,27 +811,19 @@ int device_get_global_by_ofnode(ofnode ofnode, struct udevice **devp)
 }
 
 #if CONFIG_IS_ENABLED(OF_PLATDATA)
-int device_get_by_driver_info(const struct driver_info *info,
-			      struct udevice **devp)
+int device_get_by_ofplat_idx(uint idx, struct udevice **devp)
 {
-	struct driver_info *info_base =
-		ll_entry_start(struct driver_info, driver_info);
-	int idx = info - info_base;
-	struct driver_rt *drt = gd_dm_driver_rt() + idx;
 	struct udevice *dev;
 
-	dev = drt->dev;
-	*devp = NULL;
-
-	return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
-}
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+		struct udevice *base = ll_entry_start(struct udevice, udevice);
 
-int device_get_by_driver_info_idx(uint idx, struct udevice **devp)
-{
-	struct driver_rt *drt = gd_dm_driver_rt() + idx;
-	struct udevice *dev;
+		dev = base + idx;
+	} else {
+		struct driver_rt *drt = gd_dm_driver_rt() + idx;
 
-	dev = drt->dev;
+		dev = drt->dev;
+	}
 	*devp = NULL;
 
 	return device_get_device_tail(dev, dev ? 0 : -ENOENT, devp);
@@ -1136,3 +1136,36 @@ int dev_enable_by_path(const char *path)
 	return lists_bind_fdt(parent, node, NULL, false);
 }
 #endif
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+static struct udevice_rt *dev_get_rt(const struct udevice *dev)
+{
+	struct udevice *base = ll_entry_start(struct udevice, udevice);
+	int idx = dev - base;
+
+	struct udevice_rt *urt = gd_dm_udevice_rt() + idx;
+
+	return urt;
+}
+
+u32 dev_get_flags(const struct udevice *dev)
+{
+	const struct udevice_rt *urt = dev_get_rt(dev);
+
+	return urt->flags_;
+}
+
+void dev_or_flags(const struct udevice *dev, u32 or)
+{
+	struct udevice_rt *urt = dev_get_rt(dev);
+
+	urt->flags_ |= or;
+}
+
+void dev_bic_flags(const struct udevice *dev, u32 bic)
+{
+	struct udevice_rt *urt = dev_get_rt(dev);
+
+	urt->flags_ &= ~bic;
+}
+#endif /* OF_PLATDATA_RT */

+ 2 - 2
drivers/core/of_addr.c

@@ -372,7 +372,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
 	bus_node->count_cells(dev, &na, &ns);
 	if (!OF_CHECK_COUNTS(na, ns)) {
 		printf("Bad cell count for %s\n", of_node_full_name(dev));
-		return -EINVAL;
+		ret = -EINVAL;
 		goto out_parent;
 	}
 
@@ -380,7 +380,7 @@ int of_get_dma_range(const struct device_node *dev, phys_addr_t *cpu,
 	bus_node->count_cells(parent, &pna, &pns);
 	if (!OF_CHECK_COUNTS(pna, pns)) {
 		printf("Bad cell count for %s\n", of_node_full_name(parent));
-		return -EINVAL;
+		ret = -EINVAL;
 		goto out_parent;
 	}
 

+ 70 - 15
drivers/core/root.c

@@ -11,6 +11,7 @@
 #include <fdtdec.h>
 #include <log.h>
 #include <malloc.h>
+#include <asm-generic/sections.h>
 #include <asm/global_data.h>
 #include <linux/libfdt.h>
 #include <dm/acpi.h>
@@ -129,6 +130,36 @@ void fix_devices(void)
 	}
 }
 
+static int dm_setup_inst(void)
+{
+	DM_ROOT_NON_CONST = DM_DEVICE_GET(root);
+
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_RT)) {
+		struct udevice_rt *urt;
+		void *base;
+		int n_ents;
+		uint size;
+
+		/* Allocate the udevice_rt table */
+		n_ents = ll_entry_count(struct udevice, udevice);
+		urt = calloc(n_ents, sizeof(struct udevice_rt));
+		if (!urt)
+			return log_msg_ret("urt", -ENOMEM);
+		gd_set_dm_udevice_rt(urt);
+
+		/* Now allocate space for the priv/plat data, and copy it in */
+		size = __priv_data_end - __priv_data_start;
+
+		base = calloc(1, size);
+		if (!base)
+			return log_msg_ret("priv", -ENOMEM);
+		memcpy(base, __priv_data_start, size);
+		gd_set_dm_priv_base(base);
+	}
+
+	return 0;
+}
+
 int dm_init(bool of_live)
 {
 	int ret;
@@ -140,8 +171,12 @@ int dm_init(bool of_live)
 		dm_warn("Virtual root driver already exists!\n");
 		return -EINVAL;
 	}
-	gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
-	INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+		gd->uclass_root = &uclass_head;
+	} else {
+		gd->uclass_root = &DM_UCLASS_ROOT_S_NON_CONST;
+		INIT_LIST_HEAD(DM_UCLASS_ROOT_NON_CONST);
+	}
 
 	if (IS_ENABLED(CONFIG_NEEDS_MANUAL_RELOC)) {
 		fix_drivers();
@@ -149,14 +184,23 @@ int dm_init(bool of_live)
 		fix_devices();
 	}
 
-	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
-	if (ret)
-		return ret;
-	if (CONFIG_IS_ENABLED(OF_CONTROL))
-		dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
-	ret = device_probe(DM_ROOT_NON_CONST);
-	if (ret)
-		return ret;
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+		ret = dm_setup_inst();
+		if (ret) {
+			log_debug("dm_setup_inst() failed: %d\n", ret);
+			return ret;
+		}
+	} else {
+		ret = device_bind_by_name(NULL, false, &root_info,
+					  &DM_ROOT_NON_CONST);
+		if (ret)
+			return ret;
+		if (CONFIG_IS_ENABLED(OF_CONTROL))
+			dev_set_ofnode(DM_ROOT_NON_CONST, ofnode_root());
+		ret = device_probe(DM_ROOT_NON_CONST);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
@@ -185,7 +229,7 @@ int dm_scan_plat(bool pre_reloc_only)
 {
 	int ret;
 
-	if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
+	if (CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)) {
 		struct driver_rt *dyn;
 		int n_ents;
 
@@ -303,6 +347,15 @@ __weak int dm_scan_other(bool pre_reloc_only)
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
+void *dm_priv_to_rw(void *priv)
+{
+	long offset = priv - (void *)__priv_data_start;
+
+	return gd_dm_priv_base() + offset;
+}
+#endif
+
 /**
  * dm_scan() - Scan tables to bind devices
  *
@@ -347,10 +400,12 @@ int dm_init_and_scan(bool pre_reloc_only)
 		debug("dm_init() failed: %d\n", ret);
 		return ret;
 	}
-	ret = dm_scan(pre_reloc_only);
-	if (ret) {
-		log_debug("dm_scan() failed: %d\n", ret);
-		return ret;
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+		ret = dm_scan(pre_reloc_only);
+		if (ret) {
+			log_debug("dm_scan() failed: %d\n", ret);
+			return ret;
+		}
 	}
 
 	return 0;

+ 5 - 2
drivers/core/uclass.c

@@ -148,8 +148,11 @@ int uclass_get(enum uclass_id id, struct uclass **ucp)
 
 	*ucp = NULL;
 	uc = uclass_find(id);
-	if (!uc)
+	if (!uc) {
+		if (CONFIG_IS_ENABLED(OF_PLATDATA_INST))
+			return -ENOENT;
 		return uclass_add(id, ucp);
+	}
 	*ucp = uc;
 
 	return 0;
@@ -391,7 +394,7 @@ done:
 	return ret;
 }
 
-#if CONFIG_IS_ENABLED(OF_CONTROL)
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 int uclass_find_device_by_phandle(enum uclass_id id, struct udevice *parent,
 				  const char *name, struct udevice **devp)
 {

+ 0 - 2
drivers/i2c/Makefile

@@ -39,9 +39,7 @@ obj-$(CONFIG_SYS_I2C_RCAR_I2C) += rcar_i2c.o
 obj-$(CONFIG_SYS_I2C_RCAR_IIC) += rcar_iic.o
 obj-$(CONFIG_SYS_I2C_ROCKCHIP) += rk_i2c.o
 obj-$(CONFIG_SYS_I2C_S3C24X0) += s3c24x0_i2c.o exynos_hs_i2c.o
-ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o
-endif
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o

+ 18 - 16
drivers/i2c/i2c-emul-uclass.c

@@ -7,6 +7,7 @@
 #include <dm.h>
 #include <i2c.h>
 #include <log.h>
+#include <asm/i2c.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
 
@@ -23,18 +24,6 @@
  * uclass so avoid having strange devices on the I2C bus.
  */
 
-/**
- * struct i2c_emul_uc_plat - information about the emulator for this device
- *
- * This is used by devices in UCLASS_I2C_EMUL to record information about the
- * device being emulated. It is accessible with dev_get_uclass_plat()
- *
- * @dev: Device being emulated
- */
-struct i2c_emul_uc_plat {
-	struct udevice *dev;
-};
-
 struct udevice *i2c_emul_get_device(struct udevice *emul)
 {
 	struct i2c_emul_uc_plat *uc_plat = dev_get_uclass_plat(emul);
@@ -42,14 +31,27 @@ struct udevice *i2c_emul_get_device(struct udevice *emul)
 	return uc_plat->dev;
 }
 
+void i2c_emul_set_idx(struct udevice *dev, int emul_idx)
+{
+	struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+	plat->emul_idx = emul_idx;
+}
+
 int i2c_emul_find(struct udevice *dev, struct udevice **emulp)
 {
 	struct i2c_emul_uc_plat *uc_plat;
 	struct udevice *emul;
 	int ret;
 
-	ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
-					    "sandbox,emul", &emul);
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA)) {
+		ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev,
+						    "sandbox,emul", &emul);
+	} else {
+		struct dm_i2c_chip *plat = dev_get_parent_plat(dev);
+
+		ret = device_get_by_ofplat_idx(plat->emul_idx, &emul);
+	}
 	if (ret) {
 		log_err("No emulators for device '%s'\n", dev->name);
 		return ret;
@@ -85,8 +87,8 @@ static const struct udevice_id i2c_emul_parent_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(i2c_emul_parent_drv) = {
-	.name		= "i2c_emul_parent_drv",
+U_BOOT_DRIVER(sandbox_i2c_emul_parent) = {
+	.name		= "sandbox_i2c_emul_parent",
 	.id		= UCLASS_I2C_EMUL_PARENT,
 	.of_match	= i2c_emul_parent_ids,
 };

+ 1 - 1
drivers/misc/irq-uclass.c

@@ -69,7 +69,7 @@ int irq_get_by_driver_info(struct udevice *dev,
 {
 	int ret;
 
-	ret = device_get_by_driver_info_idx(cells->idx, &irq->dev);
+	ret = device_get_by_ofplat_idx(cells->idx, &irq->dev);
 	if (ret)
 		return ret;
 	irq->id = cells->arg[0];

+ 9 - 2
drivers/misc/test_drv.c

@@ -86,7 +86,7 @@ static const struct udevice_id testbus_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(testbus_drv) = {
+U_BOOT_DRIVER(denx_u_boot_test_bus) = {
 	.name	= "testbus_drv",
 	.of_match	= testbus_ids,
 	.id	= UCLASS_TEST_BUS,
@@ -98,6 +98,7 @@ U_BOOT_DRIVER(testbus_drv) = {
 	.per_child_plat_auto	= sizeof(struct dm_test_parent_plat),
 	.child_pre_probe = testbus_child_pre_probe,
 	.child_post_remove = testbus_child_post_remove,
+	DM_HEADER(<test.h>)
 };
 
 UCLASS_DRIVER(testbus) = {
@@ -106,6 +107,9 @@ UCLASS_DRIVER(testbus) = {
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.child_pre_probe = testbus_child_pre_probe_uclass,
 	.child_post_probe = testbus_child_post_probe_uclass,
+
+	/* This is for dtoc testing only */
+	.per_device_plat_auto   = sizeof(struct dm_test_uclass_priv),
 };
 
 static int testfdt_drv_ping(struct udevice *dev, int pingval, int *pingret)
@@ -160,7 +164,9 @@ static const struct udevice_id testfdt_ids[] = {
 	{ }
 };
 
-U_BOOT_DRIVER(testfdt_drv) = {
+DM_DRIVER_ALIAS(denx_u_boot_fdt_test, google_another_fdt_test)
+
+U_BOOT_DRIVER(denx_u_boot_fdt_test) = {
 	.name	= "testfdt_drv",
 	.of_match	= testfdt_ids,
 	.id	= UCLASS_TEST_FDT,
@@ -203,6 +209,7 @@ UCLASS_DRIVER(testfdt) = {
 	.name		= "testfdt",
 	.id		= UCLASS_TEST_FDT,
 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.priv_auto	= sizeof(struct dm_test_uc_priv),
 };
 
 static const struct udevice_id testfdtm_ids[] = {

+ 1 - 0
drivers/mmc/Kconfig

@@ -311,6 +311,7 @@ config MMC_MXS
 
 config MMC_PCI
 	bool "Support for MMC controllers on PCI"
+	depends on MMC_SDHCI
 	help
 	  This selects PCI-based MMC controllers.
 	  If you have an MMC controller on a PCI bus, say Y here.

+ 1 - 2
drivers/mmc/fsl_esdhc_imx.c

@@ -1530,8 +1530,7 @@ static int fsl_esdhc_probe(struct udevice *dev)
 	if (CONFIG_IS_ENABLED(DM_GPIO) && !priv->non_removable) {
 		struct udevice *gpiodev;
 
-		ret = device_get_by_driver_info_idx(dtplat->cd_gpios->idx,
-						    &gpiodev);
+		ret = device_get_by_ofplat_idx(dtplat->cd_gpios->idx, &gpiodev);
 		if (ret)
 			return ret;
 

+ 1 - 20
drivers/rtc/i2c_rtc_emul.c

@@ -28,25 +28,6 @@
 #define debug_buffer(x, ...)
 #endif
 
-/**
- * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
- *
- * @base_time:		Base system time when RTC device was bound
- * @offset:		RTC offset from current system time
- * @use_system_time:	true to use system time, false to use @base_time
- * @reg:		Register values
- */
-struct sandbox_i2c_rtc_plat_data {
-	long base_time;
-	long offset;
-	bool use_system_time;
-	u8 reg[REG_COUNT];
-};
-
-struct sandbox_i2c_rtc {
-	unsigned int offset_secs;
-};
-
 long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
 				int offset)
 {
@@ -223,7 +204,7 @@ static int sandbox_i2c_rtc_bind(struct udevice *dev)
 }
 
 static const struct udevice_id sandbox_i2c_rtc_ids[] = {
-	{ .compatible = "sandbox,i2c-rtc" },
+	{ .compatible = "sandbox,i2c-rtc-emul" },
 	{ }
 };
 

+ 13 - 0
drivers/rtc/sandbox_rtc.c

@@ -79,6 +79,18 @@ struct acpi_ops sandbox_rtc_acpi_ops = {
 };
 #endif
 
+static int sandbox_rtc_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(PLATDATA)
+	struct sandbox_i2c_rtc_plat_data *plat = dev_get_plat(dev);
+
+	/* Set up the emul_idx for i2c_emul_find() */
+	i2c_emul_set_idx(dev, plat->dtplat.sandbox_emul->idx);
+#endif
+
+	return 0;
+}
+
 static const struct rtc_ops sandbox_rtc_ops = {
 	.get = sandbox_rtc_get,
 	.set = sandbox_rtc_set,
@@ -97,5 +109,6 @@ U_BOOT_DRIVER(sandbox_rtc) = {
 	.id	= UCLASS_RTC,
 	.of_match = sandbox_rtc_ids,
 	.ops	= &sandbox_rtc_ops,
+	.bind	= sandbox_rtc_bind,
 	ACPI_OPS_PTR(&sandbox_rtc_acpi_ops)
 };

+ 81 - 2
dts/Kconfig

@@ -338,6 +338,7 @@ config SPL_OF_PLATDATA
 	bool "Generate platform data for use in SPL"
 	depends on SPL_OF_CONTROL
 	select DTOC
+	select SPL_OF_PLATDATA_DRIVER_RT if !SPL_OF_PLATDATA_INST
 	help
 	  For very constrained SPL environments the overhead of decoding
 	  device tree nodes and converting their contents into platform data
@@ -355,19 +356,58 @@ config SPL_OF_PLATDATA
 	  compatible string, then adding platform data and U_BOOT_DRVINFO
 	  declarations for each node. See of-plat.txt for more information.
 
+if SPL_OF_PLATDATA
+
 config SPL_OF_PLATDATA_PARENT
 	bool "Support parent information in devices"
-	depends on SPL_OF_PLATDATA
 	default y
 	help
 	  Generally it is useful to be able to access the parent of a device
 	  with of-platdata. To save space this can be disabled, but in that
 	  case dev_get_parent() will always return NULL;
 
+config SPL_OF_PLATDATA_INST
+	bool "Declare devices at build time"
+	help
+	  Declare devices as udevice instances so that they do not need to be
+	  bound when U-Boot starts. This can save time and code space.
+
+config SPL_OF_PLATDATA_NO_BIND
+	bool "Don't allow run-time binding of devices"
+	depends on SPL_OF_PLATDATA_INST
+	default y
+	help
+	  This removes the ability to bind devices at run time, thus saving
+	  some code space in U-Boot. This can be disabled if binding is needed,
+	  at the code of some code size increase.
+
+config SPL_OF_PLATDATA_RT
+	bool "Use a separate struct for device runtime data"
+	depends on SPL_OF_PLATDATA_INST
+	default y
+	help
+	  For systems running SPL from read-only memory it is convenient to
+	  separate out the runtime information, so that the devices don't need
+	  to be copied before being used. This moves the read-write parts of
+	  struct udevice (at present just the flags) into a separate struct,
+	  which is allocated at runtime.
+
+config SPL_OF_PLATDATA_DRIVER_RT
+	bool
+	help
+	  Use a separate struct for driver runtime data.
+
+	  This enables the driver_rt information, used with of-platdata when
+	  of-platdata-inst is not used. It allows finding devices by their
+	  driver data.
+
+endif
+
 config TPL_OF_PLATDATA
 	bool "Generate platform data for use in TPL"
 	depends on TPL_OF_CONTROL
 	select DTOC
+	select TPL_OF_PLATDATA_DRIVER_RT if !TPL_OF_PLATDATA_INST
 	help
 	  For very constrained SPL environments the overhead of decoding
 	  device tree nodes and converting their contents into platform data
@@ -385,13 +425,52 @@ config TPL_OF_PLATDATA
 	  compatible string, then adding platform data and U_BOOT_DRVINFO
 	  declarations for each node. See of-plat.txt for more information.
 
+if TPL_OF_PLATDATA
+
 config TPL_OF_PLATDATA_PARENT
 	bool "Support parent information in devices"
-	depends on TPL_OF_PLATDATA
 	default y
 	help
 	  Generally it is useful to be able to access the parent of a device
 	  with of-platdata. To save space this can be disabled, but in that
 	  case dev_get_parent() will always return NULL;
 
+config TPL_OF_PLATDATA_INST
+	bool "Declare devices at build time"
+
+	help
+	  Declare devices as udevice instances so that they do not need to be
+	  bound when U-Boot starts. This can save time and code space.
+
+config TPL_OF_PLATDATA_NO_BIND
+	bool "Don't allow run-time binding of devices"
+	depends on TPL_OF_PLATDATA_INST
+	default y
+	help
+	  This removes the ability to bind devices at run time, thus saving
+	  some code space in U-Boot. This can be disabled if binding is needed,
+	  at the code of some code size increase.
+
+config TPL_OF_PLATDATA_RT
+	bool "Use a separate struct for device runtime data"
+	depends on TPL_OF_PLATDATA_INST
+	default y
+	help
+	  For systems running TPL from read-only memory it is convenient to
+	  separate out the runtime information, so that the devices don't need
+	  to be copied before being used. This moves the read-write parts of
+	  struct udevice (at present just the flags) into a separate struct,
+	  which is allocated at runtime.
+
+config TPL_OF_PLATDATA_DRIVER_RT
+	bool
+	help
+	  Use a separate struct for driver runtime data.
+
+	  This enables the driver_rt information, used with of-platdata when
+	  of-platdata-inst is not used. It allows finding devices by their
+	  driver data.
+
+endif
+
 endmenu

+ 24 - 2
include/asm-generic/global_data.h

@@ -215,10 +215,20 @@ struct global_data {
 	 * @uclass_root_s.
 	 */
 	struct list_head *uclass_root;
-# if CONFIG_IS_ENABLED(OF_PLATDATA)
+# if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)
 	/** @dm_driver_rt: Dynamic info about the driver */
 	struct driver_rt *dm_driver_rt;
 # endif
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+	/** @dm_udevice_rt: Dynamic info about the udevice */
+	struct udevice_rt *dm_udevice_rt;
+	/**
+	 * @dm_priv_base: Base address of the priv/plat region used when
+	 * udevices and uclasses are in read-only memory. This is NULL if not
+	 * used
+	 */
+	void *dm_priv_base;
+# endif
 #endif
 #ifdef CONFIG_TIMER
 	/**
@@ -483,7 +493,7 @@ struct global_data {
 #define gd_set_of_root(_root)
 #endif
 
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
+#if CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT)
 #define gd_set_dm_driver_rt(dyn)	gd->dm_driver_rt = dyn
 #define gd_dm_driver_rt()		gd->dm_driver_rt
 #else
@@ -491,6 +501,18 @@ struct global_data {
 #define gd_dm_driver_rt()		NULL
 #endif
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+#define gd_set_dm_udevice_rt(dyn)	gd->dm_udevice_rt = dyn
+#define gd_dm_udevice_rt()		gd->dm_udevice_rt
+#define gd_set_dm_priv_base(dyn)	gd->dm_priv_base = dyn
+#define gd_dm_priv_base()		gd->dm_priv_base
+#else
+#define gd_set_dm_udevice_rt(dyn)
+#define gd_dm_udevice_rt()		NULL
+#define gd_set_dm_priv_base(dyn)
+#define gd_dm_priv_base()		NULL
+#endif
+
 #ifdef CONFIG_GENERATE_ACPI_TABLE
 #define gd_acpi_ctx()		gd->acpi_ctx
 #else

+ 3 - 0
include/asm-generic/sections.h

@@ -28,6 +28,9 @@ extern char __efi_helloworld_end[];
 extern char __efi_var_file_begin[];
 extern char __efi_var_file_end[];
 
+/* Private data used by of-platdata devices/uclasses */
+extern char __priv_data_start[], __priv_data_end[];
+
 /* Start and end of .ctors section - used for constructor calls. */
 extern char __ctors_start[], __ctors_end[];
 

+ 93 - 0
include/dm/device-internal.h

@@ -10,11 +10,86 @@
 #ifndef _DM_DEVICE_INTERNAL_H
 #define _DM_DEVICE_INTERNAL_H
 
+#include <linker_lists.h>
 #include <dm/ofnode.h>
 
 struct device_node;
 struct udevice;
 
+/*
+ * These two macros DM_DEVICE_INST and DM_DEVICE_REF are only allowed in code
+ * generated by dtoc, because the ordering is important and if other instances
+ * creep in then they may mess up the ordering expected by dtoc.
+ *
+ * It is OK to use them with 'extern' though, since that does not actually
+ * add a new record to the linker_list.
+ */
+
+/**
+ * DM_DEVICE_INST() - Declare a bound device ready for run-time use
+ *
+ * This adds an actual struct udevice to a list which is found by driver model
+ * on start-up.
+ *
+ * For example:
+ *
+ * extern U_BOOT_DRIVER(sandbox_fixed_clock);
+ * extern DM_UCLASS_INST(clk);
+ *
+ * DM_DEVICE_INST(clk_fixed) = {
+ *	.driver		= DM_DRIVER_REF(sandbox_fixed_clock),
+ *	.name		= "sandbox_fixed_clock",
+ *	.plat_		= &_sandbox_fixed_clock_plat_clk_fixed,
+ *	.uclass		= DM_UCLASS_REF(clk),
+ *	...
+ *	.seq_		= 0,
+ * };
+ *
+ * @_name: Name of the udevice. This must be a valid C identifier, used by the
+ *	linker_list.
+ */
+#define DM_DEVICE_INST(_name)						\
+	ll_entry_declare(struct udevice, _name, udevice)
+
+/**
+ * DM_DEVICE_REF() - Get a reference to a device
+ *
+ * This is useful in data structures and code for referencing a udevice at
+ * build time. Before this is used, an extern DM_DEVICE_INST() must have been
+ * declared.
+ *
+ * For example:
+ *
+ * extern DM_DEVICE_INST(clk_fixed);
+ *
+ * struct udevice *devs[] = {
+ *	DM_DEVICE_REF(clk_fixed),
+ * };
+ *
+ * @_name: Name of the udevice. This must be a valid C identifier, used by the
+ *	linker_list
+ * @returns struct udevice * for the device
+ */
+#define DM_DEVICE_REF(_name)						\
+	ll_entry_ref(struct udevice, _name, udevice)
+
+/**
+ * DM_DEVICE_GET() - Get a pointer to a given device
+ *
+ * This is similar to DM_DEVICE_REF() except that it does not need the extern
+ * declaration before it. However it cannot be used in a data structures, only
+ * in code within a function.
+ *
+ * For example:
+ *
+ * void some_function() {
+ *	struct udevice *dev = DM_DEVICE_GET(clk_fixed);
+ * ...
+ * }
+ */
+#define DM_DEVICE_GET(__name)						\
+	ll_entry_get(struct udevice, __name, udevice)
+
 /**
  * device_bind() - Create a device and bind it to a driver
  *
@@ -209,6 +284,9 @@ static inline int device_chld_remove(struct udevice *dev, struct driver *drv,
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev		Device to check
  * @priv	New private-data pointer
  */
@@ -223,6 +301,9 @@ void dev_set_priv(struct udevice *dev, void *priv);
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev:	Device to update
  * @parent_priv: New parent-private data
  */
@@ -237,6 +318,9 @@ void dev_set_parent_priv(struct udevice *dev, void *parent_priv);
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev:	Device to update
  * @uclass_priv: New uclass private data
  */
@@ -251,6 +335,9 @@ void dev_set_uclass_priv(struct udevice *dev, void *uclass_priv);
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev		Device to check
  * @plat	New platform-data pointer
  */
@@ -265,6 +352,9 @@ void dev_set_plat(struct udevice *dev, void *priv);
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev:	Device to update
  * @parent_plat: New parent platform data
  */
@@ -279,6 +369,9 @@ void dev_set_parent_plat(struct udevice *dev, void *parent_plat);
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @dev:	Device to update
  * @uclass_plat: New uclass platform data
  */

+ 89 - 19
include/dm/device.h

@@ -177,7 +177,9 @@ struct udevice {
 	struct list_head uclass_node;
 	struct list_head child_head;
 	struct list_head sibling_node;
+#if !CONFIG_IS_ENABLED(OF_PLATDATA_RT)
 	u32 flags_;
+#endif
 	int seq_;
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 	ofnode node_;
@@ -190,12 +192,32 @@ struct udevice {
 #endif
 };
 
+/**
+ * udevice_rt - runtime information set up by U-Boot
+ *
+ * This is only used with OF_PLATDATA_RT
+ *
+ * There is one of these for every udevice in the linker list, indexed by
+ * the udevice_info idx value.
+ *
+ * @flags_: Flags for this device DM_FLAG_... (do not access outside driver
+ *	model)
+ */
+struct udevice_rt {
+	u32 flags_;
+};
+
 /* Maximum sequence number supported */
 #define DM_MAX_SEQ	999
 
 /* Returns the operations for a device */
 #define device_get_ops(dev)	(dev->driver->ops)
 
+#if CONFIG_IS_ENABLED(OF_PLATDATA_RT)
+u32 dev_get_flags(const struct udevice *dev);
+void dev_or_flags(const struct udevice *dev, u32 or);
+void dev_bic_flags(const struct udevice *dev, u32 bic);
+#else
 static inline u32 dev_get_flags(const struct udevice *dev)
 {
 	return dev->flags_;
@@ -210,6 +232,7 @@ static inline void dev_bic_flags(struct udevice *dev, u32 bic)
 {
 	dev->flags_ &= ~bic;
 }
+#endif /* OF_PLATDATA_RT */
 
 /**
  * dev_ofnode() - get the DT node reference associated with a udevice
@@ -362,6 +385,28 @@ struct driver {
 #define DM_DRIVER_GET(__name)						\
 	ll_entry_get(struct driver, __name, driver)
 
+/**
+ * DM_DRIVER_REF() - Get a reference to a driver
+ *
+ * This is useful in data structures and code for referencing a driver at
+ * build time. Before this is used, an extern U_BOOT_DRIVER() must have been
+ * declared.
+ *
+ * For example:
+ *
+ * extern U_BOOT_DRIVER(sandbox_fixed_clock);
+ *
+ * struct driver *drvs[] = {
+ *	DM_DRIVER_REF(sandbox_fixed_clock),
+ * };
+ *
+ * @_name: Name of the driver. This must be a valid C identifier, used by the
+ *	linker_list
+ * @returns struct driver * for the driver
+ */
+#define DM_DRIVER_REF(_name)					\
+	ll_entry_ref(struct driver, _name, driver)
+
 /**
  * Declare a macro to state a alias for a driver name. This macro will
  * produce no code but its information will be parsed by tools like
@@ -369,6 +414,40 @@ struct driver {
  */
 #define DM_DRIVER_ALIAS(__name, __alias)
 
+/**
+ * Declare a macro to indicate which phase of U-Boot this driver is fore.
+ *
+ *
+ * This macro produces no code but its information will be parsed by dtoc. The
+ * macro can be only be used once in a driver. Put it within the U_BOOT_DRIVER()
+ * declaration, e.g.:
+ *
+ * U_BOOT_DRIVER(cpu) = {
+ *	.name = ...
+ *	...
+ *	DM_PHASE(tpl)
+ * };
+ */
+#define DM_PHASE(_phase)
+
+/**
+ * Declare a macro to declare a header needed for a driver. Often the correct
+ * header can be found automatically, but only for struct declarations. For
+ * enums and #defines used in the driver declaration and declared in a different
+ * header from the structs, this macro must be used.
+ *
+ * This macro produces no code but its information will be parsed by dtoc. The
+ * macro can be used multiple times with different headers, for the same driver.
+ * Put it within the U_BOOT_DRIVER() declaration, e.g.:
+ *
+ * U_BOOT_DRIVER(cpu) = {
+ *	.name = ...
+ *	...
+ *	DM_HEADER(<asm/cpu.h>)
+ * };
+ */
+#define DM_HEADER(_hdr)
+
 /**
  * dev_get_plat() - Get the platform data for a device
  *
@@ -611,33 +690,24 @@ int device_find_global_by_ofnode(ofnode node, struct udevice **devp);
 int device_get_global_by_ofnode(ofnode node, struct udevice **devp);
 
 /**
- * device_get_by_driver_info() - Get a device based on driver_info
- *
- * Locates a device by its struct driver_info, by using its reference which
- * is updated during the bind process.
+ * device_get_by_ofplat_idx() - Get a device based on of-platdata index
  *
- * The device is probed to activate it ready for use.
- *
- * @info: Struct driver_info
- * @devp: Returns pointer to device if found, otherwise this is set to NULL
- * @return 0 if OK, -ve on error
- */
-int device_get_by_driver_info(const struct driver_info *info,
-			      struct udevice **devp);
-
-/**
- * device_get_by_driver_info_idx() - Get a device based on driver_info index
+ * Locates a device by either its struct driver_info index, or its
+ * struct udevice index. The latter is used with OF_PLATDATA_INST, since we have
+ * a list of build-time instantiated struct udevice records, The former is used
+ * with !OF_PLATDATA_INST since in that case we have a list of
+ * struct driver_info records.
  *
- * Locates a device by its struct driver_info, by using its index number which
- * is written into the idx field of struct phandle_1_arg, etc.
+ * The index number is written into the idx field of struct phandle_1_arg, etc.
+ * It is the position of this driver_info/udevice in its linker list.
  *
  * The device is probed to activate it ready for use.
  *
- * @idx: Index number of the driver_info structure (0=first)
+ * @idx: Index number of the driver_info/udevice structure (0=first)
  * @devp: Returns pointer to device if found, otherwise this is set to NULL
  * @return 0 if OK, -ve on error
  */
-int device_get_by_driver_info_idx(uint idx, struct udevice **devp);
+int device_get_by_ofplat_idx(uint idx, struct udevice **devp);
 
 /**
  * device_find_first_child() - Find the first child of a device

+ 0 - 15
include/dm/platdata.h

@@ -71,19 +71,4 @@ struct driver_rt {
 #define U_BOOT_DRVINFOS(__name)						\
 	ll_entry_declare_list(struct driver_info, __name, driver_info)
 
-/**
- * Get a pointer to a given device info given its name
- *
- * With the declaration U_BOOT_DRVINFO(name), DM_DRVINFO_GET(name) will return a
- * pointer to the struct driver_info created by that declaration.
- *
- * if OF_PLATDATA is enabled, from this it is possible to use the @dev member of
- * struct driver_info to find the device pointer itself.
- *
- * @__name: Driver name (C identifier, not a string. E.g. gpio7_at_ff7e0000)
- * @return struct driver_info * to the driver that created the device
- */
-#define DM_DRVINFO_GET(__name)						\
-	ll_entry_get(struct driver_info, __name, driver_info)
-
 #endif

+ 3 - 0
include/dm/root.h

@@ -11,6 +11,9 @@
 
 struct udevice;
 
+/* Head of the uclass list if CONFIG_OF_PLATDATA_INST is enabled */
+extern struct list_head uclass_head;
+
 /**
  * dm_root() - Return pointer to the top of the driver tree
  *

+ 5 - 0
include/dm/test.h

@@ -71,6 +71,11 @@ struct dm_test_priv {
 	int uclass_postp;
 };
 
+/* struct dm_test_uc_priv - private data for the testdrv uclass */
+struct dm_test_uc_priv {
+	int dummy;
+};
+
 /**
  * struct dm_test_perdev_class_priv - private per-device data for test uclass
  */

+ 52 - 0
include/dm/uclass-internal.h

@@ -11,6 +11,55 @@
 
 #include <dm/ofnode.h>
 
+/*
+ * These next two macros DM_UCLASS_INST() and DM_UCLASS_REF() are only allowed
+ * in code generated by dtoc, because the ordering is important and if other
+ * instances creep in then they may mess up the ordering expected by dtoc.
+ *
+ * It is OK to use them with 'extern' though, since that does not actually
+ * add a new record to the linker_list.
+ */
+
+/**
+ * DM_UCLASS_INST() - Declare a uclass ready for run-time use
+ *
+ * This adds an actual struct uclass to a list which is found by driver model
+ * on start-up.
+ *
+ * For example:
+ *
+ * DM_UCLASS_INST(clk) = {
+ *	.uc_drv		= DM_UCLASS_DRIVER_REF(clk),
+ * ...
+ * };
+ *
+ * @_name: Name of the uclass. This must be a valid C identifier, used by the
+ *	linker_list.
+ */
+#define DM_UCLASS_INST(_name)						\
+	ll_entry_declare(struct uclass, _name, uclass)
+
+/**
+ * DM_UCLASS_REF() - Get a reference to a uclass
+ *
+ * This is useful for referencing a uclass at build time. Before this is used,
+ * an extern DM_UCLASS_INST() must have been declared.
+ *
+ * For example:
+ *
+ * extern DM_UCLASS_INST(clk);
+ *
+ * struct uclass *ucs[] = {
+ *	DM_UCLASS_REF(clk),
+ * }
+ *
+ * @_name: Name of the uclass. This must be a valid C identifier, used by the
+ *	linker_list
+ * @returns struct uclass * for the device
+ */
+#define DM_UCLASS_REF(_name)						\
+	ll_entry_ref(struct uclass, _name, uclass)
+
 /**
  * uclass_set_priv() - Set the private data for a uclass
  *
@@ -20,6 +69,9 @@
  * Use this function to override normal operation for special situations, such
  * as needing to allocate a variable amount of data.
  *
+ * If OF_PLATDATA_RT is enabled, this function cannot be used out of core driver
+ * model code, since the pointer must be within the gd->dm_priv_base region.
+ *
  * @uc		Uclass to update
  * @priv	New private-data pointer
  */

+ 31 - 0
include/dm/uclass.h

@@ -114,6 +114,37 @@ struct uclass_driver {
 #define UCLASS_DRIVER(__name)						\
 	ll_entry_declare(struct uclass_driver, __name, uclass_driver)
 
+/*
+ * These two macros DM_UCLASS_DRIVER_REF and DM_UCLASS_DRIVER_REF are only
+ * allowed in code generated by dtoc, because the ordering is important and if
+ * other instances creep in then they may mess up the ordering expected by dtoc.
+ *
+ * It is OK to use them with 'extern' though, since that does not actually
+ * add a new record to the linker_list.
+ */
+
+/**
+ * DM_UCLASS_DRIVER_REF() - Get a reference to a uclass driver
+ *
+ * This is useful in data structures and code for referencing a uclass_driver at
+ * build time. Before this is used, an extern UCLASS_DRIVER() must have been
+ * declared.
+ *
+ * For example:
+ *
+ * extern UCLASS_DRIVER(clk);
+ *
+ * struct uclass_driver *drvs[] = {
+ *	DM_UCLASS_DRIVER_REF(clk),
+ * };
+ *
+ * @_name: Name of the uclass_driver. This must be a valid C identifier, used by
+ *	the linker_list.
+ * @returns struct uclass_driver * for the uclass driver
+ */
+#define DM_UCLASS_DRIVER_REF(_name)					\
+	ll_entry_ref(struct uclass_driver, _name, uclass_driver)
+
 /**
  * uclass_get_priv() - Get the private data for a uclass
  *

+ 9 - 0
include/dm/util.h

@@ -49,3 +49,12 @@ void dm_dump_driver_compat(void);
 void dm_dump_static_driver_info(void);
 
 #endif
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA_INST) && CONFIG_IS_ENABLED(READ_ONLY)
+void *dm_priv_to_rw(void *priv);
+#else
+static inline void *dm_priv_to_rw(void *priv)
+{
+	return priv;
+}
+#endif

+ 2 - 0
include/dt-structs.h

@@ -24,7 +24,9 @@ struct phandle_2_arg {
 	uint idx;
 	int arg[2];
 };
+
 #include <generated/dt-structs-gen.h>
+#include <generated/dt-decl.h>
 #endif
 
 #endif

+ 15 - 0
include/i2c.h

@@ -93,6 +93,8 @@ struct udevice;
  *			   datasheet explains it's usage of this addressing
  *			   mode.
  * @emul: Emulator for this chip address (only used for emulation)
+ * @emul_idx: Emulator index, used for of-platdata and set by each i2c chip's
+ *	bind() method. This allows i2c_emul_find() to work with of-platdata.
  */
 struct dm_i2c_chip {
 	uint chip_addr;
@@ -102,6 +104,7 @@ struct dm_i2c_chip {
 #ifdef CONFIG_SANDBOX
 	struct udevice *emul;
 	bool test_mode;
+	int emul_idx;
 #endif
 };
 
@@ -554,6 +557,18 @@ void i2c_dump_msgs(struct i2c_msg *msg, int nmsgs);
  */
 int i2c_emul_find(struct udevice *dev, struct udevice **emulp);
 
+/**
+ * i2c_emul_set_idx() - Set the emulator index for an i2c sandbox device
+ *
+ * With of-platdata we cannot find the emulator using the device tree, so rely
+ * on the bind() method of each i2c driver calling this function to tell us
+ * the of-platdata idx of the emulator
+ *
+ * @dev: i2c device to set the emulator for
+ * @emul_idx: of-platdata index for that emulator
+ */
+void i2c_emul_set_idx(struct udevice *dev, int emul_idx);
+
 /**
  * i2c_emul_get_device() - Find the device being emulated
  *

+ 12 - 0
include/linker_lists.h

@@ -211,6 +211,18 @@
 		_ll_result;						\
 	})
 
+/**
+ * ll_entry_ref() - Get a reference to a linker-generated array entry
+ *
+ * Once an extern ll_entry_declare() has been used to declare the reference,
+ * this macro allows the entry to be accessed.
+ *
+ * This is like ll_entry_get(), but without the extra code, so it is suitable
+ * for putting into data structures.
+ */
+#define ll_entry_ref(_type, _name, _list)				\
+	((_type *)&_u_boot_list_2_##_list##_2_##_name)
+
 /**
  * ll_start() - Point to first entry of first linker-generated array
  * @_type:	Data type of the entry

+ 5 - 0
include/linux/clk-provider.h

@@ -192,6 +192,8 @@ struct clk_fixed_factor {
 	unsigned int	div;
 };
 
+extern const struct clk_ops clk_fixed_rate_ops;
+
 #define to_clk_fixed_factor(_clk) container_of(_clk, struct clk_fixed_factor,\
 					       clk)
 
@@ -202,6 +204,9 @@ struct clk_fixed_rate {
 
 #define to_clk_fixed_rate(dev)	((struct clk_fixed_rate *)dev_get_plat(dev))
 
+void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev,
+				    struct clk_fixed_rate *plat);
+
 struct clk_composite {
 	struct clk	clk;
 	struct clk_ops	ops;

+ 35 - 13
scripts/Makefile.spl

@@ -120,10 +120,25 @@ endif
 u-boot-spl-init := $(head-y)
 u-boot-spl-main := $(libs-y)
 ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA
-u-boot-spl-platdata := $(obj)/dts/dt-plat.o
-u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata))
+platdata-hdr := include/generated/dt-structs-gen.h include/generated/dt-decl.h
+platdata-inst := $(obj)/dts/dt-uclass.o $(obj)/dts/dt-device.o
+platdata-noinst := $(obj)/dts/dt-plat.o
+
+ifdef CONFIG_$(SPL_TPL_)OF_PLATDATA_INST
+u-boot-spl-platdata := $(platdata-inst)
+u-boot-spl-old-platdata := $(platdata-noinst)
+else
+u-boot-spl-platdata := $(platdata-noinst)
+u-boot-spl-old-platdata := $(platdata-inst)
 endif
 
+# Files we need to generate
+u-boot-spl-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-platdata))
+
+# Files we won't generate and should remove
+u-boot-spl-old-platdata_c := $(patsubst %.o,%.c,$(u-boot-spl-old-platdata))
+endif  # OF_PLATDATA
+
 # Linker Script
 # First test whether there's a linker-script for the specific stage defined...
 ifneq ($(CONFIG_$(SPL_TPL_)LDSCRIPT),)
@@ -311,7 +326,11 @@ $(obj)/$(SPL_BIN).dtb: $(obj)/dts/dt-$(SPL_NAME).dtb FORCE
 pythonpath = PYTHONPATH=scripts/dtc/pylibfdt
 
 DTOC_ARGS := $(pythonpath) $(srctree)/tools/dtoc/dtoc \
-	-d $(obj)/$(SPL_BIN).dtb
+	-d $(obj)/$(SPL_BIN).dtb -p $(SPL_NAME)
+
+ifneq ($(CONFIG_$(SPL_TPL_)OF_PLATDATA_INST),)
+DTOC_ARGS += -i
+endif
 
 quiet_cmd_dtoc = DTOC    $@
 cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
@@ -319,18 +338,17 @@ cmd_dtoc = $(DTOC_ARGS) -c $(obj)/dts -C include/generated all
 quiet_cmd_plat = PLAT    $@
 cmd_plat = $(CC) $(c_flags) -c $< -o $(filter-out $(PHONY),$@)
 
-targets += $(u-boot-spl-platdata)
-
-$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c \
-		include/generated/dt-structs-gen.h prepare FORCE
+$(obj)/dts/dt-%.o: $(obj)/dts/dt-%.c $(platdata-hdr)
 	$(call if_changed,plat)
 
-PHONY += dts_dir
-dts_dir:
-	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
-
-include/generated/dt-structs-gen.h $(u-boot-spl-platdata_c) &: \
-		$(obj)/$(SPL_BIN).dtb dts_dir FORCE
+# Don't use dts_dir here, since it forces running this expensive rule every time
+$(platdata-hdr) $(u-boot-spl-platdata_c) &: $(obj)/$(SPL_BIN).dtb
+	@[ -d $(obj)/dts ] || mkdir -p $(obj)/dts
+	@# Remove old files since which ones we generate depends on the setting
+	@# of OF_PLATDATA_INST and this might change between builds. Leaving old
+	@# ones around is confusing and it is possible that switching the
+	@# setting again will use the old one instead of regenerating it.
+	@rm -f $(u-boot-spl-all-platdata_c) $(u-boot-spl-all-platdata)
 	$(call if_changed,dtoc)
 
 ifdef CONFIG_SAMSUNG
@@ -471,6 +489,10 @@ FORCE:
 $(obj)/dts/dt-$(SPL_NAME).dtb: dts/dt.dtb
 	$(Q)$(MAKE) $(build)=$(obj)/dts spl_dtbs
 
+PHONY += dts_dir
+dts_dir:
+	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
+
 # Declare the contents of the .PHONY variable as phony.  We keep that
 # information in a variable so we can use it in if_changed and friends.
 .PHONY: $(PHONY)

+ 9 - 3
scripts/dtc/pylibfdt/Makefile

@@ -23,12 +23,18 @@ quiet_cmd_pymod = PYMOD   $@
 		SWIG_OPTS="-I$(LIBFDT_srcdir) -I$(LIBFDT_srcdir)/.." \
 		$(PYTHON3) $< --quiet build_ext --inplace
 
-$(obj)/_libfdt.so: $(src)/setup.py $(PYLIBFDT_srcs) FORCE
+rebuild: $(src)/setup.py $(PYLIBFDT_srcs)
 	@# Remove the library since otherwise Python doesn't seem to regenerate
 	@# the libfdt.py file if it is missing.
-	rm -f $(obj)/_libfdt*.so
+	@rm -f $(obj)/_libfdt*.so
 	$(call if_changed,pymod)
+	@# Rename the file to _libfdt.so so this Makefile doesn't run every time
+	@if [ ! -e $(obj)/_libfdt.so ]; then \
+		mv $(obj)/_libfdt*.so $(obj)/_libfdt.so; \
+	fi
 
-always += _libfdt.so
+$(obj)/_libfdt.so $(obj)/libfdt.py &: rebuild
+
+always += _libfdt.so libfdt.py
 
 clean-files += libfdt.i _libfdt.so libfdt.py libfdt_wrap.c

+ 1 - 1
test/cmd/setexpr.c

@@ -15,7 +15,7 @@
 
 #define BUF_SIZE	0x100
 
-/* Declare a new mem test */
+/* Declare a new setexpr test */
 #define SETEXPR_TEST(_name, _flags)	UNIT_TEST(_name, _flags, setexpr_test)
 
 /* Test 'setexpr' command with simply setting integers */

+ 16 - 16
test/dm/of_platdata.c

@@ -142,12 +142,14 @@ static int find_driver_info(struct unit_test_state *uts, struct udevice *parent,
 /* Check that every device is recorded in its driver_info struct */
 static int dm_test_of_plat_dev(struct unit_test_state *uts)
 {
-	const struct driver_info *info =
-		ll_entry_start(struct driver_info, driver_info);
 	const int n_ents = ll_entry_count(struct driver_info, driver_info);
 	bool found[n_ents];
 	uint i;
 
+	/* Skip this test if there is no platform data */
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA_DRIVER_RT))
+		return 0;
+
 	/* Record the indexes that are found */
 	memset(found, '\0', sizeof(found));
 	ut_assertok(find_driver_info(uts, gd->dm_root, found));
@@ -155,18 +157,16 @@ static int dm_test_of_plat_dev(struct unit_test_state *uts)
 	/* Make sure that the driver entries without devices have no ->dev */
 	for (i = 0; i < n_ents; i++) {
 		const struct driver_rt *drt = gd_dm_driver_rt() + i;
-		const struct driver_info *entry = info + i;
 		struct udevice *dev;
 
 		if (found[i]) {
 			/* Make sure we can find it */
 			ut_assertnonnull(drt->dev);
-			ut_assertok(device_get_by_driver_info(entry, &dev));
+			ut_assertok(device_get_by_ofplat_idx(i, &dev));
 			ut_asserteq_ptr(dev, drt->dev);
 		} else {
 			ut_assertnull(drt->dev);
-			ut_asserteq(-ENOENT,
-				    device_get_by_driver_info(entry, &dev));
+			ut_asserteq(-ENOENT, device_get_by_ofplat_idx(i, &dev));
 		}
 	}
 
@@ -184,22 +184,22 @@ static int dm_test_of_plat_phandle(struct unit_test_state *uts)
 	ut_asserteq_str("sandbox_clk_test", dev->name);
 	plat = dev_get_plat(dev);
 
-	ut_assertok(device_get_by_driver_info_idx(plat->clocks[0].idx, &clk));
-	ut_asserteq_str("fixed_clock", clk->name);
+	ut_assertok(device_get_by_ofplat_idx(plat->clocks[0].idx, &clk));
+	ut_asserteq_str("sandbox_fixed_clock", clk->name);
 
-	ut_assertok(device_get_by_driver_info_idx(plat->clocks[1].idx, &clk));
+	ut_assertok(device_get_by_ofplat_idx(plat->clocks[1].idx, &clk));
 	ut_asserteq_str("sandbox_clk", clk->name);
 	ut_asserteq(1, plat->clocks[1].arg[0]);
 
-	ut_assertok(device_get_by_driver_info_idx(plat->clocks[2].idx, &clk));
+	ut_assertok(device_get_by_ofplat_idx(plat->clocks[2].idx, &clk));
 	ut_asserteq_str("sandbox_clk", clk->name);
 	ut_asserteq(0, plat->clocks[2].arg[0]);
 
-	ut_assertok(device_get_by_driver_info_idx(plat->clocks[3].idx, &clk));
+	ut_assertok(device_get_by_ofplat_idx(plat->clocks[3].idx, &clk));
 	ut_asserteq_str("sandbox_clk", clk->name);
 	ut_asserteq(3, plat->clocks[3].arg[0]);
 
-	ut_assertok(device_get_by_driver_info_idx(plat->clocks[4].idx, &clk));
+	ut_assertok(device_get_by_ofplat_idx(plat->clocks[4].idx, &clk));
 	ut_asserteq_str("sandbox_clk", clk->name);
 	ut_asserteq(2, plat->clocks[4].arg[0]);
 
@@ -211,11 +211,11 @@ DM_TEST(dm_test_of_plat_phandle, UT_TESTF_SCAN_PDATA);
 /* Test that device parents are correctly set up */
 static int dm_test_of_plat_parent(struct unit_test_state *uts)
 {
-	struct udevice *dev, *bus;
+	struct udevice *rtc, *i2c;
 
-	ut_assertok(uclass_first_device_err(UCLASS_SIMPLE_BUS, &bus));
-	ut_assertok(device_first_child_err(bus, &dev));
-	ut_asserteq_ptr(bus, dev_get_parent(dev));
+	ut_assertok(uclass_first_device_err(UCLASS_RTC, &rtc));
+	ut_assertok(uclass_first_device_err(UCLASS_I2C, &i2c));
+	ut_asserteq_ptr(i2c, dev_get_parent(rtc));
 
 	return 0;
 }

+ 3 - 3
test/dm/test-fdt.c

@@ -330,7 +330,7 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
 
 	/* Check creating a device with an alias */
 	node = ofnode_path("/some-bus/c-test@1");
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"c-test@1", NULL, node, &dev));
 	ut_asserteq(12, dev_seq(dev));
 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 12, &dev));
@@ -350,11 +350,11 @@ static int dm_test_fdt_uclass_seq_more(struct unit_test_state *uts)
 	 *
 	 * So next available is 19
 	 */
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"fred", NULL, ofnode_null(), &dev));
 	ut_asserteq(19, dev_seq(dev));
 
-	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(testfdt_drv),
+	ut_assertok(device_bind(dm_root(), DM_DRIVER_GET(denx_u_boot_fdt_test),
 				"fred2", NULL, ofnode_null(), &dev));
 	ut_asserteq(20, dev_seq(dev));
 

+ 1 - 1
test/print_ut.c

@@ -6,8 +6,8 @@
 #define DEBUG
 
 #include <common.h>
-#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 #include <command.h>
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 #include <efi_api.h>
 #endif
 #include <display_options.h>

+ 4 - 0
test/run

@@ -30,6 +30,10 @@ fi
 run_test "sandbox_spl" ./test/py/test.py --bd sandbox_spl --build \
 		-k 'test_ofplatdata or test_handoff or test_spl'
 
+# Run the sane tests with sandbox_noinst (i.e. without OF_PLATDATA_INST)
+run_test "sandbox_spl" ./test/py/test.py --bd sandbox_noinst --build \
+		-k 'test_ofplatdata or test_handoff or test_spl'
+
 if [ -z "$tools_only" ]; then
 	# Run tests for the flat-device-tree version of sandbox. This is a special
 	# build which does not enable CONFIG_OF_LIVE for the live device tree, so we can

+ 19 - 11
test/test-main.c

@@ -62,17 +62,25 @@ static int dm_test_post_run(struct unit_test_state *uts)
 {
 	int id;
 
-	for (id = 0; id < UCLASS_COUNT; id++) {
-		struct uclass *uc;
-
-		/*
-		 * If the uclass doesn't exist we don't want to create it. So
-		 * check that here before we call uclass_find_device().
-		 */
-		uc = uclass_find(id);
-		if (!uc)
-			continue;
-		ut_assertok(uclass_destroy(uc));
+	/*
+	 * With of-platdata-inst the uclasses are created at build time. If we
+	 * destroy them we cannot get them back since uclass_add() is not
+	 * supported. So skip this.
+	 */
+	if (!CONFIG_IS_ENABLED(OF_PLATDATA_INST)) {
+		for (id = 0; id < UCLASS_COUNT; id++) {
+			struct uclass *uc;
+
+			/*
+			 * If the uclass doesn't exist we don't want to create
+			 * it. So check that here before we call
+			 * uclass_find_device().
+			 */
+			uc = uclass_find(id);
+			if (!uc)
+				continue;
+			ut_assertok(uclass_destroy(uc));
+		}
 	}
 
 	return 0;

+ 1 - 0
tools/binman/README.rst

@@ -0,0 +1 @@
+binman.rst

Datei-Diff unterdrückt, da er zu groß ist
+ 515 - 268
tools/binman/binman.rst


+ 4 - 1
tools/binman/cmdline.py

@@ -56,6 +56,9 @@ controlled by a description in the board device tree.'''
         default=False, help='Output a map file for each image')
     build_parser.add_argument('-M', '--allow-missing', action='store_true',
         default=False, help='Allow external blobs to be missing')
+    build_parser.add_argument('-n', '--no-expanded', action='store_true',
+            help="Don't use 'expanded' versions of entries where available; "
+                 "normally 'u-boot' becomes 'u-boot-expanded', for example")
     build_parser.add_argument('-O', '--outdir', type=str,
         action='store', help='Path to directory to use for intermediate and '
         'output files')
@@ -66,7 +69,7 @@ controlled by a description in the board device tree.'''
         default=False, help='Update the binman node with offset/size info')
 
     entry_parser = subparsers.add_parser('entry-docs',
-        help='Write out entry documentation (see README.entries)')
+        help='Write out entry documentation (see entries.rst)')
 
     list_parser = subparsers.add_parser('ls', help='List files in an image')
     list_parser.add_argument('-i', '--image', type=str, required=True,

+ 20 - 8
tools/binman/control.py

@@ -28,7 +28,7 @@ images = OrderedDict()
 #    value: Text for the help
 missing_blob_help = {}
 
-def _ReadImageDesc(binman_node):
+def _ReadImageDesc(binman_node, use_expanded):
     """Read the image descriptions from the /binman node
 
     This normally produces a single Image object called 'image'. But if
@@ -36,15 +36,17 @@ def _ReadImageDesc(binman_node):
 
     Args:
         binman_node: Node object of the /binman node
+        use_expanded: True if the FDT will be updated with the entry information
     Returns:
         OrderedDict of Image objects, each of which describes an image
     """
     images = OrderedDict()
     if 'multiple-images' in binman_node.props:
         for node in binman_node.subnodes:
-            images[node.name] = Image(node.name, node)
+            images[node.name] = Image(node.name, node,
+                                      use_expanded=use_expanded)
     else:
-        images['image'] = Image('image', binman_node)
+        images['image'] = Image('image', binman_node, use_expanded=use_expanded)
     return images
 
 def _FindBinmanNode(dtb):
@@ -241,7 +243,7 @@ def ExtractEntries(image_fname, output_fname, outdir, entry_paths,
         # If this entry has children, create a directory for it and put its
         # data in a file called 'root' in that directory
         if entry.GetEntries():
-            if not os.path.exists(fname):
+            if fname and not os.path.exists(fname):
                 os.makedirs(fname)
             fname = os.path.join(fname, 'root')
         tout.Notice("Write entry '%s' size %x to '%s'" %
@@ -399,7 +401,7 @@ def ReplaceEntries(image_fname, input_fname, indir, entry_paths,
     return image
 
 
-def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
+def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt, use_expanded):
     """Prepare the images to be processed and select the device tree
 
     This function:
@@ -413,6 +415,9 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
         dtb_fname: Filename of the device tree file to use (.dts or .dtb)
         selected_images: List of images to output, or None for all
         update_fdt: True to update the FDT wth entry offsets, etc.
+        use_expanded: True to use expanded versions of entries, if available.
+            So if 'u-boot' is called for, we use 'u-boot-expanded' instead. This
+            is needed if update_fdt is True (although tests may disable it)
 
     Returns:
         OrderedDict of images:
@@ -438,7 +443,7 @@ def PrepareImagesAndDtbs(dtb_fname, select_images, update_fdt):
         raise ValueError("Device tree '%s' does not have a 'binman' "
                             "node" % dtb_fname)
 
-    images = _ReadImageDesc(node)
+    images = _ReadImageDesc(node, use_expanded)
 
     if select_images:
         skip = []
@@ -564,7 +569,7 @@ def Binman(args):
         if not pager:
             pager = 'more'
         fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])),
-                            'README')
+                            'README.rst')
         command.Run(pager, fname)
         return 0
 
@@ -611,6 +616,13 @@ def Binman(args):
         elf.debug = args.debug
         cbfs_util.VERBOSE = args.verbosity > 2
         state.use_fake_dtb = args.fake_dtb
+
+        # Normally we replace the 'u-boot' etype with 'u-boot-expanded', etc.
+        # When running tests this can be disabled using this flag. When not
+        # updating the FDT in image, it is not needed by binman, but we use it
+        # for consistency, so that the images look the same to U-Boot at
+        # runtime.
+        use_expanded = not args.no_expanded
         try:
             tools.SetInputDirs(args.indir)
             tools.PrepareOutputDir(args.outdir, args.preserve)
@@ -618,7 +630,7 @@ def Binman(args):
             state.SetEntryArgs(args.entry_arg)
 
             images = PrepareImagesAndDtbs(dtb_fname, args.image,
-                                          args.update_fdt)
+                                          args.update_fdt, use_expanded)
             missing = False
             for image in images.values():
                 missing |= ProcessImage(image, args.update_fdt, args.map,

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.