Merge tag 'dm-pull-12jun20' of git://git.denx.de/u-boot-dm into next

patman improvements to allow it to work with Zephyr
change to how sequence numbers are assigned to devices
minor fixes and improvements
diff --git a/Kconfig b/Kconfig
index 0e7ccc0..34a88ebe 100644
--- a/Kconfig
+++ b/Kconfig
@@ -358,12 +358,26 @@
 	help
 	  Enable this to support SHA256 checksum of FIT image contents. A
 	  SHA256 checksum is a 256-bit (32-byte) hash value used to check that
-	  the image contents have not been corrupted. SHA256 is recommended
-	  for use in secure applications since (as at 2016) there is no known
-	  feasible attack that could produce a 'collision' with differing
-	  input data. Use this for the highest security. Note that only the
-	  SHA256 variant is supported: SHA512 and others are not currently
-	  supported in U-Boot.
+	  the image contents have not been corrupted.
+
+config FIT_ENABLE_SHA384_SUPPORT
+	bool "Support SHA384 checksum of FIT image contents"
+	default n
+	select SHA384
+	help
+	  Enable this to support SHA384 checksum of FIT image contents. A
+	  SHA384 checksum is a 384-bit (48-byte) hash value used to check that
+	  the image contents have not been corrupted. Use this for the highest
+	  security.
+
+config FIT_ENABLE_SHA512_SUPPORT
+	bool "Support SHA512 checksum of FIT image contents"
+	default n
+	select SHA512
+	help
+	  Enable this to support SHA512 checksum of FIT image contents. A
+	  SHA512 checksum is a 512-bit (64-byte) hash value used to check that
+	  the image contents have not been corrupted.
 
 config FIT_SIGNATURE
 	bool "Enable signature verification of FIT uImages"
diff --git a/board/tbs/tbs2910/MAINTAINERS b/board/tbs/tbs2910/MAINTAINERS
index a3ad2f7..1e3c0d0 100644
--- a/board/tbs/tbs2910/MAINTAINERS
+++ b/board/tbs/tbs2910/MAINTAINERS
@@ -4,4 +4,5 @@
 F:	arch/arm/dts/imx6q-tbs2910.dts
 F:	board/tbs/tbs2910/
 F:	configs/tbs2910_defconfig
+F:	doc/board/tbs/
 F:	include/configs/tbs2910.h
diff --git a/cmd/net.c b/cmd/net.c
index 25390b0..9bbcdbc 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -135,11 +135,15 @@
 		env_set("netmask", tmp);
 	}
 
+#ifdef CONFIG_CMD_BOOTP
 	if (net_hostname[0])
 		env_set("hostname", net_hostname);
+#endif
 
+#ifdef CONFIG_CMD_BOOTP
 	if (net_root_path[0])
 		env_set("rootpath", net_root_path);
+#endif
 
 	if (net_ip.s_addr) {
 		ip_to_string(net_ip, tmp);
@@ -165,8 +169,10 @@
 		env_set("dnsip2", tmp);
 	}
 #endif
+#ifdef CONFIG_CMD_BOOTP
 	if (net_nis_domain[0])
 		env_set("domain", net_nis_domain);
+#endif
 
 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
 	if (net_ntp_time_offset) {
diff --git a/common/hash.c b/common/hash.c
index 8c00659..5c75848 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -31,6 +31,7 @@
 #include <u-boot/crc.h>
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
 #include <u-boot/md5.h>
 
 #if !defined(USE_HOSTCC) && defined(CONFIG_NEEDS_MANUAL_RELOC)
@@ -95,6 +96,65 @@
 }
 #endif
 
+#if defined(CONFIG_SHA384)
+static int hash_init_sha384(struct hash_algo *algo, void **ctxp)
+{
+	sha512_context *ctx = malloc(sizeof(sha512_context));
+	sha384_starts(ctx);
+	*ctxp = ctx;
+	return 0;
+}
+
+static int hash_update_sha384(struct hash_algo *algo, void *ctx,
+			      const void *buf, unsigned int size, int is_last)
+{
+	sha384_update((sha512_context *)ctx, buf, size);
+	return 0;
+}
+
+static int hash_finish_sha384(struct hash_algo *algo, void *ctx, void
+			      *dest_buf, int size)
+{
+	if (size < algo->digest_size)
+		return -1;
+
+	sha384_finish((sha512_context *)ctx, dest_buf);
+	free(ctx);
+	return 0;
+}
+#endif
+
+#if defined(CONFIG_SHA512)
+static int hash_init_sha512(struct hash_algo *algo, void **ctxp)
+{
+	sha512_context *ctx = malloc(sizeof(sha512_context));
+	sha512_starts(ctx);
+	*ctxp = ctx;
+	return 0;
+}
+
+static int hash_update_sha512(struct hash_algo *algo, void *ctx,
+			      const void *buf, unsigned int size, int is_last)
+{
+	sha512_update((sha512_context *)ctx, buf, size);
+	return 0;
+}
+
+static int hash_finish_sha512(struct hash_algo *algo, void *ctx, void
+			      *dest_buf, int size)
+{
+	if (size < algo->digest_size)
+		return -1;
+
+	printf("hello world\n");
+
+	sha512_finish((sha512_context *)ctx, dest_buf);
+	free(ctx);
+	return 0;
+}
+#endif
+
+
 static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
 {
 	uint16_t *ctx = malloc(sizeof(uint16_t));
@@ -196,6 +256,28 @@
 #endif
 	},
 #endif
+#ifdef CONFIG_SHA384
+	{
+		.name		= "sha384",
+		.digest_size	= SHA384_SUM_LEN,
+		.chunk_size	= CHUNKSZ_SHA384,
+		.hash_func_ws	= sha384_csum_wd,
+		.hash_init	= hash_init_sha384,
+		.hash_update	= hash_update_sha384,
+		.hash_finish	= hash_finish_sha384,
+	},
+#endif
+#ifdef CONFIG_SHA512
+	{
+		.name		= "sha512",
+		.digest_size	= SHA512_SUM_LEN,
+		.chunk_size	= CHUNKSZ_SHA512,
+		.hash_func_ws	= sha512_csum_wd,
+		.hash_init	= hash_init_sha512,
+		.hash_update	= hash_update_sha512,
+		.hash_finish	= hash_finish_sha512,
+	},
+#endif
 	{
 		.name		= "crc16-ccitt",
 		.digest_size	= 2,
@@ -218,7 +300,8 @@
 
 /* Try to minimize code size for boards that don't want much hashing */
 #if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM) || \
-	defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH)
+	defined(CONFIG_CRC32_VERIFY) || defined(CONFIG_CMD_HASH) || \
+	defined(CONFIG_SHA384) || defined(CONFIG_SHA512)
 #define multi_hash()	1
 #else
 #define multi_hash()	0
diff --git a/common/image-fit.c b/common/image-fit.c
index 1ece100..d54eff9 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -32,6 +32,7 @@
 #include <u-boot/md5.h>
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
 
 /*****************************************************************************/
 /* New uImage format routines */
@@ -1206,6 +1207,14 @@
 		sha256_csum_wd((unsigned char *)data, data_len,
 			       (unsigned char *)value, CHUNKSZ_SHA256);
 		*value_len = SHA256_SUM_LEN;
+	} else if (IMAGE_ENABLE_SHA384 && strcmp(algo, "sha384") == 0) {
+		sha384_csum_wd((unsigned char *)data, data_len,
+			       (unsigned char *)value, CHUNKSZ_SHA384);
+		*value_len = SHA384_SUM_LEN;
+	} else if (IMAGE_ENABLE_SHA512 && strcmp(algo, "sha512") == 0) {
+		sha512_csum_wd((unsigned char *)data, data_len,
+			       (unsigned char *)value, CHUNKSZ_SHA512);
+		*value_len = SHA512_SUM_LEN;
 	} else if (IMAGE_ENABLE_MD5 && strcmp(algo, "md5") == 0) {
 		md5_wd((unsigned char *)data, data_len, value, CHUNKSZ_MD5);
 		*value_len = 16;
diff --git a/common/image-sig.c b/common/image-sig.c
index 498969d..f3c209a 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -40,7 +40,31 @@
 		.calculate_sign = EVP_sha256,
 #endif
 		.calculate = hash_calculate,
-	}
+	},
+#ifdef CONFIG_SHA384
+	{
+		.name = "sha384",
+		.checksum_len = SHA384_SUM_LEN,
+		.der_len = SHA384_DER_LEN,
+		.der_prefix = sha384_der_prefix,
+#if IMAGE_ENABLE_SIGN
+		.calculate_sign = EVP_sha384,
+#endif
+		.calculate = hash_calculate,
+	},
+#endif
+#ifdef CONFIG_SHA512
+	{
+		.name = "sha512",
+		.checksum_len = SHA512_SUM_LEN,
+		.der_len = SHA512_DER_LEN,
+		.der_prefix = sha512_der_prefix,
+#if IMAGE_ENABLE_SIGN
+		.calculate_sign = EVP_sha512,
+#endif
+		.calculate = hash_calculate,
+	},
+#endif
 
 };
 
diff --git a/common/spl/Kconfig b/common/spl/Kconfig
index 8ece905..3eae65e 100644
--- a/common/spl/Kconfig
+++ b/common/spl/Kconfig
@@ -412,7 +412,7 @@
 	  secure as it is possible (with a brute-force attack) to adjust the
 	  image while still retaining the same MD5 hash value. For secure
 	  applications where images may be changed maliciously, you should
-	  consider SHA1 or SHA256.
+	  consider SHA256 or SHA384.
 
 config SPL_SHA1_SUPPORT
 	bool "Support SHA1"
@@ -424,7 +424,7 @@
 	  image contents have not been corrupted or maliciously altered.
 	  While SHA1 is fairly secure it is coming to the end of its life
 	  due to the expanding computing power available to brute-force
-	  attacks. For more security, consider SHA256.
+	  attacks. For more security, consider SHA256 or SHA384.
 
 config SPL_SHA256_SUPPORT
 	bool "Support SHA256"
@@ -433,12 +433,28 @@
 	help
 	  Enable this to support SHA256 in FIT images within SPL. A SHA256
 	  checksum is a 256-bit (32-byte) hash value used to check that the
-	  image contents have not been corrupted. SHA256 is recommended for
-	  use in secure applications since (as at 2016) there is no known
-	  feasible attack that could produce a 'collision' with differing
-	  input data. Use this for the highest security. Note that only the
-	  SHA256 variant is supported: SHA512 and others are not currently
-	  supported in U-Boot.
+	  image contents have not been corrupted.
+
+config SPL_SHA384_SUPPORT
+	bool "Support SHA384"
+	depends on SPL_FIT
+	select SHA384
+	select SHA512_ALGO
+	help
+	  Enable this to support SHA384 in FIT images within SPL. A SHA384
+	  checksum is a 384-bit (48-byte) hash value used to check that the
+	  image contents have not been corrupted. Use this for the highest
+	  security.
+
+config SPL_SHA512_SUPPORT
+	bool "Support SHA512"
+	depends on SPL_FIT
+	select SHA512
+	select SHA512_ALGO
+	help
+	  Enable this to support SHA512 in FIT images within SPL. A SHA512
+	  checksum is a 512-bit (64-byte) hash value used to check that the
+	  image contents have not been corrupted.
 
 config SPL_FIT_IMAGE_TINY
 	bool "Remove functionality from SPL FIT loading to reduce size"
diff --git a/configs/P2041RDB_SECURE_BOOT_defconfig b/configs/P2041RDB_SECURE_BOOT_defconfig
index b3e4280..35a9d00 100644
--- a/configs/P2041RDB_SECURE_BOOT_defconfig
+++ b/configs/P2041RDB_SECURE_BOOT_defconfig
@@ -46,7 +46,6 @@
 CONFIG_DM_ETH=y
 CONFIG_DM_MDIO=y
 CONFIG_PHY_GIGE=y
-CONFIG_E1000=y
 CONFIG_FMAN_ENET=y
 CONFIG_MII=y
 CONFIG_SYS_QE_FMAN_FW_IN_NOR=y
@@ -58,4 +57,3 @@
 CONFIG_RSA=y
 CONFIG_SPL_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
-CONFIG_OF_LIBFDT=y
diff --git a/configs/T1024RDB_NAND_defconfig b/configs/T1024RDB_NAND_defconfig
index f6deee9..e3a955a 100644
--- a/configs/T1024RDB_NAND_defconfig
+++ b/configs/T1024RDB_NAND_defconfig
@@ -34,9 +34,9 @@
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DM=y
 CONFIG_SYS_MEMTEST_START=0x00200000
 CONFIG_SYS_MEMTEST_END=0x00400000
+CONFIG_CMD_DM=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
diff --git a/configs/T1024RDB_SDCARD_defconfig b/configs/T1024RDB_SDCARD_defconfig
index a0042d8..b3abeeb 100644
--- a/configs/T1024RDB_SDCARD_defconfig
+++ b/configs/T1024RDB_SDCARD_defconfig
@@ -32,9 +32,9 @@
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DM=y
 CONFIG_SYS_MEMTEST_START=0x00200000
 CONFIG_SYS_MEMTEST_END=0x00400000
+CONFIG_CMD_DM=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
diff --git a/configs/T1024RDB_SECURE_BOOT_defconfig b/configs/T1024RDB_SECURE_BOOT_defconfig
index 6ef2dfd..fe3d28b 100644
--- a/configs/T1024RDB_SECURE_BOOT_defconfig
+++ b/configs/T1024RDB_SECURE_BOOT_defconfig
@@ -19,9 +19,9 @@
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DM=y
 CONFIG_SYS_MEMTEST_START=0x00200000
 CONFIG_SYS_MEMTEST_END=0x00400000
+CONFIG_CMD_DM=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
@@ -53,7 +53,6 @@
 CONFIG_PHYLIB=y
 CONFIG_PHY_AQUANTIA=y
 CONFIG_PHY_REALTEK=y
-CONFIG_E1000=y
 CONFIG_DM_ETH=y
 CONFIG_DM_MDIO=y
 CONFIG_FMAN_ENET=y
@@ -67,4 +66,3 @@
 CONFIG_RSA=y
 CONFIG_SPL_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
-CONFIG_OF_LIBFDT=y
diff --git a/configs/T1024RDB_SPIFLASH_defconfig b/configs/T1024RDB_SPIFLASH_defconfig
index a07c391..04e8cc6 100644
--- a/configs/T1024RDB_SPIFLASH_defconfig
+++ b/configs/T1024RDB_SPIFLASH_defconfig
@@ -34,9 +34,9 @@
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DM=y
 CONFIG_SYS_MEMTEST_START=0x00200000
 CONFIG_SYS_MEMTEST_END=0x00400000
+CONFIG_CMD_DM=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
diff --git a/configs/T1024RDB_defconfig b/configs/T1024RDB_defconfig
index 79fb395..46c857d 100644
--- a/configs/T1024RDB_defconfig
+++ b/configs/T1024RDB_defconfig
@@ -19,9 +19,9 @@
 CONFIG_CMD_GREPENV=y
 CONFIG_CMD_MEMTEST=y
 CONFIG_SYS_ALT_MEMTEST=y
-CONFIG_CMD_DM=y
 CONFIG_SYS_MEMTEST_START=0x00200000
 CONFIG_SYS_MEMTEST_END=0x00400000
+CONFIG_CMD_DM=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_SF=y
diff --git a/configs/am65x_evm_a53_defconfig b/configs/am65x_evm_a53_defconfig
index d74a2d0..c5ca4da 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -99,7 +99,7 @@
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_E1000=y
diff --git a/configs/am65x_hs_evm_a53_defconfig b/configs/am65x_hs_evm_a53_defconfig
index 1179538..644873d 100644
--- a/configs/am65x_hs_evm_a53_defconfig
+++ b/configs/am65x_hs_evm_a53_defconfig
@@ -101,7 +101,7 @@
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_E1000=y
diff --git a/configs/dra7xx_evm_defconfig b/configs/dra7xx_evm_defconfig
index e4547d9..73ac3b3 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -86,7 +86,7 @@
 CONFIG_SF_DEFAULT_MODE=0
 CONFIG_SF_DEFAULT_SPEED=76800000
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
diff --git a/configs/dra7xx_hs_evm_defconfig b/configs/dra7xx_hs_evm_defconfig
index c08bcce..40dc554 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -89,7 +89,7 @@
 CONFIG_SF_DEFAULT_MODE=0
 CONFIG_SF_DEFAULT_SPEED=76800000
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
diff --git a/configs/dra7xx_hs_evm_usb_defconfig b/configs/dra7xx_hs_evm_usb_defconfig
index 879c2b6..babd702 100644
--- a/configs/dra7xx_hs_evm_usb_defconfig
+++ b/configs/dra7xx_hs_evm_usb_defconfig
@@ -87,7 +87,7 @@
 CONFIG_SF_DEFAULT_SPEED=76800000
 CONFIG_SPI_FLASH_BAR=y
 CONFIG_SPI_FLASH_SPANSION=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_DM_ETH=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
diff --git a/configs/firefly-rk3399_defconfig b/configs/firefly-rk3399_defconfig
index 5bb54f5..5181510 100644
--- a/configs/firefly-rk3399_defconfig
+++ b/configs/firefly-rk3399_defconfig
@@ -18,8 +18,8 @@
 CONFIG_CMD_BOOTZ=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_USB=y
 CONFIG_CMD_PCI=y
+CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_SPL_OF_CONTROL=y
diff --git a/configs/j721e_evm_a72_defconfig b/configs/j721e_evm_a72_defconfig
index 4deb4e2..91a0572 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -123,7 +123,7 @@
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_TI_AM65_CPSW_NUSS=y
diff --git a/configs/j721e_hs_evm_a72_defconfig b/configs/j721e_hs_evm_a72_defconfig
index ae540a2..9aa3113 100644
--- a/configs/j721e_hs_evm_a72_defconfig
+++ b/configs/j721e_hs_evm_a72_defconfig
@@ -113,7 +113,7 @@
 CONFIG_SPI_FLASH_STMICRO=y
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_SPI_FLASH_MTD=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_FIXED=y
 CONFIG_DM_ETH=y
 CONFIG_TI_AM65_CPSW_NUSS=y
diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig
index 5bc7f7f..0379021 100644
--- a/configs/k2g_evm_defconfig
+++ b/configs/k2g_evm_defconfig
@@ -58,7 +58,7 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_PHY_MICREL=y
 CONFIG_PHY_MICREL_KSZ8XXX=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/rock-pi-e-rk3328_defconfig b/configs/rock-pi-e-rk3328_defconfig
index 7598387..e094122 100644
--- a/configs/rock-pi-e-rk3328_defconfig
+++ b/configs/rock-pi-e-rk3328_defconfig
@@ -27,9 +27,9 @@
 # CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
 CONFIG_TPL_SYS_MALLOC_SIMPLE=y
 CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000
 CONFIG_SPL_I2C_SUPPORT=y
 CONFIG_SPL_POWER_SUPPORT=y
-CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN=0x10000
 CONFIG_SPL_ATF=y
 CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y
 CONFIG_TPL_DRIVERS_MISC_SUPPORT=y
@@ -72,8 +72,8 @@
 CONFIG_PMIC_RK8XX=y
 CONFIG_SPL_DM_REGULATOR=y
 CONFIG_REGULATOR_PWM=y
-CONFIG_SPL_DM_REGULATOR_FIXED=y
 CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_SPL_DM_REGULATOR_FIXED=y
 CONFIG_REGULATOR_RK8XX=y
 CONFIG_PWM_ROCKCHIP=y
 CONFIG_RAM=y
diff --git a/configs/rockpro64-rk3399_defconfig b/configs/rockpro64-rk3399_defconfig
index 8077474..ad0c6ab 100644
--- a/configs/rockpro64-rk3399_defconfig
+++ b/configs/rockpro64-rk3399_defconfig
@@ -22,8 +22,8 @@
 CONFIG_CMD_BOOTZ=y
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_USB=y
 CONFIG_CMD_PCI=y
+CONFIG_CMD_USB=y
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_TIME=y
 CONFIG_SPL_OF_CONTROL=y
@@ -50,8 +50,8 @@
 CONFIG_REGULATOR_PWM=y
 CONFIG_REGULATOR_RK8XX=y
 CONFIG_PWM_ROCKCHIP=y
-CONFIG_DM_RESET=y
 CONFIG_RAM_RK3399_LPDDR4=y
+CONFIG_DM_RESET=y
 CONFIG_BAUDRATE=1500000
 CONFIG_DEBUG_UART_SHIFT=2
 CONFIG_ROCKCHIP_SPI=y
diff --git a/configs/tbs2910_defconfig b/configs/tbs2910_defconfig
index 2ff0e16..fbd2293 100644
--- a/configs/tbs2910_defconfig
+++ b/configs/tbs2910_defconfig
@@ -9,11 +9,15 @@
 CONFIG_PRE_CON_BUF_ADDR=0x7c000000
 CONFIG_CMD_HDMIDETECT=y
 CONFIG_AHCI=y
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
 CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="mmc rescan; if run bootcmd_up1; then run bootcmd_up2; else run bootcmd_mmc || run distro_bootcmd; fi"
 CONFIG_USE_PREBOOT=y
 CONFIG_PREBOOT="echo PCI:; pci enum; pci 1; usb start; if hdmidet; then run set_con_hdmi; else run set_con_serial; fi"
 CONFIG_PRE_CONSOLE_BUFFER=y
 CONFIG_SUPPORT_RAW_INITRD=y
+CONFIG_DEFAULT_FDT_FILE="imx6q-tbs2910.dtb"
 CONFIG_BOUNCE_BUFFER=y
 CONFIG_BOARD_EARLY_INIT_F=y
 CONFIG_HUSH_PARSER=y
@@ -28,6 +32,8 @@
 CONFIG_SYS_MEMTEST_END=0x2f400000
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
+# CONFIG_CMD_LOADB is not set
+# CONFIG_CMD_LOADS is not set
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
 CONFIG_CMD_PCI=y
@@ -39,6 +45,7 @@
 CONFIG_CMD_PING=y
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_SYSBOOT=y
 CONFIG_CMD_EXT2=y
 CONFIG_CMD_EXT4=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -86,5 +93,6 @@
 CONFIG_I2C_EDID=y
 CONFIG_VIDEO_IPUV3=y
 CONFIG_VIDEO=y
+# CONFIG_GZIP is not set
 CONFIG_OF_LIBFDT_ASSUME_MASK=0xff
 # CONFIG_EFI_LOADER is not set
diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig
index 4ed14f7..b3e21ea 100644
--- a/configs/xilinx_versal_virt_defconfig
+++ b/configs/xilinx_versal_virt_defconfig
@@ -63,7 +63,7 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_PHY_NATSEMI=y
 CONFIG_PHY_REALTEK=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_VITESSE=y
 CONFIG_PHY_FIXED=y
 CONFIG_PHY_GIGE=y
diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig
index 7886d5a..2b4a024 100644
--- a/configs/xilinx_zynqmp_virt_defconfig
+++ b/configs/xilinx_zynqmp_virt_defconfig
@@ -108,7 +108,7 @@
 CONFIG_PHY_MICREL_KSZ90X1=y
 CONFIG_PHY_NATSEMI=y
 CONFIG_PHY_REALTEK=y
-CONFIG_PHY_TI=y
+CONFIG_PHY_TI_DP83867=y
 CONFIG_PHY_VITESSE=y
 CONFIG_PHY_XILINX_GMII2RGMII=y
 CONFIG_PHY_FIXED=y
diff --git a/doc/board/index.rst b/doc/board/index.rst
index 01b233f..bb44731 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -18,5 +18,6 @@
    rockchip/index
    sifive/index
    st/index
+   tbs/index
    toradex/index
    xilinx/index
diff --git a/doc/board/tbs/index.rst b/doc/board/tbs/index.rst
new file mode 100644
index 0000000..b677bc6
--- /dev/null
+++ b/doc/board/tbs/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+TBS
+===
+
+.. toctree::
+   :maxdepth: 2
+
+   tbs2910
diff --git a/doc/board/tbs/tbs2910.rst b/doc/board/tbs/tbs2910.rst
new file mode 100644
index 0000000..e97f2b6
--- /dev/null
+++ b/doc/board/tbs/tbs2910.rst
@@ -0,0 +1,191 @@
+TBS2910 Matrix ARM miniPC
+=========================
+
+Building
+--------
+To build u-boot for the TBS2910 Matrix ARM miniPC, you can use the following
+procedure:
+
+First add the ARM toolchain to your PATH
+
+Then setup the ARCH and cross compilation environment variables.
+
+When this is done you can then build u-boot for the TBS2910 Matrix ARM miniPC
+with the following commands:
+
+.. code-block:: none
+
+   make mrproper
+   make tbs2910_defconfig
+   make
+
+Once the build is complete, you can find the resulting image as u-boot.imx in
+the current directory.
+
+UART
+----
+The UART voltage is at 3.3V and its settings are 115200bps 8N1
+
+BOOT/UPDATE boot switch:
+------------------------
+The BOOT/UPDATE switch (SW11) is connected to the BOOT_MODE0 and
+BOOT_MODE1 SoC pins. It has "BOOT" and "UPDATE" markings both on
+the PCB and on the plastic case.
+
+When set to the "UPDATE" position, the SoC will use the "Boot From Fuses"
+configuration, and since BT_FUSE_SEL is 0, this makes the SOC jump to serial
+downloader.
+
+When set in the "BOOT" position, the SoC will use the "Internal boot"
+configuration, and since BT_FUSE_SEL is 0, it will then use the GPIO pins
+for the boot configuration.
+
+SW6 binary DIP switch array on the PCB revision 2.1:
+----------------------------------------------------
+On that PCB revision, SW6 has 8 positions.
+
+Switching a position to ON sets the corresponding
+register to 1.
+
+See the following table for a correspondence between the switch positions and
+registers:
+
+===============    ============
+Switch position    Register
+===============    ============
+1                  BOOT_CFG2[3]
+2                  BOOT_CFG2[4]
+3                  BOOT_CFG2[5]
+4                  BOOT_CFG2[6]
+5                  BOOT_CFG1[4]
+6                  BOOT_CFG1[5]
+7                  BOOT_CFG1[6]
+8                  BOOT_CFG1[7]
+===============    ============
+
+For example:
+
+  - To boot from the eMMC: 1:ON , 2:ON, 3:ON, 4:OFF, 5:OFF, 6:ON, 7:ON, 8:OFF
+  - To boot from the microSD slot: 1: ON, 2: OFF, 3: OFF, 4: OFF, 5:OFF, 6:OFF,
+    7:ON, 8:OFF
+  - To boot from the SD slot: 1: OFF, 2: ON, 3: OFF, 4: OFF, 5:OFF, 6:OFF, 7:ON,
+    8:OFF
+  - To boot from SATA: 1: OFF, 2: OFF, 3: OFF, 4: OFF, 5:OFF, 6:ON, 7:OFF, 8:OFF
+
+You can refer to the BOOT_CFG registers in the I.MX6Q reference manual for
+additional details.
+
+SW6 binary DIP switch array on the PCB revision 2.3:
+----------------------------------------------------
+On that PCB revision, SW6 has only 4 positions.
+
+Switching a position to ON sets the corresponding
+register to 1.
+
+See the following table for a correspondence between the switch positions and
+registers:
+
+===============    ============
+Switch position    Register
+===============    ============
+1                  BOOT_CFG2[3]
+2                  BOOT_CFG2[4]
+3                  BOOT_CFG2[5]
+4                  BOOT_CFG1[5]
+===============    ============
+
+For example:
+
+- To boot from the eMMC: 1:ON, 2:ON, 3:ON, 4:ON
+- To boot from the microSD slot: 1:ON, 2:OFF, 3:OFF, 4:OFF
+- To boot from the SD slot: 1:OFF, 2:ON, 3:OFF, 4:OFF
+
+You can refer to the BOOT_CFG registers in the I.MX6Q reference manual for
+additional details.
+
+Loading u-boot from USB:
+------------------------
+If you need to load u-boot from USB, you can use the following instructions:
+
+First build imx_usb_loader, as we will need it to load u-boot from USB. This
+can be done with the following commands:
+
+.. code-block:: none
+
+   git clone git://github.com/boundarydevices/imx_usb_loader.git
+   cd imx_usb_loader
+   make
+
+This will create the resulting imx_usb binary.
+
+When this is done, you can copy the u-boot.imx image that you built earlier
+in in the imx_usb_loader directory.
+
+You will then need to power off the TBS2910 Matrix ARM miniPC and make sure that
+the boot switch is set to "UPDATE"
+
+Once this is done you can connect an USB cable between the computer that will
+run imx_usb and the TBS2910 Matrix ARM miniPC.
+
+If you also need to access the u-boot console, you will also need to connect an
+UART cable between the computer running imx_usb and the TBS2910 Matrix ARM
+miniPC.
+
+Once everything is connected you can finally power on the TBS2910 Matrix ARM
+miniPC. The SoC will then jump to the serial download and wait for you.
+
+Finlay, you can load u-boot through USB with with the following command:
+
+.. code-block:: none
+
+   sudo ./imx_usb -v u-boot.imx
+
+The u-boot boot messages will then appear in the serial console.
+
+Install u-boot on the eMMC:
+---------------------------
+To install u-boot on the eMMC, you first need to boot the TBS2910 Matrix ARM
+miniPC.
+
+Once booted, you can flash u-boot.imx to mmcblk0boot0 with the
+following commands:
+
+.. code-block:: none
+
+   sudo echo 0 >/sys/block/mmcblk0boot0/force_ro
+   sudo dd if=u-boot.imx of=/dev/mmcblk0boot0 bs=1k seek=1; sync
+
+Note that the eMMC card node may vary, so adjust this as needed.
+
+Once the new u-boot version is installed, to boot on it you then need to power
+off the TBS2910 Matrix ARM miniPC.
+
+Once it is off, you need make sure that the boot switch is set to "BOOT" and
+that the SW6 switch is set to boot on the eMMC as described in the previous
+sections.
+
+If you also need to access the u-boot console, you will also need to connect an
+UART cable between the computer running imx_usb and the TBS2910 Matrix ARM
+miniPC.
+
+You can then power up the TBS2910 Matrix ARM miniPC and U-Boot messages will
+appear in the serial console.
+
+Booting a distribution:
+-----------------------
+When booting on the TBS2910 Matrix ARM miniPC, by default U-Boot will first try
+to boot from hardcoded offsets from the start of the eMMC. This is for
+compatibility with the stock GNU/Linux distribution.
+
+If that fails it will then try to boot from several interfaces using
+'distro_bootcmd': It will first try to boot from the microSD slot, then the
+SD slot, then the internal eMMC, then the SATA interface and finally the USB
+interface. For more information on how to configure your distribution to boot,
+see 'README.distro'.
+
+Links:
+------
+  - https://www.tbsdtv.com/download/document/tbs2910/TBS2910-Matrix-ARM-mini-PC-SCH_rev2.1.pdf
+    - The schematics for the revision 2.1 of the TBS2910 Matrix ARM miniPC.
+  - https://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf - The
+    SoC reference manual for additional details on the BOOT_CFG registers.
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d1f049e..b0bd762 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -243,6 +243,21 @@
 
 config PHY_TI
 	bool "Texas Instruments Ethernet PHYs support"
+	---help---
+	  Adds PHY registration support for TI PHYs.
+
+config PHY_TI_DP83867
+	select PHY_TI
+	bool "Texas Instruments Ethernet DP83867 PHY support"
+	---help---
+	  Adds support for the TI DP83867 1Gbit PHY.
+
+config PHY_TI_GENERIC
+	select PHY_TI
+	bool "Texas Instruments Generic Ethernet PHYs support"
+	---help---
+	  Adds support for Generic TI PHYs that don't need special handling but
+	  the PHY name is associated with a PHY ID.
 
 config PHY_VITESSE
 	bool "Vitesse Ethernet PHYs support"
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1d81516..6e72233 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -25,7 +25,8 @@
 obj-$(CONFIG_PHY_REALTEK) += realtek.o
 obj-$(CONFIG_PHY_SMSC) += smsc.o
 obj-$(CONFIG_PHY_TERANETICS) += teranetics.o
-obj-$(CONFIG_PHY_TI) += dp83867.o
+obj-$(CONFIG_PHY_TI) += ti_phy_init.o
+obj-$(CONFIG_PHY_TI_DP83867) += dp83867.o
 obj-$(CONFIG_PHY_XILINX) += xilinx_phy.o
 obj-$(CONFIG_PHY_XILINX_GMII2RGMII) += xilinx_gmii2rgmii.o
 obj-$(CONFIG_PHY_VITESSE) += vitesse.o
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index d435cc1..eada454 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c
@@ -14,6 +14,7 @@
 #include <dm.h>
 #include <dt-bindings/net/ti-dp83867.h>
 
+#include "ti_phy_init.h"
 
 /* TI DP83867 */
 #define DP83867_DEVADDR		0x1f
@@ -430,7 +431,7 @@
 	.shutdown = &genphy_shutdown,
 };
 
-int phy_ti_init(void)
+int phy_dp83867_init(void)
 {
 	phy_register(&DP83867_driver);
 	return 0;
diff --git a/drivers/net/phy/micrel_ksz8xxx.c b/drivers/net/phy/micrel_ksz8xxx.c
index 98a0c83..60d42fe 100644
--- a/drivers/net/phy/micrel_ksz8xxx.c
+++ b/drivers/net/phy/micrel_ksz8xxx.c
@@ -82,6 +82,21 @@
 	.shutdown = &genphy_shutdown,
 };
 
+static int ksz8061_config(struct phy_device *phydev)
+{
+	return phy_write(phydev, MDIO_MMD_PMAPMD, MDIO_DEVID1, 0xB61A);
+}
+
+static struct phy_driver KSZ8061_driver = {
+	.name = "Micrel KSZ8061",
+	.uid = 0x00221570,
+	.mask = 0xfffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &ksz8061_config,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
 static int ksz8081_config(struct phy_device *phydev)
 {
 	int ret;
@@ -210,6 +225,7 @@
 	phy_register(&KSZ804_driver);
 	phy_register(&KSZ8031_driver);
 	phy_register(&KSZ8051_driver);
+	phy_register(&KSZ8061_driver);
 	phy_register(&KSZ8081_driver);
 	phy_register(&KS8721_driver);
 	phy_register(&ksz8895_driver);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cce09c4..6778989 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -786,17 +786,27 @@
 						 uint phy_mask,
 						 phy_interface_t interface)
 {
-	int i;
 	struct phy_device *phydev;
+	int devad[] = {
+		/* Clause-22 */
+		MDIO_DEVAD_NONE,
+		/* Clause-45 */
+		MDIO_MMD_PMAPMD,
+		MDIO_MMD_WIS,
+		MDIO_MMD_PCS,
+		MDIO_MMD_PHYXS,
+		MDIO_MMD_VEND1,
+	};
+	int i, devad_cnt;
 
+	devad_cnt = sizeof(devad)/sizeof(int);
 	phydev = search_for_existing_phy(bus, phy_mask, interface);
 	if (phydev)
 		return phydev;
-	/* Try Standard (ie Clause 22) access */
-	/* Otherwise we have to try Clause 45 */
-	for (i = 0; i < 5; i++) {
+	/* try different access clauses  */
+	for (i = 0; i < devad_cnt; i++) {
 		phydev = create_phy_by_mask(bus, phy_mask,
-					    i ? i : MDIO_DEVAD_NONE, interface);
+					    devad[i], interface);
 		if (IS_ERR(phydev))
 			return NULL;
 		if (phydev)
diff --git a/drivers/net/phy/ti_phy_init.c b/drivers/net/phy/ti_phy_init.c
new file mode 100644
index 0000000..50eff77
--- /dev/null
+++ b/drivers/net/phy/ti_phy_init.c
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TI Generic PHY Init to register any TI Ethernet PHYs
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright (C) 2019-20 Texas Instruments Inc.
+ */
+
+#include <phy.h>
+#include "ti_phy_init.h"
+
+#ifdef CONFIG_PHY_TI_GENERIC
+static struct phy_driver dp83822_driver = {
+	.name = "TI DP83822",
+	.uid = 0x2000a240,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83826nc_driver = {
+	.name = "TI DP83826NC",
+	.uid = 0x2000a110,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83826c_driver = {
+	.name = "TI DP83826C",
+	.uid = 0x2000a130,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83825s_driver = {
+	.name = "TI DP83825S",
+	.uid = 0x2000a140,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83825i_driver = {
+	.name = "TI DP83825I",
+	.uid = 0x2000a150,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83825m_driver = {
+	.name = "TI DP83825M",
+	.uid = 0x2000a160,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+
+static struct phy_driver dp83825cs_driver = {
+	.name = "TI DP83825CS",
+	.uid = 0x2000a170,
+	.mask = 0xfffffff0,
+	.features = PHY_BASIC_FEATURES,
+	.config = &genphy_config_aneg,
+	.startup = &genphy_startup,
+	.shutdown = &genphy_shutdown,
+};
+#endif /* CONFIG_PHY_TI_GENERIC */
+
+int phy_ti_init(void)
+{
+#ifdef CONFIG_PHY_TI_DP83867
+	phy_dp83867_init();
+#endif
+
+#ifdef CONFIG_PHY_TI_GENERIC
+	phy_register(&dp83822_driver);
+	phy_register(&dp83825s_driver);
+	phy_register(&dp83825i_driver);
+	phy_register(&dp83825m_driver);
+	phy_register(&dp83825cs_driver);
+	phy_register(&dp83826c_driver);
+	phy_register(&dp83826nc_driver);
+#endif
+	return 0;
+}
diff --git a/drivers/net/phy/ti_phy_init.h b/drivers/net/phy/ti_phy_init.h
new file mode 100644
index 0000000..6c7f6c6
--- /dev/null
+++ b/drivers/net/phy/ti_phy_init.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * TI Generic Ethernet PHY
+ *
+ * Author: Dan Murphy <dmurphy@ti.com>
+ *
+ * Copyright (C) 2019-20 Texas Instruments Inc.
+ */
+
+#ifndef _TI_GEN_PHY_H
+#define _TI_GEN_PHY_H
+
+int phy_dp83867_init(void);
+
+#endif /* _TI_GEN_PHY_H */
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index 0daeefa..8a6f305 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -70,6 +70,7 @@
 
 #include <common.h>
 #include <cpu_func.h>
+#include <dm.h>
 #include <log.h>
 #include <malloc.h>
 #include <net.h>
@@ -96,8 +97,13 @@
 #define DEBUG_TX	0	/* set to 1 to enable debug code */
 #define DEBUG_RX	0	/* set to 1 to enable debug code */
 
-#define bus_to_phys(a)	pci_mem_to_phys((pci_dev_t)dev->priv, a)
-#define phys_to_bus(a)	pci_phys_to_mem((pci_dev_t)dev->priv, a)
+#ifdef CONFIG_DM_ETH
+#define bus_to_phys(devno, a)	dm_pci_mem_to_phys((devno), (a))
+#define phys_to_bus(devno, a)	dm_pci_phys_to_mem((devno), (a))
+#else
+#define bus_to_phys(devno, a)	pci_mem_to_phys((pci_dev_t)(devno), (a))
+#define phys_to_bus(devno, a)	pci_phys_to_mem((pci_dev_t)(devno), (a))
+#endif
 
 /* Symbolic offsets to registers. */
 /* Ethernet hardware address. */
@@ -191,8 +197,19 @@
 #define RTL_STS_RXBADALIGN			BIT(1)
 #define RTL_STS_RXSTATUSOK			BIT(0)
 
-static unsigned int cur_rx, cur_tx;
-static int ioaddr;
+struct rtl8139_priv {
+#ifndef CONFIG_DM_ETH
+	struct eth_device	dev;
+	pci_dev_t		devno;
+#else
+	struct udevice		*devno;
+#endif
+	unsigned int		rxstatus;
+	unsigned int		cur_rx;
+	unsigned int		cur_tx;
+	unsigned long		ioaddr;
+	unsigned char		enetaddr[6];
+};
 
 /* The RTL8139 can only transmit from a contiguous, aligned memory block.  */
 static unsigned char tx_buffer[TX_BUF_SIZE] __aligned(4);
@@ -214,51 +231,52 @@
 #define EE_READ_CMD	6
 #define EE_ERASE_CMD	7
 
-static void rtl8139_eeprom_delay(uintptr_t regbase)
+static void rtl8139_eeprom_delay(struct rtl8139_priv *priv)
 {
 	/*
 	 * Delay between EEPROM clock transitions.
 	 * No extra delay is needed with 33MHz PCI, but 66MHz may change this.
 	 */
-	inl(regbase + RTL_REG_CFG9346);
+	inl(priv->ioaddr + RTL_REG_CFG9346);
 }
 
-static int rtl8139_read_eeprom(unsigned int location, unsigned int addr_len)
+static int rtl8139_read_eeprom(struct rtl8139_priv *priv,
+			       unsigned int location, unsigned int addr_len)
 {
 	unsigned int read_cmd = location | (EE_READ_CMD << addr_len);
-	uintptr_t ee_addr = ioaddr + RTL_REG_CFG9346;
+	uintptr_t ee_addr = priv->ioaddr + RTL_REG_CFG9346;
 	unsigned int retval = 0;
 	u8 dataval;
 	int i;
 
 	outb(EE_ENB & ~EE_CS, ee_addr);
 	outb(EE_ENB, ee_addr);
-	rtl8139_eeprom_delay(ioaddr);
+	rtl8139_eeprom_delay(priv);
 
 	/* Shift the read command bits out. */
 	for (i = 4 + addr_len; i >= 0; i--) {
 		dataval = (read_cmd & BIT(i)) ? EE_DATA_WRITE : 0;
 		outb(EE_ENB | dataval, ee_addr);
-		rtl8139_eeprom_delay(ioaddr);
+		rtl8139_eeprom_delay(priv);
 		outb(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
-		rtl8139_eeprom_delay(ioaddr);
+		rtl8139_eeprom_delay(priv);
 	}
 
 	outb(EE_ENB, ee_addr);
-	rtl8139_eeprom_delay(ioaddr);
+	rtl8139_eeprom_delay(priv);
 
 	for (i = 16; i > 0; i--) {
 		outb(EE_ENB | EE_SHIFT_CLK, ee_addr);
-		rtl8139_eeprom_delay(ioaddr);
+		rtl8139_eeprom_delay(priv);
 		retval <<= 1;
 		retval |= inb(ee_addr) & EE_DATA_READ;
 		outb(EE_ENB, ee_addr);
-		rtl8139_eeprom_delay(ioaddr);
+		rtl8139_eeprom_delay(priv);
 	}
 
 	/* Terminate the EEPROM access. */
 	outb(~EE_CS, ee_addr);
-	rtl8139_eeprom_delay(ioaddr);
+	rtl8139_eeprom_delay(priv);
 
 	return retval;
 }
@@ -268,29 +286,29 @@
 	(RX_FIFO_THRESH << 13) |
 	(RX_DMA_BURST << 8);
 
-static void rtl8139_set_rx_mode(struct eth_device *dev)
+static void rtl8139_set_rx_mode(struct rtl8139_priv *priv)
 {
 	/* !IFF_PROMISC */
 	unsigned int rx_mode = RTL_REG_RXCONFIG_ACCEPTBROADCAST |
 			       RTL_REG_RXCONFIG_ACCEPTMULTICAST |
 			       RTL_REG_RXCONFIG_ACCEPTMYPHYS;
 
-	outl(rtl8139_rx_config | rx_mode, ioaddr + RTL_REG_RXCONFIG);
+	outl(rtl8139_rx_config | rx_mode, priv->ioaddr + RTL_REG_RXCONFIG);
 
-	outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 0);
-	outl(0xffffffff, ioaddr + RTL_REG_MAR0 + 4);
+	outl(0xffffffff, priv->ioaddr + RTL_REG_MAR0 + 0);
+	outl(0xffffffff, priv->ioaddr + RTL_REG_MAR0 + 4);
 }
 
-static void rtl8139_hw_reset(struct eth_device *dev)
+static void rtl8139_hw_reset(struct rtl8139_priv *priv)
 {
 	u8 reg;
 	int i;
 
-	outb(RTL_REG_CHIPCMD_CMDRESET, ioaddr + RTL_REG_CHIPCMD);
+	outb(RTL_REG_CHIPCMD_CMDRESET, priv->ioaddr + RTL_REG_CHIPCMD);
 
 	/* Give the chip 10ms to finish the reset. */
 	for (i = 0; i < 100; i++) {
-		reg = inb(ioaddr + RTL_REG_CHIPCMD);
+		reg = inb(priv->ioaddr + RTL_REG_CHIPCMD);
 		if (!(reg & RTL_REG_CHIPCMD_CMDRESET))
 			break;
 
@@ -298,25 +316,25 @@
 	}
 }
 
-static void rtl8139_reset(struct eth_device *dev)
+static void rtl8139_reset(struct rtl8139_priv *priv)
 {
 	int i;
 
-	cur_rx = 0;
-	cur_tx = 0;
+	priv->cur_rx = 0;
+	priv->cur_tx = 0;
 
-	rtl8139_hw_reset(dev);
+	rtl8139_hw_reset(priv);
 
 	for (i = 0; i < ETH_ALEN; i++)
-		outb(dev->enetaddr[i], ioaddr + RTL_REG_MAC0 + i);
+		outb(priv->enetaddr[i], priv->ioaddr + RTL_REG_MAC0 + i);
 
 	/* Must enable Tx/Rx before setting transfer thresholds! */
 	outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
-	     ioaddr + RTL_REG_CHIPCMD);
+	     priv->ioaddr + RTL_REG_CHIPCMD);
 
 	/* accept no frames yet! */
-	outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
-	outl((TX_DMA_BURST << 8) | 0x03000000, ioaddr + RTL_REG_TXCONFIG);
+	outl(rtl8139_rx_config, priv->ioaddr + RTL_REG_RXCONFIG);
+	outl((TX_DMA_BURST << 8) | 0x03000000, priv->ioaddr + RTL_REG_TXCONFIG);
 
 	/*
 	 * The Linux driver changes RTL_REG_CONFIG1 here to use a different
@@ -331,7 +349,7 @@
 	debug_cond(DEBUG_RX, "rx ring address is %p\n", rx_ring);
 
 	flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
-	outl(phys_to_bus((int)rx_ring), ioaddr + RTL_REG_RXBUF);
+	outl(phys_to_bus(priv->devno, (int)rx_ring), priv->ioaddr + RTL_REG_RXBUF);
 
 	/*
 	 * If we add multicast support, the RTL_REG_MAR0 register would have
@@ -340,28 +358,27 @@
 	 * unicast.
 	 */
 	outb(RTL_REG_CHIPCMD_CMDRXENB | RTL_REG_CHIPCMD_CMDTXENB,
-	     ioaddr + RTL_REG_CHIPCMD);
+	     priv->ioaddr + RTL_REG_CHIPCMD);
 
-	outl(rtl8139_rx_config, ioaddr + RTL_REG_RXCONFIG);
+	outl(rtl8139_rx_config, priv->ioaddr + RTL_REG_RXCONFIG);
 
 	/* Start the chip's Tx and Rx process. */
-	outl(0, ioaddr + RTL_REG_RXMISSED);
+	outl(0, priv->ioaddr + RTL_REG_RXMISSED);
 
-	rtl8139_set_rx_mode(dev);
+	rtl8139_set_rx_mode(priv);
 
 	/* Disable all known interrupts by setting the interrupt mask. */
-	outw(0, ioaddr + RTL_REG_INTRMASK);
+	outw(0, priv->ioaddr + RTL_REG_INTRMASK);
 }
 
-static int rtl8139_send(struct eth_device *dev, void *packet, int length)
+static int rtl8139_send_common(struct rtl8139_priv *priv,
+			       void *packet, int length)
 {
 	unsigned int len = length;
 	unsigned long txstatus;
 	unsigned int status;
 	int i = 0;
 
-	ioaddr = dev->iobase;
-
 	memcpy(tx_buffer, packet, length);
 
 	debug_cond(DEBUG_TX, "sending %d bytes\n", len);
@@ -374,13 +391,13 @@
 		tx_buffer[len++] = '\0';
 
 	flush_cache((unsigned long)tx_buffer, length);
-	outl(phys_to_bus((unsigned long)tx_buffer),
-	     ioaddr + RTL_REG_TXADDR0 + cur_tx * 4);
+	outl(phys_to_bus(priv->devno, (unsigned long)tx_buffer),
+	     priv->ioaddr + RTL_REG_TXADDR0 + priv->cur_tx * 4);
 	outl(((TX_FIFO_THRESH << 11) & 0x003f0000) | len,
-	     ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
+	     priv->ioaddr + RTL_REG_TXSTATUS0 + priv->cur_tx * 4);
 
 	do {
-		status = inw(ioaddr + RTL_REG_INTRSTATUS);
+		status = inw(priv->ioaddr + RTL_REG_INTRSTATUS);
 		/*
 		 * Only acknlowledge interrupt sources we can properly
 		 * handle here - the RTL_REG_INTRSTATUS_RXOVERFLOW/
@@ -389,26 +406,26 @@
 		 */
 		status &= RTL_REG_INTRSTATUS_TXOK | RTL_REG_INTRSTATUS_TXERR |
 			  RTL_REG_INTRSTATUS_PCIERR;
-		outw(status, ioaddr + RTL_REG_INTRSTATUS);
+		outw(status, priv->ioaddr + RTL_REG_INTRSTATUS);
 		if (status)
 			break;
 
 		udelay(10);
 	} while (i++ < RTL_TIMEOUT);
 
-	txstatus = inl(ioaddr + RTL_REG_TXSTATUS0 + cur_tx * 4);
+	txstatus = inl(priv->ioaddr + RTL_REG_TXSTATUS0 + priv->cur_tx * 4);
 
 	if (!(status & RTL_REG_INTRSTATUS_TXOK)) {
 		debug_cond(DEBUG_TX,
 			   "tx timeout/error (%d usecs), status %hX txstatus %lX\n",
 			   10 * i, status, txstatus);
 
-		rtl8139_reset(dev);
+		rtl8139_reset(priv);
 
 		return 0;
 	}
 
-	cur_tx = (cur_tx + 1) % NUM_TX_DESC;
+	priv->cur_tx = (priv->cur_tx + 1) % NUM_TX_DESC;
 
 	debug_cond(DEBUG_TX, "tx done, status %hX txstatus %lX\n",
 		   status, txstatus);
@@ -416,28 +433,26 @@
 	return length;
 }
 
-static int rtl8139_recv(struct eth_device *dev)
+static int rtl8139_recv_common(struct rtl8139_priv *priv, unsigned char *rxdata,
+			       uchar **packetp)
 {
 	const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
 				    RTL_REG_INTRSTATUS_RXOVERFLOW |
 				    RTL_REG_INTRSTATUS_RXOK;
 	unsigned int rx_size, rx_status;
 	unsigned int ring_offs;
-	unsigned int status;
 	int length = 0;
 
-	ioaddr = dev->iobase;
-
-	if (inb(ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
+	if (inb(priv->ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
 		return 0;
 
-	status = inw(ioaddr + RTL_REG_INTRSTATUS);
+	priv->rxstatus = inw(priv->ioaddr + RTL_REG_INTRSTATUS);
 	/* See below for the rest of the interrupt acknowledges.  */
-	outw(status & ~rxstat, ioaddr + RTL_REG_INTRSTATUS);
+	outw(priv->rxstatus & ~rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
 
-	debug_cond(DEBUG_RX, "%s: int %hX ", __func__, status);
+	debug_cond(DEBUG_RX, "%s: int %hX ", __func__, priv->rxstatus);
 
-	ring_offs = cur_rx % RX_BUF_LEN;
+	ring_offs = priv->cur_rx % RX_BUF_LEN;
 	/* ring_offs is guaranteed being 4-byte aligned */
 	rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs));
 	rx_size = rx_status >> 16;
@@ -450,59 +465,61 @@
 	    (rx_size > ETH_FRAME_LEN + 4)) {
 		printf("rx error %hX\n", rx_status);
 		/* this clears all interrupts still pending */
-		rtl8139_reset(dev);
+		rtl8139_reset(priv);
 		return 0;
 	}
 
 	/* Received a good packet */
 	length = rx_size - 4;	/* no one cares about the FCS */
 	if (ring_offs + 4 + rx_size - 4 > RX_BUF_LEN) {
-		unsigned char rxdata[RX_BUF_LEN];
 		int semi_count = RX_BUF_LEN - ring_offs - 4;
 
 		memcpy(rxdata, rx_ring + ring_offs + 4, semi_count);
 		memcpy(&rxdata[semi_count], rx_ring,
 		       rx_size - 4 - semi_count);
 
-		net_process_received_packet(rxdata, length);
+		*packetp = rxdata;
 		debug_cond(DEBUG_RX, "rx packet %d+%d bytes",
 			   semi_count, rx_size - 4 - semi_count);
 	} else {
-		net_process_received_packet(rx_ring + ring_offs + 4, length);
+		*packetp = rx_ring + ring_offs + 4;
 		debug_cond(DEBUG_RX, "rx packet %d bytes", rx_size - 4);
 	}
+
+	return length;
+}
+
+static int rtl8139_free_pkt_common(struct rtl8139_priv *priv, unsigned int len)
+{
+	const unsigned int rxstat = RTL_REG_INTRSTATUS_RXFIFOOVER |
+				    RTL_REG_INTRSTATUS_RXOVERFLOW |
+				    RTL_REG_INTRSTATUS_RXOK;
+	unsigned int rx_size = len + 4;
+
 	flush_cache((unsigned long)rx_ring, RX_BUF_LEN);
 
-	cur_rx = ROUND(cur_rx + rx_size + 4, 4);
-	outw(cur_rx - 16, ioaddr + RTL_REG_RXBUFPTR);
+	priv->cur_rx = ROUND(priv->cur_rx + rx_size + 4, 4);
+	outw(priv->cur_rx - 16, priv->ioaddr + RTL_REG_RXBUFPTR);
 	/*
 	 * See RTL8139 Programming Guide V0.1 for the official handling of
 	 * Rx overflow situations. The document itself contains basically
 	 * no usable information, except for a few exception handling rules.
 	 */
-	outw(status & rxstat, ioaddr + RTL_REG_INTRSTATUS);
+	outw(priv->rxstatus & rxstat, priv->ioaddr + RTL_REG_INTRSTATUS);
 
-	return length;
+	return 0;
 }
 
-static int rtl8139_init(struct eth_device *dev, bd_t *bis)
+static int rtl8139_init_common(struct rtl8139_priv *priv)
 {
-	unsigned short *ap = (unsigned short *)dev->enetaddr;
-	int addr_len, i;
 	u8 reg;
 
-	ioaddr = dev->iobase;
-
 	/* Bring the chip out of low-power mode. */
-	outb(0x00, ioaddr + RTL_REG_CONFIG1);
+	outb(0x00, priv->ioaddr + RTL_REG_CONFIG1);
 
-	addr_len = rtl8139_read_eeprom(0, 8) == 0x8129 ? 8 : 6;
-	for (i = 0; i < 3; i++)
-		*ap++ = le16_to_cpu(rtl8139_read_eeprom(i + 7, addr_len));
-
-	rtl8139_reset(dev);
+	rtl8139_reset(priv);
 
-	reg = inb(ioaddr + RTL_REG_MEDIASTATUS);
+	reg = inb(priv->ioaddr + RTL_REG_MEDIASTATUS);
 	if (reg & RTL_REG_MEDIASTATUS_MSRLINKFAIL) {
 		printf("Cable not connected or other link failure\n");
 		return -1;
@@ -511,27 +528,82 @@
 	return 0;
 }
 
-static void rtl8139_stop(struct eth_device *dev)
+static void rtl8139_stop_common(struct rtl8139_priv *priv)
 {
-	ioaddr = dev->iobase;
+	rtl8139_hw_reset(priv);
+}
 
-	rtl8139_hw_reset(dev);
+static void rtl8139_get_hwaddr(struct rtl8139_priv *priv)
+{
+	unsigned short *ap = (unsigned short *)priv->enetaddr;
+	int i, addr_len;
+
+	/* Bring the chip out of low-power mode. */
+	outb(0x00, priv->ioaddr + RTL_REG_CONFIG1);
+
+	addr_len = rtl8139_read_eeprom(priv, 0, 8) == 0x8129 ? 8 : 6;
+	for (i = 0; i < 3; i++)
+		*ap++ = le16_to_cpu(rtl8139_read_eeprom(priv, i + 7, addr_len));
 }
 
-static int rtl8139_bcast_addr(struct eth_device *dev, const u8 *bcast_mac,
-			      int join)
+static void rtl8139_name(char *str, int card_number)
 {
-	return 0;
+	sprintf(str, "RTL8139#%u", card_number);
 }
 
 static struct pci_device_id supported[] = {
-	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139 },
-	{ PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139 },
+	{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139) },
 	{ }
 };
 
+#ifndef CONFIG_DM_ETH
+static int rtl8139_bcast_addr(struct eth_device *dev, const u8 *bcast_mac,
+			      int join)
+{
+	return 0;
+}
+
+static int rtl8139_init(struct eth_device *dev, bd_t *bis)
+{
+	struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+	return rtl8139_init_common(priv);
+}
+
+static void rtl8139_stop(struct eth_device *dev)
+{
+	struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+	return rtl8139_stop_common(priv);
+}
+
+static int rtl8139_send(struct eth_device *dev, void *packet, int length)
+{
+	struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+
+	return rtl8139_send_common(priv, packet, length);
+}
+
+static int rtl8139_recv(struct eth_device *dev)
+{
+	struct rtl8139_priv *priv = container_of(dev, struct rtl8139_priv, dev);
+	unsigned char rxdata[RX_BUF_LEN];
+	uchar *packet;
+	int ret;
+
+	ret = rtl8139_recv_common(priv, rxdata, &packet);
+	if (ret) {
+		net_process_received_packet(packet, ret);
+		rtl8139_free_pkt_common(priv, ret);
+	}
+
+	return ret;
+}
+
 int rtl8139_initialize(bd_t *bis)
 {
+	struct rtl8139_priv *priv;
 	struct eth_device *dev;
 	int card_number = 0;
 	pci_dev_t devno;
@@ -549,23 +621,31 @@
 
 		debug("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
 
-		dev = (struct eth_device *)malloc(sizeof(*dev));
-		if (!dev) {
+		priv = calloc(1, sizeof(*priv));
+		if (!priv) {
 			printf("Can not allocate memory of rtl8139\n");
 			break;
 		}
-		memset(dev, 0, sizeof(*dev));
+
+		priv->devno = devno;
+		priv->ioaddr = (unsigned long)bus_to_phys(devno, iobase);
 
-		sprintf(dev->name, "RTL8139#%d", card_number);
+		dev = &priv->dev;
 
-		dev->priv = (void *)devno;
-		dev->iobase = (int)bus_to_phys(iobase);
+		rtl8139_name(dev->name, card_number);
+
+		dev->iobase = priv->ioaddr;	/* Non-DM compatibility */
 		dev->init = rtl8139_init;
 		dev->halt = rtl8139_stop;
 		dev->send = rtl8139_send;
 		dev->recv = rtl8139_recv;
 		dev->mcast = rtl8139_bcast_addr;
 
+		rtl8139_get_hwaddr(priv);
+
+		/* Non-DM compatibility */
+		memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
+
 		eth_register(dev);
 
 		card_number++;
@@ -577,3 +657,123 @@
 
 	return card_number;
 }
+#else /* DM_ETH */
+static int rtl8139_start(struct udevice *dev)
+{
+	struct eth_pdata *plat = dev_get_platdata(dev);
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+
+	memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+
+	return rtl8139_init_common(priv);
+}
+
+static void rtl8139_stop(struct udevice *dev)
+{
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+
+	rtl8139_stop_common(priv);
+}
+
+static int rtl8139_send(struct udevice *dev, void *packet, int length)
+{
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = rtl8139_send_common(priv, packet, length);
+
+	return ret ? 0 : -ETIMEDOUT;
+}
+
+static int rtl8139_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+	static unsigned char rxdata[RX_BUF_LEN];
+
+	return rtl8139_recv_common(priv, rxdata, packetp);
+}
+
+static int rtl8139_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+
+	rtl8139_free_pkt_common(priv, length);
+
+	return 0;
+}
+
+static int rtl8139_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *plat = dev_get_platdata(dev);
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+
+	memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+
+	rtl8139_reset(priv);
+
+	return 0;
+}
+
+static int rtl8139_read_rom_hwaddr(struct udevice *dev)
+{
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+
+	rtl8139_get_hwaddr(priv);
+
+	return 0;
+}
+
+static int rtl8139_bind(struct udevice *dev)
+{
+	static int card_number;
+	char name[16];
+
+	rtl8139_name(name, card_number++);
+
+	return device_set_name(dev, name);
+}
+
+static int rtl8139_probe(struct udevice *dev)
+{
+	struct eth_pdata *plat = dev_get_platdata(dev);
+	struct rtl8139_priv *priv = dev_get_priv(dev);
+	u32 iobase;
+
+	dm_pci_read_config32(dev, PCI_BASE_ADDRESS_1, &iobase);
+	iobase &= ~0xf;
+
+	debug("rtl8139: REALTEK RTL8139 @0x%x\n", iobase);
+
+	priv->devno = dev;
+	priv->ioaddr = (unsigned long)bus_to_phys(dev, iobase);
+
+	rtl8139_get_hwaddr(priv);
+	memcpy(plat->enetaddr, priv->enetaddr, sizeof(priv->enetaddr));
+
+	dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x20);
+
+	return 0;
+}
+
+static const struct eth_ops rtl8139_ops = {
+	.start		= rtl8139_start,
+	.send		= rtl8139_send,
+	.recv		= rtl8139_recv,
+	.stop		= rtl8139_stop,
+	.free_pkt	= rtl8139_free_pkt,
+	.write_hwaddr	= rtl8139_write_hwaddr,
+	.read_rom_hwaddr = rtl8139_read_rom_hwaddr,
+};
+
+U_BOOT_DRIVER(eth_rtl8139) = {
+	.name	= "eth_rtl8139",
+	.id	= UCLASS_ETH,
+	.bind	= rtl8139_bind,
+	.probe	= rtl8139_probe,
+	.ops	= &rtl8139_ops,
+	.priv_auto_alloc_size = sizeof(struct rtl8139_priv),
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+};
+
+U_BOOT_PCI_DEVICE(eth_rtl8139, supported);
+#endif
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index 75058fd..fb4fae2 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -240,6 +240,9 @@
 
 	/*_TBICSRBit*/
 	TBILinkOK = 0x02000000,
+
+	/* FuncEvent/Misc */
+	RxDv_Gated_En = 0x80000,
 };
 
 static struct {
@@ -1210,6 +1213,19 @@
 		return ret;
 	}
 
+	/*
+	 * WAR for DHCP failure after rebooting from kernel.
+	 * Clear RxDv_Gated_En bit which was set by kernel driver.
+	 * Without this, U-Boot can't get an IP via DHCP.
+	 * Register (FuncEvent, aka MISC) and RXDV_GATED_EN bit are from
+	 * the r8169.c kernel driver.
+	 */
+
+	u32 val = RTL_R32(FuncEvent);
+	debug("%s: FuncEvent/Misc (0xF0) = 0x%08X\n", __func__, val);
+	val &= ~RxDv_Gated_En;
+	RTL_W32(FuncEvent, val);
+
 	return 0;
 }
 
diff --git a/examples/standalone/Makefile b/examples/standalone/Makefile
index 4a34813..d4be0c7 100644
--- a/examples/standalone/Makefile
+++ b/examples/standalone/Makefile
@@ -8,10 +8,6 @@
 extra-$(CONFIG_SPI_FLASH_ATMEL)    += atmel_df_pow2
 extra-$(CONFIG_PPC)                += sched
 
-ifndef CONFIG_DM_ETH
-extra-$(CONFIG_SMC911X)            += smc911x_eeprom
-endif
-
 #
 # Some versions of make do not handle trailing white spaces properly;
 # leading to build failures. The problem was found with GNU Make 3.80.
diff --git a/examples/standalone/smc911x_eeprom.c b/examples/standalone/smc911x_eeprom.c
deleted file mode 100644
index 9bd9a6e..0000000
--- a/examples/standalone/smc911x_eeprom.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * smc911x_eeprom.c - EEPROM interface to SMC911x parts.
- * Only tested on SMSC9118 though ...
- *
- * Copyright 2004-2009 Analog Devices Inc.
- *
- * Licensed under the GPL-2 or later.
- *
- * Based on smc91111_eeprom.c which:
- * Heavily borrowed from the following peoples GPL'ed software:
- *  - Wolfgang Denk, DENX Software Engineering, wd@denx.de
- *       Das U-Boot
- *  - Ladislav Michl ladis@linux-mips.org
- *       A rejected patch on the U-Boot mailing list
- */
-
-#include <common.h>
-#include <console.h>
-#include <exports.h>
-#include <net.h>
-#include <linux/ctype.h>
-#include <linux/types.h>
-#include "../drivers/net/smc911x.h"
-
-#define DRIVERNAME "smc911x"
-
-#if defined (CONFIG_SMC911X_32_BIT) && \
-	defined (CONFIG_SMC911X_16_BIT)
-#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
-	CONFIG_SMC911X_16_BIT shall be set"
-#endif
-
-struct chip_id {
-	u16 id;
-	char *name;
-};
-
-static const struct chip_id chip_ids[] =  {
-	{ CHIP_89218, "LAN89218" },
-	{ CHIP_9115, "LAN9115" },
-	{ CHIP_9116, "LAN9116" },
-	{ CHIP_9117, "LAN9117" },
-	{ CHIP_9118, "LAN9118" },
-	{ CHIP_9211, "LAN9211" },
-	{ CHIP_9215, "LAN9215" },
-	{ CHIP_9216, "LAN9216" },
-	{ CHIP_9217, "LAN9217" },
-	{ CHIP_9218, "LAN9218" },
-	{ CHIP_9220, "LAN9220" },
-	{ CHIP_9221, "LAN9221" },
-	{ 0, NULL },
-};
-
-#if defined (CONFIG_SMC911X_32_BIT)
-static u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
-{
-	return *(volatile u32*)(dev->iobase + offset);
-}
-
-static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
-{
-	*(volatile u32*)(dev->iobase + offset) = val;
-}
-#elif defined (CONFIG_SMC911X_16_BIT)
-static u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
-{
-	volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
-	return (*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16);
-}
-static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
-{
-	*(volatile u16 *)(dev->iobase + offset) = (u16)val;
-	*(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
-}
-#else
-#error "SMC911X: undefined bus width"
-#endif /* CONFIG_SMC911X_16_BIT */
-
-static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
-{
-	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-	smc911x_reg_write(dev, MAC_CSR_CMD,
-			MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
-	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-
-	return smc911x_reg_read(dev, MAC_CSR_DATA);
-}
-
-static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
-{
-	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-	smc911x_reg_write(dev, MAC_CSR_DATA, data);
-	smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
-	while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
-		;
-}
-
-static int smc911x_detect_chip(struct eth_device *dev)
-{
-	unsigned long val, i;
-
-	val = smc911x_reg_read(dev, BYTE_TEST);
-	if (val == 0xffffffff) {
-		/* Special case -- no chip present */
-		return -1;
-	} else if (val != 0x87654321) {
-		printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
-		return -1;
-	}
-
-	val = smc911x_reg_read(dev, ID_REV) >> 16;
-	for (i = 0; chip_ids[i].id != 0; i++) {
-		if (chip_ids[i].id == val) break;
-	}
-	if (!chip_ids[i].id) {
-		printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
-		return -1;
-	}
-
-	dev->priv = (void *)&chip_ids[i];
-
-	return 0;
-}
-
-static void smc911x_reset(struct eth_device *dev)
-{
-	int timeout;
-
-	/*
-	 *  Take out of PM setting first
-	 *  Device is already wake up if PMT_CTRL_READY bit is set
-	 */
-	if ((smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) == 0) {
-		/* Write to the bytetest will take out of powerdown */
-		smc911x_reg_write(dev, BYTE_TEST, 0x0);
-
-		timeout = 10;
-
-		while (timeout-- &&
-			!(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
-			udelay(10);
-		if (timeout < 0) {
-			printf(DRIVERNAME
-				": timeout waiting for PM restore\n");
-			return;
-		}
-	}
-
-	/* Disable interrupts */
-	smc911x_reg_write(dev, INT_EN, 0);
-
-	smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
-
-	timeout = 1000;
-	while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
-		udelay(10);
-
-	if (timeout < 0) {
-		printf(DRIVERNAME ": reset timeout\n");
-		return;
-	}
-
-	/* Reset the FIFO level and flow control settings */
-	smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
-	smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
-
-	/* Set to LED outputs */
-	smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
-}
-
-/**
- *	smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?)
- */
-static int smsc_ctrlc(void)
-{
-	return (tstc() && getc() == 0x03);
-}
-
-/**
- *	usage - dump usage information
- */
-static void usage(void)
-{
-	puts(
-		"MAC/EEPROM Commands:\n"
-		" P : Print the MAC addresses\n"
-		" D : Dump the EEPROM contents\n"
-		" M : Dump the MAC contents\n"
-		" C : Copy the MAC address from the EEPROM to the MAC\n"
-		" W : Write a register in the EEPROM or in the MAC\n"
-		" Q : Quit\n"
-		"\n"
-		"Some commands take arguments:\n"
-		" W <E|M> <register> <value>\n"
-		"    E: EEPROM   M: MAC\n"
-	);
-}
-
-/**
- *	dump_regs - dump the MAC registers
- *
- * Registers 0x00 - 0x50 are FIFOs.  The 0x50+ are the control registers
- * and they're all 32bits long.  0xB8+ are reserved, so don't bother.
- */
-static void dump_regs(struct eth_device *dev)
-{
-	u8 i, j = 0;
-	for (i = 0x50; i < 0xB8; i += sizeof(u32))
-		printf("%02x: 0x%08x %c", i,
-			smc911x_reg_read(dev, i),
-			(j++ % 2 ? '\n' : ' '));
-}
-
-/**
- *	do_eeprom_cmd - handle eeprom communication
- */
-static int do_eeprom_cmd(struct eth_device *dev, int cmd, u8 reg)
-{
-	if (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY) {
-		printf("eeprom_cmd: busy at start (E2P_CMD = 0x%08x)\n",
-			smc911x_reg_read(dev, E2P_CMD));
-		return -1;
-	}
-
-	smc911x_reg_write(dev, E2P_CMD, E2P_CMD_EPC_BUSY | cmd | reg);
-
-	while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
-		if (smsc_ctrlc()) {
-			printf("eeprom_cmd: timeout (E2P_CMD = 0x%08x)\n",
-				smc911x_reg_read(dev, E2P_CMD));
-			return -1;
-		}
-
-	return 0;
-}
-
-/**
- *	read_eeprom_reg - read specified register in EEPROM
- */
-static u8 read_eeprom_reg(struct eth_device *dev, u8 reg)
-{
-	int ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_READ, reg);
-	return (ret ? : smc911x_reg_read(dev, E2P_DATA));
-}
-
-/**
- *	write_eeprom_reg - write specified value into specified register in EEPROM
- */
-static int write_eeprom_reg(struct eth_device *dev, u8 value, u8 reg)
-{
-	int ret;
-
-	/* enable erasing/writing */
-	ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWEN, reg);
-	if (ret)
-		goto done;
-
-	/* erase the eeprom reg */
-	ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_ERASE, reg);
-	if (ret)
-		goto done;
-
-	/* write the eeprom reg */
-	smc911x_reg_write(dev, E2P_DATA, value);
-	ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_WRITE, reg);
-	if (ret)
-		goto done;
-
-	/* disable erasing/writing */
-	ret = do_eeprom_cmd(dev, E2P_CMD_EPC_CMD_EWDS, reg);
-
- done:
-	return ret;
-}
-
-/**
- *	skip_space - find first non-whitespace in given pointer
- */
-static char *skip_space(char *buf)
-{
-	while (isblank(buf[0]))
-		++buf;
-	return buf;
-}
-
-/**
- *	write_stuff - handle writing of MAC registers / eeprom
- */
-static void write_stuff(struct eth_device *dev, char *line)
-{
-	char dest;
-	char *endp;
-	u8 reg;
-	u32 value;
-
-	/* Skip over the "W " part of the command */
-	line = skip_space(line + 1);
-
-	/* Figure out destination */
-	switch (line[0]) {
-	case 'E':
-	case 'M':
-		dest = line[0];
-		break;
-	default:
-	invalid_usage:
-		printf("ERROR: Invalid write usage\n");
-		usage();
-		return;
-	}
-
-	/* Get the register to write */
-	line = skip_space(line + 1);
-	reg = simple_strtoul(line, &endp, 16);
-	if (line == endp)
-		goto invalid_usage;
-
-	/* Get the value to write */
-	line = skip_space(endp);
-	value = simple_strtoul(line, &endp, 16);
-	if (line == endp)
-		goto invalid_usage;
-
-	/* Check for trailing cruft */
-	line = skip_space(endp);
-	if (line[0])
-		goto invalid_usage;
-
-	/* Finally, execute the command */
-	if (dest == 'E') {
-		printf("Writing EEPROM register %02x with %02x\n", reg, value);
-		write_eeprom_reg(dev, value, reg);
-	} else {
-		printf("Writing MAC register %02x with %08x\n", reg, value);
-		smc911x_reg_write(dev, reg, value);
-	}
-}
-
-/**
- *	copy_from_eeprom - copy MAC address in eeprom to address registers
- */
-static void copy_from_eeprom(struct eth_device *dev)
-{
-	ulong addrl =
-		read_eeprom_reg(dev, 0x01) |
-		read_eeprom_reg(dev, 0x02) << 8 |
-		read_eeprom_reg(dev, 0x03) << 16 |
-		read_eeprom_reg(dev, 0x04) << 24;
-	ulong addrh =
-		read_eeprom_reg(dev, 0x05) |
-		read_eeprom_reg(dev, 0x06) << 8;
-	smc911x_set_mac_csr(dev, ADDRL, addrl);
-	smc911x_set_mac_csr(dev, ADDRH, addrh);
-	puts("EEPROM contents copied to MAC\n");
-}
-
-/**
- *	print_macaddr - print MAC address registers and MAC address in eeprom
- */
-static void print_macaddr(struct eth_device *dev)
-{
-	puts("Current MAC Address in MAC:     ");
-	ulong addrl = smc911x_get_mac_csr(dev, ADDRL);
-	ulong addrh = smc911x_get_mac_csr(dev, ADDRH);
-	printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
-		(u8)(addrl), (u8)(addrl >> 8), (u8)(addrl >> 16),
-		(u8)(addrl >> 24), (u8)(addrh), (u8)(addrh >> 8));
-
-	puts("Current MAC Address in EEPROM:  ");
-	int i;
-	for (i = 1; i < 6; ++i)
-		printf("%02x:", read_eeprom_reg(dev, i));
-	printf("%02x\n", read_eeprom_reg(dev, i));
-}
-
-/**
- *	dump_eeprom - dump the whole content of the EEPROM
- */
-static void dump_eeprom(struct eth_device *dev)
-{
-	int i;
-	puts("EEPROM:\n");
-	for (i = 0; i < 7; ++i)
-		printf("%02x: 0x%02x\n", i, read_eeprom_reg(dev, i));
-}
-
-/**
- *	smc911x_init - get the MAC/EEPROM up and ready for use
- */
-static int smc911x_init(struct eth_device *dev)
-{
-	/* See if there is anything there */
-	if (smc911x_detect_chip(dev))
-		return 1;
-
-	smc911x_reset(dev);
-
-	/* Make sure we set EEDIO/EECLK to the EEPROM */
-	if (smc911x_reg_read(dev, GPIO_CFG) & GPIO_CFG_EEPR_EN) {
-		while (smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
-			if (smsc_ctrlc()) {
-				printf("init: timeout (E2P_CMD = 0x%08x)\n",
-					smc911x_reg_read(dev, E2P_CMD));
-				return 1;
-			}
-		smc911x_reg_write(dev, GPIO_CFG,
-			smc911x_reg_read(dev, GPIO_CFG) & ~GPIO_CFG_EEPR_EN);
-	}
-
-	return 0;
-}
-
-/**
- *	getline - consume a line of input and handle some escape sequences
- */
-static char *getline(void)
-{
-	static char buffer[100];
-	char c;
-	size_t i;
-
-	i = 0;
-	while (1) {
-		buffer[i] = '\0';
-		while (!tstc())
-			continue;
-
-		c = getc();
-		/* Convert to uppercase */
-		if (c >= 'a' && c <= 'z')
-			c -= ('a' - 'A');
-
-		switch (c) {
-		case '\r':	/* Enter/Return key */
-		case '\n':
-			puts("\n");
-			return buffer;
-
-		case 0x03:	/* ^C - break */
-			return NULL;
-
-		case 0x5F:
-		case 0x08:	/* ^H  - backspace */
-		case 0x7F:	/* DEL - backspace */
-			if (i) {
-				puts("\b \b");
-				i--;
-			}
-			break;
-
-		default:
-			/* Ignore control characters */
-			if (c < 0x20)
-				break;
-			/* Queue up all other characters */
-			buffer[i++] = c;
-			printf("%c", c);
-			break;
-		}
-	}
-}
-
-/**
- *	smc911x_eeprom - our application's main() function
- */
-int smc911x_eeprom(int argc, char *const argv[])
-{
-	/* Avoid initializing on stack as gcc likes to call memset() */
-	struct eth_device dev;
-	dev.iobase = CONFIG_SMC911X_BASE;
-
-	/* Print the ABI version */
-	app_startup(argv);
-	if (XF_VERSION != get_version()) {
-		printf("Expects ABI version %d\n", XF_VERSION);
-		printf("Actual U-Boot ABI version %lu\n", get_version());
-		printf("Can't run\n\n");
-		return 1;
-	}
-
-	/* Initialize the MAC/EEPROM somewhat */
-	puts("\n");
-	if (smc911x_init(&dev))
-		return 1;
-
-	/* Dump helpful usage information */
-	puts("\n");
-	usage();
-	puts("\n");
-
-	while (1) {
-		char *line;
-
-		/* Send the prompt and wait for a line */
-		puts("eeprom> ");
-		line = getline();
-
-		/* Got a ctrl+c */
-		if (!line)
-			return 0;
-
-		/* Eat leading space */
-		line = skip_space(line);
-
-		/* Empty line, try again */
-		if (!line[0])
-			continue;
-
-		/* Only accept 1 letter commands */
-		if (line[0] && line[1] && !isblank(line[1]))
-			goto unknown_cmd;
-
-		/* Now parse the command */
-		switch (line[0]) {
-		case 'W': write_stuff(&dev, line); break;
-		case 'D': dump_eeprom(&dev);       break;
-		case 'M': dump_regs(&dev);         break;
-		case 'C': copy_from_eeprom(&dev);  break;
-		case 'P': print_macaddr(&dev);     break;
-		unknown_cmd:
-		default:  puts("ERROR: Unknown command!\n\n");
-		case '?':
-		case 'H': usage();            break;
-		case 'Q': return 0;
-		}
-	}
-}
diff --git a/include/configs/tbs2910.h b/include/configs/tbs2910.h
index 7376b91..17de122 100644
--- a/include/configs/tbs2910.h
+++ b/include/configs/tbs2910.h
@@ -76,6 +76,7 @@
 #define CONFIG_BOARD_SIZE_LIMIT		392192 /* (CONFIG_ENV_OFFSET - 1024) */
 
 #define CONFIG_EXTRA_ENV_SETTINGS \
+	BOOTENV \
 	"bootargs_mmc1=console=ttymxc0,115200 di0_primary console=tty1\0" \
 	"bootargs_mmc2=video=mxcfb0:dev=hdmi,1920x1080M@60 " \
 			"video=mxcfb1:off video=mxcfb2:off fbmem=28M\0" \
@@ -92,6 +93,13 @@
 			"bootm 0x10800000 0x10d00000\0" \
 	"console=ttymxc0\0" \
 	"fan=gpio set 92\0" \
+	"fdt_addr=0x13000000\0" \
+	"fdt_addr_r=0x13000000\0" \
+	"fdtfile=" CONFIG_DEFAULT_FDT_FILE "\0" \
+	"kernel_addr_r=0x10008000\0" \
+	"pxefile_addr_r=0x10008000\0" \
+	"ramdisk_addr_r=0x18000000\0" \
+	"scriptaddr=0x14000000\0" \
 	"set_con_serial=setenv stdout serial; " \
 			"setenv stderr serial\0" \
 	"set_con_hdmi=setenv stdout serial,vga; " \
@@ -100,12 +108,14 @@
 	"stdin=serial,usbkbd\0" \
 	"stdout=serial,vga\0"
 
-#define CONFIG_BOOTCOMMAND \
-	"mmc rescan; " \
-	"if run bootcmd_up1; then " \
-		"run bootcmd_up2; " \
-	"else " \
-		"run bootcmd_mmc; " \
-	"fi"
+/* Enable distro boot */
+#define BOOT_TARGET_DEVICES(func) \
+	func(MMC, mmc, 0) \
+	func(MMC, mmc, 1) \
+	func(MMC, mmc, 2) \
+	func(SATA, sata, 0) \
+	func(USB, usb, 0)
+
+#include <config_distro_bootcmd.h>
 
 #endif			       /* __TBS2910_CONFIG_H * */
diff --git a/include/hash.h b/include/hash.h
index 835962e..97bb3ed 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -12,7 +12,11 @@
  * Maximum digest size for all algorithms we support. Having this value
  * avoids a malloc() or C99 local declaration in common/cmd_hash.c.
  */
+#if defined(CONFIG_SHA384) || defined(CONFIG_SHA512)
+#define HASH_MAX_DIGEST_SIZE	64
+#else
 #define HASH_MAX_DIGEST_SIZE	32
+#endif
 
 enum {
 	HASH_FLAG_VERIFY	= 1 << 0,	/* Enable verify mode */
diff --git a/include/image.h b/include/image.h
index ad81dad..ebd581a 100644
--- a/include/image.h
+++ b/include/image.h
@@ -32,8 +32,12 @@
 #define CONFIG_FIT_VERBOSE	1 /* enable fit_format_{error,warning}() */
 #define CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT 1
 #define CONFIG_FIT_ENABLE_SHA256_SUPPORT
+#define CONFIG_FIT_ENABLE_SHA384_SUPPORT
+#define CONFIG_FIT_ENABLE_SHA512_SUPPORT
 #define CONFIG_SHA1
 #define CONFIG_SHA256
+#define CONFIG_SHA384
+#define CONFIG_SHA512
 
 #define IMAGE_ENABLE_IGNORE	0
 #define IMAGE_INDENT_STRING	""
@@ -92,6 +96,20 @@
 #define IMAGE_ENABLE_SHA256	0
 #endif
 
+#if defined(CONFIG_FIT_ENABLE_SHA384_SUPPORT) || \
+	defined(CONFIG_SPL_SHA384_SUPPORT)
+#define IMAGE_ENABLE_SHA384	1
+#else
+#define IMAGE_ENABLE_SHA384	0
+#endif
+
+#if defined(CONFIG_FIT_ENABLE_SHA512_SUPPORT) || \
+	defined(CONFIG_SPL_SHA512_SUPPORT)
+#define IMAGE_ENABLE_SHA512	1
+#else
+#define IMAGE_ENABLE_SHA512	0
+#endif
+
 #endif /* IMAGE_ENABLE_FIT */
 
 #ifdef CONFIG_SYS_BOOT_GET_CMDLINE
diff --git a/include/net.h b/include/net.h
index 00a8ec0..1bf9867 100644
--- a/include/net.h
+++ b/include/net.h
@@ -897,9 +897,6 @@
  */
 int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len);
 
-/* get a random source port */
-unsigned int random_port(void);
-
 /**
  * update_tftp - Update firmware over TFTP (via DFU)
  *
diff --git a/include/phy.h b/include/phy.h
index b5de14c..fedd146 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -170,6 +170,13 @@
 	int asym_pause;
 };
 
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: register number to read
+ * @return: value for success or negative errno for failure
+ */
 static inline int phy_read(struct phy_device *phydev, int devad, int regnum)
 {
 	struct mii_dev *bus = phydev->bus;
@@ -182,6 +189,14 @@
 	return bus->read(bus, phydev->addr, devad, regnum);
 }
 
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ * @return: 0 for success or negative errno for failure
+ */
 static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
 			u16 val)
 {
@@ -195,6 +210,13 @@
 	return bus->write(bus, phydev->addr, devad, regnum, val);
 }
 
+/**
+ * phy_mmd_start_indirect - Convenience function for writing MMD registers
+ * @phydev: the phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: register number to write
+ * @return: None
+ */
 static inline void phy_mmd_start_indirect(struct phy_device *phydev, int devad,
 					  int regnum)
 {
@@ -209,6 +231,14 @@
 		  (devad | MII_MMD_CTRL_NOINCR));
 }
 
+/**
+ * phy_read_mmd - Convenience function for reading a register
+ * from an MMD on a given PHY.
+ * @phydev: The phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ * @return: Value for success or negative errno for failure
+ */
 static inline int phy_read_mmd(struct phy_device *phydev, int devad,
 			       int regnum)
 {
@@ -233,6 +263,15 @@
 	return phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);
 }
 
+/**
+ * phy_write_mmd - Convenience function for writing a register
+ * on an MMD on a given PHY.
+ * @phydev: The phy_device struct
+ * @devad: The MMD to read from
+ * @regnum: The register on the MMD to read
+ * @val: value to write to @regnum
+ * @return: 0 for success or negative errno for failure
+ */
 static inline int phy_write_mmd(struct phy_device *phydev, int devad,
 				int regnum, u16 val)
 {
@@ -257,6 +296,60 @@
 	return phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);
 }
 
+/**
+ * phy_set_bits_mmd - Convenience function for setting bits in a register
+ * on MMD
+ * @phydev: the phy_device struct
+ * @devad: the MMD containing register to modify
+ * @regnum: register number to modify
+ * @val: bits to set
+ * @return: 0 for success or negative errno for failure
+ */
+static inline int phy_set_bits_mmd(struct phy_device *phydev, int devad,
+				   u32 regnum, u16 val)
+{
+	int value, ret;
+
+	value = phy_read_mmd(phydev, devad, regnum);
+	if (value < 0)
+		return value;
+
+	value |= val;
+
+	ret = phy_write_mmd(phydev, devad, regnum, value);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/**
+ * phy_clear_bits_mmd - Convenience function for clearing bits in a register
+ * on MMD
+ * @phydev: the phy_device struct
+ * @devad: the MMD containing register to modify
+ * @regnum: register number to modify
+ * @val: bits to clear
+ * @return: 0 for success or negative errno for failure
+ */
+static inline int phy_clear_bits_mmd(struct phy_device *phydev, int devad,
+				     u32 regnum, u16 val)
+{
+	int value, ret;
+
+	value = phy_read_mmd(phydev, devad, regnum);
+	if (value < 0)
+		return value;
+
+	value &= ~val;
+
+	ret = phy_write_mmd(phydev, devad, regnum, value);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 #ifdef CONFIG_PHYLIB_10G
 extern struct phy_driver gen10g_driver;
 
@@ -275,26 +368,23 @@
 
 /**
  * phy_init() - Initializes the PHY drivers
- *
  * This function registers all available PHY drivers
  *
- * @return 0 if OK, -ve on error
+ * @return: 0 if OK, -ve on error
  */
 int phy_init(void);
 
 /**
  * phy_reset() - Resets the specified PHY
- *
  * Issues a reset of the PHY and waits for it to complete
  *
  * @phydev:	PHY to reset
- * @return 0 if OK, -ve on error
+ * @return: 0 if OK, -ve on error
  */
 int phy_reset(struct phy_device *phydev);
 
 /**
  * phy_find_by_mask() - Searches for a PHY on the specified MDIO bus
- *
  * The function checks the PHY addresses flagged in phy_mask and returns a
  * phy_device pointer if it detects a PHY.
  * This function should only be called if just one PHY is expected to be present
@@ -304,7 +394,7 @@
  * @bus:	MII/MDIO bus to scan
  * @phy_mask:	bitmap of PYH addresses to scan
  * @interface:	type of MAC-PHY interface
- * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ * @return: pointer to phy_device if a PHY is found, or NULL otherwise
  */
 struct phy_device *phy_find_by_mask(struct mii_dev *bus, unsigned phy_mask,
 		phy_interface_t interface);
@@ -320,7 +410,6 @@
 
 /**
  * phy_connect() - Creates a PHY device for the Ethernet interface
- *
  * Creates a PHY device for the PHY at the given address, if one doesn't exist
  * already, and associates it with the Ethernet device.
  * The function may be called with addr <= 0, in this case addr value is ignored
@@ -332,7 +421,7 @@
  * @addr:	PHY address on MDIO bus
  * @dev:	Ethernet device to associate to the PHY
  * @interface:	type of MAC-PHY interface
- * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ * @return: pointer to phy_device if a PHY is found, or NULL otherwise
  */
 struct phy_device *phy_connect(struct mii_dev *bus, int addr,
 				struct udevice *dev,
@@ -356,7 +445,6 @@
 
 /**
  * phy_connect() - Creates a PHY device for the Ethernet interface
- *
  * Creates a PHY device for the PHY at the given address, if one doesn't exist
  * already, and associates it with the Ethernet device.
  * The function may be called with addr <= 0, in this case addr value is ignored
@@ -368,7 +456,7 @@
  * @addr:	PHY address on MDIO bus
  * @dev:	Ethernet device to associate to the PHY
  * @interface:	type of MAC-PHY interface
- * @return pointer to phy_device if a PHY is found, or NULL otherwise
+ * @return: pointer to phy_device if a PHY is found, or NULL otherwise
  */
 struct phy_device *phy_connect(struct mii_dev *bus, int addr,
 				struct eth_device *dev,
@@ -428,7 +516,7 @@
  * phy_get_interface_by_name() - Look up a PHY interface name
  *
  * @str:	PHY interface name, e.g. "mii"
- * @return PHY_INTERFACE_MODE_... value, or -1 if not found
+ * @return: PHY_INTERFACE_MODE_... value, or -1 if not found
  */
 int phy_get_interface_by_name(const char *str);
 
@@ -436,6 +524,7 @@
  * phy_interface_is_rgmii - Convenience function for testing if a PHY interface
  * is RGMII (all variants)
  * @phydev: the phy_device struct
+ * @return: true if MII bus is RGMII or false if it is not
  */
 static inline bool phy_interface_is_rgmii(struct phy_device *phydev)
 {
@@ -447,6 +536,7 @@
  * phy_interface_is_sgmii - Convenience function for testing if a PHY interface
  * is SGMII (all variants)
  * @phydev: the phy_device struct
+ * @return: true if MII bus is SGMII or false if it is not
  */
 static inline bool phy_interface_is_sgmii(struct phy_device *phydev)
 {
diff --git a/include/u-boot/rsa-checksum.h b/include/u-boot/rsa-checksum.h
index 02b814d..54e6a73 100644
--- a/include/u-boot/rsa-checksum.h
+++ b/include/u-boot/rsa-checksum.h
@@ -10,6 +10,7 @@
 #include <image.h>
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#include <u-boot/sha512.h>
 
 /**
  * hash_calculate() - Calculate hash over the data
diff --git a/include/u-boot/sha512.h b/include/u-boot/sha512.h
new file mode 100644
index 0000000..516729d
--- /dev/null
+++ b/include/u-boot/sha512.h
@@ -0,0 +1,38 @@
+#ifndef _SHA512_H
+#define _SHA512_H
+
+#define SHA384_SUM_LEN          48
+#define SHA384_DER_LEN          19
+#define SHA512_SUM_LEN          64
+#define SHA512_DER_LEN          19
+#define SHA512_BLOCK_SIZE       128
+
+#define CHUNKSZ_SHA384	(16 * 1024)
+#define CHUNKSZ_SHA512	(16 * 1024)
+
+typedef struct {
+	uint64_t state[SHA512_SUM_LEN / 8];
+	uint64_t count[2];
+	uint8_t buf[SHA512_BLOCK_SIZE];
+} sha512_context;
+
+extern const uint8_t sha512_der_prefix[];
+
+void sha512_starts(sha512_context * ctx);
+void sha512_update(sha512_context *ctx, const uint8_t *input, uint32_t length);
+void sha512_finish(sha512_context * ctx, uint8_t digest[SHA512_SUM_LEN]);
+
+void sha512_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz);
+
+extern const uint8_t sha384_der_prefix[];
+
+void sha384_starts(sha512_context * ctx);
+void sha384_update(sha512_context *ctx, const uint8_t *input, uint32_t length);
+void sha384_finish(sha512_context * ctx, uint8_t digest[SHA384_SUM_LEN]);
+
+void sha384_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz);
+
+
+#endif /* _SHA512_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index af5c38a..fc7d684 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -345,6 +345,29 @@
 	  The SHA256 algorithm produces a 256-bit (32-byte) hash value
 	  (digest).
 
+config SHA512_ALGO
+	bool "Enable SHA512 algorithm"
+	help
+	  This option enables support of internal SHA512 algorithm.
+
+config SHA512
+	bool "Enable SHA512 support"
+	depends on SHA512_ALGO
+	help
+	  This option enables support of hashing using SHA512 algorithm.
+	  The hash is calculated in software.
+	  The SHA512 algorithm produces a 512-bit (64-byte) hash value
+	  (digest).
+
+config SHA384
+	bool "Enable SHA384 support"
+	depends on SHA512_ALGO
+	help
+	  This option enables support of hashing using SHA384 algorithm.
+	  The hash is calculated in software.
+	  The SHA384 algorithm produces a 384-bit (48-byte) hash value
+	  (digest).
+
 config SHA_HW_ACCEL
 	bool "Enable hashing using hardware"
 	help
diff --git a/lib/Makefile b/lib/Makefile
index dc57619..1dc06c5 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -61,6 +61,7 @@
 obj-$(CONFIG_$(SPL_)RSA) += rsa/
 obj-$(CONFIG_SHA1) += sha1.o
 obj-$(CONFIG_SHA256) += sha256.o
+obj-$(CONFIG_SHA512_ALGO) += sha512.o
 
 obj-$(CONFIG_$(SPL_)ZLIB) += zlib/
 obj-$(CONFIG_$(SPL_)ZSTD) += zstd/
diff --git a/lib/sha512.c b/lib/sha512.c
new file mode 100644
index 0000000..f1e2acf
--- /dev/null
+++ b/lib/sha512.c
@@ -0,0 +1,383 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * FIPS-180-2 compliant SHA-512 and SHA-384 implementation
+ *
+ * SHA-512 code by Jean-Luc Cooke <jlcooke@certainkey.com>
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2003 Kyle McMartin <kyle@debian.org>
+ * Copyright (c) 2020 Reuben Dowle <reuben.dowle@4rf.com>
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif /* USE_HOSTCC */
+#include <watchdog.h>
+#include <u-boot/sha512.h>
+
+const uint8_t sha384_der_prefix[SHA384_DER_LEN] = {
+	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+	0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
+	0x00, 0x04, 0x30
+};
+
+const uint8_t sha512_der_prefix[SHA512_DER_LEN] = {
+	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+	0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+	0x00, 0x04, 0x40
+};
+
+#define SHA384_H0	0xcbbb9d5dc1059ed8ULL
+#define SHA384_H1	0x629a292a367cd507ULL
+#define SHA384_H2	0x9159015a3070dd17ULL
+#define SHA384_H3	0x152fecd8f70e5939ULL
+#define SHA384_H4	0x67332667ffc00b31ULL
+#define SHA384_H5	0x8eb44a8768581511ULL
+#define SHA384_H6	0xdb0c2e0d64f98fa7ULL
+#define SHA384_H7	0x47b5481dbefa4fa4ULL
+
+#define SHA512_H0	0x6a09e667f3bcc908ULL
+#define SHA512_H1	0xbb67ae8584caa73bULL
+#define SHA512_H2	0x3c6ef372fe94f82bULL
+#define SHA512_H3	0xa54ff53a5f1d36f1ULL
+#define SHA512_H4	0x510e527fade682d1ULL
+#define SHA512_H5	0x9b05688c2b3e6c1fULL
+#define SHA512_H6	0x1f83d9abfb41bd6bULL
+#define SHA512_H7	0x5be0cd19137e2179ULL
+
+static inline uint64_t Ch(uint64_t x, uint64_t y, uint64_t z)
+{
+        return z ^ (x & (y ^ z));
+}
+
+static inline uint64_t Maj(uint64_t x, uint64_t y, uint64_t z)
+{
+        return (x & y) | (z & (x | y));
+}
+
+static const uint64_t sha512_K[80] = {
+        0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
+        0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
+        0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
+        0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
+        0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
+        0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
+        0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
+        0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
+        0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
+        0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
+        0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
+        0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
+        0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
+        0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
+        0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
+        0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
+        0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
+        0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
+        0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
+        0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
+        0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
+        0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
+        0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
+        0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
+        0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
+        0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
+        0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL,
+};
+
+static inline uint64_t ror64(uint64_t word, unsigned int shift)
+{
+	return (word >> (shift & 63)) | (word << ((-shift) & 63));
+}
+
+#define e0(x)       (ror64(x,28) ^ ror64(x,34) ^ ror64(x,39))
+#define e1(x)       (ror64(x,14) ^ ror64(x,18) ^ ror64(x,41))
+#define s0(x)       (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7))
+#define s1(x)       (ror64(x,19) ^ ror64(x,61) ^ (x >> 6))
+
+/*
+ * 64-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT64_BE
+#define GET_UINT64_BE(n,b,i) {				\
+	(n) = ( (unsigned long long) (b)[(i)    ] << 56 )	\
+	    | ( (unsigned long long) (b)[(i) + 1] << 48 )	\
+	    | ( (unsigned long long) (b)[(i) + 2] << 40 )	\
+	    | ( (unsigned long long) (b)[(i) + 3] << 32 )	\
+	    | ( (unsigned long long) (b)[(i) + 4] << 24 )	\
+	    | ( (unsigned long long) (b)[(i) + 5] << 16 )	\
+	    | ( (unsigned long long) (b)[(i) + 6] <<  8 )	\
+	    | ( (unsigned long long) (b)[(i) + 7]       );	\
+}
+#endif
+#ifndef PUT_UINT64_BE
+#define PUT_UINT64_BE(n,b,i) {				\
+	(b)[(i)    ] = (unsigned char) ( (n) >> 56 );	\
+	(b)[(i) + 1] = (unsigned char) ( (n) >> 48 );	\
+	(b)[(i) + 2] = (unsigned char) ( (n) >> 40 );	\
+	(b)[(i) + 3] = (unsigned char) ( (n) >> 32 );	\
+	(b)[(i) + 4] = (unsigned char) ( (n) >> 24 );	\
+	(b)[(i) + 5] = (unsigned char) ( (n) >> 16 );	\
+	(b)[(i) + 6] = (unsigned char) ( (n) >>  8 );	\
+	(b)[(i) + 7] = (unsigned char) ( (n)       );	\
+}
+#endif
+
+static inline void LOAD_OP(int I, uint64_t *W, const uint8_t *input)
+{
+	GET_UINT64_BE(W[I], input, I*8);
+}
+
+static inline void BLEND_OP(int I, uint64_t *W)
+{
+	W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]);
+}
+
+static void
+sha512_transform(uint64_t *state, const uint8_t *input)
+{
+	uint64_t a, b, c, d, e, f, g, h, t1, t2;
+
+	int i;
+	uint64_t W[16];
+
+	/* load the state into our registers */
+	a=state[0];   b=state[1];   c=state[2];   d=state[3];
+	e=state[4];   f=state[5];   g=state[6];   h=state[7];
+
+	/* now iterate */
+	for (i=0; i<80; i+=8) {
+		if (!(i & 8)) {
+			int j;
+
+			if (i < 16) {
+				/* load the input */
+				for (j = 0; j < 16; j++)
+					LOAD_OP(i + j, W, input);
+			} else {
+				for (j = 0; j < 16; j++) {
+					BLEND_OP(i + j, W);
+				}
+			}
+		}
+
+		t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i  ] + W[(i & 15)];
+		t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+		t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[(i & 15) + 1];
+		t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+		t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[(i & 15) + 2];
+		t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+		t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[(i & 15) + 3];
+		t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+		t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[(i & 15) + 4];
+		t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+		t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[(i & 15) + 5];
+		t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+		t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[(i & 15) + 6];
+		t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+		t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[(i & 15) + 7];
+		t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+	}
+
+	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+	/* erase our data */
+	a = b = c = d = e = f = g = h = t1 = t2 = 0;
+}
+
+static void sha512_block_fn(sha512_context *sst, const uint8_t *src,
+				    int blocks)
+{
+	while (blocks--) {
+		sha512_transform(sst->state, src);
+		src += SHA512_BLOCK_SIZE;
+	}
+}
+
+static void sha512_base_do_update(sha512_context *sctx,
+					const uint8_t *data,
+					unsigned int len)
+{
+	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
+
+	sctx->count[0] += len;
+	if (sctx->count[0] < len)
+		sctx->count[1]++;
+
+	if (unlikely((partial + len) >= SHA512_BLOCK_SIZE)) {
+		int blocks;
+
+		if (partial) {
+			int p = SHA512_BLOCK_SIZE - partial;
+
+			memcpy(sctx->buf + partial, data, p);
+			data += p;
+			len -= p;
+
+			sha512_block_fn(sctx, sctx->buf, 1);
+		}
+
+		blocks = len / SHA512_BLOCK_SIZE;
+		len %= SHA512_BLOCK_SIZE;
+
+		if (blocks) {
+			sha512_block_fn(sctx, data, blocks);
+			data += blocks * SHA512_BLOCK_SIZE;
+		}
+		partial = 0;
+	}
+	if (len)
+		memcpy(sctx->buf + partial, data, len);
+}
+
+static void sha512_base_do_finalize(sha512_context *sctx)
+{
+	const int bit_offset = SHA512_BLOCK_SIZE - sizeof(uint64_t[2]);
+	uint64_t *bits = (uint64_t *)(sctx->buf + bit_offset);
+	unsigned int partial = sctx->count[0] % SHA512_BLOCK_SIZE;
+
+	sctx->buf[partial++] = 0x80;
+	if (partial > bit_offset) {
+		memset(sctx->buf + partial, 0x0, SHA512_BLOCK_SIZE - partial);
+		partial = 0;
+
+		sha512_block_fn(sctx, sctx->buf, 1);
+	}
+
+	memset(sctx->buf + partial, 0x0, bit_offset - partial);
+	bits[0] = cpu_to_be64(sctx->count[1] << 3 | sctx->count[0] >> 61);
+	bits[1] = cpu_to_be64(sctx->count[0] << 3);
+	sha512_block_fn(sctx, sctx->buf, 1);
+}
+
+#if defined(CONFIG_SHA384)
+void sha384_starts(sha512_context * ctx)
+{
+	ctx->state[0] = SHA384_H0;
+	ctx->state[1] = SHA384_H1;
+	ctx->state[2] = SHA384_H2;
+	ctx->state[3] = SHA384_H3;
+	ctx->state[4] = SHA384_H4;
+	ctx->state[5] = SHA384_H5;
+	ctx->state[6] = SHA384_H6;
+	ctx->state[7] = SHA384_H7;
+	ctx->count[0] = ctx->count[1] = 0;
+}
+
+void sha384_update(sha512_context *ctx, const uint8_t *input, uint32_t length)
+{
+	sha512_base_do_update(ctx, input, length);
+}
+
+void sha384_finish(sha512_context * ctx, uint8_t digest[SHA384_SUM_LEN])
+{
+	int i;
+
+	sha512_base_do_finalize(ctx);
+	for(i=0; i<SHA384_SUM_LEN / sizeof(uint64_t); i++)
+		PUT_UINT64_BE(ctx->state[i], digest, i * 8);
+}
+
+/*
+ * Output = SHA-512( input buffer ). Trigger the watchdog every 'chunk_sz'
+ * bytes of input processed.
+ */
+void sha384_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz)
+{
+	sha512_context ctx;
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	const unsigned char *end;
+	unsigned char *curr;
+	int chunk;
+#endif
+
+	sha384_starts(&ctx);
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	curr = (unsigned char *)input;
+	end = input + ilen;
+	while (curr < end) {
+		chunk = end - curr;
+		if (chunk > chunk_sz)
+			chunk = chunk_sz;
+		sha384_update(&ctx, curr, chunk);
+		curr += chunk;
+		WATCHDOG_RESET();
+	}
+#else
+	sha384_update(&ctx, input, ilen);
+#endif
+
+	sha384_finish(&ctx, output);
+}
+
+#endif
+
+#if defined(CONFIG_SHA512)
+void sha512_starts(sha512_context * ctx)
+{
+	ctx->state[0] = SHA512_H0;
+	ctx->state[1] = SHA512_H1;
+	ctx->state[2] = SHA512_H2;
+	ctx->state[3] = SHA512_H3;
+	ctx->state[4] = SHA512_H4;
+	ctx->state[5] = SHA512_H5;
+	ctx->state[6] = SHA512_H6;
+	ctx->state[7] = SHA512_H7;
+	ctx->count[0] = ctx->count[1] = 0;
+}
+
+void sha512_update(sha512_context *ctx, const uint8_t *input, uint32_t length)
+{
+	sha512_base_do_update(ctx, input, length);
+}
+
+void sha512_finish(sha512_context * ctx, uint8_t digest[SHA512_SUM_LEN])
+{
+	int i;
+
+	sha512_base_do_finalize(ctx);
+	for(i=0; i<SHA512_SUM_LEN / sizeof(uint64_t); i++)
+		PUT_UINT64_BE(ctx->state[i], digest, i * 8);
+}
+
+/*
+ * Output = SHA-512( input buffer ). Trigger the watchdog every 'chunk_sz'
+ * bytes of input processed.
+ */
+void sha512_csum_wd(const unsigned char *input, unsigned int ilen,
+		unsigned char *output, unsigned int chunk_sz)
+{
+	sha512_context ctx;
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	const unsigned char *end;
+	unsigned char *curr;
+	int chunk;
+#endif
+
+	sha512_starts(&ctx);
+
+#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
+	curr = (unsigned char *)input;
+	end = input + ilen;
+	while (curr < end) {
+		chunk = end - curr;
+		if (chunk > chunk_sz)
+			chunk = chunk_sz;
+		sha512_update(&ctx, curr, chunk);
+		curr += chunk;
+		WATCHDOG_RESET();
+	}
+#else
+	sha512_update(&ctx, input, ilen);
+#endif
+
+	sha512_finish(&ctx, output);
+}
+#endif
diff --git a/net/dns.c b/net/dns.c
index e35c4dc..5b1fe5b 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -36,6 +36,16 @@
 
 static int dns_our_port;
 
+/*
+ * make port a little random (1024-17407)
+ * This keeps the math somewhat trivial to compute, and seems to work with
+ * all supported protocols/clients/servers
+ */
+static unsigned int random_port(void)
+{
+	return 1024 + (get_timer(0) % 0x4000);
+}
+
 static void dns_send(void)
 {
 	struct header *header;
diff --git a/net/net.c b/net/net.c
index 3793291..1e7f633 100644
--- a/net/net.c
+++ b/net/net.c
@@ -456,6 +456,7 @@
 		net_dev_exists = 1;
 		net_boot_file_size = 0;
 		switch (protocol) {
+#ifdef CONFIG_CMD_TFTPBOOT
 		case TFTPGET:
 #ifdef CONFIG_CMD_TFTPPUT
 		case TFTPPUT:
@@ -463,6 +464,7 @@
 			/* always use ARP to get server ethernet address */
 			tftp_start(protocol);
 			break;
+#endif
 #ifdef CONFIG_CMD_TFTPSRV
 		case TFTPSRV:
 			tftp_start_server();
@@ -480,13 +482,13 @@
 			dhcp_request();		/* Basically same as BOOTP */
 			break;
 #endif
-
+#if defined(CONFIG_CMD_BOOTP)
 		case BOOTP:
 			bootp_reset();
 			net_ip.s_addr = 0;
 			bootp_request();
 			break;
-
+#endif
 #if defined(CONFIG_CMD_RARP)
 		case RARP:
 			rarp_try = 0;
@@ -1562,20 +1564,6 @@
 	return 1;
 }
 
-#if	defined(CONFIG_CMD_NFS)		|| \
-	defined(CONFIG_CMD_SNTP)	|| \
-	defined(CONFIG_CMD_DNS)
-/*
- * make port a little random (1024-17407)
- * This keeps the math somewhat trivial to compute, and seems to work with
- * all supported protocols/clients/servers
- */
-unsigned int random_port(void)
-{
-	return 1024 + (get_timer(0) % 0x4000);
-}
-#endif
-
 void ip_to_string(struct in_addr x, char *s)
 {
 	x.s_addr = ntohl(x.s_addr);
diff --git a/net/tftp.c b/net/tftp.c
index 180140e..c05b7b5 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -70,6 +70,7 @@
 	TFTP_ERR_UNEXPECTED_OPCODE   = 4,
 	TFTP_ERR_UNKNOWN_TRANSFER_ID  = 5,
 	TFTP_ERR_FILE_ALREADY_EXISTS = 6,
+	TFTP_ERR_OPTION_NEGOTIATION = 8,
 };
 
 static struct in_addr tftp_remote_ip;
@@ -113,6 +114,7 @@
 #define STATE_OACK	5
 #define STATE_RECV_WRQ	6
 #define STATE_SEND_WRQ	7
+#define STATE_INVALID_OPTION	8
 
 /* default TFTP block size */
 #define TFTP_BLOCK_SIZE		512
@@ -233,9 +235,11 @@
 
 static void show_block_marker(void)
 {
+	ulong pos;
+
 #ifdef CONFIG_TFTP_TSIZE
 	if (tftp_tsize) {
-		ulong pos = tftp_cur_block * tftp_block_size +
+		pos = tftp_cur_block * tftp_block_size +
 			tftp_block_wrap_offset;
 		if (pos > tftp_tsize)
 			pos = tftp_tsize;
@@ -247,9 +251,11 @@
 	} else
 #endif
 	{
-		if (((tftp_cur_block - 1) % 10) == 0)
+		pos = (tftp_cur_block - 1) +
+			(tftp_block_wrap * TFTP_SEQUENCE_SIZE);
+		if ((pos % 10) == 0)
 			putc('#');
-		else if ((tftp_cur_block % (10 * HASHES_PER_LINE)) == 0)
+		else if (((pos + 1) % (10 * HASHES_PER_LINE)) == 0)
 			puts("\n\t ");
 	}
 }
@@ -282,9 +288,8 @@
 		tftp_block_wrap++;
 		tftp_block_wrap_offset += tftp_block_size * TFTP_SEQUENCE_SIZE;
 		timeout_count = 0; /* we've done well, reset the timeout */
-	} else {
-		show_block_marker();
 	}
+	show_block_marker();
 }
 
 /* The TFTP get or put is complete */
@@ -315,6 +320,7 @@
 	uchar *xp;
 	int len = 0;
 	ushort *s;
+	bool err_pkt = false;
 
 	/*
 	 *	We will always be sending some sort of packet, so
@@ -385,6 +391,7 @@
 		strcpy((char *)pkt, "File too large");
 		pkt += 14 /*strlen("File too large")*/ + 1;
 		len = pkt - xp;
+		err_pkt = true;
 		break;
 
 	case STATE_BAD_MAGIC:
@@ -396,11 +403,28 @@
 		strcpy((char *)pkt, "File has bad magic");
 		pkt += 18 /*strlen("File has bad magic")*/ + 1;
 		len = pkt - xp;
+		err_pkt = true;
+		break;
+
+	case STATE_INVALID_OPTION:
+		xp = pkt;
+		s = (ushort *)pkt;
+		*s++ = htons(TFTP_ERROR);
+		*s++ = htons(TFTP_ERR_OPTION_NEGOTIATION);
+		pkt = (uchar *)s;
+		strcpy((char *)pkt, "Option Negotiation Failed");
+		/* strlen("Option Negotiation Failed") + NULL*/
+		pkt += 25 + 1;
+		len = pkt - xp;
+		err_pkt = true;
 		break;
 	}
 
 	net_send_udp_packet(net_server_ethaddr, tftp_remote_ip,
 			    tftp_remote_port, tftp_our_port, len);
+
+	if (err_pkt)
+		net_set_state(NETLOOP_FAIL);
 }
 
 #ifdef CONFIG_CMD_TFTPPUT
@@ -421,6 +445,7 @@
 	__be16 proto;
 	__be16 *s;
 	int i;
+	u16 timeout_val_rcvd;
 
 	if (dest != tftp_our_port) {
 			return;
@@ -477,8 +502,14 @@
 #endif
 
 	case TFTP_OACK:
-		debug("Got OACK: %s %s\n",
-		      pkt, pkt + strlen((char *)pkt) + 1);
+		debug("Got OACK: ");
+		for (i = 0; i < len; i++) {
+			if (pkt[i] == '\0')
+				debug(" ");
+			else
+				debug("%c", pkt[i]);
+		}
+		debug("\n");
 		tftp_state = STATE_OACK;
 		tftp_remote_port = src;
 		/*
@@ -487,15 +518,32 @@
 		 * something like "len-8" may give a *huge* number
 		 */
 		for (i = 0; i+8 < len; i++) {
-			if (strcmp((char *)pkt + i, "blksize") == 0) {
+			if (strcasecmp((char *)pkt + i, "blksize") == 0) {
 				tftp_block_size = (unsigned short)
 					simple_strtoul((char *)pkt + i + 8,
 						       NULL, 10);
-				debug("Blocksize ack: %s, %d\n",
+				debug("Blocksize oack: %s, %d\n",
 				      (char *)pkt + i + 8, tftp_block_size);
+				if (tftp_block_size > tftp_block_size_option) {
+					printf("Invalid blk size(=%d)\n",
+					       tftp_block_size);
+					tftp_state = STATE_INVALID_OPTION;
+				}
+			}
+			if (strcasecmp((char *)pkt + i, "timeout") == 0) {
+				timeout_val_rcvd = (unsigned short)
+					simple_strtoul((char *)pkt + i + 8,
+						       NULL, 10);
+				debug("Timeout oack: %s, %d\n",
+				      (char *)pkt + i + 8, timeout_val_rcvd);
+				if (timeout_val_rcvd != (timeout_ms / 1000)) {
+					printf("Invalid timeout val(=%d s)\n",
+					       timeout_val_rcvd);
+					tftp_state = STATE_INVALID_OPTION;
+				}
 			}
 #ifdef CONFIG_TFTP_TSIZE
-			if (strcmp((char *)pkt+i, "tsize") == 0) {
+			if (strcasecmp((char *)pkt + i, "tsize") == 0) {
 				tftp_tsize = simple_strtoul((char *)pkt + i + 6,
 							   NULL, 10);
 				debug("size = %s, %d\n",
@@ -504,7 +552,7 @@
 #endif
 		}
 #ifdef CONFIG_CMD_TFTPPUT
-		if (tftp_put_active) {
+		if (tftp_put_active && tftp_state == STATE_OACK) {
 			/* Get ready to send the first block */
 			tftp_state = STATE_DATA;
 			tftp_cur_block++;
@@ -518,10 +566,8 @@
 		len -= 2;
 		tftp_cur_block = ntohs(*(__be16 *)pkt);
 
-		update_block_number();
-
 		if (tftp_state == STATE_SEND_RRQ)
-			debug("Server did not acknowledge timeout option!\n");
+			debug("Server did not acknowledge any options!\n");
 
 		if (tftp_state == STATE_SEND_RRQ || tftp_state == STATE_OACK ||
 		    tftp_state == STATE_RECV_WRQ) {
@@ -545,6 +591,7 @@
 			break;
 		}
 
+		update_block_number();
 		tftp_prev_block = tftp_cur_block;
 		timeout_count_max = tftp_timeout_count_max;
 		net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
diff --git a/tools/Makefile b/tools/Makefile
index 879c3fd..51123fd 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -107,6 +107,7 @@
 			lib/crc16.o \
 			lib/sha1.o \
 			lib/sha256.o \
+			lib/sha512.o \
 			common/hash.o \
 			ublimage.o \
 			zynqimage.o \
@@ -225,6 +226,7 @@
 HOSTCFLAGS_md5.o := -pedantic
 HOSTCFLAGS_sha1.o := -pedantic
 HOSTCFLAGS_sha256.o := -pedantic
+HOSTCFLAGS_sha512.o := -pedantic -DCONFIG_SHA512 -DCONFIG_SHA384
 
 quiet_cmd_wrap = WRAP    $@
 cmd_wrap = echo "\#include <../$(patsubst $(obj)/%,%,$@)>" >$@