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
This commit is contained in:
Tom Rini 2020-06-12 14:58:12 -04:00
commit 8a1292ce3e
33 changed files with 892 additions and 693 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -18,5 +18,6 @@ Board-specific doc
rockchip/index
sifive/index
st/index
tbs/index
toradex/index
xilinx/index

9
doc/board/tbs/index.rst Normal file
View File

@ -0,0 +1,9 @@
.. SPDX-License-Identifier: GPL-2.0+
TBS
===
.. toctree::
:maxdepth: 2
tbs2910

191
doc/board/tbs/tbs2910.rst Normal file
View File

@ -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.

View File

@ -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"

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */

View File

@ -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(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 @@ 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(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 @@ 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 = (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 @@ 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

View File

@ -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;
}

View File

@ -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.

View File

@ -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;
}
}
}

View File

@ -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 * */

View File

@ -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)
*

View File

@ -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)
{

View File

@ -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;

View File

@ -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);

View File

@ -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);