summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2020-06-12 14:58:12 -0400
committerTom Rini <trini@konsulko.com>2020-06-12 14:58:12 -0400
commit8a1292ce3e21205645a155b23ac083a3fc6b64c1 (patch)
tree48fcd8954ca5d99a1b0e834d24031fbc353bf762
parentd16b38f42704fe3cc94fbee1601be96045013151 (diff)
parentf1d925d9c39628d346b3809408695cd5c8b8faa2 (diff)
downloadu-boot-8a1292ce3e21205645a155b23ac083a3fc6b64c1.tar.gz
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
-rw-r--r--board/tbs/tbs2910/MAINTAINERS1
-rw-r--r--cmd/net.c6
-rw-r--r--configs/am65x_evm_a53_defconfig2
-rw-r--r--configs/am65x_hs_evm_a53_defconfig2
-rw-r--r--configs/dra7xx_evm_defconfig2
-rw-r--r--configs/dra7xx_hs_evm_defconfig2
-rw-r--r--configs/dra7xx_hs_evm_usb_defconfig2
-rw-r--r--configs/j721e_evm_a72_defconfig2
-rw-r--r--configs/j721e_hs_evm_a72_defconfig2
-rw-r--r--configs/k2g_evm_defconfig2
-rw-r--r--configs/tbs2910_defconfig8
-rw-r--r--configs/xilinx_versal_virt_defconfig2
-rw-r--r--configs/xilinx_zynqmp_virt_defconfig2
-rw-r--r--doc/board/index.rst1
-rw-r--r--doc/board/tbs/index.rst9
-rw-r--r--doc/board/tbs/tbs2910.rst191
-rw-r--r--drivers/net/phy/Kconfig15
-rw-r--r--drivers/net/phy/Makefile3
-rw-r--r--drivers/net/phy/dp83867.c3
-rw-r--r--drivers/net/phy/micrel_ksz8xxx.c16
-rw-r--r--drivers/net/phy/phy.c22
-rw-r--r--drivers/net/phy/ti_phy_init.c101
-rw-r--r--drivers/net/phy/ti_phy_init.h15
-rw-r--r--drivers/net/rtl8139.c380
-rw-r--r--drivers/net/rtl8169.c16
-rw-r--r--examples/standalone/Makefile4
-rw-r--r--examples/standalone/smc911x_eeprom.c530
-rw-r--r--include/configs/tbs2910.h24
-rw-r--r--include/net.h3
-rw-r--r--include/phy.h112
-rw-r--r--net/dns.c10
-rw-r--r--net/net.c20
-rw-r--r--net/tftp.c75
33 files changed, 892 insertions, 693 deletions
diff --git a/board/tbs/tbs2910/MAINTAINERS b/board/tbs/tbs2910/MAINTAINERS
index a3ad2f712a..1e3c0d0ece 100644
--- a/board/tbs/tbs2910/MAINTAINERS
+++ b/board/tbs/tbs2910/MAINTAINERS
@@ -4,4 +4,5 @@ S: Maintained
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 25390b0474..9bbcdbcfe0 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -135,11 +135,15 @@ static void netboot_update_env(void)
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 @@ static void netboot_update_env(void)
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 d74a2d0930..c5ca4da73a 100644
--- a/configs/am65x_evm_a53_defconfig
+++ b/configs/am65x_evm_a53_defconfig
@@ -99,7 +99,7 @@ CONFIG_SPI_FLASH_SFDP_SUPPORT=y
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 117953817d..644873d67c 100644
--- a/configs/am65x_hs_evm_a53_defconfig
+++ b/configs/am65x_hs_evm_a53_defconfig
@@ -101,7 +101,7 @@ CONFIG_SPI_FLASH_SFDP_SUPPORT=y
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 e4547d9dcc..73ac3b319b 100644
--- a/configs/dra7xx_evm_defconfig
+++ b/configs/dra7xx_evm_defconfig
@@ -86,7 +86,7 @@ CONFIG_DM_SPI_FLASH=y
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 c08bcce903..40dc554e80 100644
--- a/configs/dra7xx_hs_evm_defconfig
+++ b/configs/dra7xx_hs_evm_defconfig
@@ -89,7 +89,7 @@ CONFIG_DM_SPI_FLASH=y
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 879c2b650b..babd7029c0 100644
--- a/configs/dra7xx_hs_evm_usb_defconfig
+++ b/configs/dra7xx_hs_evm_usb_defconfig
@@ -87,7 +87,7 @@ CONFIG_SF_DEFAULT_MODE=0
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 4deb4e219f..91a0572287 100644
--- a/configs/j721e_evm_a72_defconfig
+++ b/configs/j721e_evm_a72_defconfig
@@ -123,7 +123,7 @@ CONFIG_DM_SPI_FLASH=y
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 ae540a26a4..9aa3113642 100644
--- a/configs/j721e_hs_evm_a72_defconfig
+++ b/configs/j721e_hs_evm_a72_defconfig
@@ -113,7 +113,7 @@ CONFIG_DM_SPI_FLASH=y
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 5bc7f7f865..0379021c14 100644
--- a/configs/k2g_evm_defconfig
+++ b/configs/k2g_evm_defconfig
@@ -58,7 +58,7 @@ CONFIG_PHYLIB=y
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 2ff0e160f7..fbd2293add 100644
--- a/configs/tbs2910_defconfig
+++ b/configs/tbs2910_defconfig
@@ -9,11 +9,15 @@ CONFIG_NR_DRAM_BANKS=1
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_START=0x10000000
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_MII=y
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_USB_GADGET_DOWNLOAD=y
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 4ed14f7030..b3e21ea903 100644
--- a/configs/xilinx_versal_virt_defconfig
+++ b/configs/xilinx_versal_virt_defconfig
@@ -63,7 +63,7 @@ CONFIG_SPI_FLASH_WINBOND=y
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 7886d5a38f..2b4a0244fa 100644
--- a/configs/xilinx_zynqmp_virt_defconfig
+++ b/configs/xilinx_zynqmp_virt_defconfig
@@ -108,7 +108,7 @@ CONFIG_PHY_MICREL=y
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 01b233f737..bb4473152a 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -18,5 +18,6 @@ Board-specific doc
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 0000000000..b677bc624f
--- /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 0000000000..e97f2b6e61
--- /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 d1f049e62a..b0bd762ac3 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -243,6 +243,21 @@ config PHY_TERANETICS
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 1d81516ecd..6e722331f1 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -25,7 +25,8 @@ obj-$(CONFIG_PHY_NATSEMI) += natsemi.o
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 d435cc1e6c..eada4541c9 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 @@ static struct phy_driver DP83867_driver = {
.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 98a0c83e68..60d42fe984 100644
--- a/drivers/net/phy/micrel_ksz8xxx.c
+++ b/drivers/net/phy/micrel_ksz8xxx.c
@@ -82,6 +82,21 @@ static struct phy_driver KSZ8051_driver = {
.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 @@ int phy_micrel_ksz8xxx_init(void)
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 cce09c47f9..67789897c2 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -786,17 +786,27 @@ static struct phy_device *get_phy_device_by_mask(struct mii_dev *bus,
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 0000000000..50eff77692
--- /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 0000000000..6c7f6c640a
--- /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 0daeefa489..8a6f305893 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 @@ static unsigned char rx_ring[RX_BUF_LEN + 16] __aligned(4);
#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 @@ static const unsigned int rtl8139_rx_config =
(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_hw_reset(struct eth_device *dev)
}
}
-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 @@ static void rtl8139_reset(struct eth_device *dev)
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 @@ static void rtl8139_reset(struct eth_device *dev)
* 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 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length)
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 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length)
*/
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 @@ static int rtl8139_send(struct eth_device *dev, void *packet, int length)
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 @@ static int rtl8139_recv(struct eth_device *dev)
(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 @@ static int rtl8139_init(struct eth_device *dev, bd_t *bis)
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 @@ int rtl8139_initialize(bd_t *bis)
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->dev;
+
+ rtl8139_name(dev->name, card_number);
- dev->priv = (void *)devno;
- dev->iobase = (int)bus_to_phys(iobase);
+ 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 @@ int rtl8139_initialize(bd_t *bis)
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 75058fdadc..fb4fae20e5 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -240,6 +240,9 @@ enum RTL8169_register_content {
/*_TBICSRBit*/
TBILinkOK = 0x02000000,
+
+ /* FuncEvent/Misc */
+ RxDv_Gated_En = 0x80000,
};
static struct {
@@ -1210,6 +1213,19 @@ static int rtl8169_eth_probe(struct udevice *dev)
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 4a34813804..d4be0c7350 100644
--- a/examples/standalone/Makefile
+++ b/examples/standalone/Makefile
@@ -8,10 +8,6 @@ extra-$(CONFIG_SMC91111) += smc91111_eeprom
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 9bd9a6efa3..0000000000
--- 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 7376b91f55..17de122852 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 00a8ec0c78..1bf9867f8c 100644
--- a/include/net.h
+++ b/include/net.h
@@ -897,9 +897,6 @@ int is_serverip_in_cmd(void);
*/
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 b5de14cbfc..fedd146091 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -170,6 +170,13 @@ struct fixed_link {
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 @@ static inline int phy_read(struct phy_device *phydev, int devad, int regnum)
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 @@ static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
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 @@ static inline void phy_mmd_start_indirect(struct phy_device *phydev, int devad,
(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 @@ static inline int phy_read_mmd(struct phy_device *phydev, int devad,
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 @@ static inline int phy_write_mmd(struct phy_device *phydev, int devad,
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 @@ static inline int is_10g_interface(phy_interface_t interface)
/**
* 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 @@ int phy_reset(struct phy_device *phydev);
* @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 @@ void phy_connect_dev(struct phy_device *phydev, struct udevice *dev);
/**
* 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 @@ void phy_connect_dev(struct phy_device *phydev, struct udevice *dev);
* @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 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev);
/**
* 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 @@ void phy_connect_dev(struct phy_device *phydev, struct eth_device *dev);
* @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 @@ int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id);
* 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 @@ int phy_get_interface_by_name(const char *str);
* 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 @@ static inline bool phy_interface_is_rgmii(struct phy_device *phydev)
* 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 e35c4dca7c..5b1fe5b010 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -36,6 +36,16 @@ char *net_dns_env_var; /* The envvar to store the answer in */
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 37932919d0..1e7f633cb6 100644
--- a/net/net.c
+++ b/net/net.c
@@ -456,6 +456,7 @@ restart:
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 @@ restart:
/* 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 @@ restart:
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 @@ int net_parse_bootfile(struct in_addr *ipaddr, char *filename, int max_len)
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 180140e495..c05b7b5532 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -70,6 +70,7 @@ enum {
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 @@ static int tftp_put_final_block_sent;
#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 tftp_timeout_handler(void);
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 @@ static void show_block_marker(void)
} 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 @@ static void update_block_number(void)
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 @@ static void tftp_send(void)
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 @@ static void tftp_send(void)
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 @@ static void tftp_send(void)
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 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
__be16 proto;
__be16 *s;
int i;
+ u16 timeout_val_rcvd;
if (dest != tftp_our_port) {
return;
@@ -477,8 +502,14 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
#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 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
* 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 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
#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 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
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 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
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);