aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt19
-rw-r--r--Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt19
-rw-r--r--Documentation/devicetree/bindings/misc/gdsys,soc.txt16
-rw-r--r--arch/Kconfig6
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/mach-stm32mp/bsec.c1
-rw-r--r--arch/mips/include/asm/io.h22
-rw-r--r--arch/riscv/lib/bootm.c11
-rw-r--r--arch/sandbox/cpu/os.c7
-rw-r--r--arch/sandbox/dts/test.dts17
-rw-r--r--arch/x86/cpu/baytrail/cpu.c1
-rw-r--r--arch/x86/cpu/broadwell/cpu.c1
-rw-r--r--arch/x86/cpu/cpu_x86.c1
-rw-r--r--arch/x86/cpu/ivybridge/model_206ax.c1
-rw-r--r--arch/x86/cpu/tangier/sysreset.c1
-rw-r--r--arch/x86/include/asm/io.h66
-rw-r--r--board/emulation/qemu-arm/Kconfig13
-rw-r--r--board/emulation/qemu-arm/qemu-arm.c10
-rw-r--r--board/emulation/qemu-riscv/Kconfig11
-rw-r--r--board/emulation/qemu-riscv/qemu-riscv.c9
-rw-r--r--board/emulation/qemu-x86/Kconfig3
-rw-r--r--cmd/Kconfig7
-rw-r--r--cmd/Makefile1
-rw-r--r--cmd/sata.c9
-rw-r--r--cmd/virtio.c38
-rw-r--r--common/board_f.c28
-rw-r--r--common/usb_storage.c4
-rw-r--r--configs/imx8qxp_mek_defconfig1
-rw-r--r--configs/qemu_arm64_defconfig1
-rw-r--r--configs/qemu_arm_defconfig1
-rw-r--r--configs/sandbox_noblk_defconfig1
-rw-r--r--disk/part.c6
-rw-r--r--doc/README.virtio253
-rw-r--r--doc/driver-model/README.txt16
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/block/blk-uclass.c25
-rw-r--r--drivers/block/ide.c2
-rw-r--r--drivers/block/sandbox.c17
-rw-r--r--drivers/clk/altera/clk-arria10.c1
-rw-r--r--drivers/clk/clk_pic32.c1
-rw-r--r--drivers/clk/clk_zynq.c1
-rw-r--r--drivers/clk/exynos/clk-exynos7420.c3
-rw-r--r--drivers/clk/owl/clk_s900.c1
-rw-r--r--drivers/core/device.c2
-rw-r--r--drivers/core/dump.c2
-rw-r--r--drivers/core/lists.c9
-rw-r--r--drivers/core/ofnode.c4
-rw-r--r--drivers/core/regmap.c316
-rw-r--r--drivers/core/root.c20
-rw-r--r--drivers/core/uclass.c31
-rw-r--r--drivers/core/util.c25
-rw-r--r--drivers/cpu/mpc83xx_cpu.c2
-rw-r--r--drivers/gpio/omap_gpio.c2
-rw-r--r--drivers/gpio/stm32f7_gpio.c2
-rw-r--r--drivers/gpio/tegra186_gpio.c1
-rw-r--r--drivers/gpio/tegra_gpio.c1
-rw-r--r--drivers/i2c/omap24xx_i2c.c2
-rw-r--r--drivers/misc/Kconfig17
-rw-r--r--drivers/misc/Makefile63
-rw-r--r--drivers/misc/gdsys_soc.c74
-rw-r--r--drivers/misc/gdsys_soc.h23
-rw-r--r--drivers/misc/ihs_fpga.c867
-rw-r--r--drivers/misc/ihs_fpga.h49
-rw-r--r--drivers/misc/imx8/scu.c4
-rw-r--r--drivers/misc/swap_case.c9
-rw-r--r--drivers/mmc/mmc.c3
-rw-r--r--drivers/mmc/omap_hsmmc.c2
-rw-r--r--drivers/nvme/nvme.c1
-rw-r--r--drivers/pci/pci-uclass.c51
-rw-r--r--drivers/pinctrl/broadcom/pinctrl-bcm283x.c2
-rw-r--r--drivers/pinctrl/exynos/pinctrl-exynos7420.c1
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx5.c2
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx6.c2
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx7.c2
-rw-r--r--drivers/pinctrl/nxp/pinctrl-imx7ulp.c2
-rw-r--r--drivers/pinctrl/pinctrl-single.c1
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c2
-rw-r--r--drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c2
-rw-r--r--drivers/ram/bmips_ram.c1
-rw-r--r--drivers/scsi/scsi.c1
-rw-r--r--drivers/serial/altera_jtag_uart.c1
-rw-r--r--drivers/serial/altera_uart.c1
-rw-r--r--drivers/serial/arm_dcc.c1
-rw-r--r--drivers/serial/atmel_usart.c2
-rw-r--r--drivers/serial/ns16550.c20
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/serial/serial_ar933x.c1
-rw-r--r--drivers/serial/serial_arc.c1
-rw-r--r--drivers/serial/serial_bcm283x_mu.c2
-rw-r--r--drivers/serial/serial_bcm283x_pl011.c2
-rw-r--r--drivers/serial/serial_bcm6345.c1
-rw-r--r--drivers/serial/serial_efi.c1
-rw-r--r--drivers/serial/serial_intel_mid.c1
-rw-r--r--drivers/serial/serial_lpuart.c1
-rw-r--r--drivers/serial/serial_meson.c1
-rw-r--r--drivers/serial/serial_mvebu_a3700.c1
-rw-r--r--drivers/serial/serial_mxc.c2
-rw-r--r--drivers/serial/serial_omap.c2
-rw-r--r--drivers/serial/serial_owl.c1
-rw-r--r--drivers/serial/serial_pic32.c1
-rw-r--r--drivers/serial/serial_pl01x.c2
-rw-r--r--drivers/serial/serial_s5p.c1
-rw-r--r--drivers/serial/serial_sh.c2
-rw-r--r--drivers/serial/serial_sti_asc.c1
-rw-r--r--drivers/serial/serial_stm32.c2
-rw-r--r--drivers/serial/serial_xuartlite.c1
-rw-r--r--drivers/serial/serial_zynq.c1
-rw-r--r--drivers/sysreset/sysreset_x86.c1
-rw-r--r--drivers/timer/Kconfig110
-rw-r--r--drivers/timer/ag101p_timer.c1
-rw-r--r--drivers/timer/altera_timer.c1
-rw-r--r--drivers/timer/arc_timer.c1
-rw-r--r--drivers/timer/ast_timer.c1
-rw-r--r--drivers/timer/atcpit100_timer.c1
-rw-r--r--drivers/timer/atmel_pit_timer.c1
-rw-r--r--drivers/timer/cadence-ttc.c1
-rw-r--r--drivers/timer/dw-apb-timer.c1
-rw-r--r--drivers/timer/mpc83xx_timer.c1
-rw-r--r--drivers/timer/omap-timer.c1
-rw-r--r--drivers/timer/rockchip_timer.c1
-rw-r--r--drivers/timer/sti-timer.c1
-rw-r--r--drivers/timer/stm32_timer.c1
-rw-r--r--drivers/timer/timer-uclass.c2
-rw-r--r--drivers/timer/tsc_timer.c1
-rw-r--r--drivers/video/simplefb.c1
-rw-r--r--drivers/virtio/Kconfig62
-rw-r--r--drivers/virtio/Makefile11
-rw-r--r--drivers/virtio/virtio-uclass.c369
-rw-r--r--drivers/virtio/virtio_blk.c137
-rw-r--r--drivers/virtio/virtio_blk.h129
-rw-r--r--drivers/virtio/virtio_mmio.c413
-rw-r--r--drivers/virtio/virtio_mmio.h129
-rw-r--r--drivers/virtio/virtio_net.c239
-rw-r--r--drivers/virtio/virtio_net.h268
-rw-r--r--drivers/virtio/virtio_pci.h173
-rw-r--r--drivers/virtio/virtio_pci_legacy.c421
-rw-r--r--drivers/virtio/virtio_pci_modern.c609
-rw-r--r--drivers/virtio/virtio_ring.c358
-rw-r--r--drivers/virtio/virtio_sandbox.c233
-rw-r--r--drivers/watchdog/ast_wdt.c1
-rw-r--r--include/blk.h22
-rw-r--r--include/dm/device-internal.h4
-rw-r--r--include/dm/lists.h9
-rw-r--r--include/dm/root.h17
-rw-r--r--include/dm/test.h1
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/dm/uclass.h4
-rw-r--r--include/dm/util.h27
-rw-r--r--include/init.h7
-rw-r--r--include/linux/io.h4
-rw-r--r--include/pci.h48
-rw-r--r--include/regmap.h232
-rw-r--r--include/virtio.h707
-rw-r--r--include/virtio_ring.h320
-rw-r--r--include/virtio_types.h24
-rw-r--r--lib/Kconfig6
-rw-r--r--lib/efi/efi_app.c1
-rw-r--r--lib/efi_driver/efi_block_device.c26
-rw-r--r--test/dm/Makefile1
-rw-r--r--test/dm/blk.c27
-rw-r--r--test/dm/bus.c47
-rw-r--r--test/dm/pci.c20
-rw-r--r--test/dm/regmap.c30
-rw-r--r--test/dm/test-fdt.c36
-rw-r--r--test/dm/virtio.c122
-rw-r--r--tools/buildman/README12
-rw-r--r--tools/buildman/board.py28
-rw-r--r--tools/buildman/cmdline.py4
-rw-r--r--tools/buildman/control.py20
-rw-r--r--tools/buildman/test.py31
171 files changed, 7486 insertions, 343 deletions
diff --git a/Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt b/Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt
new file mode 100644
index 0000000000..acd466fdc6
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/gdsys,iocon_fpga.txt
@@ -0,0 +1,19 @@
1gdsys IHS FPGA for CON devices
2
3The gdsys IHS FPGA is the main FPGA on gdsys CON devices. This driver provides
4support for enabling and starting the FPGA, as well as verifying working bus
5communication.
6
7Required properties:
8- compatible: must be "gdsys,iocon_fpga"
9- reset-gpios: List of GPIOs controlling the FPGA's reset
10- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
11 done
12
13Example:
14
15FPGA0 {
16 compatible = "gdsys,iocon_fpga";
17 reset-gpios = <&PPCPCA 26 0>;
18 done-gpios = <&GPIO_VB0 19 0>;
19};
diff --git a/Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt b/Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt
new file mode 100644
index 0000000000..819db22bf7
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/gdsys,iocpu_fpga.txt
@@ -0,0 +1,19 @@
1gdsys IHS FPGA for CPU devices
2
3The gdsys IHS FPGA is the main FPGA on gdsys CPU devices. This driver provides
4support for enabling and starting the FPGA, as well as verifying working bus
5communication.
6
7Required properties:
8- compatible: must be "gdsys,iocpu_fpga"
9- reset-gpios: List of GPIOs controlling the FPGA's reset
10- done-gpios: List of GPIOs notifying whether the FPGA's reconfiguration is
11 done
12
13Example:
14
15FPGA0 {
16 compatible = "gdsys,iocpu_fpga";
17 reset-gpios = <&PPCPCA 26 0>;
18 done-gpios = <&GPIO_VB0 19 0>;
19};
diff --git a/Documentation/devicetree/bindings/misc/gdsys,soc.txt b/Documentation/devicetree/bindings/misc/gdsys,soc.txt
new file mode 100644
index 0000000000..278e935b16
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/gdsys,soc.txt
@@ -0,0 +1,16 @@
1gdsys soc bus driver
2
3This driver provides a simple interface for the busses associated with gdsys
4IHS FPGAs. The bus itself contains devices whose register maps are contained
5within the FPGA's register space.
6
7Required properties:
8- fpga: A phandle to the controlling IHS FPGA
9
10Example:
11
12FPGA0BUS: fpga0bus {
13 compatible = "gdsys,soc";
14 ranges = <0x0 0xe0600000 0x00004000>;
15 fpga = <&FPGA0>;
16};
diff --git a/arch/Kconfig b/arch/Kconfig
index 1f2f407d64..9fdd2f7e66 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -110,6 +110,11 @@ config SANDBOX
110 imply LIBAVB 110 imply LIBAVB
111 imply CMD_AVB 111 imply CMD_AVB
112 imply UDP_FUNCTION_FASTBOOT 112 imply UDP_FUNCTION_FASTBOOT
113 imply VIRTIO_MMIO
114 imply VIRTIO_PCI
115 imply VIRTIO_SANDBOX
116 imply VIRTIO_BLK
117 imply VIRTIO_NET
113 118
114config SH 119config SH
115 bool "SuperH architecture" 120 bool "SuperH architecture"
@@ -120,6 +125,7 @@ config X86
120 select CREATE_ARCH_SYMLINK 125 select CREATE_ARCH_SYMLINK
121 select DM 126 select DM
122 select DM_PCI 127 select DM_PCI
128 select HAVE_ARCH_IOMAP
123 select HAVE_PRIVATE_LIBGCC 129 select HAVE_PRIVATE_LIBGCC
124 select OF_CONTROL 130 select OF_CONTROL
125 select PCI 131 select PCI
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 2899a60793..f0e7fde137 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1496,6 +1496,7 @@ source "board/broadcom/bcmns2/Kconfig"
1496source "board/cavium/thunderx/Kconfig" 1496source "board/cavium/thunderx/Kconfig"
1497source "board/cirrus/edb93xx/Kconfig" 1497source "board/cirrus/edb93xx/Kconfig"
1498source "board/eets/pdu001/Kconfig" 1498source "board/eets/pdu001/Kconfig"
1499source "board/emulation/qemu-arm/Kconfig"
1499source "board/freescale/ls2080a/Kconfig" 1500source "board/freescale/ls2080a/Kconfig"
1500source "board/freescale/ls2080aqds/Kconfig" 1501source "board/freescale/ls2080aqds/Kconfig"
1501source "board/freescale/ls2080ardb/Kconfig" 1502source "board/freescale/ls2080ardb/Kconfig"
diff --git a/arch/arm/mach-stm32mp/bsec.c b/arch/arm/mach-stm32mp/bsec.c
index 0e152efc04..d087a31389 100644
--- a/arch/arm/mach-stm32mp/bsec.c
+++ b/arch/arm/mach-stm32mp/bsec.c
@@ -417,7 +417,6 @@ U_BOOT_DRIVER(stm32mp_bsec) = {
417 .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata, 417 .ofdata_to_platdata = stm32mp_bsec_ofdata_to_platdata,
418 .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata), 418 .platdata_auto_alloc_size = sizeof(struct stm32mp_bsec_platdata),
419 .ops = &stm32mp_bsec_ops, 419 .ops = &stm32mp_bsec_ops,
420 .flags = DM_FLAG_PRE_RELOC,
421}; 420};
422 421
423/* bsec IP is not present in device tee, manage IP address by platdata */ 422/* bsec IP is not present in device tee, manage IP address by platdata */
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 957442effd..7c40e415c7 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -547,6 +547,28 @@ __BUILD_CLRSETBITS(bwlq, sfx, end, type)
547#define __to_cpu(v) (v) 547#define __to_cpu(v) (v)
548#define cpu_to__(v) (v) 548#define cpu_to__(v) (v)
549 549
550#define out_arch(type, endian, a, v) __raw_write##type(cpu_to_##endian(v),a)
551#define in_arch(type, endian, a) endian##_to_cpu(__raw_read##type(a))
552
553#define out_le64(a, v) out_arch(q, le64, a, v)
554#define out_le32(a, v) out_arch(l, le32, a, v)
555#define out_le16(a, v) out_arch(w, le16, a, v)
556
557#define in_le64(a) in_arch(q, le64, a)
558#define in_le32(a) in_arch(l, le32, a)
559#define in_le16(a) in_arch(w, le16, a)
560
561#define out_be64(a, v) out_arch(q, be64, a, v)
562#define out_be32(a, v) out_arch(l, be32, a, v)
563#define out_be16(a, v) out_arch(w, be16, a, v)
564
565#define in_be64(a) in_arch(q, be64, a)
566#define in_be32(a) in_arch(l, be32, a)
567#define in_be16(a) in_arch(w, be16, a)
568
569#define out_8(a, v) __raw_writeb(v, a)
570#define in_8(a) __raw_readb(a)
571
550BUILD_CLRSETBITS(b, 8, _, u8) 572BUILD_CLRSETBITS(b, 8, _, u8)
551BUILD_CLRSETBITS(w, le16, le16, u16) 573BUILD_CLRSETBITS(w, le16, le16, u16)
552BUILD_CLRSETBITS(w, be16, be16, u16) 574BUILD_CLRSETBITS(w, be16, be16, u16)
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index a7a9fb921b..2b5ccce933 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -9,9 +9,11 @@
9#include <common.h> 9#include <common.h>
10#include <command.h> 10#include <command.h>
11#include <image.h> 11#include <image.h>
12#include <u-boot/zlib.h>
13#include <asm/byteorder.h> 12#include <asm/byteorder.h>
14#include <asm/csr.h> 13#include <asm/csr.h>
14#include <dm/device.h>
15#include <dm/root.h>
16#include <u-boot/zlib.h>
15 17
16DECLARE_GLOBAL_DATA_PTR; 18DECLARE_GLOBAL_DATA_PTR;
17 19
@@ -57,6 +59,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
57 /* we assume that the kernel is in place */ 59 /* we assume that the kernel is in place */
58 printf("\nStarting kernel ...\n\n"); 60 printf("\nStarting kernel ...\n\n");
59 61
62 /*
63 * Call remove function of all devices with a removal flag set.
64 * This may be useful for last-stage operations, like cancelling
65 * of DMA operation or releasing device internal buffers.
66 */
67 dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
68
60 cleanup_before_linux(); 69 cleanup_before_linux();
61 70
62 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 71 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 07e46471fe..325ded51d8 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -174,7 +174,12 @@ void *os_malloc(size_t length)
174 struct os_mem_hdr *hdr; 174 struct os_mem_hdr *hdr;
175 int page_size = getpagesize(); 175 int page_size = getpagesize();
176 176
177 hdr = mmap(NULL, length + page_size, 177 /*
178 * Use an address that is hopefully available to us so that pointers
179 * to this memory are fairly obvious. If we end up with a different
180 * address, that's fine too.
181 */
182 hdr = mmap((void *)0x10000000, length + page_size,
178 PROT_READ | PROT_WRITE | PROT_EXEC, 183 PROT_READ | PROT_WRITE | PROT_EXEC,
179 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 184 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
180 if (hdr == MAP_FAILED) 185 if (hdr == MAP_FAILED)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 57e0dd7663..024aa7c512 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -186,6 +186,10 @@
186 compatible = "denx,u-boot-fdt-test"; 186 compatible = "denx,u-boot-fdt-test";
187 }; 187 };
188 188
189 h-test {
190 compatible = "denx,u-boot-fdt-test1";
191 };
192
189 clocks { 193 clocks {
190 clk_fixed: clk-fixed { 194 clk_fixed: clk-fixed {
191 compatible = "fixed-clock"; 195 compatible = "fixed-clock";
@@ -346,14 +350,17 @@
346 350
347 cpu-test1 { 351 cpu-test1 {
348 compatible = "sandbox,cpu_sandbox"; 352 compatible = "sandbox,cpu_sandbox";
353 u-boot,dm-pre-reloc;
349 }; 354 };
350 355
351 cpu-test2 { 356 cpu-test2 {
352 compatible = "sandbox,cpu_sandbox"; 357 compatible = "sandbox,cpu_sandbox";
358 u-boot,dm-pre-reloc;
353 }; 359 };
354 360
355 cpu-test3 { 361 cpu-test3 {
356 compatible = "sandbox,cpu_sandbox"; 362 compatible = "sandbox,cpu_sandbox";
363 u-boot,dm-pre-reloc;
357 }; 364 };
358 365
359 misc-test { 366 misc-test {
@@ -525,7 +532,7 @@
525 532
526 syscon@0 { 533 syscon@0 {
527 compatible = "sandbox,syscon0"; 534 compatible = "sandbox,syscon0";
528 reg = <0x10 4>; 535 reg = <0x10 16>;
529 }; 536 };
530 537
531 syscon@1 { 538 syscon@1 {
@@ -712,6 +719,14 @@
712 sandbox_tee { 719 sandbox_tee {
713 compatible = "sandbox,tee"; 720 compatible = "sandbox,tee";
714 }; 721 };
722
723 sandbox_virtio1 {
724 compatible = "sandbox,virtio1";
725 };
726
727 sandbox_virtio2 {
728 compatible = "sandbox,virtio2";
729 };
715}; 730};
716 731
717#include "sandbox_pmic.dtsi" 732#include "sandbox_pmic.dtsi"
diff --git a/arch/x86/cpu/baytrail/cpu.c b/arch/x86/cpu/baytrail/cpu.c
index 56e98131d7..2eb917283b 100644
--- a/arch/x86/cpu/baytrail/cpu.c
+++ b/arch/x86/cpu/baytrail/cpu.c
@@ -203,4 +203,5 @@ U_BOOT_DRIVER(cpu_x86_baytrail_drv) = {
203 .bind = cpu_x86_bind, 203 .bind = cpu_x86_bind,
204 .probe = cpu_x86_baytrail_probe, 204 .probe = cpu_x86_baytrail_probe,
205 .ops = &cpu_x86_baytrail_ops, 205 .ops = &cpu_x86_baytrail_ops,
206 .flags = DM_FLAG_PRE_RELOC,
206}; 207};
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c
index 02b3169cf5..232fa40eb5 100644
--- a/arch/x86/cpu/broadwell/cpu.c
+++ b/arch/x86/cpu/broadwell/cpu.c
@@ -764,4 +764,5 @@ U_BOOT_DRIVER(cpu_x86_broadwell_drv) = {
764 .probe = cpu_x86_broadwell_probe, 764 .probe = cpu_x86_broadwell_probe,
765 .ops = &cpu_x86_broadwell_ops, 765 .ops = &cpu_x86_broadwell_ops,
766 .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv), 766 .priv_auto_alloc_size = sizeof(struct cpu_broadwell_priv),
767 .flags = DM_FLAG_PRE_RELOC,
767}; 768};
diff --git a/arch/x86/cpu/cpu_x86.c b/arch/x86/cpu/cpu_x86.c
index 2b6cc9f22d..1aaf851bb4 100644
--- a/arch/x86/cpu/cpu_x86.c
+++ b/arch/x86/cpu/cpu_x86.c
@@ -94,4 +94,5 @@ U_BOOT_DRIVER(cpu_x86_drv) = {
94 .of_match = cpu_x86_ids, 94 .of_match = cpu_x86_ids,
95 .bind = cpu_x86_bind, 95 .bind = cpu_x86_bind,
96 .ops = &cpu_x86_ops, 96 .ops = &cpu_x86_ops,
97 .flags = DM_FLAG_PRE_RELOC,
97}; 98};
diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c
index 33e5c6263d..6edc3e233c 100644
--- a/arch/x86/cpu/ivybridge/model_206ax.c
+++ b/arch/x86/cpu/ivybridge/model_206ax.c
@@ -478,4 +478,5 @@ U_BOOT_DRIVER(cpu_x86_model_206ax_drv) = {
478 .bind = cpu_x86_bind, 478 .bind = cpu_x86_bind,
479 .probe = cpu_x86_model_206ax_probe, 479 .probe = cpu_x86_model_206ax_probe,
480 .ops = &cpu_x86_model_206ax_ops, 480 .ops = &cpu_x86_model_206ax_ops,
481 .flags = DM_FLAG_PRE_RELOC,
481}; 482};
diff --git a/arch/x86/cpu/tangier/sysreset.c b/arch/x86/cpu/tangier/sysreset.c
index e762ee1b81..b03bc28f93 100644
--- a/arch/x86/cpu/tangier/sysreset.c
+++ b/arch/x86/cpu/tangier/sysreset.c
@@ -44,5 +44,4 @@ U_BOOT_DRIVER(tangier_sysreset) = {
44 .id = UCLASS_SYSRESET, 44 .id = UCLASS_SYSRESET,
45 .of_match = tangier_sysreset_ids, 45 .of_match = tangier_sysreset_ids,
46 .ops = &tangier_sysreset_ops, 46 .ops = &tangier_sysreset_ops,
47 .flags = DM_FLAG_PRE_RELOC,
48}; 47};
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index c05c6bf8a2..81def0afd3 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -241,6 +241,72 @@ static inline void sync(void)
241#define __iormb() dmb() 241#define __iormb() dmb()
242#define __iowmb() dmb() 242#define __iowmb() dmb()
243 243
244/*
245 * Read/write from/to an (offsettable) iomem cookie. It might be a PIO
246 * access or a MMIO access, these functions don't care. The info is
247 * encoded in the hardware mapping set up by the mapping functions
248 * (or the cookie itself, depending on implementation and hw).
249 *
250 * The generic routines don't assume any hardware mappings, and just
251 * encode the PIO/MMIO as part of the cookie. They coldly assume that
252 * the MMIO IO mappings are not in the low address range.
253 *
254 * Architectures for which this is not true can't use this generic
255 * implementation and should do their own copy.
256 */
257
258/*
259 * We assume that all the low physical PIO addresses (0-0xffff) always
260 * PIO. That means we can do some sanity checks on the low bits, and
261 * don't need to just take things for granted.
262 */
263#define PIO_RESERVED 0x10000UL
264
265/*
266 * Ugly macros are a way of life.
267 */
268#define IO_COND(addr, is_pio, is_mmio) do { \
269 unsigned long port = (unsigned long __force)addr; \
270 if (port >= PIO_RESERVED) { \
271 is_mmio; \
272 } else { \
273 is_pio; \
274 } \
275} while (0)
276
277static inline u8 ioread8(const volatile void __iomem *addr)
278{
279 IO_COND(addr, return inb(port), return readb(addr));
280 return 0xff;
281}
282
283static inline u16 ioread16(const volatile void __iomem *addr)
284{
285 IO_COND(addr, return inw(port), return readw(addr));
286 return 0xffff;
287}
288
289static inline u32 ioread32(const volatile void __iomem *addr)
290{
291 IO_COND(addr, return inl(port), return readl(addr));
292 return 0xffffffff;
293}
294
295static inline void iowrite8(u8 value, volatile void __iomem *addr)
296{
297 IO_COND(addr, outb(value, port), writeb(value, addr));
298}
299
300static inline void iowrite16(u16 value, volatile void __iomem *addr)
301{
302 IO_COND(addr, outw(value, port), writew(value, addr));
303}
304
305static inline void iowrite32(u32 value, volatile void __iomem *addr)
306{
307 IO_COND(addr, outl(value, port), writel(value, addr));
308}
309
244#include <asm-generic/io.h> 310#include <asm-generic/io.h>
245 311
246#endif /* _ASM_IO_H */ 312#endif /* _ASM_IO_H */
diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig
new file mode 100644
index 0000000000..02ae4d9884
--- /dev/null
+++ b/board/emulation/qemu-arm/Kconfig
@@ -0,0 +1,13 @@
1if TARGET_QEMU_ARM_32BIT || TARGET_QEMU_ARM_64BIT
2
3config SYS_TEXT_BASE
4 default 0x00000000
5
6config BOARD_SPECIFIC_OPTIONS # dummy
7 def_bool y
8 imply VIRTIO_MMIO
9 imply VIRTIO_PCI
10 imply VIRTIO_NET
11 imply VIRTIO_BLK
12
13endif
diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c
index 812c90636d..e1f4709c4c 100644
--- a/board/emulation/qemu-arm/qemu-arm.c
+++ b/board/emulation/qemu-arm/qemu-arm.c
@@ -2,8 +2,12 @@
2/* 2/*
3 * Copyright (c) 2017 Tuomas Tynkkynen 3 * Copyright (c) 2017 Tuomas Tynkkynen
4 */ 4 */
5
5#include <common.h> 6#include <common.h>
7#include <dm.h>
6#include <fdtdec.h> 8#include <fdtdec.h>
9#include <virtio_types.h>
10#include <virtio.h>
7 11
8#ifdef CONFIG_ARM64 12#ifdef CONFIG_ARM64
9#include <asm/armv8/mmu.h> 13#include <asm/armv8/mmu.h>
@@ -58,6 +62,12 @@ struct mm_region *mem_map = qemu_arm64_mem_map;
58 62
59int board_init(void) 63int board_init(void)
60{ 64{
65 /*
66 * Make sure virtio bus is enumerated so that peripherals
67 * on the virtio bus can be discovered by their drivers
68 */
69 virtio_init();
70
61 return 0; 71 return 0;
62} 72}
63 73
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig
index af23363fcf..37a80db6a9 100644
--- a/board/emulation/qemu-riscv/Kconfig
+++ b/board/emulation/qemu-riscv/Kconfig
@@ -18,5 +18,16 @@ config SYS_TEXT_BASE
18config BOARD_SPECIFIC_OPTIONS # dummy 18config BOARD_SPECIFIC_OPTIONS # dummy
19 def_bool y 19 def_bool y
20 imply SYS_NS16550 20 imply SYS_NS16550
21 imply VIRTIO_MMIO
22 imply VIRTIO_NET
23 imply VIRTIO_BLK
24 imply CMD_PING
25 imply CMD_FS_GENERIC
26 imply DOS_PARTITION
27 imply EFI_PARTITION
28 imply ISO_PARTITION
29 imply CMD_EXT2
30 imply CMD_EXT4
31 imply CMD_FAT
21 32
22endif 33endif
diff --git a/board/emulation/qemu-riscv/qemu-riscv.c b/board/emulation/qemu-riscv/qemu-riscv.c
index 041e716c9b..2730a288fb 100644
--- a/board/emulation/qemu-riscv/qemu-riscv.c
+++ b/board/emulation/qemu-riscv/qemu-riscv.c
@@ -4,12 +4,21 @@
4 */ 4 */
5 5
6#include <common.h> 6#include <common.h>
7#include <dm.h>
7#include <fdtdec.h> 8#include <fdtdec.h>
9#include <virtio_types.h>
10#include <virtio.h>
8 11
9#define MROM_FDT_ADDR 0x1020 12#define MROM_FDT_ADDR 0x1020
10 13
11int board_init(void) 14int board_init(void)
12{ 15{
16 /*
17 * Make sure virtio bus is enumerated so that peripherals
18 * on the virtio bus can be discovered by their drivers
19 */
20 virtio_init();
21
13 return 0; 22 return 0;
14} 23}
15 24
diff --git a/board/emulation/qemu-x86/Kconfig b/board/emulation/qemu-x86/Kconfig
index 41a27dd933..6d19299d8b 100644
--- a/board/emulation/qemu-x86/Kconfig
+++ b/board/emulation/qemu-x86/Kconfig
@@ -21,5 +21,8 @@ config BOARD_SPECIFIC_OPTIONS # dummy
21 select X86_RESET_VECTOR 21 select X86_RESET_VECTOR
22 select QEMU 22 select QEMU
23 select BOARD_ROMSIZE_KB_1024 23 select BOARD_ROMSIZE_KB_1024
24 imply VIRTIO_PCI
25 imply VIRTIO_NET
26 imply VIRTIO_BLK
24 27
25endif 28endif
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ad14c9ce71..d609f9d1c9 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1065,6 +1065,13 @@ config CMD_USB_MASS_STORAGE
1065 help 1065 help
1066 USB mass storage support 1066 USB mass storage support
1067 1067
1068config CMD_VIRTIO
1069 bool "virtio"
1070 depends on VIRTIO
1071 default y if VIRTIO
1072 help
1073 VirtIO block device support
1074
1068config CMD_AXI 1075config CMD_AXI
1069 bool "axi" 1076 bool "axi"
1070 depends on AXI 1077 depends on AXI
diff --git a/cmd/Makefile b/cmd/Makefile
index ac4830a692..12a1330b06 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -135,6 +135,7 @@ obj-$(CONFIG_CMD_UBI) += ubi.o
135obj-$(CONFIG_CMD_UBIFS) += ubifs.o 135obj-$(CONFIG_CMD_UBIFS) += ubifs.o
136obj-$(CONFIG_CMD_UNIVERSE) += universe.o 136obj-$(CONFIG_CMD_UNIVERSE) += universe.o
137obj-$(CONFIG_CMD_UNZIP) += unzip.o 137obj-$(CONFIG_CMD_UNZIP) += unzip.o
138obj-$(CONFIG_CMD_VIRTIO) += virtio.o
138obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o 139obj-$(CONFIG_CMD_LZMADEC) += lzmadec.o
139 140
140obj-$(CONFIG_CMD_USB) += usb.o disk.o 141obj-$(CONFIG_CMD_USB) += usb.o disk.o
diff --git a/cmd/sata.c b/cmd/sata.c
index 4f0c6e0137..6d62ba8f74 100644
--- a/cmd/sata.c
+++ b/cmd/sata.c
@@ -51,7 +51,6 @@ int sata_probe(int devnum)
51{ 51{
52#ifdef CONFIG_AHCI 52#ifdef CONFIG_AHCI
53 struct udevice *dev; 53 struct udevice *dev;
54 struct udevice *blk;
55 int rc; 54 int rc;
56 55
57 rc = uclass_get_device(UCLASS_AHCI, devnum, &dev); 56 rc = uclass_get_device(UCLASS_AHCI, devnum, &dev);
@@ -67,14 +66,6 @@ int sata_probe(int devnum)
67 return CMD_RET_FAILURE; 66 return CMD_RET_FAILURE;
68 } 67 }
69 68
70 rc = blk_get_from_parent(dev, &blk);
71 if (!rc) {
72 struct blk_desc *desc = dev_get_uclass_platdata(blk);
73
74 if (desc->lba > 0 && desc->blksz > 0)
75 part_init(desc);
76 }
77
78 return 0; 69 return 0;
79#else 70#else
80 return sata_initialize() < 0 ? CMD_RET_FAILURE : CMD_RET_SUCCESS; 71 return sata_initialize() < 0 ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
diff --git a/cmd/virtio.c b/cmd/virtio.c
new file mode 100644
index 0000000000..b7082bc63a
--- /dev/null
+++ b/cmd/virtio.c
@@ -0,0 +1,38 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 */
6
7#include <common.h>
8#include <command.h>
9#include <dm.h>
10#include <virtio_types.h>
11#include <virtio.h>
12
13static int virtio_curr_dev;
14
15static int do_virtio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
16{
17 if (argc == 2 && !strcmp(argv[1], "scan")) {
18 /* make sure all virtio devices are enumerated */
19 virtio_init();
20
21 return CMD_RET_SUCCESS;
22 }
23
24 return blk_common_cmd(argc, argv, IF_TYPE_VIRTIO, &virtio_curr_dev);
25}
26
27U_BOOT_CMD(
28 virtio, 8, 1, do_virtio,
29 "virtio block devices sub-system",
30 "scan - initialize virtio bus\n"
31 "virtio info - show all available virtio block devices\n"
32 "virtio device [dev] - show or set current virtio block device\n"
33 "virtio part [dev] - print partition table of one or all virtio block devices\n"
34 "virtio read addr blk# cnt - read `cnt' blocks starting at block\n"
35 " `blk#' to memory address `addr'\n"
36 "virtio write addr blk# cnt - write `cnt' blocks starting at block\n"
37 " `blk#' from memory address `addr'"
38);
diff --git a/common/board_f.c b/common/board_f.c
index afafec5e4d..96503ff8d3 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -11,6 +11,7 @@
11 11
12#include <common.h> 12#include <common.h>
13#include <console.h> 13#include <console.h>
14#include <cpu.h>
14#include <dm.h> 15#include <dm.h>
15#include <environment.h> 16#include <environment.h>
16#include <fdtdec.h> 17#include <fdtdec.h>
@@ -165,6 +166,33 @@ static int print_resetinfo(void)
165} 166}
166#endif 167#endif
167 168
169#if defined(CONFIG_DISPLAY_CPUINFO) && CONFIG_IS_ENABLED(CPU)
170static int print_cpuinfo(void)
171{
172 struct udevice *dev;
173 char desc[512];
174 int ret;
175
176 ret = uclass_first_device_err(UCLASS_CPU, &dev);
177 if (ret) {
178 debug("%s: Could not get CPU device (err = %d)\n",
179 __func__, ret);
180 return ret;
181 }
182
183 ret = cpu_get_desc(dev, desc, sizeof(desc));
184 if (ret) {
185 debug("%s: Could not get CPU description (err = %d)\n",
186 dev->name, ret);
187 return ret;
188 }
189
190 printf("CPU: %s\n", desc);
191
192 return 0;
193}
194#endif
195
168static int announce_dram_init(void) 196static int announce_dram_init(void)
169{ 197{
170 puts("DRAM: "); 198 puts("DRAM: ");
diff --git a/common/usb_storage.c b/common/usb_storage.c
index d92ebb6eb1..560d60538b 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -226,9 +226,7 @@ static int usb_stor_probe_device(struct usb_device *udev)
226 blkdev->lun = lun; 226 blkdev->lun = lun;
227 227
228 ret = usb_stor_get_info(udev, data, blkdev); 228 ret = usb_stor_get_info(udev, data, blkdev);
229 if (ret == 1) 229 if (ret == 1) {
230 ret = blk_prepare_device(dev);
231 if (!ret) {
232 usb_max_devs++; 230 usb_max_devs++;
233 debug("%s: Found device %p\n", __func__, udev); 231 debug("%s: Found device %p\n", __func__, udev);
234 } else { 232 } else {
diff --git a/configs/imx8qxp_mek_defconfig b/configs/imx8qxp_mek_defconfig
index 518f7259f2..58b4ca0861 100644
--- a/configs/imx8qxp_mek_defconfig
+++ b/configs/imx8qxp_mek_defconfig
@@ -6,7 +6,6 @@ CONFIG_TARGET_IMX8QXP_MEK=y
6CONFIG_NR_DRAM_BANKS=3 6CONFIG_NR_DRAM_BANKS=3
7CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/imx8qxp_mek/imximage.cfg" 7CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/imx8qxp_mek/imximage.cfg"
8CONFIG_BOOTDELAY=3 8CONFIG_BOOTDELAY=3
9# CONFIG_DISPLAY_CPUINFO is not set
10CONFIG_CMD_CPU=y 9CONFIG_CMD_CPU=y
11# CONFIG_CMD_IMPORTENV is not set 10# CONFIG_CMD_IMPORTENV is not set
12CONFIG_CMD_CLK=y 11CONFIG_CMD_CLK=y
diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig
index e9e2819272..f4502c9e9f 100644
--- a/configs/qemu_arm64_defconfig
+++ b/configs/qemu_arm64_defconfig
@@ -1,7 +1,6 @@
1CONFIG_ARM=y 1CONFIG_ARM=y
2CONFIG_ARM_SMCCC=y 2CONFIG_ARM_SMCCC=y
3CONFIG_ARCH_QEMU=y 3CONFIG_ARCH_QEMU=y
4CONFIG_SYS_TEXT_BASE=0x00000000
5CONFIG_TARGET_QEMU_ARM_64BIT=y 4CONFIG_TARGET_QEMU_ARM_64BIT=y
6CONFIG_AHCI=y 5CONFIG_AHCI=y
7CONFIG_DISTRO_DEFAULTS=y 6CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig
index 04c9afdb02..acebdc5a4e 100644
--- a/configs/qemu_arm_defconfig
+++ b/configs/qemu_arm_defconfig
@@ -1,7 +1,6 @@
1CONFIG_ARM=y 1CONFIG_ARM=y
2CONFIG_ARM_SMCCC=y 2CONFIG_ARM_SMCCC=y
3CONFIG_ARCH_QEMU=y 3CONFIG_ARCH_QEMU=y
4CONFIG_SYS_TEXT_BASE=0x00000000
5CONFIG_TARGET_QEMU_ARM_32BIT=y 4CONFIG_TARGET_QEMU_ARM_32BIT=y
6CONFIG_AHCI=y 5CONFIG_AHCI=y
7CONFIG_DISTRO_DEFAULTS=y 6CONFIG_DISTRO_DEFAULTS=y
diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig
index 93b2240185..e71e2d3860 100644
--- a/configs/sandbox_noblk_defconfig
+++ b/configs/sandbox_noblk_defconfig
@@ -171,6 +171,7 @@ CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
171CONFIG_VIDEO_SANDBOX_SDL=y 171CONFIG_VIDEO_SANDBOX_SDL=y
172CONFIG_OSD=y 172CONFIG_OSD=y
173CONFIG_SANDBOX_OSD=y 173CONFIG_SANDBOX_OSD=y
174# CONFIG_VIRTIO_BLK is not set
174CONFIG_FS_CBFS=y 175CONFIG_FS_CBFS=y
175CONFIG_FS_CRAMFS=y 176CONFIG_FS_CRAMFS=y
176CONFIG_CMD_DHRYSTONE=y 177CONFIG_CMD_DHRYSTONE=y
diff --git a/disk/part.c b/disk/part.c
index 9e457a6e72..f30f9e9187 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -150,6 +150,9 @@ void dev_print (struct blk_desc *dev_desc)
150 dev_desc->revision, 150 dev_desc->revision,
151 dev_desc->product); 151 dev_desc->product);
152 break; 152 break;
153 case IF_TYPE_VIRTIO:
154 printf("%s VirtIO Block Device\n", dev_desc->vendor);
155 break;
153 case IF_TYPE_DOC: 156 case IF_TYPE_DOC:
154 puts("device type DOC\n"); 157 puts("device type DOC\n");
155 return; 158 return;
@@ -281,6 +284,9 @@ static void print_part_header(const char *type, struct blk_desc *dev_desc)
281 case IF_TYPE_NVME: 284 case IF_TYPE_NVME:
282 puts ("NVMe"); 285 puts ("NVMe");
283 break; 286 break;
287 case IF_TYPE_VIRTIO:
288 puts("VirtIO");
289 break;
284 default: 290 default:
285 puts ("UNKNOWN"); 291 puts ("UNKNOWN");
286 break; 292 break;
diff --git a/doc/README.virtio b/doc/README.virtio
new file mode 100644
index 0000000000..d3652f2e2f
--- /dev/null
+++ b/doc/README.virtio
@@ -0,0 +1,253 @@
1# SPDX-License-Identifier: GPL-2.0+
2#
3# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4
5VirtIO Support
6==============
7
8This document describes the information about U-Boot support for VirtIO [1]
9devices, including supported boards, build instructions, driver details etc.
10
11What's VirtIO?
12--------------
13VirtIO is a virtualization standard for network and disk device drivers where
14just the guest's device driver "knows" it is running in a virtual environment,
15and cooperates with the hypervisor. This enables guests to get high performance
16network and disk operations, and gives most of the performance benefits of
17paravirtualization. In the U-Boot case, the guest is U-Boot itself, while the
18virtual environment are normally QEMU [2] targets like ARM, RISC-V and x86.
19
20Status
21------
22VirtIO can use various different buses, aka transports as described in the
23spec. While VirtIO devices are commonly implemented as PCI devices on x86,
24embedded devices models like ARM/RISC-V, which does not normally come with
25PCI support might use simple memory mapped device (MMIO) instead of the PCI
26device. The memory mapped virtio device behaviour is based on the PCI device
27specification. Therefore most operations including device initialization,
28queues configuration and buffer transfers are nearly identical. Both MMIO
29and PCI transport options are supported in U-Boot.
30
31The VirtIO spec defines a lots of VirtIO device types, however at present only
32network and block device, the most two commonly used devices, are supported.
33
34The following QEMU targets are supported.
35
36 - qemu_arm_defconfig
37 - qemu_arm64_defconfig
38 - qemu-riscv32_defconfig
39 - qemu-riscv64_defconfig
40 - qemu-x86_defconfig
41 - qemu-x86_64_defconfig
42
43Note ARM and RISC-V targets are configured with VirtIO MMIO transport driver,
44and on x86 it's the PCI transport driver.
45
46Build Instructions
47------------------
48Building U-Boot for pre-configured QEMU targets is no different from others.
49For example, we can do the following with the CROSS_COMPILE environment
50variable being properly set to a working toolchain for ARM:
51
52 $ make qemu_arm_defconfig
53 $ make
54
55You can even create a QEMU ARM target with VirtIO devices showing up on both
56MMIO and PCI buses. In this case, you can enable the PCI transport driver
57from 'make menuconfig':
58
59Device Drivers --->
60 ...
61 VirtIO Drivers --->
62 ...
63 [*] PCI driver for virtio devices
64
65Other drivers are at the same location and can be tuned to suit the needs.
66
67Requirements
68------------
69It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support
70on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V.
71
72Testing
73-------
74The following QEMU command line is used to get U-Boot up and running with
75VirtIO net and block devices on ARM.
76
77 $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
78 -netdev tap,ifname=tap0,id=net0 \
79 -device virtio-net-device,netdev=net0 \
80 -drive if=none,file=test.img,format=raw,id=hd0 \
81 -device virtio-blk-device,drive=hd0
82
83On x86, command is slightly different to create PCI VirtIO devices.
84
85 $ qemu-system-i386 -nographic -bios u-boot.rom \
86 -netdev tap,ifname=tap0,id=net0 \
87 -device virtio-net-pci,netdev=net0 \
88 -drive if=none,file=test.img,format=raw,id=hd0 \
89 -device virtio-blk-pci,drive=hd0
90
91Additional net and block devices can be created by appending more '-device'
92parameters. It is also possible to specify both MMIO and PCI VirtIO devices.
93For example, the following commnad creates 3 VirtIO devices, with 1 on MMIO
94and 2 on PCI bus.
95
96 $ qemu-system-arm -nographic -machine virt -bios u-boot.bin \
97 -netdev tap,ifname=tap0,id=net0 \
98 -device virtio-net-pci,netdev=net0 \
99 -drive if=none,file=test0.img,format=raw,id=hd0 \
100 -device virtio-blk-device,drive=hd0 \
101 -drive if=none,file=test1.img,format=raw,id=hd1 \
102 -device virtio-blk-pci,drive=hd1
103
104By default QEMU creates VirtIO legacy devices by default. To create non-legacy
105(aka modern) devices, pass additional device property/value pairs like below:
106
107 $ qemu-system-i386 -nographic -bios u-boot.rom \
108 -netdev tap,ifname=tap0,id=net0 \
109 -device virtio-net-pci,netdev=net0,disable-legacy=true,disable-modern=false \
110 -drive if=none,file=test.img,format=raw,id=hd0 \
111 -device virtio-blk-pci,drive=hd0,disable-legacy=true,disable-modern=false
112
113A 'virtio' command is provided in U-Boot shell.
114
115 => virtio
116 virtio - virtio block devices sub-system
117
118 Usage:
119 virtio scan - initialize virtio bus
120 virtio info - show all available virtio block devices
121 virtio device [dev] - show or set current virtio block device
122 virtio part [dev] - print partition table of one or all virtio block devices
123 virtio read addr blk# cnt - read `cnt' blocks starting at block
124 `blk#' to memory address `addr'
125 virtio write addr blk# cnt - write `cnt' blocks starting at block
126 `blk#' from memory address `addr'
127
128To probe all the VirtIO devices, type:
129
130 => virtio scan
131
132Then we can show the connected block device details by:
133
134 => virtio info
135 Device 0: QEMU VirtIO Block Device
136 Type: Hard Disk
137 Capacity: 4096.0 MB = 4.0 GB (8388608 x 512)
138
139And list the directories and files on the disk by:
140
141 => ls virtio 0 /
142 <DIR> 4096 .
143 <DIR> 4096 ..
144 <DIR> 16384 lost+found
145 <DIR> 4096 dev
146 <DIR> 4096 proc
147 <DIR> 4096 sys
148 <DIR> 4096 var
149 <DIR> 4096 etc
150 <DIR> 4096 usr
151 <SYM> 7 bin
152 <SYM> 8 sbin
153 <SYM> 7 lib
154 <SYM> 9 lib64
155 <DIR> 4096 run
156 <DIR> 4096 boot
157 <DIR> 4096 home
158 <DIR> 4096 media
159 <DIR> 4096 mnt
160 <DIR> 4096 opt
161 <DIR> 4096 root
162 <DIR> 4096 srv
163 <DIR> 4096 tmp
164 0 .autorelabel
165
166Driver Internals
167----------------
168There are 3 level of drivers in the VirtIO driver family.
169
170 +---------------------------------------+
171 | virtio device drivers |
172 | +-------------+ +------------+ |
173 | | virtio-net | | virtio-blk | |
174 | +-------------+ +------------+ |
175 +---------------------------------------+
176 +---------------------------------------+
177 | virtio transport drivers |
178 | +-------------+ +------------+ |
179 | | virtio-mmio | | virtio-pci | |
180 | +-------------+ +------------+ |
181 +---------------------------------------+
182 +----------------------+
183 | virtio uclass driver |
184 +----------------------+
185
186The root one is the virtio uclass driver (virtio-uclass.c), which does lots of
187common stuff for the transport drivers (virtio_mmio.c, virtio_pci.c). The real
188virtio device is discovered in the transport driver's probe() method, and its
189device ID is saved in the virtio uclass's private data of the transport device.
190Then in the virtio uclass's post_probe() method, the real virtio device driver
191(virtio_net.c, virtio_blk.c) is bound if there is a match on the device ID.
192
193The child_post_bind(), child_pre_probe() and child_post_probe() methods of the
194virtio uclass driver help bring the virtio device driver online. They do things
195like acknowledging device, feature negotiation, etc, which are really common
196for all virtio devices.
197
198The transport drivers provide a set of ops (struct dm_virtio_ops) for the real
199virtio device driver to call. These ops APIs's parameter is designed to remind
200the caller to pass the correct 'struct udevice' id of the virtio device, eg:
201
202int virtio_get_status(struct udevice *vdev, u8 *status)
203
204So the parameter 'vdev' indicates the device should be the real virtio device.
205But we also have an API like:
206
207struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
208 unsigned int vring_align,
209 struct udevice *udev)
210
211Here the parameter 'udev' indicates the device should be the transport device.
212Similar naming is applied in other functions that are even not APIs, eg:
213
214static int virtio_uclass_post_probe(struct udevice *udev)
215static int virtio_uclass_child_pre_probe(struct udevice *vdev)
216
217So it's easy to tell which device these functions are operating on.
218
219Development Flow
220----------------
221At present only VirtIO network card (device ID 1) and block device (device
222ID 2) are supported. If you want to develop new driver for new devices,
223please follow the guideline below.
224
2251. add new device ID in virtio.h
226#define VIRTIO_ID_XXX X
227
2282. update VIRTIO_ID_MAX_NUM to be the largest device ID plus 1
229
2303. add new driver name string in virtio.h
231#define VIRTIO_XXX_DRV_NAME "virtio-xxx"
232
2334. create a new driver with name set to the name string above
234U_BOOT_DRIVER(virtio_xxx) = {
235 .name = VIRTIO_XXX_DRV_NAME,
236 ...
237 .remove = virtio_reset,
238 .flags = DM_FLAG_ACTIVE_DMA,
239}
240
241Note the driver needs to provide the remove method and normally this can be
242hooked to virtio_reset(). The driver flags should contain DM_FLAG_ACTIVE_DMA
243for the remove method to be called before jumping to OS.
244
2455. provide bind() method in the driver, where virtio_driver_features_init()
246 should be called for driver to negotiate feature support with the device.
247
2486. do funny stuff with the driver
249
250References
251----------
252[1] http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf
253[2] https://www.qemu.org
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index 36541630a2..07b120d512 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -830,10 +830,18 @@ Pre-Relocation Support
830---------------------- 830----------------------
831 831
832For pre-relocation we simply call the driver model init function. Only 832For pre-relocation we simply call the driver model init function. Only
833drivers marked with DM_FLAG_PRE_RELOC or the device tree 833drivers marked with DM_FLAG_PRE_RELOC or the device tree 'u-boot,dm-pre-reloc'
834'u-boot,dm-pre-reloc' flag are initialised prior to relocation. This helps 834property are initialised prior to relocation. This helps to reduce the driver
835to reduce the driver model overhead. This flag applies to SPL and TPL as 835model overhead. This flag applies to SPL and TPL as well, if device tree is
836well, if device tree is enabled there. 836enabled (CONFIG_OF_CONTROL) there.
837
838Note when device tree is enabled, the device tree 'u-boot,dm-pre-reloc'
839property can provide better control granularity on which device is bound
840before relocation. While with DM_FLAG_PRE_RELOC flag of the driver all
841devices with the same driver are bound, which requires allocation a large
842amount of memory. When device tree is not used, DM_FLAG_PRE_RELOC is the
843only way for statically declared devices via U_BOOT_DEVICE() to be bound
844prior to relocation.
837 845
838It is possible to limit this to specific relocation steps, by using 846It is possible to limit this to specific relocation steps, by using
839the more specialized 'u-boot,dm-spl' and 'u-boot,dm-tpl' flags 847the more specialized 'u-boot,dm-spl' and 'u-boot,dm-tpl' flags
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 927a2b87f6..4ac823d962 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -112,6 +112,8 @@ source "drivers/usb/Kconfig"
112 112
113source "drivers/video/Kconfig" 113source "drivers/video/Kconfig"
114 114
115source "drivers/virtio/Kconfig"
116
115source "drivers/w1/Kconfig" 117source "drivers/w1/Kconfig"
116 118
117source "drivers/w1-eeprom/Kconfig" 119source "drivers/w1-eeprom/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index fb38b67541..4453c62ad3 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_$(SPL_TPL_)SERIAL_SUPPORT) += serial/
14obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += mtd/spi/ 14obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += mtd/spi/
15obj-$(CONFIG_$(SPL_TPL_)SPI_SUPPORT) += spi/ 15obj-$(CONFIG_$(SPL_TPL_)SPI_SUPPORT) += spi/
16obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/ 16obj-$(CONFIG_$(SPL_TPL_)TIMER) += timer/
17obj-$(CONFIG_$(SPL_TPL_)VIRTIO) += virtio/
17obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/ 18obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox/
18obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/ 19obj-$(CONFIG_$(SPL_)REMOTEPROC) += remoteproc/
19 20
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index facf52711c..65a766e586 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -23,6 +23,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = {
23 [IF_TYPE_HOST] = "host", 23 [IF_TYPE_HOST] = "host",
24 [IF_TYPE_NVME] = "nvme", 24 [IF_TYPE_NVME] = "nvme",
25 [IF_TYPE_EFI] = "efi", 25 [IF_TYPE_EFI] = "efi",
26 [IF_TYPE_VIRTIO] = "virtio",
26}; 27};
27 28
28static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { 29static 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] = {
37 [IF_TYPE_HOST] = UCLASS_ROOT, 38 [IF_TYPE_HOST] = UCLASS_ROOT,
38 [IF_TYPE_NVME] = UCLASS_NVME, 39 [IF_TYPE_NVME] = UCLASS_NVME,
39 [IF_TYPE_EFI] = UCLASS_EFI, 40 [IF_TYPE_EFI] = UCLASS_EFI,
41 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
40}; 42};
41 43
42static enum if_type if_typename_to_iftype(const char *if_typename) 44static 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,
471 return ops->erase(dev, start, blkcnt); 473 return ops->erase(dev, start, blkcnt);
472} 474}
473 475
474int blk_prepare_device(struct udevice *dev)
475{
476 struct blk_desc *desc = dev_get_uclass_platdata(dev);
477
478 part_init(desc);
479
480 return 0;
481}
482
483int blk_get_from_parent(struct udevice *parent, struct udevice **devp) 476int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
484{ 477{
485 struct udevice *dev; 478 struct udevice *dev;
@@ -526,7 +519,7 @@ int blk_find_max_devnum(enum if_type if_type)
526 return max_devnum; 519 return max_devnum;
527} 520}
528 521
529static int blk_next_free_devnum(enum if_type if_type) 522int blk_next_free_devnum(enum if_type if_type)
530{ 523{
531 int ret; 524 int ret;
532 525
@@ -644,8 +637,20 @@ int blk_unbind_all(int if_type)
644 return 0; 637 return 0;
645} 638}
646 639
640static int blk_post_probe(struct udevice *dev)
641{
642#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
643 struct blk_desc *desc = dev_get_uclass_platdata(dev);
644
645 part_init(desc);
646#endif
647
648 return 0;
649}
650
647UCLASS_DRIVER(blk) = { 651UCLASS_DRIVER(blk) = {
648 .id = UCLASS_BLK, 652 .id = UCLASS_BLK,
649 .name = "blk", 653 .name = "blk",
654 .post_probe = blk_post_probe,
650 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 655 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
651}; 656};
diff --git a/drivers/block/ide.c b/drivers/block/ide.c
index 38adb6a241..4b8a4eac17 100644
--- a/drivers/block/ide.c
+++ b/drivers/block/ide.c
@@ -1169,8 +1169,6 @@ static int ide_blk_probe(struct udevice *udev)
1169 BLK_REV_SIZE); 1169 BLK_REV_SIZE);
1170 desc->revision[BLK_REV_SIZE] = '\0'; 1170 desc->revision[BLK_REV_SIZE] = '\0';
1171 1171
1172 part_init(desc);
1173
1174 return 0; 1172 return 0;
1175} 1173}
1176 1174
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 0392437309..d3b1aaaba3 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -33,7 +33,7 @@ static unsigned long host_block_read(struct udevice *dev,
33 unsigned long start, lbaint_t blkcnt, 33 unsigned long start, lbaint_t blkcnt,
34 void *buffer) 34 void *buffer)
35{ 35{
36 struct host_block_dev *host_dev = dev_get_priv(dev); 36 struct host_block_dev *host_dev = dev_get_platdata(dev);
37 struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 37 struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
38 38
39#else 39#else
@@ -64,7 +64,7 @@ static unsigned long host_block_write(struct udevice *dev,
64 unsigned long start, lbaint_t blkcnt, 64 unsigned long start, lbaint_t blkcnt,
65 const void *buffer) 65 const void *buffer)
66{ 66{
67 struct host_block_dev *host_dev = dev_get_priv(dev); 67 struct host_block_dev *host_dev = dev_get_platdata(dev);
68 struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 68 struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
69#else 69#else
70static unsigned long host_block_write(struct blk_desc *block_dev, 70static unsigned long host_block_write(struct blk_desc *block_dev,
@@ -131,17 +131,18 @@ int host_dev_bind(int devnum, char *filename)
131 os_lseek(fd, 0, OS_SEEK_END) / 512, &dev); 131 os_lseek(fd, 0, OS_SEEK_END) / 512, &dev);
132 if (ret) 132 if (ret)
133 goto err_file; 133 goto err_file;
134
135 host_dev = dev_get_platdata(dev);
136 host_dev->fd = fd;
137 host_dev->filename = fname;
138
134 ret = device_probe(dev); 139 ret = device_probe(dev);
135 if (ret) { 140 if (ret) {
136 device_unbind(dev); 141 device_unbind(dev);
137 goto err_file; 142 goto err_file;
138 } 143 }
139 144
140 host_dev = dev_get_priv(dev); 145 return 0;
141 host_dev->fd = fd;
142 host_dev->filename = fname;
143
144 return blk_prepare_device(dev);
145err_file: 146err_file:
146 os_close(fd); 147 os_close(fd);
147err: 148err:
@@ -226,7 +227,7 @@ U_BOOT_DRIVER(sandbox_host_blk) = {
226 .name = "sandbox_host_blk", 227 .name = "sandbox_host_blk",
227 .id = UCLASS_BLK, 228 .id = UCLASS_BLK,
228 .ops = &sandbox_host_blk_ops, 229 .ops = &sandbox_host_blk_ops,
229 .priv_auto_alloc_size = sizeof(struct host_block_dev), 230 .platdata_auto_alloc_size = sizeof(struct host_block_dev),
230}; 231};
231#else 232#else
232U_BOOT_LEGACY_BLK(sandbox_host) = { 233U_BOOT_LEGACY_BLK(sandbox_host) = {
diff --git a/drivers/clk/altera/clk-arria10.c b/drivers/clk/altera/clk-arria10.c
index 78102c760d..612a1718dc 100644
--- a/drivers/clk/altera/clk-arria10.c
+++ b/drivers/clk/altera/clk-arria10.c
@@ -352,7 +352,6 @@ static const struct udevice_id socfpga_a10_clk_match[] = {
352U_BOOT_DRIVER(socfpga_a10_clk) = { 352U_BOOT_DRIVER(socfpga_a10_clk) = {
353 .name = "clk-a10", 353 .name = "clk-a10",
354 .id = UCLASS_CLK, 354 .id = UCLASS_CLK,
355 .flags = DM_FLAG_PRE_RELOC,
356 .of_match = socfpga_a10_clk_match, 355 .of_match = socfpga_a10_clk_match,
357 .ops = &socfpga_a10_clk_ops, 356 .ops = &socfpga_a10_clk_ops,
358 .bind = socfpga_a10_clk_bind, 357 .bind = socfpga_a10_clk_bind,
diff --git a/drivers/clk/clk_pic32.c b/drivers/clk/clk_pic32.c
index fdf95a12da..b3ac0d5a92 100644
--- a/drivers/clk/clk_pic32.c
+++ b/drivers/clk/clk_pic32.c
@@ -418,7 +418,6 @@ U_BOOT_DRIVER(pic32_clk) = {
418 .name = "pic32_clk", 418 .name = "pic32_clk",
419 .id = UCLASS_CLK, 419 .id = UCLASS_CLK,
420 .of_match = pic32_clk_ids, 420 .of_match = pic32_clk_ids,
421 .flags = DM_FLAG_PRE_RELOC,
422 .ops = &pic32_pic32_clk_ops, 421 .ops = &pic32_pic32_clk_ops,
423 .probe = pic32_clk_probe, 422 .probe = pic32_clk_probe,
424 .priv_auto_alloc_size = sizeof(struct pic32_clk_priv), 423 .priv_auto_alloc_size = sizeof(struct pic32_clk_priv),
diff --git a/drivers/clk/clk_zynq.c b/drivers/clk/clk_zynq.c
index d647e0a01e..482f0937cb 100644
--- a/drivers/clk/clk_zynq.c
+++ b/drivers/clk/clk_zynq.c
@@ -480,7 +480,6 @@ U_BOOT_DRIVER(zynq_clk) = {
480 .name = "zynq_clk", 480 .name = "zynq_clk",
481 .id = UCLASS_CLK, 481 .id = UCLASS_CLK,
482 .of_match = zynq_clk_ids, 482 .of_match = zynq_clk_ids,
483 .flags = DM_FLAG_PRE_RELOC,
484 .ops = &zynq_clk_ops, 483 .ops = &zynq_clk_ops,
485 .priv_auto_alloc_size = sizeof(struct zynq_clk_priv), 484 .priv_auto_alloc_size = sizeof(struct zynq_clk_priv),
486 .probe = zynq_clk_probe, 485 .probe = zynq_clk_probe,
diff --git a/drivers/clk/exynos/clk-exynos7420.c b/drivers/clk/exynos/clk-exynos7420.c
index 763567b17c..aa86c7ca44 100644
--- a/drivers/clk/exynos/clk-exynos7420.c
+++ b/drivers/clk/exynos/clk-exynos7420.c
@@ -201,7 +201,6 @@ U_BOOT_DRIVER(exynos7420_clk_topc) = {
201 .probe = exynos7420_clk_topc_probe, 201 .probe = exynos7420_clk_topc_probe,
202 .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv), 202 .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
203 .ops = &exynos7420_clk_topc_ops, 203 .ops = &exynos7420_clk_topc_ops,
204 .flags = DM_FLAG_PRE_RELOC,
205}; 204};
206 205
207static const struct udevice_id exynos7420_clk_top0_compat[] = { 206static const struct udevice_id exynos7420_clk_top0_compat[] = {
@@ -216,7 +215,6 @@ U_BOOT_DRIVER(exynos7420_clk_top0) = {
216 .probe = exynos7420_clk_top0_probe, 215 .probe = exynos7420_clk_top0_probe,
217 .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv), 216 .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
218 .ops = &exynos7420_clk_top0_ops, 217 .ops = &exynos7420_clk_top0_ops,
219 .flags = DM_FLAG_PRE_RELOC,
220}; 218};
221 219
222static const struct udevice_id exynos7420_clk_peric1_compat[] = { 220static const struct udevice_id exynos7420_clk_peric1_compat[] = {
@@ -229,5 +227,4 @@ U_BOOT_DRIVER(exynos7420_clk_peric1) = {
229 .id = UCLASS_CLK, 227 .id = UCLASS_CLK,
230 .of_match = exynos7420_clk_peric1_compat, 228 .of_match = exynos7420_clk_peric1_compat,
231 .ops = &exynos7420_clk_peric1_ops, 229 .ops = &exynos7420_clk_peric1_ops,
232 .flags = DM_FLAG_PRE_RELOC,
233}; 230};
diff --git a/drivers/clk/owl/clk_s900.c b/drivers/clk/owl/clk_s900.c
index 2b39bb99af..a7c15d2812 100644
--- a/drivers/clk/owl/clk_s900.c
+++ b/drivers/clk/owl/clk_s900.c
@@ -134,5 +134,4 @@ U_BOOT_DRIVER(clk_owl) = {
134 .ops = &owl_clk_ops, 134 .ops = &owl_clk_ops,
135 .priv_auto_alloc_size = sizeof(struct owl_clk_priv), 135 .priv_auto_alloc_size = sizeof(struct owl_clk_priv),
136 .probe = owl_clk_probe, 136 .probe = owl_clk_probe,
137 .flags = DM_FLAG_PRE_RELOC,
138}; 137};
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 5176aa3f86..47a697f3e5 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -834,5 +834,5 @@ int dev_enable_by_path(const char *path)
834 if (ret) 834 if (ret)
835 return ret; 835 return ret;
836 836
837 return lists_bind_fdt(parent, node, NULL); 837 return lists_bind_fdt(parent, node, NULL, false);
838} 838}
diff --git a/drivers/core/dump.c b/drivers/core/dump.c
index d7cdb1475d..9068084404 100644
--- a/drivers/core/dump.c
+++ b/drivers/core/dump.c
@@ -89,7 +89,7 @@ void dm_dump_uclass(void)
89 printf("uclass %d: %s\n", id, uc->uc_drv->name); 89 printf("uclass %d: %s\n", id, uc->uc_drv->name);
90 if (list_empty(&uc->dev_head)) 90 if (list_empty(&uc->dev_head))
91 continue; 91 continue;
92 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 92 uclass_foreach_dev(dev, uc) {
93 dm_display_line(dev, i); 93 dm_display_line(dev, i);
94 i++; 94 i++;
95 } 95 }
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index a1677269d8..a1f828463e 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -122,7 +122,8 @@ static int driver_check_compatible(const struct udevice_id *of_match,
122 return -ENOENT; 122 return -ENOENT;
123} 123}
124 124
125int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp) 125int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
126 bool pre_reloc_only)
126{ 127{
127 struct driver *driver = ll_entry_start(struct driver, driver); 128 struct driver *driver = ll_entry_start(struct driver, driver);
128 const int n_ents = ll_entry_count(struct driver, driver); 129 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)
171 if (entry == driver + n_ents) 172 if (entry == driver + n_ents)
172 continue; 173 continue;
173 174
175 if (pre_reloc_only) {
176 if (!dm_ofnode_pre_reloc(node) &&
177 !(entry->flags & DM_FLAG_PRE_RELOC))
178 return 0;
179 }
180
174 pr_debug(" - found match at '%s'\n", entry->name); 181 pr_debug(" - found match at '%s'\n", entry->name);
175 ret = device_bind_with_driver_data(parent, entry, name, 182 ret = device_bind_with_driver_data(parent, entry, name,
176 id->data, node, &dev); 183 id->data, node, &dev);
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index b7b7ad3a62..d9b5280b2d 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -831,8 +831,10 @@ int ofnode_write_prop(ofnode node, const char *propname, int len,
831 return -ENOMEM; 831 return -ENOMEM;
832 832
833 new->name = strdup(propname); 833 new->name = strdup(propname);
834 if (!new->name) 834 if (!new->name) {
835 free(new);
835 return -ENOMEM; 836 return -ENOMEM;
837 }
836 838
837 new->value = (void *)value; 839 new->value = (void *)value;
838 new->length = len; 840 new->length = len;
diff --git a/drivers/core/regmap.c b/drivers/core/regmap.c
index 8e5c3bcf61..5ef0f71c8b 100644
--- a/drivers/core/regmap.c
+++ b/drivers/core/regmap.c
@@ -17,6 +17,12 @@
17 17
18DECLARE_GLOBAL_DATA_PTR; 18DECLARE_GLOBAL_DATA_PTR;
19 19
20/**
21 * regmap_alloc() - Allocate a regmap with a given number of ranges.
22 *
23 * @count: Number of ranges to be allocated for the regmap.
24 * Return: A pointer to the newly allocated regmap, or NULL on error.
25 */
20static struct regmap *regmap_alloc(int count) 26static struct regmap *regmap_alloc(int count)
21{ 27{
22 struct regmap *map; 28 struct regmap *map;
@@ -50,6 +56,58 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
50 return 0; 56 return 0;
51} 57}
52#else 58#else
59/**
60 * init_range() - Initialize a single range of a regmap
61 * @node: Device node that will use the map in question
62 * @range: Pointer to a regmap_range structure that will be initialized
63 * @addr_len: The length of the addr parts of the reg property
64 * @size_len: The length of the size parts of the reg property
65 * @index: The index of the range to initialize
66 *
67 * This function will read the necessary 'reg' information from the device tree
68 * (the 'addr' part, and the 'length' part), and initialize the range in
69 * quesion.
70 *
71 * Return: 0 if OK, -ve on error
72 */
73static int init_range(ofnode node, struct regmap_range *range, int addr_len,
74 int size_len, int index)
75{
76 fdt_size_t sz;
77 struct resource r;
78
79 if (of_live_active()) {
80 int ret;
81
82 ret = of_address_to_resource(ofnode_to_np(node),
83 index, &r);
84 if (ret) {
85 debug("%s: Could not read resource of range %d (ret = %d)\n",
86 ofnode_get_name(node), index, ret);
87 return ret;
88 }
89
90 range->start = r.start;
91 range->size = r.end - r.start + 1;
92 } else {
93 int offset = ofnode_to_offset(node);
94
95 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob, offset,
96 "reg", index,
97 addr_len, size_len,
98 &sz, true);
99 if (range->start == FDT_ADDR_T_NONE) {
100 debug("%s: Could not read start of range %d\n",
101 ofnode_get_name(node), index);
102 return -EINVAL;
103 }
104
105 range->size = sz;
106 }
107
108 return 0;
109}
110
53int regmap_init_mem(ofnode node, struct regmap **mapp) 111int regmap_init_mem(ofnode node, struct regmap **mapp)
54{ 112{
55 struct regmap_range *range; 113 struct regmap_range *range;
@@ -58,19 +116,41 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
58 int addr_len, size_len, both_len; 116 int addr_len, size_len, both_len;
59 int len; 117 int len;
60 int index; 118 int index;
61 struct resource r;
62 119
63 addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node)); 120 addr_len = ofnode_read_simple_addr_cells(ofnode_get_parent(node));
121 if (addr_len < 0) {
122 debug("%s: Error while reading the addr length (ret = %d)\n",
123 ofnode_get_name(node), addr_len);
124 return addr_len;
125 }
126
64 size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node)); 127 size_len = ofnode_read_simple_size_cells(ofnode_get_parent(node));
128 if (size_len < 0) {
129 debug("%s: Error while reading the size length: (ret = %d)\n",
130 ofnode_get_name(node), size_len);
131 return size_len;
132 }
133
65 both_len = addr_len + size_len; 134 both_len = addr_len + size_len;
135 if (!both_len) {
136 debug("%s: Both addr and size length are zero\n",
137 ofnode_get_name(node));
138 return -EINVAL;
139 }
66 140
67 len = ofnode_read_size(node, "reg"); 141 len = ofnode_read_size(node, "reg");
68 if (len < 0) 142 if (len < 0) {
143 debug("%s: Error while reading reg size (ret = %d)\n",
144 ofnode_get_name(node), len);
69 return len; 145 return len;
146 }
70 len /= sizeof(fdt32_t); 147 len /= sizeof(fdt32_t);
71 count = len / both_len; 148 count = len / both_len;
72 if (!count) 149 if (!count) {
150 debug("%s: Not enough data in reg property\n",
151 ofnode_get_name(node));
73 return -EINVAL; 152 return -EINVAL;
153 }
74 154
75 map = regmap_alloc(count); 155 map = regmap_alloc(count);
76 if (!map) 156 if (!map)
@@ -78,19 +158,21 @@ int regmap_init_mem(ofnode node, struct regmap **mapp)
78 158
79 for (range = map->ranges, index = 0; count > 0; 159 for (range = map->ranges, index = 0; count > 0;
80 count--, range++, index++) { 160 count--, range++, index++) {
81 fdt_size_t sz; 161 int ret = init_range(node, range, addr_len, size_len, index);
82 if (of_live_active()) { 162
83 of_address_to_resource(ofnode_to_np(node), index, &r); 163 if (ret)
84 range->start = r.start; 164 return ret;
85 range->size = r.end - r.start + 1;
86 } else {
87 range->start = fdtdec_get_addr_size_fixed(gd->fdt_blob,
88 ofnode_to_offset(node), "reg", index,
89 addr_len, size_len, &sz, true);
90 range->size = sz;
91 }
92 } 165 }
93 166
167 if (ofnode_read_bool(node, "little-endian"))
168 map->endianness = REGMAP_LITTLE_ENDIAN;
169 else if (ofnode_read_bool(node, "big-endian"))
170 map->endianness = REGMAP_BIG_ENDIAN;
171 else if (ofnode_read_bool(node, "native-endian"))
172 map->endianness = REGMAP_NATIVE_ENDIAN;
173 else /* Default: native endianness */
174 map->endianness = REGMAP_NATIVE_ENDIAN;
175
94 *mapp = map; 176 *mapp = map;
95 177
96 return 0; 178 return 0;
@@ -115,24 +197,218 @@ int regmap_uninit(struct regmap *map)
115 return 0; 197 return 0;
116} 198}
117 199
118int regmap_read(struct regmap *map, uint offset, uint *valp) 200static inline u8 __read_8(u8 *addr, enum regmap_endianness_t endianness)
119{ 201{
120 u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE); 202 return readb(addr);
203}
121 204
122 *valp = le32_to_cpu(readl(ptr)); 205static inline u16 __read_16(u16 *addr, enum regmap_endianness_t endianness)
206{
207 switch (endianness) {
208 case REGMAP_LITTLE_ENDIAN:
209 return in_le16(addr);
210 case REGMAP_BIG_ENDIAN:
211 return in_be16(addr);
212 case REGMAP_NATIVE_ENDIAN:
213 return readw(addr);
214 }
215
216 return readw(addr);
217}
218
219static inline u32 __read_32(u32 *addr, enum regmap_endianness_t endianness)
220{
221 switch (endianness) {
222 case REGMAP_LITTLE_ENDIAN:
223 return in_le32(addr);
224 case REGMAP_BIG_ENDIAN:
225 return in_be32(addr);
226 case REGMAP_NATIVE_ENDIAN:
227 return readl(addr);
228 }
229
230 return readl(addr);
231}
232
233#if defined(in_le64) && defined(in_be64) && defined(readq)
234static inline u64 __read_64(u64 *addr, enum regmap_endianness_t endianness)
235{
236 switch (endianness) {
237 case REGMAP_LITTLE_ENDIAN:
238 return in_le64(addr);
239 case REGMAP_BIG_ENDIAN:
240 return in_be64(addr);
241 case REGMAP_NATIVE_ENDIAN:
242 return readq(addr);
243 }
244
245 return readq(addr);
246}
247#endif
248
249int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
250 void *valp, size_t val_len)
251{
252 struct regmap_range *range;
253 void *ptr;
254
255 if (range_num >= map->range_count) {
256 debug("%s: range index %d larger than range count\n",
257 __func__, range_num);
258 return -ERANGE;
259 }
260 range = &map->ranges[range_num];
261
262 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
263
264 if (offset + val_len > range->size) {
265 debug("%s: offset/size combination invalid\n", __func__);
266 return -ERANGE;
267 }
268
269 switch (val_len) {
270 case REGMAP_SIZE_8:
271 *((u8 *)valp) = __read_8(ptr, map->endianness);
272 break;
273 case REGMAP_SIZE_16:
274 *((u16 *)valp) = __read_16(ptr, map->endianness);
275 break;
276 case REGMAP_SIZE_32:
277 *((u32 *)valp) = __read_32(ptr, map->endianness);
278 break;
279#if defined(in_le64) && defined(in_be64) && defined(readq)
280 case REGMAP_SIZE_64:
281 *((u64 *)valp) = __read_64(ptr, map->endianness);
282 break;
283#endif
284 default:
285 debug("%s: regmap size %zu unknown\n", __func__, val_len);
286 return -EINVAL;
287 }
123 288
124 return 0; 289 return 0;
125} 290}
126 291
127int regmap_write(struct regmap *map, uint offset, uint val) 292int regmap_raw_read(struct regmap *map, uint offset, void *valp, size_t val_len)
128{ 293{
129 u32 *ptr = map_physmem(map->ranges[0].start + offset, 4, MAP_NOCACHE); 294 return regmap_raw_read_range(map, 0, offset, valp, val_len);
295}
130 296
131 writel(cpu_to_le32(val), ptr); 297int regmap_read(struct regmap *map, uint offset, uint *valp)
298{
299 return regmap_raw_read(map, offset, valp, REGMAP_SIZE_32);
300}
301
302static inline void __write_8(u8 *addr, const u8 *val,
303 enum regmap_endianness_t endianness)
304{
305 writeb(*val, addr);
306}
307
308static inline void __write_16(u16 *addr, const u16 *val,
309 enum regmap_endianness_t endianness)
310{
311 switch (endianness) {
312 case REGMAP_NATIVE_ENDIAN:
313 writew(*val, addr);
314 break;
315 case REGMAP_LITTLE_ENDIAN:
316 out_le16(addr, *val);
317 break;
318 case REGMAP_BIG_ENDIAN:
319 out_be16(addr, *val);
320 break;
321 }
322}
323
324static inline void __write_32(u32 *addr, const u32 *val,
325 enum regmap_endianness_t endianness)
326{
327 switch (endianness) {
328 case REGMAP_NATIVE_ENDIAN:
329 writel(*val, addr);
330 break;
331 case REGMAP_LITTLE_ENDIAN:
332 out_le32(addr, *val);
333 break;
334 case REGMAP_BIG_ENDIAN:
335 out_be32(addr, *val);
336 break;
337 }
338}
339
340#if defined(out_le64) && defined(out_be64) && defined(writeq)
341static inline void __write_64(u64 *addr, const u64 *val,
342 enum regmap_endianness_t endianness)
343{
344 switch (endianness) {
345 case REGMAP_NATIVE_ENDIAN:
346 writeq(*val, addr);
347 break;
348 case REGMAP_LITTLE_ENDIAN:
349 out_le64(addr, *val);
350 break;
351 case REGMAP_BIG_ENDIAN:
352 out_be64(addr, *val);
353 break;
354 }
355}
356#endif
357
358int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
359 const void *val, size_t val_len)
360{
361 struct regmap_range *range;
362 void *ptr;
363
364 if (range_num >= map->range_count) {
365 debug("%s: range index %d larger than range count\n",
366 __func__, range_num);
367 return -ERANGE;
368 }
369 range = &map->ranges[range_num];
370
371 ptr = map_physmem(range->start + offset, val_len, MAP_NOCACHE);
372
373 if (offset + val_len > range->size) {
374 debug("%s: offset/size combination invalid\n", __func__);
375 return -ERANGE;
376 }
377
378 switch (val_len) {
379 case REGMAP_SIZE_8:
380 __write_8(ptr, val, map->endianness);
381 break;
382 case REGMAP_SIZE_16:
383 __write_16(ptr, val, map->endianness);
384 break;
385 case REGMAP_SIZE_32:
386 __write_32(ptr, val, map->endianness);
387 break;
388#if defined(out_le64) && defined(out_be64) && defined(writeq)
389 case REGMAP_SIZE_64:
390 __write_64(ptr, val, map->endianness);
391 break;
392#endif
393 default:
394 debug("%s: regmap size %zu unknown\n", __func__, val_len);
395 return -EINVAL;
396 }
132 397
133 return 0; 398 return 0;
134} 399}
135 400
401int regmap_raw_write(struct regmap *map, uint offset, const void *val,
402 size_t val_len)
403{
404 return regmap_raw_write_range(map, 0, offset, val, val_len);
405}
406
407int regmap_write(struct regmap *map, uint offset, uint val)
408{
409 return regmap_raw_write(map, offset, &val, REGMAP_SIZE_32);
410}
411
136int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val) 412int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val)
137{ 413{
138 uint reg; 414 uint reg;
diff --git a/drivers/core/root.c b/drivers/core/root.c
index b54bf5bcdc..4ce55f9cc8 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -222,14 +222,22 @@ static int dm_scan_fdt_live(struct udevice *parent,
222 int ret = 0, err; 222 int ret = 0, err;
223 223
224 for (np = node_parent->child; np; np = np->sibling) { 224 for (np = node_parent->child; np; np = np->sibling) {
225 if (pre_reloc_only && 225 /* "chosen" node isn't a device itself but may contain some: */
226 !of_find_property(np, "u-boot,dm-pre-reloc", NULL)) 226 if (!strcmp(np->name, "chosen")) {
227 pr_debug("parsing subnodes of \"chosen\"\n");
228
229 err = dm_scan_fdt_live(parent, np, pre_reloc_only);
230 if (err && !ret)
231 ret = err;
227 continue; 232 continue;
233 }
234
228 if (!of_device_is_available(np)) { 235 if (!of_device_is_available(np)) {
229 pr_debug(" - ignoring disabled device\n"); 236 pr_debug(" - ignoring disabled device\n");
230 continue; 237 continue;
231 } 238 }
232 err = lists_bind_fdt(parent, np_to_ofnode(np), NULL); 239 err = lists_bind_fdt(parent, np_to_ofnode(np), NULL,
240 pre_reloc_only);
233 if (err && !ret) { 241 if (err && !ret) {
234 ret = err; 242 ret = err;
235 debug("%s: ret=%d\n", np->name, ret); 243 debug("%s: ret=%d\n", np->name, ret);
@@ -282,14 +290,12 @@ static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
282 continue; 290 continue;
283 } 291 }
284 292
285 if (pre_reloc_only &&
286 !dm_fdt_pre_reloc(blob, offset))
287 continue;
288 if (!fdtdec_get_is_enabled(blob, offset)) { 293 if (!fdtdec_get_is_enabled(blob, offset)) {
289 pr_debug(" - ignoring disabled device\n"); 294 pr_debug(" - ignoring disabled device\n");
290 continue; 295 continue;
291 } 296 }
292 err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL); 297 err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL,
298 pre_reloc_only);
293 if (err && !ret) { 299 if (err && !ret) {
294 ret = err; 300 ret = err;
295 debug("%s: ret=%d\n", node_name, ret); 301 debug("%s: ret=%d\n", node_name, ret);
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 3113d6a56b..6cfcde8918 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -180,7 +180,7 @@ int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp)
180 if (list_empty(&uc->dev_head)) 180 if (list_empty(&uc->dev_head))
181 return -ENODEV; 181 return -ENODEV;
182 182
183 list_for_each_entry(iter, &uc->dev_head, uclass_node) { 183 uclass_foreach_dev(iter, uc) {
184 if (iter == dev) { 184 if (iter == dev) {
185 if (ucp) 185 if (ucp)
186 *ucp = uc; 186 *ucp = uc;
@@ -205,7 +205,7 @@ int uclass_find_device(enum uclass_id id, int index, struct udevice **devp)
205 if (list_empty(&uc->dev_head)) 205 if (list_empty(&uc->dev_head))
206 return -ENODEV; 206 return -ENODEV;
207 207
208 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 208 uclass_foreach_dev(dev, uc) {
209 if (!index--) { 209 if (!index--) {
210 *devp = dev; 210 *devp = dev;
211 return 0; 211 return 0;
@@ -259,7 +259,7 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name,
259 if (ret) 259 if (ret)
260 return ret; 260 return ret;
261 261
262 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 262 uclass_foreach_dev(dev, uc) {
263 if (!strncmp(dev->name, name, strlen(name))) { 263 if (!strncmp(dev->name, name, strlen(name))) {
264 *devp = dev; 264 *devp = dev;
265 return 0; 265 return 0;
@@ -284,7 +284,7 @@ int uclass_find_device_by_seq(enum uclass_id id, int seq_or_req_seq,
284 if (ret) 284 if (ret)
285 return ret; 285 return ret;
286 286
287 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 287 uclass_foreach_dev(dev, uc) {
288 debug(" - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name); 288 debug(" - %d %d '%s'\n", dev->req_seq, dev->seq, dev->name);
289 if ((find_req_seq ? dev->req_seq : dev->seq) == 289 if ((find_req_seq ? dev->req_seq : dev->seq) ==
290 seq_or_req_seq) { 290 seq_or_req_seq) {
@@ -312,7 +312,7 @@ int uclass_find_device_by_of_offset(enum uclass_id id, int node,
312 if (ret) 312 if (ret)
313 return ret; 313 return ret;
314 314
315 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 315 uclass_foreach_dev(dev, uc) {
316 if (dev_of_offset(dev) == node) { 316 if (dev_of_offset(dev) == node) {
317 *devp = dev; 317 *devp = dev;
318 return 0; 318 return 0;
@@ -337,7 +337,7 @@ int uclass_find_device_by_ofnode(enum uclass_id id, ofnode node,
337 if (ret) 337 if (ret)
338 return ret; 338 return ret;
339 339
340 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 340 uclass_foreach_dev(dev, uc) {
341 log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n", 341 log(LOGC_DM, LOGL_DEBUG_CONTENT, " - checking %s\n",
342 dev->name); 342 dev->name);
343 if (ofnode_equal(dev_ofnode(dev), node)) { 343 if (ofnode_equal(dev_ofnode(dev), node)) {
@@ -372,7 +372,7 @@ static int uclass_find_device_by_phandle(enum uclass_id id,
372 if (ret) 372 if (ret)
373 return ret; 373 return ret;
374 374
375 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 375 uclass_foreach_dev(dev, uc) {
376 uint phandle; 376 uint phandle;
377 377
378 phandle = dev_read_phandle(dev); 378 phandle = dev_read_phandle(dev);
@@ -399,7 +399,7 @@ int uclass_get_device_by_driver(enum uclass_id id,
399 if (ret) 399 if (ret)
400 return ret; 400 return ret;
401 401
402 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 402 uclass_foreach_dev(dev, uc) {
403 if (dev->driver == find_drv) 403 if (dev->driver == find_drv)
404 return uclass_get_device_tail(dev, 0, devp); 404 return uclass_get_device_tail(dev, 0, devp);
405 } 405 }
@@ -499,7 +499,7 @@ int uclass_get_device_by_phandle_id(enum uclass_id id, uint phandle_id,
499 if (ret) 499 if (ret)
500 return ret; 500 return ret;
501 501
502 list_for_each_entry(dev, &uc->dev_head, uclass_node) { 502 uclass_foreach_dev(dev, uc) {
503 uint phandle; 503 uint phandle;
504 504
505 phandle = dev_read_phandle(dev); 505 phandle = dev_read_phandle(dev);
@@ -687,8 +687,19 @@ int uclass_pre_probe_device(struct udevice *dev)
687 687
688int uclass_post_probe_device(struct udevice *dev) 688int uclass_post_probe_device(struct udevice *dev)
689{ 689{
690 struct uclass_driver *uc_drv = dev->uclass->uc_drv; 690 struct uclass_driver *uc_drv;
691 int ret;
692
693 if (dev->parent) {
694 uc_drv = dev->parent->uclass->uc_drv;
695 if (uc_drv->child_post_probe) {
696 ret = uc_drv->child_post_probe(dev);
697 if (ret)
698 return ret;
699 }
700 }
691 701
702 uc_drv = dev->uclass->uc_drv;
692 if (uc_drv->post_probe) 703 if (uc_drv->post_probe)
693 return uc_drv->post_probe(dev); 704 return uc_drv->post_probe(dev);
694 705
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 451d4766d0..27a6848703 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -4,6 +4,7 @@
4 */ 4 */
5 5
6#include <common.h> 6#include <common.h>
7#include <dm/ofnode.h>
7#include <dm/util.h> 8#include <dm/util.h>
8#include <linux/libfdt.h> 9#include <linux/libfdt.h>
9#include <vsprintf.h> 10#include <vsprintf.h>
@@ -53,3 +54,27 @@ bool dm_fdt_pre_reloc(const void *blob, int offset)
53 54
54 return false; 55 return false;
55} 56}
57
58bool dm_ofnode_pre_reloc(ofnode node)
59{
60 if (ofnode_read_bool(node, "u-boot,dm-pre-reloc"))
61 return true;
62
63#ifdef CONFIG_TPL_BUILD
64 if (ofnode_read_bool(node, "u-boot,dm-tpl"))
65 return true;
66#elif defined(CONFIG_SPL_BUILD)
67 if (ofnode_read_bool(node, "u-boot,dm-spl"))
68 return true;
69#else
70 /*
71 * In regular builds individual spl and tpl handling both
72 * count as handled pre-relocation for later second init.
73 */
74 if (ofnode_read_bool(node, "u-boot,dm-spl") ||
75 ofnode_read_bool(node, "u-boot,dm-tpl"))
76 return true;
77#endif
78
79 return false;
80}
diff --git a/drivers/cpu/mpc83xx_cpu.c b/drivers/cpu/mpc83xx_cpu.c
index 31717afaec..7bc86bf9b2 100644
--- a/drivers/cpu/mpc83xx_cpu.c
+++ b/drivers/cpu/mpc83xx_cpu.c
@@ -262,7 +262,7 @@ static int mpc83xx_cpu_get_desc(struct udevice *dev, char *buf, int size)
262 determine_cpu_data(dev); 262 determine_cpu_data(dev);
263 263
264 snprintf(buf, size, 264 snprintf(buf, size,
265 "CPU: %s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz\n", 265 "%s, MPC%s%s%s, Rev: %d.%d at %s MHz, CSB: %s MHz",
266 e300_names[priv->e300_type], 266 e300_names[priv->e300_type],
267 cpu_type_names[priv->type], 267 cpu_type_names[priv->type],
268 priv->is_e_processor ? "E" : "", 268 priv->is_e_processor ? "E" : "",
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 555eba2662..0031415d03 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -372,7 +372,9 @@ U_BOOT_DRIVER(gpio_omap) = {
372 .ops = &gpio_omap_ops, 372 .ops = &gpio_omap_ops,
373 .probe = omap_gpio_probe, 373 .probe = omap_gpio_probe,
374 .priv_auto_alloc_size = sizeof(struct gpio_bank), 374 .priv_auto_alloc_size = sizeof(struct gpio_bank),
375#if !CONFIG_IS_ENABLED(OF_CONTROL)
375 .flags = DM_FLAG_PRE_RELOC, 376 .flags = DM_FLAG_PRE_RELOC,
377#endif
376}; 378};
377 379
378#endif /* CONFIG_DM_GPIO */ 380#endif /* CONFIG_DM_GPIO */
diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32f7_gpio.c
index 4c0786fff8..b903dc46b3 100644
--- a/drivers/gpio/stm32f7_gpio.c
+++ b/drivers/gpio/stm32f7_gpio.c
@@ -123,6 +123,6 @@ U_BOOT_DRIVER(gpio_stm32) = {
123 .of_match = stm32_gpio_ids, 123 .of_match = stm32_gpio_ids,
124 .probe = gpio_stm32_probe, 124 .probe = gpio_stm32_probe,
125 .ops = &gpio_stm32_ops, 125 .ops = &gpio_stm32_ops,
126 .flags = DM_FLAG_PRE_RELOC | DM_UC_FLAG_SEQ_ALIAS, 126 .flags = DM_UC_FLAG_SEQ_ALIAS,
127 .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv), 127 .priv_auto_alloc_size = sizeof(struct stm32_gpio_priv),
128}; 128};
diff --git a/drivers/gpio/tegra186_gpio.c b/drivers/gpio/tegra186_gpio.c
index 1f0e8d51da..6626b5415a 100644
--- a/drivers/gpio/tegra186_gpio.c
+++ b/drivers/gpio/tegra186_gpio.c
@@ -281,5 +281,4 @@ U_BOOT_DRIVER(tegra186_gpio) = {
281 .bind = tegra186_gpio_bind, 281 .bind = tegra186_gpio_bind,
282 .probe = tegra186_gpio_probe, 282 .probe = tegra186_gpio_probe,
283 .ops = &tegra186_gpio_ops, 283 .ops = &tegra186_gpio_ops,
284 .flags = DM_FLAG_PRE_RELOC,
285}; 284};
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 302efddc27..a730f5c4fe 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -378,5 +378,4 @@ U_BOOT_DRIVER(gpio_tegra) = {
378 .probe = gpio_tegra_probe, 378 .probe = gpio_tegra_probe,
379 .priv_auto_alloc_size = sizeof(struct tegra_port_info), 379 .priv_auto_alloc_size = sizeof(struct tegra_port_info),
380 .ops = &gpio_tegra_ops, 380 .ops = &gpio_tegra_ops,
381 .flags = DM_FLAG_PRE_RELOC,
382}; 381};
diff --git a/drivers/i2c/omap24xx_i2c.c b/drivers/i2c/omap24xx_i2c.c
index 54bf35e552..51f923752c 100644
--- a/drivers/i2c/omap24xx_i2c.c
+++ b/drivers/i2c/omap24xx_i2c.c
@@ -925,7 +925,9 @@ U_BOOT_DRIVER(i2c_omap) = {
925 .probe = omap_i2c_probe, 925 .probe = omap_i2c_probe,
926 .priv_auto_alloc_size = sizeof(struct omap_i2c), 926 .priv_auto_alloc_size = sizeof(struct omap_i2c),
927 .ops = &omap_i2c_ops, 927 .ops = &omap_i2c_ops,
928#if !CONFIG_IS_ENABLED(OF_CONTROL)
928 .flags = DM_FLAG_PRE_RELOC, 929 .flags = DM_FLAG_PRE_RELOC,
930#endif
929}; 931};
930 932
931#endif /* CONFIG_DM_I2C */ 933#endif /* CONFIG_DM_I2C */
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index c5697011f2..48febc47d2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -312,4 +312,21 @@ config FS_LOADER
312 The consumer driver would then use this loader to program whatever, 312 The consumer driver would then use this loader to program whatever,
313 ie. the FPGA device. 313 ie. the FPGA device.
314 314
315config GDSYS_SOC
316 bool "Enable gdsys SOC driver"
317 depends on MISC
318 help
319 Support for gdsys IHS SOC, a simple bus associated with each gdsys
320 IHS (Integrated Hardware Systems) FPGA, which holds all devices whose
321 register maps are contained within the FPGA's register map.
322
323config IHS_FPGA
324 bool "Enable IHS FPGA driver"
325 depends on MISC
326 help
327 Support IHS (Integrated Hardware Systems) FPGA, the main FPGAs on
328 gdsys devices, which supply the majority of the functionality offered
329 by the devices. This driver supports both CON and CPU variants of the
330 devices, depending on the device tree entry.
331
315endmenu 332endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 759d2c791b..302d441592 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -4,11 +4,6 @@
4# Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 5
6obj-$(CONFIG_MISC) += misc-uclass.o 6obj-$(CONFIG_MISC) += misc-uclass.o
7obj-$(CONFIG_ALI152X) += ali512x.o
8obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
9obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
10obj-$(CONFIG_DS4510) += ds4510.o
11obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
12ifndef CONFIG_SPL_BUILD 7ifndef CONFIG_SPL_BUILD
13obj-$(CONFIG_CROS_EC) += cros_ec.o 8obj-$(CONFIG_CROS_EC) += cros_ec.o
14obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o 9obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
@@ -16,46 +11,54 @@ obj-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o
16obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o 11obj-$(CONFIG_CROS_EC_SANDBOX) += cros_ec_sandbox.o
17obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o 12obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
18endif 13endif
19obj-$(CONFIG_FSL_IIM) += fsl_iim.o 14
20obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
21obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
22obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
23obj-$(CONFIG_IMX8) += imx8/
24obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
25obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
26obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
27obj-$(CONFIG_NS87308) += ns87308.o
28obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
29ifdef CONFIG_DM_I2C 15ifdef CONFIG_DM_I2C
30ifndef CONFIG_SPL_BUILD 16ifndef CONFIG_SPL_BUILD
31obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o 17obj-$(CONFIG_SANDBOX) += i2c_eeprom_emul.o
32endif 18endif
33endif 19endif
34obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
35obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
36obj-$(CONFIG_LED_STATUS) += status_led.o
37obj-$(CONFIG_SANDBOX) += swap_case.o
38ifdef CONFIG_SPL_OF_PLATDATA 20ifdef CONFIG_SPL_OF_PLATDATA
39ifdef CONFIG_SPL_BUILD 21ifdef CONFIG_SPL_BUILD
40obj-$(CONFIG_SANDBOX) += spltest_sandbox.o 22obj-$(CONFIG_SANDBOX) += spltest_sandbox.o
41endif 23endif
42endif 24endif
43obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o 25obj-$(CONFIG_ALI152X) += ali512x.o
44obj-$(CONFIG_TEGRA_CAR) += tegra_car.o 26obj-$(CONFIG_ALTERA_SYSID) += altera_sysid.o
45obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o 27obj-$(CONFIG_ATSHA204A) += atsha204a-i2c.o
46obj-$(CONFIG_TWL4030_LED) += twl4030_led.o 28obj-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o
29obj-$(CONFIG_DS4510) += ds4510.o
30obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
47obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 31obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
32obj-$(CONFIG_FSL_IIM) += fsl_iim.o
33obj-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o
48obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o 34obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
35obj-$(CONFIG_FS_LOADER) += fs_loader.o
36obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
37obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
38obj-$(CONFIG_GDSYS_SOC) += gdsys_soc.o
39obj-$(CONFIG_$(SPL_)I2C_EEPROM) += i2c_eeprom.o
40obj-$(CONFIG_IHS_FPGA) += ihs_fpga.o
41obj-$(CONFIG_IMX8) += imx8/
42obj-$(CONFIG_LED_STATUS) += status_led.o
43obj-$(CONFIG_LED_STATUS_GPIO) += gpio_led.o
44obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
45obj-$(CONFIG_MXC_OCOTP) += mxc_ocotp.o
46obj-$(CONFIG_MXS_OCOTP) += mxs_ocotp.o
47obj-$(CONFIG_NS87308) += ns87308.o
48obj-$(CONFIG_NUVOTON_NCT6102D) += nuvoton_nct6102d.o
49obj-$(CONFIG_PCA9551_LED) += pca9551_led.o 49obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
50obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o 50obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
51obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
52obj-$(CONFIG_QFW) += qfw.o 51obj-$(CONFIG_QFW) += qfw.o
53obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o 52obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
54obj-$(CONFIG_STM32_RCC) += stm32_rcc.o 53obj-$(CONFIG_SANDBOX) += swap_case.o
54obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
55obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
56obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
55obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o 57obj-$(CONFIG_STM32MP_FUSE) += stm32mp_fuse.o
58obj-$(CONFIG_STM32_RCC) += stm32_rcc.o
56obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o 59obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o
57obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o 60obj-$(CONFIG_TEGRA186_BPMP) += tegra186_bpmp.o
58obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o 61obj-$(CONFIG_TEGRA_CAR) += tegra_car.o
62obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
59obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o 63obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
60obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o 64obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
61obj-$(CONFIG_FS_LOADER) += fs_loader.o
diff --git a/drivers/misc/gdsys_soc.c b/drivers/misc/gdsys_soc.c
new file mode 100644
index 0000000000..94a21e08af
--- /dev/null
+++ b/drivers/misc/gdsys_soc.c
@@ -0,0 +1,74 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2017
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <dm/lists.h>
10
11#include "gdsys_soc.h"
12
13/**
14 * struct gdsys_soc_priv - Private data for gdsys soc bus
15 * @fpga: The gdsys IHS FPGA this bus is associated with
16 */
17struct gdsys_soc_priv {
18 struct udevice *fpga;
19};
20
21static const struct udevice_id gdsys_soc_ids[] = {
22 { .compatible = "gdsys,soc" },
23 { /* sentinel */ }
24};
25
26int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga)
27{
28 struct gdsys_soc_priv *bus_priv;
29
30 if (!child->parent) {
31 debug("%s: Invalid parent\n", child->name);
32 return -EINVAL;
33 }
34
35 if (!device_is_compatible(child->parent, "gdsys,soc")) {
36 debug("%s: Not child of a gdsys soc\n", child->name);
37 return -EINVAL;
38 }
39
40 bus_priv = dev_get_priv(child->parent);
41
42 *fpga = bus_priv->fpga;
43
44 return 0;
45}
46
47static int gdsys_soc_probe(struct udevice *dev)
48{
49 struct gdsys_soc_priv *priv = dev_get_priv(dev);
50 struct udevice *fpga;
51 int res = uclass_get_device_by_phandle(UCLASS_MISC, dev, "fpga",
52 &fpga);
53 if (res == -ENOENT) {
54 debug("%s: Could not find 'fpga' phandle\n", dev->name);
55 return -EINVAL;
56 }
57
58 if (res == -ENODEV) {
59 debug("%s: Could not get FPGA device\n", dev->name);
60 return -EINVAL;
61 }
62
63 priv->fpga = fpga;
64
65 return 0;
66}
67
68U_BOOT_DRIVER(gdsys_soc_bus) = {
69 .name = "gdsys_soc_bus",
70 .id = UCLASS_SIMPLE_BUS,
71 .of_match = gdsys_soc_ids,
72 .probe = gdsys_soc_probe,
73 .priv_auto_alloc_size = sizeof(struct gdsys_soc_priv),
74};
diff --git a/drivers/misc/gdsys_soc.h b/drivers/misc/gdsys_soc.h
new file mode 100644
index 0000000000..088d3b6523
--- /dev/null
+++ b/drivers/misc/gdsys_soc.h
@@ -0,0 +1,23 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2017
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 */
6
7#ifndef _GDSYS_SOC_H_
8#define _GDSYS_SOC_H_
9
10/**
11 * gdsys_soc_get_fpga() - Retrieve pointer to parent bus' FPGA device
12 * @child: The child device on the FPGA bus needing access to the FPGA.
13 * @fpga: Pointer to the retrieved FPGA device.
14 *
15 * To access their register maps, devices on gdsys soc buses usually have
16 * facilitate the accessor function of the IHS FPGA their parent bus is
17 * attached to. To access the FPGA device from within the bus' children, this
18 * function returns a pointer to it.
19 *
20 * Return: 0 on success, -ve on failure
21 */
22int gdsys_soc_get_fpga(struct udevice *child, struct udevice **fpga);
23#endif /* _GDSYS_SOC_H_ */
diff --git a/drivers/misc/ihs_fpga.c b/drivers/misc/ihs_fpga.c
new file mode 100644
index 0000000000..f9e4b27a27
--- /dev/null
+++ b/drivers/misc/ihs_fpga.c
@@ -0,0 +1,867 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2017
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 *
6 * based on the ioep-fpga driver, which is
7 *
8 * (C) Copyright 2014
9 * Dirk Eibach, Guntermann & Drunck GmbH, eibach@gdsys.de
10 */
11
12#include <common.h>
13#include <dm.h>
14#include <regmap.h>
15#include <asm/gpio.h>
16
17#include "ihs_fpga.h"
18
19/**
20 * struct ihs_fpga_priv - Private data structure for IHS FPGA driver
21 * @map: Register map for the FPGA's own register space
22 * @reset_gpio: GPIO to start FPGA reconfiguration
23 * @done_gpio: GPOI to read the 'ready' status of the FPGA
24 */
25struct ihs_fpga_priv {
26 struct regmap *map;
27 struct gpio_desc reset_gpio;
28 struct gpio_desc done_gpio;
29};
30
31/* Test pattern for reflection test */
32const u16 REFLECTION_TESTPATTERN = 0xdead;
33/* Delay (in ms) for each round in the reflection test */
34const uint REFLECTION_TEST_DELAY = 100;
35/* Maximum number of rounds in the reflection test */
36const uint REFLECTION_TEST_ROUNDS = 5;
37/* Delay (in ms) for each round waiting for the FPGA's done GPIO */
38const uint FPGA_DONE_WAIT_DELAY = 100;
39/* Maximum number of rounds for waiting for the FPGA's done GPIO */
40const uint FPGA_DONE_WAIT_ROUND = 5;
41
42/**
43 * enum pcb_video_type - Video type of the PCB
44 * @PCB_DVI_SL: Video type is DVI single-link
45 * @PCB_DP_165MPIX: Video type is DisplayPort (165Mpix)
46 * @PCB_DP_300MPIX: Video type is DisplayPort (300Mpix)
47 * @PCB_HDMI: Video type is HDMI
48 * @PCB_DP_1_2: Video type is DisplayPort 1.2
49 * @PCB_HDMI_2_0: Video type is HDMI 2.0
50 */
51enum pcb_video_type {
52 PCB_DVI_SL,
53 PCB_DP_165MPIX,
54 PCB_DP_300MPIX,
55 PCB_HDMI,
56 PCB_DP_1_2,
57 PCB_HDMI_2_0,
58};
59
60/**
61 * enum pcb_transmission_type - Transmission type of the PCB
62 * @PCB_CAT_1G: Transmission type is 1G Ethernet
63 * @PCB_FIBER_3G: Transmission type is 3G Fiber
64 * @PCB_CAT_10G: Transmission type is 10G Ethernet
65 * @PCB_FIBER_10G: Transmission type is 10G Fiber
66 */
67enum pcb_transmission_type {
68 PCB_CAT_1G,
69 PCB_FIBER_3G,
70 PCB_CAT_10G,
71 PCB_FIBER_10G,
72};
73
74/**
75 * enum carrier_speed - Speed of the FPGA's carrier
76 * @CARRIER_SPEED_1G: The carrier speed is 1G
77 * @CARRIER_SPEED_2_5G: The carrier speed is 2.5G
78 * @CARRIER_SPEED_3G: The carrier speed is 3G
79 * @CARRIER_SPEED_10G: The carrier speed is 10G
80 */
81enum carrier_speed {
82 CARRIER_SPEED_1G,
83 CARRIER_SPEED_3G,
84 CARRIER_SPEED_2_5G = CARRIER_SPEED_3G,
85 CARRIER_SPEED_10G,
86};
87
88/**
89 * enum ram_config - FPGA's RAM configuration
90 * @RAM_DDR2_32BIT_295MBPS: DDR2 32 bit at 295Mb/s
91 * @RAM_DDR3_32BIT_590MBPS: DDR3 32 bit at 590Mb/s
92 * @RAM_DDR3_48BIT_590MBPS: DDR3 48 bit at 590Mb/s
93 * @RAM_DDR3_64BIT_1800MBPS: DDR3 64 bit at 1800Mb/s
94 * @RAM_DDR3_48BIT_1800MBPS: DDR3 48 bit at 1800Mb/s
95 */
96enum ram_config {
97 RAM_DDR2_32BIT_295MBPS,
98 RAM_DDR3_32BIT_590MBPS,
99 RAM_DDR3_48BIT_590MBPS,
100 RAM_DDR3_64BIT_1800MBPS,
101 RAM_DDR3_48BIT_1800MBPS,
102};
103
104/**
105 * enum sysclock - Speed of the FPGA's system clock
106 * @SYSCLK_147456: System clock is 147.456 MHz
107 */
108enum sysclock {
109 SYSCLK_147456,
110};
111
112/**
113 * struct fpga_versions - Data read from the versions register
114 * @video_channel: Is the FPGA for a video channel (true) or main
115 * channel (false) device?
116 * @con_side: Is the FPGA for a CON (true) or a CPU (false) device?
117 * @pcb_video_type: Defines for whch video type the FPGA is configured
118 * @pcb_transmission_type: Defines for which transmission type the FPGA is
119 * configured
120 * @hw_version: Hardware version of the FPGA
121 */
122struct fpga_versions {
123 bool video_channel;
124 bool con_side;
125 enum pcb_video_type pcb_video_type;
126 enum pcb_transmission_type pcb_transmission_type;
127 unsigned int hw_version;
128};
129
130/**
131 * struct fpga_features - Data read from the features register
132 * @video_channels: Number of video channels supported
133 * @carriers: Number of carrier channels supported
134 * @carrier_speed: Speed of carriers
135 * @ram_config: RAM configuration of FPGA
136 * @sysclock: System clock speed of FPGA
137 * @pcm_tx: Support for PCM transmission
138 * @pcm_rx: Support for PCM reception
139 * @spdif_tx: Support for SPDIF audio transmission
140 * @spdif_rx: Support for SPDIF audio reception
141 * @usb2: Support for transparent USB2.0
142 * @rs232: Support for bidirectional RS232
143 * @compression_type1: Support for compression type 1
144 * @compression_type2: Support for compression type 2
145 * @compression_type3: Support for compression type 3
146 * @interlace: Support for interlace image formats
147 * @osd: Support for a OSD
148 * @compression_pipes: Number of compression pipes supported
149 */
150struct fpga_features {
151 u8 video_channels;
152 u8 carriers;
153 enum carrier_speed carrier_speed;
154 enum ram_config ram_config;
155 enum sysclock sysclock;
156 bool pcm_tx;
157 bool pcm_rx;
158 bool spdif_tx;
159 bool spdif_rx;
160 bool usb2;
161 bool rs232;
162 bool compression_type1;
163 bool compression_type2;
164 bool compression_type3;
165 bool interlace;
166 bool osd;
167 bool compression_pipes;
168};
169
170#ifdef CONFIG_SYS_FPGA_FLAVOR_GAZERBEAM
171
172/**
173 * get_versions() - Fill structure with info from version register.
174 * @dev: FPGA device to be queried for information
175 * @versions: Pointer to the structure to fill with information from the
176 * versions register
177 * Return: 0
178 */
179static int get_versions(struct udevice *dev, struct fpga_versions *versions)
180{
181 struct ihs_fpga_priv *priv = dev_get_priv(dev);
182 enum {
183 VERSIONS_FPGA_VIDEO_CHANNEL = BIT(12),
184 VERSIONS_FPGA_CON_SIDE = BIT(13),
185 VERSIONS_FPGA_SC = BIT(14),
186 VERSIONS_PCB_CON = BIT(9),
187 VERSIONS_PCB_SC = BIT(8),
188 VERSIONS_PCB_VIDEO_MASK = 0x3 << 6,
189 VERSIONS_PCB_VIDEO_DP_1_2 = 0x0 << 6,
190 VERSIONS_PCB_VIDEO_HDMI_2_0 = 0x1 << 6,
191 VERSIONS_PCB_TRANSMISSION_MASK = 0x3 << 4,
192 VERSIONS_PCB_TRANSMISSION_FIBER_10G = 0x0 << 4,
193 VERSIONS_PCB_TRANSMISSION_CAT_10G = 0x1 << 4,
194 VERSIONS_PCB_TRANSMISSION_FIBER_3G = 0x2 << 4,
195 VERSIONS_PCB_TRANSMISSION_CAT_1G = 0x3 << 4,
196 VERSIONS_HW_VER_MASK = 0xf << 0,
197 };
198 u16 raw_versions;
199
200 memset(versions, 0, sizeof(struct fpga_versions));
201
202 ihs_fpga_get(priv->map, versions, &raw_versions);
203
204 versions->video_channel = raw_versions & VERSIONS_FPGA_VIDEO_CHANNEL;
205 versions->con_side = raw_versions & VERSIONS_FPGA_CON_SIDE;
206
207 switch (raw_versions & VERSIONS_PCB_VIDEO_MASK) {
208 case VERSIONS_PCB_VIDEO_DP_1_2:
209 versions->pcb_video_type = PCB_DP_1_2;
210 break;
211
212 case VERSIONS_PCB_VIDEO_HDMI_2_0:
213 versions->pcb_video_type = PCB_HDMI_2_0;
214 break;
215 }
216
217 switch (raw_versions & VERSIONS_PCB_TRANSMISSION_MASK) {
218 case VERSIONS_PCB_TRANSMISSION_FIBER_10G:
219 versions->pcb_transmission_type = PCB_FIBER_10G;
220 break;
221
222 case VERSIONS_PCB_TRANSMISSION_CAT_10G:
223 versions->pcb_transmission_type = PCB_CAT_10G;
224 break;
225
226 case VERSIONS_PCB_TRANSMISSION_FIBER_3G:
227 versions->pcb_transmission_type = PCB_FIBER_3G;
228 break;
229
230 case VERSIONS_PCB_TRANSMISSION_CAT_1G:
231 versions->pcb_transmission_type = PCB_CAT_1G;
232 break;
233 }
234
235 versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
236
237 return 0;
238}
239
240/**
241 * get_features() - Fill structure with info from features register.
242 * @dev: FPGA device to be queried for information
243 * @features: Pointer to the structure to fill with information from the
244 * features register
245 * Return: 0
246 */
247static int get_features(struct udevice *dev, struct fpga_features *features)
248{
249 struct ihs_fpga_priv *priv = dev_get_priv(dev);
250 enum {
251 FEATURE_SPDIF_RX = BIT(15),
252 FEATURE_SPDIF_TX = BIT(14),
253 FEATURE_PCM_RX = BIT(13),
254 FEATURE_PCM_TX = BIT(12),
255 FEATURE_RAM_MASK = GENMASK(11, 8),
256 FEATURE_RAM_DDR2_32BIT_295MBPS = 0x0 << 8,
257 FEATURE_RAM_DDR3_32BIT_590MBPS = 0x1 << 8,
258 FEATURE_RAM_DDR3_48BIT_590MBPS = 0x2 << 8,
259 FEATURE_RAM_DDR3_64BIT_1800MBPS = 0x3 << 8,
260 FEATURE_RAM_DDR3_48BIT_1800MBPS = 0x4 << 8,
261 FEATURE_CARRIER_SPEED_MASK = GENMASK(7, 6),
262 FEATURE_CARRIER_SPEED_1G = 0x0 << 6,
263 FEATURE_CARRIER_SPEED_2_5G = 0x1 << 6,
264 FEATURE_CARRIER_SPEED_10G = 0x2 << 6,
265 FEATURE_CARRIERS_MASK = GENMASK(5, 4),
266 FEATURE_CARRIERS_0 = 0x0 << 4,
267 FEATURE_CARRIERS_1 = 0x1 << 4,
268 FEATURE_CARRIERS_2 = 0x2 << 4,
269 FEATURE_CARRIERS_4 = 0x3 << 4,
270 FEATURE_USB2 = BIT(3),
271 FEATURE_VIDEOCHANNELS_MASK = GENMASK(2, 0),
272 FEATURE_VIDEOCHANNELS_0 = 0x0 << 0,
273 FEATURE_VIDEOCHANNELS_1 = 0x1 << 0,
274 FEATURE_VIDEOCHANNELS_1_1 = 0x2 << 0,
275 FEATURE_VIDEOCHANNELS_2 = 0x3 << 0,
276 };
277
278 enum {
279 EXT_FEATURE_OSD = BIT(15),
280 EXT_FEATURE_ETHERNET = BIT(9),
281 EXT_FEATURE_INTERLACE = BIT(8),
282 EXT_FEATURE_RS232 = BIT(7),
283 EXT_FEATURE_COMPRESSION_PERF_MASK = GENMASK(6, 4),
284 EXT_FEATURE_COMPRESSION_PERF_1X = 0x0 << 4,
285 EXT_FEATURE_COMPRESSION_PERF_2X = 0x1 << 4,
286 EXT_FEATURE_COMPRESSION_PERF_4X = 0x2 << 4,
287 EXT_FEATURE_COMPRESSION_TYPE1 = BIT(0),
288 EXT_FEATURE_COMPRESSION_TYPE2 = BIT(1),
289 EXT_FEATURE_COMPRESSION_TYPE3 = BIT(2),
290 };
291
292 u16 raw_features;
293 u16 raw_extended_features;
294
295 memset(features, 0, sizeof(struct fpga_features));
296
297 ihs_fpga_get(priv->map, features, &raw_features);
298 ihs_fpga_get(priv->map, extended_features, &raw_extended_features);
299
300 switch (raw_features & FEATURE_VIDEOCHANNELS_MASK) {
301 case FEATURE_VIDEOCHANNELS_0:
302 features->video_channels = 0;
303 break;
304
305 case FEATURE_VIDEOCHANNELS_1:
306 features->video_channels = 1;
307 break;
308
309 case FEATURE_VIDEOCHANNELS_1_1:
310 case FEATURE_VIDEOCHANNELS_2:
311 features->video_channels = 2;
312 break;
313 };
314
315 switch (raw_features & FEATURE_CARRIERS_MASK) {
316 case FEATURE_CARRIERS_0:
317 features->carriers = 0;
318 break;
319
320 case FEATURE_CARRIERS_1:
321 features->carriers = 1;
322 break;
323
324 case FEATURE_CARRIERS_2:
325 features->carriers = 2;
326 break;
327
328 case FEATURE_CARRIERS_4:
329 features->carriers = 4;
330 break;
331 }
332
333 switch (raw_features & FEATURE_CARRIER_SPEED_MASK) {
334 case FEATURE_CARRIER_SPEED_1G:
335 features->carrier_speed = CARRIER_SPEED_1G;
336 break;
337 case FEATURE_CARRIER_SPEED_2_5G:
338 features->carrier_speed = CARRIER_SPEED_2_5G;
339 break;
340 case FEATURE_CARRIER_SPEED_10G:
341 features->carrier_speed = CARRIER_SPEED_10G;
342 break;
343 }
344
345 switch (raw_features & FEATURE_RAM_MASK) {
346 case FEATURE_RAM_DDR2_32BIT_295MBPS:
347 features->ram_config = RAM_DDR2_32BIT_295MBPS;
348 break;
349
350 case FEATURE_RAM_DDR3_32BIT_590MBPS:
351 features->ram_config = RAM_DDR3_32BIT_590MBPS;
352 break;
353
354 case FEATURE_RAM_DDR3_48BIT_590MBPS:
355 features->ram_config = RAM_DDR3_48BIT_590MBPS;
356 break;
357
358 case FEATURE_RAM_DDR3_64BIT_1800MBPS:
359 features->ram_config = RAM_DDR3_64BIT_1800MBPS;
360 break;
361
362 case FEATURE_RAM_DDR3_48BIT_1800MBPS:
363 features->ram_config = RAM_DDR3_48BIT_1800MBPS;
364 break;
365 }
366
367 features->pcm_tx = raw_features & FEATURE_PCM_TX;
368 features->pcm_rx = raw_features & FEATURE_PCM_RX;
369 features->spdif_tx = raw_features & FEATURE_SPDIF_TX;
370 features->spdif_rx = raw_features & FEATURE_SPDIF_RX;
371 features->usb2 = raw_features & FEATURE_USB2;
372 features->rs232 = raw_extended_features & EXT_FEATURE_RS232;
373 features->compression_type1 = raw_extended_features &
374 EXT_FEATURE_COMPRESSION_TYPE1;
375 features->compression_type2 = raw_extended_features &
376 EXT_FEATURE_COMPRESSION_TYPE2;
377 features->compression_type3 = raw_extended_features &
378 EXT_FEATURE_COMPRESSION_TYPE3;
379 features->interlace = raw_extended_features & EXT_FEATURE_INTERLACE;
380 features->osd = raw_extended_features & EXT_FEATURE_OSD;
381 features->compression_pipes = raw_extended_features &
382 EXT_FEATURE_COMPRESSION_PERF_MASK;
383
384 return 0;
385}
386
387#else
388
389/**
390 * get_versions() - Fill structure with info from version register.
391 * @fpga: Identifier of the FPGA device to be queried for information
392 * @versions: Pointer to the structure to fill with information from the
393 * versions register
394 *
395 * This is the legacy version and should be considered deprecated for new
396 * devices.
397 *
398 * Return: 0
399 */
400static int get_versions(unsigned int fpga, struct fpga_versions *versions)
401{
402 enum {
403 /* HW version encoding is a mess, leave it for the moment */
404 VERSIONS_HW_VER_MASK = 0xf << 0,
405 VERSIONS_PIX_CLOCK_GEN_IDT8N3QV01 = BIT(4),
406 VERSIONS_SFP = BIT(5),
407 VERSIONS_VIDEO_MASK = 0x7 << 6,
408 VERSIONS_VIDEO_DVI = 0x0 << 6,
409 VERSIONS_VIDEO_DP_165 = 0x1 << 6,
410 VERSIONS_VIDEO_DP_300 = 0x2 << 6,
411 VERSIONS_VIDEO_HDMI = 0x3 << 6,
412 VERSIONS_UT_MASK = 0xf << 12,
413 VERSIONS_UT_MAIN_SERVER = 0x0 << 12,
414 VERSIONS_UT_MAIN_USER = 0x1 << 12,
415 VERSIONS_UT_VIDEO_SERVER = 0x2 << 12,
416 VERSIONS_UT_VIDEO_USER = 0x3 << 12,
417 };
418 u16 raw_versions;
419
420 memset(versions, 0, sizeof(struct fpga_versions));
421
422 FPGA_GET_REG(fpga, versions, &raw_versions);
423
424 switch (raw_versions & VERSIONS_UT_MASK) {
425 case VERSIONS_UT_MAIN_SERVER:
426 versions->video_channel = false;
427 versions->con_side = false;
428 break;
429
430 case VERSIONS_UT_MAIN_USER:
431 versions->video_channel = false;
432 versions->con_side = true;
433 break;
434
435 case VERSIONS_UT_VIDEO_SERVER:
436 versions->video_channel = true;
437 versions->con_side = false;
438 break;
439
440 case VERSIONS_UT_VIDEO_USER:
441 versions->video_channel = true;
442 versions->con_side = true;
443 break;
444 }
445
446 switch (raw_versions & VERSIONS_VIDEO_MASK) {
447 case VERSIONS_VIDEO_DVI:
448 versions->pcb_video_type = PCB_DVI_SL;
449 break;
450
451 case VERSIONS_VIDEO_DP_165:
452 versions->pcb_video_type = PCB_DP_165MPIX;
453 break;
454
455 case VERSIONS_VIDEO_DP_300:
456 versions->pcb_video_type = PCB_DP_300MPIX;
457 break;
458
459 case VERSIONS_VIDEO_HDMI:
460 versions->pcb_video_type = PCB_HDMI;
461 break;
462 }
463
464 versions->hw_version = raw_versions & VERSIONS_HW_VER_MASK;
465
466 if (raw_versions & VERSIONS_SFP)
467 versions->pcb_transmission_type = PCB_FIBER_3G;
468 else
469 versions->pcb_transmission_type = PCB_CAT_1G;
470
471 return 0;
472}
473
474/**
475 * get_features() - Fill structure with info from features register.
476 * @fpga: Identifier of the FPGA device to be queried for information
477 * @features: Pointer to the structure to fill with information from the
478 * features register
479 *
480 * This is the legacy version and should be considered deprecated for new
481 * devices.
482 *
483 * Return: 0
484 */
485static int get_features(unsigned int fpga, struct fpga_features *features)
486{
487 enum {
488 FEATURE_CARRIER_SPEED_2_5 = BIT(4),
489 FEATURE_RAM_MASK = 0x7 << 5,
490 FEATURE_RAM_DDR2_32BIT = 0x0 << 5,
491 FEATURE_RAM_DDR3_32BIT = 0x1 << 5,
492 FEATURE_RAM_DDR3_48BIT = 0x2 << 5,
493 FEATURE_PCM_AUDIO_TX = BIT(9),
494 FEATURE_PCM_AUDIO_RX = BIT(10),
495 FEATURE_OSD = BIT(11),
496 FEATURE_USB20 = BIT(12),
497 FEATURE_COMPRESSION_MASK = 7 << 13,
498 FEATURE_COMPRESSION_TYPE1 = 0x1 << 13,
499 FEATURE_COMPRESSION_TYPE1_TYPE2 = 0x3 << 13,
500 FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3 = 0x7 << 13,
501 };
502
503 enum {
504 EXTENDED_FEATURE_SPDIF_AUDIO_TX = BIT(0),
505 EXTENDED_FEATURE_SPDIF_AUDIO_RX = BIT(1),
506 EXTENDED_FEATURE_RS232 = BIT(2),
507 EXTENDED_FEATURE_COMPRESSION_PIPES = BIT(3),
508 EXTENDED_FEATURE_INTERLACE = BIT(4),
509 };
510
511 u16 raw_features;
512 u16 raw_extended_features;
513
514 memset(features, 0, sizeof(struct fpga_features));
515
516 FPGA_GET_REG(fpga, fpga_features, &raw_features);
517 FPGA_GET_REG(fpga, fpga_ext_features, &raw_extended_features);
518
519 features->video_channels = raw_features & 0x3;
520 features->carriers = (raw_features >> 2) & 0x3;
521
522 features->carrier_speed = (raw_features & FEATURE_CARRIER_SPEED_2_5)
523 ? CARRIER_SPEED_2_5G : CARRIER_SPEED_1G;
524
525 switch (raw_features & FEATURE_RAM_MASK) {
526 case FEATURE_RAM_DDR2_32BIT:
527 features->ram_config = RAM_DDR2_32BIT_295MBPS;
528 break;
529
530 case FEATURE_RAM_DDR3_32BIT:
531 features->ram_config = RAM_DDR3_32BIT_590MBPS;
532 break;
533
534 case FEATURE_RAM_DDR3_48BIT:
535 features->ram_config = RAM_DDR3_48BIT_590MBPS;
536 break;
537 }
538
539 features->pcm_tx = raw_features & FEATURE_PCM_AUDIO_TX;
540 features->pcm_rx = raw_features & FEATURE_PCM_AUDIO_RX;
541 features->spdif_tx = raw_extended_features &
542 EXTENDED_FEATURE_SPDIF_AUDIO_TX;
543 features->spdif_rx = raw_extended_features &
544 EXTENDED_FEATURE_SPDIF_AUDIO_RX;
545
546 features->usb2 = raw_features & FEATURE_USB20;
547 features->rs232 = raw_extended_features & EXTENDED_FEATURE_RS232;
548
549 features->compression_type1 = false;
550 features->compression_type2 = false;
551 features->compression_type3 = false;
552 switch (raw_features & FEATURE_COMPRESSION_MASK) {
553 case FEATURE_COMPRESSION_TYPE1_TYPE2_TYPE3:
554 features->compression_type3 = true;
555 /* fall-through */
556 case FEATURE_COMPRESSION_TYPE1_TYPE2:
557 features->compression_type2 = true;
558 /* fall-through */
559 case FEATURE_COMPRESSION_TYPE1:
560 features->compression_type1 = true;
561 break;
562 }
563
564 features->interlace = raw_extended_features &
565 EXTENDED_FEATURE_INTERLACE;
566 features->osd = raw_features & FEATURE_OSD;
567 features->compression_pipes = raw_extended_features &
568 EXTENDED_FEATURE_COMPRESSION_PIPES;
569
570 return 0;
571}
572
573#endif
574
575/**
576 * fpga_print_info() - Print information about FPGA device
577 * @dev: FPGA device to print information about
578 */
579static void fpga_print_info(struct udevice *dev)
580{
581 struct ihs_fpga_priv *priv = dev_get_priv(dev);
582 u16 fpga_version;
583 struct fpga_versions versions;
584 struct fpga_features features;
585
586 ihs_fpga_get(priv->map, fpga_version, &fpga_version);
587 get_versions(dev, &versions);
588 get_features(dev, &features);
589
590 if (versions.video_channel)
591 printf("Videochannel");
592 else
593 printf("Mainchannel");
594
595 if (versions.con_side)
596 printf(" User");
597 else
598 printf(" Server");
599
600 switch (versions.pcb_transmission_type) {
601 case PCB_CAT_1G:
602 case PCB_CAT_10G:
603 printf(" CAT");
604 break;
605 case PCB_FIBER_3G:
606 case PCB_FIBER_10G:
607 printf(" Fiber");
608 break;
609 };
610
611 switch (versions.pcb_video_type) {
612 case PCB_DVI_SL:
613 printf(" DVI,");
614 break;
615 case PCB_DP_165MPIX:
616 printf(" DP 165MPix/s,");
617 break;
618 case PCB_DP_300MPIX:
619 printf(" DP 300MPix/s,");
620 break;
621 case PCB_HDMI:
622 printf(" HDMI,");
623 break;
624 case PCB_DP_1_2:
625 printf(" DP 1.2,");
626 break;
627 case PCB_HDMI_2_0:
628 printf(" HDMI 2.0,");
629 break;
630 }
631
632 printf(" FPGA V %d.%02d\n features: ",
633 fpga_version / 100, fpga_version % 100);
634
635 if (!features.compression_type1 &&
636 !features.compression_type2 &&
637 !features.compression_type3)
638 printf("no compression, ");
639
640 if (features.compression_type1)
641 printf("type1, ");
642
643 if (features.compression_type2)
644 printf("type2, ");
645
646 if (features.compression_type3)
647 printf("type3, ");
648
649 printf("%sosd", features.osd ? "" : "no ");
650
651 if (features.pcm_rx && features.pcm_tx)
652 printf(", pcm rx+tx");
653 else if (features.pcm_rx)
654 printf(", pcm rx");
655 else if (features.pcm_tx)
656 printf(", pcm tx");
657
658 if (features.spdif_rx && features.spdif_tx)
659 printf(", spdif rx+tx");
660 else if (features.spdif_rx)
661 printf(", spdif rx");
662 else if (features.spdif_tx)
663 printf(", spdif tx");
664
665 puts(",\n ");
666
667 switch (features.sysclock) {
668 case SYSCLK_147456:
669 printf("clock 147.456 MHz");
670 break;
671 }
672
673 switch (features.ram_config) {
674 case RAM_DDR2_32BIT_295MBPS:
675 printf(", RAM 32 bit DDR2");
676 break;
677 case RAM_DDR3_32BIT_590MBPS:
678 printf(", RAM 32 bit DDR3");
679 break;
680 case RAM_DDR3_48BIT_590MBPS:
681 case RAM_DDR3_48BIT_1800MBPS:
682 printf(", RAM 48 bit DDR3");
683 break;
684 case RAM_DDR3_64BIT_1800MBPS:
685 printf(", RAM 64 bit DDR3");
686 break;
687 }
688
689 printf(", %d carrier(s)", features.carriers);
690
691 switch (features.carrier_speed) {
692 case CARRIER_SPEED_1G:
693 printf(", 1Gbit/s");
694 break;
695 case CARRIER_SPEED_3G:
696 printf(", 3Gbit/s");
697 break;
698 case CARRIER_SPEED_10G:
699 printf(", 10Gbit/s");
700 break;
701 }
702
703 printf(", %d video channel(s)\n", features.video_channels);
704}
705
706/**
707 * do_reflection_test() - Run reflection test on a FPGA device
708 * @dev: FPGA device to run reflection test on
709 *
710 * Return: 0 if reflection test succeeded, -ve on error
711 */
712static int do_reflection_test(struct udevice *dev)
713{
714 struct ihs_fpga_priv *priv = dev_get_priv(dev);
715 int ctr = 0;
716
717 while (1) {
718 u16 val;
719
720 ihs_fpga_set(priv->map, reflection_low, REFLECTION_TESTPATTERN);
721
722 ihs_fpga_get(priv->map, reflection_low, &val);
723 if (val == (~REFLECTION_TESTPATTERN & 0xffff))
724 return -EIO;
725
726 mdelay(REFLECTION_TEST_DELAY);
727 if (ctr++ > REFLECTION_TEST_ROUNDS)
728 return 0;
729 }
730}
731
732/**
733 * wait_for_fpga_done() - Wait until 'done'-flag is set for FPGA device
734 * @dev: FPGA device whose done flag to wait for
735 *
736 * This function waits until it detects that the done-GPIO's value was changed
737 * to 1 by the FPGA, which indicates that the device is configured and ready to
738 * use.
739 *
740 * Return: 0 if done flag was detected, -ve on error
741 */
742static int wait_for_fpga_done(struct udevice *dev)
743{
744 struct ihs_fpga_priv *priv = dev_get_priv(dev);
745 int ctr = 0;
746 int done_val;
747
748 while (1) {
749 done_val = dm_gpio_get_value(&priv->done_gpio);
750 if (done_val < 0) {
751 debug("%s: Error while reading done-GPIO (err = %d)\n",
752 dev->name, done_val);
753 return done_val;
754 }
755
756 if (done_val)
757 return 0;
758
759 mdelay(FPGA_DONE_WAIT_DELAY);
760 if (ctr++ > FPGA_DONE_WAIT_ROUND) {
761 debug("%s: FPGA init failed (done not detected)\n",
762 dev->name);
763 return -EIO;
764 }
765 }
766}
767
768static int ihs_fpga_probe(struct udevice *dev)
769{
770 struct ihs_fpga_priv *priv = dev_get_priv(dev);
771 int ret;
772
773 /* TODO(mario.six@gdsys.cc): Case of FPGA attached to MCLink bus */
774
775 ret = regmap_init_mem(dev_ofnode(dev), &priv->map);
776 if (ret) {
777 debug("%s: Could not initialize regmap (err = %d)",
778 dev->name, ret);
779 return ret;
780 }
781
782 ret = gpio_request_by_name(dev, "reset-gpios", 0, &priv->reset_gpio,
783 GPIOD_IS_OUT);
784 if (ret) {
785 debug("%s: Could not get reset-GPIO (err = %d)\n",
786 dev->name, ret);
787 return ret;
788 }
789
790 if (!priv->reset_gpio.dev) {
791 debug("%s: Could not get reset-GPIO\n", dev->name);
792 return -ENOENT;
793 }
794
795 ret = gpio_request_by_name(dev, "done-gpios", 0, &priv->done_gpio,
796 GPIOD_IS_IN);
797 if (ret) {
798 debug("%s: Could not get done-GPIO (err = %d)\n",
799 dev->name, ret);
800 return ret;
801 }
802
803 if (!priv->done_gpio.dev) {
804 debug("%s: Could not get done-GPIO\n", dev->name);
805 return -ENOENT;
806 }
807
808 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
809 if (ret) {
810 debug("%s: Error while setting reset-GPIO (err = %d)\n",
811 dev->name, ret);
812 return ret;
813 }
814
815 /* If FPGA already runs, don't initialize again */
816 if (do_reflection_test(dev))
817 goto reflection_ok;
818
819 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
820 if (ret) {
821 debug("%s: Error while setting reset-GPIO (err = %d)\n",
822 dev->name, ret);
823 return ret;
824 }
825
826 ret = wait_for_fpga_done(dev);
827 if (ret) {
828 debug("%s: Error while waiting for FPGA done (err = %d)\n",
829 dev->name, ret);
830 return ret;
831 }
832
833 udelay(10);
834
835 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
836 if (ret) {
837 debug("%s: Error while setting reset-GPIO (err = %d)\n",
838 dev->name, ret);
839 return ret;
840 }
841
842 if (!do_reflection_test(dev)) {
843 debug("%s: Reflection test FAILED\n", dev->name);
844 return -EIO;
845 }
846
847reflection_ok:
848 printf("%s: Reflection test passed.\n", dev->name);
849
850 fpga_print_info(dev);
851
852 return 0;
853}
854
855static const struct udevice_id ihs_fpga_ids[] = {
856 { .compatible = "gdsys,iocon_fpga" },
857 { .compatible = "gdsys,iocpu_fpga" },
858 { }
859};
860
861U_BOOT_DRIVER(ihs_fpga_bus) = {
862 .name = "ihs_fpga_bus",
863 .id = UCLASS_MISC,
864 .of_match = ihs_fpga_ids,
865 .probe = ihs_fpga_probe,
866 .priv_auto_alloc_size = sizeof(struct ihs_fpga_priv),
867};
diff --git a/drivers/misc/ihs_fpga.h b/drivers/misc/ihs_fpga.h
new file mode 100644
index 0000000000..efb5dabb9c
--- /dev/null
+++ b/drivers/misc/ihs_fpga.h
@@ -0,0 +1,49 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * (C) Copyright 2018
4 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc
5 */
6
7/**
8 * struct ihs_fpga_regs - IHS FPGA register map structure
9 * @reflection_low: Lower reflection register
10 * @versions: PCB versions register
11 * @fpga_version: FPGA versions register
12 * @features: FPGA features register
13 * @extended_features: FPGA extended features register
14 * @top_interrupt: Top interrupt register
15 * @top_interrupt_enable: Top interrupt enable register
16 * @status: FPGA status register
17 * @control: FPGA control register
18 * @extended_control: FPGA extended control register
19 */
20struct ihs_fpga_regs {
21 u16 reflection_low;
22 u16 versions;
23 u16 fpga_version;
24 u16 features;
25 u16 extended_features;
26 u16 top_interrupt;
27 u16 top_interrupt_enable;
28 u16 status;
29 u16 control;
30 u16 extended_control;
31};
32
33/**
34 * ihs_fpga_set() - Convenience macro to set values in FPGA register map
35 * @map: Register map to set a value in
36 * @member: Name of member (described by ihs_fpga_regs) to set
37 * @val: Value to set the member to
38 */
39#define ihs_fpga_set(map, member, val) \
40 regmap_set(map, struct ihs_fpga_regs, member, val)
41
42/**
43 * ihs_fpga_get() - Convenience macro to get values from FPGA register map
44 * @map: Register map to read value from
45 * @member: Name of member (described by ihs_fpga_regs) to get
46 * @valp: Pointe to variable to receive the value read
47 */
48#define ihs_fpga_get(map, member, valp) \
49 regmap_get(map, struct ihs_fpga_regs, member, valp)
diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c
index 0647ddf103..b824ac79e6 100644
--- a/drivers/misc/imx8/scu.c
+++ b/drivers/misc/imx8/scu.c
@@ -223,7 +223,7 @@ static int imx8_scu_bind(struct udevice *dev)
223 if (node < 0) 223 if (node < 0)
224 panic("No clk node found\n"); 224 panic("No clk node found\n");
225 225
226 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child); 226 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
227 if (ret) 227 if (ret)
228 return ret; 228 return ret;
229 229
@@ -234,7 +234,7 @@ static int imx8_scu_bind(struct udevice *dev)
234 if (node < 0) 234 if (node < 0)
235 panic("No iomuxc node found\n"); 235 panic("No iomuxc node found\n");
236 236
237 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child); 237 ret = lists_bind_fdt(dev, offset_to_ofnode(node), &child, true);
238 if (ret) 238 if (ret)
239 return ret; 239 return ret;
240 240
diff --git a/drivers/misc/swap_case.c b/drivers/misc/swap_case.c
index bffb809f14..fa608cec1b 100644
--- a/drivers/misc/swap_case.c
+++ b/drivers/misc/swap_case.c
@@ -124,12 +124,21 @@ static int sandbox_swap_case_read_config(struct udevice *emul, uint offset,
124 case PCI_CAP_ID_PM_OFFSET: 124 case PCI_CAP_ID_PM_OFFSET:
125 *valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM; 125 *valuep = (PCI_CAP_ID_EXP_OFFSET << 8) | PCI_CAP_ID_PM;
126 break; 126 break;
127 case PCI_CAP_ID_PM_OFFSET + PCI_CAP_LIST_NEXT:
128 *valuep = PCI_CAP_ID_EXP_OFFSET;
129 break;
127 case PCI_CAP_ID_EXP_OFFSET: 130 case PCI_CAP_ID_EXP_OFFSET:
128 *valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP; 131 *valuep = (PCI_CAP_ID_MSIX_OFFSET << 8) | PCI_CAP_ID_EXP;
129 break; 132 break;
133 case PCI_CAP_ID_EXP_OFFSET + PCI_CAP_LIST_NEXT:
134 *valuep = PCI_CAP_ID_MSIX_OFFSET;
135 break;
130 case PCI_CAP_ID_MSIX_OFFSET: 136 case PCI_CAP_ID_MSIX_OFFSET:
131 *valuep = PCI_CAP_ID_MSIX; 137 *valuep = PCI_CAP_ID_MSIX;
132 break; 138 break;
139 case PCI_CAP_ID_MSIX_OFFSET + PCI_CAP_LIST_NEXT:
140 *valuep = 0;
141 break;
133 case PCI_EXT_CAP_ID_ERR_OFFSET: 142 case PCI_EXT_CAP_ID_ERR_OFFSET:
134 *valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR; 143 *valuep = (PCI_EXT_CAP_ID_VC_OFFSET << 20) | PCI_EXT_CAP_ID_ERR;
135 break; 144 break;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 585951cd78..d6b9cdc992 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -2444,9 +2444,6 @@ static int mmc_startup(struct mmc *mmc)
2444 bdesc->product[0] = 0; 2444 bdesc->product[0] = 0;
2445 bdesc->revision[0] = 0; 2445 bdesc->revision[0] = 0;
2446#endif 2446#endif
2447#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2448 part_init(bdesc);
2449#endif
2450 2447
2451 return 0; 2448 return 0;
2452} 2449}
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index ec853d063f..5cb97eb02a 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -1953,6 +1953,8 @@ U_BOOT_DRIVER(omap_hsmmc) = {
1953 .ops = &omap_hsmmc_ops, 1953 .ops = &omap_hsmmc_ops,
1954 .probe = omap_hsmmc_probe, 1954 .probe = omap_hsmmc_probe,
1955 .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data), 1955 .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
1956#if !CONFIG_IS_ENABLED(OF_CONTROL)
1956 .flags = DM_FLAG_PRE_RELOC, 1957 .flags = DM_FLAG_PRE_RELOC,
1958#endif
1957}; 1959};
1958#endif 1960#endif
diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c
index eb6fdeda50..1ee0a0aefb 100644
--- a/drivers/nvme/nvme.c
+++ b/drivers/nvme/nvme.c
@@ -664,7 +664,6 @@ static int nvme_blk_probe(struct udevice *udev)
664 sprintf(desc->vendor, "0x%.4x", pplat->vendor); 664 sprintf(desc->vendor, "0x%.4x", pplat->vendor);
665 memcpy(desc->product, ndev->serial, sizeof(ndev->serial)); 665 memcpy(desc->product, ndev->serial, sizeof(ndev->serial));
666 memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev)); 666 memcpy(desc->revision, ndev->firmware_rev, sizeof(ndev->firmware_rev));
667 part_init(desc);
668 667
669 return 0; 668 return 0;
670} 669}
diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c
index da49c96ed5..0c52337f33 100644
--- a/drivers/pci/pci-uclass.c
+++ b/drivers/pci/pci-uclass.c
@@ -1344,26 +1344,14 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags)
1344 return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE); 1344 return dm_pci_bus_to_virt(dev, pci_bus_addr, flags, 0, MAP_NOCACHE);
1345} 1345}
1346 1346
1347int dm_pci_find_capability(struct udevice *dev, int cap) 1347static int _dm_pci_find_next_capability(struct udevice *dev, u8 pos, int cap)
1348{ 1348{
1349 u16 status;
1350 u8 header_type;
1351 int ttl = PCI_FIND_CAP_TTL; 1349 int ttl = PCI_FIND_CAP_TTL;
1352 u8 id; 1350 u8 id;
1353 u16 ent; 1351 u16 ent;
1354 u8 pos;
1355
1356 dm_pci_read_config16(dev, PCI_STATUS, &status);
1357 if (!(status & PCI_STATUS_CAP_LIST))
1358 return 0;
1359
1360 dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
1361 if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
1362 pos = PCI_CB_CAPABILITY_LIST;
1363 else
1364 pos = PCI_CAPABILITY_LIST;
1365 1352
1366 dm_pci_read_config8(dev, pos, &pos); 1353 dm_pci_read_config8(dev, pos, &pos);
1354
1367 while (ttl--) { 1355 while (ttl--) {
1368 if (pos < PCI_STD_HEADER_SIZEOF) 1356 if (pos < PCI_STD_HEADER_SIZEOF)
1369 break; 1357 break;
@@ -1381,7 +1369,32 @@ int dm_pci_find_capability(struct udevice *dev, int cap)
1381 return 0; 1369 return 0;
1382} 1370}
1383 1371
1384int dm_pci_find_ext_capability(struct udevice *dev, int cap) 1372int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap)
1373{
1374 return _dm_pci_find_next_capability(dev, start + PCI_CAP_LIST_NEXT,
1375 cap);
1376}
1377
1378int dm_pci_find_capability(struct udevice *dev, int cap)
1379{
1380 u16 status;
1381 u8 header_type;
1382 u8 pos;
1383
1384 dm_pci_read_config16(dev, PCI_STATUS, &status);
1385 if (!(status & PCI_STATUS_CAP_LIST))
1386 return 0;
1387
1388 dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type);
1389 if ((header_type & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
1390 pos = PCI_CB_CAPABILITY_LIST;
1391 else
1392 pos = PCI_CAPABILITY_LIST;
1393
1394 return _dm_pci_find_next_capability(dev, pos, cap);
1395}
1396
1397int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap)
1385{ 1398{
1386 u32 header; 1399 u32 header;
1387 int ttl; 1400 int ttl;
@@ -1390,6 +1403,9 @@ int dm_pci_find_ext_capability(struct udevice *dev, int cap)
1390 /* minimum 8 bytes per capability */ 1403 /* minimum 8 bytes per capability */
1391 ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; 1404 ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8;
1392 1405
1406 if (start)
1407 pos = start;
1408
1393 dm_pci_read_config32(dev, pos, &header); 1409 dm_pci_read_config32(dev, pos, &header);
1394 /* 1410 /*
1395 * If we have no capabilities, this is indicated by cap ID, 1411 * 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)
1412 return 0; 1428 return 0;
1413} 1429}
1414 1430
1431int dm_pci_find_ext_capability(struct udevice *dev, int cap)
1432{
1433 return dm_pci_find_next_ext_capability(dev, 0, cap);
1434}
1435
1415UCLASS_DRIVER(pci) = { 1436UCLASS_DRIVER(pci) = {
1416 .id = UCLASS_PCI, 1437 .id = UCLASS_PCI,
1417 .name = "pci", 1438 .name = "pci",
diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
index 891b4c25fd..3be080d29e 100644
--- a/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
+++ b/drivers/pinctrl/broadcom/pinctrl-bcm283x.c
@@ -148,5 +148,7 @@ U_BOOT_DRIVER(pinctrl_bcm283x) = {
148 .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv), 148 .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv),
149 .ops = &bcm283x_pinctrl_ops, 149 .ops = &bcm283x_pinctrl_ops,
150 .probe = bcm283x_pinctl_probe, 150 .probe = bcm283x_pinctl_probe,
151#if !CONFIG_IS_ENABLED(OF_CONTROL)
151 .flags = DM_FLAG_PRE_RELOC, 152 .flags = DM_FLAG_PRE_RELOC,
153#endif
152}; 154};
diff --git a/drivers/pinctrl/exynos/pinctrl-exynos7420.c b/drivers/pinctrl/exynos/pinctrl-exynos7420.c
index cb5975b252..ff6d6c4143 100644
--- a/drivers/pinctrl/exynos/pinctrl-exynos7420.c
+++ b/drivers/pinctrl/exynos/pinctrl-exynos7420.c
@@ -113,5 +113,4 @@ U_BOOT_DRIVER(pinctrl_exynos7420) = {
113 .priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv), 113 .priv_auto_alloc_size = sizeof(struct exynos_pinctrl_priv),
114 .ops = &exynos7420_pinctrl_ops, 114 .ops = &exynos7420_pinctrl_ops,
115 .probe = exynos_pinctrl_probe, 115 .probe = exynos_pinctrl_probe,
116 .flags = DM_FLAG_PRE_RELOC
117}; 116};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx5.c b/drivers/pinctrl/nxp/pinctrl-imx5.c
index 5d17380919..4e831b6f39 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx5.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx5.c
@@ -40,5 +40,7 @@ U_BOOT_DRIVER(imx5_pinctrl) = {
40 .remove = imx_pinctrl_remove, 40 .remove = imx_pinctrl_remove,
41 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv), 41 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
42 .ops = &imx_pinctrl_ops, 42 .ops = &imx_pinctrl_ops,
43#if !CONFIG_IS_ENABLED(OF_CONTROL)
43 .flags = DM_FLAG_PRE_RELOC, 44 .flags = DM_FLAG_PRE_RELOC,
45#endif
44}; 46};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx6.c b/drivers/pinctrl/nxp/pinctrl-imx6.c
index e63ecbdee6..d7c95bb738 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx6.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx6.c
@@ -49,5 +49,7 @@ U_BOOT_DRIVER(imx6_pinctrl) = {
49 .remove = imx_pinctrl_remove, 49 .remove = imx_pinctrl_remove,
50 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv), 50 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
51 .ops = &imx_pinctrl_ops, 51 .ops = &imx_pinctrl_ops,
52#if !CONFIG_IS_ENABLED(OF_CONTROL)
52 .flags = DM_FLAG_PRE_RELOC, 53 .flags = DM_FLAG_PRE_RELOC,
54#endif
53}; 55};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx7.c b/drivers/pinctrl/nxp/pinctrl-imx7.c
index 769d428dda..8776fd9650 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx7.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx7.c
@@ -37,5 +37,7 @@ U_BOOT_DRIVER(imx7_pinctrl) = {
37 .remove = imx_pinctrl_remove, 37 .remove = imx_pinctrl_remove,
38 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv), 38 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
39 .ops = &imx_pinctrl_ops, 39 .ops = &imx_pinctrl_ops,
40#if !CONFIG_IS_ENABLED(OF_CONTROL)
40 .flags = DM_FLAG_PRE_RELOC, 41 .flags = DM_FLAG_PRE_RELOC,
42#endif
41}; 43};
diff --git a/drivers/pinctrl/nxp/pinctrl-imx7ulp.c b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c
index 598bbfaf35..d778f82aac 100644
--- a/drivers/pinctrl/nxp/pinctrl-imx7ulp.c
+++ b/drivers/pinctrl/nxp/pinctrl-imx7ulp.c
@@ -41,5 +41,7 @@ U_BOOT_DRIVER(imx7ulp_pinctrl) = {
41 .remove = imx_pinctrl_remove, 41 .remove = imx_pinctrl_remove,
42 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv), 42 .priv_auto_alloc_size = sizeof(struct imx_pinctrl_priv),
43 .ops = &imx_pinctrl_ops, 43 .ops = &imx_pinctrl_ops,
44#if !CONFIG_IS_ENABLED(OF_CONTROL)
44 .flags = DM_FLAG_PRE_RELOC, 45 .flags = DM_FLAG_PRE_RELOC,
46#endif
45}; 47};
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index d80c6eda70..9dec88c1aa 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -136,7 +136,6 @@ U_BOOT_DRIVER(single_pinctrl) = {
136 .id = UCLASS_PINCTRL, 136 .id = UCLASS_PINCTRL,
137 .of_match = single_pinctrl_match, 137 .of_match = single_pinctrl_match,
138 .ops = &single_pinctrl_ops, 138 .ops = &single_pinctrl_ops,
139 .flags = DM_FLAG_PRE_RELOC,
140 .platdata_auto_alloc_size = sizeof(struct single_pdata), 139 .platdata_auto_alloc_size = sizeof(struct single_pdata),
141 .ofdata_to_platdata = single_ofdata_to_platdata, 140 .ofdata_to_platdata = single_ofdata_to_platdata,
142}; 141};
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
index a1da90baa4..eb5978a166 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro4.c
@@ -171,5 +171,7 @@ U_BOOT_DRIVER(uniphier_pro4_pinctrl) = {
171 .probe = uniphier_pro4_pinctrl_probe, 171 .probe = uniphier_pro4_pinctrl_probe,
172 .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), 172 .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
173 .ops = &uniphier_pinctrl_ops, 173 .ops = &uniphier_pinctrl_ops,
174#if !CONFIG_IS_ENABLED(OF_CONTROL)
174 .flags = DM_FLAG_PRE_RELOC, 175 .flags = DM_FLAG_PRE_RELOC,
176#endif
175}; 177};
diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
index 0ba2052b29..685d8be80c 100644
--- a/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
+++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-pro5.c
@@ -153,5 +153,7 @@ U_BOOT_DRIVER(uniphier_pro5_pinctrl) = {
153 .probe = uniphier_pro5_pinctrl_probe, 153 .probe = uniphier_pro5_pinctrl_probe,
154 .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv), 154 .priv_auto_alloc_size = sizeof(struct uniphier_pinctrl_priv),
155 .ops = &uniphier_pinctrl_ops, 155 .ops = &uniphier_pinctrl_ops,
156#if !CONFIG_IS_ENABLED(OF_CONTROL)
156 .flags = DM_FLAG_PRE_RELOC, 157 .flags = DM_FLAG_PRE_RELOC,
158#endif
157}; 159};
diff --git a/drivers/ram/bmips_ram.c b/drivers/ram/bmips_ram.c
index b5f19c983c..3e1dd9e241 100644
--- a/drivers/ram/bmips_ram.c
+++ b/drivers/ram/bmips_ram.c
@@ -173,5 +173,4 @@ U_BOOT_DRIVER(bmips_ram) = {
173 .probe = bmips_ram_probe, 173 .probe = bmips_ram_probe,
174 .priv_auto_alloc_size = sizeof(struct bmips_ram_priv), 174 .priv_auto_alloc_size = sizeof(struct bmips_ram_priv),
175 .ops = &bmips_ram_ops, 175 .ops = &bmips_ram_ops,
176 .flags = DM_FLAG_PRE_RELOC,
177}; 176};
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index bc6ac8cd32..df47e2fc78 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -592,7 +592,6 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose)
592 memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor)); 592 memcpy(&bdesc->vendor, &bd.vendor, sizeof(bd.vendor));
593 memcpy(&bdesc->product, &bd.product, sizeof(bd.product)); 593 memcpy(&bdesc->product, &bd.product, sizeof(bd.product));
594 memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision)); 594 memcpy(&bdesc->revision, &bd.revision, sizeof(bd.revision));
595 part_init(bdesc);
596 595
597 if (verbose) { 596 if (verbose) {
598 printf(" Device %d: ", 0); 597 printf(" Device %d: ", 0);
diff --git a/drivers/serial/altera_jtag_uart.c b/drivers/serial/altera_jtag_uart.c
index 61052a92d6..86c3de4e45 100644
--- a/drivers/serial/altera_jtag_uart.c
+++ b/drivers/serial/altera_jtag_uart.c
@@ -121,7 +121,6 @@ U_BOOT_DRIVER(altera_jtaguart) = {
121 .platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata), 121 .platdata_auto_alloc_size = sizeof(struct altera_jtaguart_platdata),
122 .probe = altera_jtaguart_probe, 122 .probe = altera_jtaguart_probe,
123 .ops = &altera_jtaguart_ops, 123 .ops = &altera_jtaguart_ops,
124 .flags = DM_FLAG_PRE_RELOC,
125}; 124};
126 125
127#ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART 126#ifdef CONFIG_DEBUG_UART_ALTERA_JTAGUART
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
index b7b0a13ca1..67d47199aa 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/serial/altera_uart.c
@@ -117,7 +117,6 @@ U_BOOT_DRIVER(altera_uart) = {
117 .platdata_auto_alloc_size = sizeof(struct altera_uart_platdata), 117 .platdata_auto_alloc_size = sizeof(struct altera_uart_platdata),
118 .probe = altera_uart_probe, 118 .probe = altera_uart_probe,
119 .ops = &altera_uart_ops, 119 .ops = &altera_uart_ops,
120 .flags = DM_FLAG_PRE_RELOC,
121}; 120};
122 121
123#ifdef CONFIG_DEBUG_UART_ALTERA_UART 122#ifdef CONFIG_DEBUG_UART_ALTERA_UART
diff --git a/drivers/serial/arm_dcc.c b/drivers/serial/arm_dcc.c
index 43e8691a93..dfcb6fd698 100644
--- a/drivers/serial/arm_dcc.c
+++ b/drivers/serial/arm_dcc.c
@@ -155,7 +155,6 @@ U_BOOT_DRIVER(serial_dcc) = {
155 .id = UCLASS_SERIAL, 155 .id = UCLASS_SERIAL,
156 .of_match = arm_dcc_ids, 156 .of_match = arm_dcc_ids,
157 .ops = &arm_dcc_ops, 157 .ops = &arm_dcc_ops,
158 .flags = DM_FLAG_PRE_RELOC,
159}; 158};
160 159
161#ifdef CONFIG_DEBUG_UART_ARM_DCC 160#ifdef CONFIG_DEBUG_UART_ARM_DCC
diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c
index 9414f5f692..aa8cdff840 100644
--- a/drivers/serial/atmel_usart.c
+++ b/drivers/serial/atmel_usart.c
@@ -294,7 +294,9 @@ U_BOOT_DRIVER(serial_atmel) = {
294#endif 294#endif
295 .probe = atmel_serial_probe, 295 .probe = atmel_serial_probe,
296 .ops = &atmel_serial_ops, 296 .ops = &atmel_serial_ops,
297#if !CONFIG_IS_ENABLED(OF_CONTROL)
297 .flags = DM_FLAG_PRE_RELOC, 298 .flags = DM_FLAG_PRE_RELOC,
299#endif
298 .priv_auto_alloc_size = sizeof(struct atmel_serial_priv), 300 .priv_auto_alloc_size = sizeof(struct atmel_serial_priv),
299}; 301};
300#endif 302#endif
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index f9041aa626..1e6fc6c668 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -267,12 +267,26 @@ static inline void _debug_uart_init(void)
267 serial_dout(&com_port->lcr, UART_LCRVAL); 267 serial_dout(&com_port->lcr, UART_LCRVAL);
268} 268}
269 269
270static inline int NS16550_read_baud_divisor(struct NS16550 *com_port)
271{
272 int ret;
273
274 serial_dout(&com_port->lcr, UART_LCR_BKSE | UART_LCRVAL);
275 ret = serial_din(&com_port->dll) & 0xff;
276 ret |= (serial_din(&com_port->dlm) & 0xff) << 8;
277 serial_dout(&com_port->lcr, UART_LCRVAL);
278
279 return ret;
280}
281
270static inline void _debug_uart_putc(int ch) 282static inline void _debug_uart_putc(int ch)
271{ 283{
272 struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE; 284 struct NS16550 *com_port = (struct NS16550 *)CONFIG_DEBUG_UART_BASE;
273 285
274 while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) 286 while (!(serial_din(&com_port->lsr) & UART_LSR_THRE)) {
275 ; 287 if (!NS16550_read_baud_divisor(com_port))
288 return;
289 }
276 serial_dout(&com_port->thr, ch); 290 serial_dout(&com_port->thr, ch);
277} 291}
278 292
@@ -473,7 +487,9 @@ U_BOOT_DRIVER(ns16550_serial) = {
473 .priv_auto_alloc_size = sizeof(struct NS16550), 487 .priv_auto_alloc_size = sizeof(struct NS16550),
474 .probe = ns16550_serial_probe, 488 .probe = ns16550_serial_probe,
475 .ops = &ns16550_serial_ops, 489 .ops = &ns16550_serial_ops,
490#if !CONFIG_IS_ENABLED(OF_CONTROL)
476 .flags = DM_FLAG_PRE_RELOC, 491 .flags = DM_FLAG_PRE_RELOC,
492#endif
477}; 493};
478#endif 494#endif
479#endif /* SERIAL_PRESENT */ 495#endif /* SERIAL_PRESENT */
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 665cca85cb..3ded62732d 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -62,7 +62,7 @@ static int serial_check_stdout(const void *blob, struct udevice **devp)
62 * anyway. 62 * anyway.
63 */ 63 */
64 if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), 64 if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
65 devp)) { 65 devp, false)) {
66 if (!device_probe(*devp)) 66 if (!device_probe(*devp))
67 return 0; 67 return 0;
68 } 68 }
diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c
index e91a5f7b24..5249c55398 100644
--- a/drivers/serial/serial_ar933x.c
+++ b/drivers/serial/serial_ar933x.c
@@ -189,7 +189,6 @@ U_BOOT_DRIVER(serial_ar933x) = {
189 .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv), 189 .priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
190 .probe = ar933x_serial_probe, 190 .probe = ar933x_serial_probe,
191 .ops = &ar933x_serial_ops, 191 .ops = &ar933x_serial_ops,
192 .flags = DM_FLAG_PRE_RELOC,
193}; 192};
194 193
195#ifdef CONFIG_DEBUG_UART_AR933X 194#ifdef CONFIG_DEBUG_UART_AR933X
diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c
index 925f0c2555..980b38d2a1 100644
--- a/drivers/serial/serial_arc.c
+++ b/drivers/serial/serial_arc.c
@@ -128,7 +128,6 @@ U_BOOT_DRIVER(serial_arc) = {
128 .ofdata_to_platdata = arc_serial_ofdata_to_platdata, 128 .ofdata_to_platdata = arc_serial_ofdata_to_platdata,
129 .probe = arc_serial_probe, 129 .probe = arc_serial_probe,
130 .ops = &arc_serial_ops, 130 .ops = &arc_serial_ops,
131 .flags = DM_FLAG_PRE_RELOC,
132}; 131};
133 132
134#ifdef CONFIG_DEBUG_ARC_SERIAL 133#ifdef CONFIG_DEBUG_ARC_SERIAL
diff --git a/drivers/serial/serial_bcm283x_mu.c b/drivers/serial/serial_bcm283x_mu.c
index 1f87f0cb28..bd1d89ec83 100644
--- a/drivers/serial/serial_bcm283x_mu.c
+++ b/drivers/serial/serial_bcm283x_mu.c
@@ -199,6 +199,8 @@ U_BOOT_DRIVER(serial_bcm283x_mu) = {
199 .platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata), 199 .platdata_auto_alloc_size = sizeof(struct bcm283x_mu_serial_platdata),
200 .probe = bcm283x_mu_serial_probe, 200 .probe = bcm283x_mu_serial_probe,
201 .ops = &bcm283x_mu_serial_ops, 201 .ops = &bcm283x_mu_serial_ops,
202#if !CONFIG_IS_ENABLED(OF_CONTROL)
202 .flags = DM_FLAG_PRE_RELOC, 203 .flags = DM_FLAG_PRE_RELOC,
204#endif
203 .priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv), 205 .priv_auto_alloc_size = sizeof(struct bcm283x_mu_priv),
204}; 206};
diff --git a/drivers/serial/serial_bcm283x_pl011.c b/drivers/serial/serial_bcm283x_pl011.c
index 54fc9b5b39..2527bb8b1c 100644
--- a/drivers/serial/serial_bcm283x_pl011.c
+++ b/drivers/serial/serial_bcm283x_pl011.c
@@ -90,6 +90,8 @@ U_BOOT_DRIVER(bcm283x_pl011_uart) = {
90 .platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata), 90 .platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
91 .probe = pl01x_serial_probe, 91 .probe = pl01x_serial_probe,
92 .ops = &bcm283x_pl011_serial_ops, 92 .ops = &bcm283x_pl011_serial_ops,
93#if !CONFIG_IS_ENABLED(OF_CONTROL)
93 .flags = DM_FLAG_PRE_RELOC, 94 .flags = DM_FLAG_PRE_RELOC,
95#endif
94 .priv_auto_alloc_size = sizeof(struct pl01x_priv), 96 .priv_auto_alloc_size = sizeof(struct pl01x_priv),
95}; 97};
diff --git a/drivers/serial/serial_bcm6345.c b/drivers/serial/serial_bcm6345.c
index ee5d561bfd..a0e709a11e 100644
--- a/drivers/serial/serial_bcm6345.c
+++ b/drivers/serial/serial_bcm6345.c
@@ -264,7 +264,6 @@ U_BOOT_DRIVER(bcm6345_serial) = {
264 .probe = bcm6345_serial_probe, 264 .probe = bcm6345_serial_probe,
265 .priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv), 265 .priv_auto_alloc_size = sizeof(struct bcm6345_serial_priv),
266 .ops = &bcm6345_serial_ops, 266 .ops = &bcm6345_serial_ops,
267 .flags = DM_FLAG_PRE_RELOC,
268}; 267};
269 268
270#ifdef CONFIG_DEBUG_UART_BCM6345 269#ifdef CONFIG_DEBUG_UART_BCM6345
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 1b54d1880f..dd3e511fc9 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -152,5 +152,4 @@ U_BOOT_DRIVER(serial_efi) = {
152 .priv_auto_alloc_size = sizeof(struct serial_efi_priv), 152 .priv_auto_alloc_size = sizeof(struct serial_efi_priv),
153 .probe = serial_efi_probe, 153 .probe = serial_efi_probe,
154 .ops = &serial_efi_ops, 154 .ops = &serial_efi_ops,
155 .flags = DM_FLAG_PRE_RELOC,
156}; 155};
diff --git a/drivers/serial/serial_intel_mid.c b/drivers/serial/serial_intel_mid.c
index bdb5adb2a4..39bd40e68b 100644
--- a/drivers/serial/serial_intel_mid.c
+++ b/drivers/serial/serial_intel_mid.c
@@ -64,5 +64,4 @@ U_BOOT_DRIVER(serial_intel_mid) = {
64 .priv_auto_alloc_size = sizeof(struct NS16550), 64 .priv_auto_alloc_size = sizeof(struct NS16550),
65 .probe = mid_serial_probe, 65 .probe = mid_serial_probe,
66 .ops = &ns16550_serial_ops, 66 .ops = &ns16550_serial_ops,
67 .flags = DM_FLAG_PRE_RELOC,
68}; 67};
diff --git a/drivers/serial/serial_lpuart.c b/drivers/serial/serial_lpuart.c
index 6106c1f9ec..a357b00d28 100644
--- a/drivers/serial/serial_lpuart.c
+++ b/drivers/serial/serial_lpuart.c
@@ -540,5 +540,4 @@ U_BOOT_DRIVER(serial_lpuart) = {
540 .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata), 540 .platdata_auto_alloc_size = sizeof(struct lpuart_serial_platdata),
541 .probe = lpuart_serial_probe, 541 .probe = lpuart_serial_probe,
542 .ops = &lpuart_serial_ops, 542 .ops = &lpuart_serial_ops,
543 .flags = DM_FLAG_PRE_RELOC,
544}; 543};
diff --git a/drivers/serial/serial_meson.c b/drivers/serial/serial_meson.c
index dbb853735f..b3dad77aa2 100644
--- a/drivers/serial/serial_meson.c
+++ b/drivers/serial/serial_meson.c
@@ -132,7 +132,6 @@ U_BOOT_DRIVER(serial_meson) = {
132 .of_match = meson_serial_ids, 132 .of_match = meson_serial_ids,
133 .probe = meson_serial_probe, 133 .probe = meson_serial_probe,
134 .ops = &meson_serial_ops, 134 .ops = &meson_serial_ops,
135 .flags = DM_FLAG_PRE_RELOC,
136 .ofdata_to_platdata = meson_serial_ofdata_to_platdata, 135 .ofdata_to_platdata = meson_serial_ofdata_to_platdata,
137 .platdata_auto_alloc_size = sizeof(struct meson_serial_platdata), 136 .platdata_auto_alloc_size = sizeof(struct meson_serial_platdata),
138}; 137};
diff --git a/drivers/serial/serial_mvebu_a3700.c b/drivers/serial/serial_mvebu_a3700.c
index ce26d2bd15..7e4cd6c4b4 100644
--- a/drivers/serial/serial_mvebu_a3700.c
+++ b/drivers/serial/serial_mvebu_a3700.c
@@ -129,7 +129,6 @@ U_BOOT_DRIVER(serial_mvebu) = {
129 .platdata_auto_alloc_size = sizeof(struct mvebu_platdata), 129 .platdata_auto_alloc_size = sizeof(struct mvebu_platdata),
130 .probe = mvebu_serial_probe, 130 .probe = mvebu_serial_probe,
131 .ops = &mvebu_serial_ops, 131 .ops = &mvebu_serial_ops,
132 .flags = DM_FLAG_PRE_RELOC,
133}; 132};
134 133
135#ifdef CONFIG_DEBUG_MVEBU_A3700_UART 134#ifdef CONFIG_DEBUG_MVEBU_A3700_UART
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index e586c18cf0..7e4e6d36b8 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -354,7 +354,9 @@ U_BOOT_DRIVER(serial_mxc) = {
354#endif 354#endif
355 .probe = mxc_serial_probe, 355 .probe = mxc_serial_probe,
356 .ops = &mxc_serial_ops, 356 .ops = &mxc_serial_ops,
357#if !CONFIG_IS_ENABLED(OF_CONTROL)
357 .flags = DM_FLAG_PRE_RELOC, 358 .flags = DM_FLAG_PRE_RELOC,
359#endif
358}; 360};
359#endif 361#endif
360 362
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
index af3c755f96..ee6ad9c9e5 100644
--- a/drivers/serial/serial_omap.c
+++ b/drivers/serial/serial_omap.c
@@ -121,7 +121,9 @@ U_BOOT_DRIVER(omap_serial) = {
121 .priv_auto_alloc_size = sizeof(struct NS16550), 121 .priv_auto_alloc_size = sizeof(struct NS16550),
122 .probe = ns16550_serial_probe, 122 .probe = ns16550_serial_probe,
123 .ops = &ns16550_serial_ops, 123 .ops = &ns16550_serial_ops,
124#if !CONFIG_IS_ENABLED(OF_CONTROL)
124 .flags = DM_FLAG_PRE_RELOC, 125 .flags = DM_FLAG_PRE_RELOC,
126#endif
125}; 127};
126#endif 128#endif
127#endif /* DM_SERIAL */ 129#endif /* DM_SERIAL */
diff --git a/drivers/serial/serial_owl.c b/drivers/serial/serial_owl.c
index 6fd97e2502..7ead73e6b7 100644
--- a/drivers/serial/serial_owl.c
+++ b/drivers/serial/serial_owl.c
@@ -132,5 +132,4 @@ U_BOOT_DRIVER(serial_owl) = {
132 .priv_auto_alloc_size = sizeof(struct owl_serial_priv), 132 .priv_auto_alloc_size = sizeof(struct owl_serial_priv),
133 .probe = owl_serial_probe, 133 .probe = owl_serial_probe,
134 .ops = &owl_serial_ops, 134 .ops = &owl_serial_ops,
135 .flags = DM_FLAG_PRE_RELOC,
136}; 135};
diff --git a/drivers/serial/serial_pic32.c b/drivers/serial/serial_pic32.c
index ba73978e25..84600b1201 100644
--- a/drivers/serial/serial_pic32.c
+++ b/drivers/serial/serial_pic32.c
@@ -176,7 +176,6 @@ U_BOOT_DRIVER(pic32_serial) = {
176 .of_match = pic32_uart_ids, 176 .of_match = pic32_uart_ids,
177 .probe = pic32_uart_probe, 177 .probe = pic32_uart_probe,
178 .ops = &pic32_uart_ops, 178 .ops = &pic32_uart_ops,
179 .flags = DM_FLAG_PRE_RELOC,
180 .priv_auto_alloc_size = sizeof(struct pic32_uart_priv), 179 .priv_auto_alloc_size = sizeof(struct pic32_uart_priv),
181}; 180};
182 181
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 2a5f256184..12512f6578 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -363,7 +363,9 @@ U_BOOT_DRIVER(serial_pl01x) = {
363 .platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata), 363 .platdata_auto_alloc_size = sizeof(struct pl01x_serial_platdata),
364 .probe = pl01x_serial_probe, 364 .probe = pl01x_serial_probe,
365 .ops = &pl01x_serial_ops, 365 .ops = &pl01x_serial_ops,
366#if !CONFIG_IS_ENABLED(OF_CONTROL)
366 .flags = DM_FLAG_PRE_RELOC, 367 .flags = DM_FLAG_PRE_RELOC,
368#endif
367 .priv_auto_alloc_size = sizeof(struct pl01x_priv), 369 .priv_auto_alloc_size = sizeof(struct pl01x_priv),
368}; 370};
369 371
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index faea6d4c99..e3160cf1bd 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -211,7 +211,6 @@ U_BOOT_DRIVER(serial_s5p) = {
211 .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata), 211 .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
212 .probe = s5p_serial_probe, 212 .probe = s5p_serial_probe,
213 .ops = &s5p_serial_ops, 213 .ops = &s5p_serial_ops,
214 .flags = DM_FLAG_PRE_RELOC,
215}; 214};
216#endif 215#endif
217 216
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index b1534981f8..c934d5f25a 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -247,7 +247,9 @@ U_BOOT_DRIVER(serial_sh) = {
247 .platdata_auto_alloc_size = sizeof(struct sh_serial_platdata), 247 .platdata_auto_alloc_size = sizeof(struct sh_serial_platdata),
248 .probe = sh_serial_probe, 248 .probe = sh_serial_probe,
249 .ops = &sh_serial_ops, 249 .ops = &sh_serial_ops,
250#if !CONFIG_IS_ENABLED(OF_CONTROL)
250 .flags = DM_FLAG_PRE_RELOC, 251 .flags = DM_FLAG_PRE_RELOC,
252#endif
251 .priv_auto_alloc_size = sizeof(struct uart_port), 253 .priv_auto_alloc_size = sizeof(struct uart_port),
252}; 254};
253 255
diff --git a/drivers/serial/serial_sti_asc.c b/drivers/serial/serial_sti_asc.c
index 5dfc6171eb..c972f1e9af 100644
--- a/drivers/serial/serial_sti_asc.c
+++ b/drivers/serial/serial_sti_asc.c
@@ -205,6 +205,5 @@ U_BOOT_DRIVER(serial_sti_asc) = {
205 .ops = &sti_asc_serial_ops, 205 .ops = &sti_asc_serial_ops,
206 .probe = sti_asc_serial_probe, 206 .probe = sti_asc_serial_probe,
207 .priv_auto_alloc_size = sizeof(struct sti_asc_serial), 207 .priv_auto_alloc_size = sizeof(struct sti_asc_serial),
208 .flags = DM_FLAG_PRE_RELOC,
209}; 208};
210 209
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 66e02d5689..31b43ee88d 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -230,7 +230,9 @@ U_BOOT_DRIVER(serial_stm32) = {
230 .platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata), 230 .platdata_auto_alloc_size = sizeof(struct stm32x7_serial_platdata),
231 .ops = &stm32_serial_ops, 231 .ops = &stm32_serial_ops,
232 .probe = stm32_serial_probe, 232 .probe = stm32_serial_probe,
233#if !CONFIG_IS_ENABLED(OF_CONTROL)
233 .flags = DM_FLAG_PRE_RELOC, 234 .flags = DM_FLAG_PRE_RELOC,
235#endif
234}; 236};
235 237
236#ifdef CONFIG_DEBUG_UART_STM32 238#ifdef CONFIG_DEBUG_UART_STM32
diff --git a/drivers/serial/serial_xuartlite.c b/drivers/serial/serial_xuartlite.c
index cead3c62f5..1be777bd3b 100644
--- a/drivers/serial/serial_xuartlite.c
+++ b/drivers/serial/serial_xuartlite.c
@@ -109,7 +109,6 @@ U_BOOT_DRIVER(serial_uartlite) = {
109 .platdata_auto_alloc_size = sizeof(struct uartlite_platdata), 109 .platdata_auto_alloc_size = sizeof(struct uartlite_platdata),
110 .probe = uartlite_serial_probe, 110 .probe = uartlite_serial_probe,
111 .ops = &uartlite_serial_ops, 111 .ops = &uartlite_serial_ops,
112 .flags = DM_FLAG_PRE_RELOC,
113}; 112};
114 113
115#ifdef CONFIG_DEBUG_UART_UARTLITE 114#ifdef CONFIG_DEBUG_UART_UARTLITE
diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c
index f689015b4a..7e486a68ff 100644
--- a/drivers/serial/serial_zynq.c
+++ b/drivers/serial/serial_zynq.c
@@ -210,7 +210,6 @@ U_BOOT_DRIVER(serial_zynq) = {
210 .platdata_auto_alloc_size = sizeof(struct zynq_uart_platdata), 210 .platdata_auto_alloc_size = sizeof(struct zynq_uart_platdata),
211 .probe = zynq_serial_probe, 211 .probe = zynq_serial_probe,
212 .ops = &zynq_serial_ops, 212 .ops = &zynq_serial_ops,
213 .flags = DM_FLAG_PRE_RELOC,
214}; 213};
215 214
216#ifdef CONFIG_DEBUG_UART_ZYNQ 215#ifdef CONFIG_DEBUG_UART_ZYNQ
diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c
index 5943a63854..20b958cfd4 100644
--- a/drivers/sysreset/sysreset_x86.c
+++ b/drivers/sysreset/sysreset_x86.c
@@ -45,5 +45,4 @@ U_BOOT_DRIVER(x86_sysreset) = {
45 .id = UCLASS_SYSRESET, 45 .id = UCLASS_SYSRESET,
46 .of_match = x86_sysreset_ids, 46 .of_match = x86_sysreset_ids,
47 .ops = &x86_sysreset_ops, 47 .ops = &x86_sysreset_ops,
48 .flags = DM_FLAG_PRE_RELOC,
49}; 48};
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index d012cf71a9..d0cfc35306 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -40,6 +40,12 @@ config TIMER_EARLY
40 use an early timer. These functions must be supported by your timer 40 use an early timer. These functions must be supported by your timer
41 driver: timer_early_get_count() and timer_early_get_rate(). 41 driver: timer_early_get_count() and timer_early_get_rate().
42 42
43config AG101P_TIMER
44 bool "AG101P timer support"
45 depends on TIMER && NDS32
46 help
47 Select this to enable a timer for AG01P devices.
48
43config ALTERA_TIMER 49config ALTERA_TIMER
44 bool "Altera timer support" 50 bool "Altera timer support"
45 depends on TIMER 51 depends on TIMER
@@ -47,6 +53,34 @@ config ALTERA_TIMER
47 Select this to enable a timer for Altera devices. Please find 53 Select this to enable a timer for Altera devices. Please find
48 details on the "Embedded Peripherals IP User Guide" of Altera. 54 details on the "Embedded Peripherals IP User Guide" of Altera.
49 55
56config ARC_TIMER
57 bool "ARC timer support"
58 depends on TIMER && ARC && CLK
59 help
60 Select this to enable built-in ARC timers.
61 ARC cores may have up to 2 built-in timers: timer0 and timer1,
62 usually at least one of them exists. Either of them is supported
63 in U-Boot.
64
65config AST_TIMER
66 bool "Aspeed ast2400/ast2500 timer support"
67 depends on TIMER
68 default y if ARCH_ASPEED
69 help
70 Select this to enable timer for Aspeed ast2400/ast2500 devices.
71 This is a simple sys timer driver, it is compatible with lib/time.c,
72 but does not support any interrupts. Even though SoC has 8 hardware
73 counters, they are all treated as a single device by this driver.
74 This is mostly because they all share several registers which
75 makes it difficult to completely separate them.
76
77config ATCPIT100_TIMER
78 bool "ATCPIT100 timer support"
79 depends on TIMER
80 help
81 Select this to enable a ATCPIT100 timer which will be embedded
82 in AE3XX, AE250 boards.
83
50config ATMEL_PIT_TIMER 84config ATMEL_PIT_TIMER
51 bool "Atmel periodic interval timer support" 85 bool "Atmel periodic interval timer support"
52 depends on TIMER 86 depends on TIMER
@@ -69,18 +103,12 @@ config DESIGNWARE_APB_TIMER
69 Enables support for the Designware APB Timer driver. This timer is 103 Enables support for the Designware APB Timer driver. This timer is
70 present on Altera SoCFPGA SoCs. 104 present on Altera SoCFPGA SoCs.
71 105
72config SANDBOX_TIMER 106config MPC83XX_TIMER
73 bool "Sandbox timer support" 107 bool "MPC83xx timer support"
74 depends on SANDBOX && TIMER 108 depends on TIMER
75 help
76 Select this to enable an emulated timer for sandbox. It gets
77 time from host os.
78
79config X86_TSC_TIMER
80 bool "x86 Time-Stamp Counter (TSC) timer support"
81 depends on TIMER && X86
82 help 109 help
83 Select this to enable Time-Stamp Counter (TSC) timer for x86. 110 Select this to enable support for the timer found on
111 devices based on the MPC83xx family of SoCs.
84 112
85config X86_TSC_TIMER_EARLY_FREQ 113config X86_TSC_TIMER_EARLY_FREQ
86 int "x86 TSC timer frequency in MHz when used as the early timer" 114 int "x86 TSC timer frequency in MHz when used as the early timer"
@@ -98,17 +126,19 @@ config OMAP_TIMER
98 help 126 help
99 Select this to enable an timer for Omap devices. 127 Select this to enable an timer for Omap devices.
100 128
101config AST_TIMER 129config ROCKCHIP_TIMER
102 bool "Aspeed ast2400/ast2500 timer support" 130 bool "Rockchip timer support"
103 depends on TIMER 131 depends on TIMER
104 default y if ARCH_ASPEED
105 help 132 help
106 Select this to enable timer for Aspeed ast2400/ast2500 devices. 133 Select this to enable support for the timer found on
107 This is a simple sys timer driver, it is compatible with lib/time.c, 134 Rockchip devices.
108 but does not support any interrupts. Even though SoC has 8 hardware 135
109 counters, they are all treated as a single device by this driver. 136config SANDBOX_TIMER
110 This is mostly because they all share several registers which 137 bool "Sandbox timer support"
111 makes it difficult to completely separate them. 138 depends on SANDBOX && TIMER
139 help
140 Select this to enable an emulated timer for sandbox. It gets
141 time from host os.
112 142
113config STI_TIMER 143config STI_TIMER
114 bool "STi timer support" 144 bool "STi timer support"
@@ -117,47 +147,17 @@ config STI_TIMER
117 help 147 help
118 Select this to enable a timer for STi devices. 148 Select this to enable a timer for STi devices.
119 149
120config ARC_TIMER
121 bool "ARC timer support"
122 depends on TIMER && ARC && CLK
123 help
124 Select this to enable built-in ARC timers.
125 ARC cores may have up to 2 built-in timers: timer0 and timer1,
126 usually at least one of them exists. Either of them is supported
127 in U-Boot.
128
129config AG101P_TIMER
130 bool "AG101P timer support"
131 depends on TIMER && NDS32
132 help
133 Select this to enable a timer for AG01P devices.
134
135config ATCPIT100_TIMER
136 bool "ATCPIT100 timer support"
137 depends on TIMER
138 help
139 Select this to enable a ATCPIT100 timer which will be embeded
140 in AE3XX, AE250 boards.
141
142config ROCKCHIP_TIMER
143 bool "Rockchip timer support"
144 depends on TIMER
145 help
146 Select this to enable support for the timer found on
147 Rockchip devices.
148
149config STM32_TIMER 150config STM32_TIMER
150 bool "STM32 timer support" 151 bool "STM32 timer support"
151 depends on TIMER 152 depends on TIMER
152 help 153 help
153 Select this to enable support for the timer found on 154 Select this to enable support for the timer found on
154 STM32 devices. 155 STM32 devices.
155 156
156config MPC83XX_TIMER 157config X86_TSC_TIMER
157 bool "MPC83xx timer support" 158 bool "x86 Time-Stamp Counter (TSC) timer support"
158 depends on TIMER 159 depends on TIMER && X86
159 help 160 help
160 Select this to enable support for the timer found on 161 Select this to enable Time-Stamp Counter (TSC) timer for x86.
161 devices based on the MPC83xx family of SoCs.
162 162
163endmenu 163endmenu
diff --git a/drivers/timer/ag101p_timer.c b/drivers/timer/ag101p_timer.c
index 6e1ae68b32..6e20b4fc33 100644
--- a/drivers/timer/ag101p_timer.c
+++ b/drivers/timer/ag101p_timer.c
@@ -115,5 +115,4 @@ U_BOOT_DRIVER(altera_timer) = {
115 .platdata_auto_alloc_size = sizeof(struct atftmr_timer_platdata), 115 .platdata_auto_alloc_size = sizeof(struct atftmr_timer_platdata),
116 .probe = atftmr_timer_probe, 116 .probe = atftmr_timer_probe,
117 .ops = &ag101p_timer_ops, 117 .ops = &ag101p_timer_ops,
118 .flags = DM_FLAG_PRE_RELOC,
119}; 118};
diff --git a/drivers/timer/altera_timer.c b/drivers/timer/altera_timer.c
index bc76819674..6f504f7cc4 100644
--- a/drivers/timer/altera_timer.c
+++ b/drivers/timer/altera_timer.c
@@ -92,5 +92,4 @@ U_BOOT_DRIVER(altera_timer) = {
92 .platdata_auto_alloc_size = sizeof(struct altera_timer_platdata), 92 .platdata_auto_alloc_size = sizeof(struct altera_timer_platdata),
93 .probe = altera_timer_probe, 93 .probe = altera_timer_probe,
94 .ops = &altera_timer_ops, 94 .ops = &altera_timer_ops,
95 .flags = DM_FLAG_PRE_RELOC,
96}; 95};
diff --git a/drivers/timer/arc_timer.c b/drivers/timer/arc_timer.c
index cf9671ebbe..8c574ec5af 100644
--- a/drivers/timer/arc_timer.c
+++ b/drivers/timer/arc_timer.c
@@ -107,6 +107,5 @@ U_BOOT_DRIVER(arc_timer) = {
107 .of_match = arc_timer_ids, 107 .of_match = arc_timer_ids,
108 .probe = arc_timer_probe, 108 .probe = arc_timer_probe,
109 .ops = &arc_timer_ops, 109 .ops = &arc_timer_ops,
110 .flags = DM_FLAG_PRE_RELOC,
111 .priv_auto_alloc_size = sizeof(struct arc_timer_priv), 110 .priv_auto_alloc_size = sizeof(struct arc_timer_priv),
112}; 111};
diff --git a/drivers/timer/ast_timer.c b/drivers/timer/ast_timer.c
index 9973506f6b..21ffdbf575 100644
--- a/drivers/timer/ast_timer.c
+++ b/drivers/timer/ast_timer.c
@@ -90,5 +90,4 @@ U_BOOT_DRIVER(ast_timer) = {
90 .priv_auto_alloc_size = sizeof(struct ast_timer_priv), 90 .priv_auto_alloc_size = sizeof(struct ast_timer_priv),
91 .ofdata_to_platdata = ast_timer_ofdata_to_platdata, 91 .ofdata_to_platdata = ast_timer_ofdata_to_platdata,
92 .ops = &ast_timer_ops, 92 .ops = &ast_timer_ops,
93 .flags = DM_FLAG_PRE_RELOC,
94}; 93};
diff --git a/drivers/timer/atcpit100_timer.c b/drivers/timer/atcpit100_timer.c
index f650c1bf66..c5d43b4a4a 100644
--- a/drivers/timer/atcpit100_timer.c
+++ b/drivers/timer/atcpit100_timer.c
@@ -110,5 +110,4 @@ U_BOOT_DRIVER(atcpit100_timer) = {
110 .platdata_auto_alloc_size = sizeof(struct atcpit_timer_platdata), 110 .platdata_auto_alloc_size = sizeof(struct atcpit_timer_platdata),
111 .probe = atcpit_timer_probe, 111 .probe = atcpit_timer_probe,
112 .ops = &atcpit_timer_ops, 112 .ops = &atcpit_timer_ops,
113 .flags = DM_FLAG_PRE_RELOC,
114}; 113};
diff --git a/drivers/timer/atmel_pit_timer.c b/drivers/timer/atmel_pit_timer.c
index 603563d3de..009af2f929 100644
--- a/drivers/timer/atmel_pit_timer.c
+++ b/drivers/timer/atmel_pit_timer.c
@@ -85,5 +85,4 @@ U_BOOT_DRIVER(atmel_pit) = {
85 .platdata_auto_alloc_size = sizeof(struct atmel_pit_platdata), 85 .platdata_auto_alloc_size = sizeof(struct atmel_pit_platdata),
86 .probe = atmel_pit_probe, 86 .probe = atmel_pit_probe,
87 .ops = &atmel_pit_ops, 87 .ops = &atmel_pit_ops,
88 .flags = DM_FLAG_PRE_RELOC,
89}; 88};
diff --git a/drivers/timer/cadence-ttc.c b/drivers/timer/cadence-ttc.c
index 4125a078b3..75263c5375 100644
--- a/drivers/timer/cadence-ttc.c
+++ b/drivers/timer/cadence-ttc.c
@@ -111,5 +111,4 @@ U_BOOT_DRIVER(cadence_ttc) = {
111 .priv_auto_alloc_size = sizeof(struct cadence_ttc_priv), 111 .priv_auto_alloc_size = sizeof(struct cadence_ttc_priv),
112 .probe = cadence_ttc_probe, 112 .probe = cadence_ttc_probe,
113 .ops = &cadence_ttc_ops, 113 .ops = &cadence_ttc_ops,
114 .flags = DM_FLAG_PRE_RELOC,
115}; 114};
diff --git a/drivers/timer/dw-apb-timer.c b/drivers/timer/dw-apb-timer.c
index 031f429acb..085bfb02c5 100644
--- a/drivers/timer/dw-apb-timer.c
+++ b/drivers/timer/dw-apb-timer.c
@@ -83,7 +83,6 @@ U_BOOT_DRIVER(dw_apb_timer) = {
83 .id = UCLASS_TIMER, 83 .id = UCLASS_TIMER,
84 .ops = &dw_apb_timer_ops, 84 .ops = &dw_apb_timer_ops,
85 .probe = dw_apb_timer_probe, 85 .probe = dw_apb_timer_probe,
86 .flags = DM_FLAG_PRE_RELOC,
87 .of_match = dw_apb_timer_ids, 86 .of_match = dw_apb_timer_ids,
88 .ofdata_to_platdata = dw_apb_timer_ofdata_to_platdata, 87 .ofdata_to_platdata = dw_apb_timer_ofdata_to_platdata,
89 .priv_auto_alloc_size = sizeof(struct dw_apb_timer_priv), 88 .priv_auto_alloc_size = sizeof(struct dw_apb_timer_priv),
diff --git a/drivers/timer/mpc83xx_timer.c b/drivers/timer/mpc83xx_timer.c
index 84a9ab072a..8e541109d4 100644
--- a/drivers/timer/mpc83xx_timer.c
+++ b/drivers/timer/mpc83xx_timer.c
@@ -244,6 +244,5 @@ U_BOOT_DRIVER(mpc83xx_timer) = {
244 .of_match = mpc83xx_timer_ids, 244 .of_match = mpc83xx_timer_ids,
245 .probe = mpc83xx_timer_probe, 245 .probe = mpc83xx_timer_probe,
246 .ops = &mpc83xx_timer_ops, 246 .ops = &mpc83xx_timer_ops,
247 .flags = DM_FLAG_PRE_RELOC,
248 .priv_auto_alloc_size = sizeof(struct mpc83xx_timer_priv), 247 .priv_auto_alloc_size = sizeof(struct mpc83xx_timer_priv),
249}; 248};
diff --git a/drivers/timer/omap-timer.c b/drivers/timer/omap-timer.c
index f10df69092..a13fb71165 100644
--- a/drivers/timer/omap-timer.c
+++ b/drivers/timer/omap-timer.c
@@ -104,5 +104,4 @@ U_BOOT_DRIVER(omap_timer) = {
104 .priv_auto_alloc_size = sizeof(struct omap_timer_priv), 104 .priv_auto_alloc_size = sizeof(struct omap_timer_priv),
105 .probe = omap_timer_probe, 105 .probe = omap_timer_probe,
106 .ops = &omap_timer_ops, 106 .ops = &omap_timer_ops,
107 .flags = DM_FLAG_PRE_RELOC,
108}; 107};
diff --git a/drivers/timer/rockchip_timer.c b/drivers/timer/rockchip_timer.c
index 17bf6a44c3..69019740b0 100644
--- a/drivers/timer/rockchip_timer.c
+++ b/drivers/timer/rockchip_timer.c
@@ -163,7 +163,6 @@ U_BOOT_DRIVER(rockchip_rk3368_timer) = {
163 .of_match = rockchip_timer_ids, 163 .of_match = rockchip_timer_ids,
164 .probe = rockchip_timer_probe, 164 .probe = rockchip_timer_probe,
165 .ops = &rockchip_timer_ops, 165 .ops = &rockchip_timer_ops,
166 .flags = DM_FLAG_PRE_RELOC,
167 .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv), 166 .priv_auto_alloc_size = sizeof(struct rockchip_timer_priv),
168#if CONFIG_IS_ENABLED(OF_PLATDATA) 167#if CONFIG_IS_ENABLED(OF_PLATDATA)
169 .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat), 168 .platdata_auto_alloc_size = sizeof(struct rockchip_timer_plat),
diff --git a/drivers/timer/sti-timer.c b/drivers/timer/sti-timer.c
index f7f0e72fe1..9def7e02f4 100644
--- a/drivers/timer/sti-timer.c
+++ b/drivers/timer/sti-timer.c
@@ -74,5 +74,4 @@ U_BOOT_DRIVER(sti_timer) = {
74 .priv_auto_alloc_size = sizeof(struct sti_timer_priv), 74 .priv_auto_alloc_size = sizeof(struct sti_timer_priv),
75 .probe = sti_timer_probe, 75 .probe = sti_timer_probe,
76 .ops = &sti_timer_ops, 76 .ops = &sti_timer_ops,
77 .flags = DM_FLAG_PRE_RELOC,
78}; 77};
diff --git a/drivers/timer/stm32_timer.c b/drivers/timer/stm32_timer.c
index 9a856b1b5a..76315100e2 100644
--- a/drivers/timer/stm32_timer.c
+++ b/drivers/timer/stm32_timer.c
@@ -132,6 +132,5 @@ U_BOOT_DRIVER(stm32_timer) = {
132 .priv_auto_alloc_size = sizeof(struct stm32_timer_priv), 132 .priv_auto_alloc_size = sizeof(struct stm32_timer_priv),
133 .probe = stm32_timer_probe, 133 .probe = stm32_timer_probe,
134 .ops = &stm32_timer_ops, 134 .ops = &stm32_timer_ops,
135 .flags = DM_FLAG_PRE_RELOC,
136}; 135};
137 136
diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c
index fe73f71819..12ee6eb804 100644
--- a/drivers/timer/timer-uclass.c
+++ b/drivers/timer/timer-uclass.c
@@ -108,7 +108,7 @@ int notrace dm_timer_init(void)
108 * If the timer is not marked to be bound before 108 * If the timer is not marked to be bound before
109 * relocation, bind it anyway. 109 * relocation, bind it anyway.
110 */ 110 */
111 if (!lists_bind_fdt(dm_root(), node, &dev)) { 111 if (!lists_bind_fdt(dm_root(), node, &dev, false)) {
112 ret = device_probe(dev); 112 ret = device_probe(dev);
113 if (ret) 113 if (ret)
114 return ret; 114 return ret;
diff --git a/drivers/timer/tsc_timer.c b/drivers/timer/tsc_timer.c
index da7c812908..ba940ebf1c 100644
--- a/drivers/timer/tsc_timer.c
+++ b/drivers/timer/tsc_timer.c
@@ -424,5 +424,4 @@ U_BOOT_DRIVER(tsc_timer) = {
424 .of_match = tsc_timer_ids, 424 .of_match = tsc_timer_ids,
425 .probe = tsc_timer_probe, 425 .probe = tsc_timer_probe,
426 .ops = &tsc_timer_ops, 426 .ops = &tsc_timer_ops,
427 .flags = DM_FLAG_PRE_RELOC,
428}; 427};
diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c
index 3b8da808bd..1679d20002 100644
--- a/drivers/video/simplefb.c
+++ b/drivers/video/simplefb.c
@@ -68,5 +68,4 @@ U_BOOT_DRIVER(simple_video) = {
68 .id = UCLASS_VIDEO, 68 .id = UCLASS_VIDEO,
69 .of_match = simple_video_ids, 69 .of_match = simple_video_ids,
70 .probe = simple_video_probe, 70 .probe = simple_video_probe,
71 .flags = DM_FLAG_PRE_RELOC,
72}; 71};
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
new file mode 100644
index 0000000000..a9d5fd07b7
--- /dev/null
+++ b/drivers/virtio/Kconfig
@@ -0,0 +1,62 @@
1# SPDX-License-Identifier: GPL-2.0+
2#
3# Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5#
6# VirtIO is a virtualization standard for network and disk device drivers
7# where just the guest's device driver "knows" it is running in a virtual
8# environment, and cooperates with the hypervisor. This enables guests to
9# get high performance network and disk operations, and gives most of the
10# performance benefits of paravirtualization. In the U-Boot case, the guest
11# is U-Boot itself, while the virtual environment are normally QEMU targets
12# like ARM, RISC-V and x86.
13#
14# See http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf for
15# the VirtIO specification v1.0.
16
17menu "VirtIO Drivers"
18
19config VIRTIO
20 bool
21 help
22 This option is selected by any driver which implements the virtio
23 transport, such as CONFIG_VIRTIO_MMIO or CONFIG_VIRTIO_PCI.
24
25config VIRTIO_MMIO
26 bool "Platform bus driver for memory mapped virtio devices"
27 select VIRTIO
28 help
29 This driver provides support for memory mapped virtio
30 platform device driver.
31
32config VIRTIO_PCI
33 bool "PCI driver for virtio devices"
34 depends on DM_PCI
35 select VIRTIO
36 help
37 This driver provides support for virtio based paravirtual device
38 drivers over PCI.
39
40config VIRTIO_SANDBOX
41 bool "Sandbox driver for virtio devices"
42 depends on SANDBOX
43 select VIRTIO
44 help
45 This driver provides support for Sandbox implementation of virtio
46 transport driver which is used for testing purpose only.
47
48config VIRTIO_NET
49 bool "virtio net driver"
50 depends on VIRTIO
51 help
52 This is the virtual net driver for virtio. It can be used with
53 QEMU based targets.
54
55config VIRTIO_BLK
56 bool "virtio block driver"
57 depends on VIRTIO
58 help
59 This is the virtual block driver for virtio. It can be used with
60 QEMU based targets.
61
62endmenu
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
new file mode 100644
index 0000000000..4579044ae3
--- /dev/null
+++ b/drivers/virtio/Makefile
@@ -0,0 +1,11 @@
1# SPDX-License-Identifier: GPL-2.0+
2#
3# Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5
6obj-y += virtio-uclass.o virtio_ring.o
7obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
8obj-$(CONFIG_VIRTIO_PCI) += virtio_pci_legacy.o virtio_pci_modern.o
9obj-$(CONFIG_VIRTIO_SANDBOX) += virtio_sandbox.o
10obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
11obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o
diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c
new file mode 100644
index 0000000000..34397d7dbb
--- /dev/null
+++ b/drivers/virtio/virtio-uclass.c
@@ -0,0 +1,369 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * VirtIO is a virtualization standard for network and disk device drivers
7 * where just the guest's device driver "knows" it is running in a virtual
8 * environment, and cooperates with the hypervisor. This enables guests to
9 * get high performance network and disk operations, and gives most of the
10 * performance benefits of paravirtualization. In the U-Boot case, the guest
11 * is U-Boot itself, while the virtual environment are normally QEMU targets
12 * like ARM, RISC-V and x86.
13 *
14 * See http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf for
15 * the VirtIO specification v1.0.
16 */
17
18#include <common.h>
19#include <dm.h>
20#include <virtio_types.h>
21#include <virtio.h>
22#include <dm/lists.h>
23
24static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = {
25 [VIRTIO_ID_NET] = VIRTIO_NET_DRV_NAME,
26 [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME,
27};
28
29int virtio_get_config(struct udevice *vdev, unsigned int offset,
30 void *buf, unsigned int len)
31{
32 struct dm_virtio_ops *ops;
33
34 ops = virtio_get_ops(vdev->parent);
35
36 return ops->get_config(vdev->parent, offset, buf, len);
37}
38
39int virtio_set_config(struct udevice *vdev, unsigned int offset,
40 void *buf, unsigned int len)
41{
42 struct dm_virtio_ops *ops;
43
44 ops = virtio_get_ops(vdev->parent);
45
46 return ops->set_config(vdev->parent, offset, buf, len);
47}
48
49int virtio_generation(struct udevice *vdev, u32 *counter)
50{
51 struct dm_virtio_ops *ops;
52
53 ops = virtio_get_ops(vdev->parent);
54 if (!ops->generation)
55 return -ENOSYS;
56
57 return ops->generation(vdev->parent, counter);
58}
59
60int virtio_get_status(struct udevice *vdev, u8 *status)
61{
62 struct dm_virtio_ops *ops;
63
64 ops = virtio_get_ops(vdev->parent);
65
66 return ops->get_status(vdev->parent, status);
67}
68
69int virtio_set_status(struct udevice *vdev, u8 status)
70{
71 struct dm_virtio_ops *ops;
72
73 ops = virtio_get_ops(vdev->parent);
74
75 return ops->set_status(vdev->parent, status);
76}
77
78int virtio_reset(struct udevice *vdev)
79{
80 struct dm_virtio_ops *ops;
81
82 ops = virtio_get_ops(vdev->parent);
83
84 return ops->reset(vdev->parent);
85}
86
87int virtio_get_features(struct udevice *vdev, u64 *features)
88{
89 struct dm_virtio_ops *ops;
90
91 ops = virtio_get_ops(vdev->parent);
92
93 return ops->get_features(vdev->parent, features);
94}
95
96int virtio_set_features(struct udevice *vdev)
97{
98 struct dm_virtio_ops *ops;
99
100 ops = virtio_get_ops(vdev->parent);
101
102 return ops->set_features(vdev->parent);
103}
104
105int virtio_find_vqs(struct udevice *vdev, unsigned int nvqs,
106 struct virtqueue *vqs[])
107{
108 struct dm_virtio_ops *ops;
109
110 ops = virtio_get_ops(vdev->parent);
111
112 return ops->find_vqs(vdev->parent, nvqs, vqs);
113}
114
115int virtio_del_vqs(struct udevice *vdev)
116{
117 struct dm_virtio_ops *ops;
118
119 ops = virtio_get_ops(vdev->parent);
120
121 return ops->del_vqs(vdev->parent);
122}
123
124int virtio_notify(struct udevice *vdev, struct virtqueue *vq)
125{
126 struct dm_virtio_ops *ops;
127
128 ops = virtio_get_ops(vdev->parent);
129
130 return ops->notify(vdev->parent, vq);
131}
132
133void virtio_add_status(struct udevice *vdev, u8 status)
134{
135 u8 old;
136
137 if (!virtio_get_status(vdev, &old))
138 virtio_set_status(vdev, old | status);
139}
140
141int virtio_finalize_features(struct udevice *vdev)
142{
143 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
144 u8 status;
145 int ret;
146
147 ret = virtio_set_features(vdev);
148 if (ret)
149 return ret;
150
151 if (uc_priv->legacy)
152 return 0;
153
154 virtio_add_status(vdev, VIRTIO_CONFIG_S_FEATURES_OK);
155 ret = virtio_get_status(vdev, &status);
156 if (ret)
157 return ret;
158 if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
159 debug("(%s): device refuses features %x\n", vdev->name, status);
160 return -ENODEV;
161 }
162
163 return 0;
164}
165
166void virtio_driver_features_init(struct virtio_dev_priv *priv,
167 const u32 *feature,
168 u32 feature_size,
169 const u32 *feature_legacy,
170 u32 feature_legacy_size)
171{
172 priv->feature_table = feature;
173 priv->feature_table_size = feature_size;
174 priv->feature_table_legacy = feature_legacy;
175 priv->feature_table_size_legacy = feature_legacy_size;
176}
177
178int virtio_init(void)
179{
180 struct udevice *bus;
181 int ret;
182
183 /* Enumerate all known virtio devices */
184 ret = uclass_first_device(UCLASS_VIRTIO, &bus);
185 if (ret)
186 return ret;
187
188 while (bus) {
189 ret = uclass_next_device(&bus);
190 if (ret)
191 break;
192 }
193
194 return ret;
195}
196
197static int virtio_uclass_pre_probe(struct udevice *udev)
198{
199 struct dm_virtio_ops *ops;
200
201 ops = (struct dm_virtio_ops *)(udev->driver->ops);
202
203 /*
204 * Check virtio transport driver ops here so that we don't need
205 * check these ops each time when the virtio_xxx APIs are called.
206 *
207 * Only generation op is optional. All other ops are must-have.
208 */
209 if (!ops->get_config || !ops->set_config ||
210 !ops->get_status || !ops->set_status ||
211 !ops->get_features || !ops->set_features ||
212 !ops->find_vqs || !ops->del_vqs ||
213 !ops->reset || !ops->notify)
214 return -ENOENT;
215
216 return 0;
217}
218
219static int virtio_uclass_post_probe(struct udevice *udev)
220{
221 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
222 char dev_name[30], *str;
223 struct udevice *vdev;
224 int ret;
225
226 if (uc_priv->device > VIRTIO_ID_MAX_NUM) {
227 debug("(%s): virtio device ID %d exceeds maximum num\n",
228 udev->name, uc_priv->device);
229 return 0;
230 }
231
232 if (!virtio_drv_name[uc_priv->device]) {
233 debug("(%s): underlying virtio device driver unavailable\n",
234 udev->name);
235 return 0;
236 }
237
238 snprintf(dev_name, sizeof(dev_name), "%s#%d",
239 virtio_drv_name[uc_priv->device], udev->seq);
240 str = strdup(dev_name);
241 if (!str)
242 return -ENOMEM;
243
244 ret = device_bind_driver(udev, virtio_drv_name[uc_priv->device],
245 str, &vdev);
246 if (ret == -ENOENT) {
247 debug("(%s): no driver configured\n", udev->name);
248 return 0;
249 }
250 if (ret) {
251 free(str);
252 return ret;
253 }
254 device_set_name_alloced(vdev);
255
256 INIT_LIST_HEAD(&uc_priv->vqs);
257
258 return 0;
259}
260
261static int virtio_uclass_child_post_bind(struct udevice *vdev)
262{
263 /* Acknowledge that we've seen the device */
264 virtio_add_status(vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
265
266 return 0;
267}
268
269static int virtio_uclass_child_pre_probe(struct udevice *vdev)
270{
271 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
272 u64 device_features;
273 u64 driver_features;
274 u64 driver_features_legacy;
275 int i;
276 int ret;
277
278 /*
279 * Save the real virtio device (eg: virtio-net, virtio-blk) to
280 * the transport (parent) device's uclass priv for future use.
281 */
282 uc_priv->vdev = vdev;
283
284 /*
285 * We always start by resetting the device, in case a previous driver
286 * messed it up. This also tests that code path a little.
287 */
288 ret = virtio_reset(vdev);
289 if (ret)
290 goto err;
291
292 /* We have a driver! */
293 virtio_add_status(vdev, VIRTIO_CONFIG_S_DRIVER);
294
295 /* Figure out what features the device supports */
296 virtio_get_features(vdev, &device_features);
297 debug("(%s) plain device features supported %016llx\n",
298 vdev->name, device_features);
299 if (!(device_features & (1ULL << VIRTIO_F_VERSION_1)))
300 uc_priv->legacy = true;
301
302 /* Figure out what features the driver supports */
303 driver_features = 0;
304 for (i = 0; i < uc_priv->feature_table_size; i++) {
305 unsigned int f = uc_priv->feature_table[i];
306
307 WARN_ON(f >= 64);
308 driver_features |= (1ULL << f);
309 }
310
311 /* Some drivers have a separate feature table for virtio v1.0 */
312 if (uc_priv->feature_table_legacy) {
313 driver_features_legacy = 0;
314 for (i = 0; i < uc_priv->feature_table_size_legacy; i++) {
315 unsigned int f = uc_priv->feature_table_legacy[i];
316
317 WARN_ON(f >= 64);
318 driver_features_legacy |= (1ULL << f);
319 }
320 } else {
321 driver_features_legacy = driver_features;
322 }
323
324 if (uc_priv->legacy) {
325 debug("(%s): legacy virtio device\n", vdev->name);
326 uc_priv->features = driver_features_legacy & device_features;
327 } else {
328 debug("(%s): v1.0 complaint virtio device\n", vdev->name);
329 uc_priv->features = driver_features & device_features;
330 }
331
332 /* Transport features always preserved to pass to finalize_features */
333 for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
334 if ((device_features & (1ULL << i)) &&
335 (i == VIRTIO_F_VERSION_1))
336 __virtio_set_bit(vdev->parent, i);
337
338 debug("(%s) final negotiated features supported %016llx\n",
339 vdev->name, uc_priv->features);
340 ret = virtio_finalize_features(vdev);
341 if (ret)
342 goto err;
343
344 return 0;
345
346err:
347 virtio_add_status(vdev, VIRTIO_CONFIG_S_FAILED);
348 return ret;
349}
350
351static int virtio_uclass_child_post_probe(struct udevice *vdev)
352{
353 /* Indicates that the driver is set up and ready to drive the device */
354 virtio_add_status(vdev, VIRTIO_CONFIG_S_DRIVER_OK);
355
356 return 0;
357}
358
359UCLASS_DRIVER(virtio) = {
360 .name = "virtio",
361 .id = UCLASS_VIRTIO,
362 .flags = DM_UC_FLAG_SEQ_ALIAS,
363 .pre_probe = virtio_uclass_pre_probe,
364 .post_probe = virtio_uclass_post_probe,
365 .child_post_bind = virtio_uclass_child_post_bind,
366 .child_pre_probe = virtio_uclass_child_pre_probe,
367 .child_post_probe = virtio_uclass_child_post_probe,
368 .per_device_auto_alloc_size = sizeof(struct virtio_dev_priv),
369};
diff --git a/drivers/virtio/virtio_blk.c b/drivers/virtio/virtio_blk.c
new file mode 100644
index 0000000000..e793e34e83
--- /dev/null
+++ b/drivers/virtio/virtio_blk.c
@@ -0,0 +1,137 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 */
6
7#include <common.h>
8#include <blk.h>
9#include <dm.h>
10#include <virtio_types.h>
11#include <virtio.h>
12#include <virtio_ring.h>
13#include "virtio_blk.h"
14
15struct virtio_blk_priv {
16 struct virtqueue *vq;
17};
18
19static ulong virtio_blk_do_req(struct udevice *dev, u64 sector,
20 lbaint_t blkcnt, void *buffer, u32 type)
21{
22 struct virtio_blk_priv *priv = dev_get_priv(dev);
23 unsigned int num_out = 0, num_in = 0;
24 struct virtio_sg *sgs[3];
25 u8 status;
26 int ret;
27
28 struct virtio_blk_outhdr out_hdr = {
29 .type = cpu_to_virtio32(dev, type),
30 .sector = cpu_to_virtio64(dev, sector),
31 };
32 struct virtio_sg hdr_sg = { &out_hdr, sizeof(out_hdr) };
33 struct virtio_sg data_sg = { buffer, blkcnt * 512 };
34 struct virtio_sg status_sg = { &status, sizeof(status) };
35
36 sgs[num_out++] = &hdr_sg;
37
38 if (type & VIRTIO_BLK_T_OUT)
39 sgs[num_out++] = &data_sg;
40 else
41 sgs[num_out + num_in++] = &data_sg;
42
43 sgs[num_out + num_in++] = &status_sg;
44
45 ret = virtqueue_add(priv->vq, sgs, num_out, num_in);
46 if (ret)
47 return ret;
48
49 virtqueue_kick(priv->vq);
50
51 while (!virtqueue_get_buf(priv->vq, NULL))
52 ;
53
54 return status == VIRTIO_BLK_S_OK ? blkcnt : -EIO;
55}
56
57static ulong virtio_blk_read(struct udevice *dev, lbaint_t start,
58 lbaint_t blkcnt, void *buffer)
59{
60 return virtio_blk_do_req(dev, start, blkcnt, buffer,
61 VIRTIO_BLK_T_IN);
62}
63
64static ulong virtio_blk_write(struct udevice *dev, lbaint_t start,
65 lbaint_t blkcnt, const void *buffer)
66{
67 return virtio_blk_do_req(dev, start, blkcnt, (void *)buffer,
68 VIRTIO_BLK_T_OUT);
69}
70
71static int virtio_blk_bind(struct udevice *dev)
72{
73 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
74 struct blk_desc *desc = dev_get_uclass_platdata(dev);
75 int devnum;
76
77 desc->if_type = IF_TYPE_VIRTIO;
78 /*
79 * Initialize the devnum to -ENODEV. This is to make sure that
80 * blk_next_free_devnum() works as expected, since the default
81 * value 0 is a valid devnum.
82 */
83 desc->devnum = -ENODEV;
84 devnum = blk_next_free_devnum(IF_TYPE_VIRTIO);
85 if (devnum < 0)
86 return devnum;
87 desc->devnum = devnum;
88 desc->part_type = PART_TYPE_UNKNOWN;
89 /*
90 * virtio mmio transport supplies string identification for us,
91 * while pci trnasport uses a 2-byte subvendor value.
92 */
93 if (uc_priv->vendor >> 16)
94 sprintf(desc->vendor, "%s", (char *)&uc_priv->vendor);
95 else
96 sprintf(desc->vendor, "%04x", uc_priv->vendor);
97 desc->bdev = dev;
98
99 /* Indicate what driver features we support */
100 virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0);
101
102 return 0;
103}
104
105static int virtio_blk_probe(struct udevice *dev)
106{
107 struct virtio_blk_priv *priv = dev_get_priv(dev);
108 struct blk_desc *desc = dev_get_uclass_platdata(dev);
109 u64 cap;
110 int ret;
111
112 ret = virtio_find_vqs(dev, 1, &priv->vq);
113 if (ret)
114 return ret;
115
116 desc->blksz = 512;
117 virtio_cread(dev, struct virtio_blk_config, capacity, &cap);
118 desc->lba = cap;
119
120 return 0;
121}
122
123static const struct blk_ops virtio_blk_ops = {
124 .read = virtio_blk_read,
125 .write = virtio_blk_write,
126};
127
128U_BOOT_DRIVER(virtio_blk) = {
129 .name = VIRTIO_BLK_DRV_NAME,
130 .id = UCLASS_BLK,
131 .ops = &virtio_blk_ops,
132 .bind = virtio_blk_bind,
133 .probe = virtio_blk_probe,
134 .remove = virtio_reset,
135 .priv_auto_alloc_size = sizeof(struct virtio_blk_priv),
136 .flags = DM_FLAG_ACTIVE_DMA,
137};
diff --git a/drivers/virtio/virtio_blk.h b/drivers/virtio/virtio_blk.h
new file mode 100644
index 0000000000..8d8e02fa2e
--- /dev/null
+++ b/drivers/virtio/virtio_blk.h
@@ -0,0 +1,129 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_blk.h
7 */
8
9#ifndef _LINUX_VIRTIO_BLK_H
10#define _LINUX_VIRTIO_BLK_H
11
12/* Feature bits */
13#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
14#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
15#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
16#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
17#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available */
18#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
19#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
20
21/* Legacy feature bits */
22#ifndef VIRTIO_BLK_NO_LEGACY
23#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
24#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
25#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */
26#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
27#ifndef __KERNEL__
28/* Old (deprecated) name for VIRTIO_BLK_F_FLUSH */
29#define VIRTIO_BLK_F_WCE VIRTIO_BLK_F_FLUSH
30#endif
31#endif /* !VIRTIO_BLK_NO_LEGACY */
32
33#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */
34
35struct __packed virtio_blk_config {
36 /* The capacity (in 512-byte sectors) */
37 __u64 capacity;
38 /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
39 __u32 size_max;
40 /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
41 __u32 seg_max;
42 /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
43 struct virtio_blk_geometry {
44 __u16 cylinders;
45 __u8 heads;
46 __u8 sectors;
47 } geometry;
48
49 /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
50 __u32 blk_size;
51
52 /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */
53 /* exponent for physical block per logical block */
54 __u8 physical_block_exp;
55 /* alignment offset in logical blocks */
56 __u8 alignment_offset;
57 /* minimum I/O size without performance penalty in logical blocks */
58 __u16 min_io_size;
59 /* optimal sustained I/O size in logical blocks */
60 __u32 opt_io_size;
61
62 /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */
63 __u8 wce;
64 __u8 unused;
65
66 /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */
67 __u16 num_queues;
68};
69
70/*
71 * Command types
72 *
73 * Usage is a bit tricky as some bits are used as flags and some are not.
74 *
75 * Rules:
76 * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or
77 * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own
78 * and may not be combined with any of the other flags.
79 */
80
81/* These two define direction */
82#define VIRTIO_BLK_T_IN 0
83#define VIRTIO_BLK_T_OUT 1
84
85#ifndef VIRTIO_BLK_NO_LEGACY
86/* This bit says it's a scsi command, not an actual read or write */
87#define VIRTIO_BLK_T_SCSI_CMD 2
88#endif /* VIRTIO_BLK_NO_LEGACY */
89
90/* Cache flush command */
91#define VIRTIO_BLK_T_FLUSH 4
92
93/* Get device ID command */
94#define VIRTIO_BLK_T_GET_ID 8
95
96#ifndef VIRTIO_BLK_NO_LEGACY
97/* Barrier before this op */
98#define VIRTIO_BLK_T_BARRIER 0x80000000
99#endif /* !VIRTIO_BLK_NO_LEGACY */
100
101/*
102 * This comes first in the read scatter-gather list.
103 * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated,
104 * this is the first element of the read scatter-gather list.
105 */
106struct virtio_blk_outhdr {
107 /* VIRTIO_BLK_T* */
108 __virtio32 type;
109 /* io priority */
110 __virtio32 ioprio;
111 /* Sector (ie. 512 byte offset) */
112 __virtio64 sector;
113};
114
115#ifndef VIRTIO_BLK_NO_LEGACY
116struct virtio_scsi_inhdr {
117 __virtio32 errors;
118 __virtio32 data_len;
119 __virtio32 sense_len;
120 __virtio32 residual;
121};
122#endif /* !VIRTIO_BLK_NO_LEGACY */
123
124/* And this is the final byte of the write scatter-gather list */
125#define VIRTIO_BLK_S_OK 0
126#define VIRTIO_BLK_S_IOERR 1
127#define VIRTIO_BLK_S_UNSUPP 2
128
129#endif /* _LINUX_VIRTIO_BLK_H */
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
new file mode 100644
index 0000000000..7b738703b8
--- /dev/null
+++ b/drivers/virtio/virtio_mmio.c
@@ -0,0 +1,413 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * VirtIO memory-maped I/O transport driver
7 * Ported from Linux drivers/virtio/virtio_mmio.c
8 */
9
10#include <common.h>
11#include <dm.h>
12#include <virtio_types.h>
13#include <virtio.h>
14#include <virtio_ring.h>
15#include <linux/compat.h>
16#include <linux/io.h>
17#include "virtio_mmio.h"
18
19static int virtio_mmio_get_config(struct udevice *udev, unsigned int offset,
20 void *buf, unsigned int len)
21{
22 struct virtio_mmio_priv *priv = dev_get_priv(udev);
23 void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
24 u8 b;
25 __le16 w;
26 __le32 l;
27
28 if (priv->version == 1) {
29 u8 *ptr = buf;
30 int i;
31
32 for (i = 0; i < len; i++)
33 ptr[i] = readb(base + offset + i);
34
35 return 0;
36 }
37
38 switch (len) {
39 case 1:
40 b = readb(base + offset);
41 memcpy(buf, &b, sizeof(b));
42 break;
43 case 2:
44 w = cpu_to_le16(readw(base + offset));
45 memcpy(buf, &w, sizeof(w));
46 break;
47 case 4:
48 l = cpu_to_le32(readl(base + offset));
49 memcpy(buf, &l, sizeof(l));
50 break;
51 case 8:
52 l = cpu_to_le32(readl(base + offset));
53 memcpy(buf, &l, sizeof(l));
54 l = cpu_to_le32(readl(base + offset + sizeof(l)));
55 memcpy(buf + sizeof(l), &l, sizeof(l));
56 break;
57 default:
58 WARN_ON(true);
59 }
60
61 return 0;
62}
63
64static int virtio_mmio_set_config(struct udevice *udev, unsigned int offset,
65 const void *buf, unsigned int len)
66{
67 struct virtio_mmio_priv *priv = dev_get_priv(udev);
68 void __iomem *base = priv->base + VIRTIO_MMIO_CONFIG;
69 u8 b;
70 __le16 w;
71 __le32 l;
72
73 if (priv->version == 1) {
74 const u8 *ptr = buf;
75 int i;
76
77 for (i = 0; i < len; i++)
78 writeb(ptr[i], base + offset + i);
79
80 return 0;
81 }
82
83 switch (len) {
84 case 1:
85 memcpy(&b, buf, sizeof(b));
86 writeb(b, base + offset);
87 break;
88 case 2:
89 memcpy(&w, buf, sizeof(w));
90 writew(le16_to_cpu(w), base + offset);
91 break;
92 case 4:
93 memcpy(&l, buf, sizeof(l));
94 writel(le32_to_cpu(l), base + offset);
95 break;
96 case 8:
97 memcpy(&l, buf, sizeof(l));
98 writel(le32_to_cpu(l), base + offset);
99 memcpy(&l, buf + sizeof(l), sizeof(l));
100 writel(le32_to_cpu(l), base + offset + sizeof(l));
101 break;
102 default:
103 WARN_ON(true);
104 }
105
106 return 0;
107}
108
109static int virtio_mmio_generation(struct udevice *udev, u32 *counter)
110{
111 struct virtio_mmio_priv *priv = dev_get_priv(udev);
112
113 if (priv->version == 1)
114 *counter = 0;
115 else
116 *counter = readl(priv->base + VIRTIO_MMIO_CONFIG_GENERATION);
117
118 return 0;
119}
120
121static int virtio_mmio_get_status(struct udevice *udev, u8 *status)
122{
123 struct virtio_mmio_priv *priv = dev_get_priv(udev);
124
125 *status = readl(priv->base + VIRTIO_MMIO_STATUS) & 0xff;
126
127 return 0;
128}
129
130static int virtio_mmio_set_status(struct udevice *udev, u8 status)
131{
132 struct virtio_mmio_priv *priv = dev_get_priv(udev);
133
134 /* We should never be setting status to 0 */
135 WARN_ON(status == 0);
136
137 writel(status, priv->base + VIRTIO_MMIO_STATUS);
138
139 return 0;
140}
141
142static int virtio_mmio_reset(struct udevice *udev)
143{
144 struct virtio_mmio_priv *priv = dev_get_priv(udev);
145
146 /* 0 status means a reset */
147 writel(0, priv->base + VIRTIO_MMIO_STATUS);
148
149 return 0;
150}
151
152static int virtio_mmio_get_features(struct udevice *udev, u64 *features)
153{
154 struct virtio_mmio_priv *priv = dev_get_priv(udev);
155
156 writel(1, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
157 *features = readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
158 *features <<= 32;
159
160 writel(0, priv->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
161 *features |= readl(priv->base + VIRTIO_MMIO_DEVICE_FEATURES);
162
163 return 0;
164}
165
166static int virtio_mmio_set_features(struct udevice *udev)
167{
168 struct virtio_mmio_priv *priv = dev_get_priv(udev);
169 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
170
171 /* Make sure there is are no mixed devices */
172 if (priv->version == 2 && uc_priv->legacy) {
173 debug("New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n");
174 return -EINVAL;
175 }
176
177 writel(1, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
178 writel((u32)(uc_priv->features >> 32),
179 priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
180
181 writel(0, priv->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
182 writel((u32)uc_priv->features,
183 priv->base + VIRTIO_MMIO_DRIVER_FEATURES);
184
185 return 0;
186}
187
188static struct virtqueue *virtio_mmio_setup_vq(struct udevice *udev,
189 unsigned int index)
190{
191 struct virtio_mmio_priv *priv = dev_get_priv(udev);
192 struct virtqueue *vq;
193 unsigned int num;
194 int err;
195
196 /* Select the queue we're interested in */
197 writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
198
199 /* Queue shouldn't already be set up */
200 if (readl(priv->base + (priv->version == 1 ?
201 VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) {
202 err = -ENOENT;
203 goto error_available;
204 }
205
206 num = readl(priv->base + VIRTIO_MMIO_QUEUE_NUM_MAX);
207 if (num == 0) {
208 err = -ENOENT;
209 goto error_new_virtqueue;
210 }
211
212 /* Create the vring */
213 vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, udev);
214 if (!vq) {
215 err = -ENOMEM;
216 goto error_new_virtqueue;
217 }
218
219 /* Activate the queue */
220 writel(virtqueue_get_vring_size(vq),
221 priv->base + VIRTIO_MMIO_QUEUE_NUM);
222 if (priv->version == 1) {
223 u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT;
224
225 /*
226 * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something
227 * that doesn't fit in 32bit, fail the setup rather than
228 * pretending to be successful.
229 */
230 if (q_pfn >> 32) {
231 debug("platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n",
232 0x1ULL << (32 + PAGE_SHIFT - 30));
233 err = -E2BIG;
234 goto error_bad_pfn;
235 }
236
237 writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_QUEUE_ALIGN);
238 writel(q_pfn, priv->base + VIRTIO_MMIO_QUEUE_PFN);
239 } else {
240 u64 addr;
241
242 addr = virtqueue_get_desc_addr(vq);
243 writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
244 writel((u32)(addr >> 32),
245 priv->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
246
247 addr = virtqueue_get_avail_addr(vq);
248 writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
249 writel((u32)(addr >> 32),
250 priv->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
251
252 addr = virtqueue_get_used_addr(vq);
253 writel((u32)addr, priv->base + VIRTIO_MMIO_QUEUE_USED_LOW);
254 writel((u32)(addr >> 32),
255 priv->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
256
257 writel(1, priv->base + VIRTIO_MMIO_QUEUE_READY);
258 }
259
260 return vq;
261
262error_bad_pfn:
263 vring_del_virtqueue(vq);
264
265error_new_virtqueue:
266 if (priv->version == 1) {
267 writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
268 } else {
269 writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
270 WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
271 }
272
273error_available:
274 return ERR_PTR(err);
275}
276
277static void virtio_mmio_del_vq(struct virtqueue *vq)
278{
279 struct virtio_mmio_priv *priv = dev_get_priv(vq->vdev);
280 unsigned int index = vq->index;
281
282 /* Select and deactivate the queue */
283 writel(index, priv->base + VIRTIO_MMIO_QUEUE_SEL);
284 if (priv->version == 1) {
285 writel(0, priv->base + VIRTIO_MMIO_QUEUE_PFN);
286 } else {
287 writel(0, priv->base + VIRTIO_MMIO_QUEUE_READY);
288 WARN_ON(readl(priv->base + VIRTIO_MMIO_QUEUE_READY));
289 }
290
291 vring_del_virtqueue(vq);
292}
293
294static int virtio_mmio_del_vqs(struct udevice *udev)
295{
296 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
297 struct virtqueue *vq, *n;
298
299 list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
300 virtio_mmio_del_vq(vq);
301
302 return 0;
303}
304
305static int virtio_mmio_find_vqs(struct udevice *udev, unsigned int nvqs,
306 struct virtqueue *vqs[])
307{
308 int i;
309
310 for (i = 0; i < nvqs; ++i) {
311 vqs[i] = virtio_mmio_setup_vq(udev, i);
312 if (IS_ERR(vqs[i])) {
313 virtio_mmio_del_vqs(udev);
314 return PTR_ERR(vqs[i]);
315 }
316 }
317
318 return 0;
319}
320
321static int virtio_mmio_notify(struct udevice *udev, struct virtqueue *vq)
322{
323 struct virtio_mmio_priv *priv = dev_get_priv(udev);
324
325 /*
326 * We write the queue's selector into the notification register
327 * to signal the other end
328 */
329 writel(vq->index, priv->base + VIRTIO_MMIO_QUEUE_NOTIFY);
330
331 return 0;
332}
333
334static int virtio_mmio_ofdata_to_platdata(struct udevice *udev)
335{
336 struct virtio_mmio_priv *priv = dev_get_priv(udev);
337
338 priv->base = (void __iomem *)(ulong)dev_read_addr(udev);
339 if (priv->base == (void __iomem *)FDT_ADDR_T_NONE)
340 return -EINVAL;
341
342 return 0;
343}
344
345static int virtio_mmio_probe(struct udevice *udev)
346{
347 struct virtio_mmio_priv *priv = dev_get_priv(udev);
348 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
349 u32 magic;
350
351 /* Check magic value */
352 magic = readl(priv->base + VIRTIO_MMIO_MAGIC_VALUE);
353 if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) {
354 debug("(%s): wrong magic value 0x%08x!\n", udev->name, magic);
355 return 0;
356 }
357
358 /* Check device version */
359 priv->version = readl(priv->base + VIRTIO_MMIO_VERSION);
360 if (priv->version < 1 || priv->version > 2) {
361 debug("(%s): version %d not supported!\n",
362 udev->name, priv->version);
363 return 0;
364 }
365
366 /* Check devicd ID */
367 uc_priv->device = readl(priv->base + VIRTIO_MMIO_DEVICE_ID);
368 if (uc_priv->device == 0) {
369 /*
370 * virtio-mmio device with an ID 0 is a (dummy) placeholder
371 * with no function. End probing now with no error reported.
372 */
373 return 0;
374 }
375 uc_priv->vendor = readl(priv->base + VIRTIO_MMIO_VENDOR_ID);
376
377 if (priv->version == 1)
378 writel(PAGE_SIZE, priv->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
379
380 debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
381 uc_priv->device, uc_priv->vendor, priv->version);
382
383 return 0;
384}
385
386static const struct dm_virtio_ops virtio_mmio_ops = {
387 .get_config = virtio_mmio_get_config,
388 .set_config = virtio_mmio_set_config,
389 .generation = virtio_mmio_generation,
390 .get_status = virtio_mmio_get_status,
391 .set_status = virtio_mmio_set_status,
392 .reset = virtio_mmio_reset,
393 .get_features = virtio_mmio_get_features,
394 .set_features = virtio_mmio_set_features,
395 .find_vqs = virtio_mmio_find_vqs,
396 .del_vqs = virtio_mmio_del_vqs,
397 .notify = virtio_mmio_notify,
398};
399
400static const struct udevice_id virtio_mmio_ids[] = {
401 { .compatible = "virtio,mmio" },
402 { }
403};
404
405U_BOOT_DRIVER(virtio_mmio) = {
406 .name = "virtio-mmio",
407 .id = UCLASS_VIRTIO,
408 .of_match = virtio_mmio_ids,
409 .ops = &virtio_mmio_ops,
410 .probe = virtio_mmio_probe,
411 .ofdata_to_platdata = virtio_mmio_ofdata_to_platdata,
412 .priv_auto_alloc_size = sizeof(struct virtio_mmio_priv),
413};
diff --git a/drivers/virtio/virtio_mmio.h b/drivers/virtio/virtio_mmio.h
new file mode 100644
index 0000000000..b3408828a5
--- /dev/null
+++ b/drivers/virtio/virtio_mmio.h
@@ -0,0 +1,129 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_mmio.h
7 */
8
9#ifndef _LINUX_VIRTIO_MMIO_H
10#define _LINUX_VIRTIO_MMIO_H
11
12/* Control registers */
13
14/* Magic value ("virt" string) - Read Only */
15#define VIRTIO_MMIO_MAGIC_VALUE 0x000
16
17/* Virtio device version - Read Only */
18#define VIRTIO_MMIO_VERSION 0x004
19
20/* Virtio device ID - Read Only */
21#define VIRTIO_MMIO_DEVICE_ID 0x008
22
23/* Virtio vendor ID - Read Only */
24#define VIRTIO_MMIO_VENDOR_ID 0x00c
25
26/*
27 * Bitmask of the features supported by the device (host)
28 * (32 bits per set) - Read Only
29 */
30#define VIRTIO_MMIO_DEVICE_FEATURES 0x010
31
32/* Device (host) features set selector - Write Only */
33#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014
34
35/*
36 * Bitmask of features activated by the driver (guest)
37 * (32 bits per set) - Write Only
38 */
39#define VIRTIO_MMIO_DRIVER_FEATURES 0x020
40
41/* Activated features set selector - Write Only */
42#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024
43
44#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */
45
46/* Guest's memory page size in bytes - Write Only */
47#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028
48
49#endif
50
51/* Queue selector - Write Only */
52#define VIRTIO_MMIO_QUEUE_SEL 0x030
53
54/* Maximum size of the currently selected queue - Read Only */
55#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034
56
57/* Queue size for the currently selected queue - Write Only */
58#define VIRTIO_MMIO_QUEUE_NUM 0x038
59
60#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */
61
62/* Used Ring alignment for the currently selected queue - Write Only */
63#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c
64
65/* Guest's PFN for the currently selected queue - Read Write */
66#define VIRTIO_MMIO_QUEUE_PFN 0x040
67
68#endif
69
70/* Ready bit for the currently selected queue - Read Write */
71#define VIRTIO_MMIO_QUEUE_READY 0x044
72
73/* Queue notifier - Write Only */
74#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050
75
76/* Interrupt status - Read Only */
77#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060
78
79/* Interrupt acknowledge - Write Only */
80#define VIRTIO_MMIO_INTERRUPT_ACK 0x064
81
82/* Device status register - Read Write */
83#define VIRTIO_MMIO_STATUS 0x070
84
85/* Selected queue's Descriptor Table address, 64 bits in two halves */
86#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080
87#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084
88
89/* Selected queue's Available Ring address, 64 bits in two halves */
90#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090
91#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094
92
93/* Selected queue's Used Ring address, 64 bits in two halves */
94#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0
95#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4
96
97/* Configuration atomicity value */
98#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc
99
100/*
101 * The config space is defined by each driver as
102 * the per-driver configuration space - Read Write
103 */
104#define VIRTIO_MMIO_CONFIG 0x100
105
106/* Interrupt flags (re: interrupt status & acknowledge registers) */
107
108#define VIRTIO_MMIO_INT_VRING BIT(0)
109#define VIRTIO_MMIO_INT_CONFIG BIT(1)
110
111/*
112 * The alignment to use between consumer and producer parts of vring.
113 * Currently hardcoded to the page size.
114 */
115#define PAGE_SHIFT 12
116#define VIRTIO_MMIO_VRING_ALIGN PAGE_SIZE
117
118/**
119 * virtio mmio transport driver private data
120 *
121 * @base: mmio transport device register base
122 * @version: mmio transport device version
123 */
124struct virtio_mmio_priv {
125 void __iomem *base;
126 u32 version;
127};
128
129#endif /* _LINUX_VIRTIO_MMIO_H */
diff --git a/drivers/virtio/virtio_net.c b/drivers/virtio/virtio_net.c
new file mode 100644
index 0000000000..0dbbd78023
--- /dev/null
+++ b/drivers/virtio/virtio_net.c
@@ -0,0 +1,239 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 */
6
7#include <common.h>
8#include <dm.h>
9#include <net.h>
10#include <virtio_types.h>
11#include <virtio.h>
12#include <virtio_ring.h>
13#include "virtio_net.h"
14
15/* Amount of buffers to keep in the RX virtqueue */
16#define VIRTIO_NET_NUM_RX_BUFS 32
17
18/*
19 * This value comes from the VirtIO spec: 1500 for maximum packet size,
20 * 14 for the Ethernet header, 12 for virtio_net_hdr. In total 1526 bytes.
21 */
22#define VIRTIO_NET_RX_BUF_SIZE 1526
23
24struct virtio_net_priv {
25 union {
26 struct virtqueue *vqs[2];
27 struct {
28 struct virtqueue *rx_vq;
29 struct virtqueue *tx_vq;
30 };
31 };
32
33 char rx_buff[VIRTIO_NET_NUM_RX_BUFS][VIRTIO_NET_RX_BUF_SIZE];
34 bool rx_running;
35 int net_hdr_len;
36};
37
38/*
39 * For simplicity, the driver only negotiates the VIRTIO_NET_F_MAC feature.
40 * For the VIRTIO_NET_F_STATUS feature, we don't negotiate it, hence per spec
41 * we should assume the link is always active.
42 */
43static const u32 feature[] = {
44 VIRTIO_NET_F_MAC
45};
46
47static const u32 feature_legacy[] = {
48 VIRTIO_NET_F_MAC
49};
50
51static int virtio_net_start(struct udevice *dev)
52{
53 struct virtio_net_priv *priv = dev_get_priv(dev);
54 struct virtio_sg sg;
55 struct virtio_sg *sgs[] = { &sg };
56 int i;
57
58 if (!priv->rx_running) {
59 /* receive buffer length is always 1526 */
60 sg.length = VIRTIO_NET_RX_BUF_SIZE;
61
62 /* setup the receive buffer address */
63 for (i = 0; i < VIRTIO_NET_NUM_RX_BUFS; i++) {
64 sg.addr = priv->rx_buff[i];
65 virtqueue_add(priv->rx_vq, sgs, 0, 1);
66 }
67
68 virtqueue_kick(priv->rx_vq);
69
70 /* setup the receive queue only once */
71 priv->rx_running = true;
72 }
73
74 return 0;
75}
76
77static int virtio_net_send(struct udevice *dev, void *packet, int length)
78{
79 struct virtio_net_priv *priv = dev_get_priv(dev);
80 struct virtio_net_hdr hdr;
81 struct virtio_net_hdr_v1 hdr_v1;
82 struct virtio_sg hdr_sg;
83 struct virtio_sg data_sg = { packet, length };
84 struct virtio_sg *sgs[] = { &hdr_sg, &data_sg };
85 int ret;
86
87 if (priv->net_hdr_len == sizeof(struct virtio_net_hdr))
88 hdr_sg.addr = &hdr;
89 else
90 hdr_sg.addr = &hdr_v1;
91 hdr_sg.length = priv->net_hdr_len;
92
93 memset(hdr_sg.addr, 0, priv->net_hdr_len);
94
95 ret = virtqueue_add(priv->tx_vq, sgs, 2, 0);
96 if (ret)
97 return ret;
98
99 virtqueue_kick(priv->tx_vq);
100
101 while (1) {
102 if (virtqueue_get_buf(priv->tx_vq, NULL))
103 break;
104 }
105
106 return 0;
107}
108
109static int virtio_net_recv(struct udevice *dev, int flags, uchar **packetp)
110{
111 struct virtio_net_priv *priv = dev_get_priv(dev);
112 unsigned int len;
113 void *buf;
114
115 buf = virtqueue_get_buf(priv->rx_vq, &len);
116 if (!buf)
117 return -EAGAIN;
118
119 *packetp = buf + priv->net_hdr_len;
120 return len - priv->net_hdr_len;
121}
122
123static int virtio_net_free_pkt(struct udevice *dev, uchar *packet, int length)
124{
125 struct virtio_net_priv *priv = dev_get_priv(dev);
126 void *buf = packet - priv->net_hdr_len;
127 struct virtio_sg sg = { buf, VIRTIO_NET_RX_BUF_SIZE };
128 struct virtio_sg *sgs[] = { &sg };
129
130 /* Put the buffer back to the rx ring */
131 virtqueue_add(priv->rx_vq, sgs, 0, 1);
132
133 return 0;
134}
135
136static void virtio_net_stop(struct udevice *dev)
137{
138 /*
139 * There is no way to stop the queue from running, unless we issue
140 * a reset to the virtio device, and re-do the queue initialization
141 * from the beginning.
142 */
143}
144
145static int virtio_net_write_hwaddr(struct udevice *dev)
146{
147 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
148 struct eth_pdata *pdata = dev_get_platdata(dev);
149 int i;
150
151 /*
152 * v1.0 compliant device's MAC address is set through control channel,
153 * which we don't support for now.
154 */
155 if (!uc_priv->legacy)
156 return -ENOSYS;
157
158 for (i = 0; i < sizeof(pdata->enetaddr); i++) {
159 virtio_cwrite8(dev,
160 offsetof(struct virtio_net_config, mac) + i,
161 pdata->enetaddr[i]);
162 }
163
164 return 0;
165}
166
167static int virtio_net_read_rom_hwaddr(struct udevice *dev)
168{
169 struct eth_pdata *pdata = dev_get_platdata(dev);
170
171 if (!pdata)
172 return -ENOSYS;
173
174 if (virtio_has_feature(dev, VIRTIO_NET_F_MAC)) {
175 virtio_cread_bytes(dev,
176 offsetof(struct virtio_net_config, mac),
177 pdata->enetaddr, sizeof(pdata->enetaddr));
178 }
179
180 return 0;
181}
182
183static int virtio_net_bind(struct udevice *dev)
184{
185 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
186
187 /* Indicate what driver features we support */
188 virtio_driver_features_init(uc_priv, feature, ARRAY_SIZE(feature),
189 feature_legacy, ARRAY_SIZE(feature_legacy));
190
191 return 0;
192}
193
194static int virtio_net_probe(struct udevice *dev)
195{
196 struct virtio_net_priv *priv = dev_get_priv(dev);
197 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
198 int ret;
199
200 ret = virtio_find_vqs(dev, 2, priv->vqs);
201 if (ret < 0)
202 return ret;
203
204 /*
205 * For v1.0 compliant device, it always assumes the member
206 * 'num_buffers' exists in the struct virtio_net_hdr while
207 * the legacy driver only presented 'num_buffers' when
208 * VIRTIO_NET_F_MRG_RXBUF was negotiated. Without that feature
209 * the structure was 2 bytes shorter.
210 */
211 if (uc_priv->legacy)
212 priv->net_hdr_len = sizeof(struct virtio_net_hdr);
213 else
214 priv->net_hdr_len = sizeof(struct virtio_net_hdr_v1);
215
216 return 0;
217}
218
219static const struct eth_ops virtio_net_ops = {
220 .start = virtio_net_start,
221 .send = virtio_net_send,
222 .recv = virtio_net_recv,
223 .free_pkt = virtio_net_free_pkt,
224 .stop = virtio_net_stop,
225 .write_hwaddr = virtio_net_write_hwaddr,
226 .read_rom_hwaddr = virtio_net_read_rom_hwaddr,
227};
228
229U_BOOT_DRIVER(virtio_net) = {
230 .name = VIRTIO_NET_DRV_NAME,
231 .id = UCLASS_ETH,
232 .bind = virtio_net_bind,
233 .probe = virtio_net_probe,
234 .remove = virtio_reset,
235 .ops = &virtio_net_ops,
236 .priv_auto_alloc_size = sizeof(struct virtio_net_priv),
237 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
238 .flags = DM_FLAG_ACTIVE_DMA,
239};
diff --git a/drivers/virtio/virtio_net.h b/drivers/virtio/virtio_net.h
new file mode 100644
index 0000000000..c92bae5269
--- /dev/null
+++ b/drivers/virtio/virtio_net.h
@@ -0,0 +1,268 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_net.h
7 */
8
9#ifndef _LINUX_VIRTIO_NET_H
10#define _LINUX_VIRTIO_NET_H
11
12/* TODO: needs to be removed! */
13#define ETH_ALEN 6
14
15/* The feature bitmap for virtio net */
16
17/* Host handles pkts w/ partial csum */
18#define VIRTIO_NET_F_CSUM 0
19/* Guest handles pkts w/ partial csum */
20#define VIRTIO_NET_F_GUEST_CSUM 1
21/* Dynamic offload configuration */
22#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2
23/* Initial MTU advice */
24#define VIRTIO_NET_F_MTU 3
25/* Host has given MAC address */
26#define VIRTIO_NET_F_MAC 5
27/* Guest can handle TSOv4 in */
28#define VIRTIO_NET_F_GUEST_TSO4 7
29/* Guest can handle TSOv6 in */
30#define VIRTIO_NET_F_GUEST_TSO6 8
31/* Guest can handle TSO[6] w/ ECN in */
32#define VIRTIO_NET_F_GUEST_ECN 9
33/* Guest can handle UFO in */
34#define VIRTIO_NET_F_GUEST_UFO 10
35/* Host can handle TSOv4 in */
36#define VIRTIO_NET_F_HOST_TSO4 11
37/* Host can handle TSOv6 in */
38#define VIRTIO_NET_F_HOST_TSO6 12
39/* Host can handle TSO[6] w/ ECN in */
40#define VIRTIO_NET_F_HOST_ECN 13
41/* Host can handle UFO in */
42#define VIRTIO_NET_F_HOST_UFO 14
43/* Host can merge receive buffers */
44#define VIRTIO_NET_F_MRG_RXBUF 15
45/* virtio_net_config.status available */
46#define VIRTIO_NET_F_STATUS 16
47/* Control channel available */
48#define VIRTIO_NET_F_CTRL_VQ 17
49/* Control channel RX mode support */
50#define VIRTIO_NET_F_CTRL_RX 18
51/* Control channel VLAN filtering */
52#define VIRTIO_NET_F_CTRL_VLAN 19
53/* Extra RX mode control support */
54#define VIRTIO_NET_F_CTRL_RX_EXTRA 20
55/* Guest can announce device on the network */
56#define VIRTIO_NET_F_GUEST_ANNOUNCE 21
57/* Device supports receive flow steering */
58#define VIRTIO_NET_F_MQ 22
59/* Set MAC address */
60#define VIRTIO_NET_F_CTRL_MAC_ADDR 23
61/* Device set linkspeed and duplex */
62#define VIRTIO_NET_F_SPEED_DUPLEX 63
63
64#ifndef VIRTIO_NET_NO_LEGACY
65/* Host handles pkts w/ any GSO type */
66#define VIRTIO_NET_F_GSO 6
67#endif /* VIRTIO_NET_NO_LEGACY */
68
69#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
70#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */
71
72struct __packed virtio_net_config {
73 /* The config defining mac address (if VIRTIO_NET_F_MAC) */
74 __u8 mac[ETH_ALEN];
75 /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */
76 __u16 status;
77 /*
78 * Maximum number of each of transmit and receive queues;
79 * see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ.
80 * Legal values are between 1 and 0x8000
81 */
82 __u16 max_virtqueue_pairs;
83 /* Default maximum transmit unit advice */
84 __u16 mtu;
85 /*
86 * speed, in units of 1Mb. All values 0 to INT_MAX are legal.
87 * Any other value stands for unknown.
88 */
89 __u32 speed;
90 /*
91 * 0x00 - half duplex
92 * 0x01 - full duplex
93 * Any other value stands for unknown.
94 */
95 __u8 duplex;
96};
97
98/*
99 * This header comes first in the scatter-gather list. If you don't
100 * specify GSO or CSUM features, you can simply ignore the header.
101 *
102 * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf,
103 * only flattened.
104 */
105struct virtio_net_hdr_v1 {
106#define VIRTIO_NET_HDR_F_NEEDS_CSUM 0x01 /* Use csum_start, csum_offset */
107#define VIRTIO_NET_HDR_F_DATA_VALID 0x02 /* Csum is valid */
108 __u8 flags;
109#define VIRTIO_NET_HDR_GSO_NONE 0x00 /* Not a GSO frame */
110#define VIRTIO_NET_HDR_GSO_TCPV4 0x01 /* GSO frame, IPv4 TCP (TSO) */
111#define VIRTIO_NET_HDR_GSO_UDP 0x03 /* GSO frame, IPv4 UDP (UFO) */
112#define VIRTIO_NET_HDR_GSO_TCPV6 0x04 /* GSO frame, IPv6 TCP */
113#define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */
114 __u8 gso_type;
115 __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
116 __virtio16 gso_size; /* Bytes to append to hdr_len per frame */
117 __virtio16 csum_start; /* Position to start checksumming from */
118 __virtio16 csum_offset; /* Offset after that to place checksum */
119 __virtio16 num_buffers; /* Number of merged rx buffers */
120};
121
122#ifndef VIRTIO_NET_NO_LEGACY
123/*
124 * This header comes first in the scatter-gather list.
125 *
126 * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
127 * be the first element of the scatter-gather list. If you don't
128 * specify GSO or CSUM features, you can simply ignore the header.
129 */
130struct virtio_net_hdr {
131 /* See VIRTIO_NET_HDR_F_* */
132 __u8 flags;
133 /* See VIRTIO_NET_HDR_GSO_* */
134 __u8 gso_type;
135 __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
136 __virtio16 gso_size; /* Bytes to append to hdr_len per frame */
137 __virtio16 csum_start; /* Position to start checksumming from */
138 __virtio16 csum_offset; /* Offset after that to place checksum */
139};
140
141/*
142 * This is the version of the header to use when the MRG_RXBUF
143 * feature has been negotiated.
144 */
145struct virtio_net_hdr_mrg_rxbuf {
146 struct virtio_net_hdr hdr;
147 __virtio16 num_buffers; /* Number of merged rx buffers */
148};
149#endif /* ...VIRTIO_NET_NO_LEGACY */
150
151/*
152 * Control virtqueue data structures
153 *
154 * The control virtqueue expects a header in the first sg entry
155 * and an ack/status response in the last entry. Data for the
156 * command goes in between.
157 */
158struct __packed virtio_net_ctrl_hdr {
159 __u8 class;
160 __u8 cmd;
161};
162
163typedef __u8 virtio_net_ctrl_ack;
164
165#define VIRTIO_NET_OK 0
166#define VIRTIO_NET_ERR 1
167
168/*
169 * Control the RX mode, ie. promisucous, allmulti, etc...
170 *
171 * All commands require an "out" sg entry containing a 1 byte state value,
172 * zero = disable, non-zero = enable.
173 *
174 * Commands 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
175 * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
176 */
177#define VIRTIO_NET_CTRL_RX 0
178#define VIRTIO_NET_CTRL_RX_PROMISC 0
179#define VIRTIO_NET_CTRL_RX_ALLMULTI 1
180#define VIRTIO_NET_CTRL_RX_ALLUNI 2
181#define VIRTIO_NET_CTRL_RX_NOMULTI 3
182#define VIRTIO_NET_CTRL_RX_NOUNI 4
183#define VIRTIO_NET_CTRL_RX_NOBCAST 5
184
185/*
186 * Control the MAC
187 *
188 * The MAC filter table is managed by the hypervisor, the guest should assume
189 * the size is infinite. Filtering should be considered non-perfect, ie. based
190 * on hypervisor resources, the guest may received packets from sources not
191 * specified in the filter list.
192 *
193 * In addition to the class/cmd header, the TABLE_SET command requires two
194 * out scatterlists. Each contains a 4 byte count of entries followed by a
195 * concatenated byte stream of the ETH_ALEN MAC addresses. The first sg list
196 * contains unicast addresses, the second is for multicast. This functionality
197 * is present if the VIRTIO_NET_F_CTRL_RX feature is available.
198 *
199 * The ADDR_SET command requests one out scatterlist, it contains a 6 bytes MAC
200 * address. This functionality is present if the VIRTIO_NET_F_CTRL_MAC_ADDR
201 * feature is available.
202 */
203struct __packed virtio_net_ctrl_mac {
204 __virtio32 entries;
205 __u8 macs[][ETH_ALEN];
206};
207
208#define VIRTIO_NET_CTRL_MAC 1
209#define VIRTIO_NET_CTRL_MAC_TABLE_SET 0
210#define VIRTIO_NET_CTRL_MAC_ADDR_SET 1
211
212/*
213 * Control VLAN filtering
214 *
215 * The VLAN filter table is controlled via a simple ADD/DEL interface. VLAN IDs
216 * not added may be filterd by the hypervisor. Del is the opposite of add. Both
217 * commands expect an out entry containing a 2 byte VLAN ID. VLAN filterting is
218 * available with the VIRTIO_NET_F_CTRL_VLAN feature bit.
219 */
220#define VIRTIO_NET_CTRL_VLAN 2
221#define VIRTIO_NET_CTRL_VLAN_ADD 0
222#define VIRTIO_NET_CTRL_VLAN_DEL 1
223
224/*
225 * Control link announce acknowledgment
226 *
227 * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that driver has
228 * recevied the notification; device would clear the VIRTIO_NET_S_ANNOUNCE bit
229 * in the status field after it receives this command.
230 */
231#define VIRTIO_NET_CTRL_ANNOUNCE 3
232#define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0
233
234/*
235 * Control receive flow steering
236 *
237 * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET enables receive flow steering,
238 * specifying the number of the transmit and receive queues that will be used.
239 * After the command is consumed and acked by the device, the device will not
240 * steer new packets on receive virtqueues other than specified nor read from
241 * transmit virtqueues other than specified. Accordingly, driver should not
242 * transmit new packets on virtqueues other than specified.
243 */
244struct virtio_net_ctrl_mq {
245 __virtio16 virtqueue_pairs;
246};
247
248#define VIRTIO_NET_CTRL_MQ 4
249#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0
250#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1
251#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000
252
253/*
254 * Control network offloads
255 *
256 * Reconfigures the network offloads that guest can handle.
257 *
258 * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit.
259 *
260 * Command data format matches the feature bit mask exactly.
261 *
262 * See VIRTIO_NET_F_GUEST_* for the list of offloads
263 * that can be enabled/disabled.
264 */
265#define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5
266#define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0
267
268#endif /* _LINUX_VIRTIO_NET_H */
diff --git a/drivers/virtio/virtio_pci.h b/drivers/virtio/virtio_pci.h
new file mode 100644
index 0000000000..cc753ed7b3
--- /dev/null
+++ b/drivers/virtio/virtio_pci.h
@@ -0,0 +1,173 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * From Linux kernel include/uapi/linux/virtio_pci.h
6 */
7
8#ifndef _LINUX_VIRTIO_PCI_H
9#define _LINUX_VIRTIO_PCI_H
10
11#ifndef VIRTIO_PCI_NO_LEGACY
12
13/* A 32-bit r/o bitmask of the features supported by the host */
14#define VIRTIO_PCI_HOST_FEATURES 0
15
16/* A 32-bit r/w bitmask of features activated by the guest */
17#define VIRTIO_PCI_GUEST_FEATURES 4
18
19/* A 32-bit r/w PFN for the currently selected queue */
20#define VIRTIO_PCI_QUEUE_PFN 8
21
22/* A 16-bit r/o queue size for the currently selected queue */
23#define VIRTIO_PCI_QUEUE_NUM 12
24
25/* A 16-bit r/w queue selector */
26#define VIRTIO_PCI_QUEUE_SEL 14
27
28/* A 16-bit r/w queue notifier */
29#define VIRTIO_PCI_QUEUE_NOTIFY 16
30
31/* An 8-bit device status register */
32#define VIRTIO_PCI_STATUS 18
33
34/*
35 * An 8-bit r/o interrupt status register. Reading the value will return the
36 * current contents of the ISR and will also clear it. This is effectively
37 * a read-and-acknowledge.
38 */
39#define VIRTIO_PCI_ISR 19
40
41/* MSI-X registers: only enabled if MSI-X is enabled */
42
43/* A 16-bit vector for configuration changes */
44#define VIRTIO_MSI_CONFIG_VECTOR 20
45/* A 16-bit vector for selected queue notifications */
46#define VIRTIO_MSI_QUEUE_VECTOR 22
47
48/*
49 * The remaining space is defined by each driver as the per-driver
50 * configuration space
51 */
52#define VIRTIO_PCI_CONFIG_OFF(msix) ((msix) ? 24 : 20)
53
54/* Virtio ABI version, this must match exactly */
55#define VIRTIO_PCI_ABI_VERSION 0
56
57/*
58 * How many bits to shift physical queue address written to QUEUE_PFN.
59 * 12 is historical, and due to x86 page size.
60 */
61#define VIRTIO_PCI_QUEUE_ADDR_SHIFT 12
62
63/*
64 * The alignment to use between consumer and producer parts of vring.
65 * x86 pagesize again.
66 */
67#define VIRTIO_PCI_VRING_ALIGN 4096
68
69#endif /* VIRTIO_PCI_NO_LEGACY */
70
71/* The bit of the ISR which indicates a device configuration change */
72#define VIRTIO_PCI_ISR_CONFIG 0x2
73/* Vector value used to disable MSI for queue */
74#define VIRTIO_MSI_NO_VECTOR 0xffff
75
76#ifndef VIRTIO_PCI_NO_MODERN
77
78/* IDs for different capabilities. Must all exist. */
79
80/* Common configuration */
81#define VIRTIO_PCI_CAP_COMMON_CFG 1
82/* Notifications */
83#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
84/* ISR access */
85#define VIRTIO_PCI_CAP_ISR_CFG 3
86/* Device specific configuration */
87#define VIRTIO_PCI_CAP_DEVICE_CFG 4
88/* PCI configuration access */
89#define VIRTIO_PCI_CAP_PCI_CFG 5
90
91/* This is the PCI capability header: */
92struct virtio_pci_cap {
93 __u8 cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
94 __u8 cap_next; /* Generic PCI field: next ptr */
95 __u8 cap_len; /* Generic PCI field: capability length */
96 __u8 cfg_type; /* Identifies the structure */
97 __u8 bar; /* Where to find it */
98 __u8 padding[3]; /* Pad to full dword */
99 __le32 offset; /* Offset within bar */
100 __le32 length; /* Length of the structure, in bytes */
101};
102
103struct virtio_pci_notify_cap {
104 struct virtio_pci_cap cap;
105 __le32 notify_off_multiplier; /* Multiplier for queue_notify_off */
106};
107
108/* Fields in VIRTIO_PCI_CAP_COMMON_CFG: */
109struct virtio_pci_common_cfg {
110 /* About the whole device */
111 __le32 device_feature_select; /* read-write */
112 __le32 device_feature; /* read-only */
113 __le32 guest_feature_select; /* read-write */
114 __le32 guest_feature; /* read-write */
115 __le16 msix_config; /* read-write */
116 __le16 num_queues; /* read-only */
117 __u8 device_status; /* read-write */
118 __u8 config_generation; /* read-only */
119
120 /* About a specific virtqueue */
121 __le16 queue_select; /* read-write */
122 __le16 queue_size; /* read-write, power of 2 */
123 __le16 queue_msix_vector; /* read-write */
124 __le16 queue_enable; /* read-write */
125 __le16 queue_notify_off; /* read-only */
126 __le32 queue_desc_lo; /* read-write */
127 __le32 queue_desc_hi; /* read-write */
128 __le32 queue_avail_lo; /* read-write */
129 __le32 queue_avail_hi; /* read-write */
130 __le32 queue_used_lo; /* read-write */
131 __le32 queue_used_hi; /* read-write */
132};
133
134/* Fields in VIRTIO_PCI_CAP_PCI_CFG: */
135struct virtio_pci_cfg_cap {
136 struct virtio_pci_cap cap;
137 __u8 pci_cfg_data[4]; /* Data for BAR access */
138};
139
140/* Macro versions of offsets for the Old Timers! */
141#define VIRTIO_PCI_CAP_VNDR 0
142#define VIRTIO_PCI_CAP_NEXT 1
143#define VIRTIO_PCI_CAP_LEN 2
144#define VIRTIO_PCI_CAP_CFG_TYPE 3
145#define VIRTIO_PCI_CAP_BAR 4
146#define VIRTIO_PCI_CAP_OFFSET 8
147#define VIRTIO_PCI_CAP_LENGTH 12
148
149#define VIRTIO_PCI_NOTIFY_CAP_MULT 16
150
151#define VIRTIO_PCI_COMMON_DFSELECT 0
152#define VIRTIO_PCI_COMMON_DF 4
153#define VIRTIO_PCI_COMMON_GFSELECT 8
154#define VIRTIO_PCI_COMMON_GF 12
155#define VIRTIO_PCI_COMMON_MSIX 16
156#define VIRTIO_PCI_COMMON_NUMQ 18
157#define VIRTIO_PCI_COMMON_STATUS 20
158#define VIRTIO_PCI_COMMON_CFGGENERATION 21
159#define VIRTIO_PCI_COMMON_Q_SELECT 22
160#define VIRTIO_PCI_COMMON_Q_SIZE 24
161#define VIRTIO_PCI_COMMON_Q_MSIX 26
162#define VIRTIO_PCI_COMMON_Q_ENABLE 28
163#define VIRTIO_PCI_COMMON_Q_NOFF 30
164#define VIRTIO_PCI_COMMON_Q_DESCLO 32
165#define VIRTIO_PCI_COMMON_Q_DESCHI 36
166#define VIRTIO_PCI_COMMON_Q_AVAILLO 40
167#define VIRTIO_PCI_COMMON_Q_AVAILHI 44
168#define VIRTIO_PCI_COMMON_Q_USEDLO 48
169#define VIRTIO_PCI_COMMON_Q_USEDHI 52
170
171#endif /* VIRTIO_PCI_NO_MODERN */
172
173#endif /* _LINUX_VIRTIO_PCI_H */
diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c
new file mode 100644
index 0000000000..08764ee6f2
--- /dev/null
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -0,0 +1,421 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * VirtIO PCI bus transport driver
6 * Ported from Linux drivers/virtio/virtio_pci*.c
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <virtio_types.h>
12#include <virtio.h>
13#include <virtio_ring.h>
14#include <dm/device.h>
15#include <linux/compat.h>
16#include <linux/io.h>
17#include "virtio_pci.h"
18
19#define VIRTIO_PCI_DRV_NAME "virtio-pci.l"
20
21/* PCI device ID in the range 0x1000 to 0x103f */
22#define VIRTIO_PCI_VENDOR_ID 0x1af4
23#define VIRTIO_PCI_DEVICE_ID00 0x1000
24#define VIRTIO_PCI_DEVICE_ID01 0x1001
25#define VIRTIO_PCI_DEVICE_ID02 0x1002
26#define VIRTIO_PCI_DEVICE_ID03 0x1003
27#define VIRTIO_PCI_DEVICE_ID04 0x1004
28#define VIRTIO_PCI_DEVICE_ID05 0x1005
29#define VIRTIO_PCI_DEVICE_ID06 0x1006
30#define VIRTIO_PCI_DEVICE_ID07 0x1007
31#define VIRTIO_PCI_DEVICE_ID08 0x1008
32#define VIRTIO_PCI_DEVICE_ID09 0x1009
33#define VIRTIO_PCI_DEVICE_ID0A 0x100a
34#define VIRTIO_PCI_DEVICE_ID0B 0x100b
35#define VIRTIO_PCI_DEVICE_ID0C 0x100c
36#define VIRTIO_PCI_DEVICE_ID0D 0x100d
37#define VIRTIO_PCI_DEVICE_ID0E 0x100e
38#define VIRTIO_PCI_DEVICE_ID0F 0x100f
39#define VIRTIO_PCI_DEVICE_ID10 0x1010
40#define VIRTIO_PCI_DEVICE_ID11 0x1011
41#define VIRTIO_PCI_DEVICE_ID12 0x1012
42#define VIRTIO_PCI_DEVICE_ID13 0x1013
43#define VIRTIO_PCI_DEVICE_ID14 0x1014
44#define VIRTIO_PCI_DEVICE_ID15 0x1015
45#define VIRTIO_PCI_DEVICE_ID16 0x1016
46#define VIRTIO_PCI_DEVICE_ID17 0x1017
47#define VIRTIO_PCI_DEVICE_ID18 0x1018
48#define VIRTIO_PCI_DEVICE_ID19 0x1019
49#define VIRTIO_PCI_DEVICE_ID1A 0x101a
50#define VIRTIO_PCI_DEVICE_ID1B 0x101b
51#define VIRTIO_PCI_DEVICE_ID1C 0x101c
52#define VIRTIO_PCI_DEVICE_ID1D 0x101d
53#define VIRTIO_PCI_DEVICE_ID1E 0x101e
54#define VIRTIO_PCI_DEVICE_ID1F 0x101f
55#define VIRTIO_PCI_DEVICE_ID20 0x1020
56#define VIRTIO_PCI_DEVICE_ID21 0x1021
57#define VIRTIO_PCI_DEVICE_ID22 0x1022
58#define VIRTIO_PCI_DEVICE_ID23 0x1023
59#define VIRTIO_PCI_DEVICE_ID24 0x1024
60#define VIRTIO_PCI_DEVICE_ID25 0x1025
61#define VIRTIO_PCI_DEVICE_ID26 0x1026
62#define VIRTIO_PCI_DEVICE_ID27 0x1027
63#define VIRTIO_PCI_DEVICE_ID28 0x1028
64#define VIRTIO_PCI_DEVICE_ID29 0x1029
65#define VIRTIO_PCI_DEVICE_ID2A 0x102a
66#define VIRTIO_PCI_DEVICE_ID2B 0x102b
67#define VIRTIO_PCI_DEVICE_ID2C 0x102c
68#define VIRTIO_PCI_DEVICE_ID2D 0x102d
69#define VIRTIO_PCI_DEVICE_ID2E 0x102e
70#define VIRTIO_PCI_DEVICE_ID2F 0x102f
71#define VIRTIO_PCI_DEVICE_ID30 0x1030
72#define VIRTIO_PCI_DEVICE_ID31 0x1031
73#define VIRTIO_PCI_DEVICE_ID32 0x1032
74#define VIRTIO_PCI_DEVICE_ID33 0x1033
75#define VIRTIO_PCI_DEVICE_ID34 0x1034
76#define VIRTIO_PCI_DEVICE_ID35 0x1035
77#define VIRTIO_PCI_DEVICE_ID36 0x1036
78#define VIRTIO_PCI_DEVICE_ID37 0x1037
79#define VIRTIO_PCI_DEVICE_ID38 0x1038
80#define VIRTIO_PCI_DEVICE_ID39 0x1039
81#define VIRTIO_PCI_DEVICE_ID3A 0x103a
82#define VIRTIO_PCI_DEVICE_ID3B 0x103b
83#define VIRTIO_PCI_DEVICE_ID3C 0x103c
84#define VIRTIO_PCI_DEVICE_ID3D 0x103d
85#define VIRTIO_PCI_DEVICE_ID3E 0x103e
86#define VIRTIO_PCI_DEVICE_ID3F 0x103f
87
88/**
89 * virtio pci transport driver private data
90 *
91 * @ioaddr: pci transport device register base
92 * @version: pci transport device version
93 */
94struct virtio_pci_priv {
95 void __iomem *ioaddr;
96};
97
98static int virtio_pci_get_config(struct udevice *udev, unsigned int offset,
99 void *buf, unsigned int len)
100{
101 struct virtio_pci_priv *priv = dev_get_priv(udev);
102 void __iomem *ioaddr = priv->ioaddr + VIRTIO_PCI_CONFIG_OFF(false);
103 u8 *ptr = buf;
104 int i;
105
106 for (i = 0; i < len; i++)
107 ptr[i] = ioread8(ioaddr + i);
108
109 return 0;
110}
111
112static int virtio_pci_set_config(struct udevice *udev, unsigned int offset,
113 const void *buf, unsigned int len)
114{
115 struct virtio_pci_priv *priv = dev_get_priv(udev);
116 void __iomem *ioaddr = priv->ioaddr + VIRTIO_PCI_CONFIG_OFF(false);
117 const u8 *ptr = buf;
118 int i;
119
120 for (i = 0; i < len; i++)
121 iowrite8(ptr[i], ioaddr + i);
122
123 return 0;
124}
125
126static int virtio_pci_get_status(struct udevice *udev, u8 *status)
127{
128 struct virtio_pci_priv *priv = dev_get_priv(udev);
129
130 *status = ioread8(priv->ioaddr + VIRTIO_PCI_STATUS);
131
132 return 0;
133}
134
135static int virtio_pci_set_status(struct udevice *udev, u8 status)
136{
137 struct virtio_pci_priv *priv = dev_get_priv(udev);
138
139 /* We should never be setting status to 0 */
140 WARN_ON(status == 0);
141
142 iowrite8(status, priv->ioaddr + VIRTIO_PCI_STATUS);
143
144 return 0;
145}
146
147static int virtio_pci_reset(struct udevice *udev)
148{
149 struct virtio_pci_priv *priv = dev_get_priv(udev);
150
151 /* 0 status means a reset */
152 iowrite8(0, priv->ioaddr + VIRTIO_PCI_STATUS);
153
154 /*
155 * Flush out the status write, and flush in device writes,
156 * including MSI-X interrupts, if any.
157 */
158 ioread8(priv->ioaddr + VIRTIO_PCI_STATUS);
159
160 return 0;
161}
162
163static int virtio_pci_get_features(struct udevice *udev, u64 *features)
164{
165 struct virtio_pci_priv *priv = dev_get_priv(udev);
166
167 /*
168 * When someone needs more than 32 feature bits, we'll need to
169 * steal a bit to indicate that the rest are somewhere else.
170 */
171 *features = ioread32(priv->ioaddr + VIRTIO_PCI_HOST_FEATURES);
172
173 return 0;
174}
175
176static int virtio_pci_set_features(struct udevice *udev)
177{
178 struct virtio_pci_priv *priv = dev_get_priv(udev);
179 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
180
181 /* Make sure we don't have any features > 32 bits! */
182 WARN_ON((u32)uc_priv->features != uc_priv->features);
183
184 /* We only support 32 feature bits */
185 iowrite32(uc_priv->features, priv->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
186
187 return 0;
188}
189
190static struct virtqueue *virtio_pci_setup_vq(struct udevice *udev,
191 unsigned int index)
192{
193 struct virtio_pci_priv *priv = dev_get_priv(udev);
194 struct virtqueue *vq;
195 unsigned int num;
196 int err;
197
198 /* Select the queue we're interested in */
199 iowrite16(index, priv->ioaddr + VIRTIO_PCI_QUEUE_SEL);
200
201 /* Check if queue is either not available or already active */
202 num = ioread16(priv->ioaddr + VIRTIO_PCI_QUEUE_NUM);
203 if (!num || ioread32(priv->ioaddr + VIRTIO_PCI_QUEUE_PFN)) {
204 err = -ENOENT;
205 goto error_available;
206 }
207
208 /* Create the vring */
209 vq = vring_create_virtqueue(index, num, VIRTIO_PCI_VRING_ALIGN, udev);
210 if (!vq) {
211 err = -ENOMEM;
212 goto error_available;
213 }
214
215 /* Activate the queue */
216 iowrite32(virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
217 priv->ioaddr + VIRTIO_PCI_QUEUE_PFN);
218
219 return vq;
220
221error_available:
222 return ERR_PTR(err);
223}
224
225static void virtio_pci_del_vq(struct virtqueue *vq)
226{
227 struct virtio_pci_priv *priv = dev_get_priv(vq->vdev);
228 unsigned int index = vq->index;
229
230 iowrite16(index, priv->ioaddr + VIRTIO_PCI_QUEUE_SEL);
231
232 /* Select and deactivate the queue */
233 iowrite32(0, priv->ioaddr + VIRTIO_PCI_QUEUE_PFN);
234
235 vring_del_virtqueue(vq);
236}
237
238static int virtio_pci_del_vqs(struct udevice *udev)
239{
240 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
241 struct virtqueue *vq, *n;
242
243 list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
244 virtio_pci_del_vq(vq);
245
246 return 0;
247}
248
249static int virtio_pci_find_vqs(struct udevice *udev, unsigned int nvqs,
250 struct virtqueue *vqs[])
251{
252 int i;
253
254 for (i = 0; i < nvqs; ++i) {
255 vqs[i] = virtio_pci_setup_vq(udev, i);
256 if (IS_ERR(vqs[i])) {
257 virtio_pci_del_vqs(udev);
258 return PTR_ERR(vqs[i]);
259 }
260 }
261
262 return 0;
263}
264
265static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq)
266{
267 struct virtio_pci_priv *priv = dev_get_priv(udev);
268
269 /*
270 * We write the queue's selector into the notification register
271 * to signal the other end
272 */
273 iowrite16(vq->index, priv->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
274
275 return 0;
276}
277
278static int virtio_pci_bind(struct udevice *udev)
279{
280 static int num_devs;
281 char name[20];
282
283 /* Create a unique device name for PCI type devices */
284 sprintf(name, "%s#%u", VIRTIO_PCI_DRV_NAME, num_devs++);
285 device_set_name(udev, name);
286
287 return 0;
288}
289
290static int virtio_pci_probe(struct udevice *udev)
291{
292 struct pci_child_platdata *pplat = dev_get_parent_platdata(udev);
293 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
294 struct virtio_pci_priv *priv = dev_get_priv(udev);
295 u16 subvendor, subdevice;
296 u8 revision;
297
298 /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
299 if (pplat->device < 0x1000 || pplat->device > 0x103f)
300 return -ENODEV;
301
302 /* Transitional devices must have a PCI revision ID of 0 */
303 dm_pci_read_config8(udev, PCI_REVISION_ID, &revision);
304 if (revision != VIRTIO_PCI_ABI_VERSION) {
305 printf("(%s): virtio_pci expected ABI version %d, got %d\n",
306 udev->name, VIRTIO_PCI_ABI_VERSION, revision);
307 return -ENODEV;
308 }
309
310 /*
311 * Transitional devices must have the PCI subsystem device ID matching
312 * the virtio device ID
313 */
314 dm_pci_read_config16(udev, PCI_SUBSYSTEM_ID, &subdevice);
315 dm_pci_read_config16(udev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
316 uc_priv->device = subdevice;
317 uc_priv->vendor = subvendor;
318
319 priv->ioaddr = dm_pci_map_bar(udev, PCI_BASE_ADDRESS_0, PCI_REGION_IO);
320 if (!priv->ioaddr)
321 return -ENXIO;
322 debug("(%s): virtio legacy device reg base %04lx\n",
323 udev->name, (ulong)priv->ioaddr);
324
325 debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
326 uc_priv->device, uc_priv->vendor, revision);
327
328 return 0;
329}
330
331static const struct dm_virtio_ops virtio_pci_ops = {
332 .get_config = virtio_pci_get_config,
333 .set_config = virtio_pci_set_config,
334 .get_status = virtio_pci_get_status,
335 .set_status = virtio_pci_set_status,
336 .reset = virtio_pci_reset,
337 .get_features = virtio_pci_get_features,
338 .set_features = virtio_pci_set_features,
339 .find_vqs = virtio_pci_find_vqs,
340 .del_vqs = virtio_pci_del_vqs,
341 .notify = virtio_pci_notify,
342};
343
344U_BOOT_DRIVER(virtio_pci_legacy) = {
345 .name = VIRTIO_PCI_DRV_NAME,
346 .id = UCLASS_VIRTIO,
347 .ops = &virtio_pci_ops,
348 .bind = virtio_pci_bind,
349 .probe = virtio_pci_probe,
350 .priv_auto_alloc_size = sizeof(struct virtio_pci_priv),
351};
352
353static struct pci_device_id virtio_pci_supported[] = {
354 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID00) },
355 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID01) },
356 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID02) },
357 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID03) },
358 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID04) },
359 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID05) },
360 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID06) },
361 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID07) },
362 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID08) },
363 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID09) },
364 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0A) },
365 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0B) },
366 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0C) },
367 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0D) },
368 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0E) },
369 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0F) },
370 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID10) },
371 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID11) },
372 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID12) },
373 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID13) },
374 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID14) },
375 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID15) },
376 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID16) },
377 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID17) },
378 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID18) },
379 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID19) },
380 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1A) },
381 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1B) },
382 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1C) },
383 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1D) },
384 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1E) },
385 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1F) },
386 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID20) },
387 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID21) },
388 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID22) },
389 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID23) },
390 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID24) },
391 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID25) },
392 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID26) },
393 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID27) },
394 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID28) },
395 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID29) },
396 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2A) },
397 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2B) },
398 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2C) },
399 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2D) },
400 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2E) },
401 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2F) },
402 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID30) },
403 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID31) },
404 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID32) },
405 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID33) },
406 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID34) },
407 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID35) },
408 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID36) },
409 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID37) },
410 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID38) },
411 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID39) },
412 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3A) },
413 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3B) },
414 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3C) },
415 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3D) },
416 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3E) },
417 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3F) },
418 {},
419};
420
421U_BOOT_PCI_DEVICE(virtio_pci_legacy, virtio_pci_supported);
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
new file mode 100644
index 0000000000..da76aea8d1
--- /dev/null
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -0,0 +1,609 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * VirtIO PCI bus transport driver
6 * Ported from Linux drivers/virtio/virtio_pci*.c
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <virtio_types.h>
12#include <virtio.h>
13#include <virtio_ring.h>
14#include <dm/device.h>
15#include <linux/compat.h>
16#include <linux/io.h>
17#include "virtio_pci.h"
18
19#define VIRTIO_PCI_DRV_NAME "virtio-pci.m"
20
21/* PCI device ID in the range 0x1040 to 0x107f */
22#define VIRTIO_PCI_VENDOR_ID 0x1af4
23#define VIRTIO_PCI_DEVICE_ID00 0x1040
24#define VIRTIO_PCI_DEVICE_ID01 0x1041
25#define VIRTIO_PCI_DEVICE_ID02 0x1042
26#define VIRTIO_PCI_DEVICE_ID03 0x1043
27#define VIRTIO_PCI_DEVICE_ID04 0x1044
28#define VIRTIO_PCI_DEVICE_ID05 0x1045
29#define VIRTIO_PCI_DEVICE_ID06 0x1046
30#define VIRTIO_PCI_DEVICE_ID07 0x1047
31#define VIRTIO_PCI_DEVICE_ID08 0x1048
32#define VIRTIO_PCI_DEVICE_ID09 0x1049
33#define VIRTIO_PCI_DEVICE_ID0A 0x104a
34#define VIRTIO_PCI_DEVICE_ID0B 0x104b
35#define VIRTIO_PCI_DEVICE_ID0C 0x104c
36#define VIRTIO_PCI_DEVICE_ID0D 0x104d
37#define VIRTIO_PCI_DEVICE_ID0E 0x104e
38#define VIRTIO_PCI_DEVICE_ID0F 0x104f
39#define VIRTIO_PCI_DEVICE_ID10 0x1050
40#define VIRTIO_PCI_DEVICE_ID11 0x1051
41#define VIRTIO_PCI_DEVICE_ID12 0x1052
42#define VIRTIO_PCI_DEVICE_ID13 0x1053
43#define VIRTIO_PCI_DEVICE_ID14 0x1054
44#define VIRTIO_PCI_DEVICE_ID15 0x1055
45#define VIRTIO_PCI_DEVICE_ID16 0x1056
46#define VIRTIO_PCI_DEVICE_ID17 0x1057
47#define VIRTIO_PCI_DEVICE_ID18 0x1058
48#define VIRTIO_PCI_DEVICE_ID19 0x1059
49#define VIRTIO_PCI_DEVICE_ID1A 0x105a
50#define VIRTIO_PCI_DEVICE_ID1B 0x105b
51#define VIRTIO_PCI_DEVICE_ID1C 0x105c
52#define VIRTIO_PCI_DEVICE_ID1D 0x105d
53#define VIRTIO_PCI_DEVICE_ID1E 0x105e
54#define VIRTIO_PCI_DEVICE_ID1F 0x105f
55#define VIRTIO_PCI_DEVICE_ID20 0x1060
56#define VIRTIO_PCI_DEVICE_ID21 0x1061
57#define VIRTIO_PCI_DEVICE_ID22 0x1062
58#define VIRTIO_PCI_DEVICE_ID23 0x1063
59#define VIRTIO_PCI_DEVICE_ID24 0x1064
60#define VIRTIO_PCI_DEVICE_ID25 0x1065
61#define VIRTIO_PCI_DEVICE_ID26 0x1066
62#define VIRTIO_PCI_DEVICE_ID27 0x1067
63#define VIRTIO_PCI_DEVICE_ID28 0x1068
64#define VIRTIO_PCI_DEVICE_ID29 0x1069
65#define VIRTIO_PCI_DEVICE_ID2A 0x106a
66#define VIRTIO_PCI_DEVICE_ID2B 0x106b
67#define VIRTIO_PCI_DEVICE_ID2C 0x106c
68#define VIRTIO_PCI_DEVICE_ID2D 0x106d
69#define VIRTIO_PCI_DEVICE_ID2E 0x106e
70#define VIRTIO_PCI_DEVICE_ID2F 0x106f
71#define VIRTIO_PCI_DEVICE_ID30 0x1070
72#define VIRTIO_PCI_DEVICE_ID31 0x1071
73#define VIRTIO_PCI_DEVICE_ID32 0x1072
74#define VIRTIO_PCI_DEVICE_ID33 0x1073
75#define VIRTIO_PCI_DEVICE_ID34 0x1074
76#define VIRTIO_PCI_DEVICE_ID35 0x1075
77#define VIRTIO_PCI_DEVICE_ID36 0x1076
78#define VIRTIO_PCI_DEVICE_ID37 0x1077
79#define VIRTIO_PCI_DEVICE_ID38 0x1078
80#define VIRTIO_PCI_DEVICE_ID39 0x1079
81#define VIRTIO_PCI_DEVICE_ID3A 0x107a
82#define VIRTIO_PCI_DEVICE_ID3B 0x107b
83#define VIRTIO_PCI_DEVICE_ID3C 0x107c
84#define VIRTIO_PCI_DEVICE_ID3D 0x107d
85#define VIRTIO_PCI_DEVICE_ID3E 0x107e
86#define VIRTIO_PCI_DEVICE_ID3F 0x107f
87
88/**
89 * virtio pci transport driver private data
90 *
91 * @common: pci transport device common register block base
92 * @notify_base: pci transport device notify register block base
93 * @device: pci transport device device-specific register block base
94 * @device_len: pci transport device device-specific register block length
95 * @notify_offset_multiplier: multiply queue_notify_off by this value
96 */
97struct virtio_pci_priv {
98 struct virtio_pci_common_cfg __iomem *common;
99 void __iomem *notify_base;
100 void __iomem *device;
101 u32 device_len;
102 u32 notify_offset_multiplier;
103};
104
105static int virtio_pci_get_config(struct udevice *udev, unsigned int offset,
106 void *buf, unsigned int len)
107{
108 struct virtio_pci_priv *priv = dev_get_priv(udev);
109 u8 b;
110 __le16 w;
111 __le32 l;
112
113 WARN_ON(offset + len > priv->device_len);
114
115 switch (len) {
116 case 1:
117 b = ioread8(priv->device + offset);
118 memcpy(buf, &b, sizeof(b));
119 break;
120 case 2:
121 w = cpu_to_le16(ioread16(priv->device + offset));
122 memcpy(buf, &w, sizeof(w));
123 break;
124 case 4:
125 l = cpu_to_le32(ioread32(priv->device + offset));
126 memcpy(buf, &l, sizeof(l));
127 break;
128 case 8:
129 l = cpu_to_le32(ioread32(priv->device + offset));
130 memcpy(buf, &l, sizeof(l));
131 l = cpu_to_le32(ioread32(priv->device + offset + sizeof(l)));
132 memcpy(buf + sizeof(l), &l, sizeof(l));
133 break;
134 default:
135 WARN_ON(true);
136 }
137
138 return 0;
139}
140
141static int virtio_pci_set_config(struct udevice *udev, unsigned int offset,
142 const void *buf, unsigned int len)
143{
144 struct virtio_pci_priv *priv = dev_get_priv(udev);
145 u8 b;
146 __le16 w;
147 __le32 l;
148
149 WARN_ON(offset + len > priv->device_len);
150
151 switch (len) {
152 case 1:
153 memcpy(&b, buf, sizeof(b));
154 iowrite8(b, priv->device + offset);
155 break;
156 case 2:
157 memcpy(&w, buf, sizeof(w));
158 iowrite16(le16_to_cpu(w), priv->device + offset);
159 break;
160 case 4:
161 memcpy(&l, buf, sizeof(l));
162 iowrite32(le32_to_cpu(l), priv->device + offset);
163 break;
164 case 8:
165 memcpy(&l, buf, sizeof(l));
166 iowrite32(le32_to_cpu(l), priv->device + offset);
167 memcpy(&l, buf + sizeof(l), sizeof(l));
168 iowrite32(le32_to_cpu(l), priv->device + offset + sizeof(l));
169 break;
170 default:
171 WARN_ON(true);
172 }
173
174 return 0;
175}
176
177static int virtio_pci_generation(struct udevice *udev, u32 *counter)
178{
179 struct virtio_pci_priv *priv = dev_get_priv(udev);
180
181 *counter = ioread8(&priv->common->config_generation);
182
183 return 0;
184}
185
186static int virtio_pci_get_status(struct udevice *udev, u8 *status)
187{
188 struct virtio_pci_priv *priv = dev_get_priv(udev);
189
190 *status = ioread8(&priv->common->device_status);
191
192 return 0;
193}
194
195static int virtio_pci_set_status(struct udevice *udev, u8 status)
196{
197 struct virtio_pci_priv *priv = dev_get_priv(udev);
198
199 /* We should never be setting status to 0 */
200 WARN_ON(status == 0);
201
202 iowrite8(status, &priv->common->device_status);
203
204 return 0;
205}
206
207static int virtio_pci_reset(struct udevice *udev)
208{
209 struct virtio_pci_priv *priv = dev_get_priv(udev);
210
211 /* 0 status means a reset */
212 iowrite8(0, &priv->common->device_status);
213
214 /*
215 * After writing 0 to device_status, the driver MUST wait for a read
216 * of device_status to return 0 before reinitializing the device.
217 * This will flush out the status write, and flush in device writes,
218 * including MSI-X interrupts, if any.
219 */
220 while (ioread8(&priv->common->device_status))
221 udelay(1000);
222
223 return 0;
224}
225
226static int virtio_pci_get_features(struct udevice *udev, u64 *features)
227{
228 struct virtio_pci_priv *priv = dev_get_priv(udev);
229
230 iowrite32(0, &priv->common->device_feature_select);
231 *features = ioread32(&priv->common->device_feature);
232 iowrite32(1, &priv->common->device_feature_select);
233 *features |= ((u64)ioread32(&priv->common->device_feature) << 32);
234
235 return 0;
236}
237
238static int virtio_pci_set_features(struct udevice *udev)
239{
240 struct virtio_pci_priv *priv = dev_get_priv(udev);
241 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
242
243 if (!__virtio_test_bit(udev, VIRTIO_F_VERSION_1)) {
244 debug("virtio: device uses modern interface but does not have VIRTIO_F_VERSION_1\n");
245 return -EINVAL;
246 }
247
248 iowrite32(0, &priv->common->guest_feature_select);
249 iowrite32((u32)uc_priv->features, &priv->common->guest_feature);
250 iowrite32(1, &priv->common->guest_feature_select);
251 iowrite32(uc_priv->features >> 32, &priv->common->guest_feature);
252
253 return 0;
254}
255
256static struct virtqueue *virtio_pci_setup_vq(struct udevice *udev,
257 unsigned int index)
258{
259 struct virtio_pci_priv *priv = dev_get_priv(udev);
260 struct virtio_pci_common_cfg __iomem *cfg = priv->common;
261 struct virtqueue *vq;
262 u16 num;
263 u64 addr;
264 int err;
265
266 if (index >= ioread16(&cfg->num_queues))
267 return ERR_PTR(-ENOENT);
268
269 /* Select the queue we're interested in */
270 iowrite16(index, &cfg->queue_select);
271
272 /* Check if queue is either not available or already active */
273 num = ioread16(&cfg->queue_size);
274 if (!num || ioread16(&cfg->queue_enable))
275 return ERR_PTR(-ENOENT);
276
277 if (num & (num - 1)) {
278 printf("(%s): bad queue size %u", udev->name, num);
279 return ERR_PTR(-EINVAL);
280 }
281
282 /* Create the vring */
283 vq = vring_create_virtqueue(index, num, VIRTIO_PCI_VRING_ALIGN, udev);
284 if (!vq) {
285 err = -ENOMEM;
286 goto error_available;
287 }
288
289 /* Activate the queue */
290 iowrite16(virtqueue_get_vring_size(vq), &cfg->queue_size);
291
292 addr = virtqueue_get_desc_addr(vq);
293 iowrite32((u32)addr, &cfg->queue_desc_lo);
294 iowrite32(addr >> 32, &cfg->queue_desc_hi);
295
296 addr = virtqueue_get_avail_addr(vq);
297 iowrite32((u32)addr, &cfg->queue_avail_lo);
298 iowrite32(addr >> 32, &cfg->queue_avail_hi);
299
300 addr = virtqueue_get_used_addr(vq);
301 iowrite32((u32)addr, &cfg->queue_used_lo);
302 iowrite32(addr >> 32, &cfg->queue_used_hi);
303
304 iowrite16(1, &cfg->queue_enable);
305
306 return vq;
307
308error_available:
309 return ERR_PTR(err);
310}
311
312static void virtio_pci_del_vq(struct virtqueue *vq)
313{
314 struct virtio_pci_priv *priv = dev_get_priv(vq->vdev);
315 unsigned int index = vq->index;
316
317 iowrite16(index, &priv->common->queue_select);
318
319 /* Select and deactivate the queue */
320 iowrite16(0, &priv->common->queue_enable);
321
322 vring_del_virtqueue(vq);
323}
324
325static int virtio_pci_del_vqs(struct udevice *udev)
326{
327 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
328 struct virtqueue *vq, *n;
329
330 list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
331 virtio_pci_del_vq(vq);
332
333 return 0;
334}
335
336static int virtio_pci_find_vqs(struct udevice *udev, unsigned int nvqs,
337 struct virtqueue *vqs[])
338{
339 int i;
340
341 for (i = 0; i < nvqs; ++i) {
342 vqs[i] = virtio_pci_setup_vq(udev, i);
343 if (IS_ERR(vqs[i])) {
344 virtio_pci_del_vqs(udev);
345 return PTR_ERR(vqs[i]);
346 }
347 }
348
349 return 0;
350}
351
352static int virtio_pci_notify(struct udevice *udev, struct virtqueue *vq)
353{
354 struct virtio_pci_priv *priv = dev_get_priv(udev);
355 u16 off;
356
357 /* Select the queue we're interested in */
358 iowrite16(vq->index, &priv->common->queue_select);
359
360 /* get offset of notification word for this vq */
361 off = ioread16(&priv->common->queue_notify_off);
362
363 /*
364 * We write the queue's selector into the notification register
365 * to signal the other end
366 */
367 iowrite16(vq->index,
368 priv->notify_base + off * priv->notify_offset_multiplier);
369
370 return 0;
371}
372
373/**
374 * virtio_pci_find_capability - walk capabilities to find device info
375 *
376 * @udev: the transport device
377 * @cfg_type: the VIRTIO_PCI_CAP_* value we seek
378 *
379 * @return offset of the configuration structure
380 */
381static int virtio_pci_find_capability(struct udevice *udev, u8 cfg_type)
382{
383 int pos;
384 int offset;
385 u8 type, bar;
386
387 for (pos = dm_pci_find_capability(udev, PCI_CAP_ID_VNDR);
388 pos > 0;
389 pos = dm_pci_find_next_capability(udev, pos, PCI_CAP_ID_VNDR)) {
390 offset = pos + offsetof(struct virtio_pci_cap, cfg_type);
391 dm_pci_read_config8(udev, offset, &type);
392 offset = pos + offsetof(struct virtio_pci_cap, bar);
393 dm_pci_read_config8(udev, offset, &bar);
394
395 /* Ignore structures with reserved BAR values */
396 if (bar > 0x5)
397 continue;
398
399 if (type == cfg_type)
400 return pos;
401 }
402
403 return 0;
404}
405
406/**
407 * virtio_pci_map_capability - map base address of the capability
408 *
409 * @udev: the transport device
410 * @off: offset of the configuration structure
411 *
412 * @return base address of the capability
413 */
414static void __iomem *virtio_pci_map_capability(struct udevice *udev, int off)
415{
416 u8 bar;
417 u32 offset;
418 ulong base;
419 void __iomem *p;
420
421 if (!off)
422 return NULL;
423
424 offset = off + offsetof(struct virtio_pci_cap, bar);
425 dm_pci_read_config8(udev, offset, &bar);
426 offset = off + offsetof(struct virtio_pci_cap, offset);
427 dm_pci_read_config32(udev, offset, &offset);
428
429 /*
430 * TODO: adding 64-bit BAR support
431 *
432 * Per spec, the BAR is permitted to be either 32-bit or 64-bit.
433 * For simplicity, only read the BAR address as 32-bit.
434 */
435 base = dm_pci_read_bar32(udev, bar);
436 p = (void __iomem *)base + offset;
437
438 return p;
439}
440
441static int virtio_pci_bind(struct udevice *udev)
442{
443 static int num_devs;
444 char name[20];
445
446 /* Create a unique device name */
447 sprintf(name, "%s#%u", VIRTIO_PCI_DRV_NAME, num_devs++);
448 device_set_name(udev, name);
449
450 return 0;
451}
452
453static int virtio_pci_probe(struct udevice *udev)
454{
455 struct pci_child_platdata *pplat = dev_get_parent_platdata(udev);
456 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
457 struct virtio_pci_priv *priv = dev_get_priv(udev);
458 u16 subvendor;
459 u8 revision;
460 int common, notify, device;
461 int offset;
462
463 /* We only own devices >= 0x1040 and <= 0x107f: leave the rest. */
464 if (pplat->device < 0x1040 || pplat->device > 0x107f)
465 return -ENODEV;
466
467 /* Transitional devices must not have a PCI revision ID of 0 */
468 dm_pci_read_config8(udev, PCI_REVISION_ID, &revision);
469
470 /* Modern devices: simply use PCI device id, but start from 0x1040. */
471 uc_priv->device = pplat->device - 0x1040;
472 dm_pci_read_config16(udev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor);
473 uc_priv->vendor = subvendor;
474
475 /* Check for a common config: if not, use legacy mode (bar 0) */
476 common = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_COMMON_CFG);
477 if (!common) {
478 printf("(%s): leaving for legacy driver\n", udev->name);
479 return -ENODEV;
480 }
481
482 /* If common is there, notify should be too */
483 notify = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_NOTIFY_CFG);
484 if (!notify) {
485 printf("(%s): missing capabilities %i/%i\n", udev->name,
486 common, notify);
487 return -EINVAL;
488 }
489
490 /*
491 * Device capability is only mandatory for devices that have
492 * device-specific configuration.
493 */
494 device = virtio_pci_find_capability(udev, VIRTIO_PCI_CAP_DEVICE_CFG);
495 if (device) {
496 offset = notify + offsetof(struct virtio_pci_cap, length);
497 dm_pci_read_config32(udev, offset, &priv->device_len);
498 }
499
500 /* Map configuration structures */
501 priv->common = virtio_pci_map_capability(udev, common);
502 priv->notify_base = virtio_pci_map_capability(udev, notify);
503 priv->device = virtio_pci_map_capability(udev, device);
504 debug("(%p): common @ %p, notify base @ %p, device @ %p\n",
505 udev, priv->common, priv->notify_base, priv->device);
506
507 /* Read notify_off_multiplier from config space */
508 offset = notify + offsetof(struct virtio_pci_notify_cap,
509 notify_off_multiplier);
510 dm_pci_read_config32(udev, offset, &priv->notify_offset_multiplier);
511
512 debug("(%s): device (%d) vendor (%08x) version (%d)\n", udev->name,
513 uc_priv->device, uc_priv->vendor, revision);
514
515 return 0;
516}
517
518static const struct dm_virtio_ops virtio_pci_ops = {
519 .get_config = virtio_pci_get_config,
520 .set_config = virtio_pci_set_config,
521 .generation = virtio_pci_generation,
522 .get_status = virtio_pci_get_status,
523 .set_status = virtio_pci_set_status,
524 .reset = virtio_pci_reset,
525 .get_features = virtio_pci_get_features,
526 .set_features = virtio_pci_set_features,
527 .find_vqs = virtio_pci_find_vqs,
528 .del_vqs = virtio_pci_del_vqs,
529 .notify = virtio_pci_notify,
530};
531
532U_BOOT_DRIVER(virtio_pci_modern) = {
533 .name = VIRTIO_PCI_DRV_NAME,
534 .id = UCLASS_VIRTIO,
535 .ops = &virtio_pci_ops,
536 .bind = virtio_pci_bind,
537 .probe = virtio_pci_probe,
538 .priv_auto_alloc_size = sizeof(struct virtio_pci_priv),
539};
540
541static struct pci_device_id virtio_pci_supported[] = {
542 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID00) },
543 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID01) },
544 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID02) },
545 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID03) },
546 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID04) },
547 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID05) },
548 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID06) },
549 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID07) },
550 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID08) },
551 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID09) },
552 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0A) },
553 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0B) },
554 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0C) },
555 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0D) },
556 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0E) },
557 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID0F) },
558 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID10) },
559 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID11) },
560 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID12) },
561 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID13) },
562 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID14) },
563 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID15) },
564 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID16) },
565 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID17) },
566 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID18) },
567 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID19) },
568 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1A) },
569 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1B) },
570 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1C) },
571 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1D) },
572 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1E) },
573 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID1F) },
574 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID20) },
575 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID21) },
576 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID22) },
577 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID23) },
578 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID24) },
579 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID25) },
580 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID26) },
581 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID27) },
582 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID28) },
583 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID29) },
584 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2A) },
585 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2B) },
586 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2C) },
587 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2D) },
588 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2E) },
589 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID2F) },
590 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID30) },
591 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID31) },
592 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID32) },
593 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID33) },
594 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID34) },
595 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID35) },
596 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID36) },
597 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID37) },
598 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID38) },
599 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID39) },
600 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3A) },
601 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3B) },
602 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3C) },
603 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3D) },
604 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3E) },
605 { PCI_DEVICE(VIRTIO_PCI_VENDOR_ID, VIRTIO_PCI_DEVICE_ID3F) },
606 {},
607};
608
609U_BOOT_PCI_DEVICE(virtio_pci_modern, virtio_pci_supported);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
new file mode 100644
index 0000000000..0eeb3501c2
--- /dev/null
+++ b/drivers/virtio/virtio_ring.c
@@ -0,0 +1,358 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * virtio ring implementation
7 */
8
9#include <common.h>
10#include <dm.h>
11#include <malloc.h>
12#include <virtio_types.h>
13#include <virtio.h>
14#include <virtio_ring.h>
15
16int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
17 unsigned int out_sgs, unsigned int in_sgs)
18{
19 struct vring_desc *desc;
20 unsigned int total_sg = out_sgs + in_sgs;
21 unsigned int i, n, avail, descs_used, uninitialized_var(prev);
22 int head;
23
24 WARN_ON(total_sg == 0);
25
26 head = vq->free_head;
27
28 desc = vq->vring.desc;
29 i = head;
30 descs_used = total_sg;
31
32 if (vq->num_free < descs_used) {
33 debug("Can't add buf len %i - avail = %i\n",
34 descs_used, vq->num_free);
35 /*
36 * FIXME: for historical reasons, we force a notify here if
37 * there are outgoing parts to the buffer. Presumably the
38 * host should service the ring ASAP.
39 */
40 if (out_sgs)
41 virtio_notify(vq->vdev, vq);
42 return -ENOSPC;
43 }
44
45 for (n = 0; n < out_sgs; n++) {
46 struct virtio_sg *sg = sgs[n];
47
48 desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
49 desc[i].addr = cpu_to_virtio64(vq->vdev, (u64)(size_t)sg->addr);
50 desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
51
52 prev = i;
53 i = virtio16_to_cpu(vq->vdev, desc[i].next);
54 }
55 for (; n < (out_sgs + in_sgs); n++) {
56 struct virtio_sg *sg = sgs[n];
57
58 desc[i].flags = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT |
59 VRING_DESC_F_WRITE);
60 desc[i].addr = cpu_to_virtio64(vq->vdev,
61 (u64)(uintptr_t)sg->addr);
62 desc[i].len = cpu_to_virtio32(vq->vdev, sg->length);
63
64 prev = i;
65 i = virtio16_to_cpu(vq->vdev, desc[i].next);
66 }
67 /* Last one doesn't continue */
68 desc[prev].flags &= cpu_to_virtio16(vq->vdev, ~VRING_DESC_F_NEXT);
69
70 /* We're using some buffers from the free list. */
71 vq->num_free -= descs_used;
72
73 /* Update free pointer */
74 vq->free_head = i;
75
76 /*
77 * Put entry in available array (but don't update avail->idx
78 * until they do sync).
79 */
80 avail = vq->avail_idx_shadow & (vq->vring.num - 1);
81 vq->vring.avail->ring[avail] = cpu_to_virtio16(vq->vdev, head);
82
83 /*
84 * Descriptors and available array need to be set before we expose the
85 * new available array entries.
86 */
87 virtio_wmb();
88 vq->avail_idx_shadow++;
89 vq->vring.avail->idx = cpu_to_virtio16(vq->vdev, vq->avail_idx_shadow);
90 vq->num_added++;
91
92 /*
93 * This is very unlikely, but theoretically possible.
94 * Kick just in case.
95 */
96 if (unlikely(vq->num_added == (1 << 16) - 1))
97 virtqueue_kick(vq);
98
99 return 0;
100}
101
102static bool virtqueue_kick_prepare(struct virtqueue *vq)
103{
104 u16 new, old;
105 bool needs_kick;
106
107 /*
108 * We need to expose available array entries before checking
109 * avail event.
110 */
111 virtio_mb();
112
113 old = vq->avail_idx_shadow - vq->num_added;
114 new = vq->avail_idx_shadow;
115 vq->num_added = 0;
116
117 if (vq->event) {
118 needs_kick = vring_need_event(virtio16_to_cpu(vq->vdev,
119 vring_avail_event(&vq->vring)), new, old);
120 } else {
121 needs_kick = !(vq->vring.used->flags & cpu_to_virtio16(vq->vdev,
122 VRING_USED_F_NO_NOTIFY));
123 }
124
125 return needs_kick;
126}
127
128void virtqueue_kick(struct virtqueue *vq)
129{
130 if (virtqueue_kick_prepare(vq))
131 virtio_notify(vq->vdev, vq);
132}
133
134static void detach_buf(struct virtqueue *vq, unsigned int head)
135{
136 unsigned int i;
137 __virtio16 nextflag = cpu_to_virtio16(vq->vdev, VRING_DESC_F_NEXT);
138
139 /* Put back on free list: unmap first-level descriptors and find end */
140 i = head;
141
142 while (vq->vring.desc[i].flags & nextflag) {
143 i = virtio16_to_cpu(vq->vdev, vq->vring.desc[i].next);
144 vq->num_free++;
145 }
146
147 vq->vring.desc[i].next = cpu_to_virtio16(vq->vdev, vq->free_head);
148 vq->free_head = head;
149
150 /* Plus final descriptor */
151 vq->num_free++;
152}
153
154static inline bool more_used(const struct virtqueue *vq)
155{
156 return vq->last_used_idx != virtio16_to_cpu(vq->vdev,
157 vq->vring.used->idx);
158}
159
160void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len)
161{
162 unsigned int i;
163 u16 last_used;
164
165 if (!more_used(vq)) {
166 debug("(%s.%d): No more buffers in queue\n",
167 vq->vdev->name, vq->index);
168 return NULL;
169 }
170
171 /* Only get used array entries after they have been exposed by host */
172 virtio_rmb();
173
174 last_used = (vq->last_used_idx & (vq->vring.num - 1));
175 i = virtio32_to_cpu(vq->vdev, vq->vring.used->ring[last_used].id);
176 if (len) {
177 *len = virtio32_to_cpu(vq->vdev,
178 vq->vring.used->ring[last_used].len);
179 debug("(%s.%d): last used idx %u with len %u\n",
180 vq->vdev->name, vq->index, i, *len);
181 }
182
183 if (unlikely(i >= vq->vring.num)) {
184 printf("(%s.%d): id %u out of range\n",
185 vq->vdev->name, vq->index, i);
186 return NULL;
187 }
188
189 detach_buf(vq, i);
190 vq->last_used_idx++;
191 /*
192 * If we expect an interrupt for the next entry, tell host
193 * by writing event index and flush out the write before
194 * the read in the next get_buf call.
195 */
196 if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT))
197 virtio_store_mb(&vring_used_event(&vq->vring),
198 cpu_to_virtio16(vq->vdev, vq->last_used_idx));
199
200 return (void *)(uintptr_t)virtio64_to_cpu(vq->vdev,
201 vq->vring.desc[i].addr);
202}
203
204static struct virtqueue *__vring_new_virtqueue(unsigned int index,
205 struct vring vring,
206 struct udevice *udev)
207{
208 unsigned int i;
209 struct virtqueue *vq;
210 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
211 struct udevice *vdev = uc_priv->vdev;
212
213 vq = malloc(sizeof(*vq));
214 if (!vq)
215 return NULL;
216
217 vq->vdev = vdev;
218 vq->index = index;
219 vq->num_free = vring.num;
220 vq->vring = vring;
221 vq->last_used_idx = 0;
222 vq->avail_flags_shadow = 0;
223 vq->avail_idx_shadow = 0;
224 vq->num_added = 0;
225 list_add_tail(&vq->list, &uc_priv->vqs);
226
227 vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
228
229 /* Tell other side not to bother us */
230 vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
231 if (!vq->event)
232 vq->vring.avail->flags = cpu_to_virtio16(vdev,
233 vq->avail_flags_shadow);
234
235 /* Put everything in free lists */
236 vq->free_head = 0;
237 for (i = 0; i < vring.num - 1; i++)
238 vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1);
239
240 return vq;
241}
242
243struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
244 unsigned int vring_align,
245 struct udevice *udev)
246{
247 struct virtqueue *vq;
248 void *queue = NULL;
249 struct vring vring;
250
251 /* We assume num is a power of 2 */
252 if (num & (num - 1)) {
253 printf("Bad virtqueue length %u\n", num);
254 return NULL;
255 }
256
257 /* TODO: allocate each queue chunk individually */
258 for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) {
259 queue = memalign(PAGE_SIZE, vring_size(num, vring_align));
260 if (queue)
261 break;
262 }
263
264 if (!num)
265 return NULL;
266
267 if (!queue) {
268 /* Try to get a single page. You are my only hope! */
269 queue = memalign(PAGE_SIZE, vring_size(num, vring_align));
270 }
271 if (!queue)
272 return NULL;
273
274 memset(queue, 0, vring_size(num, vring_align));
275 vring_init(&vring, num, queue, vring_align);
276
277 vq = __vring_new_virtqueue(index, vring, udev);
278 if (!vq) {
279 free(queue);
280 return NULL;
281 }
282 debug("(%s): created vring @ %p for vq @ %p with num %u\n", udev->name,
283 queue, vq, num);
284
285 return vq;
286}
287
288void vring_del_virtqueue(struct virtqueue *vq)
289{
290 free(vq->vring.desc);
291 list_del(&vq->list);
292 free(vq);
293}
294
295unsigned int virtqueue_get_vring_size(struct virtqueue *vq)
296{
297 return vq->vring.num;
298}
299
300ulong virtqueue_get_desc_addr(struct virtqueue *vq)
301{
302 return (ulong)vq->vring.desc;
303}
304
305ulong virtqueue_get_avail_addr(struct virtqueue *vq)
306{
307 return (ulong)vq->vring.desc +
308 ((char *)vq->vring.avail - (char *)vq->vring.desc);
309}
310
311ulong virtqueue_get_used_addr(struct virtqueue *vq)
312{
313 return (ulong)vq->vring.desc +
314 ((char *)vq->vring.used - (char *)vq->vring.desc);
315}
316
317bool virtqueue_poll(struct virtqueue *vq, u16 last_used_idx)
318{
319 virtio_mb();
320
321 return last_used_idx != virtio16_to_cpu(vq->vdev, vq->vring.used->idx);
322}
323
324void virtqueue_dump(struct virtqueue *vq)
325{
326 unsigned int i;
327
328 printf("virtqueue %p for dev %s:\n", vq, vq->vdev->name);
329 printf("\tindex %u, phys addr %p num %u\n",
330 vq->index, vq->vring.desc, vq->vring.num);
331 printf("\tfree_head %u, num_added %u, num_free %u\n",
332 vq->free_head, vq->num_added, vq->num_free);
333 printf("\tlast_used_idx %u, avail_flags_shadow %u, avail_idx_shadow %u\n",
334 vq->last_used_idx, vq->avail_flags_shadow, vq->avail_idx_shadow);
335
336 printf("Descriptor dump:\n");
337 for (i = 0; i < vq->vring.num; i++) {
338 printf("\tdesc[%u] = { 0x%llx, len %u, flags %u, next %u }\n",
339 i, vq->vring.desc[i].addr, vq->vring.desc[i].len,
340 vq->vring.desc[i].flags, vq->vring.desc[i].next);
341 }
342
343 printf("Avail ring dump:\n");
344 printf("\tflags %u, idx %u\n",
345 vq->vring.avail->flags, vq->vring.avail->idx);
346 for (i = 0; i < vq->vring.num; i++) {
347 printf("\tavail[%u] = %u\n",
348 i, vq->vring.avail->ring[i]);
349 }
350
351 printf("Used ring dump:\n");
352 printf("\tflags %u, idx %u\n",
353 vq->vring.used->flags, vq->vring.used->idx);
354 for (i = 0; i < vq->vring.num; i++) {
355 printf("\tused[%u] = { %u, %u }\n", i,
356 vq->vring.used->ring[i].id, vq->vring.used->ring[i].len);
357 }
358}
diff --git a/drivers/virtio/virtio_sandbox.c b/drivers/virtio/virtio_sandbox.c
new file mode 100644
index 0000000000..2addb1ebc5
--- /dev/null
+++ b/drivers/virtio/virtio_sandbox.c
@@ -0,0 +1,233 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 *
5 * VirtIO Sandbox transport driver, for testing purpose only
6 */
7
8#include <common.h>
9#include <dm.h>
10#include <virtio_types.h>
11#include <virtio.h>
12#include <virtio_ring.h>
13#include <linux/compat.h>
14#include <linux/io.h>
15
16struct virtio_sandbox_priv {
17 u8 id;
18 u8 status;
19 u64 device_features;
20 u64 driver_features;
21 ulong queue_desc;
22 ulong queue_available;
23 ulong queue_used;
24};
25
26static int virtio_sandbox_get_config(struct udevice *udev, unsigned int offset,
27 void *buf, unsigned int len)
28{
29 return 0;
30}
31
32static int virtio_sandbox_set_config(struct udevice *udev, unsigned int offset,
33 const void *buf, unsigned int len)
34{
35 return 0;
36}
37
38static int virtio_sandbox_get_status(struct udevice *udev, u8 *status)
39{
40 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
41
42 *status = priv->status;
43
44 return 0;
45}
46
47static int virtio_sandbox_set_status(struct udevice *udev, u8 status)
48{
49 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
50
51 /* We should never be setting status to 0 */
52 WARN_ON(status == 0);
53
54 priv->status = status;
55
56 return 0;
57}
58
59static int virtio_sandbox_reset(struct udevice *udev)
60{
61 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
62
63 /* 0 status means a reset */
64 priv->status = 0;
65
66 return 0;
67}
68
69static int virtio_sandbox_get_features(struct udevice *udev, u64 *features)
70{
71 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
72
73 *features = priv->device_features;
74
75 return 0;
76}
77
78static int virtio_sandbox_set_features(struct udevice *udev)
79{
80 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
81 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
82
83 priv->driver_features = uc_priv->features;
84
85 return 0;
86}
87
88static struct virtqueue *virtio_sandbox_setup_vq(struct udevice *udev,
89 unsigned int index)
90{
91 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
92 struct virtqueue *vq;
93 ulong addr;
94 int err;
95
96 /* Create the vring */
97 vq = vring_create_virtqueue(index, 4, 4096, udev);
98 if (!vq) {
99 err = -ENOMEM;
100 goto error_new_virtqueue;
101 }
102
103 addr = virtqueue_get_desc_addr(vq);
104 priv->queue_desc = addr;
105
106 addr = virtqueue_get_avail_addr(vq);
107 priv->queue_available = addr;
108
109 addr = virtqueue_get_used_addr(vq);
110 priv->queue_used = addr;
111
112 return vq;
113
114error_new_virtqueue:
115 return ERR_PTR(err);
116}
117
118static void virtio_sandbox_del_vq(struct virtqueue *vq)
119{
120 vring_del_virtqueue(vq);
121}
122
123static int virtio_sandbox_del_vqs(struct udevice *udev)
124{
125 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
126 struct virtqueue *vq, *n;
127
128 list_for_each_entry_safe(vq, n, &uc_priv->vqs, list)
129 virtio_sandbox_del_vq(vq);
130
131 return 0;
132}
133
134static int virtio_sandbox_find_vqs(struct udevice *udev, unsigned int nvqs,
135 struct virtqueue *vqs[])
136{
137 int i;
138
139 for (i = 0; i < nvqs; ++i) {
140 vqs[i] = virtio_sandbox_setup_vq(udev, i);
141 if (IS_ERR(vqs[i])) {
142 virtio_sandbox_del_vqs(udev);
143 return PTR_ERR(vqs[i]);
144 }
145 }
146
147 return 0;
148}
149
150static int virtio_sandbox_notify(struct udevice *udev, struct virtqueue *vq)
151{
152 return 0;
153}
154
155static int virtio_sandbox_probe(struct udevice *udev)
156{
157 struct virtio_sandbox_priv *priv = dev_get_priv(udev);
158 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
159
160 /* fake some information for testing */
161 priv->device_features = VIRTIO_F_VERSION_1;
162 uc_priv->device = VIRTIO_ID_BLOCK;
163 uc_priv->vendor = ('u' << 24) | ('b' << 16) | ('o' << 8) | 't';
164
165 return 0;
166}
167
168/* check virtio device driver's remove routine was called to reset the device */
169static int virtio_sandbox_child_post_remove(struct udevice *vdev)
170{
171 u8 status;
172
173 virtio_get_status(vdev, &status);
174 if (status)
175 panic("virtio device was not reset\n");
176
177 return 0;
178}
179
180static const struct dm_virtio_ops virtio_sandbox1_ops = {
181 .get_config = virtio_sandbox_get_config,
182 .set_config = virtio_sandbox_set_config,
183 .get_status = virtio_sandbox_get_status,
184 .set_status = virtio_sandbox_set_status,
185 .reset = virtio_sandbox_reset,
186 .get_features = virtio_sandbox_get_features,
187 .set_features = virtio_sandbox_set_features,
188 .find_vqs = virtio_sandbox_find_vqs,
189 .del_vqs = virtio_sandbox_del_vqs,
190 .notify = virtio_sandbox_notify,
191};
192
193static const struct udevice_id virtio_sandbox1_ids[] = {
194 { .compatible = "sandbox,virtio1" },
195 { }
196};
197
198U_BOOT_DRIVER(virtio_sandbox1) = {
199 .name = "virtio-sandbox1",
200 .id = UCLASS_VIRTIO,
201 .of_match = virtio_sandbox1_ids,
202 .ops = &virtio_sandbox1_ops,
203 .probe = virtio_sandbox_probe,
204 .child_post_remove = virtio_sandbox_child_post_remove,
205 .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
206};
207
208/* this one without notify op */
209static const struct dm_virtio_ops virtio_sandbox2_ops = {
210 .get_config = virtio_sandbox_get_config,
211 .set_config = virtio_sandbox_set_config,
212 .get_status = virtio_sandbox_get_status,
213 .set_status = virtio_sandbox_set_status,
214 .reset = virtio_sandbox_reset,
215 .get_features = virtio_sandbox_get_features,
216 .set_features = virtio_sandbox_set_features,
217 .find_vqs = virtio_sandbox_find_vqs,
218 .del_vqs = virtio_sandbox_del_vqs,
219};
220
221static const struct udevice_id virtio_sandbox2_ids[] = {
222 { .compatible = "sandbox,virtio2" },
223 { }
224};
225
226U_BOOT_DRIVER(virtio_sandbox2) = {
227 .name = "virtio-sandbox2",
228 .id = UCLASS_VIRTIO,
229 .of_match = virtio_sandbox2_ids,
230 .ops = &virtio_sandbox2_ops,
231 .probe = virtio_sandbox_probe,
232 .priv_auto_alloc_size = sizeof(struct virtio_sandbox_priv),
233};
diff --git a/drivers/watchdog/ast_wdt.c b/drivers/watchdog/ast_wdt.c
index 59afa21efa..523484b1ff 100644
--- a/drivers/watchdog/ast_wdt.c
+++ b/drivers/watchdog/ast_wdt.c
@@ -119,5 +119,4 @@ U_BOOT_DRIVER(ast_wdt) = {
119 .priv_auto_alloc_size = sizeof(struct ast_wdt_priv), 119 .priv_auto_alloc_size = sizeof(struct ast_wdt_priv),
120 .ofdata_to_platdata = ast_wdt_ofdata_to_platdata, 120 .ofdata_to_platdata = ast_wdt_ofdata_to_platdata,
121 .ops = &ast_wdt_ops, 121 .ops = &ast_wdt_ops,
122 .flags = DM_FLAG_PRE_RELOC,
123}; 122};
diff --git a/include/blk.h b/include/blk.h
index 6af219681c..d0c033aece 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -33,6 +33,7 @@ enum if_type {
33 IF_TYPE_HOST, 33 IF_TYPE_HOST,
34 IF_TYPE_NVME, 34 IF_TYPE_NVME,
35 IF_TYPE_EFI, 35 IF_TYPE_EFI,
36 IF_TYPE_VIRTIO,
36 37
37 IF_TYPE_COUNT, /* Number of interface types */ 38 IF_TYPE_COUNT, /* Number of interface types */
38}; 39};
@@ -357,16 +358,6 @@ int blk_create_devicef(struct udevice *parent, const char *drv_name,
357 lbaint_t lba, struct udevice **devp); 358 lbaint_t lba, struct udevice **devp);
358 359
359/** 360/**
360 * blk_prepare_device() - Prepare a block device for use
361 *
362 * This reads partition information from the device if supported.
363 *
364 * @dev: Device to prepare
365 * @return 0 if ok, -ve on error
366 */
367int blk_prepare_device(struct udevice *dev);
368
369/**
370 * blk_unbind_all() - Unbind all device of the given interface type 361 * blk_unbind_all() - Unbind all device of the given interface type
371 * 362 *
372 * The devices are removed and then unbound. 363 * The devices are removed and then unbound.
@@ -389,6 +380,17 @@ int blk_unbind_all(int if_type);
389int blk_find_max_devnum(enum if_type if_type); 380int blk_find_max_devnum(enum if_type if_type);
390 381
391/** 382/**
383 * blk_next_free_devnum() - get the next device number for an interface type
384 *
385 * Finds the next number that is safe to use for a newly allocated device for
386 * an interface type @if_type.
387 *
388 * @if_type: Interface type to scan
389 * @return next device number safe to use, or -ve on error
390 */
391int blk_next_free_devnum(enum if_type if_type);
392
393/**
392 * blk_select_hwpart() - select a hardware partition 394 * blk_select_hwpart() - select a hardware partition
393 * 395 *
394 * Select a hardware partition if the device supports it (typically MMC does) 396 * Select a hardware partition if the device supports it (typically MMC does)
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 02ac4c7952..ee2b24a62a 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -74,8 +74,8 @@ int device_bind_with_driver_data(struct udevice *parent,
74 * tree. 74 * tree.
75 * 75 *
76 * @parent: Pointer to device's parent 76 * @parent: Pointer to device's parent
77 * @pre_reloc_only: If true, bind the driver only if its DM_INIT_F flag is set. 77 * @pre_reloc_only: If true, bind the driver only if its DM_FLAG_PRE_RELOC flag
78 * If false bind the driver always. 78 * is set. If false bind the driver always.
79 * @info: Name and platdata for this device 79 * @info: Name and platdata for this device
80 * @devp: if non-NULL, returns a pointer to the bound device 80 * @devp: if non-NULL, returns a pointer to the bound device
81 * @return 0 if OK, -ve on error 81 * @return 0 if OK, -ve on error
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 13d1516a12..810e244d9e 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -39,8 +39,8 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id);
39 * each one. The devices will have @parent as their parent. 39 * each one. The devices will have @parent as their parent.
40 * 40 *
41 * @parent: parent device (root) 41 * @parent: parent device (root)
42 * @early_only: If true, bind only drivers with the DM_INIT_F flag. If false 42 * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC flag.
43 * bind all drivers. 43 * If false bind all drivers.
44 */ 44 */
45int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only); 45int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
46 46
@@ -53,10 +53,13 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only);
53 * @parent: parent device (root) 53 * @parent: parent device (root)
54 * @node: device tree node to bind 54 * @node: device tree node to bind
55 * @devp: if non-NULL, returns a pointer to the bound device 55 * @devp: if non-NULL, returns a pointer to the bound device
56 * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
57 * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
56 * @return 0 if device was bound, -EINVAL if the device tree is invalid, 58 * @return 0 if device was bound, -EINVAL if the device tree is invalid,
57 * other -ve value on error 59 * other -ve value on error
58 */ 60 */
59int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp); 61int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
62 bool pre_reloc_only);
60 63
61/** 64/**
62 * device_bind_driver() - bind a device to a driver 65 * device_bind_driver() - bind a device to a driver
diff --git a/include/dm/root.h b/include/dm/root.h
index 2b9c6da416..c8d629ba9b 100644
--- a/include/dm/root.h
+++ b/include/dm/root.h
@@ -48,8 +48,8 @@ int dm_scan_platdata(bool pre_reloc_only);
48 * the top-level subnodes are examined. 48 * the top-level subnodes are examined.
49 * 49 *
50 * @blob: Pointer to device tree blob 50 * @blob: Pointer to device tree blob
51 * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC 51 * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
52 * flag. If false bind all drivers. 52 * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
53 * @return 0 if OK, -ve on error 53 * @return 0 if OK, -ve on error
54 */ 54 */
55int dm_scan_fdt(const void *blob, bool pre_reloc_only); 55int dm_scan_fdt(const void *blob, bool pre_reloc_only);
@@ -62,8 +62,8 @@ int dm_scan_fdt(const void *blob, bool pre_reloc_only);
62 * of "clocks" node. 62 * of "clocks" node.
63 * 63 *
64 * @blob: Pointer to device tree blob 64 * @blob: Pointer to device tree blob
65 * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC 65 * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
66 * flag. If false bind all drivers. 66 * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
67 * @return 0 if OK, -ve on error 67 * @return 0 if OK, -ve on error
68 */ 68 */
69int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only); 69int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only);
@@ -76,8 +76,9 @@ int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only);
76 * programmaticaly. They should do this by calling device_bind() on each 76 * programmaticaly. They should do this by calling device_bind() on each
77 * device. 77 * device.
78 * 78 *
79 * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC 79 * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
80 * flag. If false bind all drivers. 80 * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
81 * @return 0 if OK, -ve on error
81 */ 82 */
82int dm_scan_other(bool pre_reloc_only); 83int dm_scan_other(bool pre_reloc_only);
83 84
@@ -88,8 +89,8 @@ int dm_scan_other(bool pre_reloc_only);
88 * then scans and binds available devices from platform data and the FDT. 89 * then scans and binds available devices from platform data and the FDT.
89 * This calls dm_init() to set up Driver Model structures. 90 * This calls dm_init() to set up Driver Model structures.
90 * 91 *
91 * @pre_reloc_only: If true, bind only drivers with the DM_FLAG_PRE_RELOC 92 * @pre_reloc_only: If true, bind only nodes with special devicetree properties,
92 * flag. If false bind all drivers. 93 * or drivers with the DM_FLAG_PRE_RELOC flag. If false bind all drivers.
93 * @return 0 if OK, -ve on error 94 * @return 0 if OK, -ve on error
94 */ 95 */
95int dm_init_and_scan(bool pre_reloc_only); 96int dm_init_and_scan(bool pre_reloc_only);
diff --git a/include/dm/test.h b/include/dm/test.h
index 83418eb482..07385cd531 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -69,6 +69,7 @@ struct dm_test_priv {
69 int op_count[DM_TEST_OP_COUNT]; 69 int op_count[DM_TEST_OP_COUNT];
70 int uclass_flag; 70 int uclass_flag;
71 int uclass_total; 71 int uclass_total;
72 int uclass_postp;
72}; 73};
73 74
74/** 75/**
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 269a2c6e72..c91dca1f82 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -96,6 +96,7 @@ enum uclass_id {
96 UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */ 96 UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
97 UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */ 97 UCLASS_VIDEO_CONSOLE, /* Text console driver for video device */
98 UCLASS_VIDEO_OSD, /* On-screen display */ 98 UCLASS_VIDEO_OSD, /* On-screen display */
99 UCLASS_VIRTIO, /* VirtIO transport device */
99 UCLASS_W1, /* Dallas 1-Wire bus */ 100 UCLASS_W1, /* Dallas 1-Wire bus */
100 UCLASS_W1_EEPROM, /* one-wire EEPROMs */ 101 UCLASS_W1_EEPROM, /* one-wire EEPROMs */
101 UCLASS_WDT, /* Watchdot Timer driver */ 102 UCLASS_WDT, /* Watchdot Timer driver */
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index eebf2d5614..4ef0d0f0c0 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -61,7 +61,8 @@ struct udevice;
61 * @post_probe: Called after a new device is probed 61 * @post_probe: Called after a new device is probed
62 * @pre_remove: Called before a device is removed 62 * @pre_remove: Called before a device is removed
63 * @child_post_bind: Called after a child is bound to a device in this uclass 63 * @child_post_bind: Called after a child is bound to a device in this uclass
64 * @child_pre_probe: Called before a child is probed in this uclass 64 * @child_pre_probe: Called before a child in this uclass is probed
65 * @child_post_probe: Called after a child in this uclass is probed
65 * @init: Called to set up the uclass 66 * @init: Called to set up the uclass
66 * @destroy: Called to destroy the uclass 67 * @destroy: Called to destroy the uclass
67 * @priv_auto_alloc_size: If non-zero this is the size of the private data 68 * @priv_auto_alloc_size: If non-zero this is the size of the private data
@@ -94,6 +95,7 @@ struct uclass_driver {
94 int (*pre_remove)(struct udevice *dev); 95 int (*pre_remove)(struct udevice *dev);
95 int (*child_post_bind)(struct udevice *dev); 96 int (*child_post_bind)(struct udevice *dev);
96 int (*child_pre_probe)(struct udevice *dev); 97 int (*child_pre_probe)(struct udevice *dev);
98 int (*child_post_probe)(struct udevice *dev);
97 int (*init)(struct uclass *class); 99 int (*init)(struct uclass *class);
98 int (*destroy)(struct uclass *class); 100 int (*destroy)(struct uclass *class);
99 int priv_auto_alloc_size; 101 int priv_auto_alloc_size;
diff --git a/include/dm/util.h b/include/dm/util.h
index 898822e445..9ff6531d1b 100644
--- a/include/dm/util.h
+++ b/include/dm/util.h
@@ -55,7 +55,7 @@ static inline void dm_dump_devres(void)
55 * There are 3 settings currently in use 55 * There are 3 settings currently in use
56 * - 56 * -
57 * - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL 57 * - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL
58 * Existing platforms only use it to indicate nodes needee in 58 * Existing platforms only use it to indicate nodes needed in
59 * SPL. Should probably be replaced by u-boot,dm-spl for 59 * SPL. Should probably be replaced by u-boot,dm-spl for
60 * existing platforms. 60 * existing platforms.
61 * @blob: devicetree 61 * @blob: devicetree
@@ -65,4 +65,29 @@ static inline void dm_dump_devres(void)
65 */ 65 */
66bool dm_fdt_pre_reloc(const void *blob, int offset); 66bool dm_fdt_pre_reloc(const void *blob, int offset);
67 67
68/**
69 * Check if an of node should be or was bound before relocation.
70 *
71 * Devicetree nodes can be marked as needed to be bound
72 * in the loader stages via special devicetree properties.
73 *
74 * Before relocation this function can be used to check if nodes
75 * are required in either SPL or TPL stages.
76 *
77 * After relocation and jumping into the real U-Boot binary
78 * it is possible to determine if a node was bound in one of
79 * SPL/TPL stages.
80 *
81 * There are 3 settings currently in use
82 * -
83 * - u-boot,dm-pre-reloc: legacy and indicates any of TPL or SPL
84 * Existing platforms only use it to indicate nodes needed in
85 * SPL. Should probably be replaced by u-boot,dm-spl for
86 * existing platforms.
87 * @node: of node
88 *
89 * Returns true if node is needed in SPL/TL, false otherwise.
90 */
91bool dm_ofnode_pre_reloc(ofnode node);
92
68#endif 93#endif
diff --git a/include/init.h b/include/init.h
index a58d7a6917..afc953d51e 100644
--- a/include/init.h
+++ b/include/init.h
@@ -109,7 +109,14 @@ int arch_reserve_stacks(void);
109 */ 109 */
110int init_cache_f_r(void); 110int init_cache_f_r(void);
111 111
112#if !CONFIG_IS_ENABLED(CPU)
113/**
114 * print_cpuinfo() - Display information about the CPU
115 *
116 * Return: 0 if OK, -ve on error
117 */
112int print_cpuinfo(void); 118int print_cpuinfo(void);
119#endif
113int timer_init(void); 120int timer_init(void);
114int reserve_mmu(void); 121int reserve_mmu(void);
115int misc_init_f(void); 122int misc_init_f(void);
diff --git a/include/linux/io.h b/include/linux/io.h
index d1b3efed9d..9badab49b0 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -7,6 +7,7 @@
7#include <linux/types.h> 7#include <linux/types.h>
8#include <asm/io.h> 8#include <asm/io.h>
9 9
10#ifndef CONFIG_HAVE_ARCH_IOMAP
10static inline u8 ioread8(const volatile void __iomem *addr) 11static inline u8 ioread8(const volatile void __iomem *addr)
11{ 12{
12 return readb(addr); 13 return readb(addr);
@@ -21,6 +22,7 @@ static inline u32 ioread32(const volatile void __iomem *addr)
21{ 22{
22 return readl(addr); 23 return readl(addr);
23} 24}
25#endif /* !CONFIG_HAVE_ARCH_IOMAP */
24 26
25#ifdef CONFIG_64BIT 27#ifdef CONFIG_64BIT
26static inline u64 ioread64(const volatile void __iomem *addr) 28static inline u64 ioread64(const volatile void __iomem *addr)
@@ -29,6 +31,7 @@ static inline u64 ioread64(const volatile void __iomem *addr)
29} 31}
30#endif /* CONFIG_64BIT */ 32#endif /* CONFIG_64BIT */
31 33
34#ifndef CONFIG_HAVE_ARCH_IOMAP
32static inline void iowrite8(u8 value, volatile void __iomem *addr) 35static inline void iowrite8(u8 value, volatile void __iomem *addr)
33{ 36{
34 writeb(value, addr); 37 writeb(value, addr);
@@ -43,6 +46,7 @@ static inline void iowrite32(u32 value, volatile void __iomem *addr)
43{ 46{
44 writel(value, addr); 47 writel(value, addr);
45} 48}
49#endif /* !CONFIG_HAVE_ARCH_IOMAP */
46 50
47#ifdef CONFIG_64BIT 51#ifdef CONFIG_64BIT
48static inline void iowrite64(u64 value, volatile void __iomem *addr) 52static inline void iowrite64(u64 value, volatile void __iomem *addr)
diff --git a/include/pci.h b/include/pci.h
index 938a8390cb..785d7d28b7 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -1313,6 +1313,29 @@ pci_addr_t dm_pci_phys_to_bus(struct udevice *dev, phys_addr_t addr,
1313void *dm_pci_map_bar(struct udevice *dev, int bar, int flags); 1313void *dm_pci_map_bar(struct udevice *dev, int bar, int flags);
1314 1314
1315/** 1315/**
1316 * dm_pci_find_next_capability() - find a capability starting from an offset
1317 *
1318 * Tell if a device supports a given PCI capability. Returns the
1319 * address of the requested capability structure within the device's
1320 * PCI configuration space or 0 in case the device does not support it.
1321 *
1322 * Possible values for @cap:
1323 *
1324 * %PCI_CAP_ID_MSI Message Signalled Interrupts
1325 * %PCI_CAP_ID_PCIX PCI-X
1326 * %PCI_CAP_ID_EXP PCI Express
1327 * %PCI_CAP_ID_MSIX MSI-X
1328 *
1329 * See PCI_CAP_ID_xxx for the complete capability ID codes.
1330 *
1331 * @dev: PCI device to query
1332 * @start: offset to start from
1333 * @cap: capability code
1334 * @return: capability address or 0 if not supported
1335 */
1336int dm_pci_find_next_capability(struct udevice *dev, u8 start, int cap);
1337
1338/**
1316 * dm_pci_find_capability() - find a capability 1339 * dm_pci_find_capability() - find a capability
1317 * 1340 *
1318 * Tell if a device supports a given PCI capability. Returns the 1341 * Tell if a device supports a given PCI capability. Returns the
@@ -1335,6 +1358,31 @@ void *dm_pci_map_bar(struct udevice *dev, int bar, int flags);
1335int dm_pci_find_capability(struct udevice *dev, int cap); 1358int dm_pci_find_capability(struct udevice *dev, int cap);
1336 1359
1337/** 1360/**
1361 * dm_pci_find_next_ext_capability() - find an extended capability
1362 * starting from an offset
1363 *
1364 * Tell if a device supports a given PCI express extended capability.
1365 * Returns the address of the requested extended capability structure
1366 * within the device's PCI configuration space or 0 in case the device
1367 * does not support it.
1368 *
1369 * Possible values for @cap:
1370 *
1371 * %PCI_EXT_CAP_ID_ERR Advanced Error Reporting
1372 * %PCI_EXT_CAP_ID_VC Virtual Channel
1373 * %PCI_EXT_CAP_ID_DSN Device Serial Number
1374 * %PCI_EXT_CAP_ID_PWR Power Budgeting
1375 *
1376 * See PCI_EXT_CAP_ID_xxx for the complete extended capability ID codes.
1377 *
1378 * @dev: PCI device to query
1379 * @start: offset to start from
1380 * @cap: extended capability code
1381 * @return: extended capability address or 0 if not supported
1382 */
1383int dm_pci_find_next_ext_capability(struct udevice *dev, int start, int cap);
1384
1385/**
1338 * dm_pci_find_ext_capability() - find an extended capability 1386 * dm_pci_find_ext_capability() - find an extended capability
1339 * 1387 *
1340 * Tell if a device supports a given PCI express extended capability. 1388 * Tell if a device supports a given PCI express extended capability.
diff --git a/include/regmap.h b/include/regmap.h
index 6a574eaa41..b2b733fda6 100644
--- a/include/regmap.h
+++ b/include/regmap.h
@@ -8,6 +8,61 @@
8#define __REGMAP_H 8#define __REGMAP_H
9 9
10/** 10/**
11 * DOC: Overview
12 *
13 * Regmaps are an abstraction mechanism that allows device drivers to access
14 * register maps irrespective of the underlying bus architecture. This entails
15 * that for devices that support multiple busses (e.g. I2C and SPI for a GPIO
16 * expander chip) only one driver has to be written. This driver will
17 * instantiate a regmap with a backend depending on the bus the device is
18 * attached to, and use the regmap API to access the register map through that
19 * bus transparently.
20 *
21 * Read and write functions are supplied, which can read/write data of
22 * arbitrary length from/to the regmap.
23 *
24 * The endianness of regmap accesses is selectable for each map through device
25 * tree settings via the boolean "little-endian", "big-endian", and
26 * "native-endian" properties.
27 *
28 * Furthermore, the register map described by a regmap can be split into
29 * multiple disjoint areas called ranges. In this way, register maps with
30 * "holes", i.e. areas of addressable memory that are not part of the register
31 * map, can be accessed in a concise manner.
32 *
33 * Currently, only a bare "mem" backend for regmaps is supported, which
34 * accesses the register map as regular IO-mapped memory.
35 */
36
37/**
38 * enum regmap_size_t - Access sizes for regmap reads and writes
39 *
40 * @REGMAP_SIZE_8: 8-bit read/write access size
41 * @REGMAP_SIZE_16: 16-bit read/write access size
42 * @REGMAP_SIZE_32: 32-bit read/write access size
43 * @REGMAP_SIZE_64: 64-bit read/write access size
44 */
45enum regmap_size_t {
46 REGMAP_SIZE_8 = 1,
47 REGMAP_SIZE_16 = 2,
48 REGMAP_SIZE_32 = 4,
49 REGMAP_SIZE_64 = 8,
50};
51
52/**
53 * enum regmap_endianness_t - Endianness for regmap reads and writes
54 *
55 * @REGMAP_NATIVE_ENDIAN: Native endian read/write accesses
56 * @REGMAP_LITTLE_ENDIAN: Little endian read/write accesses
57 * @REGMAP_BIG_ENDIAN: Big endian read/write accesses
58 */
59enum regmap_endianness_t {
60 REGMAP_NATIVE_ENDIAN,
61 REGMAP_LITTLE_ENDIAN,
62 REGMAP_BIG_ENDIAN,
63};
64
65/**
11 * struct regmap_range - a register map range 66 * struct regmap_range - a register map range
12 * 67 *
13 * @start: Start address 68 * @start: Start address
@@ -21,10 +76,11 @@ struct regmap_range {
21/** 76/**
22 * struct regmap - a way of accessing hardware/bus registers 77 * struct regmap - a way of accessing hardware/bus registers
23 * 78 *
24 * @range_count: Number of ranges available within the map 79 * @range_count: Number of ranges available within the map
25 * @ranges: Array of ranges 80 * @ranges: Array of ranges
26 */ 81 */
27struct regmap { 82struct regmap {
83 enum regmap_endianness_t endianness;
28 int range_count; 84 int range_count;
29 struct regmap_range ranges[0]; 85 struct regmap_range ranges[0];
30}; 86};
@@ -33,14 +89,155 @@ struct regmap {
33 * Interface to provide access to registers either through a direct memory 89 * Interface to provide access to registers either through a direct memory
34 * bus or through a peripheral bus like I2C, SPI. 90 * bus or through a peripheral bus like I2C, SPI.
35 */ 91 */
92
93/**
94 * regmap_write() - Write a 32-bit value to a regmap
95 *
96 * @map: Regmap to write to
97 * @offset: Offset in the regmap to write to
98 * @val: Data to write to the regmap at the specified offset
99 *
100 * Note that this function will only write values of 32 bit width to the
101 * regmap; if the size of data to be read is different, the regmap_raw_write
102 * function can be used.
103 *
104 * Return: 0 if OK, -ve on error
105 */
36int regmap_write(struct regmap *map, uint offset, uint val); 106int regmap_write(struct regmap *map, uint offset, uint val);
107
108/**
109 * regmap_read() - Read a 32-bit value from a regmap
110 *
111 * @map: Regmap to read from
112 * @offset: Offset in the regmap to read from
113 * @valp: Pointer to the buffer to receive the data read from the regmap
114 * at the specified offset
115 *
116 * Note that this function will only read values of 32 bit width from the
117 * regmap; if the size of data to be read is different, the regmap_raw_read
118 * function can be used.
119 *
120 * Return: 0 if OK, -ve on error
121 */
37int regmap_read(struct regmap *map, uint offset, uint *valp); 122int regmap_read(struct regmap *map, uint offset, uint *valp);
38 123
39#define regmap_write32(map, ptr, member, val) \ 124/**
40 regmap_write(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), val) 125 * regmap_raw_write() - Write a value of specified length to a regmap
126 *
127 * @map: Regmap to write to
128 * @offset: Offset in the regmap to write to
129 * @val: Value to write to the regmap at the specified offset
130 * @val_len: Length of the data to be written to the regmap
131 *
132 * Note that this function will, as opposed to regmap_write, write data of
133 * arbitrary length to the regmap, and not just 32-bit values, and is thus a
134 * generalized version of regmap_write.
135 *
136 * Return: 0 if OK, -ve on error
137 */
138int regmap_raw_write(struct regmap *map, uint offset, const void *val,
139 size_t val_len);
140
141/**
142 * regmap_raw_read() - Read a value of specified length from a regmap
143 *
144 * @map: Regmap to read from
145 * @offset: Offset in the regmap to read from
146 * @valp: Pointer to the buffer to receive the data read from the regmap
147 * at the specified offset
148 * @val_len: Length of the data to be read from the regmap
149 *
150 * Note that this function will, as opposed to regmap_read, read data of
151 * arbitrary length from the regmap, and not just 32-bit values, and is thus a
152 * generalized version of regmap_read.
153 *
154 * Return: 0 if OK, -ve on error
155 */
156int regmap_raw_read(struct regmap *map, uint offset, void *valp,
157 size_t val_len);
158
159/**
160 * regmap_raw_write_range() - Write a value of specified length to a range of a
161 * regmap
162 *
163 * @map: Regmap to write to
164 * @range_num: Number of the range in the regmap to write to
165 * @offset: Offset in the regmap to write to
166 * @val: Value to write to the regmap at the specified offset
167 * @val_len: Length of the data to be written to the regmap
168 *
169 * Return: 0 if OK, -ve on error
170 */
171int regmap_raw_write_range(struct regmap *map, uint range_num, uint offset,
172 const void *val, size_t val_len);
173
174/**
175 * regmap_raw_read_range() - Read a value of specified length from a range of a
176 * regmap
177 *
178 * @map: Regmap to read from
179 * @range_num: Number of the range in the regmap to write to
180 * @offset: Offset in the regmap to read from
181 * @valp: Pointer to the buffer to receive the data read from the regmap
182 * at the specified offset
183 * @val_len: Length of the data to be read from the regmap
184 *
185 * Return: 0 if OK, -ve on error
186 */
187int regmap_raw_read_range(struct regmap *map, uint range_num, uint offset,
188 void *valp, size_t val_len);
189
190/**
191 * regmap_range_set() - Set a value in a regmap range described by a struct
192 * @map: Regmap in which a value should be set
193 * @range: Range of the regmap in which a value should be set
194 * @type: Structure type that describes the memory layout of the regmap range
195 * @member: Member of the describing structure that should be set in the regmap
196 * range
197 * @val: Value which should be written to the regmap range
198 */
199#define regmap_range_set(map, range, type, member, val) \
200 do { \
201 typeof(((type *)0)->member) __tmp = val; \
202 regmap_raw_write_range(map, range, offsetof(type, member), \
203 &__tmp, sizeof(((type *)0)->member)); \
204 } while (0)
205
206/**
207 * regmap_set() - Set a value in a regmap described by a struct
208 * @map: Regmap in which a value should be set
209 * @type: Structure type that describes the memory layout of the regmap
210 * @member: Member of the describing structure that should be set in the regmap
211 * @val: Value which should be written to the regmap
212 */
213#define regmap_set(map, type, member, val) \
214 regmap_range_set(map, 0, type, member, val)
215
216/**
217 * regmap_range_get() - Get a value from a regmap range described by a struct
218 * @map: Regmap from which a value should be read
219 * @range: Range of the regmap from which a value should be read
220 * @type: Structure type that describes the memory layout of the regmap
221 * range
222 * @member: Member of the describing structure that should be read in the
223 * regmap range
224 * @valp: Variable that receives the value read from the regmap range
225 */
226#define regmap_range_get(map, range, type, member, valp) \
227 regmap_raw_read_range(map, range, offsetof(type, member), \
228 (void *)valp, sizeof(((type *)0)->member))
41 229
42#define regmap_read32(map, ptr, member, valp) \ 230/**
43 regmap_read(map, (uint32_t *)(ptr)->member - (uint32_t *)(ptr), valp) 231 * regmap_get() - Get a value from a regmap described by a struct
232 * @map: Regmap from which a value should be read
233 * @type: Structure type that describes the memory layout of the regmap
234 * range
235 * @member: Member of the describing structure that should be read in the
236 * regmap
237 * @valp: Variable that receives the value read from the regmap
238 */
239#define regmap_get(map, type, member, valp) \
240 regmap_range_get(map, 0, type, member, valp)
44 241
45/** 242/**
46 * regmap_update_bits() - Perform a read/modify/write using a mask 243 * regmap_update_bits() - Perform a read/modify/write using a mask
@@ -49,31 +246,36 @@ int regmap_read(struct regmap *map, uint offset, uint *valp);
49 * @offset: Offset of the memory 246 * @offset: Offset of the memory
50 * @mask: Mask to apply to the read value 247 * @mask: Mask to apply to the read value
51 * @val: Value to apply to the value to write 248 * @val: Value to apply to the value to write
249 * Return: 0 if OK, -ve on error
52 */ 250 */
53int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val); 251int regmap_update_bits(struct regmap *map, uint offset, uint mask, uint val);
54 252
55/** 253/**
56 * regmap_init_mem() - Set up a new register map that uses memory access 254 * regmap_init_mem() - Set up a new register map that uses memory access
57 * 255 *
58 * Use regmap_uninit() to free it.
59 *
60 * @node: Device node that uses this map 256 * @node: Device node that uses this map
61 * @mapp: Returns allocated map 257 * @mapp: Returns allocated map
258 * Return: 0 if OK, -ve on error
259 *
260 * Use regmap_uninit() to free it.
62 */ 261 */
63int regmap_init_mem(ofnode node, struct regmap **mapp); 262int regmap_init_mem(ofnode node, struct regmap **mapp);
64 263
65/** 264/**
66 * regmap_init_mem_platdata() - Set up a new memory register map for of-platdata 265 * regmap_init_mem_platdata() - Set up a new memory register map for
266 * of-platdata
267 *
268 * @dev: Device that uses this map
269 * @reg: List of address, size pairs
270 * @count: Number of pairs (e.g. 1 if the regmap has a single entry)
271 * @mapp: Returns allocated map
272 * Return: 0 if OK, -ve on error
67 * 273 *
68 * This creates a new regmap with a list of regions passed in, rather than 274 * This creates a new regmap with a list of regions passed in, rather than
69 * using the device tree. It only supports 32-bit machines. 275 * using the device tree. It only supports 32-bit machines.
70 * 276 *
71 * Use regmap_uninit() to free it. 277 * Use regmap_uninit() to free it.
72 * 278 *
73 * @dev: Device that uses this map
74 * @reg: List of address, size pairs
75 * @count: Number of pairs (e.g. 1 if the regmap has a single entry)
76 * @mapp: Returns allocated map
77 */ 279 */
78int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count, 280int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
79 struct regmap **mapp); 281 struct regmap **mapp);
@@ -83,11 +285,15 @@ int regmap_init_mem_platdata(struct udevice *dev, fdt_val_t *reg, int count,
83 * 285 *
84 * @map: Regmap to query 286 * @map: Regmap to query
85 * @range_num: Range to look up 287 * @range_num: Range to look up
288 * Return: Pointer to the range in question if OK, NULL on error
86 */ 289 */
87void *regmap_get_range(struct regmap *map, unsigned int range_num); 290void *regmap_get_range(struct regmap *map, unsigned int range_num);
88 291
89/** 292/**
90 * regmap_uninit() - free a previously inited regmap 293 * regmap_uninit() - free a previously inited regmap
294 *
295 * @map: Regmap to free
296 * Return: 0 if OK, -ve on error
91 */ 297 */
92int regmap_uninit(struct regmap *map); 298int regmap_uninit(struct regmap *map);
93 299
diff --git a/include/virtio.h b/include/virtio.h
new file mode 100644
index 0000000000..654fdf154b
--- /dev/null
+++ b/include/virtio.h
@@ -0,0 +1,707 @@
1/* SPDX-License-Identifier: GPL-2.0+ */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * VirtIO is a virtualization standard for network and disk device drivers
7 * where just the guest's device driver "knows" it is running in a virtual
8 * environment, and cooperates with the hypervisor. This enables guests to
9 * get high performance network and disk operations, and gives most of the
10 * performance benefits of paravirtualization. In the U-Boot case, the guest
11 * is U-Boot itself, while the virtual environment are normally QEMU targets
12 * like ARM, RISC-V and x86.
13 *
14 * See http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.pdf for
15 * the VirtIO specification v1.0.
16 *
17 * This file is largely based on Linux kernel virtio_*.h files
18 */
19
20#ifndef __VIRTIO_H__
21#define __VIRTIO_H__
22
23#define VIRTIO_ID_NET 1 /* virtio net */
24#define VIRTIO_ID_BLOCK 2 /* virtio block */
25#define VIRTIO_ID_MAX_NUM 3
26
27#define VIRTIO_NET_DRV_NAME "virtio-net"
28#define VIRTIO_BLK_DRV_NAME "virtio-blk"
29
30/* Status byte for guest to report progress, and synchronize features */
31
32/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */
33#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1
34/* We have found a driver for the device */
35#define VIRTIO_CONFIG_S_DRIVER 2
36/* Driver has used its parts of the config, and is happy */
37#define VIRTIO_CONFIG_S_DRIVER_OK 4
38/* Driver has finished configuring features */
39#define VIRTIO_CONFIG_S_FEATURES_OK 8
40/* Device entered invalid state, driver must reset it */
41#define VIRTIO_CONFIG_S_NEEDS_RESET 0x40
42/* We've given up on this device */
43#define VIRTIO_CONFIG_S_FAILED 0x80
44
45/*
46 * Virtio feature bits VIRTIO_TRANSPORT_F_START through VIRTIO_TRANSPORT_F_END
47 * are reserved for the transport being used (eg: virtio_ring, virtio_pci etc.),
48 * the rest are per-device feature bits.
49 */
50#define VIRTIO_TRANSPORT_F_START 28
51#define VIRTIO_TRANSPORT_F_END 38
52
53#ifndef VIRTIO_CONFIG_NO_LEGACY
54/*
55 * Do we get callbacks when the ring is completely used,
56 * even if we've suppressed them?
57 */
58#define VIRTIO_F_NOTIFY_ON_EMPTY 24
59
60/* Can the device handle any descriptor layout? */
61#define VIRTIO_F_ANY_LAYOUT 27
62#endif /* VIRTIO_CONFIG_NO_LEGACY */
63
64/* v1.0 compliant */
65#define VIRTIO_F_VERSION_1 32
66
67/*
68 * If clear - device has the IOMMU bypass quirk feature.
69 * If set - use platform tools to detect the IOMMU.
70 *
71 * Note the reverse polarity (compared to most other features),
72 * this is for compatibility with legacy systems.
73 */
74#define VIRTIO_F_IOMMU_PLATFORM 33
75
76/* Does the device support Single Root I/O Virtualization? */
77#define VIRTIO_F_SR_IOV 37
78
79/**
80 * virtio scatter-gather struct
81 *
82 * @addr: sg buffer address
83 * @lengh: sg buffer length
84 */
85struct virtio_sg {
86 void *addr;
87 size_t length;
88};
89
90struct virtqueue;
91
92/* virtio bus operations */
93struct dm_virtio_ops {
94 /**
95 * get_config() - read the value of a configuration field
96 *
97 * @vdev: the real virtio device
98 * @offset: the offset of the configuration field
99 * @buf: the buffer to write the field value into
100 * @len: the length of the buffer
101 * @return 0 if OK, -ve on error
102 */
103 int (*get_config)(struct udevice *vdev, unsigned int offset,
104 void *buf, unsigned int len);
105 /**
106 * set_config() - write the value of a configuration field
107 *
108 * @vdev: the real virtio device
109 * @offset: the offset of the configuration field
110 * @buf: the buffer to read the field value from
111 * @len: the length of the buffer
112 * @return 0 if OK, -ve on error
113 */
114 int (*set_config)(struct udevice *vdev, unsigned int offset,
115 const void *buf, unsigned int len);
116 /**
117 * generation() - config generation counter
118 *
119 * @vdev: the real virtio device
120 * @counter: the returned config generation counter
121 * @return 0 if OK, -ve on error
122 */
123 int (*generation)(struct udevice *vdev, u32 *counter);
124 /**
125 * get_status() - read the status byte
126 *
127 * @vdev: the real virtio device
128 * @status: the returned status byte
129 * @return 0 if OK, -ve on error
130 */
131 int (*get_status)(struct udevice *vdev, u8 *status);
132 /**
133 * set_status() - write the status byte
134 *
135 * @vdev: the real virtio device
136 * @status: the new status byte
137 * @return 0 if OK, -ve on error
138 */
139 int (*set_status)(struct udevice *vdev, u8 status);
140 /**
141 * reset() - reset the device
142 *
143 * @vdev: the real virtio device
144 * @return 0 if OK, -ve on error
145 */
146 int (*reset)(struct udevice *vdev);
147 /**
148 * get_features() - get the array of feature bits for this device
149 *
150 * @vdev: the real virtio device
151 * @features: the first 32 feature bits (all we currently need)
152 * @return 0 if OK, -ve on error
153 */
154 int (*get_features)(struct udevice *vdev, u64 *features);
155 /**
156 * set_features() - confirm what device features we'll be using
157 *
158 * @vdev: the real virtio device
159 * @return 0 if OK, -ve on error
160 */
161 int (*set_features)(struct udevice *vdev);
162 /**
163 * find_vqs() - find virtqueues and instantiate them
164 *
165 * @vdev: the real virtio device
166 * @nvqs: the number of virtqueues to find
167 * @vqs: on success, includes new virtqueues
168 * @return 0 if OK, -ve on error
169 */
170 int (*find_vqs)(struct udevice *vdev, unsigned int nvqs,
171 struct virtqueue *vqs[]);
172 /**
173 * del_vqs() - free virtqueues found by find_vqs()
174 *
175 * @vdev: the real virtio device
176 * @return 0 if OK, -ve on error
177 */
178 int (*del_vqs)(struct udevice *vdev);
179 /**
180 * notify() - notify the device to process the queue
181 *
182 * @vdev: the real virtio device
183 * @vq: virtqueue to process
184 * @return 0 if OK, -ve on error
185 */
186 int (*notify)(struct udevice *vdev, struct virtqueue *vq);
187};
188
189/* Get access to a virtio bus' operations */
190#define virtio_get_ops(dev) ((struct dm_virtio_ops *)(dev)->driver->ops)
191
192/**
193 * virtio uclass per device private data
194 *
195 * @vqs: virtualqueue for the virtio device
196 * @vdev: the real virtio device underneath
197 * @legacy: is it a legacy device?
198 * @device: virtio device ID
199 * @vendor: virtio vendor ID
200 * @features: negotiated supported features
201 * @feature_table: an array of feature supported by the driver
202 * @feature_table_size: number of entries in the feature table array
203 * @feature_table_legacy: same as feature_table but working in legacy mode
204 * @feature_table_size_legacy: number of entries in feature table legacy array
205 */
206struct virtio_dev_priv {
207 struct list_head vqs;
208 struct udevice *vdev;
209 bool legacy;
210 u32 device;
211 u32 vendor;
212 u64 features;
213 const u32 *feature_table;
214 u32 feature_table_size;
215 const u32 *feature_table_legacy;
216 u32 feature_table_size_legacy;
217};
218
219/**
220 * virtio_get_config() - read the value of a configuration field
221 *
222 * @vdev: the real virtio device
223 * @offset: the offset of the configuration field
224 * @buf: the buffer to write the field value into
225 * @len: the length of the buffer
226 * @return 0 if OK, -ve on error
227 */
228int virtio_get_config(struct udevice *vdev, unsigned int offset,
229 void *buf, unsigned int len);
230
231/**
232 * virtio_set_config() - write the value of a configuration field
233 *
234 * @vdev: the real virtio device
235 * @offset: the offset of the configuration field
236 * @buf: the buffer to read the field value from
237 * @len: the length of the buffer
238 * @return 0 if OK, -ve on error
239 */
240int virtio_set_config(struct udevice *vdev, unsigned int offset,
241 void *buf, unsigned int len);
242
243/**
244 * virtio_generation() - config generation counter
245 *
246 * @vdev: the real virtio device
247 * @counter: the returned config generation counter
248 * @return 0 if OK, -ve on error
249 */
250int virtio_generation(struct udevice *vdev, u32 *counter);
251
252/**
253 * virtio_get_status() - read the status byte
254 *
255 * @vdev: the real virtio device
256 * @status: the returned status byte
257 * @return 0 if OK, -ve on error
258 */
259int virtio_get_status(struct udevice *vdev, u8 *status);
260
261/**
262 * virtio_set_status() - write the status byte
263 *
264 * @vdev: the real virtio device
265 * @status: the new status byte
266 * @return 0 if OK, -ve on error
267 */
268int virtio_set_status(struct udevice *vdev, u8 status);
269
270/**
271 * virtio_reset() - reset the device
272 *
273 * @vdev: the real virtio device
274 * @return 0 if OK, -ve on error
275 */
276int virtio_reset(struct udevice *vdev);
277
278/**
279 * virtio_get_features() - get the array of feature bits for this device
280 *
281 * @vdev: the real virtio device
282 * @features: the first 32 feature bits (all we currently need)
283 * @return 0 if OK, -ve on error
284 */
285int virtio_get_features(struct udevice *vdev, u64 *features);
286
287/**
288 * virtio_set_features() - confirm what device features we'll be using
289 *
290 * @vdev: the real virtio device
291 * @return 0 if OK, -ve on error
292 */
293int virtio_set_features(struct udevice *vdev);
294
295/**
296 * virtio_find_vqs() - find virtqueues and instantiate them
297 *
298 * @vdev: the real virtio device
299 * @nvqs: the number of virtqueues to find
300 * @vqs: on success, includes new virtqueues
301 * @return 0 if OK, -ve on error
302 */
303int virtio_find_vqs(struct udevice *vdev, unsigned int nvqs,
304 struct virtqueue *vqs[]);
305
306/**
307 * virtio_del_vqs() - free virtqueues found by find_vqs()
308 *
309 * @vdev: the real virtio device
310 * @return 0 if OK, -ve on error
311 */
312int virtio_del_vqs(struct udevice *vdev);
313
314/**
315 * virtio_notify() - notify the device to process the queue
316 *
317 * @vdev: the real virtio device
318 * @vq: virtqueue to process
319 * @return 0 if OK, -ve on error
320 */
321int virtio_notify(struct udevice *vdev, struct virtqueue *vq);
322
323/**
324 * virtio_add_status() - helper to set a new status code to the device
325 *
326 * @vdev: the real virtio device
327 * @status: new status code to be added
328 */
329void virtio_add_status(struct udevice *vdev, u8 status);
330
331/**
332 * virtio_finalize_features() - helper to finalize features
333 *
334 * @vdev: the real virtio device
335 * @return 0 if OK, -ve on error
336 */
337int virtio_finalize_features(struct udevice *vdev);
338
339/**
340 * virtio_driver_features_init() - initialize driver supported features
341 *
342 * This fills in the virtio device parent per child private data with the given
343 * information, which contains driver supported features and legacy features.
344 *
345 * This API should be called in the virtio device driver's bind method, so that
346 * later virtio transport uclass driver can utilize the driver supplied features
347 * to negotiate with the device on the final supported features.
348 *
349 * @priv: virtio uclass per device private data
350 * @feature: an array of feature supported by the driver
351 * @feature_size: number of entries in the feature table array
352 * @feature_legacy: same as feature_table but working in legacy mode
353 * @feature_legacy_size:number of entries in feature table legacy array
354 */
355void virtio_driver_features_init(struct virtio_dev_priv *priv,
356 const u32 *feature,
357 u32 feature_size,
358 const u32 *feature_legacy,
359 u32 feature_legacy_size);
360
361/**
362 * virtio_init() - helper to enumerate all known virtio devices
363 *
364 * @return 0 if OK, -ve on error
365 */
366int virtio_init(void);
367
368static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
369{
370 if (little_endian)
371 return le16_to_cpu((__force __le16)val);
372 else
373 return be16_to_cpu((__force __be16)val);
374}
375
376static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
377{
378 if (little_endian)
379 return (__force __virtio16)cpu_to_le16(val);
380 else
381 return (__force __virtio16)cpu_to_be16(val);
382}
383
384static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
385{
386 if (little_endian)
387 return le32_to_cpu((__force __le32)val);
388 else
389 return be32_to_cpu((__force __be32)val);
390}
391
392static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
393{
394 if (little_endian)
395 return (__force __virtio32)cpu_to_le32(val);
396 else
397 return (__force __virtio32)cpu_to_be32(val);
398}
399
400static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
401{
402 if (little_endian)
403 return le64_to_cpu((__force __le64)val);
404 else
405 return be64_to_cpu((__force __be64)val);
406}
407
408static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
409{
410 if (little_endian)
411 return (__force __virtio64)cpu_to_le64(val);
412 else
413 return (__force __virtio64)cpu_to_be64(val);
414}
415
416/**
417 * __virtio_test_bit - helper to test feature bits
418 *
419 * For use by transports. Devices should normally use virtio_has_feature,
420 * which includes more checks.
421 *
422 * @udev: the transport device
423 * @fbit: the feature bit
424 */
425static inline bool __virtio_test_bit(struct udevice *udev, unsigned int fbit)
426{
427 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
428
429 /* Did you forget to fix assumptions on max features? */
430 if (__builtin_constant_p(fbit))
431 BUILD_BUG_ON(fbit >= 64);
432 else
433 WARN_ON(fbit >= 64);
434
435 return uc_priv->features & BIT_ULL(fbit);
436}
437
438/**
439 * __virtio_set_bit - helper to set feature bits
440 *
441 * For use by transports.
442 *
443 * @udev: the transport device
444 * @fbit: the feature bit
445 */
446static inline void __virtio_set_bit(struct udevice *udev, unsigned int fbit)
447{
448 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
449
450 /* Did you forget to fix assumptions on max features? */
451 if (__builtin_constant_p(fbit))
452 BUILD_BUG_ON(fbit >= 64);
453 else
454 WARN_ON(fbit >= 64);
455
456 uc_priv->features |= BIT_ULL(fbit);
457}
458
459/**
460 * __virtio_clear_bit - helper to clear feature bits
461 *
462 * For use by transports.
463 *
464 * @vdev: the transport device
465 * @fbit: the feature bit
466 */
467static inline void __virtio_clear_bit(struct udevice *udev, unsigned int fbit)
468{
469 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
470
471 /* Did you forget to fix assumptions on max features? */
472 if (__builtin_constant_p(fbit))
473 BUILD_BUG_ON(fbit >= 64);
474 else
475 WARN_ON(fbit >= 64);
476
477 uc_priv->features &= ~BIT_ULL(fbit);
478}
479
480/**
481 * virtio_has_feature - helper to determine if this device has this feature
482 *
483 * Note this API is only usable after the virtio device driver's bind phase,
484 * as the feature has been negotiated between the device and the driver.
485 *
486 * @vdev: the virtio device
487 * @fbit: the feature bit
488 */
489static inline bool virtio_has_feature(struct udevice *vdev, unsigned int fbit)
490{
491 if (!(vdev->flags & DM_FLAG_BOUND))
492 WARN_ON(true);
493
494 return __virtio_test_bit(vdev->parent, fbit);
495}
496
497static inline bool virtio_legacy_is_little_endian(void)
498{
499#ifdef __LITTLE_ENDIAN
500 return true;
501#else
502 return false;
503#endif
504}
505
506static inline bool virtio_is_little_endian(struct udevice *vdev)
507{
508 struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(vdev->parent);
509
510 return !uc_priv->legacy || virtio_legacy_is_little_endian();
511}
512
513/* Memory accessors */
514static inline u16 virtio16_to_cpu(struct udevice *vdev, __virtio16 val)
515{
516 return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
517}
518
519static inline __virtio16 cpu_to_virtio16(struct udevice *vdev, u16 val)
520{
521 return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
522}
523
524static inline u32 virtio32_to_cpu(struct udevice *vdev, __virtio32 val)
525{
526 return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
527}
528
529static inline __virtio32 cpu_to_virtio32(struct udevice *vdev, u32 val)
530{
531 return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
532}
533
534static inline u64 virtio64_to_cpu(struct udevice *vdev, __virtio64 val)
535{
536 return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
537}
538
539static inline __virtio64 cpu_to_virtio64(struct udevice *vdev, u64 val)
540{
541 return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
542}
543
544/* Read @count fields, @bytes each */
545static inline void __virtio_cread_many(struct udevice *vdev,
546 unsigned int offset,
547 void *buf, size_t count, size_t bytes)
548{
549 u32 old, gen;
550 int i;
551
552 /* no need to check return value as generation can be optional */
553 virtio_generation(vdev, &gen);
554 do {
555 old = gen;
556
557 for (i = 0; i < count; i++)
558 virtio_get_config(vdev, offset + bytes * i,
559 buf + i * bytes, bytes);
560
561 virtio_generation(vdev, &gen);
562 } while (gen != old);
563}
564
565static inline void virtio_cread_bytes(struct udevice *vdev,
566 unsigned int offset,
567 void *buf, size_t len)
568{
569 __virtio_cread_many(vdev, offset, buf, len, 1);
570}
571
572static inline u8 virtio_cread8(struct udevice *vdev, unsigned int offset)
573{
574 u8 ret;
575
576 virtio_get_config(vdev, offset, &ret, sizeof(ret));
577 return ret;
578}
579
580static inline void virtio_cwrite8(struct udevice *vdev,
581 unsigned int offset, u8 val)
582{
583 virtio_set_config(vdev, offset, &val, sizeof(val));
584}
585
586static inline u16 virtio_cread16(struct udevice *vdev,
587 unsigned int offset)
588{
589 u16 ret;
590
591 virtio_get_config(vdev, offset, &ret, sizeof(ret));
592 return virtio16_to_cpu(vdev, (__force __virtio16)ret);
593}
594
595static inline void virtio_cwrite16(struct udevice *vdev,
596 unsigned int offset, u16 val)
597{
598 val = (__force u16)cpu_to_virtio16(vdev, val);
599 virtio_set_config(vdev, offset, &val, sizeof(val));
600}
601
602static inline u32 virtio_cread32(struct udevice *vdev,
603 unsigned int offset)
604{
605 u32 ret;
606
607 virtio_get_config(vdev, offset, &ret, sizeof(ret));
608 return virtio32_to_cpu(vdev, (__force __virtio32)ret);
609}
610
611static inline void virtio_cwrite32(struct udevice *vdev,
612 unsigned int offset, u32 val)
613{
614 val = (__force u32)cpu_to_virtio32(vdev, val);
615 virtio_set_config(vdev, offset, &val, sizeof(val));
616}
617
618static inline u64 virtio_cread64(struct udevice *vdev,
619 unsigned int offset)
620{
621 u64 ret;
622
623 __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret));
624 return virtio64_to_cpu(vdev, (__force __virtio64)ret);
625}
626
627static inline void virtio_cwrite64(struct udevice *vdev,
628 unsigned int offset, u64 val)
629{
630 val = (__force u64)cpu_to_virtio64(vdev, val);
631 virtio_set_config(vdev, offset, &val, sizeof(val));
632}
633
634/* Config space read accessor */
635#define virtio_cread(vdev, structname, member, ptr) \
636 do { \
637 /* Must match the member's type, and be integer */ \
638 if (!typecheck(typeof((((structname *)0)->member)), *(ptr))) \
639 (*ptr) = 1; \
640 \
641 switch (sizeof(*ptr)) { \
642 case 1: \
643 *(ptr) = virtio_cread8(vdev, \
644 offsetof(structname, member)); \
645 break; \
646 case 2: \
647 *(ptr) = virtio_cread16(vdev, \
648 offsetof(structname, member)); \
649 break; \
650 case 4: \
651 *(ptr) = virtio_cread32(vdev, \
652 offsetof(structname, member)); \
653 break; \
654 case 8: \
655 *(ptr) = virtio_cread64(vdev, \
656 offsetof(structname, member)); \
657 break; \
658 default: \
659 WARN_ON(true); \
660 } \
661 } while (0)
662
663/* Config space write accessor */
664#define virtio_cwrite(vdev, structname, member, ptr) \
665 do { \
666 /* Must match the member's type, and be integer */ \
667 if (!typecheck(typeof((((structname *)0)->member)), *(ptr))) \
668 WARN_ON((*ptr) == 1); \
669 \
670 switch (sizeof(*ptr)) { \
671 case 1: \
672 virtio_cwrite8(vdev, \
673 offsetof(structname, member), \
674 *(ptr)); \
675 break; \
676 case 2: \
677 virtio_cwrite16(vdev, \
678 offsetof(structname, member), \
679 *(ptr)); \
680 break; \
681 case 4: \
682 virtio_cwrite32(vdev, \
683 offsetof(structname, member), \
684 *(ptr)); \
685 break; \
686 case 8: \
687 virtio_cwrite64(vdev, \
688 offsetof(structname, member), \
689 *(ptr)); \
690 break; \
691 default: \
692 WARN_ON(true); \
693 } \
694 } while (0)
695
696/* Conditional config space accessors */
697#define virtio_cread_feature(vdev, fbit, structname, member, ptr) \
698 ({ \
699 int _r = 0; \
700 if (!virtio_has_feature(vdev, fbit)) \
701 _r = -ENOENT; \
702 else \
703 virtio_cread(vdev, structname, member, ptr); \
704 _r; \
705 })
706
707#endif /* __VIRTIO_H__ */
diff --git a/include/virtio_ring.h b/include/virtio_ring.h
new file mode 100644
index 0000000000..6fc0593b14
--- /dev/null
+++ b/include/virtio_ring.h
@@ -0,0 +1,320 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_ring.h
7 */
8
9#ifndef _LINUX_VIRTIO_RING_H
10#define _LINUX_VIRTIO_RING_H
11
12#include <virtio_types.h>
13
14/* This marks a buffer as continuing via the next field */
15#define VRING_DESC_F_NEXT 1
16/* This marks a buffer as write-only (otherwise read-only) */
17#define VRING_DESC_F_WRITE 2
18/* This means the buffer contains a list of buffer descriptors */
19#define VRING_DESC_F_INDIRECT 4
20
21/*
22 * The Host uses this in used->flags to advise the Guest: don't kick me when
23 * you add a buffer. It's unreliable, so it's simply an optimization. Guest
24 * will still kick if it's out of buffers.
25 */
26#define VRING_USED_F_NO_NOTIFY 1
27
28/*
29 * The Guest uses this in avail->flags to advise the Host: don't interrupt me
30 * when you consume a buffer. It's unreliable, so it's simply an optimization.
31 */
32#define VRING_AVAIL_F_NO_INTERRUPT 1
33
34/* We support indirect buffer descriptors */
35#define VIRTIO_RING_F_INDIRECT_DESC 28
36
37/*
38 * The Guest publishes the used index for which it expects an interrupt
39 * at the end of the avail ring. Host should ignore the avail->flags field.
40 *
41 * The Host publishes the avail index for which it expects a kick
42 * at the end of the used ring. Guest should ignore the used->flags field.
43 */
44#define VIRTIO_RING_F_EVENT_IDX 29
45
46/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
47struct vring_desc {
48 /* Address (guest-physical) */
49 __virtio64 addr;
50 /* Length */
51 __virtio32 len;
52 /* The flags as indicated above */
53 __virtio16 flags;
54 /* We chain unused descriptors via this, too */
55 __virtio16 next;
56};
57
58struct vring_avail {
59 __virtio16 flags;
60 __virtio16 idx;
61 __virtio16 ring[];
62};
63
64struct vring_used_elem {
65 /* Index of start of used descriptor chain */
66 __virtio32 id;
67 /* Total length of the descriptor chain which was used (written to) */
68 __virtio32 len;
69};
70
71struct vring_used {
72 __virtio16 flags;
73 __virtio16 idx;
74 struct vring_used_elem ring[];
75};
76
77struct vring {
78 unsigned int num;
79 struct vring_desc *desc;
80 struct vring_avail *avail;
81 struct vring_used *used;
82};
83
84/**
85 * virtqueue - a queue to register buffers for sending or receiving.
86 *
87 * @list: the chain of virtqueues for this device
88 * @vdev: the virtio device this queue was created for
89 * @index: the zero-based ordinal number for this queue
90 * @num_free: number of elements we expect to be able to fit
91 * @vring: actual memory layout for this queue
92 * @event: host publishes avail event idx
93 * @free_head: head of free buffer list
94 * @num_added: number we've added since last sync
95 * @last_used_idx: last used index we've seen
96 * @avail_flags_shadow: last written value to avail->flags
97 * @avail_idx_shadow: last written value to avail->idx in guest byte order
98 */
99struct virtqueue {
100 struct list_head list;
101 struct udevice *vdev;
102 unsigned int index;
103 unsigned int num_free;
104 struct vring vring;
105 bool event;
106 unsigned int free_head;
107 unsigned int num_added;
108 u16 last_used_idx;
109 u16 avail_flags_shadow;
110 u16 avail_idx_shadow;
111};
112
113/*
114 * Alignment requirements for vring elements.
115 * When using pre-virtio 1.0 layout, these fall out naturally.
116 */
117#define VRING_AVAIL_ALIGN_SIZE 2
118#define VRING_USED_ALIGN_SIZE 4
119#define VRING_DESC_ALIGN_SIZE 16
120
121/*
122 * We publish the used event index at the end of the available ring,
123 * and vice versa. They are at the end for backwards compatibility.
124 */
125#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
126#define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num])
127
128static inline void vring_init(struct vring *vr, unsigned int num, void *p,
129 unsigned long align)
130{
131 vr->num = num;
132 vr->desc = p;
133 vr->avail = p + num * sizeof(struct vring_desc);
134 vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] +
135 sizeof(__virtio16) + align - 1) & ~(align - 1));
136}
137
138static inline unsigned int vring_size(unsigned int num, unsigned long align)
139{
140 return ((sizeof(struct vring_desc) * num +
141 sizeof(__virtio16) * (3 + num) + align - 1) & ~(align - 1)) +
142 sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num;
143}
144
145/*
146 * The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX.
147 * Assuming a given event_idx value from the other side, if we have just
148 * incremented index from old to new_idx, should we trigger an event?
149 */
150static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
151{
152 /*
153 * Note: Xen has similar logic for notification hold-off
154 * in include/xen/interface/io/ring.h with req_event and req_prod
155 * corresponding to event_idx + 1 and new_idx respectively.
156 * Note also that req_event and req_prod in Xen start at 1,
157 * event indexes in virtio start at 0.
158 */
159 return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
160}
161
162struct virtio_sg;
163
164/**
165 * virtqueue_add - expose buffers to other end
166 *
167 * @vq: the struct virtqueue we're talking about
168 * @sgs: array of terminated scatterlists
169 * @out_sgs: the number of scatterlists readable by other side
170 * @in_sgs: the number of scatterlists which are writable
171 * (after readable ones)
172 *
173 * Caller must ensure we don't call this with other virtqueue operations
174 * at the same time (except where noted).
175 *
176 * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO).
177 */
178int virtqueue_add(struct virtqueue *vq, struct virtio_sg *sgs[],
179 unsigned int out_sgs, unsigned int in_sgs);
180
181/**
182 * virtqueue_kick - update after add_buf
183 *
184 * @vq: the struct virtqueue
185 *
186 * After one or more virtqueue_add() calls, invoke this to kick
187 * the other side.
188 *
189 * Caller must ensure we don't call this with other virtqueue
190 * operations at the same time (except where noted).
191 */
192void virtqueue_kick(struct virtqueue *vq);
193
194/**
195 * virtqueue_get_buf - get the next used buffer
196 *
197 * @vq: the struct virtqueue we're talking about
198 * @len: the length written into the buffer
199 *
200 * If the device wrote data into the buffer, @len will be set to the
201 * amount written. This means you don't need to clear the buffer
202 * beforehand to ensure there's no data leakage in the case of short
203 * writes.
204 *
205 * Caller must ensure we don't call this with other virtqueue
206 * operations at the same time (except where noted).
207 *
208 * Returns NULL if there are no used buffers, or the memory buffer
209 * handed to virtqueue_add_*().
210 */
211void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len);
212
213/**
214 * vring_create_virtqueue - create a virtqueue for a virtio device
215 *
216 * @index: the index of the queue
217 * @num: number of elements of the queue
218 * @vring_align:the alignment requirement of the descriptor ring
219 * @udev: the virtio transport udevice
220 * @return: the virtqueue pointer or NULL if failed
221 *
222 * This creates a virtqueue and allocates the descriptor ring for a virtio
223 * device. The caller should query virtqueue_get_ring_size() to learn the
224 * actual size of the ring.
225 *
226 * This API is supposed to be called by the virtio transport driver in the
227 * virtio find_vqs() uclass method.
228 */
229struct virtqueue *vring_create_virtqueue(unsigned int index, unsigned int num,
230 unsigned int vring_align,
231 struct udevice *udev);
232
233/**
234 * vring_del_virtqueue - destroy a virtqueue
235 *
236 * @vq: the struct virtqueue we're talking about
237 *
238 * This destroys a virtqueue. If created with vring_create_virtqueue(),
239 * this also frees the descriptor ring.
240 *
241 * This API is supposed to be called by the virtio transport driver in the
242 * virtio del_vqs() uclass method.
243 */
244void vring_del_virtqueue(struct virtqueue *vq);
245
246/**
247 * virtqueue_get_vring_size - get the size of the virtqueue's vring
248 *
249 * @vq: the struct virtqueue containing the vring of interest
250 * @return: the size of the vring in a virtqueue.
251 */
252unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
253
254/**
255 * virtqueue_get_desc_addr - get the vring descriptor table address
256 *
257 * @vq: the struct virtqueue containing the vring of interest
258 * @return: the descriptor table address of the vring in a virtqueue.
259 */
260ulong virtqueue_get_desc_addr(struct virtqueue *vq);
261
262/**
263 * virtqueue_get_avail_addr - get the vring available ring address
264 *
265 * @vq: the struct virtqueue containing the vring of interest
266 * @return: the available ring address of the vring in a virtqueue.
267 */
268ulong virtqueue_get_avail_addr(struct virtqueue *vq);
269
270/**
271 * virtqueue_get_used_addr - get the vring used ring address
272 *
273 * @vq: the struct virtqueue containing the vring of interest
274 * @return: the used ring address of the vring in a virtqueue.
275 */
276ulong virtqueue_get_used_addr(struct virtqueue *vq);
277
278/**
279 * virtqueue_poll - query pending used buffers
280 *
281 * @vq: the struct virtqueue we're talking about
282 * @last_used_idx: virtqueue last used index
283 *
284 * Returns "true" if there are pending used buffers in the queue.
285 */
286bool virtqueue_poll(struct virtqueue *vq, u16 last_used_idx);
287
288/**
289 * virtqueue_dump - dump the virtqueue for debugging
290 *
291 * @vq: the struct virtqueue we're talking about
292 *
293 * Caller must ensure we don't call this with other virtqueue operations
294 * at the same time (except where noted).
295 */
296void virtqueue_dump(struct virtqueue *vq);
297
298/*
299 * Barriers in virtio are tricky. Since we are not in a hyperviosr/guest
300 * scenario, having these as nops is enough to work as expected.
301 */
302
303static inline void virtio_mb(void)
304{
305}
306
307static inline void virtio_rmb(void)
308{
309}
310
311static inline void virtio_wmb(void)
312{
313}
314
315static inline void virtio_store_mb(__virtio16 *p, __virtio16 v)
316{
317 WRITE_ONCE(*p, v);
318}
319
320#endif /* _LINUX_VIRTIO_RING_H */
diff --git a/include/virtio_types.h b/include/virtio_types.h
new file mode 100644
index 0000000000..d700d1936d
--- /dev/null
+++ b/include/virtio_types.h
@@ -0,0 +1,24 @@
1/* SPDX-License-Identifier: BSD-3-Clause */
2/*
3 * Copyright (C) 2018, Tuomas Tynkkynen <tuomas.tynkkynen@iki.fi>
4 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
5 *
6 * From Linux kernel include/uapi/linux/virtio_types.h
7 */
8
9#ifndef _LINUX_VIRTIO_TYPES_H
10#define _LINUX_VIRTIO_TYPES_H
11
12#include <linux/types.h>
13
14/*
15 * __virtio{16,32,64} have the following meaning:
16 * - __u{16,32,64} for virtio devices in legacy mode, accessed in native endian
17 * - __le{16,32,64} for standard-compliant virtio devices
18 */
19
20typedef __u16 __bitwise __virtio16;
21typedef __u32 __bitwise __virtio32;
22typedef __u64 __bitwise __virtio64;
23
24#endif /* _LINUX_VIRTIO_TYPES_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index ccab426e12..847e797a3a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -21,6 +21,12 @@ config DYNAMIC_CRC_TABLE
21 Enable this option to calculate entries for CRC tables at runtime. 21 Enable this option to calculate entries for CRC tables at runtime.
22 This can be helpful when reducing the size of the build image 22 This can be helpful when reducing the size of the build image
23 23
24config HAVE_ARCH_IOMAP
25 bool
26 help
27 Enable this option if architecture provides io{read,write}{8,16,32}
28 I/O accessor functions.
29
24config HAVE_PRIVATE_LIBGCC 30config HAVE_PRIVATE_LIBGCC
25 bool 31 bool
26 32
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index 5879d40386..0047998ee0 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -161,5 +161,4 @@ U_BOOT_DRIVER(efi_sysreset) = {
161 .id = UCLASS_SYSRESET, 161 .id = UCLASS_SYSRESET,
162 .of_match = efi_sysreset_ids, 162 .of_match = efi_sysreset_ids,
163 .ops = &efi_sysreset_ops, 163 .ops = &efi_sysreset_ops,
164 .flags = DM_FLAG_PRE_RELOC,
165}; 164};
diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c
index 5b9c139f38..3f147cf608 100644
--- a/lib/efi_driver/efi_block_device.c
+++ b/lib/efi_driver/efi_block_device.c
@@ -38,7 +38,7 @@
38 * handle handle of the controller on which this driver is installed 38 * handle handle of the controller on which this driver is installed
39 * io block io protocol proxied by this driver 39 * io block io protocol proxied by this driver
40 */ 40 */
41struct efi_blk_priv { 41struct efi_blk_platdata {
42 efi_handle_t handle; 42 efi_handle_t handle;
43 struct efi_block_io *io; 43 struct efi_block_io *io;
44}; 44};
@@ -55,8 +55,8 @@ struct efi_blk_priv {
55static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 55static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
56 void *buffer) 56 void *buffer)
57{ 57{
58 struct efi_blk_priv *priv = dev->priv; 58 struct efi_blk_platdata *platdata = dev_get_platdata(dev);
59 struct efi_block_io *io = priv->io; 59 struct efi_block_io *io = platdata->io;
60 efi_status_t ret; 60 efi_status_t ret;
61 61
62 EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n", 62 EFI_PRINT("%s: read '%s', from block " LBAFU ", " LBAFU " blocks\n",
@@ -84,8 +84,8 @@ static ulong efi_bl_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
84static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt, 84static ulong efi_bl_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
85 const void *buffer) 85 const void *buffer)
86{ 86{
87 struct efi_blk_priv *priv = dev->priv; 87 struct efi_blk_platdata *platdata = dev_get_platdata(dev);
88 struct efi_block_io *io = priv->io; 88 struct efi_block_io *io = platdata->io;
89 efi_status_t ret; 89 efi_status_t ret;
90 90
91 EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n", 91 EFI_PRINT("%s: write '%s', from block " LBAFU ", " LBAFU " blocks\n",
@@ -135,7 +135,7 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
135 struct efi_object *obj = efi_search_obj(handle); 135 struct efi_object *obj = efi_search_obj(handle);
136 struct efi_block_io *io = interface; 136 struct efi_block_io *io = interface;
137 int disks; 137 int disks;
138 struct efi_blk_priv *priv; 138 struct efi_blk_platdata *platdata;
139 139
140 EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io); 140 EFI_PRINT("%s: handle %p, interface %p\n", __func__, handle, io);
141 141
@@ -163,18 +163,16 @@ static int efi_bl_bind(efi_handle_t handle, void *interface)
163 return -ENOENT; 163 return -ENOENT;
164 /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */ 164 /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */
165 device_set_name_alloced(bdev); 165 device_set_name_alloced(bdev);
166 /* Allocate priv */ 166
167 platdata = dev_get_platdata(bdev);
168 platdata->handle = handle;
169 platdata->io = interface;
170
167 ret = device_probe(bdev); 171 ret = device_probe(bdev);
168 if (ret) 172 if (ret)
169 return ret; 173 return ret;
170 EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name); 174 EFI_PRINT("%s: block device '%s' created\n", __func__, bdev->name);
171 175
172 priv = bdev->priv;
173 priv->handle = handle;
174 priv->io = interface;
175
176 ret = blk_prepare_device(bdev);
177
178 /* Create handles for the partions of the block device */ 176 /* Create handles for the partions of the block device */
179 disks = efi_bl_bind_partitions(handle, bdev); 177 disks = efi_bl_bind_partitions(handle, bdev);
180 EFI_PRINT("Found %d partitions\n", disks); 178 EFI_PRINT("Found %d partitions\n", disks);
@@ -193,7 +191,7 @@ U_BOOT_DRIVER(efi_blk) = {
193 .name = "efi_blk", 191 .name = "efi_blk",
194 .id = UCLASS_BLK, 192 .id = UCLASS_BLK,
195 .ops = &efi_blk_ops, 193 .ops = &efi_blk_ops,
196 .priv_auto_alloc_size = sizeof(struct efi_blk_priv), 194 .platdata_auto_alloc_size = sizeof(struct efi_blk_platdata),
197}; 195};
198 196
199/* EFI driver operators */ 197/* EFI driver operators */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index b490cf2862..213e0fda94 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -53,4 +53,5 @@ obj-$(CONFIG_MISC) += misc.o
53obj-$(CONFIG_DM_SERIAL) += serial.o 53obj-$(CONFIG_DM_SERIAL) += serial.o
54obj-$(CONFIG_CPU) += cpu.o 54obj-$(CONFIG_CPU) += cpu.o
55obj-$(CONFIG_TEE) += tee.o 55obj-$(CONFIG_TEE) += tee.o
56obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
56endif 57endif
diff --git a/test/dm/blk.c b/test/dm/blk.c
index 4de477bafa..9c71adc69d 100644
--- a/test/dm/blk.c
+++ b/test/dm/blk.c
@@ -15,34 +15,29 @@ DECLARE_GLOBAL_DATA_PTR;
15/* Test that block devices can be created */ 15/* Test that block devices can be created */
16static int dm_test_blk_base(struct unit_test_state *uts) 16static int dm_test_blk_base(struct unit_test_state *uts)
17{ 17{
18 struct udevice *blk, *usb_blk, *dev; 18 struct udevice *blk1, *blk3, *dev;
19 19
20 /* Make sure there are no block devices */ 20 /* Make sure there are no block devices */
21 ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_BLK, 0, &blk)); 21 ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_BLK, 0, &dev));
22 22
23 /* Create two, one the parent of the other */ 23 /* Create two, one the parent of the other */
24 ut_assertok(blk_create_device(gd->dm_root, "sandbox_host_blk", "test", 24 ut_assertok(blk_create_device(gd->dm_root, "sandbox_host_blk", "test",
25 IF_TYPE_HOST, 1, 512, 2, &blk)); 25 IF_TYPE_HOST, 1, 512, 2, &blk1));
26 ut_assertok(blk_create_device(blk, "usb_storage_blk", "test", 26 ut_assertok(blk_create_device(blk1, "sandbox_host_blk", "test",
27 IF_TYPE_USB, 3, 512, 2, &usb_blk)); 27 IF_TYPE_HOST, 3, 512, 2, &blk3));
28 28
29 /* Check we can find them */ 29 /* Check we can find them */
30 ut_asserteq(-ENODEV, blk_get_device(IF_TYPE_HOST, 0, &dev)); 30 ut_asserteq(-ENODEV, blk_get_device(IF_TYPE_HOST, 0, &dev));
31 ut_assertok(blk_get_device(IF_TYPE_HOST, 1, &dev)); 31 ut_assertok(blk_get_device(IF_TYPE_HOST, 1, &dev));
32 ut_asserteq_ptr(blk, dev); 32 ut_asserteq_ptr(blk1, dev);
33 33 ut_assertok(blk_get_device(IF_TYPE_HOST, 3, &dev));
34 ut_asserteq(-ENODEV, blk_get_device(IF_TYPE_USB, 0, &dev)); 34 ut_asserteq_ptr(blk3, dev);
35 ut_assertok(blk_get_device(IF_TYPE_USB, 3, &dev));
36 ut_asserteq_ptr(usb_blk, dev);
37 35
38 /* Check we can iterate */ 36 /* Check we can iterate */
39 ut_assertok(blk_first_device(IF_TYPE_HOST, &dev)); 37 ut_assertok(blk_first_device(IF_TYPE_HOST, &dev));
40 ut_asserteq_ptr(blk, dev); 38 ut_asserteq_ptr(blk1, dev);
41 ut_asserteq(-ENODEV, blk_next_device(&dev)); 39 ut_assertok(blk_next_device(&dev));
42 40 ut_asserteq_ptr(blk3, dev);
43 ut_assertok(blk_first_device(IF_TYPE_USB, &dev));
44 ut_asserteq_ptr(usb_blk, dev);
45 ut_asserteq(-ENODEV, blk_next_device(&dev));
46 41
47 return 0; 42 return 0;
48} 43}
diff --git a/test/dm/bus.c b/test/dm/bus.c
index 08137a2216..93f3acd430 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -63,6 +63,15 @@ static int testbus_child_pre_probe_uclass(struct udevice *dev)
63 return 0; 63 return 0;
64} 64}
65 65
66static int testbus_child_post_probe_uclass(struct udevice *dev)
67{
68 struct dm_test_priv *priv = dev_get_priv(dev);
69
70 priv->uclass_postp++;
71
72 return 0;
73}
74
66static int testbus_child_post_remove(struct udevice *dev) 75static int testbus_child_post_remove(struct udevice *dev)
67{ 76{
68 struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev); 77 struct dm_test_parent_data *parent_data = dev_get_parent_priv(dev);
@@ -102,12 +111,13 @@ UCLASS_DRIVER(testbus) = {
102 .id = UCLASS_TEST_BUS, 111 .id = UCLASS_TEST_BUS,
103 .flags = DM_UC_FLAG_SEQ_ALIAS, 112 .flags = DM_UC_FLAG_SEQ_ALIAS,
104 .child_pre_probe = testbus_child_pre_probe_uclass, 113 .child_pre_probe = testbus_child_pre_probe_uclass,
114 .child_post_probe = testbus_child_post_probe_uclass,
105}; 115};
106 116
107/* Test that we can probe for children */ 117/* Test that we can probe for children */
108static int dm_test_bus_children(struct unit_test_state *uts) 118static int dm_test_bus_children(struct unit_test_state *uts)
109{ 119{
110 int num_devices = 7; 120 int num_devices = 8;
111 struct udevice *bus; 121 struct udevice *bus;
112 struct uclass *uc; 122 struct uclass *uc;
113 123
@@ -547,3 +557,38 @@ static int dm_test_bus_child_pre_probe_uclass(struct unit_test_state *uts)
547} 557}
548DM_TEST(dm_test_bus_child_pre_probe_uclass, 558DM_TEST(dm_test_bus_child_pre_probe_uclass,
549 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 559 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
560
561/*
562 * Test that the bus' uclass' child_post_probe() is called after the
563 * device's probe() method
564 */
565static int dm_test_bus_child_post_probe_uclass(struct unit_test_state *uts)
566{
567 struct udevice *bus, *dev;
568 int child_count;
569
570 /*
571 * See testfdt_drv_probe() which effectively initializes that
572 * the uclass postp flag is set to a value
573 */
574 ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
575 for (device_find_first_child(bus, &dev), child_count = 0;
576 dev;
577 device_find_next_child(&dev)) {
578 struct dm_test_priv *priv = dev_get_priv(dev);
579
580 /* Check that things happened in the right order */
581 ut_asserteq_ptr(NULL, priv);
582 ut_assertok(device_probe(dev));
583
584 priv = dev_get_priv(dev);
585 ut_assert(priv != NULL);
586 ut_asserteq(0, priv->uclass_postp);
587 child_count++;
588 }
589 ut_asserteq(3, child_count);
590
591 return 0;
592}
593DM_TEST(dm_test_bus_child_post_probe_uclass,
594 DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/pci.c b/test/dm/pci.c
index a1dedd84a7..a1febd54b7 100644
--- a/test/dm/pci.c
+++ b/test/dm/pci.c
@@ -211,6 +211,16 @@ static int dm_test_pci_cap(struct unit_test_state *uts)
211 cap = dm_pci_find_capability(swap, PCI_CAP_ID_PCIX); 211 cap = dm_pci_find_capability(swap, PCI_CAP_ID_PCIX);
212 ut_asserteq(0, cap); 212 ut_asserteq(0, cap);
213 213
214 /* look up PCI_CAP_ID_MSIX starting from PCI_CAP_ID_PM_OFFSET */
215 cap = dm_pci_find_next_capability(swap, PCI_CAP_ID_PM_OFFSET,
216 PCI_CAP_ID_MSIX);
217 ut_asserteq(PCI_CAP_ID_MSIX_OFFSET, cap);
218
219 /* look up PCI_CAP_ID_VNDR starting from PCI_CAP_ID_EXP_OFFSET */
220 cap = dm_pci_find_next_capability(swap, PCI_CAP_ID_EXP_OFFSET,
221 PCI_CAP_ID_VNDR);
222 ut_asserteq(0, cap);
223
214 ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus)); 224 ut_assertok(uclass_get_device_by_seq(UCLASS_PCI, 1, &bus));
215 ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &swap)); 225 ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(1, 0x08, 0), &swap));
216 226
@@ -222,6 +232,16 @@ static int dm_test_pci_cap(struct unit_test_state *uts)
222 cap = dm_pci_find_ext_capability(swap, PCI_EXT_CAP_ID_SRIOV); 232 cap = dm_pci_find_ext_capability(swap, PCI_EXT_CAP_ID_SRIOV);
223 ut_asserteq(0, cap); 233 ut_asserteq(0, cap);
224 234
235 /* look up PCI_EXT_CAP_ID_DSN starting from PCI_EXT_CAP_ID_ERR_OFFSET */
236 cap = dm_pci_find_next_ext_capability(swap, PCI_EXT_CAP_ID_ERR_OFFSET,
237 PCI_EXT_CAP_ID_DSN);
238 ut_asserteq(PCI_EXT_CAP_ID_DSN_OFFSET, cap);
239
240 /* look up PCI_EXT_CAP_ID_RCRB starting from PCI_EXT_CAP_ID_VC_OFFSET */
241 cap = dm_pci_find_next_ext_capability(swap, PCI_EXT_CAP_ID_VC_OFFSET,
242 PCI_EXT_CAP_ID_RCRB);
243 ut_asserteq(0, cap);
244
225 return 0; 245 return 0;
226} 246}
227DM_TEST(dm_test_pci_cap, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 247DM_TEST(dm_test_pci_cap, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/regmap.c b/test/dm/regmap.c
index d4b86b3b03..a8d7e6829e 100644
--- a/test/dm/regmap.c
+++ b/test/dm/regmap.c
@@ -25,7 +25,7 @@ static int dm_test_regmap_base(struct unit_test_state *uts)
25 ut_assertok_ptr(map); 25 ut_assertok_ptr(map);
26 ut_asserteq(1, map->range_count); 26 ut_asserteq(1, map->range_count);
27 ut_asserteq(0x10, map->ranges[0].start); 27 ut_asserteq(0x10, map->ranges[0].start);
28 ut_asserteq(4, map->ranges[0].size); 28 ut_asserteq(16, map->ranges[0].size);
29 ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0))); 29 ut_asserteq(0x10, map_to_sysmem(regmap_get_range(map, 0)));
30 30
31 ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev)); 31 ut_assertok(uclass_get_device(UCLASS_SYSCON, 1, &dev));
@@ -116,3 +116,31 @@ static int dm_test_regmap_rw(struct unit_test_state *uts)
116} 116}
117 117
118DM_TEST(dm_test_regmap_rw, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); 118DM_TEST(dm_test_regmap_rw, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
119
120/* Get/Set test */
121static int dm_test_regmap_getset(struct unit_test_state *uts)
122{
123 struct udevice *dev;
124 struct regmap *map;
125 uint reg;
126 struct layout {
127 u32 val0;
128 u32 val1;
129 u32 val2;
130 u32 val3;
131 };
132
133 ut_assertok(uclass_get_device(UCLASS_SYSCON, 0, &dev));
134 map = syscon_get_regmap(dev);
135 ut_assertok_ptr(map);
136
137 regmap_set(map, struct layout, val0, 0xcacafafa);
138 regmap_set(map, struct layout, val3, 0x55aa2211);
139
140 ut_assertok(regmap_get(map, struct layout, val0, &reg));
141 ut_assertok(regmap_get(map, struct layout, val3, &reg));
142
143 return 0;
144}
145
146DM_TEST(dm_test_regmap_getset, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 79b1f1de45..e43acb21d5 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -55,10 +55,13 @@ static int testfdt_drv_probe(struct udevice *dev)
55 55
56 /* 56 /*
57 * If this device is on a bus, the uclass_flag will be set before 57 * If this device is on a bus, the uclass_flag will be set before
58 * calling this function. This is used by 58 * calling this function. In the meantime the uclass_postp is
59 * dm_test_bus_child_pre_probe_uclass(). 59 * initlized to a value -1. These are used respectively by
60 * dm_test_bus_child_pre_probe_uclass() and
61 * dm_test_bus_child_post_probe_uclass().
60 */ 62 */
61 priv->uclass_total += priv->uclass_flag; 63 priv->uclass_total += priv->uclass_flag;
64 priv->uclass_postp = -1;
62 65
63 return 0; 66 return 0;
64} 67}
@@ -84,6 +87,25 @@ U_BOOT_DRIVER(testfdt_drv) = {
84 .platdata_auto_alloc_size = sizeof(struct dm_test_pdata), 87 .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
85}; 88};
86 89
90static const struct udevice_id testfdt1_ids[] = {
91 {
92 .compatible = "denx,u-boot-fdt-test1",
93 .data = DM_TEST_TYPE_FIRST },
94 { }
95};
96
97U_BOOT_DRIVER(testfdt1_drv) = {
98 .name = "testfdt1_drv",
99 .of_match = testfdt1_ids,
100 .id = UCLASS_TEST_FDT,
101 .ofdata_to_platdata = testfdt_ofdata_to_platdata,
102 .probe = testfdt_drv_probe,
103 .ops = &test_ops,
104 .priv_auto_alloc_size = sizeof(struct dm_test_priv),
105 .platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
106 .flags = DM_FLAG_PRE_RELOC,
107};
108
87/* From here is the testfdt uclass code */ 109/* From here is the testfdt uclass code */
88int testfdt_ping(struct udevice *dev, int pingval, int *pingret) 110int testfdt_ping(struct udevice *dev, int pingval, int *pingret)
89{ 111{
@@ -168,7 +190,7 @@ int dm_check_devices(struct unit_test_state *uts, int num_devices)
168/* Test that FDT-based binding works correctly */ 190/* Test that FDT-based binding works correctly */
169static int dm_test_fdt(struct unit_test_state *uts) 191static int dm_test_fdt(struct unit_test_state *uts)
170{ 192{
171 const int num_devices = 7; 193 const int num_devices = 8;
172 struct udevice *dev; 194 struct udevice *dev;
173 struct uclass *uc; 195 struct uclass *uc;
174 int ret; 196 int ret;
@@ -208,8 +230,12 @@ static int dm_test_fdt_pre_reloc(struct unit_test_state *uts)
208 ret = uclass_get(UCLASS_TEST_FDT, &uc); 230 ret = uclass_get(UCLASS_TEST_FDT, &uc);
209 ut_assert(!ret); 231 ut_assert(!ret);
210 232
211 /* These is only one pre-reloc device */ 233 /*
212 ut_asserteq(1, list_count_items(&uc->dev_head)); 234 * These are 2 pre-reloc devices:
235 * one with "u-boot,dm-pre-reloc" property (a-test node), and the other
236 * one whose driver marked with DM_FLAG_PRE_RELOC flag (h-test node).
237 */
238 ut_asserteq(2, list_count_items(&uc->dev_head));
213 239
214 return 0; 240 return 0;
215} 241}
diff --git a/test/dm/virtio.c b/test/dm/virtio.c
new file mode 100644
index 0000000000..4b317d2ec3
--- /dev/null
+++ b/test/dm/virtio.c
@@ -0,0 +1,122 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <virtio_types.h>
9#include <virtio.h>
10#include <virtio_ring.h>
11#include <dm/device-internal.h>
12#include <dm/uclass-internal.h>
13#include <dm/root.h>
14#include <dm/test.h>
15#include <test/ut.h>
16
17/* Basic test of the virtio uclass */
18static int dm_test_virtio_base(struct unit_test_state *uts)
19{
20 struct udevice *bus, *dev;
21 u8 status;
22
23 /* check probe success */
24 ut_assertok(uclass_first_device(UCLASS_VIRTIO, &bus));
25
26 /* check the child virtio-blk device is bound */
27 ut_assertok(device_find_first_child(bus, &dev));
28 ut_assertok(strcmp(dev->name, "virtio-blk#0"));
29
30 /* check driver status */
31 ut_assertok(virtio_get_status(dev, &status));
32 ut_asserteq(VIRTIO_CONFIG_S_ACKNOWLEDGE, status);
33
34 return 0;
35}
36DM_TEST(dm_test_virtio_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
37
38/* Test all of the virtio uclass ops */
39static int dm_test_virtio_all_ops(struct unit_test_state *uts)
40{
41 struct udevice *bus, *dev;
42 struct virtio_dev_priv *uc_priv;
43 uint offset = 0, len = 0, nvqs = 1;
44 void *buffer = NULL;
45 u8 status;
46 u32 counter;
47 u64 features;
48 struct virtqueue *vqs[2];
49
50 /* check probe success */
51 ut_assertok(uclass_first_device(UCLASS_VIRTIO, &bus));
52
53 /* check the child virtio-blk device is bound */
54 ut_assertok(device_find_first_child(bus, &dev));
55
56 /*
57 * fake the virtio device probe by filling in uc_priv->vdev
58 * which is used by virtio_find_vqs/virtio_del_vqs.
59 */
60 uc_priv = dev_get_uclass_priv(bus);
61 uc_priv->vdev = dev;
62
63 /* test virtio_xxx APIs */
64 ut_assertok(virtio_get_config(dev, offset, buffer, len));
65 ut_assertok(virtio_set_config(dev, offset, buffer, len));
66 ut_asserteq(-ENOSYS, virtio_generation(dev, &counter));
67 ut_assertok(virtio_set_status(dev, VIRTIO_CONFIG_S_DRIVER_OK));
68 ut_assertok(virtio_get_status(dev, &status));
69 ut_asserteq(VIRTIO_CONFIG_S_DRIVER_OK, status);
70 ut_assertok(virtio_reset(dev));
71 ut_assertok(virtio_get_status(dev, &status));
72 ut_asserteq(0, status);
73 ut_assertok(virtio_get_features(dev, &features));
74 ut_asserteq(VIRTIO_F_VERSION_1, features);
75 ut_assertok(virtio_set_features(dev));
76 ut_assertok(virtio_find_vqs(dev, nvqs, vqs));
77 ut_assertok(virtio_del_vqs(dev));
78 ut_assertok(virtio_notify(dev, vqs[0]));
79
80 return 0;
81}
82DM_TEST(dm_test_virtio_all_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
83
84/* Test of the virtio driver that does not have required driver ops */
85static int dm_test_virtio_missing_ops(struct unit_test_state *uts)
86{
87 struct udevice *bus;
88
89 /* find the virtio device */
90 ut_assertok(uclass_find_device(UCLASS_VIRTIO, 1, &bus));
91
92 /*
93 * Probe the device should fail with error -ENOENT.
94 * See ops check in virtio_uclass_pre_probe().
95 */
96 ut_asserteq(-ENOENT, device_probe(bus));
97
98 return 0;
99}
100DM_TEST(dm_test_virtio_missing_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
101
102/* Test removal of virtio device driver */
103static int dm_test_virtio_remove(struct unit_test_state *uts)
104{
105 struct udevice *bus, *dev;
106
107 /* check probe success */
108 ut_assertok(uclass_first_device(UCLASS_VIRTIO, &bus));
109
110 /* check the child virtio-blk device is bound */
111 ut_assertok(device_find_first_child(bus, &dev));
112
113 /* set driver status to VIRTIO_CONFIG_S_DRIVER_OK */
114 ut_assertok(virtio_set_status(dev, VIRTIO_CONFIG_S_DRIVER_OK));
115
116 /* check the device can be successfully removed */
117 dev->flags |= DM_FLAG_ACTIVATED;
118 ut_assertok(device_remove(bus, DM_REMOVE_ACTIVE_ALL));
119
120 return 0;
121}
122DM_TEST(dm_test_virtio_remove, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/tools/buildman/README b/tools/buildman/README
index 76601902cb..5a709c6ff9 100644
--- a/tools/buildman/README
+++ b/tools/buildman/README
@@ -114,6 +114,10 @@ a few commits or boards, it will be pretty slow. As a tip, if you don't
114plan to use your machine for anything else, you can use -T to increase the 114plan to use your machine for anything else, you can use -T to increase the
115number of threads beyond the default. 115number of threads beyond the default.
116 116
117
118Selecting which boards to build
119===============================
120
117Buildman lets you build all boards, or a subset. Specify the subset by passing 121Buildman lets you build all boards, or a subset. Specify the subset by passing
118command-line arguments that list the desired board name, architecture name, 122command-line arguments that list the desired board name, architecture name,
119SOC name, or anything else in the boards.cfg file. Multiple arguments are 123SOC name, or anything else in the boards.cfg file. Multiple arguments are
@@ -138,11 +142,17 @@ You can also use -x to specifically exclude some boards. For example:
138means to build all arm boards except nvidia, freescale and anything ending 142means to build all arm boards except nvidia, freescale and anything ending
139with 'ball'. 143with 'ball'.
140 144
145For building specific boards you can use the --boards option, which takes a
146comma-separated list of board target names and be used multiple times on
147the command line:
148
149 buidman --boards sandbox,snow --boards
150
141It is convenient to use the -n option to see what will be built based on 151It is convenient to use the -n option to see what will be built based on
142the subset given. Use -v as well to get an actual list of boards. 152the subset given. Use -v as well to get an actual list of boards.
143 153
144Buildman does not store intermediate object files. It optionally copies 154Buildman does not store intermediate object files. It optionally copies
145the binary output into a directory when a build is successful. Size 155the binary output into a directory when a build is successful (-k). Size
146information is always recorded. It needs a fair bit of disk space to work, 156information is always recorded. It needs a fair bit of disk space to work,
147typically 250MB per thread. 157typically 250MB per thread.
148 158
diff --git a/tools/buildman/board.py b/tools/buildman/board.py
index 272bac0c21..2a1d021574 100644
--- a/tools/buildman/board.py
+++ b/tools/buildman/board.py
@@ -237,20 +237,30 @@ class Boards:
237 terms.append(term) 237 terms.append(term)
238 return terms 238 return terms
239 239
240 def SelectBoards(self, args, exclude=[]): 240 def SelectBoards(self, args, exclude=[], boards=None):
241 """Mark boards selected based on args 241 """Mark boards selected based on args
242 242
243 Normally either boards (an explicit list of boards) or args (a list of
244 terms to match against) is used. It is possible to specify both, in
245 which case they are additive.
246
247 If boards and args are both empty, all boards are selected.
248
243 Args: 249 Args:
244 args: List of strings specifying boards to include, either named, 250 args: List of strings specifying boards to include, either named,
245 or by their target, architecture, cpu, vendor or soc. If 251 or by their target, architecture, cpu, vendor or soc. If
246 empty, all boards are selected. 252 empty, all boards are selected.
247 exclude: List of boards to exclude, regardless of 'args' 253 exclude: List of boards to exclude, regardless of 'args'
254 boards: List of boards to build
248 255
249 Returns: 256 Returns:
250 Dictionary which holds the list of boards which were selected 257 Tuple
251 due to each argument, arranged by argument. 258 Dictionary which holds the list of boards which were selected
259 due to each argument, arranged by argument.
260 List of errors found
252 """ 261 """
253 result = {} 262 result = {}
263 warnings = []
254 terms = self._BuildTerms(args) 264 terms = self._BuildTerms(args)
255 265
256 result['all'] = [] 266 result['all'] = []
@@ -261,6 +271,7 @@ class Boards:
261 for expr in exclude: 271 for expr in exclude:
262 exclude_list.append(Expr(expr)) 272 exclude_list.append(Expr(expr))
263 273
274 found = []
264 for board in self._boards: 275 for board in self._boards:
265 matching_term = None 276 matching_term = None
266 build_it = False 277 build_it = False
@@ -271,6 +282,10 @@ class Boards:
271 matching_term = str(term) 282 matching_term = str(term)
272 build_it = True 283 build_it = True
273 break 284 break
285 elif boards:
286 if board.target in boards:
287 build_it = True
288 found.append(board.target)
274 else: 289 else:
275 build_it = True 290 build_it = True
276 291
@@ -286,4 +301,9 @@ class Boards:
286 result[matching_term].append(board.target) 301 result[matching_term].append(board.target)
287 result['all'].append(board.target) 302 result['all'].append(board.target)
288 303
289 return result 304 if boards:
305 remaining = set(boards) - set(found)
306 if remaining:
307 warnings.append('Boards not found: %s\n' % ', '.join(remaining))
308
309 return result, warnings
diff --git a/tools/buildman/cmdline.py b/tools/buildman/cmdline.py
index e493b1ac4a..49a8a13118 100644
--- a/tools/buildman/cmdline.py
+++ b/tools/buildman/cmdline.py
@@ -18,6 +18,8 @@ def ParseArgs():
18 parser.add_option('-B', '--bloat', dest='show_bloat', 18 parser.add_option('-B', '--bloat', dest='show_bloat',
19 action='store_true', default=False, 19 action='store_true', default=False,
20 help='Show changes in function code size for each board') 20 help='Show changes in function code size for each board')
21 parser.add_option('--boards', type='string', action='append',
22 help='List of board names to build separated by comma')
21 parser.add_option('-c', '--count', dest='count', type='int', 23 parser.add_option('-c', '--count', dest='count', type='int',
22 default=-1, help='Run build on the top n commits') 24 default=-1, help='Run build on the top n commits')
23 parser.add_option('-C', '--force-reconfig', dest='force_reconfig', 25 parser.add_option('-C', '--force-reconfig', dest='force_reconfig',
@@ -102,7 +104,7 @@ def ParseArgs():
102 type='string', action='append', 104 type='string', action='append',
103 help='Specify a list of boards to exclude, separated by comma') 105 help='Specify a list of boards to exclude, separated by comma')
104 106
105 parser.usage += """ 107 parser.usage += """ [list of target/arch/cpu/board/vendor/soc to build]
106 108
107 Build U-Boot for all commits in a branch. Use -n to do a dry run""" 109 Build U-Boot for all commits in a branch. Use -n to do a dry run"""
108 110
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index bc0819784f..96f8ccfe07 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -41,7 +41,8 @@ def GetActionSummary(is_summary, commits, selected, options):
41 GetPlural(options.threads), options.jobs, GetPlural(options.jobs)) 41 GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
42 return str 42 return str
43 43
44def ShowActions(series, why_selected, boards_selected, builder, options): 44def ShowActions(series, why_selected, boards_selected, builder, options,
45 board_warnings):
45 """Display a list of actions that we would take, if not a dry run. 46 """Display a list of actions that we would take, if not a dry run.
46 47
47 Args: 48 Args:
@@ -55,6 +56,7 @@ def ShowActions(series, why_selected, boards_selected, builder, options):
55 value is Board object 56 value is Board object
56 builder: The builder that will be used to build the commits 57 builder: The builder that will be used to build the commits
57 options: Command line options object 58 options: Command line options object
59 board_warnings: List of warnings obtained from board selected
58 """ 60 """
59 col = terminal.Color() 61 col = terminal.Color()
60 print 'Dry run, so not doing much. But I would do this:' 62 print 'Dry run, so not doing much. But I would do this:'
@@ -79,6 +81,9 @@ def ShowActions(series, why_selected, boards_selected, builder, options):
79 print ' %s' % ' '.join(why_selected[arg]) 81 print ' %s' % ' '.join(why_selected[arg])
80 print ('Total boards to build for each commit: %d\n' % 82 print ('Total boards to build for each commit: %d\n' %
81 len(why_selected['all'])) 83 len(why_selected['all']))
84 if board_warnings:
85 for warning in board_warnings:
86 print col.Color(col.YELLOW, warning)
82 87
83def CheckOutputDir(output_dir): 88def CheckOutputDir(output_dir):
84 """Make sure that the output directory is not within the current directory 89 """Make sure that the output directory is not within the current directory
@@ -210,7 +215,15 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
210 for arg in options.exclude: 215 for arg in options.exclude:
211 exclude += arg.split(',') 216 exclude += arg.split(',')
212 217
213 why_selected = boards.SelectBoards(args, exclude) 218
219 if options.boards:
220 requested_boards = []
221 for b in options.boards:
222 requested_boards += b.split(',')
223 else:
224 requested_boards = None
225 why_selected, board_warnings = boards.SelectBoards(args, exclude,
226 requested_boards)
214 selected = boards.GetSelected() 227 selected = boards.GetSelected()
215 if not len(selected): 228 if not len(selected):
216 sys.exit(col.Color(col.RED, 'No matching boards found')) 229 sys.exit(col.Color(col.RED, 'No matching boards found'))
@@ -292,7 +305,8 @@ def DoBuildman(options, args, toolchains=None, make_func=None, boards=None,
292 305
293 # For a dry run, just show our actions as a sanity check 306 # For a dry run, just show our actions as a sanity check
294 if options.dry_run: 307 if options.dry_run:
295 ShowActions(series, why_selected, selected, builder, options) 308 ShowActions(series, why_selected, selected, builder, options,
309 board_warnings)
296 else: 310 else:
297 builder.force_build = options.force_build 311 builder.force_build = options.force_build
298 builder.force_build_failures = options.force_build_failures 312 builder.force_build_failures = options.force_build_failures
diff --git a/tools/buildman/test.py b/tools/buildman/test.py
index e0c9d6da6a..61a462655f 100644
--- a/tools/buildman/test.py
+++ b/tools/buildman/test.py
@@ -313,60 +313,63 @@ class TestBuild(unittest.TestCase):
313 def testBoardSingle(self): 313 def testBoardSingle(self):
314 """Test single board selection""" 314 """Test single board selection"""
315 self.assertEqual(self.boards.SelectBoards(['sandbox']), 315 self.assertEqual(self.boards.SelectBoards(['sandbox']),
316 {'all': ['board4'], 'sandbox': ['board4']}) 316 ({'all': ['board4'], 'sandbox': ['board4']}, []))
317 317
318 def testBoardArch(self): 318 def testBoardArch(self):
319 """Test single board selection""" 319 """Test single board selection"""
320 self.assertEqual(self.boards.SelectBoards(['arm']), 320 self.assertEqual(self.boards.SelectBoards(['arm']),
321 {'all': ['board0', 'board1'], 321 ({'all': ['board0', 'board1'],
322 'arm': ['board0', 'board1']}) 322 'arm': ['board0', 'board1']}, []))
323 323
324 def testBoardArchSingle(self): 324 def testBoardArchSingle(self):
325 """Test single board selection""" 325 """Test single board selection"""
326 self.assertEqual(self.boards.SelectBoards(['arm sandbox']), 326 self.assertEqual(self.boards.SelectBoards(['arm sandbox']),
327 {'sandbox': ['board4'], 327 ({'sandbox': ['board4'],
328 'all': ['board0', 'board1', 'board4'], 328 'all': ['board0', 'board1', 'board4'],
329 'arm': ['board0', 'board1']}) 329 'arm': ['board0', 'board1']}, []))
330 330
331 331
332 def testBoardArchSingleMultiWord(self): 332 def testBoardArchSingleMultiWord(self):
333 """Test single board selection""" 333 """Test single board selection"""
334 self.assertEqual(self.boards.SelectBoards(['arm', 'sandbox']), 334 self.assertEqual(self.boards.SelectBoards(['arm', 'sandbox']),
335 {'sandbox': ['board4'], 'all': ['board0', 'board1', 'board4'], 'arm': ['board0', 'board1']}) 335 ({'sandbox': ['board4'],
336 'all': ['board0', 'board1', 'board4'],
337 'arm': ['board0', 'board1']}, []))
336 338
337 def testBoardSingleAnd(self): 339 def testBoardSingleAnd(self):
338 """Test single board selection""" 340 """Test single board selection"""
339 self.assertEqual(self.boards.SelectBoards(['Tester & arm']), 341 self.assertEqual(self.boards.SelectBoards(['Tester & arm']),
340 {'Tester&arm': ['board0', 'board1'], 'all': ['board0', 'board1']}) 342 ({'Tester&arm': ['board0', 'board1'],
343 'all': ['board0', 'board1']}, []))
341 344
342 def testBoardTwoAnd(self): 345 def testBoardTwoAnd(self):
343 """Test single board selection""" 346 """Test single board selection"""
344 self.assertEqual(self.boards.SelectBoards(['Tester', '&', 'arm', 347 self.assertEqual(self.boards.SelectBoards(['Tester', '&', 'arm',
345 'Tester' '&', 'powerpc', 348 'Tester' '&', 'powerpc',
346 'sandbox']), 349 'sandbox']),
347 {'sandbox': ['board4'], 350 ({'sandbox': ['board4'],
348 'all': ['board0', 'board1', 'board2', 'board3', 351 'all': ['board0', 'board1', 'board2', 'board3',
349 'board4'], 352 'board4'],
350 'Tester&powerpc': ['board2', 'board3'], 353 'Tester&powerpc': ['board2', 'board3'],
351 'Tester&arm': ['board0', 'board1']}) 354 'Tester&arm': ['board0', 'board1']}, []))
352 355
353 def testBoardAll(self): 356 def testBoardAll(self):
354 """Test single board selection""" 357 """Test single board selection"""
355 self.assertEqual(self.boards.SelectBoards([]), 358 self.assertEqual(self.boards.SelectBoards([]),
356 {'all': ['board0', 'board1', 'board2', 'board3', 359 ({'all': ['board0', 'board1', 'board2', 'board3',
357 'board4']}) 360 'board4']}, []))
358 361
359 def testBoardRegularExpression(self): 362 def testBoardRegularExpression(self):
360 """Test single board selection""" 363 """Test single board selection"""
361 self.assertEqual(self.boards.SelectBoards(['T.*r&^Po']), 364 self.assertEqual(self.boards.SelectBoards(['T.*r&^Po']),
362 {'all': ['board2', 'board3'], 365 ({'all': ['board2', 'board3'],
363 'T.*r&^Po': ['board2', 'board3']}) 366 'T.*r&^Po': ['board2', 'board3']}, []))
364 367
365 def testBoardDuplicate(self): 368 def testBoardDuplicate(self):
366 """Test single board selection""" 369 """Test single board selection"""
367 self.assertEqual(self.boards.SelectBoards(['sandbox sandbox', 370 self.assertEqual(self.boards.SelectBoards(['sandbox sandbox',
368 'sandbox']), 371 'sandbox']),
369 {'all': ['board4'], 'sandbox': ['board4']}) 372 ({'all': ['board4'], 'sandbox': ['board4']}, []))
370 def CheckDirs(self, build, dirname): 373 def CheckDirs(self, build, dirname):
371 self.assertEqual('base%s' % dirname, build._GetOutputDir(1)) 374 self.assertEqual('base%s' % dirname, build._GetOutputDir(1))
372 self.assertEqual('base%s/fred' % dirname, 375 self.assertEqual('base%s/fred' % dirname,