Merge tag 'mmc-9-6-2019' of https://gitlab.denx.de/u-boot/custodians/u-boot-mmc

Bug fixes to mmc_spi
Add Aspeed SD driver
Fix dw_mmc timeout calculation
Fix timeout values passed to mmc_wait_dat0
sdhci dt caps/mask update

[trini: Fix evb-ast2500_defconfig CONFIG_MMC line]
Signed-off-by: Tom Rini <trini@konsulko.com>
diff --git a/Makefile b/Makefile
index c02accf..ae56e47 100644
--- a/Makefile
+++ b/Makefile
@@ -1026,6 +1026,17 @@
 	@echo >&2 "===================================================="
 endif
 endif
+ifneq ($(CONFIG_NET),)
+ifneq ($(CONFIG_DM_ETH),y)
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "This board does not use CONFIG_DM_ETH (Driver Model"
+	@echo >&2 "for Ethernet drivers). Please update the board to use"
+	@echo >&2 "CONFIG_DM_ETH before the v2020.07 release. Failure to"
+	@echo >&2 "update by the deadline may result in board removal."
+	@echo >&2 "See doc/driver-model/migration.rst for more info."
+	@echo >&2 "===================================================="
+endif
+endif
 	@# Check that this build does not use CONFIG options that we do not
 	@# know about unless they are in Kconfig. All the existing CONFIG
 	@# options are whitelisted, so new ones should not be added.
diff --git a/arch/Kconfig b/arch/Kconfig
index f4ada57..141e48b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -137,6 +137,7 @@
 config SH
 	bool "SuperH architecture"
 	select HAVE_PRIVATE_LIBGCC
+	select SUPPORT_OF_CONTROL
 
 config X86
 	bool "x86 architecture"
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
index 42d31fd..54d03ae 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
+++ b/arch/arm/cpu/armv8/fsl-layerscape/Kconfig
@@ -245,14 +245,6 @@
 config NXP_LSCH3_2
 	bool
 
-config FSL_MC_ENET
-	bool "Management Complex network"
-	depends on ARCH_LS2080A || ARCH_LS1088A || ARCH_LX2160A
-	default y
-	select RESV_RAM
-	help
-	  Enable Management Complex (MC) network
-
 menu "Layerscape architecture"
 	depends on FSL_LSCH2 || FSL_LSCH3
 
@@ -593,15 +585,6 @@
 	bool
 	depends on SYS_FSL_EC1 || SYS_FSL_EC2
 
-
-config SYS_MC_RSV_MEM_ALIGN
-	hex "Management Complex reserved memory alignment"
-	depends on RESV_RAM
-	default 0x20000000 if ARCH_LS2080A || ARCH_LS1088A || ARCH_LX2160A
-	help
-	  Reserved memory needs to be aligned for MC to use. Default value
-	  is 512MB.
-
 config SPL_LDSCRIPT
 	default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARCH_LS1043A || ARCH_LS1046A || ARCH_LS2080A
 
diff --git a/arch/arm/dts/armada-cp110-master.dtsi b/arch/arm/dts/armada-cp110-master.dtsi
index 551d00d..e4c17e9 100644
--- a/arch/arm/dts/armada-cp110-master.dtsi
+++ b/arch/arm/dts/armada-cp110-master.dtsi
@@ -96,6 +96,7 @@
 				#size-cells = <0>;
 				compatible = "marvell,orion-mdio";
 				reg = <0x12a200 0x10>;
+				device-name = "cpm-mdio";
 			};
 
 			cpm_syscon0: system-controller@440000 {
diff --git a/arch/arm/dts/armada-cp110-slave.dtsi b/arch/arm/dts/armada-cp110-slave.dtsi
index 2ea9004..2fbd7b5 100644
--- a/arch/arm/dts/armada-cp110-slave.dtsi
+++ b/arch/arm/dts/armada-cp110-slave.dtsi
@@ -96,6 +96,7 @@
 				#size-cells = <0>;
 				compatible = "marvell,orion-mdio";
 				reg = <0x12a200 0x10>;
+				device-name = "cps-mdio";
 			};
 
 			cps_syscon0: system-controller@440000 {
diff --git a/arch/arm/mach-bcm283x/Kconfig b/arch/arm/mach-bcm283x/Kconfig
index 3eb5a9a..b08275f 100644
--- a/arch/arm/mach-bcm283x/Kconfig
+++ b/arch/arm/mach-bcm283x/Kconfig
@@ -26,6 +26,23 @@
 	select BCM2837
 	select ARM64
 
+config BCM2711
+	bool "Broadcom BCM2711 SoC support"
+	depends on ARCH_BCM283X
+
+config BCM2711_32B
+	bool "Broadcom BCM2711 SoC 32-bit support"
+	depends on ARCH_BCM283X
+	select BCM2711
+	select ARMV7_LPAE
+	select CPU_V7A
+
+config BCM2711_64B
+	bool "Broadcom BCM2711 SoC 64-bit support"
+	depends on ARCH_BCM283X
+	select BCM2711
+	select ARM64
+
 menu "Broadcom BCM283X family"
 	depends on ARCH_BCM283X
 
@@ -127,6 +144,50 @@
 	  This option creates a build targeting the ARMv8/AArch64 ISA.
 	select BCM2837_64B
 
+config TARGET_RPI_4_32B
+	bool "Raspberry Pi 4 32-bit build"
+	help
+	  Support for all BCM2711-based Raspberry Pi variants, such as
+	  the RPi 4 model B, in AArch32 (32-bit) mode.
+
+	  This option assumes the VideoCore firmware is configured to use the
+	  mini UART (rather than PL011) for the serial console. This is the
+	  default on the RPi 4. To enable the UART console, the following non-
+	  default option must be present in config.txt: enable_uart=1. This is
+	  required for U-Boot to operate correctly, even if you only care
+	  about the HDMI/usbkbd console.
+
+	  Due to hardware incompatibilities, this can't be used with
+	  BCM283/5/6/7.
+
+	  This option creates a build targeting the ARMv7/AArch32 ISA.
+	select BCM2711_32B
+
+config TARGET_RPI_4
+	bool "Raspberry Pi 4 64-bit build"
+	help
+	  Support for all BCM2711-based Raspberry Pi variants, such as
+	  the RPi 4 model B, in AArch64 (64-bit) mode.
+
+	  This option assumes the VideoCore firmware is configured to use the
+	  mini UART (rather than PL011) for the serial console. This is the
+	  default on the RPi 4. To enable the UART console, the following non-
+	  default option must be present in config.txt: enable_uart=1. This is
+	  required for U-Boot to operate correctly, even if you only care
+	  about the HDMI/usbkbd console.
+
+	  Due to hardware incompatibilities, this can't be used with
+	  BCM283/5/6/7.
+
+	  Also, due to a bug in firmware, switching to 64bit mode doesn't
+	  happen automatically based on the kernel's image filename. See
+	  https://github.com/raspberrypi/firmware/issues/1193 for more details.
+	  Until that is resolved, the configuration (config.txt) needs to
+	  explicitly set: arm_64bit=1.
+
+	  This option creates a build targeting the ARMv8/AArch64 ISA.
+	select BCM2711_64B
+
 endchoice
 
 config SYS_BOARD
@@ -141,4 +202,10 @@
 config SYS_CONFIG_NAME
 	default "rpi"
 
+config BCM283x_BASE
+	hex
+	default "0x20000000" if BCM2835
+	default "0x3f000000" if BCM2836 || BCM2837
+	default "0xfe000000" if BCM2711
+
 endmenu
diff --git a/arch/arm/mach-bcm283x/include/mach/mbox.h b/arch/arm/mach-bcm283x/include/mach/mbox.h
index e3a893e..0b6c254 100644
--- a/arch/arm/mach-bcm283x/include/mach/mbox.h
+++ b/arch/arm/mach-bcm283x/include/mach/mbox.h
@@ -37,18 +37,17 @@
 
 /* Raw mailbox HW */
 
-#ifndef CONFIG_BCM2835
-#define BCM2835_MBOX_PHYSADDR	0x3f00b880
-#else
-#define BCM2835_MBOX_PHYSADDR	0x2000b880
-#endif
+#define BCM2835_MBOX_PHYSADDR	(CONFIG_BCM283x_BASE + 0x0000b880)
 
 struct bcm2835_mbox_regs {
 	u32 read;
 	u32 rsvd0[5];
-	u32 status;
-	u32 config;
+	u32 mail0_status;
+	u32 mail0_config;
 	u32 write;
+	u32 rsvd1[5];
+	u32 mail1_status;
+	u32 mail1_config;
 };
 
 #define BCM2835_MBOX_STATUS_WR_FULL	0x80000000
@@ -234,6 +233,7 @@
 #define BCM2835_MBOX_CLOCK_ID_SDRAM	8
 #define BCM2835_MBOX_CLOCK_ID_PIXEL	9
 #define BCM2835_MBOX_CLOCK_ID_PWM	10
+#define BCM2835_MBOX_CLOCK_ID_EMMC2	12
 
 struct bcm2835_mbox_tag_get_clock_rate {
 	struct bcm2835_mbox_tag_hdr tag_hdr;
diff --git a/arch/arm/mach-bcm283x/include/mach/sdhci.h b/arch/arm/mach-bcm283x/include/mach/sdhci.h
index 5cb6ec3..b443c37 100644
--- a/arch/arm/mach-bcm283x/include/mach/sdhci.h
+++ b/arch/arm/mach-bcm283x/include/mach/sdhci.h
@@ -6,11 +6,7 @@
 #ifndef _BCM2835_SDHCI_H_
 #define _BCM2835_SDHCI_H_
 
-#ifndef CONFIG_BCM2835
-#define BCM2835_SDHCI_BASE 0x3f300000
-#else
-#define BCM2835_SDHCI_BASE 0x20300000
-#endif
+#define BCM2835_SDHCI_BASE (CONFIG_BCM283x_BASE + 0x00300000)
 
 int bcm2835_sdhci_init(u32 regbase, u32 emmc_freq);
 
diff --git a/arch/arm/mach-bcm283x/include/mach/timer.h b/arch/arm/mach-bcm283x/include/mach/timer.h
index 56b0c35..014355e 100644
--- a/arch/arm/mach-bcm283x/include/mach/timer.h
+++ b/arch/arm/mach-bcm283x/include/mach/timer.h
@@ -6,11 +6,7 @@
 #ifndef _BCM2835_TIMER_H
 #define _BCM2835_TIMER_H
 
-#ifndef CONFIG_BCM2835
-#define BCM2835_TIMER_PHYSADDR	0x3f003000
-#else
-#define BCM2835_TIMER_PHYSADDR	0x20003000
-#endif
+#define BCM2835_TIMER_PHYSADDR	(CONFIG_BCM283x_BASE + 0x00003000)
 
 #define BCM2835_TIMER_CS_M3	(1 << 3)
 #define BCM2835_TIMER_CS_M2	(1 << 2)
diff --git a/arch/arm/mach-bcm283x/include/mach/wdog.h b/arch/arm/mach-bcm283x/include/mach/wdog.h
index 99c88e5..8292b3c 100644
--- a/arch/arm/mach-bcm283x/include/mach/wdog.h
+++ b/arch/arm/mach-bcm283x/include/mach/wdog.h
@@ -6,11 +6,7 @@
 #ifndef _BCM2835_WDOG_H
 #define _BCM2835_WDOG_H
 
-#ifndef CONFIG_BCM2835
-#define BCM2835_WDOG_PHYSADDR			0x3f100000
-#else
-#define BCM2835_WDOG_PHYSADDR			0x20100000
-#endif
+#define BCM2835_WDOG_PHYSADDR	(CONFIG_BCM283x_BASE + 0x00100000)
 
 struct bcm2835_wdog_regs {
 	u32 unknown0[7];
diff --git a/arch/arm/mach-bcm283x/mbox.c b/arch/arm/mach-bcm283x/mbox.c
index 1642ebd..3c67f68 100644
--- a/arch/arm/mach-bcm283x/mbox.c
+++ b/arch/arm/mach-bcm283x/mbox.c
@@ -27,7 +27,7 @@
 	/* Drain any stale responses */
 
 	for (;;) {
-		val = readl(&regs->status);
+		val = readl(&regs->mail0_status);
 		if (val & BCM2835_MBOX_STATUS_RD_EMPTY)
 			break;
 		if (get_timer(0) >= endtime) {
@@ -40,7 +40,7 @@
 	/* Wait for space to send */
 
 	for (;;) {
-		val = readl(&regs->status);
+		val = readl(&regs->mail1_status);
 		if (!(val & BCM2835_MBOX_STATUS_WR_FULL))
 			break;
 		if (get_timer(0) >= endtime) {
@@ -58,7 +58,7 @@
 	/* Wait for the response */
 
 	for (;;) {
-		val = readl(&regs->status);
+		val = readl(&regs->mail0_status);
 		if (!(val & BCM2835_MBOX_STATUS_RD_EMPTY))
 			break;
 		if (get_timer(0) >= endtime) {
diff --git a/arch/sh/cpu/u-boot.lds b/arch/sh/cpu/u-boot.lds
index 7b225a6..47302da 100644
--- a/arch/sh/cpu/u-boot.lds
+++ b/arch/sh/cpu/u-boot.lds
@@ -75,6 +75,7 @@
 
 	PROVIDE (__init_end = .);
 	PROVIDE (reloc_dst_end = .);
+	PROVIDE (_end = .);
 
 	PROVIDE (bss_start = .);
 	PROVIDE (__bss_start = .);
diff --git a/arch/sh/dts/Makefile b/arch/sh/dts/Makefile
new file mode 100644
index 0000000..e423bfd
--- /dev/null
+++ b/arch/sh/dts/Makefile
@@ -0,0 +1,12 @@
+dtb-y += sh7751-r2dplus.dtb
+
+targets += $(dtb-y)
+
+# Add any required device tree compiler flags here
+DTC_FLAGS +=
+
+PHONY += dtbs
+dtbs: $(addprefix $(obj)/, $(dtb-y))
+	@:
+
+clean-files := *.dtb *_HS
diff --git a/arch/sh/dts/sh7751-r2dplus.dts b/arch/sh/dts/sh7751-r2dplus.dts
new file mode 100644
index 0000000..ecaf077
--- /dev/null
+++ b/arch/sh/dts/sh7751-r2dplus.dts
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device Tree Source for the SH7751 R2Dplus
+ *
+ * Copyright (C) 2019 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+/dts-v1/;
+/ {
+	model = "R2D";
+	compatible = "renesas,r2d", "renesas,sh7751";
+
+	pci@fe200000 {
+		compatible = "renesas,pci-sh7751";
+		device_type = "pci";
+		reg = <0 0xfe200000 0 0x1000>;
+		status = "okay";
+
+		bus-range = <0 0>;
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		ranges = <0x01000000 0 0xfe240000 0 0xfe240000 0 0x00040000
+			  0x02000000 0 0xfd000000 0 0xfd000000 0 0x01000000>;
+	};
+};
diff --git a/arch/sh/include/asm/config.h b/arch/sh/include/asm/config.h
index df38c82..e1cd322 100644
--- a/arch/sh/include/asm/config.h
+++ b/arch/sh/include/asm/config.h
@@ -8,9 +8,11 @@
 
 #include <asm/processor.h>
 
+#define CONFIG_LMB
+
 /* Timer */
 #define CONFIG_SYS_TIMER_COUNTS_DOWN
-#define CONFIG_SYS_TIMER_COUNTER	(TMU_BASE + 0x8)	/* TCNT0 */
+#define CONFIG_SYS_TIMER_COUNTER	(TMU_BASE + 0xc)	/* TCNT0 */
 #define CONFIG_SYS_TIMER_RATE		(CONFIG_SYS_CLK_FREQ / 4)
 
 #endif
diff --git a/arch/sh/lib/start.S b/arch/sh/lib/start.S
index f5350b9..f9f26d3 100644
--- a/arch/sh/lib/start.S
+++ b/arch/sh/lib/start.S
@@ -22,6 +22,17 @@
 	mov.l	._reloc_dst, r4
 	add	#(_start-1b), r5
 	mov.l	._reloc_dst_end, r6
+#ifdef CONFIG_OF_SEPARATE
+	mov.l	._reloc_size, r0
+	add	r5, r0
+	add	#4, r0
+	mov.l	@r0, r0
+	swap.b	r0, r0
+	swap.w	r0, r0
+	swap.b	r0, r0
+	add	#4, r0
+	add	r0, r6
+#endif
 
 2:	mov.l	@r5+, r1
 	mov.l	r1, @r4
@@ -29,6 +40,7 @@
 	cmp/hs	r6, r4
 	bf	2b
 
+#ifndef CONFIG_OF_SEPARATE
 	mov.l	._bss_start, r4
 	mov.l	._bss_end, r5
 	mov	#0, r1
@@ -37,6 +49,7 @@
 	add	#4, r4
 	cmp/hs	r5, r4
 	bf	3b
+#endif
 
 	mov.l	._gd_init, r13		/* global data */
 	mov.l	._stack_init, r15	/* stack */
@@ -53,6 +66,7 @@
 ._lowlevel_init:	.long	(lowlevel_init - (100b + 4))
 ._reloc_dst:		.long	_start
 ._reloc_dst_end:	.long	reloc_dst_end
+._reloc_size:		.long	(_end - _start)
 ._bss_start:		.long	bss_start
 ._bss_end:		.long	bss_end
 ._gd_init:		.long	(_start - GENERATED_GBL_DATA_SIZE)
diff --git a/board/raspberrypi/rpi/rpi.c b/board/raspberrypi/rpi/rpi.c
index 7a6ca8f..fa57d50 100644
--- a/board/raspberrypi/rpi/rpi.c
+++ b/board/raspberrypi/rpi/rpi.c
@@ -148,6 +148,11 @@
 		DTB_DIR "bcm2837-rpi-cm3.dtb",
 		false,
 	},
+	[0x11] = {
+		"4 Model B",
+		DTB_DIR "bcm2711-rpi-4-b.dtb",
+		true,
+	},
 };
 
 static const struct rpi_model rpi_models_old_scheme[] = {
@@ -244,7 +249,8 @@
 static const struct rpi_model *model;
 
 #ifdef CONFIG_ARM64
-static struct mm_region bcm2837_mem_map[] = {
+#ifndef CONFIG_BCM2711
+static struct mm_region bcm283x_mem_map[] = {
 	{
 		.virt = 0x00000000UL,
 		.phys = 0x00000000UL,
@@ -263,8 +269,28 @@
 		0,
 	}
 };
-
-struct mm_region *mem_map = bcm2837_mem_map;
+#else
+static struct mm_region bcm283x_mem_map[] = {
+	{
+		.virt = 0x00000000UL,
+		.phys = 0x00000000UL,
+		.size = 0xfe000000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
+			 PTE_BLOCK_INNER_SHARE
+	}, {
+		.virt = 0xfe000000UL,
+		.phys = 0xfe000000UL,
+		.size = 0x01800000UL,
+		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
+			 PTE_BLOCK_NON_SHARE |
+			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
+	}, {
+		/* List terminator */
+		0,
+	}
+};
+#endif
+struct mm_region *mem_map = bcm283x_mem_map;
 #endif
 
 int dram_init(void)
diff --git a/board/renesas/r2dplus/r2dplus.c b/board/renesas/r2dplus/r2dplus.c
index f077326..6eff987 100644
--- a/board/renesas/r2dplus/r2dplus.c
+++ b/board/renesas/r2dplus/r2dplus.c
@@ -9,7 +9,6 @@
 #include <netdev.h>
 #include <asm/processor.h>
 #include <asm/io.h>
-#include <asm/pci.h>
 
 int checkboard(void)
 {
@@ -45,12 +44,6 @@
 	}
 }
 
-static struct pci_controller hose;
-void pci_init_board(void)
-{
-	pci_sh7751_init(&hose);
-}
-
 int board_eth_init(bd_t *bis)
 {
 	return pci_eth_init(bis);
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index fc14ad3..18f9b84 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -17,6 +17,7 @@
 #include <misc.h>
 #include <mtd.h>
 #include <mtd_node.h>
+#include <netdev.h>
 #include <phy.h>
 #include <remoteproc.h>
 #include <reset.h>
@@ -683,12 +684,21 @@
 #endif
 }
 
-/* board interface eth init */
-int board_interface_eth_init(phy_interface_t interface_type,
-			     bool eth_clk_sel_reg, bool eth_ref_clk_sel_reg)
+/* eth init function : weak called in eqos driver */
+int board_interface_eth_init(struct udevice *dev,
+			     phy_interface_t interface_type)
 {
 	u8 *syscfg;
 	u32 value;
+	bool eth_clk_sel_reg = false;
+	bool eth_ref_clk_sel_reg = false;
+
+	/* Gigabit Ethernet 125MHz clock selection. */
+	eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
+
+	/* Ethernet 50Mhz RMII clock selection */
+	eth_ref_clk_sel_reg =
+		dev_read_bool(dev, "st,eth_ref_clk_sel");
 
 	syscfg = (u8 *)syscon_get_first_range(STM32MP_SYSCON_SYSCFG);
 
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 05872fa..98647f5 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1339,6 +1339,13 @@
 	bool "Request & store 'ntpserverip' from BOOTP/DHCP server"
 	depends on CMD_BOOTP
 
+config CMD_PCAP
+	bool "pcap capture"
+	help
+	  Selecting this will allow capturing all Ethernet packets and store
+	  them in physical memory in a PCAP formated file,
+	  later to be analyzed by PCAP reader application (IE. WireShark).
+
 config BOOTP_PXE
 	bool "Send PXE client arch to BOOTP/DHCP server"
 	default y
diff --git a/cmd/Makefile b/cmd/Makefile
index 58827b5..ac843b4 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -103,6 +103,7 @@
 obj-$(CONFIG_CMD_ONENAND) += onenand.o
 obj-$(CONFIG_CMD_OSD) += osd.o
 obj-$(CONFIG_CMD_PART) += part.o
+obj-$(CONFIG_CMD_PCAP) += pcap.o
 ifdef CONFIG_PCI
 obj-$(CONFIG_CMD_PCI) += pci.o
 endif
diff --git a/cmd/mdio.c b/cmd/mdio.c
index add6440..22c8fbe 100644
--- a/cmd/mdio.c
+++ b/cmd/mdio.c
@@ -253,12 +253,13 @@
 	case 'w':
 		if (pos > 1)
 			data = simple_strtoul(argv[pos--], NULL, 16);
+		/* Intentional fall-through - Get reg for read and write */
 	case 'r':
 		if (pos > 1)
 			if (extract_reg_range(argv[pos--], &devadlo, &devadhi,
 					      &reglo, &reghi))
 				return CMD_RET_FAILURE;
-
+		/* Intentional fall-through - Get phy for all commands */
 	default:
 		if (pos > 1)
 			if (extract_phy_range(&argv[2], pos - 1, &bus,
diff --git a/cmd/pcap.c b/cmd/pcap.c
new file mode 100644
index 0000000..980603f
--- /dev/null
+++ b/cmd/pcap.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Ramon Fried <rfried.dev@gmail.com>
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include <net/pcap.h>
+
+static int do_pcap_init(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	phys_addr_t addr;
+	unsigned int size;
+
+	if (argc != 3)
+		return CMD_RET_USAGE;
+
+	addr = simple_strtoul(argv[1], NULL, 16);
+	size = simple_strtoul(argv[2], NULL, 10);
+
+	return pcap_init(addr, size) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_start(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	return pcap_start_stop(true) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_stop(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	return pcap_start_stop(false) ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_status(cmd_tbl_t *cmdtp, int flag, int argc,
+			  char * const argv[])
+{
+	return pcap_print_status() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static int do_pcap_clear(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	return pcap_clear() ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
+}
+
+static char pcap_help_text[] =
+	"- network packet capture\n\n"
+	"pcap\n"
+	"pcap init\t\t\t<addr> <max_size>\n"
+	"pcap start\t\t\tstart capture\n"
+	"pcap stop\t\t\tstop capture\n"
+	"pcap status\t\t\tprint status\n"
+	"pcap clear\t\t\tclear capture buffer\n"
+	"\n"
+	"With:\n"
+	"\t<addr>: user address to which pcap will be stored (hexedcimal)\n"
+	"\t<max_size>: Maximum size of pcap file (decimal)\n"
+	"\n";
+
+U_BOOT_CMD_WITH_SUBCMDS(pcap, "pcap", pcap_help_text,
+			U_BOOT_SUBCMD_MKENT(init, 3, 0, do_pcap_init),
+			U_BOOT_SUBCMD_MKENT(start, 1, 0, do_pcap_start),
+			U_BOOT_SUBCMD_MKENT(stop, 1, 0, do_pcap_stop),
+			U_BOOT_SUBCMD_MKENT(status, 1, 0, do_pcap_status),
+			U_BOOT_SUBCMD_MKENT(clear, 1, 0, do_pcap_clear),
+);
diff --git a/configs/evb-ast2500_defconfig b/configs/evb-ast2500_defconfig
index b47ca5b..299fbfe 100644
--- a/configs/evb-ast2500_defconfig
+++ b/configs/evb-ast2500_defconfig
@@ -24,7 +24,6 @@
 CONFIG_CLK=y
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_ASPEED=y
-# CONFIG_MMC is not set
 CONFIG_PHY_REALTEK=y
 CONFIG_DM_ETH=y
 CONFIG_FTGMAC100=y
diff --git a/configs/qemu-riscv32_defconfig b/configs/qemu-riscv32_defconfig
index d5b33b5..fe09a0d 100644
--- a/configs/qemu-riscv32_defconfig
+++ b/configs/qemu-riscv32_defconfig
@@ -5,5 +5,6 @@
 CONFIG_FIT=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 # CONFIG_CMD_MII is not set
 CONFIG_OF_PRIOR_STAGE=y
diff --git a/configs/qemu-riscv32_smode_defconfig b/configs/qemu-riscv32_smode_defconfig
index a80e68b..7103324 100644
--- a/configs/qemu-riscv32_smode_defconfig
+++ b/configs/qemu-riscv32_smode_defconfig
@@ -6,5 +6,6 @@
 CONFIG_FIT=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 # CONFIG_CMD_MII is not set
 CONFIG_OF_PRIOR_STAGE=y
diff --git a/configs/qemu-riscv64_defconfig b/configs/qemu-riscv64_defconfig
index 19a5849..ef84dfd 100644
--- a/configs/qemu-riscv64_defconfig
+++ b/configs/qemu-riscv64_defconfig
@@ -6,5 +6,6 @@
 CONFIG_FIT=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 # CONFIG_CMD_MII is not set
 CONFIG_OF_PRIOR_STAGE=y
diff --git a/configs/qemu-riscv64_smode_defconfig b/configs/qemu-riscv64_smode_defconfig
index 74743a5..1c7a2d1 100644
--- a/configs/qemu-riscv64_smode_defconfig
+++ b/configs/qemu-riscv64_smode_defconfig
@@ -7,5 +7,6 @@
 CONFIG_FIT=y
 CONFIG_DISPLAY_CPUINFO=y
 CONFIG_DISPLAY_BOARDINFO=y
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 # CONFIG_CMD_MII is not set
 CONFIG_OF_PRIOR_STAGE=y
diff --git a/configs/r2dplus_defconfig b/configs/r2dplus_defconfig
index 4c1912c..b2334af 100644
--- a/configs/r2dplus_defconfig
+++ b/configs/r2dplus_defconfig
@@ -1,12 +1,14 @@
 CONFIG_SH=y
 CONFIG_SYS_TEXT_BASE=0x8FE00000
 CONFIG_TARGET_R2DPLUS=y
+# CONFIG_SYS_MALLOC_F is not set
 CONFIG_BOOTDELAY=-1
 CONFIG_USE_BOOTARGS=y
 CONFIG_BOOTARGS="console=ttySC0,115200"
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
 CONFIG_CMD_IMLS=y
+CONFIG_CMD_DM=y
 CONFIG_CMD_IDE=y
 CONFIG_CMD_PCI=y
 # CONFIG_CMD_SETEXPR is not set
@@ -14,11 +16,16 @@
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_EXT2=y
 CONFIG_DOS_PARTITION=y
+CONFIG_OF_CONTROL=y
+CONFIG_DEFAULT_DEVICE_TREE="sh7751-r2dplus"
 CONFIG_ENV_IS_IN_FLASH=y
+CONFIG_DM=y
 CONFIG_MTD_NOR_FLASH=y
 CONFIG_FLASH_CFI_DRIVER=y
 CONFIG_SYS_FLASH_CFI=y
 CONFIG_RTL8139=y
 CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
 CONFIG_SCIF_CONSOLE=y
 CONFIG_USE_PRIVATE_LIBGCC=y
diff --git a/configs/rpi_4_32b_defconfig b/configs/rpi_4_32b_defconfig
new file mode 100644
index 0000000..a31a617
--- /dev/null
+++ b/configs/rpi_4_32b_defconfig
@@ -0,0 +1,33 @@
+CONFIG_ARM=y
+CONFIG_ARCH_BCM283X=y
+CONFIG_SYS_TEXT_BASE=0x00008000
+CONFIG_TARGET_RPI_4_32B=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_OF_BOARD=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_MISC_INIT_R=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SYS_PROMPT="U-Boot> "
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_ENV_FAT_INTERFACE="mmc"
+CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DM_KEYBOARD=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_GENERIC is not set
+# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_DM_VIDEO=y
+CONFIG_SYS_WHITE_ON_BLACK=y
+CONFIG_CONSOLE_SCROLL_LINES=10
+CONFIG_PHYS_TO_BUS=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/rpi_4_defconfig b/configs/rpi_4_defconfig
new file mode 100644
index 0000000..da8c960
--- /dev/null
+++ b/configs/rpi_4_defconfig
@@ -0,0 +1,33 @@
+CONFIG_ARM=y
+CONFIG_ARCH_BCM283X=y
+CONFIG_SYS_TEXT_BASE=0x00080000
+CONFIG_TARGET_RPI_4=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DISTRO_DEFAULTS=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_OF_BOARD=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_MISC_INIT_R=y
+# CONFIG_DISPLAY_CPUINFO is not set
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SYS_PROMPT="U-Boot> "
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_FS_UUID=y
+CONFIG_ENV_FAT_INTERFACE="mmc"
+CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
+CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DM_KEYBOARD=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_PINCTRL=y
+# CONFIG_PINCTRL_GENERIC is not set
+# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_DM_VIDEO=y
+CONFIG_SYS_WHITE_ON_BLACK=y
+CONFIG_CONSOLE_SCROLL_LINES=10
+CONFIG_PHYS_TO_BUS=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 7355e3a..968ffda 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -49,6 +49,7 @@
 CONFIG_CMD_USB=y
 CONFIG_CMD_AXI=y
 CONFIG_CMD_AB_SELECT=y
+CONFIG_CMD_PCAP=y
 CONFIG_CMD_TFTPPUT=y
 CONFIG_CMD_TFTPSRV=y
 CONFIG_CMD_RARP=y
diff --git a/doc/README.pcap b/doc/README.pcap
new file mode 100644
index 0000000..97b3e55
--- /dev/null
+++ b/doc/README.pcap
@@ -0,0 +1,62 @@
+PCAP:
+
+U-boot supports live Ethernet packet capture in PCAP(2.4) format.
+This is enabled by CONFIG_CMD_PCAP.
+
+The capture is stored on physical memory, and should be copied to
+a machine capable of parsing and displaying PCAP files (IE. wireshark)
+If networking works properly one can copy the capture file from physical memory
+using tftpput, or save it to local storage with (sf write, mmc write, fatwrite, etc)
+
+the pcap capturing requires maximum buffer size.
+when the buffer is full an error message will be displayed and then packets
+will silently drop.
+the actual capture file size is populate in the environment variable "pcapsize".
+
+Usage example:
+
+# Initialize pcap capture to physical address (0x100000) with maximum size of
+# 100000 bytes.
+
+# Start capture
+pcap start
+
+# Initialize network activity
+env set ipaddr 10.0.2.15; env set serverip 10.0.2.2; tftp uImage64
+
+# Stop capture
+pcap stop
+
+# pcap init 0x100000 100000
+PCAP capture initialized: addr: 0xffffffff80100000 max length: 100000
+
+# pcap start
+# env set ipaddr 10.0.2.15; env set serverip 10.0.2.2; tftp uImage64
+eth0@10000000: PHY present at 0
+eth0@10000000: link up, 1000Mbps full-duplex (lpa: 0x7c00)
+Using eth0@10000000 device
+TFTP from server 10.0.2.2; our IP address is 10.0.2.15
+Filename 'uImage64'.
+Load address: 0xffffffff88000000
+Loading: #################################################################
+         #################################################################
+         #################################################################
+         #################################################################
+!!! Buffer is full, consider increasing buffer size !!!
+         #################################################################
+         #################################################################
+         #################################################################
+         #################################################################
+         #################################################################
+         #
+         18.2 MiB/s
+done
+Bytes transferred = 8359376 (7f8dd0 hex)
+PCAP status:
+        Initialized addr: 0xffffffff80100000    max length: 100000
+        Status: Active.  file size: 99991
+        Incoming packets: 66 Outgoing packets: 67
+
+# pcap stop
+# tftpput 0xffffffff80100000 $pcapsize 10.0.2.2:capture.pcap
+
diff --git a/doc/api/efi.rst b/doc/api/efi.rst
index 39e2dba..2ca3449 100644
--- a/doc/api/efi.rst
+++ b/doc/api/efi.rst
@@ -103,3 +103,36 @@
 
 .. kernel-doc:: lib/efi_driver/efi_block_device.c
    :internal:
+
+Protocols
+---------
+
+Block IO protocol
+~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_disk.c
+   :internal:
+
+File protocol
+~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_file.c
+   :internal:
+
+Graphical output protocol
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_gop.c
+   :internal:
+
+Network protocols
+~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_net.c
+   :internal:
+
+Text IO protocols
+~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: lib/efi_loader/efi_console.c
+   :internal:
diff --git a/doc/device-tree-bindings/net/marvell-mdio.txt b/doc/device-tree-bindings/net/marvell-mdio.txt
new file mode 100644
index 0000000..e2038e2
--- /dev/null
+++ b/doc/device-tree-bindings/net/marvell-mdio.txt
@@ -0,0 +1,15 @@
+* Marvell MDIO Ethernet Controller interface
+
+The Ethernet controllers of the Marvel Armada 3700 and Armada 7k/8k
+have an identical unit that provides an interface with the MDIO bus.
+This driver handles this MDIO interface.
+
+Mandatory properties:
+SoC specific:
+	- #address-cells: Must be <1>.
+	- #size-cells: Must be <0>.
+	- compatible: Should be "marvell,orion-mdio" (for SMI)
+				"marvell,xmdio"	     (for XSMI)
+	- reg: Base address and size SMI/XMSI bus.
+
+Please refer to "mdio.txt" for generic MDIO bus bindings.
diff --git a/doc/device-tree-bindings/net/mdio.txt b/doc/device-tree-bindings/net/mdio.txt
new file mode 100644
index 0000000..1595325
--- /dev/null
+++ b/doc/device-tree-bindings/net/mdio.txt
@@ -0,0 +1,36 @@
+Common MDIO bus properties.
+
+These are generic properties that can apply to any MDIO bus.
+
+Optional properties:
+	- device-name - If present it is used to name the device and MDIO bus.
+			The name must be unique and must not contain spaces.
+
+A list of child nodes, one per device on the bus is expected.  These could be
+PHYs, switches or similar devices and child nodes should follow the specific
+binding for the device type.
+
+Example :
+This example shows the structure used for the external MDIO bus on NXP LS1028A
+RDB board.  Note that this MDIO device is an integrated PCI function and
+requires no compatible property for probing.
+
+/* definition in SoC dtsi file */
+	pcie@1f0000000 {
+
+		mdio0: pci@0,3 {
+			#address-cells=<0>;
+			#size-cells=<1>;
+			reg = <0x000300 0 0 0 0>;
+			status = "disabled";
+			device-name = "emdio";
+		};
+	};
+/* definition of PHYs in RDB dts file */
+&mdio0 {
+	status = "okay";
+	rdb_phy0: phy@2 {
+		reg = <2>;
+	};
+};
+
diff --git a/doc/driver-model/migration.rst b/doc/driver-model/migration.rst
index a26e7ab..75b8523 100644
--- a/doc/driver-model/migration.rst
+++ b/doc/driver-model/migration.rst
@@ -97,3 +97,11 @@
 The video subsystem has supported driver model since early 2016. Maintainers
 should submit patches switching over to using CONFIG_DM_VIDEO and other base
 driver model options in time for inclusion in the 2019.07 release.
+
+CONFIG_DM_ETH
+-------------
+Deadline: 2020.07
+
+The network subsystem has supported the driver model since early 2015.
+Maintainers should submit patches switching over to using CONFIG_DM_ETH and
+other base driver model options in time for inclusion in the 2020.07 release.
diff --git a/doc/git-mailrc b/doc/git-mailrc
index a63b76b..1d36f58 100644
--- a/doc/git-mailrc
+++ b/doc/git-mailrc
@@ -35,6 +35,7 @@
 alias masahiro       Masahiro Yamada <yamada.masahiro@socionext.com>
 alias mateusz        Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
 alias maxime         Maxime Ripard <maxime.ripard@free-electrons.com>
+alias mbrugger       Matthias Brugger <mbrugger@suse.com>
 alias monstr         Michal Simek <monstr@monstr.eu>
 alias prom           Minkyu Kang <mk7.kang@samsung.com>
 alias ptomsich       Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
@@ -74,6 +75,9 @@
 alias zynq           uboot, monstr
 alias rockchip       uboot, sjg, kevery, ptomsich
 
+alias bcm283x        uboot, mbrugger
+alias rpi            uboot, mbrugger
+
 alias m68k           uboot, alisonwang, angelo_ts
 alias coldfire       m68k
 
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 474c164..05dadf9 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -526,6 +526,7 @@
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 /**
  * device_find_by_ofnode() - Return device associated with given ofnode
  *
@@ -552,6 +553,7 @@
 
 	return -ENODEV;
 }
+#endif
 
 int device_get_child(struct udevice *parent, int index, struct udevice **devp)
 {
@@ -817,6 +819,7 @@
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 bool device_is_compatible(struct udevice *dev, const char *compat)
 {
 	return ofnode_device_is_compatible(dev_ofnode(dev), compat);
@@ -879,3 +882,4 @@
 
 	return lists_bind_fdt(parent, node, NULL, false);
 }
+#endif
diff --git a/drivers/core/root.c b/drivers/core/root.c
index aa5ca40..e856438 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -314,13 +314,6 @@
 #endif
 	return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
 }
-#else
-static int dm_scan_fdt_node(struct udevice *parent, const void *blob,
-			    int offset, bool pre_reloc_only)
-{
-	return 0;
-}
-#endif
 
 static int dm_scan_fdt_ofnode_path(const char *path, bool pre_reloc_only)
 {
@@ -360,6 +353,7 @@
 
 	return ret;
 }
+#endif
 
 __weak int dm_scan_other(bool pre_reloc_only)
 {
diff --git a/drivers/core/util.c b/drivers/core/util.c
index 60b939a..7dc1a2a 100644
--- a/drivers/core/util.c
+++ b/drivers/core/util.c
@@ -31,6 +31,7 @@
 	return count;
 }
 
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 bool dm_ofnode_pre_reloc(ofnode node)
 {
 #if defined(CONFIG_SPL_BUILD) || defined(CONFIG_TPL_BUILD)
@@ -56,3 +57,4 @@
 	return false;
 #endif
 }
+#endif
diff --git a/drivers/mmc/bcm2835_sdhci.c b/drivers/mmc/bcm2835_sdhci.c
index bf3304c..bc9ee95 100644
--- a/drivers/mmc/bcm2835_sdhci.c
+++ b/drivers/mmc/bcm2835_sdhci.c
@@ -178,12 +178,13 @@
 	fdt_addr_t base;
 	int emmc_freq;
 	int ret;
+	int clock_id = (int)dev_get_driver_data(dev);
 
 	base = devfdt_get_addr(dev);
 	if (base == FDT_ADDR_T_NONE)
 		return -EINVAL;
 
-	ret = bcm2835_get_mmc_clock(BCM2835_MBOX_CLOCK_ID_EMMC);
+	ret = bcm2835_get_mmc_clock(clock_id);
 	if (ret < 0) {
 		debug("%s: Failed to set MMC clock (err=%d)\n", __func__, ret);
 		return ret;
@@ -230,7 +231,14 @@
 }
 
 static const struct udevice_id bcm2835_sdhci_match[] = {
-	{ .compatible = "brcm,bcm2835-sdhci" },
+	{
+		.compatible = "brcm,bcm2835-sdhci",
+		.data = BCM2835_MBOX_CLOCK_ID_EMMC
+	},
+	{
+		.compatible = "brcm,bcm2711-emmc2",
+		.data = BCM2835_MBOX_CLOCK_ID_EMMC2
+	},
 	{ /* sentinel */ }
 };
 
diff --git a/drivers/mmc/bcm2835_sdhost.c b/drivers/mmc/bcm2835_sdhost.c
index 1ce019a..7f70aca 100644
--- a/drivers/mmc/bcm2835_sdhost.c
+++ b/drivers/mmc/bcm2835_sdhost.c
@@ -234,7 +234,7 @@
 
 static int bcm2835_wait_transfer_complete(struct bcm2835_host *host)
 {
-	int timediff = 0;
+	ulong tstart_ms = get_timer(0);
 
 	while (1) {
 		u32 edm, fsm;
@@ -254,11 +254,13 @@
 			break;
 		}
 
-		/* Error out after 100000 register reads (~1s) */
-		if (timediff++ == 100000) {
+		/* Error out after ~1s */
+		ulong tlapse_ms = get_timer(tstart_ms);
+		if ( tlapse_ms > 1000 /* ms */ ) {
+
 			dev_err(host->dev,
-				"wait_transfer_complete - still waiting after %d retries\n",
-				timediff);
+				"wait_transfer_complete - still waiting after %lu ms\n",
+				tlapse_ms);
 			bcm2835_dumpregs(host);
 			return -ETIMEDOUT;
 		}
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 084e095..2ce3092 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1,5 +1,6 @@
 source "drivers/net/phy/Kconfig"
 source "drivers/net/pfe_eth/Kconfig"
+source "drivers/net/fsl-mc/Kconfig"
 
 config DM_ETH
 	bool "Enable Driver Model for Ethernet drivers"
@@ -603,4 +604,14 @@
 	  an I2C chip.  The board it was developed for uses a mux controlled by
 	  on-board FPGA which in turn is accessed as a chip over I2C.
 
+config MVMDIO
+	bool "Marvell MDIO interface support"
+	depends on DM_MDIO
+	help
+	  This driver supports the MDIO interface found in the network
+	  interface units of the Marvell EBU SoCs (Kirkwood, Orion5x,
+	  Dove, Armada 370, Armada XP, Armada 37xx and Armada7K/8K/8KP).
+
+	  This driver is used by the MVPP2 and MVNETA drivers.
+
 endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 71c0889..3099183 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -42,6 +42,7 @@
 obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
 obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
 obj-$(CONFIG_MVGBE) += mvgbe.o
+obj-$(CONFIG_MVMDIO) += mvmdio.o
 obj-$(CONFIG_MVNETA) += mvneta.o
 obj-$(CONFIG_MVPP2) += mvpp2.o
 obj-$(CONFIG_NATSEMI) += natsemi.o
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index c4fe40b..145eeac 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -847,7 +847,6 @@
 
 static const struct udevice_id designware_eth_ids[] = {
 	{ .compatible = "allwinner,sun7i-a20-gmac" },
-	{ .compatible = "altr,socfpga-stmmac" },
 	{ .compatible = "amlogic,meson6-dwmac" },
 	{ .compatible = "amlogic,meson-gx-dwmac" },
 	{ .compatible = "amlogic,meson-gxbb-dwmac" },
diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
index 07b3667..4557093 100644
--- a/drivers/net/dwc_eth_qos.c
+++ b/drivers/net/dwc_eth_qos.c
@@ -621,7 +621,7 @@
 	return ret;
 }
 
-void eqos_stop_clks_tegra186(struct udevice *dev)
+static void eqos_stop_clks_tegra186(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
@@ -636,7 +636,7 @@
 	debug("%s: OK\n", __func__);
 }
 
-void eqos_stop_clks_stm32(struct udevice *dev)
+static void eqos_stop_clks_stm32(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 
@@ -1290,7 +1290,7 @@
 	return ret;
 }
 
-void eqos_stop(struct udevice *dev)
+static void eqos_stop(struct udevice *dev)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	int i;
@@ -1344,7 +1344,7 @@
 	debug("%s: OK\n", __func__);
 }
 
-int eqos_send(struct udevice *dev, void *packet, int length)
+static int eqos_send(struct udevice *dev, void *packet, int length)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	struct eqos_desc *tx_desc;
@@ -1385,7 +1385,7 @@
 	return -ETIMEDOUT;
 }
 
-int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
+static int eqos_recv(struct udevice *dev, int flags, uchar **packetp)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	struct eqos_desc *rx_desc;
@@ -1409,7 +1409,7 @@
 	return length;
 }
 
-int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
+static int eqos_free_pkt(struct udevice *dev, uchar *packet, int length)
 {
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	uchar *packet_expected;
@@ -1591,8 +1591,8 @@
 }
 
 /* board-specific Ethernet Interface initializations. */
-__weak int board_interface_eth_init(int interface_type, bool eth_clk_sel_reg,
-				    bool eth_ref_clk_sel_reg)
+__weak int board_interface_eth_init(struct udevice *dev,
+				    phy_interface_t interface_type)
 {
 	return 0;
 }
@@ -1602,8 +1602,6 @@
 	struct eqos_priv *eqos = dev_get_priv(dev);
 	int ret;
 	phy_interface_t interface;
-	bool eth_clk_sel_reg = false;
-	bool eth_ref_clk_sel_reg = false;
 
 	debug("%s(dev=%p):\n", __func__, dev);
 
@@ -1614,15 +1612,7 @@
 		return -EINVAL;
 	}
 
-	/* Gigabit Ethernet 125MHz clock selection. */
-	eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
-
-	/* Ethernet 50Mhz RMII clock selection */
-	eth_ref_clk_sel_reg =
-		dev_read_bool(dev, "st,eth_ref_clk_sel");
-
-	ret = board_interface_eth_init(interface, eth_clk_sel_reg,
-				       eth_ref_clk_sel_reg);
+	ret = board_interface_eth_init(dev, interface);
 	if (ret)
 		return -EINVAL;
 
diff --git a/drivers/net/fsl-mc/Kconfig b/drivers/net/fsl-mc/Kconfig
new file mode 100644
index 0000000..25a2cb8
--- /dev/null
+++ b/drivers/net/fsl-mc/Kconfig
@@ -0,0 +1,25 @@
+#
+# NXP Management Complex
+#
+
+menuconfig FSL_MC_ENET
+	bool "NXP Management Complex"
+	depends on ARCH_LS2080A || ARCH_LS1088A || ARCH_LX2160A
+	default y
+	select RESV_RAM
+	help
+	  Enable Management Complex (MC) network
+	  This is NXP Management Complex menuconfig
+	  that contains all MC related config options
+
+if FSL_MC_ENET
+
+config SYS_MC_RSV_MEM_ALIGN
+	hex "Management Complex reserved memory alignment"
+	depends on RESV_RAM
+	default 0x20000000 if ARCH_LS2080A || ARCH_LS1088A || ARCH_LX2160A
+	help
+	  Reserved memory needs to be aligned for MC to use. Default value
+	  is 512MB.
+
+endif # FSL_MC_ENET
diff --git a/drivers/net/fsl_enetc_mdio.c b/drivers/net/fsl_enetc_mdio.c
index 60d2153..b4463a5 100644
--- a/drivers/net/fsl_enetc_mdio.c
+++ b/drivers/net/fsl_enetc_mdio.c
@@ -144,6 +144,7 @@
 
 static struct pci_device_id enetc_mdio_ids[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_ENETC_MDIO) },
+	{ }
 };
 
 U_BOOT_PCI_DEVICE(enetc_mdio, enetc_mdio_ids);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index c99cf66..377188e 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -296,13 +296,15 @@
 static inline void macb_flush_rx_buffer(struct macb_device *macb)
 {
 	flush_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
-			   ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN));
+			   ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
+				 PKTALIGN));
 }
 
 static inline void macb_invalidate_rx_buffer(struct macb_device *macb)
 {
 	invalidate_dcache_range(macb->rx_buffer_dma, macb->rx_buffer_dma +
-				ALIGN(MACB_RX_BUFFER_SIZE, PKTALIGN));
+				ALIGN(macb->rx_buffer_size * MACB_RX_RING_SIZE,
+				      PKTALIGN));
 }
 
 #if defined(CONFIG_CMD_NET)
@@ -643,7 +645,7 @@
 
 	/* First check for GMAC and that it is GiB capable */
 	if (gem_is_gigabit_capable(macb)) {
-		lpa = macb_mdio_read(macb, MII_LPA);
+		lpa = macb_mdio_read(macb, MII_STAT1000);
 
 		if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL |
 					LPA_1000XHALF)) {
diff --git a/drivers/net/mdio_mux_i2creg.c b/drivers/net/mdio_mux_i2creg.c
new file mode 100644
index 0000000..3e82898
--- /dev/null
+++ b/drivers/net/mdio_mux_i2creg.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2019
+ * Alex Marginean, NXP
+ */
+
+#include <dm.h>
+#include <errno.h>
+#include <miiphy.h>
+#include <i2c.h>
+
+/*
+ * This driver is used for MDIO muxes driven by writing to a register of an I2C
+ * chip.  The board it was developed for uses a mux controlled by on-board FPGA
+ * which in turn is accessed as a chip over I2C.
+ */
+
+struct mdio_mux_i2creg_priv {
+	struct udevice *chip;
+	int reg;
+	int mask;
+};
+
+static int mdio_mux_i2creg_select(struct udevice *mux, int cur, int sel)
+{
+	struct mdio_mux_i2creg_priv *priv = dev_get_priv(mux);
+	u8 val, val_old;
+
+	/* if last selection didn't change we're good to go */
+	if (cur == sel)
+		return 0;
+
+	val_old = dm_i2c_reg_read(priv->chip, priv->reg);
+	val = (val_old & ~priv->mask) | (sel & priv->mask);
+	debug("%s: chip %s, reg %x, val %x => %x\n", __func__, priv->chip->name,
+	      priv->reg, val_old, val);
+	dm_i2c_reg_write(priv->chip, priv->reg, val);
+
+	return 0;
+}
+
+static const struct mdio_mux_ops mdio_mux_i2creg_ops = {
+	.select = mdio_mux_i2creg_select,
+};
+
+static int mdio_mux_i2creg_probe(struct udevice *dev)
+{
+	struct mdio_mux_i2creg_priv *priv = dev_get_priv(dev);
+	ofnode chip_node, bus_node;
+	struct udevice *i2c_bus;
+	u32 reg_mask[2];
+	u32 chip_addr;
+	int err;
+
+	/* read the register addr/mask pair */
+	err = dev_read_u32_array(dev, "mux-reg-masks", reg_mask, 2);
+	if (err) {
+		debug("%s: error reading mux-reg-masks property\n", __func__);
+		return err;
+	}
+
+	/* parent should be an I2C chip, grandparent should be an I2C bus */
+	chip_node = ofnode_get_parent(dev->node);
+	bus_node = ofnode_get_parent(chip_node);
+
+	err = uclass_get_device_by_ofnode(UCLASS_I2C, bus_node, &i2c_bus);
+	if (err) {
+		debug("%s: can't find I2C bus for node %s\n", __func__,
+		      ofnode_get_name(bus_node));
+		return err;
+	}
+
+	err = ofnode_read_u32(chip_node, "reg", &chip_addr);
+	if (err) {
+		debug("%s: can't read chip address in %s\n", __func__,
+		      ofnode_get_name(chip_node));
+		return err;
+	}
+
+	err = i2c_get_chip(i2c_bus, (uint)chip_addr, 1, &priv->chip);
+	if (err) {
+		debug("%s: can't find i2c chip device for addr %x\n", __func__,
+		      chip_addr);
+		return err;
+	}
+
+	priv->reg = (int)reg_mask[0];
+	priv->mask = (int)reg_mask[1];
+
+	debug("%s: chip %s, reg %x, mask %x\n", __func__, priv->chip->name,
+	      priv->reg, priv->mask);
+
+	return 0;
+}
+
+static const struct udevice_id mdio_mux_i2creg_ids[] = {
+	{ .compatible = "mdio-mux-i2creg" },
+	{ }
+};
+
+U_BOOT_DRIVER(mdio_mux_i2creg) = {
+	.name		= "mdio_mux_i2creg",
+	.id		= UCLASS_MDIO_MUX,
+	.of_match	= mdio_mux_i2creg_ids,
+	.probe		= mdio_mux_i2creg_probe,
+	.ops		= &mdio_mux_i2creg_ops,
+	.priv_auto_alloc_size = sizeof(struct mdio_mux_i2creg_priv),
+};
diff --git a/drivers/net/mdio_sandbox.c b/drivers/net/mdio_sandbox.c
index df053f5..b731f60 100644
--- a/drivers/net/mdio_sandbox.c
+++ b/drivers/net/mdio_sandbox.c
@@ -27,7 +27,7 @@
 		return -ENODEV;
 	if (devad != MDIO_DEVAD_NONE)
 		return -ENODEV;
-	if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
+	if (reg < 0 || reg >= SANDBOX_PHY_REG_CNT)
 		return -ENODEV;
 
 	return priv->reg[reg];
@@ -45,7 +45,7 @@
 		return -ENODEV;
 	if (devad != MDIO_DEVAD_NONE)
 		return -ENODEV;
-	if (reg < 0 || reg > SANDBOX_PHY_REG_CNT)
+	if (reg < 0 || reg >= SANDBOX_PHY_REG_CNT)
 		return -ENODEV;
 
 	priv->reg[reg] = val;
diff --git a/drivers/net/mvmdio.c b/drivers/net/mvmdio.c
new file mode 100644
index 0000000..ec6805e
--- /dev/null
+++ b/drivers/net/mvmdio.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Marvell International Ltd.
+ * Author: Ken Ma<make@marvell.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <miiphy.h>
+#include <phy.h>
+#include <asm/io.h>
+#include <wait_bit.h>
+
+#define MVMDIO_SMI_DATA_SHIFT		0
+#define MVMDIO_SMI_PHY_ADDR_SHIFT	16
+#define MVMDIO_SMI_PHY_REG_SHIFT	21
+#define MVMDIO_SMI_READ_OPERATION	BIT(26)
+#define MVMDIO_SMI_WRITE_OPERATION	0
+#define MVMDIO_SMI_READ_VALID		BIT(27)
+#define MVMDIO_SMI_BUSY			BIT(28)
+
+#define MVMDIO_XSMI_MGNT_REG		0x0
+#define MVMDIO_XSMI_PHYADDR_SHIFT	16
+#define MVMDIO_XSMI_DEVADDR_SHIFT	21
+#define MVMDIO_XSMI_WRITE_OPERATION	(0x5 << 26)
+#define MVMDIO_XSMI_READ_OPERATION	(0x7 << 26)
+#define MVMDIO_XSMI_READ_VALID		BIT(29)
+#define MVMDIO_XSMI_BUSY		BIT(30)
+#define MVMDIO_XSMI_ADDR_REG		0x8
+
+enum mvmdio_bus_type {
+	BUS_TYPE_SMI,
+	BUS_TYPE_XSMI
+};
+
+struct mvmdio_priv {
+	void *mdio_base;
+	enum mvmdio_bus_type type;
+};
+
+static int mvmdio_smi_read(struct udevice *dev, int addr,
+			   int devad, int reg)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	u32 val;
+	int ret;
+
+	if (devad != MDIO_DEVAD_NONE)
+		return -EOPNOTSUPP;
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
+		(reg << MVMDIO_SMI_PHY_REG_SHIFT)  |
+		MVMDIO_SMI_READ_OPERATION),
+	       priv->mdio_base);
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	val = readl(priv->mdio_base);
+	if (!(val & MVMDIO_SMI_READ_VALID)) {
+		pr_err("SMI bus read not valid\n");
+		return -ENODEV;
+	}
+
+	return val & GENMASK(15, 0);
+}
+
+static int mvmdio_smi_write(struct udevice *dev, int addr, int devad,
+			    int reg, u16 value)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (devad != MDIO_DEVAD_NONE)
+		return -EOPNOTSUPP;
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_SMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	writel(((addr << MVMDIO_SMI_PHY_ADDR_SHIFT) |
+		(reg << MVMDIO_SMI_PHY_REG_SHIFT)  |
+		MVMDIO_SMI_WRITE_OPERATION            |
+		(value << MVMDIO_SMI_DATA_SHIFT)),
+	       priv->mdio_base);
+
+	return 0;
+}
+
+static int mvmdio_xsmi_read(struct udevice *dev, int addr,
+			    int devad, int reg)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (devad == MDIO_DEVAD_NONE)
+		return -EOPNOTSUPP;
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
+	writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
+		(devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
+		MVMDIO_XSMI_READ_OPERATION),
+	       priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	if (!(readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) &
+	      MVMDIO_XSMI_READ_VALID)) {
+		pr_err("XSMI bus read not valid\n");
+		return -ENODEV;
+	}
+
+	return readl(priv->mdio_base + MVMDIO_XSMI_MGNT_REG) & GENMASK(15, 0);
+}
+
+static int mvmdio_xsmi_write(struct udevice *dev, int addr, int devad,
+			     int reg, u16 value)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	if (devad == MDIO_DEVAD_NONE)
+		return -EOPNOTSUPP;
+
+	ret = wait_for_bit_le32(priv->mdio_base, MVMDIO_XSMI_BUSY,
+				false, CONFIG_SYS_HZ, false);
+	if (ret < 0)
+		return ret;
+
+	writel(reg & GENMASK(15, 0), priv->mdio_base + MVMDIO_XSMI_ADDR_REG);
+	writel(((addr << MVMDIO_XSMI_PHYADDR_SHIFT) |
+		(devad << MVMDIO_XSMI_DEVADDR_SHIFT) |
+		MVMDIO_XSMI_WRITE_OPERATION | value),
+	       priv->mdio_base + MVMDIO_XSMI_MGNT_REG);
+
+	return 0;
+}
+
+static int mvmdio_read(struct udevice *dev, int addr, int devad, int reg)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	int err = -ENOTSUPP;
+
+	switch (priv->type) {
+	case BUS_TYPE_SMI:
+		err = mvmdio_smi_read(dev, addr, devad, reg);
+		break;
+	case BUS_TYPE_XSMI:
+		err = mvmdio_xsmi_read(dev, addr, devad, reg);
+		break;
+	}
+
+	return err;
+}
+
+static int mvmdio_write(struct udevice *dev, int addr, int devad, int reg,
+			u16 value)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+	int err = -ENOTSUPP;
+
+	switch (priv->type) {
+	case BUS_TYPE_SMI:
+		err = mvmdio_smi_write(dev, addr, devad, reg, value);
+		break;
+	case BUS_TYPE_XSMI:
+		err = mvmdio_xsmi_write(dev, addr, devad, reg, value);
+		break;
+	}
+
+	return err;
+}
+
+/*
+ * Name the device, we use the device tree node name.
+ * This can be overwritten by MDIO class code if device-name property is
+ * present.
+ */
+static int mvmdio_bind(struct udevice *dev)
+{
+	if (ofnode_valid(dev->node))
+		device_set_name(dev, ofnode_get_name(dev->node));
+
+	return 0;
+}
+
+/* Get device base address and type, either C22 SMII or C45 XSMI */
+static int mvmdio_probe(struct udevice *dev)
+{
+	struct mvmdio_priv *priv = dev_get_priv(dev);
+
+	priv->mdio_base = (void *)dev_read_addr(dev);
+	priv->type = (enum mvmdio_bus_type)dev_get_driver_data(dev);
+
+	return 0;
+}
+
+static const struct mdio_ops mvmdio_ops = {
+	.read = mvmdio_read,
+	.write = mvmdio_write,
+};
+
+static const struct udevice_id mvmdio_ids[] = {
+	{ .compatible = "marvell,orion-mdio", .data = BUS_TYPE_SMI },
+	{ .compatible = "marvell,xmdio", .data = BUS_TYPE_XSMI },
+	{ }
+};
+
+U_BOOT_DRIVER(mvmdio) = {
+	.name			= "mvmdio",
+	.id			= UCLASS_MDIO,
+	.of_match		= mvmdio_ids,
+	.bind			= mvmdio_bind,
+	.probe			= mvmdio_probe,
+	.ops			= &mvmdio_ops,
+	.priv_auto_alloc_size	= sizeof(struct mvmdio_priv),
+};
+
diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c
index bcc6fe9..bd89725 100644
--- a/drivers/net/mvpp2.c
+++ b/drivers/net/mvpp2.c
@@ -5321,6 +5321,13 @@
 	mvpp2_cleanup_txqs(port);
 }
 
+static int mvpp2_write_hwaddr(struct udevice *dev)
+{
+	struct mvpp2_port *port = dev_get_priv(dev);
+
+	return mvpp2_prs_update_mac_da(port, port->dev_addr);
+}
+
 static int mvpp22_smi_phy_addr_cfg(struct mvpp2_port *port)
 {
 	writel(port->phyaddr, port->priv->iface_base +
@@ -5525,6 +5532,7 @@
 	.send		= mvpp2_send,
 	.recv		= mvpp2_recv,
 	.stop		= mvpp2_stop,
+	.write_hwaddr	= mvpp2_write_hwaddr
 };
 
 static struct driver mvpp2_driver = {
diff --git a/drivers/net/pfe_eth/pfe_mdio.c b/drivers/net/pfe_eth/pfe_mdio.c
index 2dde9e7..6230967 100644
--- a/drivers/net/pfe_eth/pfe_mdio.c
+++ b/drivers/net/pfe_eth/pfe_mdio.c
@@ -110,7 +110,6 @@
 	u32 phy;
 	u32 reg_data;
 	int timeout = MDIO_TIMEOUT;
-	int val;
 
 	if (dev_addr == MDIO_DEVAD_NONE) {
 		reg = ((reg_addr & EMAC_MII_DATA_RA_MASK) <<
@@ -150,7 +149,7 @@
 	debug("%s: phy: %02x reg:%02x val:%#x\n", __func__, phy_addr,
 	      reg_addr, data);
 
-	return val;
+	return 0;
 }
 
 static void pfe_configure_serdes(struct pfe_eth_dev *priv)
diff --git a/drivers/pci/pci_sh7751.c b/drivers/pci/pci_sh7751.c
index 2f918f1..53e1668 100644
--- a/drivers/pci/pci_sh7751.c
+++ b/drivers/pci/pci_sh7751.c
@@ -6,6 +6,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <pci.h>
 #include <asm/processor.h>
 #include <asm/io.h>
@@ -19,82 +20,113 @@
 #define SH7751_WCR3	(vu_long *)0xFF800010
 #define SH7751_MCR	(vu_long *)0xFF800014
 #define SH7751_BCR3	(vu_short *)0xFF800050
-#define SH7751_PCICONF0 (vu_long *)0xFE200000
-#define SH7751_PCICONF1 (vu_long *)0xFE200004
-#define SH7751_PCICONF2 (vu_long *)0xFE200008
-#define SH7751_PCICONF3 (vu_long *)0xFE20000C
-#define SH7751_PCICONF4 (vu_long *)0xFE200010
-#define SH7751_PCICONF5 (vu_long *)0xFE200014
-#define SH7751_PCICONF6 (vu_long *)0xFE200018
-#define SH7751_PCICR    (vu_long *)0xFE200100
-#define SH7751_PCILSR0  (vu_long *)0xFE200104
-#define SH7751_PCILSR1  (vu_long *)0xFE200108
-#define SH7751_PCILAR0  (vu_long *)0xFE20010C
-#define SH7751_PCILAR1  (vu_long *)0xFE200110
-#define SH7751_PCIMBR   (vu_long *)0xFE2001C4
-#define SH7751_PCIIOBR  (vu_long *)0xFE2001C8
-#define SH7751_PCIPINT  (vu_long *)0xFE2001CC
-#define SH7751_PCIPINTM (vu_long *)0xFE2001D0
-#define SH7751_PCICLKR  (vu_long *)0xFE2001D4
-#define SH7751_PCIBCR1  (vu_long *)0xFE2001E0
-#define SH7751_PCIBCR2  (vu_long *)0xFE2001E4
-#define SH7751_PCIWCR1  (vu_long *)0xFE2001E8
-#define SH7751_PCIWCR2  (vu_long *)0xFE2001EC
-#define SH7751_PCIWCR3  (vu_long *)0xFE2001F0
-#define SH7751_PCIMCR   (vu_long *)0xFE2001F4
-#define SH7751_PCIBCR3  (vu_long *)0xFE2001F8
+#define SH7751_PCICONF0	(vu_long *)0xFE200000
+#define SH7751_PCICONF1	(vu_long *)0xFE200004
+#define SH7751_PCICONF2	(vu_long *)0xFE200008
+#define SH7751_PCICONF3	(vu_long *)0xFE20000C
+#define SH7751_PCICONF4	(vu_long *)0xFE200010
+#define SH7751_PCICONF5	(vu_long *)0xFE200014
+#define SH7751_PCICONF6	(vu_long *)0xFE200018
+#define SH7751_PCICR	(vu_long *)0xFE200100
+#define SH7751_PCILSR0	(vu_long *)0xFE200104
+#define SH7751_PCILSR1	(vu_long *)0xFE200108
+#define SH7751_PCILAR0	(vu_long *)0xFE20010C
+#define SH7751_PCILAR1	(vu_long *)0xFE200110
+#define SH7751_PCIMBR	(vu_long *)0xFE2001C4
+#define SH7751_PCIIOBR	(vu_long *)0xFE2001C8
+#define SH7751_PCIPINT	(vu_long *)0xFE2001CC
+#define SH7751_PCIPINTM	(vu_long *)0xFE2001D0
+#define SH7751_PCICLKR	(vu_long *)0xFE2001D4
+#define SH7751_PCIBCR1	(vu_long *)0xFE2001E0
+#define SH7751_PCIBCR2	(vu_long *)0xFE2001E4
+#define SH7751_PCIWCR1	(vu_long *)0xFE2001E8
+#define SH7751_PCIWCR2	(vu_long *)0xFE2001EC
+#define SH7751_PCIWCR3	(vu_long *)0xFE2001F0
+#define SH7751_PCIMCR	(vu_long *)0xFE2001F4
+#define SH7751_PCIBCR3	(vu_long *)0xFE2001F8
 
-#define BCR1_BREQEN				0x00080000
-#define PCI_SH7751_ID			0x35051054
-#define PCI_SH7751R_ID			0x350E1054
-#define SH7751_PCICONF1_WCC		0x00000080
-#define SH7751_PCICONF1_PER		0x00000040
-#define SH7751_PCICONF1_BUM		0x00000004
-#define SH7751_PCICONF1_MES		0x00000002
+#define BCR1_BREQEN		0x00080000
+#define PCI_SH7751_ID		0x35051054
+#define PCI_SH7751R_ID		0x350E1054
+#define SH7751_PCICONF1_WCC	0x00000080
+#define SH7751_PCICONF1_PER	0x00000040
+#define SH7751_PCICONF1_BUM	0x00000004
+#define SH7751_PCICONF1_MES	0x00000002
 #define SH7751_PCICONF1_CMDS	0x000000C6
 #define SH7751_PCI_HOST_BRIDGE	0x6
-#define SH7751_PCICR_PREFIX		0xa5000000
-#define SH7751_PCICR_PRST		0x00000002
-#define SH7751_PCICR_CFIN		0x00000001
-#define SH7751_PCIPINT_D3		0x00000002
-#define SH7751_PCIPINT_D0		0x00000001
-#define SH7751_PCICLKR_PREFIX   0xa5000000
+#define SH7751_PCICR_PREFIX	0xa5000000
+#define SH7751_PCICR_PRST	0x00000002
+#define SH7751_PCICR_CFIN	0x00000001
+#define SH7751_PCIPINT_D3	0x00000002
+#define SH7751_PCIPINT_D0	0x00000001
+#define SH7751_PCICLKR_PREFIX	0xa5000000
 
-#define SH7751_PCI_MEM_BASE		0xFD000000
-#define SH7751_PCI_MEM_SIZE		0x01000000
-#define SH7751_PCI_IO_BASE		0xFE240000
-#define SH7751_PCI_IO_SIZE		0x00040000
+#define SH7751_PCI_MEM_BASE	0xFD000000
+#define SH7751_PCI_MEM_SIZE	0x01000000
+#define SH7751_PCI_IO_BASE	0xFE240000
+#define SH7751_PCI_IO_SIZE	0x00040000
 
-#define SH7751_PCIPAR   (vu_long *)0xFE2001C0
-#define SH7751_PCIPDR   (vu_long *)0xFE200220
+#define SH7751_PCIPAR	(vu_long *)0xFE2001C0
+#define SH7751_PCIPDR	(vu_long *)0xFE200220
 
 #define p4_in(addr)	(*addr)
 #define p4_out(data, addr) (*addr) = (data)
 
-/* Double word */
-int pci_sh4_read_config_dword(struct pci_controller *hose,
-			      pci_dev_t dev, int offset, u32 *value)
+static int sh7751_pci_addr_valid(pci_dev_t d, uint offset)
 {
-	u32 par_data = 0x80000000 | dev;
-
-	p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
-	*value = p4_in(SH7751_PCIPDR);
+	if (PCI_FUNC(d))
+		return -EINVAL;
 
 	return 0;
 }
 
-int pci_sh4_write_config_dword(struct pci_controller *hose,
-			       pci_dev_t dev, int offset, u32 value)
+static u32 get_bus_address(struct udevice *dev, pci_dev_t bdf, u32 offset)
 {
-	u32 par_data = 0x80000000 | dev;
+	return BIT(31) | (PCI_DEV(bdf) << 8) | (offset & ~3);
+}
 
-	p4_out(par_data | (offset & 0xfc), SH7751_PCIPAR);
-	p4_out(value, SH7751_PCIPDR);
+static int sh7751_pci_read_config(struct udevice *dev, pci_dev_t bdf,
+				  uint offset, ulong *value,
+				  enum pci_size_t size)
+{
+	u32 addr, reg;
+	int ret;
+
+	ret = sh7751_pci_addr_valid(bdf, offset);
+	if (ret) {
+		*value = pci_get_ff(size);
+		return 0;
+	}
+
+	addr = get_bus_address(dev, bdf, offset);
+	p4_out(addr, SH7751_PCIPAR);
+	reg = p4_in(SH7751_PCIPDR);
+	*value = pci_conv_32_to_size(reg, offset, size);
 
 	return 0;
 }
 
-int pci_sh7751_init(struct pci_controller *hose)
+static int sh7751_pci_write_config(struct udevice *dev, pci_dev_t bdf,
+				      uint offset, ulong value,
+				      enum pci_size_t size)
+{
+	u32 addr, reg, old;
+	int ret;
+
+	ret = sh7751_pci_addr_valid(bdf, offset);
+	if (ret)
+		return ret;
+
+	addr = get_bus_address(dev, bdf, offset);
+	p4_out(addr, SH7751_PCIPAR);
+	old = p4_in(SH7751_PCIPDR);
+	reg = pci_conv_size_to_32(old, value, offset, size);
+	p4_out(reg, SH7751_PCIPDR);
+
+	return 0;
+}
+
+static int sh7751_pci_probe(struct udevice *dev)
 {
 	/* Double-check that we're a 7751 or 7751R chip */
 	if (p4_in(SH7751_PCICONF0) != PCI_SH7751_ID
@@ -178,7 +210,23 @@
 	/* Finally, set central function init complete */
 	p4_out((SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN), SH7751_PCICR);
 
-	pci_sh4_init(hose);
-
 	return 0;
 }
+
+static const struct dm_pci_ops sh7751_pci_ops = {
+	.read_config	= sh7751_pci_read_config,
+	.write_config	= sh7751_pci_write_config,
+};
+
+static const struct udevice_id sh7751_pci_ids[] = {
+	{ .compatible = "renesas,pci-sh7751" },
+	{ }
+};
+
+U_BOOT_DRIVER(sh7751_pci) = {
+	.name		= "sh7751_pci",
+	.id		= UCLASS_PCI,
+	.of_match	= sh7751_pci_ids,
+	.ops		= &sh7751_pci_ops,
+	.probe		= sh7751_pci_probe,
+};
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index 397bbf6..e0a4d76 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -128,9 +128,9 @@
 #define EXYNOS_IRAM_SECONDARY_BASE	0x02020018
 
 #define BOOT_TARGET_DEVICES(func) \
+	func(MMC, mmc, 2) \
 	func(MMC, mmc, 1) \
 	func(MMC, mmc, 0) \
-	func(MMC, mmc, 2) \
 	func(PXE, pxe, na) \
 	func(DHCP, dhcp, na)
 
diff --git a/include/configs/r2dplus.h b/include/configs/r2dplus.h
index e10de1b..0b16fb0 100644
--- a/include/configs/r2dplus.h
+++ b/include/configs/r2dplus.h
@@ -64,19 +64,6 @@
 /*
  * SuperH PCI Bridge Configration
  */
-#define CONFIG_SH4_PCI
 #define CONFIG_SH7751_PCI
-#define CONFIG_PCI_SCAN_SHOW	1
-#define __mem_pci
-
-#define CONFIG_PCI_MEM_BUS	0xFD000000	/* Memory space base addr */
-#define CONFIG_PCI_MEM_PHYS	CONFIG_PCI_MEM_BUS
-#define CONFIG_PCI_MEM_SIZE	0x01000000	/* Size of Memory window */
-#define CONFIG_PCI_IO_BUS	0xFE240000	/* IO space base address */
-#define CONFIG_PCI_IO_PHYS	CONFIG_PCI_IO_BUS
-#define CONFIG_PCI_IO_SIZE	0x00040000	/* Size of IO window */
-#define CONFIG_PCI_SYS_BUS	CONFIG_SYS_SDRAM_BASE
-#define CONFIG_PCI_SYS_PHYS	CONFIG_SYS_SDRAM_BASE
-#define CONFIG_PCI_SYS_SIZE	CONFIG_SYS_SDRAM_SIZE
 
 #endif /* __CONFIG_H */
diff --git a/include/configs/rpi.h b/include/configs/rpi.h
index 8473cec..77d2d54 100644
--- a/include/configs/rpi.h
+++ b/include/configs/rpi.h
@@ -55,6 +55,10 @@
 #define CONFIG_SYS_MEMTEST_END		0x00200000
 #define CONFIG_LOADADDR			0x00200000
 
+#ifdef CONFIG_ARM64
+#define CONFIG_SYS_BOOTM_LEN		SZ_64M
+#endif
+
 /* Devices */
 /* GPIO */
 #define CONFIG_BCM2835_GPIO
diff --git a/include/efi_api.h b/include/efi_api.h
index 4377819..cb895f3 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -483,7 +483,7 @@
 	struct efi_device_path dp;
 	u32 boot_entry;
 	u64 partition_start;
-	u64 partition_end;
+	u64 partition_size;
 } __packed;
 
 struct efi_device_path_file_path {
@@ -1281,6 +1281,8 @@
 			struct efi_mac_address *dest_addr, u16 *protocol);
 	struct efi_event *wait_for_packet;
 	struct efi_simple_network_mode *mode;
+	/* private fields */
+	u32 int_status;
 };
 
 #define EFI_PXE_BASE_CODE_PROTOCOL_GUID \
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 5298ea7..00eba8a 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -478,6 +478,10 @@
 /* Adds a range into the EFI memory map */
 efi_status_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type,
 				bool overlap_only_ram);
+/* Adds a conventional range into the EFI memory map */
+efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
+					     u64 ram_top);
+
 /* Called by board init to initialize the EFI drivers */
 efi_status_t efi_driver_init(void);
 /* Called by board init to initialize the EFI memory map */
diff --git a/include/env_callback.h b/include/env_callback.h
index 982c078..74da20e 100644
--- a/include/env_callback.h
+++ b/include/env_callback.h
@@ -42,7 +42,7 @@
 #define DNS_CALLBACK
 #endif
 
-#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_NET
 #define NET_CALLBACKS \
 	"bootfile:bootfile," \
 	"ipaddr:ipaddr," \
diff --git a/include/env_flags.h b/include/env_flags.h
index e5380f2..725841a 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -36,7 +36,7 @@
 #define CONFIG_ENV_FLAGS_LIST_STATIC ""
 #endif
 
-#ifdef CONFIG_CMD_NET
+#ifdef CONFIG_NET
 #ifdef CONFIG_REGEX
 #define ETHADDR_WILDCARD "\\d*"
 #else
diff --git a/include/net.h b/include/net.h
index a54d5ee..75a16e4 100644
--- a/include/net.h
+++ b/include/net.h
@@ -816,7 +816,7 @@
 static inline void net_random_ethaddr(uchar *addr)
 {
 	int i;
-	unsigned int seed = get_timer(0);
+	unsigned int seed = get_ticks();
 
 	for (i = 0; i < 6; i++)
 		addr[i] = rand_r(&seed);
diff --git a/include/net/pcap.h b/include/net/pcap.h
new file mode 100644
index 0000000..512ba98
--- /dev/null
+++ b/include/net/pcap.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2019
+ * Ramon Fried <rfried.dev@gmail.com>
+ */
+
+/**
+ * pcap_init() - Initialize PCAP memory buffer
+ *
+ * @paddr	physicaly memory address to store buffer
+ * @size	maximum size of capture file in memory
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_init(phys_addr_t paddr, unsigned long size);
+
+/**
+ * pcap_start_stop() - start / stop pcap capture
+ *
+ * @start	if true, start capture if false stop capture
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_start_stop(bool start);
+
+/**
+ * pcap_clear() - clear pcap capture buffer and statistics
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_clear(void);
+
+/**
+ * pcap_print_status() - print status of pcap capture
+ *
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_print_status(void);
+
+/**
+ * pcap_active() - check if pcap is enabled
+ *
+ * @return	TRUE if active, FALSE if not.
+ */
+bool pcap_active(void);
+
+/**
+ * pcap_post() - Post a packet to PCAP file
+ *
+ * @packet:	packet to post
+ * @len:	packet length in bytes
+ * @outgoing	packet direction (outgoing/incoming)
+ * @return	0 on success, -ERROR on error
+ */
+int pcap_post(const void *packet, size_t len, bool outgoing);
diff --git a/include/netdev.h b/include/netdev.h
index a40c4ad..68a3fce 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -10,6 +10,7 @@
 
 #ifndef _NETDEV_H_
 #define _NETDEV_H_
+#include <phy_interface.h>
 
 /*
  * Board and CPU-specific initialization functions
@@ -21,6 +22,8 @@
  */
 
 int board_eth_init(bd_t *bis);
+int board_interface_eth_init(struct udevice *dev,
+			     phy_interface_t interface_type);
 int cpu_eth_init(bd_t *bis);
 
 /* Driver initialization prototypes */
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index d4765af..a55e4b3 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -156,13 +156,14 @@
 	 * Update the cursor position.
 	 *
 	 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
-	 * and U000D. All other characters, including control characters
-	 * U+0007 (BEL) and U+0009 (TAB), have to increase the column by one.
+	 * and U000D. All other control characters are ignored. Any non-control
+	 * character increase the column by one.
 	 */
 	for (p = string; *p; ++p) {
 		switch (*p) {
 		case '\b':	/* U+0008, backspace */
-			con->cursor_column = max(0, con->cursor_column - 1);
+			if (con->cursor_column)
+				con->cursor_column--;
 			break;
 		case '\n':	/* U+000A, newline */
 			con->cursor_column = 0;
@@ -178,14 +179,21 @@
 			 */
 			break;
 		default:
-			con->cursor_column++;
+			/* Exclude control codes */
+			if (*p > 0x1f)
+				con->cursor_column++;
 			break;
 		}
 		if (con->cursor_column >= mode->columns) {
 			con->cursor_column = 0;
 			con->cursor_row++;
 		}
-		con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
+		/*
+		 * When we exceed the row count the terminal will scroll up one
+		 * line. We have to adjust the cursor position.
+		 */
+		if (con->cursor_row >= mode->rows && con->cursor_row)
+			con->cursor_row--;
 	}
 
 out:
@@ -211,9 +219,9 @@
 /**
  * query_console_serial() - query console size
  *
- * @rows	pointer to return number of rows
- * @columns	pointer to return number of columns
- * Returns	0 on success
+ * @rows:	pointer to return number of rows
+ * @cols:	pointer to return number of columns
+ * Returns:	0 on success
  */
 static int query_console_serial(int *rows, int *cols)
 {
@@ -371,6 +379,10 @@
 
 	if (mode_number >= efi_con_mode.max_mode)
 		return EFI_EXIT(EFI_UNSUPPORTED);
+
+	if (!efi_cout_modes[mode_number].present)
+		return EFI_EXIT(EFI_UNSUPPORTED);
+
 	efi_con_mode.mode = mode_number;
 	EFI_CALL(efi_cout_clear_screen(this));
 
@@ -452,7 +464,7 @@
  * struct efi_cin_notify_function - registered console input notify function
  *
  * @link:	link to list
- * @data:	key to notify
+ * @key:	key to notify
  * @function:	function to call
  */
 struct efi_cin_notify_function {
@@ -470,6 +482,7 @@
  * set_shift_mask() - set shift mask
  *
  * @mod:	Xterm shift mask
+ * @key_state:  receives the state of the shift, alt, control, and logo keys
  */
 void set_shift_mask(int mod, struct efi_key_state *key_state)
 {
@@ -492,7 +505,7 @@
  *
  * This gets called when we have already parsed CSI.
  *
- * @modifiers:  bit mask (shift, alt, ctrl)
+ * @key_state:  receives the state of the shift, alt, control, and logo keys
  * @return:	the unmodified code
  */
 static int analyze_modifiers(struct efi_key_state *key_state)
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index eeeb806..ea39f13 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -665,7 +665,7 @@
 		cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
 		cddp->dp.length = sizeof(*cddp);
 		cddp->partition_start = info.start;
-		cddp->partition_end = info.size;
+		cddp->partition_size = info.size;
 
 		buf = &cddp[1];
 	} else {
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index 96fd089..b20b7c0 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -60,9 +60,18 @@
 		break;
 	}
 	case DEVICE_PATH_SUB_TYPE_VENDOR: {
+		int i, n;
 		struct efi_device_path_vendor *vdp =
 			(struct efi_device_path_vendor *)dp;
-		s += sprintf(s, "VenHw(%pUl)", &vdp->guid);
+
+		s += sprintf(s, "VenHw(%pUl", &vdp->guid);
+		n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
+		if (n > 0) {
+			s += sprintf(s, ",");
+			for (i = 0; i < n; ++i)
+				s += sprintf(s, "%02x", vdp->vendor_data[i]);
+		}
+		s += sprintf(s, ")");
 		break;
 	}
 	default:
@@ -115,17 +124,16 @@
 		break;
 	}
 	case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
+		int i, n = sizeof(struct efi_mac_addr);
 		struct efi_device_path_mac_addr *mdp =
 			(struct efi_device_path_mac_addr *)dp;
 
-		if (mdp->if_type != 0 && mdp->if_type != 1)
-			break;
-
-		s += sprintf(s, "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
-			mdp->mac.addr[0], mdp->mac.addr[1],
-			mdp->mac.addr[2], mdp->mac.addr[3],
-			mdp->mac.addr[4], mdp->mac.addr[5],
-			mdp->if_type);
+		if (mdp->if_type <= 1)
+			n = 6;
+		s += sprintf(s, "MAC(");
+		for (i = 0; i < n; ++i)
+			s += sprintf(s, "%02x", mdp->mac.addr[i]);
+		s += sprintf(s, ",%u)", mdp->if_type);
 
 		break;
 	}
@@ -133,7 +141,7 @@
 		struct efi_device_path_usb_class *ucdp =
 			(struct efi_device_path_usb_class *)dp;
 
-		s += sprintf(s, "USBClass(%x,%x,%x,%x,%x)",
+		s += sprintf(s, "UsbClass(0x%x,0x%x,0x%x,0x%x,0x%x)",
 			ucdp->vendor_id, ucdp->product_id,
 			ucdp->device_class, ucdp->device_subclass,
 			ucdp->device_protocol);
@@ -206,7 +214,8 @@
 	case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
 		struct efi_device_path_cdrom_path *cddp =
 			(struct efi_device_path_cdrom_path *)dp;
-		s += sprintf(s, "CDROM(0x%x)", cddp->boot_entry);
+		s += sprintf(s, "CDROM(%u,0x%llx,0x%llx)", cddp->boot_entry,
+			     cddp->partition_start, cddp->partition_size);
 		break;
 	}
 	case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 7a6b068..9007a5f 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -41,11 +41,26 @@
 	struct blk_desc *desc;
 };
 
+/**
+ * efi_disk_reset() - reset block device
+ *
+ * This function implements the Reset service of the EFI_BLOCK_IO_PROTOCOL.
+ *
+ * As U-Boot's block devices do not have a reset function simply return
+ * EFI_SUCCESS.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * @this:			pointer to the BLOCK_IO_PROTOCOL
+ * @extended_verification:	extended verification
+ * Return:			status code
+ */
 static efi_status_t EFIAPI efi_disk_reset(struct efi_block_io *this,
 			char extended_verification)
 {
 	EFI_ENTRY("%p, %x", this, extended_verification);
-	return EFI_EXIT(EFI_DEVICE_ERROR);
+	return EFI_EXIT(EFI_SUCCESS);
 }
 
 enum efi_disk_direction {
@@ -69,12 +84,12 @@
 	blocks = buffer_size / blksz;
 	lba += diskobj->offset;
 
-	debug("EFI: %s:%d blocks=%x lba=%llx blksz=%x dir=%d\n", __func__,
-	      __LINE__, blocks, lba, blksz, direction);
+	EFI_PRINT("blocks=%x lba=%llx blksz=%x dir=%d\n",
+		  blocks, lba, blksz, direction);
 
 	/* We only support full block access */
 	if (buffer_size & (blksz - 1))
-		return EFI_DEVICE_ERROR;
+		return EFI_BAD_BUFFER_SIZE;
 
 	if (direction == EFI_DISK_READ)
 		n = blk_dread(desc, lba, blocks, buffer);
@@ -84,7 +99,7 @@
 	/* We don't do interrupts, so check for timers cooperatively */
 	efi_timer_check();
 
-	debug("EFI: %s:%d n=%lx blocks=%x\n", __func__, __LINE__, n, blocks);
+	EFI_PRINT("n=%lx blocks=%x\n", n, blocks);
 
 	if (n != blocks)
 		return EFI_DEVICE_ERROR;
@@ -99,6 +114,20 @@
 	void *real_buffer = buffer;
 	efi_status_t r;
 
+	if (!this)
+		return EFI_INVALID_PARAMETER;
+	/* TODO: check for media changes */
+	if (media_id != this->media->media_id)
+		return EFI_MEDIA_CHANGED;
+	if (!this->media->media_present)
+		return EFI_NO_MEDIA;
+	/* media->io_align is a power of 2 */
+	if ((uintptr_t)buffer & (this->media->io_align - 1))
+		return EFI_INVALID_PARAMETER;
+	if (lba * this->media->block_size + buffer_size >
+	    this->media->last_block * this->media->block_size)
+		return EFI_INVALID_PARAMETER;
+
 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 	if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
 		r = efi_disk_read_blocks(this, media_id, lba,
@@ -134,6 +163,22 @@
 	void *real_buffer = buffer;
 	efi_status_t r;
 
+	if (!this)
+		return EFI_INVALID_PARAMETER;
+	if (this->media->read_only)
+		return EFI_WRITE_PROTECTED;
+	/* TODO: check for media changes */
+	if (media_id != this->media->media_id)
+		return EFI_MEDIA_CHANGED;
+	if (!this->media->media_present)
+		return EFI_NO_MEDIA;
+	/* media->io_align is a power of 2 */
+	if ((uintptr_t)buffer & (this->media->io_align - 1))
+		return EFI_INVALID_PARAMETER;
+	if (lba * this->media->block_size + buffer_size >
+	    this->media->last_block * this->media->block_size)
+		return EFI_INVALID_PARAMETER;
+
 #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER
 	if (buffer_size > EFI_LOADER_BOUNCE_BUFFER_SIZE) {
 		r = efi_disk_write_blocks(this, media_id, lba,
@@ -288,6 +333,11 @@
 	/* Fill in EFI IO Media info (for read/write callbacks) */
 	diskobj->media.removable_media = desc->removable;
 	diskobj->media.media_present = 1;
+	/*
+	 * MediaID is just an arbitrary counter.
+	 * We have to change it if the medium is removed or changed.
+	 */
+	diskobj->media.media_id = 1;
 	diskobj->media.block_size = desc->blksz;
 	diskobj->media.io_align = desc->blksz;
 	diskobj->media.last_block = desc->lba - offset;
diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c
index cad509b..1511e3b 100644
--- a/lib/efi_loader/efi_gop.c
+++ b/lib/efi_loader/efi_gop.c
@@ -319,7 +319,7 @@
  * details.
  *
  * @this:		the graphical output protocol
- * @model_number:	the mode to be set
+ * @mode_number:	the mode to be set
  * Return:		status code
  */
 static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number)
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index b5775e0..83cbc91 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -655,6 +655,54 @@
 	return EFI_SUCCESS;
 }
 
+/**
+ * efi_add_conventional_memory_map() - add a RAM memory area to the map
+ *
+ * @ram_start:		start address of a RAM memory area
+ * @ram_end:		end address of a RAM memory area
+ * @ram_top:		max address to be used as conventional memory
+ * Return:		status code
+ */
+efi_status_t efi_add_conventional_memory_map(u64 ram_start, u64 ram_end,
+					     u64 ram_top)
+{
+	u64 pages;
+
+	/* Remove partial pages */
+	ram_end &= ~EFI_PAGE_MASK;
+	ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
+
+	if (ram_end <= ram_start) {
+		/* Invalid mapping */
+		return EFI_INVALID_PARAMETER;
+	}
+
+	pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
+
+	efi_add_memory_map(ram_start, pages,
+			   EFI_CONVENTIONAL_MEMORY, false);
+
+	/*
+	 * Boards may indicate to the U-Boot memory core that they
+	 * can not support memory above ram_top. Let's honor this
+	 * in the efi_loader subsystem too by declaring any memory
+	 * above ram_top as "already occupied by firmware".
+	 */
+	if (ram_top < ram_start) {
+		/* ram_top is before this region, reserve all */
+		efi_add_memory_map(ram_start, pages,
+				   EFI_BOOT_SERVICES_DATA, true);
+	} else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
+		/* ram_top is inside this region, reserve parts */
+		pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
+
+		efi_add_memory_map(ram_top, pages,
+				   EFI_BOOT_SERVICES_DATA, true);
+	}
+
+	return EFI_SUCCESS;
+}
+
 __weak void efi_add_known_memory(void)
 {
 	u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK;
@@ -672,42 +720,12 @@
 
 	/* Add RAM */
 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
-		u64 ram_end, ram_start, pages;
+		u64 ram_end, ram_start;
 
 		ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0);
 		ram_end = ram_start + gd->bd->bi_dram[i].size;
 
-		/* Remove partial pages */
-		ram_end &= ~EFI_PAGE_MASK;
-		ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK;
-
-		if (ram_end <= ram_start) {
-			/* Invalid mapping, keep going. */
-			continue;
-		}
-
-		pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT;
-
-		efi_add_memory_map(ram_start, pages,
-				   EFI_CONVENTIONAL_MEMORY, false);
-
-		/*
-		 * Boards may indicate to the U-Boot memory core that they
-		 * can not support memory above ram_top. Let's honor this
-		 * in the efi_loader subsystem too by declaring any memory
-		 * above ram_top as "already occupied by firmware".
-		 */
-		if (ram_top < ram_start) {
-			/* ram_top is before this region, reserve all */
-			efi_add_memory_map(ram_start, pages,
-					   EFI_BOOT_SERVICES_DATA, true);
-		} else if ((ram_top >= ram_start) && (ram_top < ram_end)) {
-			/* ram_top is inside this region, reserve parts */
-			pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT;
-
-			efi_add_memory_map(ram_top, pages,
-					   EFI_BOOT_SERVICES_DATA, true);
-		}
+		efi_add_conventional_memory_map(ram_start, ram_end, ram_top);
 	}
 }
 
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index 825e064..82d2595 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -1,8 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- *  EFI application network access support
+ * Simple network protocol
+ * PXE base code protocol
  *
- *  Copyright (c) 2016 Alexander Graf
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * The simple network protocol has the following statuses and services
+ * to move between them:
+ *
+ * Start():	 EfiSimpleNetworkStopped     -> EfiSimpleNetworkStarted
+ * Initialize(): EfiSimpleNetworkStarted     -> EfiSimpleNetworkInitialized
+ * Shutdown():	 EfiSimpleNetworkInitialized -> EfiSimpleNetworkStarted
+ * Stop():	 EfiSimpleNetworkStarted     -> EfiSimpleNetworkStopped
+ * Reset():	 EfiSimpleNetworkInitialized -> EfiSimpleNetworkInitialized
  */
 
 #include <common.h>
@@ -66,10 +76,13 @@
 		goto out;
 	}
 
-	if (this->mode->state != EFI_NETWORK_STOPPED)
+	if (this->mode->state != EFI_NETWORK_STOPPED) {
 		ret = EFI_ALREADY_STARTED;
-	else
+	} else {
+		this->int_status = 0;
+		wait_for_packet->is_signaled = false;
 		this->mode->state = EFI_NETWORK_STARTED;
+	}
 out:
 	return EFI_EXIT(ret);
 }
@@ -96,10 +109,13 @@
 		goto out;
 	}
 
-	if (this->mode->state == EFI_NETWORK_STOPPED)
+	if (this->mode->state == EFI_NETWORK_STOPPED) {
 		ret = EFI_NOT_STARTED;
-	else
+	} else {
+		/* Disable hardware and put it into the reset state */
+		eth_halt();
 		this->mode->state = EFI_NETWORK_STOPPED;
+	}
 out:
 	return EFI_EXIT(ret);
 }
@@ -130,6 +146,15 @@
 		goto out;
 	}
 
+	switch (this->mode->state) {
+	case EFI_NETWORK_INITIALIZED:
+	case EFI_NETWORK_STARTED:
+		break;
+	default:
+		r = EFI_NOT_STARTED;
+		goto out;
+	}
+
 	/* Setup packet buffers */
 	net_init();
 	/* Disable hardware and put it into the reset state */
@@ -144,6 +169,8 @@
 		r = EFI_DEVICE_ERROR;
 		goto out;
 	} else {
+		this->int_status = 0;
+		wait_for_packet->is_signaled = false;
 		this->mode->state = EFI_NETWORK_INITIALIZED;
 	}
 out:
@@ -164,9 +191,31 @@
 static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
 					 int extended_verification)
 {
+	efi_status_t ret;
+
 	EFI_ENTRY("%p, %x", this, extended_verification);
 
-	return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
+	/* Check parameters */
+	if (!this) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	switch (this->mode->state) {
+	case EFI_NETWORK_INITIALIZED:
+		break;
+	case EFI_NETWORK_STOPPED:
+		ret = EFI_NOT_STARTED;
+		goto out;
+	default:
+		ret = EFI_DEVICE_ERROR;
+		goto out;
+	}
+
+	this->mode->state = EFI_NETWORK_STARTED;
+	ret = EFI_CALL(efi_net_initialize(this, 0, 0));
+out:
+	return EFI_EXIT(ret);
 }
 
 /*
@@ -191,8 +240,21 @@
 		goto out;
 	}
 
+	switch (this->mode->state) {
+	case EFI_NETWORK_INITIALIZED:
+		break;
+	case EFI_NETWORK_STOPPED:
+		ret = EFI_NOT_STARTED;
+		goto out;
+	default:
+		ret = EFI_DEVICE_ERROR;
+		goto out;
+	}
+
 	eth_halt();
-	this->mode->state = EFI_NETWORK_STOPPED;
+	this->int_status = 0;
+	wait_for_packet->is_signaled = false;
+	this->mode->state = EFI_NETWORK_STARTED;
 
 out:
 	return EFI_EXIT(ret);
@@ -270,7 +332,7 @@
 /*
  * efi_net_mcastiptomac() - translate multicast IP address to MAC address
  *
- * This function implements the Statistics service of the
+ * This function implements the MCastIPtoMAC service of the
  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
  * (UEFI) specification for details.
  *
@@ -285,9 +347,49 @@
 						struct efi_ip_address *ip,
 						struct efi_mac_address *mac)
 {
+	efi_status_t ret = EFI_SUCCESS;
+
 	EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
 
-	return EFI_EXIT(EFI_INVALID_PARAMETER);
+	if (!this || !ip || !mac) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	if (ipv6) {
+		ret = EFI_UNSUPPORTED;
+		goto out;
+	}
+
+	/* Multi-cast addresses are in the range 224.0.0.0 - 239.255.255.255 */
+	if ((ip->ip_addr[0] & 0xf0) != 0xe0) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	};
+
+	switch (this->mode->state) {
+	case EFI_NETWORK_INITIALIZED:
+	case EFI_NETWORK_STARTED:
+		break;
+	default:
+		ret = EFI_NOT_STARTED;
+		goto out;
+	}
+
+	memset(mac, 0, sizeof(struct efi_mac_address));
+
+	/*
+	 * Copy lower 23 bits of IPv4 multi-cast address
+	 * RFC 1112, RFC 7042 2.1.1.
+	 */
+	mac->mac_addr[0] = 0x01;
+	mac->mac_addr[1] = 0x00;
+	mac->mac_addr[2] = 0x5E;
+	mac->mac_addr[3] = ip->ip_addr[1] & 0x7F;
+	mac->mac_addr[4] = ip->ip_addr[2];
+	mac->mac_addr[5] = ip->ip_addr[3];
+out:
+	return EFI_EXIT(ret);
 }
 
 /**
@@ -297,7 +399,7 @@
  * Protocol. See the UEFI spec for details.
  *
  * @this:		the instance of the Simple Network Protocol
- * @readwrite:		true for read, false for write
+ * @read_write:		true for read, false for write
  * @offset:		offset in NVRAM
  * @buffer_size:	size of buffer
  * @buffer:		buffer
@@ -350,10 +452,8 @@
 	}
 
 	if (int_status) {
-		/* We send packets synchronously, so nothing is outstanding */
-		*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
-		if (new_rx_packet)
-			*int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+		*int_status = this->int_status;
+		this->int_status = 0;
 	}
 	if (txbuf)
 		*txbuf = new_tx_packet;
@@ -404,15 +504,33 @@
 		goto out;
 	}
 
-	if (header_size) {
-		/*
-		 * TODO: We would need to create the header
-		 * if header_size != 0
-		 */
-		ret = EFI_UNSUPPORTED;
+	/* At least the IP header has to fit into the buffer */
+	if (buffer_size < this->mode->media_header_size) {
+		ret = EFI_BUFFER_TOO_SMALL;
 		goto out;
 	}
 
+	/*
+	 * TODO:
+	 * Support VLANs. Use net_set_ether() for copying the header. Use a
+	 * U_BOOT_ENV_CALLBACK to update the media header size.
+	 */
+	if (header_size) {
+		struct ethernet_hdr *header = buffer;
+
+		if (!dest_addr || !protocol ||
+		    header_size != this->mode->media_header_size) {
+			ret = EFI_INVALID_PARAMETER;
+			goto out;
+		}
+		if (!src_addr)
+			src_addr = &this->mode->current_address;
+
+		memcpy(header->et_dest, dest_addr, ARP_HLEN);
+		memcpy(header->et_src, src_addr, ARP_HLEN);
+		header->et_protlen = htons(*protocol);
+	}
+
 	switch (this->mode->state) {
 	case EFI_NETWORK_STOPPED:
 		ret = EFI_NOT_STARTED;
@@ -429,7 +547,7 @@
 	net_send_packet(transmit_buffer, buffer_size);
 
 	new_tx_packet = buffer;
-
+	this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
 out:
 	return EFI_EXIT(ret);
 }
@@ -487,12 +605,6 @@
 		ret = EFI_NOT_READY;
 		goto out;
 	}
-	/* Check that we at least received an Ethernet header */
-	if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
-		new_rx_packet = false;
-		ret = EFI_NOT_READY;
-		goto out;
-	}
 	/* Fill export parameters */
 	eth_hdr = (struct ethernet_hdr *)net_rx_packet;
 	protlen = ntohs(eth_hdr->et_protlen);
@@ -517,7 +629,8 @@
 	/* Copy packet */
 	memcpy(buffer, net_rx_packet, net_rx_packet_len);
 	*buffer_size = net_rx_packet_len;
-	new_rx_packet = false;
+	new_rx_packet = 0;
+	this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
 out:
 	return EFI_EXIT(ret);
 }
@@ -526,6 +639,9 @@
  * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
  *
  * This function is called by dhcp_handler().
+ *
+ * @pkt:	packet received by dhcp_handler()
+ * @len:	length of the packet received
  */
 void efi_net_set_dhcp_ack(void *pkt, int len)
 {
@@ -548,7 +664,6 @@
 static void efi_net_push(void *pkt, int len)
 {
 	new_rx_packet = true;
-	wait_for_packet->is_signaled = true;
 }
 
 /**
@@ -556,8 +671,8 @@
  *
  * This notification function is called in every timer cycle.
  *
- * @event	the event for which this notification function is registered
- * @context	event context - not used in this function
+ * @event:	the event for which this notification function is registered
+ * @context:	event context - not used in this function
  */
 static void EFIAPI efi_network_timer_notify(struct efi_event *event,
 					    void *context)
@@ -577,6 +692,17 @@
 		push_packet = efi_net_push;
 		eth_rx();
 		push_packet = NULL;
+		if (new_rx_packet) {
+			/* Check that we at least received an Ethernet header */
+			if (net_rx_packet_len >=
+			    sizeof(struct ethernet_hdr)) {
+				this->int_status |=
+					EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+				wait_for_packet->is_signaled = true;
+			} else {
+				new_rx_packet = 0;
+			}
+		}
 	}
 out:
 	EFI_EXIT(EFI_SUCCESS);
@@ -751,9 +877,10 @@
 	netobj->net.transmit = efi_net_transmit;
 	netobj->net.receive = efi_net_receive;
 	netobj->net.mode = &netobj->net_mode;
-	netobj->net_mode.state = EFI_NETWORK_STARTED;
+	netobj->net_mode.state = EFI_NETWORK_STOPPED;
 	memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
 	netobj->net_mode.hwaddr_size = ARP_HLEN;
+	netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
 	netobj->net_mode.max_packet_size = PKTSIZE;
 	netobj->net_mode.if_type = ARP_ETHER;
 
diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c
index 4c26619..9797eca 100644
--- a/lib/efi_selftest/efi_selftest_snp.c
+++ b/lib/efi_selftest/efi_selftest_snp.c
@@ -228,6 +228,26 @@
 		efi_st_error("WaitForPacket event missing\n");
 		return EFI_ST_FAILURE;
 	}
+	if (net->mode->state == EFI_NETWORK_INITIALIZED) {
+		/*
+		 * Shut down network adapter.
+		 */
+		ret = net->shutdown(net);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to shut down network adapter\n");
+			return EFI_ST_FAILURE;
+		}
+	}
+	if (net->mode->state == EFI_NETWORK_STARTED) {
+		/*
+		 * Stop network adapter.
+		 */
+		ret = net->stop(net);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to stop network adapter\n");
+			return EFI_ST_FAILURE;
+		}
+	}
 	/*
 	 * Start network adapter.
 	 */
@@ -236,6 +256,10 @@
 		efi_st_error("Failed to start network adapter\n");
 		return EFI_ST_FAILURE;
 	}
+	if (net->mode->state != EFI_NETWORK_STARTED) {
+		efi_st_error("Failed to start network adapter\n");
+		return EFI_ST_FAILURE;
+	}
 	/*
 	 * Initialize network adapter.
 	 */
@@ -244,6 +268,10 @@
 		efi_st_error("Failed to initialize network adapter\n");
 		return EFI_ST_FAILURE;
 	}
+	if (net->mode->state != EFI_NETWORK_INITIALIZED) {
+		efi_st_error("Failed to initialize network adapter\n");
+		return EFI_ST_FAILURE;
+	}
 	return EFI_ST_SUCCESS;
 }
 
@@ -268,6 +296,7 @@
 	struct efi_mac_address destaddr;
 	size_t buffer_size;
 	u8 *addr;
+
 	/*
 	 * The timeout is to occur after 10 s.
 	 */
@@ -298,6 +327,8 @@
 	events[0] = timer;
 	events[1] = net->wait_for_packet;
 	for (;;) {
+		u32 int_status;
+
 		/*
 		 * Wait for packet to be received or timer event.
 		 */
@@ -323,8 +354,17 @@
 		 * Receive packet
 		 */
 		buffer_size = sizeof(buffer);
-		net->receive(net, NULL, &buffer_size, &buffer,
-			     &srcaddr, &destaddr, NULL);
+		ret = net->get_status(net, &int_status, NULL);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to get status");
+			return EFI_ST_FAILURE;
+		}
+		if (!(int_status & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT)) {
+			efi_st_error("RX interrupt not set");
+			return EFI_ST_FAILURE;
+		}
+		ret = net->receive(net, NULL, &buffer_size, &buffer,
+				   &srcaddr, &destaddr, NULL);
 		if (ret != EFI_SUCCESS) {
 			efi_st_error("Failed to receive packet");
 			return EFI_ST_FAILURE;
@@ -400,6 +440,18 @@
 	}
 	if (net) {
 		/*
+		 * Shut down network adapter.
+		 */
+		ret = net->shutdown(net);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("Failed to shut down network adapter\n");
+			exit_status = EFI_ST_FAILURE;
+		}
+		if (net->mode->state != EFI_NETWORK_STARTED) {
+			efi_st_error("Failed to shutdown network adapter\n");
+			return EFI_ST_FAILURE;
+		}
+		/*
 		 * Stop network adapter.
 		 */
 		ret = net->stop(net);
@@ -407,13 +459,9 @@
 			efi_st_error("Failed to stop network adapter\n");
 			exit_status = EFI_ST_FAILURE;
 		}
-		/*
-		 * Shut down network adapter.
-		 */
-		ret = net->shutdown(net);
-		if (ret != EFI_SUCCESS) {
-			efi_st_error("Failed to shut down network adapter\n");
-			exit_status = EFI_ST_FAILURE;
+		if (net->mode->state != EFI_NETWORK_STOPPED) {
+			efi_st_error("Failed to stop network adapter\n");
+			return EFI_ST_FAILURE;
 		}
 	}
 
diff --git a/net/Makefile b/net/Makefile
index 826544f..2a700c8 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -22,6 +22,7 @@
 obj-$(CONFIG_NET)      += net.o
 obj-$(CONFIG_CMD_NFS)  += nfs.o
 obj-$(CONFIG_CMD_PING) += ping.o
+obj-$(CONFIG_CMD_PCAP) += pcap.o
 obj-$(CONFIG_CMD_RARP) += rarp.o
 obj-$(CONFIG_CMD_SNTP) += sntp.o
 obj-$(CONFIG_CMD_TFTPBOOT) += tftp.o
diff --git a/net/eth-uclass.c b/net/eth-uclass.c
index 1d5d2f0..3bd98b0 100644
--- a/net/eth-uclass.c
+++ b/net/eth-uclass.c
@@ -11,6 +11,7 @@
 #include <net.h>
 #include <dm/device-internal.h>
 #include <dm/uclass-internal.h>
+#include <net/pcap.h>
 #include "eth_internal.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -344,6 +345,10 @@
 		/* We cannot completely return the error at present */
 		debug("%s: send() returned error %d\n", __func__, ret);
 	}
+#if defined(CONFIG_CMD_PCAP)
+	if (ret >= 0)
+		pcap_post(packet, length, true);
+#endif
 	return ret;
 }
 
diff --git a/net/eth_legacy.c b/net/eth_legacy.c
index 850f362..41f5263 100644
--- a/net/eth_legacy.c
+++ b/net/eth_legacy.c
@@ -11,6 +11,7 @@
 #include <net.h>
 #include <phy.h>
 #include <linux/errno.h>
+#include <net/pcap.h>
 #include "eth_internal.h"
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -352,10 +353,17 @@
 
 int eth_send(void *packet, int length)
 {
+	int ret;
+
 	if (!eth_current)
 		return -ENODEV;
 
-	return eth_current->send(eth_current, packet, length);
+	ret = eth_current->send(eth_current, packet, length);
+#if defined(CONFIG_CMD_PCAP)
+	if (ret >= 0)
+		pcap_post(packet, lengeth, true);
+#endif
+	return ret;
 }
 
 int eth_rx(void)
diff --git a/net/mdio-uclass.c b/net/mdio-uclass.c
index 36a404f..6f922e8 100644
--- a/net/mdio-uclass.c
+++ b/net/mdio-uclass.c
@@ -23,6 +23,17 @@
 
 static int dm_mdio_post_bind(struct udevice *dev)
 {
+	const char *dt_name;
+
+	/* set a custom name for the MDIO device, if present in DT */
+	if (ofnode_valid(dev->node)) {
+		dt_name = ofnode_read_string(dev->node, "device-name");
+		if (dt_name) {
+			debug("renaming dev %s to %s\n", dev->name, dt_name);
+			device_set_name(dev, dt_name);
+		}
+	}
+
 	/*
 	 * MDIO command doesn't like spaces in names, don't allow them to keep
 	 * it happy
@@ -75,7 +86,7 @@
 	pdata->mii_bus->write = mdio_write;
 	pdata->mii_bus->reset = mdio_reset;
 	pdata->mii_bus->priv = dev;
-	strncpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN);
+	strncpy(pdata->mii_bus->name, dev->name, MDIO_NAME_LEN - 1);
 
 	return mdio_register(pdata->mii_bus);
 }
diff --git a/net/net.c b/net/net.c
index 40511db..ded86e7 100644
--- a/net/net.c
+++ b/net/net.c
@@ -96,6 +96,9 @@
 #include <net.h>
 #include <net/fastboot.h>
 #include <net/tftp.h>
+#if defined(CONFIG_CMD_PCAP)
+#include <net/pcap.h>
+#endif
 #if defined(CONFIG_LED_STATUS)
 #include <miiphy.h>
 #include <status_led.h>
@@ -672,6 +675,11 @@
 	net_set_icmp_handler(NULL);
 #endif
 	net_set_state(prev_net_state);
+
+#if defined(CONFIG_CMD_PCAP)
+	if (pcap_active())
+		pcap_print_status();
+#endif
 	return ret;
 }
 
@@ -1084,6 +1092,9 @@
 
 	debug_cond(DEBUG_NET_PKT, "packet received\n");
 
+#if defined(CONFIG_CMD_PCAP)
+	pcap_post(in_packet, len, false);
+#endif
 	net_rx_packet = in_packet;
 	net_rx_packet_len = len;
 	et = (struct ethernet_hdr *)in_packet;
@@ -1253,6 +1264,9 @@
 			return;
 		}
 
+		if (ntohs(ip->udp_len) < UDP_HDR_SIZE || ntohs(ip->udp_len) > ntohs(ip->ip_len))
+			return;
+
 		debug_cond(DEBUG_DEV_PKT,
 			   "received UDP (to=%pI4, from=%pI4, len=%d)\n",
 			   &dst_ip, &src_ip, len);
diff --git a/net/nfs.c b/net/nfs.c
index d6a7f8e..aca0ca5 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -196,10 +196,10 @@
 		rpc_pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
 	}
 	rpc_pkt.u.call.proc = htonl(rpc_proc);
-	p = (uint32_t *)&(rpc_pkt.u.call.data);
+	p = rpc_pkt.u.call.data;
 
 	if (datalen)
-		memcpy((char *)p, (char *)data, datalen*sizeof(uint32_t));
+		memcpy(p, data, datalen * sizeof(uint32_t));
 
 	pktlen = (char *)p + datalen * sizeof(uint32_t) - (char *)&rpc_pkt;
 
@@ -566,11 +566,15 @@
 	}
 
 	if (supported_nfs_versions & NFSV2_FLAG) {
+		if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + NFS_FHSIZE) > len)
+			return -NFS_RPC_DROP;
 		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
 	} else {  /* NFSV3_FLAG */
 		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
 		if (filefh3_length > NFS3_FHSIZE)
 			filefh3_length  = NFS3_FHSIZE;
+		if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + filefh3_length) > len)
+			return -NFS_RPC_DROP;
 		memcpy(filefh, rpc_pkt.u.reply.data + 2, filefh3_length);
 	}
 
@@ -579,7 +583,7 @@
 
 static int nfs3_get_attributes_offset(uint32_t *data)
 {
-	if (ntohl(data[1]) != 0) {
+	if (data[1]) {
 		/* 'attributes_follow' flag is TRUE,
 		 * so we have attributes on 21 dwords */
 		/* Skip unused values :
@@ -634,6 +638,9 @@
 	/* new path length */
 	rlen = ntohl(rpc_pkt.u.reply.data[1 + nfsv3_data_offset]);
 
+	if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + rlen) > len)
+		return -NFS_RPC_DROP;
+
 	if (*((char *)&(rpc_pkt.u.reply.data[2 + nfsv3_data_offset])) != '/') {
 		int pathlen;
 
@@ -701,6 +708,9 @@
 			&(rpc_pkt.u.reply.data[4 + nfsv3_data_offset]);
 	}
 
+	if (((uchar *)&(rpc_pkt.u.reply.data[0]) - (uchar *)(&rpc_pkt) + rlen) > len)
+			return -9999;
+
 	if (store_block(data_ptr, nfs_offset, rlen))
 			return -9999;
 
@@ -732,6 +742,9 @@
 
 	debug("%s\n", __func__);
 
+	if (len > sizeof(struct rpc_t))
+		return;
+
 	if (dest != nfs_our_port)
 		return;
 
diff --git a/net/nfs.h b/net/nfs.h
index a377c90..68ada0e 100644
--- a/net/nfs.h
+++ b/net/nfs.h
@@ -78,7 +78,7 @@
 				NFS_MAX_ATTRS];
 		} reply;
 	} u;
-} __attribute__((packed));
+};
 void nfs_start(void);	/* Begin NFS */
 
 
diff --git a/net/pcap.c b/net/pcap.c
new file mode 100644
index 0000000..4036d8a
--- /dev/null
+++ b/net/pcap.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 Ramon Fried <rfried.dev@gmail.com>
+ */
+
+#include <common.h>
+#include <net.h>
+#include <net/pcap.h>
+#include <time.h>
+#include <asm/io.h>
+
+#define LINKTYPE_ETHERNET	1
+
+static bool initialized;
+static bool running;
+static bool buffer_full;
+static void *buf;
+static unsigned int max_size;
+static unsigned int pos;
+
+static unsigned long incoming_count;
+static unsigned long outgoing_count;
+
+struct pcap_header {
+	u32 magic;
+	u16 version_major;
+	u16 version_minor;
+	s32 thiszone;
+	u32 sigfigs;
+	u32 snaplen;
+	u32 network;
+};
+
+struct pcap_packet_header {
+	u32 ts_sec;
+	u32 ts_usec;
+	u32 incl_len;
+	u32 orig_len;
+};
+
+static struct pcap_header file_header = {
+	.magic = 0xa1b2c3d4,
+	.version_major = 2,
+	.version_minor = 4,
+	.snaplen = 65535,
+	.network = LINKTYPE_ETHERNET,
+};
+
+int pcap_init(phys_addr_t paddr, unsigned long size)
+{
+	buf = map_physmem(paddr, size, 0);
+	if (!buf) {
+		printf("Failed mapping PCAP memory\n");
+		return -ENOMEM;
+	}
+
+	printf("PCAP capture initialized: addr: 0x%lx max length: %lu\n",
+	       (unsigned long)buf, size);
+
+	memcpy(buf, &file_header, sizeof(file_header));
+	pos = sizeof(file_header);
+	max_size = size;
+	initialized = true;
+	running = false;
+	buffer_full = false;
+	incoming_count = 0;
+	outgoing_count = 0;
+	return 0;
+}
+
+int pcap_start_stop(bool start)
+{
+	if (!initialized) {
+		printf("error: pcap was not initialized\n");
+		return -ENODEV;
+	}
+
+	running = start;
+
+	return 0;
+}
+
+int pcap_clear(void)
+{
+	if (!initialized) {
+		printf("error: pcap was not initialized\n");
+		return -ENODEV;
+	}
+
+	pos = sizeof(file_header);
+	incoming_count = 0;
+	outgoing_count = 0;
+	buffer_full = false;
+
+	printf("pcap capture cleared\n");
+	return 0;
+}
+
+int pcap_post(const void *packet, size_t len, bool outgoing)
+{
+	struct pcap_packet_header header;
+	u64 cur_time = timer_get_us();
+
+	if (!initialized || !running || !buf)
+		return -ENODEV;
+
+	if (buffer_full)
+		return -ENOMEM;
+
+	if ((pos + len + sizeof(header)) >= max_size) {
+		buffer_full = true;
+		printf("\n!!! Buffer is full, consider increasing buffer size !!!\n");
+		return -ENOMEM;
+	}
+
+	header.ts_sec = cur_time / 1000000;
+	header.ts_usec = cur_time % 1000000;
+	header.incl_len = len;
+	header.orig_len = len;
+
+	memcpy(buf + pos, &header, sizeof(header));
+	pos += sizeof(header);
+	memcpy(buf + pos, packet, len);
+	pos += len;
+
+	if (outgoing)
+		outgoing_count++;
+	else
+		incoming_count++;
+
+	env_set_hex("pcapsize", pos);
+
+	return 0;
+}
+
+int pcap_print_status(void)
+{
+	if (!initialized) {
+		printf("pcap was not initialized\n");
+		return -ENODEV;
+	}
+	printf("PCAP status:\n");
+	printf("\tInitialized addr: 0x%lx\tmax length: %u\n",
+	       (unsigned long)buf, max_size);
+	printf("\tStatus: %s.\t file size: %u\n", running ? "Active" : "Idle",
+	       pos);
+	printf("\tIncoming packets: %lu Outgoing packets: %lu\n",
+	       incoming_count, outgoing_count);
+
+	return 0;
+}
+
+bool pcap_active(void)
+{
+	return running;
+}