Merge branch '2020-06-12-next-net' into next

- Merge tbs2910 distro boot support and associated clean-ups and size
  reduction.
- Assorted networking corrections / bugfixes.
- Drop smc911x standalone API example as it was likely non-functional for a
  long time.
- Enhanced support for TI PHYs
- rtl8139 DM conversion
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/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/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/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(priv);
 
-	rtl8139_reset(dev);
-
-	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(dev);
+	rtl8139_hw_reset(priv);
 }
 
+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 void rtl8139_name(char *str, int card_number)
+{
+	sprintf(str, "RTL8139#%u", card_number);
+}
+
+static struct pci_device_id supported[] = {
+	{ 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 struct pci_device_id supported[] = {
-	{ PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139 },
-	{ PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_8139 },
-	{ }
-};
+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));
 
-		sprintf(dev->name, "RTL8139#%d", card_number);
+		priv->devno = devno;
+		priv->ioaddr = (unsigned long)bus_to_phys(devno, iobase);
 
-		dev->priv = (void *)devno;
-		dev->iobase = (int)bus_to_phys(iobase);
+		dev = &priv->dev;
+
+		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/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/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);