瀏覽代碼

Merge tag 'pull-14nov18' of git://git.denx.de/u-boot-dm

- virtio implementation and supporting patches
- DM_FLAG_PRE_RELOC fixes
- regmap improvements
- minor buildman and sandbox things
Tom Rini 5 年之前
父節點
當前提交
1d6edcbfed
共有 100 個文件被更改,包括 2134 次插入166 次删除
  1. 19 0
      Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt
  2. 19 0
      Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt
  3. 16 0
      Documentation/devicetree/bindings/misc/gdsys,soc.txt
  4. 6 0
      arch/Kconfig
  5. 1 0
      arch/arm/Kconfig
  6. 0 1
      arch/arm/mach-stm32mp/bsec.c
  7. 22 0
      arch/mips/include/asm/io.h
  8. 10 1
      arch/riscv/lib/bootm.c
  9. 6 1
      arch/sandbox/cpu/os.c
  10. 16 1
      arch/sandbox/dts/test.dts
  11. 1 0
      arch/x86/cpu/baytrail/cpu.c
  12. 1 0
      arch/x86/cpu/broadwell/cpu.c
  13. 1 0
      arch/x86/cpu/cpu_x86.c
  14. 1 0
      arch/x86/cpu/ivybridge/model_206ax.c
  15. 0 1
      arch/x86/cpu/tangier/sysreset.c
  16. 66 0
      arch/x86/include/asm/io.h
  17. 13 0
      board/emulation/qemu-arm/Kconfig
  18. 10 0
      board/emulation/qemu-arm/qemu-arm.c
  19. 11 0
      board/emulation/qemu-riscv/Kconfig
  20. 9 0
      board/emulation/qemu-riscv/qemu-riscv.c
  21. 3 0
      board/emulation/qemu-x86/Kconfig
  22. 7 0
      cmd/Kconfig
  23. 1 0
      cmd/Makefile
  24. 0 9
      cmd/sata.c
  25. 38 0
      cmd/virtio.c
  26. 28 0
      common/board_f.c
  27. 1 3
      common/usb_storage.c
  28. 0 1
      configs/imx8qxp_mek_defconfig
  29. 0 1
      configs/qemu_arm64_defconfig
  30. 0 1
      configs/qemu_arm_defconfig
  31. 1 0
      configs/sandbox_noblk_defconfig
  32. 6 0
      disk/part.c
  33. 253 0
      doc/README.virtio
  34. 12 4
      doc/driver-model/README.txt
  35. 2 0
      drivers/Kconfig
  36. 1 0
      drivers/Makefile
  37. 15 10
      drivers/block/blk-uclass.c
  38. 0 2
      drivers/block/ide.c
  39. 9 8
      drivers/block/sandbox.c
  40. 0 1
      drivers/clk/altera/clk-arria10.c
  41. 0 1
      drivers/clk/clk_pic32.c
  42. 0 1
      drivers/clk/clk_zynq.c
  43. 0 3
      drivers/clk/exynos/clk-exynos7420.c
  44. 0 1
      drivers/clk/owl/clk_s900.c
  45. 1 1
      drivers/core/device.c
  46. 1 1
      drivers/core/dump.c
  47. 8 1
      drivers/core/lists.c
  48. 3 1
      drivers/core/ofnode.c
  49. 296 20
      drivers/core/regmap.c
  50. 13 7
      drivers/core/root.c
  51. 21 10
      drivers/core/uclass.c
  52. 25 0
      drivers/core/util.c
  53. 1 1
      drivers/cpu/mpc83xx_cpu.c
  54. 2 0
      drivers/gpio/omap_gpio.c
  55. 1 1
      drivers/gpio/stm32f7_gpio.c
  56. 0 1
      drivers/gpio/tegra186_gpio.c
  57. 0 1
      drivers/gpio/tegra_gpio.c
  58. 2 0
      drivers/i2c/omap24xx_i2c.c
  59. 17 0
      drivers/misc/Kconfig
  60. 33 30
      drivers/misc/Makefile
  61. 74 0
      drivers/misc/gdsys_soc.c
  62. 23 0
      drivers/misc/gdsys_soc.h
  63. 867 0
      drivers/misc/ihs_fpga.c
  64. 49 0
      drivers/misc/ihs_fpga.h
  65. 2 2
      drivers/misc/imx8/scu.c
  66. 9 0
      drivers/misc/swap_case.c
  67. 0 3
      drivers/mmc/mmc.c
  68. 2 0
      drivers/mmc/omap_hsmmc.c
  69. 0 1
      drivers/nvme/nvme.c
  70. 36 15
      drivers/pci/pci-uclass.c
  71. 2 0
      drivers/pinctrl/broadcom/pinctrl-bcm283x.c
  72. 0 1
      drivers/pinctrl/exynos/pinctrl-exynos7420.c
  73. 2 0
      drivers/pinctrl/nxp/pinctrl-imx5.c
  74. 2 0
      drivers/pinctrl/nxp/pinctrl-imx6.c
  75. 2 0
      drivers/pinctrl/nxp/pinctrl-imx7.c
  76. 2 0
      drivers/pinctrl/nxp/pinctrl-imx7ulp.c
  77. 0 1
      drivers/pinctrl/pinctrl-single.c
  78. 2 0
      drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
  79. 2 0
      drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
  80. 0 1
      drivers/ram/bmips_ram.c
  81. 0 1
      drivers/scsi/scsi.c
  82. 0 1
      drivers/serial/altera_jtag_uart.c
  83. 0 1
      drivers/serial/altera_uart.c
  84. 0 1
      drivers/serial/arm_dcc.c
  85. 2 0
      drivers/serial/atmel_usart.c
  86. 18 2
      drivers/serial/ns16550.c
  87. 1 1
      drivers/serial/serial-uclass.c
  88. 0 1
      drivers/serial/serial_ar933x.c
  89. 0 1
      drivers/serial/serial_arc.c
  90. 2 0
      drivers/serial/serial_bcm283x_mu.c
  91. 2 0
      drivers/serial/serial_bcm283x_pl011.c
  92. 0 1
      drivers/serial/serial_bcm6345.c
  93. 0 1
      drivers/serial/serial_efi.c
  94. 0 1
      drivers/serial/serial_intel_mid.c
  95. 0 1
      drivers/serial/serial_lpuart.c
  96. 0 1
      drivers/serial/serial_meson.c
  97. 0 1
      drivers/serial/serial_mvebu_a3700.c
  98. 2 0
      drivers/serial/serial_mxc.c
  99. 2 0
      drivers/serial/serial_omap.c
  100. 0 1
      drivers/serial/serial_owl.c

+ 19 - 0
Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt

@@ -0,0 +1,19 @@
+gdsys IHS FPGA for CON devices
+
+The gdsys IHS FPGA is the main FPGA on gdsys CON devices. This driver provides
+support for enabling and starting the FPGA, as well as verifying working bus
+communication.
+
+Required properties:
+- compatible: must be "gdsys,iocon_fpga"
+- reset-gpios: List of GPIOs controlling the FPGA's reset
+- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
+              done
+
+Example:
+
+FPGA0 {
+	compatible = "gdsys,iocon_fpga";
+	reset-gpios = <&PPCPCA 26 0>;
+	done-gpios = <&GPIO_VB0 19 0>;
+};

+ 19 - 0
Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt

@@ -0,0 +1,19 @@
+gdsys IHS FPGA for CPU devices
+
+The gdsys IHS FPGA is the main FPGA on gdsys CPU devices. This driver provides
+support for enabling and starting the FPGA, as well as verifying working bus
+communication.
+
+Required properties:
+- compatible: must be "gdsys,iocpu_fpga"
+- reset-gpios: List of GPIOs controlling the FPGA's reset
+- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
+              done
+
+Example:
+
+FPGA0 {
+	compatible = "gdsys,iocpu_fpga";
+	reset-gpios = <&PPCPCA 26 0>;
+	done-gpios = <&GPIO_VB0 19 0>;
+};

+ 16 - 0
Documentation/devicetree/bindings/misc/gdsys,soc.txt

@@ -0,0 +1,16 @@
+gdsys soc bus driver
+
+This driver provides a simple interface for the busses associated with gdsys
+IHS FPGAs. The bus itself contains devices whose register maps are contained
+within the FPGA's register space.
+
+Required properties:
+- fpga: A phandle to the controlling IHS FPGA
+
+Example:
+
+FPGA0BUS: fpga0bus {
+	compatible = "gdsys,soc";
+	ranges = <0x0 0xe0600000 0x00004000>;
+	fpga = <&FPGA0>;
+};

+ 6 - 0
arch/Kconfig

@@ -110,6 +110,11 @@ config SANDBOX
 	imply LIBAVB
 	imply CMD_AVB
 	imply UDP_FUNCTION_FASTBOOT
+	imply VIRTIO_MMIO
+	imply VIRTIO_PCI
+	imply VIRTIO_SANDBOX
+	imply VIRTIO_BLK
+	imply VIRTIO_NET
 
 config SH
 	bool "SuperH architecture"
@@ -120,6 +125,7 @@ config X86
 	select CREATE_ARCH_SYMLINK
 	select DM
 	select DM_PCI
+	select HAVE_ARCH_IOMAP
 	select HAVE_PRIVATE_LIBGCC
 	select OF_CONTROL
 	select PCI

+ 1 - 0
arch/arm/Kconfig

@@ -1496,6 +1496,7 @@ source "board/broadcom/bcmns2/Kconfig"
 source "board/cavium/thunderx/Kconfig"
 source "board/cirrus/edb93xx/Kconfig"
 source "board/eets/pdu001/Kconfig"
+source "board/emulation/qemu-arm/Kconfig"
 source "board/freescale/ls2080a/Kconfig"
 source "board/freescale/ls2080aqds/Kconfig"
 source "board/freescale/ls2080ardb/Kconfig"

+ 0 - 1
arch/arm/mach-stm32mp/bsec.c

@@ -417,7 +417,6 @@ U_BOOT_DRIVER(stm32mp_bsec) = {
 	.ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata),
 	.ops = &stm32mp_bsec_ops,
-	.flags  = DM_FLAG_PRE_RELOC,
 };
 
 /* bsec IP is not present in device tee, manage IP address by platdata */

+ 22 - 0
arch/mips/include/asm/io.h

@@ -547,6 +547,28 @@ __BUILD_CLRSETBITS(bwlq, sfx, end, type)
 #define __to_cpu(v)		(v)
 #define cpu_to__(v)		(v)
 
+#define out_arch(type, endian, a, v)	__raw_write##type(cpu_to_##endian(v),a)
+#define in_arch(type, endian, a)	endian##_to_cpu(__raw_read##type(a))
+
+#define out_le64(a, v)	out_arch(q, le64, a, v)
+#define out_le32(a, v)	out_arch(l, le32, a, v)
+#define out_le16(a, v)	out_arch(w, le16, a, v)
+
+#define in_le64(a)	in_arch(q, le64, a)
+#define in_le32(a)	in_arch(l, le32, a)
+#define in_le16(a)	in_arch(w, le16, a)
+
+#define out_be64(a, v)	out_arch(q, be64, a, v)
+#define out_be32(a, v)	out_arch(l, be32, a, v)
+#define out_be16(a, v)	out_arch(w, be16, a, v)
+
+#define in_be64(a)	in_arch(q, be64, a)
+#define in_be32(a)	in_arch(l, be32, a)
+#define in_be16(a)	in_arch(w, be16, a)
+
+#define out_8(a, v)	__raw_writeb(v, a)
+#define in_8(a)		__raw_readb(a)
+
 BUILD_CLRSETBITS(b, 8, _, u8)
 BUILD_CLRSETBITS(w, le16, le16, u16)
 BUILD_CLRSETBITS(w, be16, be16, u16)

+ 10 - 1
arch/riscv/lib/bootm.c

@@ -9,9 +9,11 @@
 #include <common.h>
 #include <command.h>
 #include <image.h>
-#include <u-boot/zlib.h>
 #include <asm/byteorder.h>
 #include <asm/csr.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <u-boot/zlib.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -57,6 +59,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
 	/* we assume that the kernel is in place */
 	printf("\nStarting kernel ...\n\n");
 
+	/*
+	 * Call remove function of all devices with a removal flag set.
+	 * This may be useful for last-stage operations, like cancelling
+	 * of DMA operation or releasing device internal buffers.
+	 */
+	dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+
 	cleanup_before_linux();
 
 	if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)

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

@@ -174,7 +174,12 @@ void *os_malloc(size_t length)
 	struct os_mem_hdr *hdr;
 	int page_size = getpagesize();
 
-	hdr = mmap(NULL, length + page_size,
+	/*
+	 * Use an address that is hopefully available to us so that pointers
+	 * to this memory are fairly obvious. If we end up with a different
+	 * address, that's fine too.
+	 */
+	hdr = mmap((void *)0x10000000, length + page_size,
 		   PROT_READ | PROT_WRITE | PROT_EXEC,
 		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 	if (hdr == MAP_FAILED)

+ 16 - 1
arch/sandbox/dts/test.dts

@@ -186,6 +186,10 @@
 		compatible = "denx,u-boot-fdt-test";
 	};
 
+	h-test {
+		compatible = "denx,u-boot-fdt-test1";
+	};
+
 	clocks {
 		clk_fixed: clk-fixed {
 			compatible = "fixed-clock";
@@ -346,14 +350,17 @@
 
 	cpu-test1 {
 		compatible = "sandbox,cpu_sandbox";
+		u-boot,dm-pre-reloc;
 	};
 
 	cpu-test2 {
 		compatible = "sandbox,cpu_sandbox";
+		u-boot,dm-pre-reloc;
 	};
 
 	cpu-test3 {
 		compatible = "sandbox,cpu_sandbox";
+		u-boot,dm-pre-reloc;
 	};
 
 	misc-test {
@@ -525,7 +532,7 @@
 
 	syscon@0 {
 		compatible = "sandbox,syscon0";
-		reg = <0x10 4>;
+		reg = <0x10 16>;
 	};
 
 	syscon@1 {
@@ -712,6 +719,14 @@
 	sandbox_tee {
 		compatible = "sandbox,tee";
 	};
+
+	sandbox_virtio1 {
+		compatible = "sandbox,virtio1";
+	};
+
+	sandbox_virtio2 {
+		compatible = "sandbox,virtio2";
+	};
 };
 
 #include "sandbox_pmic.dtsi"

+ 1 - 0
arch/x86/cpu/baytrail/cpu.c

@@ -203,4 +203,5 @@ U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
 	.bind		= cpu_x86_bind,
 	.probe		= cpu_x86_baytrail_probe,
 	.ops		= &cpu_x86_baytrail_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
 };

+ 1 - 0
arch/x86/cpu/broadwell/cpu.c

@@ -764,4 +764,5 @@ U_BOOT_DRIVER(cpu_x86_broadwell_drv) = {
 	.probe		= cpu_x86_broadwell_probe,
 	.ops		= &cpu_x86_broadwell_ops,
 	.priv_auto_alloc_size	= sizeof(struct cpu_broadwell_priv),
+	.flags		= DM_FLAG_PRE_RELOC,
 };

+ 1 - 0
arch/x86/cpu/cpu_x86.c

@@ -94,4 +94,5 @@ U_BOOT_DRIVER(cpu_x86_drv) = {
 	.of_match	= cpu_x86_ids,
 	.bind		= cpu_x86_bind,
 	.ops		= &cpu_x86_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
 };

+ 1 - 0
arch/x86/cpu/ivybridge/model_206ax.c

@@ -478,4 +478,5 @@ U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = {
 	.bind		= cpu_x86_bind,
 	.probe		= cpu_x86_model_206ax_probe,
 	.ops		= &cpu_x86_model_206ax_ops,
+	.flags		= DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
arch/x86/cpu/tangier/sysreset.c

@@ -44,5 +44,4 @@ U_BOOT_DRIVER(tangier_sysreset) = {
 	.id = UCLASS_SYSRESET,
 	.of_match = tangier_sysreset_ids,
 	.ops = &tangier_sysreset_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 66 - 0
arch/x86/include/asm/io.h

@@ -241,6 +241,72 @@ static inline void sync(void)
 #define __iormb()	dmb()
 #define __iowmb()	dmb()
 
+/*
+ * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
+ * access or a MMIO access, these functions don't care. The info is
+ * encoded in the hardware mapping set up by the mapping functions
+ * (or the cookie itself, depending on implementation and hw).
+ *
+ * The generic routines don't assume any hardware mappings, and just
+ * encode the PIO/MMIO as part of the cookie. They coldly assume that
+ * the MMIO IO mappings are not in the low address range.
+ *
+ * Architectures for which this is not true can't use this generic
+ * implementation and should do their own copy.
+ */
+
+/*
+ * We assume that all the low physical PIO addresses (0-0xffff) always
+ * PIO. That means we can do some sanity checks on the low bits, and
+ * don't need to just take things for granted.
+ */
+#define PIO_RESERVED	0x10000UL
+
+/*
+ * Ugly macros are a way of life.
+ */
+#define IO_COND(addr, is_pio, is_mmio) do {			\
+	unsigned long port = (unsigned long __force)addr;	\
+	if (port >= PIO_RESERVED) {				\
+		is_mmio;					\
+	} else {						\
+		is_pio;						\
+	}							\
+} while (0)
+
+static inline u8 ioread8(const volatile void __iomem *addr)
+{
+	IO_COND(addr, return inb(port), return readb(addr));
+	return 0xff;
+}
+
+static inline u16 ioread16(const volatile void __iomem *addr)
+{
+	IO_COND(addr, return inw(port), return readw(addr));
+	return 0xffff;
+}
+
+static inline u32 ioread32(const volatile void __iomem *addr)
+{
+	IO_COND(addr, return inl(port), return readl(addr));
+	return 0xffffffff;
+}
+
+static inline void iowrite8(u8 value, volatile void __iomem *addr)
+{
+	IO_COND(addr, outb(value, port), writeb(value, addr));
+}
+
+static inline void iowrite16(u16 value, volatile void __iomem *addr)
+{
+	IO_COND(addr, outw(value, port), writew(value, addr));
+}
+
+static inline void iowrite32(u32 value, volatile void __iomem *addr)
+{
+	IO_COND(addr, outl(value, port), writel(value, addr));
+}
+
 #include <asm-generic/io.h>
 
 #endif /* _ASM_IO_H */

+ 13 - 0
board/emulation/qemu-arm/Kconfig

@@ -0,0 +1,13 @@
+if TARGET_QEMU_ARM_32BIT || TARGET_QEMU_ARM_64BIT
+
+config SYS_TEXT_BASE
+	default 0x00000000
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	imply VIRTIO_MMIO
+	imply VIRTIO_PCI
+	imply VIRTIO_NET
+	imply VIRTIO_BLK
+
+endif

+ 10 - 0
board/emulation/qemu-arm/qemu-arm.c

@@ -2,8 +2,12 @@
 /*
  * Copyright (c) 2017 Tuomas Tynkkynen
  */
+
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
+#include <virtio_types.h>
+#include <virtio.h>
 
 #ifdef CONFIG_ARM64
 #include <asm/armv8/mmu.h>
@@ -58,6 +62,12 @@ struct mm_region *mem_map = qemu_arm64_mem_map;
 
 int board_init(void)
 {
+	/*
+	 * Make sure virtio bus is enumerated so that peripherals
+	 * on the virtio bus can be discovered by their drivers
+	 */
+	virtio_init();
+
 	return 0;
 }
 

+ 11 - 0
board/emulation/qemu-riscv/Kconfig

@@ -18,5 +18,16 @@ config SYS_TEXT_BASE
 config BOARD_SPECIFIC_OPTIONS # dummy
 	def_bool y
 	imply SYS_NS16550
+	imply VIRTIO_MMIO
+	imply VIRTIO_NET
+	imply VIRTIO_BLK
+	imply CMD_PING
+	imply CMD_FS_GENERIC
+	imply DOS_PARTITION
+	imply EFI_PARTITION
+	imply ISO_PARTITION
+	imply CMD_EXT2
+	imply CMD_EXT4
+	imply CMD_FAT
 
 endif

+ 9 - 0
board/emulation/qemu-riscv/qemu-riscv.c

@@ -4,12 +4,21 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <fdtdec.h>
+#include <virtio_types.h>
+#include <virtio.h>
 
 #define MROM_FDT_ADDR	0x1020
 
 int board_init(void)
 {
+	/*
+	 * Make sure virtio bus is enumerated so that peripherals
+	 * on the virtio bus can be discovered by their drivers
+	 */
+	virtio_init();
+
 	return 0;
 }
 

+ 3 - 0
board/emulation/qemu-x86/Kconfig

@@ -21,5 +21,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	select X86_RESET_VECTOR
 	select QEMU
 	select BOARD_ROMSIZE_KB_1024
+	imply VIRTIO_PCI
+	imply VIRTIO_NET
+	imply VIRTIO_BLK
 
 endif

+ 7 - 0
cmd/Kconfig

@@ -1065,6 +1065,13 @@ config CMD_USB_MASS_STORAGE
 	help
 	  USB mass storage support
 
+config CMD_VIRTIO
+	bool "virtio"
+	depends on VIRTIO
+	default y if VIRTIO
+	help
+	  VirtIO block device support
+
 config CMD_AXI
 	bool "axi"
 	depends on AXI

+ 1 - 0
cmd/Makefile

@@ -135,6 +135,7 @@ obj-$(CONFIG_CMD_UBI) += ubi.o
 obj-$(CONFIG_CMD_UBIFS) += ubifs.o
 obj-$(CONFIG_CMD_UNIVERSE) += universe.o
 obj-$(CONFIG_CMD_UNZIP) += unzip.o
+obj-$(CONFIG_CMD_VIRTIO) += virtio.o
 obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o
 
 obj-$(CONFIG_CMD_USB) += usb.o disk.o

+ 0 - 9
cmd/sata.c

@@ -51,7 +51,6 @@ int sata_probe(int devnum)
 {
 #ifdef CONFIG_AHCI
 	struct udevice *dev;
-	struct udevice *blk;
 	int rc;
 
 	rc = uclass_get_device(UCLASS_AHCI, devnum, &dev);
@@ -67,14 +66,6 @@ int sata_probe(int devnum)
 		return CMD_RET_FAILURE;
 	}
 
-	rc = blk_get_from_parent(dev, &blk);
-	if (!rc) {
-		struct blk_desc *desc = dev_get_uclass_platdata(blk);
-
-		if (desc->lba > 0 && desc->blksz > 0)
-			part_init(desc);
-	}
-
 	return 0;
 #else
 	return sata_initialize() < 0 ? CMD_RET_FAILURE : CMD_RET_SUCCESS;

+ 38 - 0
cmd/virtio.c

@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm.h>
+#include <virtio_types.h>
+#include <virtio.h>
+
+static int virtio_curr_dev;
+
+static int do_virtio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	if (argc == 2 && !strcmp(argv[1], "scan")) {
+		/* make sure all virtio devices are enumerated */
+		virtio_init();
+
+		return CMD_RET_SUCCESS;
+	}
+
+	return blk_common_cmd(argc, argv, IF_TYPE_VIRTIO, &virtio_curr_dev);
+}
+
+U_BOOT_CMD(
+	virtio, 8, 1, do_virtio,
+	"virtio block devices sub-system",
+	"scan - initialize virtio bus\n"
+	"virtio info - show all available virtio block devices\n"
+	"virtio device [dev] - show or set current virtio block device\n"
+	"virtio part [dev] - print partition table of one or all virtio block devices\n"
+	"virtio read addr blk# cnt - read `cnt' blocks starting at block\n"
+	"     `blk#' to memory address `addr'\n"
+	"virtio write addr blk# cnt - write `cnt' blocks starting at block\n"
+	"     `blk#' from memory address `addr'"
+);

+ 28 - 0
common/board_f.c

@@ -11,6 +11,7 @@
 
 #include <common.h>
 #include <console.h>
+#include <cpu.h>
 #include <dm.h>
 #include <environment.h>
 #include <fdtdec.h>
@@ -165,6 +166,33 @@ static int print_resetinfo(void)
 }
 #endif
 
+#if defined(CONFIG_DISPLAY_CPUINFO) && CONFIG_IS_ENABLED(CPU)
+static int print_cpuinfo(void)
+{
+	struct udevice *dev;
+	char desc[512];
+	int ret;
+
+	ret = uclass_first_device_err(UCLASS_CPU, &dev);
+	if (ret) {
+		debug("%s: Could not get CPU device (err = %d)\n",
+		      __func__, ret);
+		return ret;
+	}
+
+	ret = cpu_get_desc(dev, desc, sizeof(desc));
+	if (ret) {
+		debug("%s: Could not get CPU description (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	printf("CPU:   %s\n", desc);
+
+	return 0;
+}
+#endif
+
 static int announce_dram_init(void)
 {
 	puts("DRAM:  ");

+ 1 - 3
common/usb_storage.c

@@ -226,9 +226,7 @@ static int usb_stor_probe_device(struct usb_device *udev)
 		blkdev->lun = lun;
 
 		ret = usb_stor_get_info(udev, data, blkdev);
-		if (ret == 1)
-			ret = blk_prepare_device(dev);
-		if (!ret) {
+		if (ret == 1) {
 			usb_max_devs++;
 			debug("%s: Found device %p\n", __func__, udev);
 		} else {

+ 0 - 1
configs/imx8qxp_mek_defconfig

@@ -6,7 +6,6 @@ CONFIG_TARGET_IMX8QXP_MEK=y
 CONFIG_NR_DRAM_BANKS=3
 CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/imx8qxp_mek/imximage.cfg"
 CONFIG_BOOTDELAY=3
-# CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_CMD_CPU=y
 # CONFIG_CMD_IMPORTENV is not set
 CONFIG_CMD_CLK=y

+ 0 - 1
configs/qemu_arm64_defconfig

@@ -1,7 +1,6 @@
 CONFIG_ARM=y
 CONFIG_ARM_SMCCC=y
 CONFIG_ARCH_QEMU=y
-CONFIG_SYS_TEXT_BASE=0x00000000
 CONFIG_TARGET_QEMU_ARM_64BIT=y
 CONFIG_AHCI=y
 CONFIG_DISTRO_DEFAULTS=y

+ 0 - 1
configs/qemu_arm_defconfig

@@ -1,7 +1,6 @@
 CONFIG_ARM=y
 CONFIG_ARM_SMCCC=y
 CONFIG_ARCH_QEMU=y
-CONFIG_SYS_TEXT_BASE=0x00000000
 CONFIG_TARGET_QEMU_ARM_32BIT=y
 CONFIG_AHCI=y
 CONFIG_DISTRO_DEFAULTS=y

+ 1 - 0
configs/sandbox_noblk_defconfig

@@ -171,6 +171,7 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
 CONFIG_VIDEO_SANDBOX_SDL=y
 CONFIG_OSD=y
 CONFIG_SANDBOX_OSD=y
+# CONFIG_VIRTIO_BLK is not set
 CONFIG_FS_CBFS=y
 CONFIG_FS_CRAMFS=y
 CONFIG_CMD_DHRYSTONE=y

+ 6 - 0
disk/part.c

@@ -150,6 +150,9 @@ void dev_print (struct blk_desc *dev_desc)
 			dev_desc->revision,
 			dev_desc->product);
 		break;
+	case IF_TYPE_VIRTIO:
+		printf("%s VirtIO Block Device\n", dev_desc->vendor);
+		break;
 	case IF_TYPE_DOC:
 		puts("device type DOC\n");
 		return;
@@ -281,6 +284,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
 	case IF_TYPE_NVME:
 		puts ("NVMe");
 		break;
+	case IF_TYPE_VIRTIO:
+		puts("VirtIO");
+		break;
 	default:
 		puts ("UNKNOWN");
 		break;

+ 253 - 0
doc/README.virtio

@@ -0,0 +1,253 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+
+VirtIO Support
+==============
+
+This document describes the information about U-Boot support for VirtIO [1]
+devices, including supported boards, build instructions, driver details etc.
+
+What's VirtIO?
+--------------
+VirtIO is a virtualization standard for network and disk device drivers where
+just the guest's device driver "knows" it is running in a virtual environment,
+and cooperates with the hypervisor. This enables guests to get high performance
+network and disk operations, and gives most of the performance benefits of
+paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the
+virtual environment are normally QEMU [2] targets like ARM, RISC-V and x86.
+
+Status
+------
+VirtIO can use various different buses, aka transports as described in the
+spec. While VirtIO devices are commonly implemented as PCI devices on x86,
+embedded devices models like ARM/RISC-V, which does not normally come with
+PCI support might use simple memory mapped device (MMIO) instead of the PCI
+device. The memory mapped virtio device behaviour is based on the PCI device
+specification. Therefore most operations including device initialization,
+queues configuration and buffer transfers are nearly identical. Both MMIO
+and PCI transport options are supported in U-Boot.
+
+The VirtIO spec defines a lots of VirtIO device types, however at present only
+network and block device, the most two commonly used devices, are supported.
+
+The following QEMU targets are supported.
+
+  - qemu_arm_defconfig
+  - qemu_arm64_defconfig
+  - qemu-riscv32_defconfig
+  - qemu-riscv64_defconfig
+  - qemu-x86_defconfig
+  - qemu-x86_64_defconfig
+
+Note ARM and RISC-V targets are configured with VirtIO MMIO transport driver,
+and on x86 it's the PCI transport driver.
+
+Build Instructions
+------------------
+Building U-Boot for pre-configured QEMU targets is no different from others.
+For example, we can do the following with the CROSS_COMPILE environment
+variable being properly set to a working toolchain for ARM:
+
+  $ make qemu_arm_defconfig
+  $ make
+
+You can even create a QEMU ARM target with VirtIO devices showing up on both
+MMIO and PCI buses. In this case, you can enable the PCI transport driver
+from 'make menuconfig':
+
+Device Drivers  --->
+	...
+	VirtIO Drivers  --->
+		...
+		[*] PCI driver for virtio devices
+
+Other drivers are at the same location and can be tuned to suit the needs.
+
+Requirements
+------------
+It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support
+on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V.
+
+Testing
+-------
+The following QEMU command line is used to get U-Boot up and running with
+VirtIO net and block devices on ARM.
+
+  $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
+    -netdev tap,ifname=tap0,id=net0 \
+    -device virtio-net-device,netdev=net0 \
+    -drive if=none,file=test.img,format=raw,id=hd0 \
+    -device virtio-blk-device,drive=hd0
+
+On x86, command is slightly different to create PCI VirtIO devices.
+
+  $ qemu-system-i386 -nographic -bios u-boot.rom \
+    -netdev tap,ifname=tap0,id=net0 \
+    -device virtio-net-pci,netdev=net0 \
+    -drive if=none,file=test.img,format=raw,id=hd0 \
+    -device virtio-blk-pci,drive=hd0
+
+Additional net and block devices can be created by appending more '-device'
+parameters. It is also possible to specify both MMIO and PCI VirtIO devices.
+For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO
+and 2 on PCI bus.
+
+  $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
+    -netdev tap,ifname=tap0,id=net0 \
+    -device virtio-net-pci,netdev=net0 \
+    -drive if=none,file=test0.img,format=raw,id=hd0 \
+    -device virtio-blk-device,drive=hd0 \
+    -drive if=none,file=test1.img,format=raw,id=hd1 \
+    -device virtio-blk-pci,drive=hd1
+
+By default QEMU creates VirtIO legacy devices by default. To create non-legacy
+(aka modern) devices, pass additional device property/value pairs like below:
+
+  $ qemu-system-i386 -nographic -bios u-boot.rom \
+    -netdev tap,ifname=tap0,id=net0 \
+    -device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \
+    -drive if=none,file=test.img,format=raw,id=hd0 \
+    -device virtio-blk-pci,drive=hd0,disable-legacy=true,disable-modern=false
+
+A 'virtio' command is provided in U-Boot shell.
+
+  => virtio
+  virtio - virtio block devices sub-system
+
+  Usage:
+  virtio scan - initialize virtio bus
+  virtio info - show all available virtio block devices
+  virtio device [dev] - show or set current virtio block device
+  virtio part [dev] - print partition table of one or all virtio block devices
+  virtio read addr blk# cnt - read `cnt' blocks starting at block
+       `blk#' to memory address `addr'
+  virtio write addr blk# cnt - write `cnt' blocks starting at block
+       `blk#' from memory address `addr'
+
+To probe all the VirtIO devices, type:
+
+  => virtio scan
+
+Then we can show the connected block device details by:
+
+  => virtio info
+  Device 0: QEMU VirtIO Block Device
+              Type: Hard Disk
+              Capacity: 4096.0 MB = 4.0 GB (8388608 x 512)
+
+And list the directories and files on the disk by:
+
+  => ls virtio 0 /
+  <DIR>       4096 .
+  <DIR>       4096 ..
+  <DIR>      16384 lost+found
+  <DIR>       4096 dev
+  <DIR>       4096 proc
+  <DIR>       4096 sys
+  <DIR>       4096 var
+  <DIR>       4096 etc
+  <DIR>       4096 usr
+  <SYM>          7 bin
+  <SYM>          8 sbin
+  <SYM>          7 lib
+  <SYM>          9 lib64
+  <DIR>       4096 run
+  <DIR>       4096 boot
+  <DIR>       4096 home
+  <DIR>       4096 media
+  <DIR>       4096 mnt
+  <DIR>       4096 opt
+  <DIR>       4096 root
+  <DIR>       4096 srv
+  <DIR>       4096 tmp
+                 0 .autorelabel
+
+Driver Internals
+----------------
+There are 3 level of drivers in the VirtIO driver family.
+
+	+---------------------------------------+
+	|	 virtio device drivers		|
+	|    +-------------+ +------------+	|
+	|    | virtio-net  | | virtio-blk |	|
+	|    +-------------+ +------------+	|
+	+---------------------------------------+
+	+---------------------------------------+
+	|	virtio transport drivers	|
+	|    +-------------+ +------------+	|
+	|    | virtio-mmio | | virtio-pci |	|
+	|    +-------------+ +------------+	|
+	+---------------------------------------+
+		+----------------------+
+		| virtio uclass driver |
+		+----------------------+
+
+The root one is the virtio uclass driver (virtio-uclass.c), which does lots of
+common stuff for the transport drivers (virtio_mmio.c, virtio_pci.c). The real
+virtio device is discovered in the transport driver's probe() method, and its
+device ID is saved in the virtio uclass's private data of the transport device.
+Then in the virtio uclass's post_probe() method, the real virtio device driver
+(virtio_net.c, virtio_blk.c) is bound if there is a match on the device ID.
+
+The child_post_bind(), child_pre_probe() and child_post_probe() methods of the
+virtio uclass driver help bring the virtio device driver online. They do things
+like acknowledging device, feature negotiation, etc, which are really common
+for all virtio devices.
+
+The transport drivers provide a set of ops (struct dm_virtio_ops) for the real
+virtio device driver to call. These ops APIs's parameter is designed to remind
+the caller to pass the correct 'struct udevice' id of the virtio device, eg:
+
+int virtio_get_status(struct udevice *vdev, u8 *status)
+
+So the parameter 'vdev' indicates the device should be the real virtio device.
+But we also have an API like:
+
+struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
+					 unsigned int vring_align,
+					 struct udevice *udev)
+
+Here the parameter 'udev' indicates the device should be the transport device.
+Similar naming is applied in other functions that are even not APIs, eg:
+
+static int virtio_uclass_post_probe(struct udevice *udev)
+static int virtio_uclass_child_pre_probe(struct udevice *vdev)
+
+So it's easy to tell which device these functions are operating on.
+
+Development Flow
+----------------
+At present only VirtIO network card (device ID 1) and block device (device
+ID 2) are supported. If you want to develop new driver for new devices,
+please follow the guideline below.
+
+1. add new device ID in virtio.h
+#define VIRTIO_ID_XXX		X
+
+2. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1
+
+3. add new driver name string in virtio.h
+#define VIRTIO_XXX_DRV_NAME	"virtio-xxx"
+
+4. create a new driver with name set to the name string above
+U_BOOT_DRIVER(virtio_xxx) = {
+	.name = VIRTIO_XXX_DRV_NAME,
+	...
+	.remove = virtio_reset,
+	.flags = DM_FLAG_ACTIVE_DMA,
+}
+
+Note the driver needs to provide the remove method and normally this can be
+hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA
+for the remove method to be called before jumping to OS.
+
+5. provide bind() method in the driver, where virtio_driver_features_init()
+   should be called for driver to negotiate feature support with the device.
+
+6. do funny stuff with the driver
+
+References
+----------
+[1] http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
+[2] https://www.qemu.org

+ 12 - 4
doc/driver-model/README.txt

@@ -830,10 +830,18 @@ Pre-Relocation Support
 ----------------------
 
 For pre-relocation we simply call the driver model init function. Only
-drivers marked with DM_FLAG_PRE_RELOC or the device tree
-'u-boot,dm-pre-reloc' flag are initialised prior to relocation. This helps
-to reduce the driver model overhead. This flag applies to SPL and TPL as
-well, if device tree is enabled there.
+drivers marked with DM_FLAG_PRE_RELOC or the device tree 'u-boot,dm-pre-reloc'
+property are initialised prior to relocation. This helps to reduce the driver
+model overhead. This flag applies to SPL and TPL as well, if device tree is
+enabled (CONFIG_OF_CONTROL) there.
+
+Note when device tree is enabled, the device tree 'u-boot,dm-pre-reloc'
+property can provide better control granularity on which device is bound
+before relocation. While with DM_FLAG_PRE_RELOC flag of the driver all
+devices with the same driver are bound, which requires allocation a large
+amount of memory. When device tree is not used, DM_FLAG_PRE_RELOC is the
+only way for statically declared devices via U_BOOT_DEVICE() to be bound
+prior to relocation.
 
 It is possible to limit this to specific relocation steps, by using
 the more specialized 'u-boot,dm-spl' and 'u-boot,dm-tpl' flags

+ 2 - 0
drivers/Kconfig

@@ -112,6 +112,8 @@ source "drivers/usb/Kconfig"
 
 source "drivers/video/Kconfig"
 
+source "drivers/virtio/Kconfig"
+
 source "drivers/w1/Kconfig"
 
 source "drivers/w1-eeprom/Kconfig"

+ 1 - 0
drivers/Makefile

@@ -14,6 +14,7 @@ obj-$(CONFIG_$(SPL_TPL_)SERIAL_SUPPORT) += serial/
 obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += mtd/spi/
 obj-$(CONFIG_$(SPL_TPL_)SPI_SUPPORT) += spi/
 obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/
+obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
 obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
 obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
 

+ 15 - 10
drivers/block/blk-uclass.c

@@ -23,6 +23,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
 	[IF_TYPE_HOST]		= "host",
 	[IF_TYPE_NVME]		= "nvme",
 	[IF_TYPE_EFI]		= "efi",
+	[IF_TYPE_VIRTIO]	= "virtio",
 };
 
 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
@@ -37,6 +38,7 @@ static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
 	[IF_TYPE_HOST]		= UCLASS_ROOT,
 	[IF_TYPE_NVME]		= UCLASS_NVME,
 	[IF_TYPE_EFI]		= UCLASS_EFI,
+	[IF_TYPE_VIRTIO]	= UCLASS_VIRTIO,
 };
 
 static enum if_type if_typename_to_iftype(const char *if_typename)
@@ -471,15 +473,6 @@ unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
 	return ops->erase(dev, start, blkcnt);
 }
 
-int blk_prepare_device(struct udevice *dev)
-{
-	struct blk_desc *desc = dev_get_uclass_platdata(dev);
-
-	part_init(desc);
-
-	return 0;
-}
-
 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
 {
 	struct udevice *dev;
@@ -526,7 +519,7 @@ int blk_find_max_devnum(enum if_type if_type)
 	return max_devnum;
 }
 
-static int blk_next_free_devnum(enum if_type if_type)
+int blk_next_free_devnum(enum if_type if_type)
 {
 	int ret;
 
@@ -644,8 +637,20 @@ int blk_unbind_all(int if_type)
 	return 0;
 }
 
+static int blk_post_probe(struct udevice *dev)
+{
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
+	struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+	part_init(desc);
+#endif
+
+	return 0;
+}
+
 UCLASS_DRIVER(blk) = {
 	.id		= UCLASS_BLK,
 	.name		= "blk",
+	.post_probe	= blk_post_probe,
 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
 };

+ 0 - 2
drivers/block/ide.c

@@ -1169,8 +1169,6 @@ static int ide_blk_probe(struct udevice *udev)
 		BLK_REV_SIZE);
 	desc->revision[BLK_REV_SIZE] = '\0';
 
-	part_init(desc);
-
 	return 0;
 }
 

+ 9 - 8
drivers/block/sandbox.c

@@ -33,7 +33,7 @@ static unsigned long host_block_read(struct udevice *dev,
 				     unsigned long start, lbaint_t blkcnt,
 				     void *buffer)
 {
-	struct host_block_dev *host_dev = dev_get_priv(dev);
+	struct host_block_dev *host_dev = dev_get_platdata(dev);
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 
 #else
@@ -64,7 +64,7 @@ static unsigned long host_block_write(struct udevice *dev,
 				      unsigned long start, lbaint_t blkcnt,
 				      const void *buffer)
 {
-	struct host_block_dev *host_dev = dev_get_priv(dev);
+	struct host_block_dev *host_dev = dev_get_platdata(dev);
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 #else
 static unsigned long host_block_write(struct blk_desc *block_dev,
@@ -131,17 +131,18 @@ int host_dev_bind(int devnum, char *filename)
 				os_lseek(fd, 0, OS_SEEK_END) / 512, &dev);
 	if (ret)
 		goto err_file;
+
+	host_dev = dev_get_platdata(dev);
+	host_dev->fd = fd;
+	host_dev->filename = fname;
+
 	ret = device_probe(dev);
 	if (ret) {
 		device_unbind(dev);
 		goto err_file;
 	}
 
-	host_dev = dev_get_priv(dev);
-	host_dev->fd = fd;
-	host_dev->filename = fname;
-
-	return blk_prepare_device(dev);
+	return 0;
 err_file:
 	os_close(fd);
 err:
@@ -226,7 +227,7 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
 	.name		= "sandbox_host_blk",
 	.id		= UCLASS_BLK,
 	.ops		= &sandbox_host_blk_ops,
-	.priv_auto_alloc_size	= sizeof(struct host_block_dev),
+	.platdata_auto_alloc_size = sizeof(struct host_block_dev),
 };
 #else
 U_BOOT_LEGACY_BLK(sandbox_host) = {

+ 0 - 1
drivers/clk/altera/clk-arria10.c

@@ -352,7 +352,6 @@ static const struct udevice_id socfpga_a10_clk_match[] = {
 U_BOOT_DRIVER(socfpga_a10_clk) = {
 	.name		= "clk-a10",
 	.id		= UCLASS_CLK,
-	.flags		= DM_FLAG_PRE_RELOC,
 	.of_match	= socfpga_a10_clk_match,
 	.ops		= &socfpga_a10_clk_ops,
 	.bind		= socfpga_a10_clk_bind,

+ 0 - 1
drivers/clk/clk_pic32.c

@@ -418,7 +418,6 @@ U_BOOT_DRIVER(pic32_clk) = {
 	.name		= "pic32_clk",
 	.id		= UCLASS_CLK,
 	.of_match	= pic32_clk_ids,
-	.flags		= DM_FLAG_PRE_RELOC,
 	.ops		= &pic32_pic32_clk_ops,
 	.probe		= pic32_clk_probe,
 	.priv_auto_alloc_size = sizeof(struct pic32_clk_priv),

+ 0 - 1
drivers/clk/clk_zynq.c

@@ -480,7 +480,6 @@ U_BOOT_DRIVER(zynq_clk) = {
 	.name		= "zynq_clk",
 	.id		= UCLASS_CLK,
 	.of_match	= zynq_clk_ids,
-	.flags		= DM_FLAG_PRE_RELOC,
 	.ops		= &zynq_clk_ops,
 	.priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
 	.probe		= zynq_clk_probe,

+ 0 - 3
drivers/clk/exynos/clk-exynos7420.c

@@ -201,7 +201,6 @@ U_BOOT_DRIVER(exynos7420_clk_topc) = {
 	.probe = exynos7420_clk_topc_probe,
 	.priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
 	.ops = &exynos7420_clk_topc_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 static const struct udevice_id exynos7420_clk_top0_compat[] = {
@@ -216,7 +215,6 @@ U_BOOT_DRIVER(exynos7420_clk_top0) = {
 	.probe = exynos7420_clk_top0_probe,
 	.priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
 	.ops = &exynos7420_clk_top0_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 static const struct udevice_id exynos7420_clk_peric1_compat[] = {
@@ -229,5 +227,4 @@ U_BOOT_DRIVER(exynos7420_clk_peric1) = {
 	.id = UCLASS_CLK,
 	.of_match = exynos7420_clk_peric1_compat,
 	.ops = &exynos7420_clk_peric1_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/clk/owl/clk_s900.c

@@ -134,5 +134,4 @@ U_BOOT_DRIVER(clk_owl) = {
 	.ops		= &owl_clk_ops,
 	.priv_auto_alloc_size = sizeof(struct owl_clk_priv),
 	.probe		= owl_clk_probe,
-	.flags		= DM_FLAG_PRE_RELOC,
 };

+ 1 - 1
drivers/core/device.c

@@ -834,5 +834,5 @@ int dev_enable_by_path(const char *path)
 	if (ret)
 		return ret;
 
-	return lists_bind_fdt(parent, node, NULL);
+	return lists_bind_fdt(parent, node, NULL, false);
 }

+ 1 - 1
drivers/core/dump.c

@@ -89,7 +89,7 @@ void dm_dump_uclass(void)
 		printf("uclass %d: %s\n", id, uc->uc_drv->name);
 		if (list_empty(&uc->dev_head))
 			continue;
-		list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+		uclass_foreach_dev(dev, uc) {
 			dm_display_line(dev, i);
 			i++;
 		}

+ 8 - 1
drivers/core/lists.c

@@ -122,7 +122,8 @@ static int driver_check_compatible(const struct udevice_id *of_match,
 	return -ENOENT;
 }
 
-int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp)
+int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
+		   bool pre_reloc_only)
 {
 	struct driver *driver = ll_entry_start(struct driver, driver);
 	const int n_ents = ll_entry_count(struct driver, driver);
@@ -171,6 +172,12 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp)
 		if (entry == driver + n_ents)
 			continue;
 
+		if (pre_reloc_only) {
+			if (!dm_ofnode_pre_reloc(node) &&
+			    !(entry->flags & DM_FLAG_PRE_RELOC))
+				return 0;
+		}
+
 		pr_debug("   - found match at '%s'\n", entry->name);
 		ret = device_bind_with_driver_data(parent, entry, name,
 						   id->data, node, &dev);

+ 3 - 1
drivers/core/ofnode.c

@@ -831,8 +831,10 @@ int ofnode_write_prop(ofnode node, const char *propname, int len,
 		return -ENOMEM;
 
 	new->name = strdup(propname);
-	if (!new->name)
+	if (!new->name) {
+		free(new);
 		return -ENOMEM;
+	}
 
 	new->value = (void *)value;
 	new->length = len;

+ 296 - 20
drivers/core/regmap.c

@@ -17,6 +17,12 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/**
+ * regmap_alloc() - Allocate a regmap with a given number of ranges.
+ *
+ * @count: Number of ranges to be allocated for the regmap.
+ * Return: A pointer to the newly allocated regmap, or NULL on error.
+ */
 static struct regmap *regmap_alloc(int count)
 {
 	struct regmap *map;
@@ -50,6 +56,58 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
 	return 0;
 }
 #else
+/**
+ * init_range() - Initialize a single range of a regmap
+ * @node:     Device node that will use the map in question
+ * @range:    Pointer to a regmap_range structure that will be initialized
+ * @addr_len: The length of the addr parts of the reg property
+ * @size_len: The length of the size parts of the reg property
+ * @index:    The index of the range to initialize
+ *
+ * This function will read the necessary 'reg' information from the device tree
+ * (the 'addr' part, and the 'length' part), and initialize the range in
+ * quesion.
+ *
+ * Return: 0 if OK, -ve on error
+ */
+static int init_range(ofnode node, struct regmap_range *range, int addr_len,
+		      int size_len, int index)
+{
+	fdt_size_t sz;
+	struct resource r;
+
+	if (of_live_active()) {
+		int ret;
+
+		ret = of_address_to_resource(ofnode_to_np(node),
+					     index, &r);
+		if (ret) {
+			debug("%s: Could not read resource of range %d (ret = %d)\n",
+			      ofnode_get_name(node), index, ret);
+			return ret;
+		}
+
+		range->start = r.start;
+		range->size = r.end - r.start + 1;
+	} else {
+		int offset = ofnode_to_offset(node);
+
+		range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
+							  "reg", index,
+							  addr_len, size_len,
+							  &sz, true);
+		if (range->start == FDT_ADDR_T_NONE) {
+			debug("%s: Could not read start of range %d\n",
+			      ofnode_get_name(node), index);
+			return -EINVAL;
+		}
+
+		range->size = sz;
+	}
+
+	return 0;
+}
+
 int regmap_init_mem(ofnode node, struct regmap **mapp)
 {
 	struct regmap_range *range;
@@ -58,19 +116,41 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
 	int addr_len, size_len, both_len;
 	int len;
 	int index;
-	struct resource r;
 
 	addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
+	if (addr_len < 0) {
+		debug("%s: Error while reading the addr length (ret = %d)\n",
+		      ofnode_get_name(node), addr_len);
+		return addr_len;
+	}
+
 	size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
+	if (size_len < 0) {
+		debug("%s: Error while reading the size length: (ret = %d)\n",
+		      ofnode_get_name(node), size_len);
+		return size_len;
+	}
+
 	both_len = addr_len + size_len;
+	if (!both_len) {
+		debug("%s: Both addr and size length are zero\n",
+		      ofnode_get_name(node));
+		return -EINVAL;
+	}
 
 	len = ofnode_read_size(node, "reg");
-	if (len < 0)
+	if (len < 0) {
+		debug("%s: Error while reading reg size (ret = %d)\n",
+		      ofnode_get_name(node), len);
 		return len;
+	}
 	len /= sizeof(fdt32_t);
 	count = len / both_len;
-	if (!count)
+	if (!count) {
+		debug("%s: Not enough data in reg property\n",
+		      ofnode_get_name(node));
 		return -EINVAL;
+	}
 
 	map = regmap_alloc(count);
 	if (!map)
@@ -78,19 +158,21 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
 
 	for (range = map->ranges, index = 0; count > 0;
 	     count--, range++, index++) {
-		fdt_size_t sz;
-		if (of_live_active()) {
-			of_address_to_resource(ofnode_to_np(node), index, &r);
-			range->start = r.start;
-			range->size = r.end - r.start + 1;
-		} else {
-			range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
-					ofnode_to_offset(node), "reg", index,
-					addr_len, size_len, &sz, true);
-			range->size = sz;
-		}
+		int ret = init_range(node, range, addr_len, size_len, index);
+
+		if (ret)
+			return ret;
 	}
 
+	if (ofnode_read_bool(node, "little-endian"))
+		map->endianness = REGMAP_LITTLE_ENDIAN;
+	else if (ofnode_read_bool(node, "big-endian"))
+		map->endianness = REGMAP_BIG_ENDIAN;
+	else if (ofnode_read_bool(node, "native-endian"))
+		map->endianness = REGMAP_NATIVE_ENDIAN;
+	else /* Default: native endianness */
+		map->endianness = REGMAP_NATIVE_ENDIAN;
+
 	*mapp = map;
 
 	return 0;
@@ -115,24 +197,218 @@ int regmap_uninit(struct regmap *map)
 	return 0;
 }
 
-int regmap_read(struct regmap *map, uint offset, uint *valp)
+static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
 {
-	u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
+	return readb(addr);
+}
 
-	*valp = le32_to_cpu(readl(ptr));
+static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_LITTLE_ENDIAN:
+		return in_le16(addr);
+	case REGMAP_BIG_ENDIAN:
+		return in_be16(addr);
+	case REGMAP_NATIVE_ENDIAN:
+		return readw(addr);
+	}
+
+	return readw(addr);
+}
+
+static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_LITTLE_ENDIAN:
+		return in_le32(addr);
+	case REGMAP_BIG_ENDIAN:
+		return in_be32(addr);
+	case REGMAP_NATIVE_ENDIAN:
+		return readl(addr);
+	}
+
+	return readl(addr);
+}
+
+#if defined(in_le64) && defined(in_be64) && defined(readq)
+static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_LITTLE_ENDIAN:
+		return in_le64(addr);
+	case REGMAP_BIG_ENDIAN:
+		return in_be64(addr);
+	case REGMAP_NATIVE_ENDIAN:
+		return readq(addr);
+	}
+
+	return readq(addr);
+}
+#endif
+
+int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
+			  void *valp, size_t val_len)
+{
+	struct regmap_range *range;
+	void *ptr;
+
+	if (range_num >= map->range_count) {
+		debug("%s: range index %d larger than range count\n",
+		      __func__, range_num);
+		return -ERANGE;
+	}
+	range = &map->ranges[range_num];
+
+	ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
+	if (offset + val_len > range->size) {
+		debug("%s: offset/size combination invalid\n", __func__);
+		return -ERANGE;
+	}
+
+	switch (val_len) {
+	case REGMAP_SIZE_8:
+		*((u8 *)valp) = __read_8(ptr, map->endianness);
+		break;
+	case REGMAP_SIZE_16:
+		*((u16 *)valp) = __read_16(ptr, map->endianness);
+		break;
+	case REGMAP_SIZE_32:
+		*((u32 *)valp) = __read_32(ptr, map->endianness);
+		break;
+#if defined(in_le64) && defined(in_be64) && defined(readq)
+	case REGMAP_SIZE_64:
+		*((u64 *)valp) = __read_64(ptr, map->endianness);
+		break;
+#endif
+	default:
+		debug("%s: regmap size %zu unknown\n", __func__, val_len);
+		return -EINVAL;
+	}
 
 	return 0;
 }
 
-int regmap_write(struct regmap *map, uint offset, uint val)
+int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
 {
-	u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE);
+	return regmap_raw_read_range(map, 0, offset, valp, val_len);
+}
 
-	writel(cpu_to_le32(val), ptr);
+int regmap_read(struct regmap *map, uint offset, uint *valp)
+{
+	return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
+}
+
+static inline void __write_8(u8 *addr, const u8 *val,
+			     enum regmap_endianness_t endianness)
+{
+	writeb(*val, addr);
+}
+
+static inline void __write_16(u16 *addr, const u16 *val,
+			      enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_NATIVE_ENDIAN:
+		writew(*val, addr);
+		break;
+	case REGMAP_LITTLE_ENDIAN:
+		out_le16(addr, *val);
+		break;
+	case REGMAP_BIG_ENDIAN:
+		out_be16(addr, *val);
+		break;
+	}
+}
+
+static inline void __write_32(u32 *addr, const u32 *val,
+			      enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_NATIVE_ENDIAN:
+		writel(*val, addr);
+		break;
+	case REGMAP_LITTLE_ENDIAN:
+		out_le32(addr, *val);
+		break;
+	case REGMAP_BIG_ENDIAN:
+		out_be32(addr, *val);
+		break;
+	}
+}
+
+#if defined(out_le64) && defined(out_be64) && defined(writeq)
+static inline void __write_64(u64 *addr, const u64 *val,
+			      enum regmap_endianness_t endianness)
+{
+	switch (endianness) {
+	case REGMAP_NATIVE_ENDIAN:
+		writeq(*val, addr);
+		break;
+	case REGMAP_LITTLE_ENDIAN:
+		out_le64(addr, *val);
+		break;
+	case REGMAP_BIG_ENDIAN:
+		out_be64(addr, *val);
+		break;
+	}
+}
+#endif
+
+int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
+			   const void *val, size_t val_len)
+{
+	struct regmap_range *range;
+	void *ptr;
+
+	if (range_num >= map->range_count) {
+		debug("%s: range index %d larger than range count\n",
+		      __func__, range_num);
+		return -ERANGE;
+	}
+	range = &map->ranges[range_num];
+
+	ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
+
+	if (offset + val_len > range->size) {
+		debug("%s: offset/size combination invalid\n", __func__);
+		return -ERANGE;
+	}
+
+	switch (val_len) {
+	case REGMAP_SIZE_8:
+		__write_8(ptr, val, map->endianness);
+		break;
+	case REGMAP_SIZE_16:
+		__write_16(ptr, val, map->endianness);
+		break;
+	case REGMAP_SIZE_32:
+		__write_32(ptr, val, map->endianness);
+		break;
+#if defined(out_le64) && defined(out_be64) && defined(writeq)
+	case REGMAP_SIZE_64:
+		__write_64(ptr, val, map->endianness);
+		break;
+#endif
+	default:
+		debug("%s: regmap size %zu unknown\n", __func__, val_len);
+		return -EINVAL;
+	}
 
 	return 0;
 }
 
+int regmap_raw_write(struct regmap *map, uint offset, const void *val,
+		     size_t val_len)
+{
+	return regmap_raw_write_range(map, 0, offset, val, val_len);
+}
+
+int regmap_write(struct regmap *map, uint offset, uint val)
+{
+	return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
+}
+
 int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
 {
 	uint reg;

+ 13 - 7
drivers/core/root.c

@@ -222,14 +222,22 @@ static int dm_scan_fdt_live(struct udevice *parent,
 	int ret = 0, err;
 
 	for (np = node_parent->child; np; np = np->sibling) {
-		if (pre_reloc_only &&
-		    !of_find_property(np, "u-boot,dm-pre-reloc", NULL))
+		/* "chosen" node isn't a device itself but may contain some: */
+		if (!strcmp(np->name, "chosen")) {
+			pr_debug("parsing subnodes of \"chosen\"\n");
+
+			err = dm_scan_fdt_live(parent, np, pre_reloc_only);
+			if (err && !ret)
+				ret = err;
 			continue;
+		}
+
 		if (!of_device_is_available(np)) {
 			pr_debug("   - ignoring disabled device\n");
 			continue;
 		}
-		err = lists_bind_fdt(parent, np_to_ofnode(np), NULL);
+		err = lists_bind_fdt(parent, np_to_ofnode(np), NULL,
+				     pre_reloc_only);
 		if (err && !ret) {
 			ret = err;
 			debug("%s: ret=%d\n", np->name, ret);
@@ -282,14 +290,12 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
 			continue;
 		}
 
-		if (pre_reloc_only &&
-		    !dm_fdt_pre_reloc(blob, offset))
-			continue;
 		if (!fdtdec_get_is_enabled(blob, offset)) {
 			pr_debug("   - ignoring disabled device\n");
 			continue;
 		}
-		err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL);
+		err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL,
+				     pre_reloc_only);
 		if (err && !ret) {
 			ret = err;
 			debug("%s: ret=%d\n", node_name, ret);

+ 21 - 10
drivers/core/uclass.c

@@ -180,7 +180,7 @@ int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
 	if (list_empty(&uc->dev_head))
 		return -ENODEV;
 
-	list_for_each_entry(iter, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(iter, uc) {
 		if (iter == dev) {
 			if (ucp)
 				*ucp = uc;
@@ -205,7 +205,7 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
 	if (list_empty(&uc->dev_head))
 		return -ENODEV;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		if (!index--) {
 			*devp = dev;
 			return 0;
@@ -259,7 +259,7 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		if (!strncmp(dev->name, name, strlen(name))) {
 			*devp = dev;
 			return 0;
@@ -284,7 +284,7 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		debug("   - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name);
 		if ((find_req_seq ? dev->req_seq : dev->seq) ==
 				seq_or_req_seq) {
@@ -312,7 +312,7 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int node,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		if (dev_of_offset(dev) == node) {
 			*devp = dev;
 			return 0;
@@ -337,7 +337,7 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		log(LOGC_DM, LOGL_DEBUG_CONTENT, "      - checking %s\n",
 		    dev->name);
 		if (ofnode_equal(dev_ofnode(dev), node)) {
@@ -372,7 +372,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		uint phandle;
 
 		phandle = dev_read_phandle(dev);
@@ -399,7 +399,7 @@ int uclass_get_device_by_driver(enum uclass_id id,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		if (dev->driver == find_drv)
 			return uclass_get_device_tail(dev, 0, devp);
 	}
@@ -499,7 +499,7 @@ int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
 	if (ret)
 		return ret;
 
-	list_for_each_entry(dev, &uc->dev_head, uclass_node) {
+	uclass_foreach_dev(dev, uc) {
 		uint phandle;
 
 		phandle = dev_read_phandle(dev);
@@ -687,8 +687,19 @@ int uclass_pre_probe_device(struct udevice *dev)
 
 int uclass_post_probe_device(struct udevice *dev)
 {
-	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
+	struct uclass_driver *uc_drv;
+	int ret;
+
+	if (dev->parent) {
+		uc_drv = dev->parent->uclass->uc_drv;
+		if (uc_drv->child_post_probe) {
+			ret = uc_drv->child_post_probe(dev);
+			if (ret)
+				return ret;
+		}
+	}
 
+	uc_drv = dev->uclass->uc_drv;
 	if (uc_drv->post_probe)
 		return uc_drv->post_probe(dev);
 

+ 25 - 0
drivers/core/util.c

@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <dm/ofnode.h>
 #include <dm/util.h>
 #include <linux/libfdt.h>
 #include <vsprintf.h>
@@ -53,3 +54,27 @@ bool dm_fdt_pre_reloc(const void *blob, int offset)
 
 	return false;
 }
+
+bool dm_ofnode_pre_reloc(ofnode node)
+{
+	if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
+		return true;
+
+#ifdef CONFIG_TPL_BUILD
+	if (ofnode_read_bool(node, "u-boot,dm-tpl"))
+		return true;
+#elif defined(CONFIG_SPL_BUILD)
+	if (ofnode_read_bool(node, "u-boot,dm-spl"))
+		return true;
+#else
+	/*
+	 * In regular builds individual spl and tpl handling both
+	 * count as handled pre-relocation for later second init.
+	 */
+	if (ofnode_read_bool(node, "u-boot,dm-spl") ||
+	    ofnode_read_bool(node, "u-boot,dm-tpl"))
+		return true;
+#endif
+
+	return false;
+}

+ 1 - 1
drivers/cpu/mpc83xx_cpu.c

@@ -262,7 +262,7 @@ static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size)
 	determine_cpu_data(dev);
 
 	snprintf(buf, size,
-		 "CPU:   %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n",
+		 "%s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz",
 		 e300_names[priv->e300_type],
 		 cpu_type_names[priv->type],
 		 priv->is_e_processor ? "E" : "",

+ 2 - 0
drivers/gpio/omap_gpio.c

@@ -372,7 +372,9 @@ U_BOOT_DRIVER(gpio_omap) = {
 	.ops	= &gpio_omap_ops,
 	.probe	= omap_gpio_probe,
 	.priv_auto_alloc_size = sizeof(struct gpio_bank),
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };
 
 #endif /* CONFIG_DM_GPIO */

+ 1 - 1
drivers/gpio/stm32f7_gpio.c

@@ -123,6 +123,6 @@ U_BOOT_DRIVER(gpio_stm32) = {
 	.of_match = stm32_gpio_ids,
 	.probe	= gpio_stm32_probe,
 	.ops	= &gpio_stm32_ops,
-	.flags	= DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS,
+	.flags	= DM_UC_FLAG_SEQ_ALIAS,
 	.priv_auto_alloc_size	= sizeof(struct stm32_gpio_priv),
 };

+ 0 - 1
drivers/gpio/tegra186_gpio.c

@@ -281,5 +281,4 @@ U_BOOT_DRIVER(tegra186_gpio) = {
 	.bind = tegra186_gpio_bind,
 	.probe = tegra186_gpio_probe,
 	.ops = &tegra186_gpio_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/gpio/tegra_gpio.c

@@ -378,5 +378,4 @@ U_BOOT_DRIVER(gpio_tegra) = {
 	.probe = gpio_tegra_probe,
 	.priv_auto_alloc_size = sizeof(struct tegra_port_info),
 	.ops	= &gpio_tegra_ops,
-	.flags	= DM_FLAG_PRE_RELOC,
 };

+ 2 - 0
drivers/i2c/omap24xx_i2c.c

@@ -925,7 +925,9 @@ U_BOOT_DRIVER(i2c_omap) = {
 	.probe	= omap_i2c_probe,
 	.priv_auto_alloc_size = sizeof(struct omap_i2c),
 	.ops	= &omap_i2c_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags  = DM_FLAG_PRE_RELOC,
+#endif
 };
 
 #endif /* CONFIG_DM_I2C */

+ 17 - 0
drivers/misc/Kconfig

@@ -312,4 +312,21 @@ config FS_LOADER
 	  The consumer driver would then use this loader to program whatever,
 	  ie. the FPGA device.
 
+config GDSYS_SOC
+	bool "Enable gdsys SOC driver"
+	depends on MISC
+	help
+	  Support for gdsys IHS SOC, a simple bus associated with each gdsys
+	  IHS (Integrated Hardware Systems) FPGA, which holds all devices whose
+	  register maps are contained within the FPGA's register map.
+
+config IHS_FPGA
+	bool "Enable IHS FPGA driver"
+	depends on MISC
+	help
+	  Support IHS (Integrated Hardware Systems) FPGA, the main FPGAs on
+	  gdsys devices, which supply the majority of the functionality offered
+	  by the devices. This driver supports both CON and CPU variants of the
+	  devices, depending on the device tree entry.
+
 endmenu

+ 33 - 30
drivers/misc/Makefile

@@ -4,11 +4,6 @@
 # Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 
 obj-$(CONFIG_MISC) += misc-uclass.o
-obj-$(CONFIG_ALI152X) += ali512x.o
-obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
-obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
-obj-$(CONFIG_DS4510)  += ds4510.o
-obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_CROS_EC) += cros_ec.o
 obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
@@ -16,46 +11,54 @@ obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
 obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
 obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
 endif
-obj-$(CONFIG_FSL_IIM) += fsl_iim.o
-obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
-obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
-obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
-obj-$(CONFIG_IMX8) += imx8/
-obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
-obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
-obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
-obj-$(CONFIG_NS87308) += ns87308.o
-obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
+
 ifdef CONFIG_DM_I2C
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
 endif
 endif
-obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
-obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
-obj-$(CONFIG_LED_STATUS) += status_led.o
-obj-$(CONFIG_SANDBOX) += swap_case.o
 ifdef CONFIG_SPL_OF_PLATDATA
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
 endif
 endif
-obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
-obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
-obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
-obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
+obj-$(CONFIG_ALI152X) += ali512x.o
+obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
+obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
+obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
+obj-$(CONFIG_DS4510)  += ds4510.o
+obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
 obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
+obj-$(CONFIG_FSL_IIM) += fsl_iim.o
+obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
 obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
+obj-$(CONFIG_FS_LOADER) += fs_loader.o
+obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
+obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
+obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
+obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
+obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
+obj-$(CONFIG_IMX8) += imx8/
+obj-$(CONFIG_LED_STATUS) += status_led.o
+obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
+obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
+obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
+obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
+obj-$(CONFIG_NS87308) += ns87308.o
+obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
-obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
-obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
+obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
 obj-$(CONFIG_QFW) += qfw.o
 obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
-obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
+obj-$(CONFIG_SANDBOX) += swap_case.o
+obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
+obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
+obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
 obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o
+obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
 obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
-obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
-obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
+obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
+obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
+obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
-obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
-obj-$(CONFIG_FS_LOADER) += fs_loader.o
+obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o

+ 74 - 0
drivers/misc/gdsys_soc.c

@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ * Mario Six,  Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/lists.h>
+
+#include "gdsys_soc.h"
+
+/**
+ * struct gdsys_soc_priv - Private data for gdsys soc bus
+ * @fpga: The gdsys IHS FPGA this bus is associated with
+ */
+struct gdsys_soc_priv {
+	struct udevice *fpga;
+};
+
+static const struct udevice_id gdsys_soc_ids[] = {
+	{ .compatible = "gdsys,soc" },
+	{ /* sentinel */ }
+};
+
+int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga)
+{
+	struct gdsys_soc_priv *bus_priv;
+
+	if (!child->parent) {
+		debug("%s: Invalid parent\n", child->name);
+		return -EINVAL;
+	}
+
+	if (!device_is_compatible(child->parent, "gdsys,soc")) {
+		debug("%s: Not child of a gdsys soc\n", child->name);
+		return -EINVAL;
+	}
+
+	bus_priv = dev_get_priv(child->parent);
+
+	*fpga = bus_priv->fpga;
+
+	return 0;
+}
+
+static int gdsys_soc_probe(struct udevice *dev)
+{
+	struct gdsys_soc_priv *priv = dev_get_priv(dev);
+	struct udevice *fpga;
+	int res = uclass_get_device_by_phandle(UCLASS_MISC, dev, "fpga",
+					       &fpga);
+	if (res == -ENOENT) {
+		debug("%s: Could not find 'fpga' phandle\n", dev->name);
+		return -EINVAL;
+	}
+
+	if (res == -ENODEV) {
+		debug("%s: Could not get FPGA device\n", dev->name);
+		return -EINVAL;
+	}
+
+	priv->fpga = fpga;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(gdsys_soc_bus) = {
+	.name           = "gdsys_soc_bus",
+	.id             = UCLASS_SIMPLE_BUS,
+	.of_match       = gdsys_soc_ids,
+	.probe          = gdsys_soc_probe,
+	.priv_auto_alloc_size = sizeof(struct gdsys_soc_priv),
+};

+ 23 - 0
drivers/misc/gdsys_soc.h

@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2017
+ * Mario Six,  Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+#ifndef _GDSYS_SOC_H_
+#define _GDSYS_SOC_H_
+
+/**
+ * gdsys_soc_get_fpga() - Retrieve pointer to parent bus' FPGA device
+ * @child:	The child device on the FPGA bus needing access to the FPGA.
+ * @fpga:	Pointer to the retrieved FPGA device.
+ *
+ * To access their register maps, devices on gdsys soc buses usually have
+ * facilitate the accessor function of the IHS FPGA their parent bus is
+ * attached to. To access the FPGA device from within the bus' children, this
+ * function returns a pointer to it.
+ *
+ * Return: 0 on success, -ve on failure
+ */
+int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga);
+#endif /* _GDSYS_SOC_H_ */

+ 867 - 0
drivers/misc/ihs_fpga.c

@@ -0,0 +1,867 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2017
+ * Mario Six,  Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ *
+ * based on the ioep-fpga driver, which is
+ *
+ * (C) Copyright 2014
+ * Dirk Eibach,  Guntermann & Drunck GmbH, eibach@gdsys.de
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <asm/gpio.h>
+
+#include "ihs_fpga.h"
+
+/**
+ * struct ihs_fpga_priv - Private data structure for IHS FPGA driver
+ * @map:        Register map for the FPGA's own register space
+ * @reset_gpio: GPIO to start FPGA reconfiguration
+ * @done_gpio:  GPOI to read the 'ready' status of the FPGA
+ */
+struct ihs_fpga_priv {
+	struct regmap *map;
+	struct gpio_desc reset_gpio;
+	struct gpio_desc done_gpio;
+};
+
+/* Test pattern for reflection test */
+const u16 REFLECTION_TESTPATTERN = 0xdead;
+/* Delay (in ms) for each round in the reflection test */
+const uint REFLECTION_TEST_DELAY = 100;
+/* Maximum number of rounds in the reflection test */
+const uint REFLECTION_TEST_ROUNDS = 5;
+/* Delay (in ms) for each round waiting for the FPGA's done GPIO */
+const uint FPGA_DONE_WAIT_DELAY = 100;
+/* Maximum number of rounds for waiting for the FPGA's done GPIO */
+const uint FPGA_DONE_WAIT_ROUND = 5;
+
+/**
+ * enum pcb_video_type - Video type of the PCB
+ * @PCB_DVI_SL:     Video type is DVI single-link
+ * @PCB_DP_165MPIX: Video type is DisplayPort (165Mpix)
+ * @PCB_DP_300MPIX: Video type is DisplayPort (300Mpix)
+ * @PCB_HDMI:       Video type is HDMI
+ * @PCB_DP_1_2:     Video type is DisplayPort 1.2
+ * @PCB_HDMI_2_0:   Video type is HDMI 2.0
+ */
+enum pcb_video_type {
+	PCB_DVI_SL,
+	PCB_DP_165MPIX,
+	PCB_DP_300MPIX,
+	PCB_HDMI,
+	PCB_DP_1_2,
+	PCB_HDMI_2_0,
+};
+
+/**
+ * enum pcb_transmission_type - Transmission type of the PCB
+ * @PCB_CAT_1G:    Transmission type is 1G Ethernet
+ * @PCB_FIBER_3G:  Transmission type is 3G Fiber
+ * @PCB_CAT_10G:   Transmission type is 10G Ethernet
+ * @PCB_FIBER_10G: Transmission type is 10G Fiber
+ */
+enum pcb_transmission_type {
+	PCB_CAT_1G,
+	PCB_FIBER_3G,
+	PCB_CAT_10G,
+	PCB_FIBER_10G,
+};
+
+/**
+ * enum carrier_speed - Speed of the FPGA's carrier
+ * @CARRIER_SPEED_1G:   The carrier speed is 1G
+ * @CARRIER_SPEED_2_5G: The carrier speed is 2.5G
+ * @CARRIER_SPEED_3G:   The carrier speed is 3G
+ * @CARRIER_SPEED_10G:  The carrier speed is 10G
+ */
+enum carrier_speed {
+	CARRIER_SPEED_1G,
+	CARRIER_SPEED_3G,
+	CARRIER_SPEED_2_5G = CARRIER_SPEED_3G,
+	CARRIER_SPEED_10G,
+};
+
+/**
+ * enum ram_config - FPGA's RAM configuration
+ * @RAM_DDR2_32BIT_295MBPS:  DDR2 32 bit at 295Mb/s
+ * @RAM_DDR3_32BIT_590MBPS:  DDR3 32 bit at 590Mb/s
+ * @RAM_DDR3_48BIT_590MBPS:  DDR3 48 bit at 590Mb/s
+ * @RAM_DDR3_64BIT_1800MBPS: DDR3 64 bit at 1800Mb/s
+ * @RAM_DDR3_48BIT_1800MBPS: DDR3 48 bit at 1800Mb/s
+ */
+enum ram_config {
+	RAM_DDR2_32BIT_295MBPS,
+	RAM_DDR3_32BIT_590MBPS,
+	RAM_DDR3_48BIT_590MBPS,
+	RAM_DDR3_64BIT_1800MBPS,
+	RAM_DDR3_48BIT_1800MBPS,
+};
+
+/**
+ * enum sysclock - Speed of the FPGA's system clock
+ * @SYSCLK_147456: System clock is 147.456 MHz
+ */
+enum sysclock {
+	SYSCLK_147456,
+};
+
+/**
+ * struct fpga_versions - Data read from the versions register
+ * @video_channel:	   Is the FPGA for a video channel (true) or main
+ *			   channel (false) device?
+ * @con_side:		   Is the FPGA for a CON (true) or a CPU (false) device?
+ * @pcb_video_type:	   Defines for whch video type the FPGA is configured
+ * @pcb_transmission_type: Defines for which transmission type the FPGA is
+ *			   configured
+ * @hw_version:		   Hardware version of the FPGA
+ */
+struct fpga_versions {
+	bool video_channel;
+	bool con_side;
+	enum pcb_video_type pcb_video_type;
+	enum pcb_transmission_type pcb_transmission_type;
+	unsigned int hw_version;
+};
+
+/**
+ * struct fpga_features - Data read from the features register
+ * @video_channels:	Number of video channels supported
+ * @carriers:		Number of carrier channels supported
+ * @carrier_speed:	Speed of carriers
+ * @ram_config:		RAM configuration of FPGA
+ * @sysclock:		System clock speed of FPGA
+ * @pcm_tx:		Support for PCM transmission
+ * @pcm_rx:		Support for PCM reception
+ * @spdif_tx:		Support for SPDIF audio transmission
+ * @spdif_rx:		Support for SPDIF audio reception
+ * @usb2:		Support for transparent USB2.0
+ * @rs232:		Support for bidirectional RS232
+ * @compression_type1:	Support for compression type 1
+ * @compression_type2:	Support for compression type 2
+ * @compression_type3:	Support for compression type 3
+ * @interlace:		Support for interlace image formats
+ * @osd:		Support for a OSD
+ * @compression_pipes:	Number of compression pipes supported
+ */
+struct fpga_features {
+	u8 video_channels;
+	u8 carriers;
+	enum carrier_speed carrier_speed;
+	enum ram_config ram_config;
+	enum sysclock sysclock;
+	bool pcm_tx;
+	bool pcm_rx;
+	bool spdif_tx;
+	bool spdif_rx;
+	bool usb2;
+	bool rs232;
+	bool compression_type1;
+	bool compression_type2;
+	bool compression_type3;
+	bool interlace;
+	bool osd;
+	bool compression_pipes;
+};
+
+#ifdef CONFIG_SYS_FPGA_FLAVOR_GAZERBEAM
+
+/**
+ * get_versions() - Fill structure with info from version register.
+ * @dev:      FPGA device to be queried for information
+ * @versions: Pointer to the structure to fill with information from the
+ *	      versions register
+ * Return: 0
+ */
+static int get_versions(struct udevice *dev, struct fpga_versions *versions)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	enum {
+		VERSIONS_FPGA_VIDEO_CHANNEL = BIT(12),
+		VERSIONS_FPGA_CON_SIDE = BIT(13),
+		VERSIONS_FPGA_SC = BIT(14),
+		VERSIONS_PCB_CON = BIT(9),
+		VERSIONS_PCB_SC = BIT(8),
+		VERSIONS_PCB_VIDEO_MASK = 0x3 << 6,
+		VERSIONS_PCB_VIDEO_DP_1_2 = 0x0 << 6,
+		VERSIONS_PCB_VIDEO_HDMI_2_0 = 0x1 << 6,
+		VERSIONS_PCB_TRANSMISSION_MASK = 0x3 << 4,
+		VERSIONS_PCB_TRANSMISSION_FIBER_10G = 0x0 << 4,
+		VERSIONS_PCB_TRANSMISSION_CAT_10G = 0x1 << 4,
+		VERSIONS_PCB_TRANSMISSION_FIBER_3G = 0x2 << 4,
+		VERSIONS_PCB_TRANSMISSION_CAT_1G = 0x3 << 4,
+		VERSIONS_HW_VER_MASK = 0xf << 0,
+	};
+	u16 raw_versions;
+
+	memset(versions, 0, sizeof(struct fpga_versions));
+
+	ihs_fpga_get(priv->map, versions, &raw_versions);
+
+	versions->video_channel = raw_versions & VERSIONS_FPGA_VIDEO_CHANNEL;
+	versions->con_side = raw_versions & VERSIONS_FPGA_CON_SIDE;
+
+	switch (raw_versions & VERSIONS_PCB_VIDEO_MASK) {
+	case VERSIONS_PCB_VIDEO_DP_1_2:
+		versions->pcb_video_type = PCB_DP_1_2;
+		break;
+
+	case VERSIONS_PCB_VIDEO_HDMI_2_0:
+		versions->pcb_video_type = PCB_HDMI_2_0;
+		break;
+	}
+
+	switch (raw_versions & VERSIONS_PCB_TRANSMISSION_MASK) {
+	case VERSIONS_PCB_TRANSMISSION_FIBER_10G:
+		versions->pcb_transmission_type = PCB_FIBER_10G;
+		break;
+
+	case VERSIONS_PCB_TRANSMISSION_CAT_10G:
+		versions->pcb_transmission_type = PCB_CAT_10G;
+		break;
+
+	case VERSIONS_PCB_TRANSMISSION_FIBER_3G:
+		versions->pcb_transmission_type = PCB_FIBER_3G;
+		break;
+
+	case VERSIONS_PCB_TRANSMISSION_CAT_1G:
+		versions->pcb_transmission_type = PCB_CAT_1G;
+		break;
+	}
+
+	versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
+
+	return 0;
+}
+
+/**
+ * get_features() - Fill structure with info from features register.
+ * @dev:      FPGA device to be queried for information
+ * @features: Pointer to the structure to fill with information from the
+ *	      features register
+ * Return: 0
+ */
+static int get_features(struct udevice *dev, struct fpga_features *features)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	enum {
+		FEATURE_SPDIF_RX = BIT(15),
+		FEATURE_SPDIF_TX = BIT(14),
+		FEATURE_PCM_RX = BIT(13),
+		FEATURE_PCM_TX = BIT(12),
+		FEATURE_RAM_MASK = GENMASK(11, 8),
+		FEATURE_RAM_DDR2_32BIT_295MBPS = 0x0 << 8,
+		FEATURE_RAM_DDR3_32BIT_590MBPS = 0x1 << 8,
+		FEATURE_RAM_DDR3_48BIT_590MBPS = 0x2 << 8,
+		FEATURE_RAM_DDR3_64BIT_1800MBPS = 0x3 << 8,
+		FEATURE_RAM_DDR3_48BIT_1800MBPS = 0x4 << 8,
+		FEATURE_CARRIER_SPEED_MASK = GENMASK(7, 6),
+		FEATURE_CARRIER_SPEED_1G = 0x0 << 6,
+		FEATURE_CARRIER_SPEED_2_5G = 0x1 << 6,
+		FEATURE_CARRIER_SPEED_10G = 0x2 << 6,
+		FEATURE_CARRIERS_MASK = GENMASK(5, 4),
+		FEATURE_CARRIERS_0 = 0x0 << 4,
+		FEATURE_CARRIERS_1 = 0x1 << 4,
+		FEATURE_CARRIERS_2 = 0x2 << 4,
+		FEATURE_CARRIERS_4 = 0x3 << 4,
+		FEATURE_USB2 = BIT(3),
+		FEATURE_VIDEOCHANNELS_MASK = GENMASK(2, 0),
+		FEATURE_VIDEOCHANNELS_0 = 0x0 << 0,
+		FEATURE_VIDEOCHANNELS_1 = 0x1 << 0,
+		FEATURE_VIDEOCHANNELS_1_1 = 0x2 << 0,
+		FEATURE_VIDEOCHANNELS_2 = 0x3 << 0,
+	};
+
+	enum {
+		EXT_FEATURE_OSD = BIT(15),
+		EXT_FEATURE_ETHERNET = BIT(9),
+		EXT_FEATURE_INTERLACE = BIT(8),
+		EXT_FEATURE_RS232 = BIT(7),
+		EXT_FEATURE_COMPRESSION_PERF_MASK = GENMASK(6, 4),
+		EXT_FEATURE_COMPRESSION_PERF_1X = 0x0 << 4,
+		EXT_FEATURE_COMPRESSION_PERF_2X = 0x1 << 4,
+		EXT_FEATURE_COMPRESSION_PERF_4X = 0x2 << 4,
+		EXT_FEATURE_COMPRESSION_TYPE1 = BIT(0),
+		EXT_FEATURE_COMPRESSION_TYPE2 = BIT(1),
+		EXT_FEATURE_COMPRESSION_TYPE3 = BIT(2),
+	};
+
+	u16 raw_features;
+	u16 raw_extended_features;
+
+	memset(features, 0, sizeof(struct fpga_features));
+
+	ihs_fpga_get(priv->map, features, &raw_features);
+	ihs_fpga_get(priv->map, extended_features, &raw_extended_features);
+
+	switch (raw_features & FEATURE_VIDEOCHANNELS_MASK) {
+	case FEATURE_VIDEOCHANNELS_0:
+		features->video_channels = 0;
+		break;
+
+	case FEATURE_VIDEOCHANNELS_1:
+		features->video_channels = 1;
+		break;
+
+	case FEATURE_VIDEOCHANNELS_1_1:
+	case FEATURE_VIDEOCHANNELS_2:
+		features->video_channels = 2;
+		break;
+	};
+
+	switch (raw_features & FEATURE_CARRIERS_MASK) {
+	case FEATURE_CARRIERS_0:
+		features->carriers = 0;
+		break;
+
+	case FEATURE_CARRIERS_1:
+		features->carriers = 1;
+		break;
+
+	case FEATURE_CARRIERS_2:
+		features->carriers = 2;
+		break;
+
+	case FEATURE_CARRIERS_4:
+		features->carriers = 4;
+		break;
+	}
+
+	switch (raw_features & FEATURE_CARRIER_SPEED_MASK) {
+	case FEATURE_CARRIER_SPEED_1G:
+		features->carrier_speed = CARRIER_SPEED_1G;
+		break;
+	case FEATURE_CARRIER_SPEED_2_5G:
+		features->carrier_speed = CARRIER_SPEED_2_5G;
+		break;
+	case FEATURE_CARRIER_SPEED_10G:
+		features->carrier_speed = CARRIER_SPEED_10G;
+		break;
+	}
+
+	switch (raw_features & FEATURE_RAM_MASK) {
+	case FEATURE_RAM_DDR2_32BIT_295MBPS:
+		features->ram_config = RAM_DDR2_32BIT_295MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_32BIT_590MBPS:
+		features->ram_config = RAM_DDR3_32BIT_590MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_48BIT_590MBPS:
+		features->ram_config = RAM_DDR3_48BIT_590MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_64BIT_1800MBPS:
+		features->ram_config = RAM_DDR3_64BIT_1800MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_48BIT_1800MBPS:
+		features->ram_config = RAM_DDR3_48BIT_1800MBPS;
+		break;
+	}
+
+	features->pcm_tx = raw_features & FEATURE_PCM_TX;
+	features->pcm_rx = raw_features & FEATURE_PCM_RX;
+	features->spdif_tx = raw_features & FEATURE_SPDIF_TX;
+	features->spdif_rx = raw_features & FEATURE_SPDIF_RX;
+	features->usb2 = raw_features & FEATURE_USB2;
+	features->rs232 = raw_extended_features & EXT_FEATURE_RS232;
+	features->compression_type1 = raw_extended_features &
+					EXT_FEATURE_COMPRESSION_TYPE1;
+	features->compression_type2 = raw_extended_features &
+					EXT_FEATURE_COMPRESSION_TYPE2;
+	features->compression_type3 = raw_extended_features &
+					EXT_FEATURE_COMPRESSION_TYPE3;
+	features->interlace = raw_extended_features & EXT_FEATURE_INTERLACE;
+	features->osd = raw_extended_features & EXT_FEATURE_OSD;
+	features->compression_pipes = raw_extended_features &
+					EXT_FEATURE_COMPRESSION_PERF_MASK;
+
+	return 0;
+}
+
+#else
+
+/**
+ * get_versions() - Fill structure with info from version register.
+ * @fpga:     Identifier of the FPGA device to be queried for information
+ * @versions: Pointer to the structure to fill with information from the
+ *	      versions register
+ *
+ * This is the legacy version and should be considered deprecated for new
+ * devices.
+ *
+ * Return: 0
+ */
+static int get_versions(unsigned int fpga, struct fpga_versions *versions)
+{
+	enum {
+		/* HW version encoding is a mess, leave it for the moment */
+		VERSIONS_HW_VER_MASK = 0xf << 0,
+		VERSIONS_PIX_CLOCK_GEN_IDT8N3QV01 = BIT(4),
+		VERSIONS_SFP = BIT(5),
+		VERSIONS_VIDEO_MASK = 0x7 << 6,
+		VERSIONS_VIDEO_DVI = 0x0 << 6,
+		VERSIONS_VIDEO_DP_165 = 0x1 << 6,
+		VERSIONS_VIDEO_DP_300 = 0x2 << 6,
+		VERSIONS_VIDEO_HDMI = 0x3 << 6,
+		VERSIONS_UT_MASK = 0xf << 12,
+		VERSIONS_UT_MAIN_SERVER = 0x0 << 12,
+		VERSIONS_UT_MAIN_USER = 0x1 << 12,
+		VERSIONS_UT_VIDEO_SERVER = 0x2 << 12,
+		VERSIONS_UT_VIDEO_USER = 0x3 << 12,
+	};
+	u16 raw_versions;
+
+	memset(versions, 0, sizeof(struct fpga_versions));
+
+	FPGA_GET_REG(fpga, versions, &raw_versions);
+
+	switch (raw_versions & VERSIONS_UT_MASK) {
+	case VERSIONS_UT_MAIN_SERVER:
+		versions->video_channel = false;
+		versions->con_side = false;
+		break;
+
+	case VERSIONS_UT_MAIN_USER:
+		versions->video_channel = false;
+		versions->con_side = true;
+		break;
+
+	case VERSIONS_UT_VIDEO_SERVER:
+		versions->video_channel = true;
+		versions->con_side = false;
+		break;
+
+	case VERSIONS_UT_VIDEO_USER:
+		versions->video_channel = true;
+		versions->con_side = true;
+		break;
+	}
+
+	switch (raw_versions & VERSIONS_VIDEO_MASK) {
+	case VERSIONS_VIDEO_DVI:
+		versions->pcb_video_type = PCB_DVI_SL;
+		break;
+
+	case VERSIONS_VIDEO_DP_165:
+		versions->pcb_video_type = PCB_DP_165MPIX;
+		break;
+
+	case VERSIONS_VIDEO_DP_300:
+		versions->pcb_video_type = PCB_DP_300MPIX;
+		break;
+
+	case VERSIONS_VIDEO_HDMI:
+		versions->pcb_video_type = PCB_HDMI;
+		break;
+	}
+
+	versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
+
+	if (raw_versions & VERSIONS_SFP)
+		versions->pcb_transmission_type = PCB_FIBER_3G;
+	else
+		versions->pcb_transmission_type = PCB_CAT_1G;
+
+	return 0;
+}
+
+/**
+ * get_features() - Fill structure with info from features register.
+ * @fpga:     Identifier of the FPGA device to be queried for information
+ * @features: Pointer to the structure to fill with information from the
+ *	      features register
+ *
+ * This is the legacy version and should be considered deprecated for new
+ * devices.
+ *
+ * Return: 0
+ */
+static int get_features(unsigned int fpga, struct fpga_features *features)
+{
+	enum {
+		FEATURE_CARRIER_SPEED_2_5 = BIT(4),
+		FEATURE_RAM_MASK = 0x7 << 5,
+		FEATURE_RAM_DDR2_32BIT = 0x0 << 5,
+		FEATURE_RAM_DDR3_32BIT = 0x1 << 5,
+		FEATURE_RAM_DDR3_48BIT = 0x2 << 5,
+		FEATURE_PCM_AUDIO_TX = BIT(9),
+		FEATURE_PCM_AUDIO_RX = BIT(10),
+		FEATURE_OSD = BIT(11),
+		FEATURE_USB20 = BIT(12),
+		FEATURE_COMPRESSION_MASK = 7 << 13,
+		FEATURE_COMPRESSION_TYPE1 = 0x1 << 13,
+		FEATURE_COMPRESSION_TYPE1_TYPE2 = 0x3 << 13,
+		FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3 = 0x7 << 13,
+	};
+
+	enum {
+		EXTENDED_FEATURE_SPDIF_AUDIO_TX = BIT(0),
+		EXTENDED_FEATURE_SPDIF_AUDIO_RX = BIT(1),
+		EXTENDED_FEATURE_RS232 = BIT(2),
+		EXTENDED_FEATURE_COMPRESSION_PIPES = BIT(3),
+		EXTENDED_FEATURE_INTERLACE = BIT(4),
+	};
+
+	u16 raw_features;
+	u16 raw_extended_features;
+
+	memset(features, 0, sizeof(struct fpga_features));
+
+	FPGA_GET_REG(fpga, fpga_features, &raw_features);
+	FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features);
+
+	features->video_channels = raw_features & 0x3;
+	features->carriers = (raw_features >> 2) & 0x3;
+
+	features->carrier_speed = (raw_features & FEATURE_CARRIER_SPEED_2_5)
+		? CARRIER_SPEED_2_5G : CARRIER_SPEED_1G;
+
+	switch (raw_features & FEATURE_RAM_MASK) {
+	case FEATURE_RAM_DDR2_32BIT:
+		features->ram_config = RAM_DDR2_32BIT_295MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_32BIT:
+		features->ram_config = RAM_DDR3_32BIT_590MBPS;
+		break;
+
+	case FEATURE_RAM_DDR3_48BIT:
+		features->ram_config = RAM_DDR3_48BIT_590MBPS;
+		break;
+	}
+
+	features->pcm_tx = raw_features & FEATURE_PCM_AUDIO_TX;
+	features->pcm_rx = raw_features & FEATURE_PCM_AUDIO_RX;
+	features->spdif_tx = raw_extended_features &
+				EXTENDED_FEATURE_SPDIF_AUDIO_TX;
+	features->spdif_rx = raw_extended_features &
+				EXTENDED_FEATURE_SPDIF_AUDIO_RX;
+
+	features->usb2 = raw_features & FEATURE_USB20;
+	features->rs232 = raw_extended_features & EXTENDED_FEATURE_RS232;
+
+	features->compression_type1 = false;
+	features->compression_type2 = false;
+	features->compression_type3 = false;
+	switch (raw_features & FEATURE_COMPRESSION_MASK) {
+	case FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3:
+		features->compression_type3 = true;
+		/* fall-through */
+	case FEATURE_COMPRESSION_TYPE1_TYPE2:
+		features->compression_type2 = true;
+		/* fall-through */
+	case FEATURE_COMPRESSION_TYPE1:
+		features->compression_type1 = true;
+		break;
+	}
+
+	features->interlace = raw_extended_features &
+				EXTENDED_FEATURE_INTERLACE;
+	features->osd = raw_features & FEATURE_OSD;
+	features->compression_pipes = raw_extended_features &
+					EXTENDED_FEATURE_COMPRESSION_PIPES;
+
+	return 0;
+}
+
+#endif
+
+/**
+ * fpga_print_info() - Print information about FPGA device
+ * @dev: FPGA device to print information about
+ */
+static void fpga_print_info(struct udevice *dev)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	u16 fpga_version;
+	struct fpga_versions versions;
+	struct fpga_features features;
+
+	ihs_fpga_get(priv->map, fpga_version, &fpga_version);
+	get_versions(dev, &versions);
+	get_features(dev, &features);
+
+	if (versions.video_channel)
+		printf("Videochannel");
+	else
+		printf("Mainchannel");
+
+	if (versions.con_side)
+		printf(" User");
+	else
+		printf(" Server");
+
+	switch (versions.pcb_transmission_type) {
+	case PCB_CAT_1G:
+	case PCB_CAT_10G:
+		printf(" CAT");
+		break;
+	case PCB_FIBER_3G:
+	case PCB_FIBER_10G:
+		printf(" Fiber");
+		break;
+	};
+
+	switch (versions.pcb_video_type) {
+	case PCB_DVI_SL:
+		printf(" DVI,");
+		break;
+	case PCB_DP_165MPIX:
+		printf(" DP 165MPix/s,");
+		break;
+	case PCB_DP_300MPIX:
+		printf(" DP 300MPix/s,");
+		break;
+	case PCB_HDMI:
+		printf(" HDMI,");
+		break;
+	case PCB_DP_1_2:
+		printf(" DP 1.2,");
+		break;
+	case PCB_HDMI_2_0:
+		printf(" HDMI 2.0,");
+		break;
+	}
+
+	printf(" FPGA V %d.%02d\n       features: ",
+	       fpga_version / 100, fpga_version % 100);
+
+	if (!features.compression_type1 &&
+	    !features.compression_type2 &&
+	    !features.compression_type3)
+		printf("no compression, ");
+
+	if (features.compression_type1)
+		printf("type1, ");
+
+	if (features.compression_type2)
+		printf("type2, ");
+
+	if (features.compression_type3)
+		printf("type3, ");
+
+	printf("%sosd", features.osd ? "" : "no ");
+
+	if (features.pcm_rx && features.pcm_tx)
+		printf(", pcm rx+tx");
+	else if (features.pcm_rx)
+		printf(", pcm rx");
+	else if (features.pcm_tx)
+		printf(", pcm tx");
+
+	if (features.spdif_rx && features.spdif_tx)
+		printf(", spdif rx+tx");
+	else if (features.spdif_rx)
+		printf(", spdif rx");
+	else if (features.spdif_tx)
+		printf(", spdif tx");
+
+	puts(",\n       ");
+
+	switch (features.sysclock) {
+	case SYSCLK_147456:
+		printf("clock 147.456 MHz");
+		break;
+	}
+
+	switch (features.ram_config) {
+	case RAM_DDR2_32BIT_295MBPS:
+		printf(", RAM 32 bit DDR2");
+		break;
+	case RAM_DDR3_32BIT_590MBPS:
+		printf(", RAM 32 bit DDR3");
+		break;
+	case RAM_DDR3_48BIT_590MBPS:
+	case RAM_DDR3_48BIT_1800MBPS:
+		printf(", RAM 48 bit DDR3");
+		break;
+	case RAM_DDR3_64BIT_1800MBPS:
+		printf(", RAM 64 bit DDR3");
+		break;
+	}
+
+	printf(", %d carrier(s)", features.carriers);
+
+	switch (features.carrier_speed) {
+	case CARRIER_SPEED_1G:
+		printf(", 1Gbit/s");
+		break;
+	case CARRIER_SPEED_3G:
+		printf(", 3Gbit/s");
+		break;
+	case CARRIER_SPEED_10G:
+		printf(", 10Gbit/s");
+		break;
+	}
+
+	printf(", %d video channel(s)\n", features.video_channels);
+}
+
+/**
+ * do_reflection_test() - Run reflection test on a FPGA device
+ * @dev: FPGA device to run reflection test on
+ *
+ * Return: 0 if reflection test succeeded, -ve on error
+ */
+static int do_reflection_test(struct udevice *dev)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	int ctr = 0;
+
+	while (1) {
+		u16 val;
+
+		ihs_fpga_set(priv->map, reflection_low, REFLECTION_TESTPATTERN);
+
+		ihs_fpga_get(priv->map, reflection_low, &val);
+		if (val == (~REFLECTION_TESTPATTERN & 0xffff))
+			return -EIO;
+
+		mdelay(REFLECTION_TEST_DELAY);
+		if (ctr++ > REFLECTION_TEST_ROUNDS)
+			return 0;
+	}
+}
+
+/**
+ * wait_for_fpga_done() - Wait until 'done'-flag is set for FPGA device
+ * @dev: FPGA device whose done flag to wait for
+ *
+ * This function waits until it detects that the done-GPIO's value was changed
+ * to 1 by the FPGA, which indicates that the device is configured and ready to
+ * use.
+ *
+ * Return: 0 if done flag was detected, -ve on error
+ */
+static int wait_for_fpga_done(struct udevice *dev)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	int ctr = 0;
+	int done_val;
+
+	while (1) {
+		done_val = dm_gpio_get_value(&priv->done_gpio);
+		if (done_val < 0) {
+			debug("%s: Error while reading done-GPIO (err = %d)\n",
+			      dev->name, done_val);
+			return done_val;
+		}
+
+		if (done_val)
+			return 0;
+
+		mdelay(FPGA_DONE_WAIT_DELAY);
+		if (ctr++ > FPGA_DONE_WAIT_ROUND) {
+			debug("%s: FPGA init failed (done not detected)\n",
+			      dev->name);
+			return -EIO;
+		}
+	}
+}
+
+static int ihs_fpga_probe(struct udevice *dev)
+{
+	struct ihs_fpga_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	/* TODO(mario.six@gdsys.cc): Case of FPGA attached to MCLink bus */
+
+	ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
+	if (ret) {
+		debug("%s: Could not initialize regmap (err = %d)",
+		      dev->name, ret);
+		return ret;
+	}
+
+	ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
+				   GPIOD_IS_OUT);
+	if (ret) {
+		debug("%s: Could not get reset-GPIO (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	if (!priv->reset_gpio.dev) {
+		debug("%s: Could not get reset-GPIO\n", dev->name);
+		return -ENOENT;
+	}
+
+	ret = gpio_request_by_name(dev, "done-gpios", 0, &priv->done_gpio,
+				   GPIOD_IS_IN);
+	if (ret) {
+		debug("%s: Could not get done-GPIO (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	if (!priv->done_gpio.dev) {
+		debug("%s: Could not get done-GPIO\n", dev->name);
+		return -ENOENT;
+	}
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		debug("%s: Error while setting reset-GPIO (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	/* If FPGA already runs, don't initialize again */
+	if (do_reflection_test(dev))
+		goto reflection_ok;
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 0);
+	if (ret) {
+		debug("%s: Error while setting reset-GPIO (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	ret = wait_for_fpga_done(dev);
+	if (ret) {
+		debug("%s: Error while waiting for FPGA done (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	udelay(10);
+
+	ret = dm_gpio_set_value(&priv->reset_gpio, 1);
+	if (ret) {
+		debug("%s: Error while setting reset-GPIO (err = %d)\n",
+		      dev->name, ret);
+		return ret;
+	}
+
+	if (!do_reflection_test(dev)) {
+		debug("%s: Reflection test FAILED\n", dev->name);
+		return -EIO;
+	}
+
+reflection_ok:
+	printf("%s: Reflection test passed.\n", dev->name);
+
+	fpga_print_info(dev);
+
+	return 0;
+}
+
+static const struct udevice_id ihs_fpga_ids[] = {
+	{ .compatible = "gdsys,iocon_fpga" },
+	{ .compatible = "gdsys,iocpu_fpga" },
+	{ }
+};
+
+U_BOOT_DRIVER(ihs_fpga_bus) = {
+	.name           = "ihs_fpga_bus",
+	.id             = UCLASS_MISC,
+	.of_match       = ihs_fpga_ids,
+	.probe          = ihs_fpga_probe,
+	.priv_auto_alloc_size = sizeof(struct ihs_fpga_priv),
+};

+ 49 - 0
drivers/misc/ihs_fpga.h

@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
+ */
+
+/**
+ * struct ihs_fpga_regs - IHS FPGA register map structure
+ * @reflection_low:	  Lower reflection register
+ * @versions:		  PCB versions register
+ * @fpga_version:	  FPGA versions register
+ * @features:		  FPGA features register
+ * @extended_features:	  FPGA extended features register
+ * @top_interrupt:	  Top interrupt register
+ * @top_interrupt_enable: Top interrupt enable register
+ * @status:		  FPGA status register
+ * @control:		  FPGA control register
+ * @extended_control:	  FPGA extended control register
+ */
+struct ihs_fpga_regs {
+	u16 reflection_low;
+	u16 versions;
+	u16 fpga_version;
+	u16 features;
+	u16 extended_features;
+	u16 top_interrupt;
+	u16 top_interrupt_enable;
+	u16 status;
+	u16 control;
+	u16 extended_control;
+};
+
+/**
+ * ihs_fpga_set() - Convenience macro to set values in FPGA register map
+ * @map:    Register map to set a value in
+ * @member: Name of member (described by ihs_fpga_regs) to set
+ * @val:    Value to set the member to
+ */
+#define ihs_fpga_set(map, member, val) \
+	regmap_set(map, struct ihs_fpga_regs, member, val)
+
+/**
+ * ihs_fpga_get() - Convenience macro to get values from FPGA register map
+ * @map:    Register map to read value from
+ * @member: Name of member (described by ihs_fpga_regs) to get
+ * @valp:   Pointe to variable to receive the value read
+ */
+#define ihs_fpga_get(map, member, valp) \
+	regmap_get(map, struct ihs_fpga_regs, member, valp)

+ 2 - 2
drivers/misc/imx8/scu.c

@@ -223,7 +223,7 @@ static int imx8_scu_bind(struct udevice *dev)
 	if (node < 0)
 		panic("No clk node found\n");
 
-	ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child);
+	ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
 	if (ret)
 		return ret;
 
@@ -234,7 +234,7 @@ static int imx8_scu_bind(struct udevice *dev)
 	if (node < 0)
 		panic("No iomuxc node found\n");
 
-	ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child);
+	ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
 	if (ret)
 		return ret;
 

+ 9 - 0
drivers/misc/swap_case.c

@@ -124,12 +124,21 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
 	case PCI_CAP_ID_PM_OFFSET:
 		*valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM;
 		break;
+	case PCI_CAP_ID_PM_OFFSET + PCI_CAP_LIST_NEXT:
+		*valuep = PCI_CAP_ID_EXP_OFFSET;
+		break;
 	case PCI_CAP_ID_EXP_OFFSET:
 		*valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP;
 		break;
+	case PCI_CAP_ID_EXP_OFFSET + PCI_CAP_LIST_NEXT:
+		*valuep = PCI_CAP_ID_MSIX_OFFSET;
+		break;
 	case PCI_CAP_ID_MSIX_OFFSET:
 		*valuep = PCI_CAP_ID_MSIX;
 		break;
+	case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT:
+		*valuep = 0;
+		break;
 	case PCI_EXT_CAP_ID_ERR_OFFSET:
 		*valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR;
 		break;

+ 0 - 3
drivers/mmc/mmc.c

@@ -2444,9 +2444,6 @@ static int mmc_startup(struct mmc *mmc)
 	bdesc->product[0] = 0;
 	bdesc->revision[0] = 0;
 #endif
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
-	part_init(bdesc);
-#endif
 
 	return 0;
 }

+ 2 - 0
drivers/mmc/omap_hsmmc.c

@@ -1953,6 +1953,8 @@ U_BOOT_DRIVER(omap_hsmmc) = {
 	.ops = &omap_hsmmc_ops,
 	.probe	= omap_hsmmc_probe,
 	.priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags	= DM_FLAG_PRE_RELOC,
+#endif
 };
 #endif

+ 0 - 1
drivers/nvme/nvme.c

@@ -664,7 +664,6 @@ static int nvme_blk_probe(struct udevice *udev)
 	sprintf(desc->vendor, "0x%.4x", pplat->vendor);
 	memcpy(desc->product, ndev->serial, sizeof(ndev->serial));
 	memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev));
-	part_init(desc);
 
 	return 0;
 }

+ 36 - 15
drivers/pci/pci-uclass.c

@@ -1344,26 +1344,14 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
 	return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
 }
 
-int dm_pci_find_capability(struct udevice *dev, int cap)
+static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
 {
-	u16 status;
-	u8 header_type;
 	int ttl = PCI_FIND_CAP_TTL;
 	u8 id;
 	u16 ent;
-	u8 pos;
-
-	dm_pci_read_config16(dev, PCI_STATUS, &status);
-	if (!(status & PCI_STATUS_CAP_LIST))
-		return 0;
-
-	dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
-	if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
-		pos = PCI_CB_CAPABILITY_LIST;
-	else
-		pos = PCI_CAPABILITY_LIST;
 
 	dm_pci_read_config8(dev, pos, &pos);
+
 	while (ttl--) {
 		if (pos < PCI_STD_HEADER_SIZEOF)
 			break;
@@ -1381,7 +1369,32 @@ int dm_pci_find_capability(struct udevice *dev, int cap)
 	return 0;
 }
 
-int dm_pci_find_ext_capability(struct udevice *dev, int cap)
+int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap)
+{
+	return _dm_pci_find_next_capability(dev, start + PCI_CAP_LIST_NEXT,
+					    cap);
+}
+
+int dm_pci_find_capability(struct udevice *dev, int cap)
+{
+	u16 status;
+	u8 header_type;
+	u8 pos;
+
+	dm_pci_read_config16(dev, PCI_STATUS, &status);
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+
+	dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
+	if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+		pos = PCI_CB_CAPABILITY_LIST;
+	else
+		pos = PCI_CAPABILITY_LIST;
+
+	return _dm_pci_find_next_capability(dev, pos, cap);
+}
+
+int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap)
 {
 	u32 header;
 	int ttl;
@@ -1390,6 +1403,9 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
 	/* minimum 8 bytes per capability */
 	ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
 
+	if (start)
+		pos = start;
+
 	dm_pci_read_config32(dev, pos, &header);
 	/*
 	 * If we have no capabilities, this is indicated by cap ID,
@@ -1412,6 +1428,11 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
 	return 0;
 }
 
+int dm_pci_find_ext_capability(struct udevice *dev, int cap)
+{
+	return dm_pci_find_next_ext_capability(dev, 0, cap);
+}
+
 UCLASS_DRIVER(pci) = {
 	.id		= UCLASS_PCI,
 	.name		= "pci",

+ 2 - 0
drivers/pinctrl/broadcom/pinctrl-bcm283x.c

@@ -148,5 +148,7 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = {
 	.priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv),
 	.ops		= &bcm283x_pinctrl_ops,
 	.probe		= bcm283x_pinctl_probe,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags		= DM_FLAG_PRE_RELOC,
+#endif
 };

+ 0 - 1
drivers/pinctrl/exynos/pinctrl-exynos7420.c

@@ -113,5 +113,4 @@ U_BOOT_DRIVER(pinctrl_exynos7420) = {
 	.priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv),
 	.ops		= &exynos7420_pinctrl_ops,
 	.probe		= exynos_pinctrl_probe,
-	.flags		= DM_FLAG_PRE_RELOC
 };

+ 2 - 0
drivers/pinctrl/nxp/pinctrl-imx5.c

@@ -40,5 +40,7 @@ U_BOOT_DRIVER(imx5_pinctrl) = {
 	.remove = imx_pinctrl_remove,
 	.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
 	.ops = &imx_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 2 - 0
drivers/pinctrl/nxp/pinctrl-imx6.c

@@ -49,5 +49,7 @@ U_BOOT_DRIVER(imx6_pinctrl) = {
 	.remove = imx_pinctrl_remove,
 	.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
 	.ops = &imx_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 2 - 0
drivers/pinctrl/nxp/pinctrl-imx7.c

@@ -37,5 +37,7 @@ U_BOOT_DRIVER(imx7_pinctrl) = {
 	.remove = imx_pinctrl_remove,
 	.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
 	.ops = &imx_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 2 - 0
drivers/pinctrl/nxp/pinctrl-imx7ulp.c

@@ -41,5 +41,7 @@ U_BOOT_DRIVER(imx7ulp_pinctrl) = {
 	.remove = imx_pinctrl_remove,
 	.priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
 	.ops = &imx_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 0 - 1
drivers/pinctrl/pinctrl-single.c

@@ -136,7 +136,6 @@ U_BOOT_DRIVER(single_pinctrl) = {
 	.id = UCLASS_PINCTRL,
 	.of_match = single_pinctrl_match,
 	.ops = &single_pinctrl_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 	.platdata_auto_alloc_size = sizeof(struct single_pdata),
 	.ofdata_to_platdata = single_ofdata_to_platdata,
 };

+ 2 - 0
drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c

@@ -171,5 +171,7 @@ U_BOOT_DRIVER(uniphier_pro4_pinctrl) = {
 	.probe = uniphier_pro4_pinctrl_probe,
 	.priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
 	.ops = &uniphier_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 2 - 0
drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c

@@ -153,5 +153,7 @@ U_BOOT_DRIVER(uniphier_pro5_pinctrl) = {
 	.probe = uniphier_pro5_pinctrl_probe,
 	.priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
 	.ops = &uniphier_pinctrl_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };

+ 0 - 1
drivers/ram/bmips_ram.c

@@ -173,5 +173,4 @@ U_BOOT_DRIVER(bmips_ram) = {
 	.probe = bmips_ram_probe,
 	.priv_auto_alloc_size = sizeof(struct bmips_ram_priv),
 	.ops = &bmips_ram_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/scsi/scsi.c

@@ -592,7 +592,6 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
 	memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
 	memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
 	memcpy(&bdesc->revision, &bd.revision,	sizeof(bd.revision));
-	part_init(bdesc);
 
 	if (verbose) {
 		printf("  Device %d: ", 0);

+ 0 - 1
drivers/serial/altera_jtag_uart.c

@@ -121,7 +121,6 @@ U_BOOT_DRIVER(altera_jtaguart) = {
 	.platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata),
 	.probe = altera_jtaguart_probe,
 	.ops	= &altera_jtaguart_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART

+ 0 - 1
drivers/serial/altera_uart.c

@@ -117,7 +117,6 @@ U_BOOT_DRIVER(altera_uart) = {
 	.platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
 	.probe = altera_uart_probe,
 	.ops	= &altera_uart_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_UART_ALTERA_UART

+ 0 - 1
drivers/serial/arm_dcc.c

@@ -155,7 +155,6 @@ U_BOOT_DRIVER(serial_dcc) = {
 	.id	= UCLASS_SERIAL,
 	.of_match = arm_dcc_ids,
 	.ops	= &arm_dcc_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_UART_ARM_DCC

+ 2 - 0
drivers/serial/atmel_usart.c

@@ -294,7 +294,9 @@ U_BOOT_DRIVER(serial_atmel) = {
 #endif
 	.probe = atmel_serial_probe,
 	.ops	= &atmel_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 	.priv_auto_alloc_size	= sizeof(struct atmel_serial_priv),
 };
 #endif

+ 18 - 2
drivers/serial/ns16550.c

@@ -267,12 +267,26 @@ static inline void _debug_uart_init(void)
 	serial_dout(&com_port->lcr, UART_LCRVAL);
 }
 
+static inline int NS16550_read_baud_divisor(struct NS16550 *com_port)
+{
+	int ret;
+
+	serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
+	ret = serial_din(&com_port->dll) & 0xff;
+	ret |= (serial_din(&com_port->dlm) & 0xff) << 8;
+	serial_dout(&com_port->lcr, UART_LCRVAL);
+
+	return ret;
+}
+
 static inline void _debug_uart_putc(int ch)
 {
 	struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
 
-	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE))
-		;
+	while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) {
+		if (!NS16550_read_baud_divisor(com_port))
+			return;
+	}
 	serial_dout(&com_port->thr, ch);
 }
 
@@ -473,7 +487,9 @@ U_BOOT_DRIVER(ns16550_serial) = {
 	.priv_auto_alloc_size = sizeof(struct NS16550),
 	.probe = ns16550_serial_probe,
 	.ops	= &ns16550_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags	= DM_FLAG_PRE_RELOC,
+#endif
 };
 #endif
 #endif /* SERIAL_PRESENT */

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

@@ -62,7 +62,7 @@ static int serial_check_stdout(const void *blob, struct udevice **devp)
 	 * anyway.
 	 */
 	if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
-					devp)) {
+					devp, false)) {
 		if (!device_probe(*devp))
 			return 0;
 	}

+ 0 - 1
drivers/serial/serial_ar933x.c

@@ -189,7 +189,6 @@ U_BOOT_DRIVER(serial_ar933x) = {
 	.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
 	.probe = ar933x_serial_probe,
 	.ops    = &ar933x_serial_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_UART_AR933X

+ 0 - 1
drivers/serial/serial_arc.c

@@ -128,7 +128,6 @@ U_BOOT_DRIVER(serial_arc) = {
 	.ofdata_to_platdata = arc_serial_ofdata_to_platdata,
 	.probe = arc_serial_probe,
 	.ops	= &arc_serial_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_ARC_SERIAL

+ 2 - 0
drivers/serial/serial_bcm283x_mu.c

@@ -199,6 +199,8 @@ U_BOOT_DRIVER(serial_bcm283x_mu) = {
 	.platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
 	.probe = bcm283x_mu_serial_probe,
 	.ops = &bcm283x_mu_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 	.priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
 };

+ 2 - 0
drivers/serial/serial_bcm283x_pl011.c

@@ -90,6 +90,8 @@ U_BOOT_DRIVER(bcm283x_pl011_uart) = {
 	.platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
 	.probe	= pl01x_serial_probe,
 	.ops	= &bcm283x_pl011_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags	= DM_FLAG_PRE_RELOC,
+#endif
 	.priv_auto_alloc_size = sizeof(struct pl01x_priv),
 };

+ 0 - 1
drivers/serial/serial_bcm6345.c

@@ -264,7 +264,6 @@ U_BOOT_DRIVER(bcm6345_serial) = {
 	.probe = bcm6345_serial_probe,
 	.priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
 	.ops = &bcm6345_serial_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_UART_BCM6345

+ 0 - 1
drivers/serial/serial_efi.c

@@ -152,5 +152,4 @@ U_BOOT_DRIVER(serial_efi) = {
 	.priv_auto_alloc_size = sizeof(struct serial_efi_priv),
 	.probe = serial_efi_probe,
 	.ops	= &serial_efi_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/serial/serial_intel_mid.c

@@ -64,5 +64,4 @@ U_BOOT_DRIVER(serial_intel_mid) = {
 	.priv_auto_alloc_size = sizeof(struct NS16550),
 	.probe	= mid_serial_probe,
 	.ops	= &ns16550_serial_ops,
-	.flags	= DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/serial/serial_lpuart.c

@@ -540,5 +540,4 @@ U_BOOT_DRIVER(serial_lpuart) = {
 	.platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
 	.probe = lpuart_serial_probe,
 	.ops	= &lpuart_serial_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

+ 0 - 1
drivers/serial/serial_meson.c

@@ -132,7 +132,6 @@ U_BOOT_DRIVER(serial_meson) = {
 	.of_match	= meson_serial_ids,
 	.probe		= meson_serial_probe,
 	.ops		= &meson_serial_ops,
-	.flags		= DM_FLAG_PRE_RELOC,
 	.ofdata_to_platdata = meson_serial_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
 };

+ 0 - 1
drivers/serial/serial_mvebu_a3700.c

@@ -129,7 +129,6 @@ U_BOOT_DRIVER(serial_mvebu) = {
 	.platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
 	.probe	= mvebu_serial_probe,
 	.ops	= &mvebu_serial_ops,
-	.flags	= DM_FLAG_PRE_RELOC,
 };
 
 #ifdef CONFIG_DEBUG_MVEBU_A3700_UART

+ 2 - 0
drivers/serial/serial_mxc.c

@@ -354,7 +354,9 @@ U_BOOT_DRIVER(serial_mxc) = {
 #endif
 	.probe = mxc_serial_probe,
 	.ops	= &mxc_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags = DM_FLAG_PRE_RELOC,
+#endif
 };
 #endif
 

+ 2 - 0
drivers/serial/serial_omap.c

@@ -121,7 +121,9 @@ U_BOOT_DRIVER(omap_serial) = {
 	.priv_auto_alloc_size = sizeof(struct NS16550),
 	.probe = ns16550_serial_probe,
 	.ops	= &ns16550_serial_ops,
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 	.flags	= DM_FLAG_PRE_RELOC,
+#endif
 };
 #endif
 #endif /* DM_SERIAL */

+ 0 - 1
drivers/serial/serial_owl.c

@@ -132,5 +132,4 @@ U_BOOT_DRIVER(serial_owl) = {
 	.priv_auto_alloc_size =	sizeof(struct owl_serial_priv),
 	.probe = owl_serial_probe,
 	.ops = &owl_serial_ops,
-	.flags = DM_FLAG_PRE_RELOC,
 };

部分文件因文件數量過多而無法顯示