summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig55
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/dc2114x.c133
-rw-r--r--drivers/net/dwc_eth_xgmac_socfpga.c2
-rw-r--r--drivers/net/dwmac_socfpga.c2
-rw-r--r--drivers/net/eepro100.c2
-rw-r--r--drivers/net/fec_mxc.c13
-rw-r--r--drivers/net/fm/eth.c6
-rw-r--r--drivers/net/ksz9477.c241
-rw-r--r--drivers/net/phy/Kconfig3
-rw-r--r--drivers/net/phy/motorcomm.c505
-rw-r--r--drivers/net/rtl8139.c2
-rw-r--r--drivers/net/sandbox-lwip.c85
-rw-r--r--drivers/net/zynq_gem.c9
14 files changed, 992 insertions, 67 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce80e43966a..576cd2d50ad 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -48,6 +48,7 @@ config DM_DSA
bool "Enable Driver Model for DSA switches"
depends on DM_MDIO
depends on PHY_FIXED
+ depends on !NET_LWIP
help
Enable driver model for DSA switches
@@ -96,7 +97,7 @@ config DSA_SANDBOX
menuconfig NETDEVICES
bool "Network device support"
- depends on NET
+ depends on NET || NET_LWIP
select DM_ETH
help
You must select Y to enable any network device support
@@ -342,6 +343,7 @@ config ESSEDMA
config ETH_SANDBOX
depends on SANDBOX
+ depends on NET
default y
bool "Sandbox: Mocked Ethernet driver"
help
@@ -350,8 +352,20 @@ config ETH_SANDBOX
This driver is particularly useful in the test/dm/eth.c tests
+config ETH_SANDBOX_LWIP
+ depends on SANDBOX
+ depends on NET_LWIP
+ default y
+ bool "Sandbox: Mocked Ethernet driver (for NET_LWIP)"
+ help
+ This driver is meant as a replacement for ETH_SANDBOX when
+ the network stack is NET_LWIP rather than NET. It currently
+ does nothing, i.e. it drops the sent packets and never receives
+ data.
+
config ETH_SANDBOX_RAW
depends on SANDBOX
+ depends on NET
default y
bool "Sandbox: Bridge to Linux Raw Sockets"
help
@@ -468,6 +482,7 @@ config FTMAC100
config FTGMAC100
bool "Ftgmac100 Ethernet Support"
select PHYLIB
+ depends on NET
help
This driver supports the Faraday's FTGMAC100 Gigabit SoC
Ethernet controller that can be found on Aspeed SoCs (which
@@ -510,11 +525,11 @@ config KS8851_MLL
The Microchip KS8851 parallel bus external ethernet interface chip.
config KSZ9477
- bool "Microchip KSZ9477 I2C controller driver"
- depends on DM_DSA && DM_I2C
+ bool "Microchip KSZ9477 controller driver"
+ depends on DM_DSA && (DM_I2C || DM_SPI)
help
This driver implements a DSA switch driver for the KSZ9477 family
- of GbE switches using the I2C interface.
+ of GbE switches using the I2C or SPI interface.
config LITEETH
bool "LiteX LiteEth Ethernet MAC"
@@ -747,6 +762,38 @@ config TULIP
help
This driver supports DEC DC2114x Fast ethernet chips.
+config TULIP_SUPPORT_NON_PCI
+ bool "No PCI controller"
+ depends on TULIP
+ default n
+ help
+ Say Y to this and you can run this driver on platforms that do not
+ have PCI controllers.
+
+config TULIP_IGNORE_TX_NO_CARRIER
+ bool "Ignore tx no carrier error"
+ depends on TULIP
+ default n
+ help
+ Some IP cores of dc2114x or its variants do not comply so well with
+ the behaviors described by the official document. A packet could be
+ sent successfully but reported with No Carrier error. Latest drivers
+ of this IP core do not detect this error anymore. Say Y to this could
+ disable handling of this error.
+
+config TULIP_MULTIPLE_TX_DESC
+ bool "Use multiple tx descriptors"
+ depends on TULIP
+ default n
+ help
+ Some IP cores of dc2114x or its variants do not comply so well with
+ the behaviors described by the official document. Originally this
+ driver uses only one tx descriptor and organizes it as a ring buffer,
+ which would lead to a problem that one packet would be sent twice.
+ Say Y to this could prevent this bug if you are using IP cores with
+ this issue, by using multiple tx descriptors and organizing them as
+ a real well-defined ring buffer.
+
config XILINX_AXIEMAC
select PHYLIB
select MII
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4946a63f80f..f5ab1f5dedf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
obj-$(CONFIG_ETH_SANDBOX) += sandbox.o
obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw-bus.o
obj-$(CONFIG_ETH_SANDBOX_RAW) += sandbox-raw.o
+obj-$(CONFIG_ETH_SANDBOX_LWIP) += sandbox-lwip.o
obj-$(CONFIG_FEC_MXC) += fec_mxc.o
obj-$(CONFIG_FMAN_ENET) += fm/
obj-$(CONFIG_FMAN_ENET) += fsl_mdio.o
diff --git a/drivers/net/dc2114x.c b/drivers/net/dc2114x.c
index ce028f451f1..7c0665faa8e 100644
--- a/drivers/net/dc2114x.c
+++ b/drivers/net/dc2114x.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
#include <asm/io.h>
+#include <cpu_func.h>
#include <dm.h>
#include <malloc.h>
#include <net.h>
@@ -72,10 +73,20 @@
#define POLL_DEMAND 1
+#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
+#define phys_to_bus(dev, a) virt_to_phys((volatile const void *)(a))
+#else
#define phys_to_bus(dev, a) dm_pci_phys_to_mem((dev), (a))
+#endif
+
+/* Number of TX descriptors */
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+#define NUM_TX_DESC 4
+#else
+#define NUM_TX_DESC 1
+#endif
#define NUM_RX_DESC PKTBUFSRX
-#define NUM_TX_DESC 1 /* Number of TX descriptors */
#define RX_BUFF_SZ PKTSIZE_ALIGN
#define TOUT_LOOP 1000000
@@ -89,9 +100,17 @@ struct de4x5_desc {
u32 next;
};
+/* Assigned for network card's ring buffer:
+ * Some CPU might treat these memories as cached, and changes to these memories
+ * won't immediately be visible to each other. It is necessary to ensure that
+ * these memories between the CPU and the network card are marked as uncached.
+ */
+static struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32);
+static struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32);
+
struct dc2114x_priv {
- struct de4x5_desc rx_ring[NUM_RX_DESC] __aligned(32);
- struct de4x5_desc tx_ring[NUM_TX_DESC] __aligned(32);
+ struct de4x5_desc *rx_ring; /* Must be uncached to CPU */
+ struct de4x5_desc *tx_ring; /* Must be uncached to CPU */
int rx_new; /* RX descriptor ring pointer */
int tx_new; /* TX descriptor ring pointer */
char rx_ring_size;
@@ -271,7 +290,12 @@ static int read_srom(struct dc2114x_priv *priv, u_long ioaddr, int index)
static void send_setup_frame(struct dc2114x_priv *priv)
{
- char setup_frame[SETUP_FRAME_LEN];
+ /* We are writing setup frame and these changes should be visible to the
+ * network card immediately. So let's directly read/write through the
+ * uncached window.
+ */
+ char __setup_frame[SETUP_FRAME_LEN] __aligned(32);
+ char *setup_frame = (char *)map_physmem((phys_addr_t)virt_to_phys(__setup_frame), 0, MAP_NOCACHE);
char *pa = &setup_frame[0];
int i;
@@ -292,8 +316,13 @@ static void send_setup_frame(struct dc2114x_priv *priv)
}
priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno,
- (u32)&setup_frame[0]));
+ (phys_addr_t)&setup_frame[0]));
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+ priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_SET | SETUP_FRAME_LEN);
+ priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+#else
priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_SET | SETUP_FRAME_LEN);
+#endif
priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN);
dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD);
@@ -307,7 +336,7 @@ static void send_setup_frame(struct dc2114x_priv *priv)
}
if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) != 0x7FFFFFFF) {
- printf("TX error status2 = 0x%08X\n",
+ debug("TX error status2 = 0x%08X\n",
le32_to_cpu(priv->tx_ring[priv->tx_new].status));
}
@@ -332,9 +361,17 @@ static int dc21x4x_send_common(struct dc2114x_priv *priv, void *packet, int leng
goto done;
}
+ /* Packet should be visible to the network card */
+ flush_dcache_range((phys_addr_t)packet, (phys_addr_t)(packet + RX_BUFF_SZ));
+
priv->tx_ring[priv->tx_new].buf = cpu_to_le32(phys_to_bus(priv->devno,
- (u32)packet));
+ (phys_addr_t)packet));
+#if CONFIG_IS_ENABLED(TULIP_MULTIPLE_TX_DESC)
+ priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_LS | TD_FS | length);
+ priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
+#else
priv->tx_ring[priv->tx_new].des1 = cpu_to_le32(TD_TER | TD_LS | TD_FS | length);
+#endif
priv->tx_ring[priv->tx_new].status = cpu_to_le32(T_OWN);
dc2114x_outl(priv, POLL_DEMAND, DE4X5_TPD);
@@ -349,7 +386,9 @@ static int dc21x4x_send_common(struct dc2114x_priv *priv, void *packet, int leng
if (le32_to_cpu(priv->tx_ring[priv->tx_new].status) & TD_ES) {
priv->tx_ring[priv->tx_new].status = 0x0;
+#if !CONFIG_IS_ENABLED(TULIP_IGNORE_TX_NO_CARRIER)
goto done;
+#endif
}
status = length;
@@ -398,13 +437,22 @@ static int dc21x4x_init_common(struct dc2114x_priv *priv)
return -1;
}
- dc2114x_outl(priv, OMR_SDP | OMR_PS | OMR_PM, DE4X5_OMR);
+ /* 2024-07:
+ * Remove the OMR_PM flag and choose 16 perfect filtering mode since in
+ * modern networks there're plenty of multicasts and set ORM_PM flag will
+ * increase the dc2114x's workload and ask the U-Boot to handle packets
+ * not related to itself. And most of the time, U-Boot does not need this
+ * feature.
+ *
+ * A better way: let user to decide whether to have this flag.
+ */
+ dc2114x_outl(priv, OMR_SDP | OMR_PS, DE4X5_OMR);
for (i = 0; i < NUM_RX_DESC; i++) {
priv->rx_ring[i].status = cpu_to_le32(R_OWN);
priv->rx_ring[i].des1 = cpu_to_le32(RX_BUFF_SZ);
priv->rx_ring[i].buf = cpu_to_le32(phys_to_bus(priv->devno,
- (u32)net_rx_packets[i]));
+ (phys_addr_t)net_rx_packets[i]));
priv->rx_ring[i].next = 0;
}
@@ -423,9 +471,9 @@ static int dc21x4x_init_common(struct dc2114x_priv *priv)
priv->tx_ring[priv->tx_ring_size - 1].des1 |= cpu_to_le32(TD_TER);
/* Tell the adapter where the TX/RX rings are located. */
- dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->rx_ring),
+ dc2114x_outl(priv, phys_to_bus(priv->devno, (phys_addr_t)priv->rx_ring),
DE4X5_RRBA);
- dc2114x_outl(priv, phys_to_bus(priv->devno, (u32)&priv->tx_ring),
+ dc2114x_outl(priv, phys_to_bus(priv->devno, (phys_addr_t)priv->tx_ring),
DE4X5_TRBA);
start_de4x5(priv);
@@ -461,21 +509,32 @@ static void read_hw_addr(struct dc2114x_priv *priv)
}
}
+#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
static struct pci_device_id supported[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST) },
{ PCI_DEVICE(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142) },
{ }
};
+#endif
static int dc2114x_start(struct udevice *dev)
{
- struct eth_pdata *plat = dev_get_plat(dev);
struct dc2114x_priv *priv = dev_get_priv(dev);
+ int rval;
- memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
+ if (!priv->enetaddr) {
+ rval = eth_env_get_enetaddr("ethaddr", priv->enetaddr);
+ if (!rval) {
+ printf("dc2114x: Err: please set a valid MAC address\n");
+ return -EINVAL;
+ }
+ }
+
+#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
/* Ensure we're not sleeping. */
dm_pci_write_config8(dev, PCI_CFDA_PSM, WAKEUP);
+#endif
return dc21x4x_init_common(priv);
}
@@ -485,8 +544,9 @@ static void dc2114x_stop(struct udevice *dev)
struct dc2114x_priv *priv = dev_get_priv(dev);
dc21x4x_halt_common(priv);
-
+#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
dm_pci_write_config8(dev, PCI_CFDA_PSM, SLEEP);
+#endif
}
static int dc2114x_send(struct udevice *dev, void *packet, int length)
@@ -515,7 +575,8 @@ static int dc2114x_recv(struct udevice *dev, int flags, uchar **packetp)
if (!ret)
return 0;
- *packetp = net_rx_packets[priv->rx_new];
+ invalidate_dcache_range((phys_addr_t)net_rx_packets[priv->rx_new], (phys_addr_t)(net_rx_packets[priv->rx_new] + RX_BUFF_SZ));
+ *packetp = (uchar *)net_rx_packets[priv->rx_new];
return ret - 4;
}
@@ -543,7 +604,7 @@ static int dc2114x_read_rom_hwaddr(struct udevice *dev)
static int dc2114x_bind(struct udevice *dev)
{
- static int card_number;
+ static int card_number = 0;
char name[16];
sprintf(name, "dc2114x#%u", card_number++);
@@ -555,6 +616,8 @@ static int dc2114x_probe(struct udevice *dev)
{
struct eth_pdata *plat = dev_get_plat(dev);
struct dc2114x_priv *priv = dev_get_priv(dev);
+
+#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
u16 command, status;
u32 iobase;
@@ -562,9 +625,6 @@ static int dc2114x_probe(struct udevice *dev)
iobase &= ~0xf;
debug("dc2114x: DEC 2114x PCI Device @0x%x\n", iobase);
-
- priv->devno = dev;
- priv->enetaddr = plat->enetaddr;
priv->iobase = (void __iomem *)dm_pci_mem_to_phys(dev, iobase);
command = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
@@ -576,10 +636,29 @@ static int dc2114x_probe(struct udevice *dev)
}
dm_pci_write_config8(dev, PCI_LATENCY_TIMER, 0x60);
+#endif
+
+ priv->devno = dev;
+ priv->enetaddr = plat->enetaddr;
+ priv->rx_ring = (struct de4x5_desc *)map_physmem((phys_addr_t)virt_to_phys(rx_ring), 0, MAP_NOCACHE);
+ priv->tx_ring = (struct de4x5_desc *)map_physmem((phys_addr_t)virt_to_phys(tx_ring), 0, MAP_NOCACHE);
return 0;
}
+#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
+static int dc2114x_of_to_plat(struct udevice *dev)
+{
+ struct eth_pdata *plat = dev_get_plat(dev);
+ struct dc2114x_priv *priv = dev_get_priv(dev);
+
+ plat->iobase = (phys_addr_t)map_physmem((phys_addr_t)devfdt_get_addr(dev), 0, MAP_NOCACHE);
+ priv->iobase = (void *)plat->iobase;
+
+ return 0;
+}
+#endif
+
static const struct eth_ops dc2114x_ops = {
.start = dc2114x_start,
.send = dc2114x_send,
@@ -589,9 +668,23 @@ static const struct eth_ops dc2114x_ops = {
.read_rom_hwaddr = dc2114x_read_rom_hwaddr,
};
+#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
+static const struct udevice_id dc2114x_eth_ids[] = {
+ { .compatible = "dec,dmfe" },
+ { .compatible = "tulip,dmfe" },
+ { .compatible = "dec,dc2114x" },
+ { .compatible = "tulip,dc2114x" },
+ { }
+};
+#endif
+
U_BOOT_DRIVER(eth_dc2114x) = {
.name = "eth_dc2114x",
.id = UCLASS_ETH,
+#if CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
+ .of_match = dc2114x_eth_ids,
+ .of_to_plat = dc2114x_of_to_plat,
+#endif
.bind = dc2114x_bind,
.probe = dc2114x_probe,
.ops = &dc2114x_ops,
@@ -599,4 +692,6 @@ U_BOOT_DRIVER(eth_dc2114x) = {
.plat_auto = sizeof(struct eth_pdata),
};
+#if !CONFIG_IS_ENABLED(TULIP_SUPPORT_NON_PCI)
U_BOOT_PCI_DEVICE(eth_dc2114x, supported);
+#endif
diff --git a/drivers/net/dwc_eth_xgmac_socfpga.c b/drivers/net/dwc_eth_xgmac_socfpga.c
index 270c1b0ca6c..87fb7e887e7 100644
--- a/drivers/net/dwc_eth_xgmac_socfpga.c
+++ b/drivers/net/dwc_eth_xgmac_socfpga.c
@@ -37,7 +37,7 @@ static int dwxgmac_socfpga_do_setphy(struct udevice *dev, u32 modereg)
u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK <<
xgmac->syscon_phy_regshift;
- if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) {
+ if (!(IS_ENABLED(CONFIG_XPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) {
u32 index = ((u64)xgmac->syscon_phy - socfpga_get_sysmgr_addr() -
SYSMGR_SOC64_EMAC0) >> 2;
diff --git a/drivers/net/dwmac_socfpga.c b/drivers/net/dwmac_socfpga.c
index bba3fc4d34b..a9e2d8c0972 100644
--- a/drivers/net/dwmac_socfpga.c
+++ b/drivers/net/dwmac_socfpga.c
@@ -68,7 +68,7 @@ static int dwmac_socfpga_do_setphy(struct udevice *dev, u32 modereg)
struct dwmac_socfpga_plat *pdata = dev_get_plat(dev);
u32 modemask = SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << pdata->reg_shift;
-#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_ATF)
+#if !defined(CONFIG_XPL_BUILD) && defined(CONFIG_SPL_ATF)
u32 index = ((u64)pdata->phy_intf - socfpga_get_sysmgr_addr() -
SYSMGR_SOC64_EMAC0) >> 2;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index d18a8d577ca..f64dbb7d6a1 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -678,7 +678,7 @@ static int eepro100_recv_common(struct eepro100_priv *priv, uchar **packetp)
status = le16_to_cpu(desc->status);
if (!(status & RFD_STATUS_C))
- return 0;
+ return -EAGAIN;
/* Valid frame status. */
if (status & RFD_STATUS_OK) {
diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c
index 0a0d92bc2cd..d6d5cb52fdd 100644
--- a/drivers/net/fec_mxc.c
+++ b/drivers/net/fec_mxc.c
@@ -615,8 +615,7 @@ static int fecmxc_init(struct udevice *dev)
if (fec->xcv_type != SEVENWIRE)
miiphy_restart_aneg(dev);
#endif
- fec_open(dev);
- return 0;
+ return fec_open(dev);
}
/**
@@ -818,6 +817,9 @@ static int fecmxc_recv(struct udevice *dev, int flags, uchar **packetp)
return -ENOMEM;
}
+ if (!(readl(&fec->eth->ecntrl) & FEC_ECNTRL_ETHER_EN))
+ return 0;
+
/* Check if any critical events have happened */
ievent = readl(&fec->eth->ievent);
writel(ievent, &fec->eth->ievent);
@@ -1210,10 +1212,13 @@ static int fecmxc_set_ref_clk(struct clk *clk_ref, phy_interface_t interface)
else if (interface == PHY_INTERFACE_MODE_RGMII ||
interface == PHY_INTERFACE_MODE_RGMII_ID ||
interface == PHY_INTERFACE_MODE_RGMII_RXID ||
- interface == PHY_INTERFACE_MODE_RGMII_TXID)
+ interface == PHY_INTERFACE_MODE_RGMII_TXID) {
freq = 125000000;
- else
+ if (is_imx93())
+ freq = freq << 1;
+ } else {
return -EINVAL;
+ }
ret = clk_set_rate(clk_ref, freq);
if (ret < 0)
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 19f3f0fef07..63fe4b2d33c 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -26,7 +26,8 @@
#include "fm.h"
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) && !defined(BITBANGMII)
+#if ((defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+ !defined(CONFIG_BITBANGMII))
#define TBIANA_SETTINGS (TBIANA_ASYMMETRIC_PAUSE | TBIANA_SYMMETRIC_PAUSE | \
TBIANA_FULL_DUPLEX)
@@ -701,8 +702,11 @@ static int init_phy(struct fm_eth *fm_eth)
supported |= SUPPORTED_2500baseX_Full;
#endif
+#if (CONFIG_IS_ENABLED(MII) || CONFIG_IS_ENABLED(CMD_MII)) && \
+ !CONFIG_IS_ENABLED(BITBANGMII)
if (fm_eth->type == FM_ETH_1G_E)
dtsec_init_phy(fm_eth);
+#endif
#ifdef CONFIG_PHYLIB
#ifdef CONFIG_DM_MDIO
diff --git a/drivers/net/ksz9477.c b/drivers/net/ksz9477.c
index 43baa699619..7ebbe197660 100644
--- a/drivers/net/ksz9477.c
+++ b/drivers/net/ksz9477.c
@@ -11,7 +11,12 @@
#include <eth_phy.h>
#include <linux/delay.h>
#include <miiphy.h>
-#include <i2c.h>
+#if CONFIG_IS_ENABLED(DM_I2C)
+# include <i2c.h>
+#endif
+#if CONFIG_IS_ENABLED(DM_SPI)
+# include <spi.h>
+#endif
#include <net/dsa.h>
#include <asm-generic/gpio.h>
@@ -71,15 +76,157 @@
#define MMD_SETUP(mode, dev) (((u16)(mode) << PORT_MMD_OP_MODE_S) | (dev))
#define REG_PORT_PHY_MMD_INDEX_DATA 0x011C
+/* SPI specific define (opcodes) */
+#define KSZ_SPI_OP_RD 3
+#define KSZ_SPI_OP_WR 2
+
+#define KSZ9477_SPI_ADDR_SHIFT 24
+#define KSZ9477_SPI_ADDR_ALIGN 3
+#define KSZ9477_SPI_TURNAROUND_SHIFT 5
+
+/**
+ * struct ksz_phy_ops - low-level KSZ bus operations
+ */
+struct ksz_phy_ops {
+ /* read() - Read bytes from the device
+ *
+ * @udev: bus device
+ * @reg: register offset
+ * @val: data read
+ * @len: Number of bytes to read
+ *
+ * @return: 0 on success, negative on failure
+ */
+ int (*read)(struct udevice *udev, u32 reg, u8 *val, int len);
+
+ /* write() - Write bytes to the device
+ *
+ * @udev: bus device
+ * @reg: register offset
+ * @val: data to write
+ * @len: Number of bytes to write
+ *
+ * @return: 0 on success, negative on failure
+ */
+ int (*write)(struct udevice *udev, u32 reg, u8 *val, int len);
+};
+
struct ksz_dsa_priv {
struct udevice *dev;
+ struct ksz_phy_ops *phy_ops;
u32 features; /* chip specific features */
};
+#if CONFIG_IS_ENABLED(DM_I2C)
+static inline int ksz_i2c_read(struct udevice *dev, u32 reg, u8 *val, int len)
+{
+ return dm_i2c_read(dev, reg, val, len);
+}
+
+static inline int ksz_i2c_write(struct udevice *dev, u32 reg, u8 *val, int len)
+{
+ return dm_i2c_write(dev, reg, val, len);
+}
+
+static struct ksz_phy_ops phy_i2c_ops = {
+ .read = ksz_i2c_read,
+ .write = ksz_i2c_write,
+};
+#endif
+
+#if CONFIG_IS_ENABLED(DM_SPI)
+/**
+ * ksz_spi_xfer() - only used for 8/16/32 bits bus access
+ *
+ * @dev: The SPI slave device which will be sending/receiving the data.
+ * @reg: register address.
+ * @out: Pointer to a string of bits to send out. The bits are
+ * held in a byte array and are sent MSB first.
+ * @in: Pointer to a string of bits that will be filled in.
+ * @len: number of bytes to read.
+ *
+ * Return: 0 on success, not 0 on failure
+ */
+static int ksz_spi_xfer(struct udevice *dev, u32 reg, const u8 *out,
+ u8 *in, u16 len)
+{
+ int ret;
+ u32 addr = 0;
+ u8 opcode;
+
+ if (in && out) {
+ printf("%s: can't do full duplex\n", __func__);
+ return -EINVAL;
+ }
+
+ if (len > 4 || len == 0) {
+ printf("%s: only 8/16/32 bits bus access supported\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ ret = dm_spi_claim_bus(dev);
+ if (ret < 0) {
+ printf("%s: could not claim bus\n", __func__);
+ return ret;
+ }
+
+ opcode = (in ? KSZ_SPI_OP_RD : KSZ_SPI_OP_WR);
+
+ /* The actual device address space is 16 bits (A15 - A0),
+ * so the values of address bits A23 - A16 in the SPI
+ * command/address phase are “don't care”.
+ */
+ addr |= opcode << (KSZ9477_SPI_ADDR_SHIFT + KSZ9477_SPI_TURNAROUND_SHIFT);
+ addr |= reg << KSZ9477_SPI_TURNAROUND_SHIFT;
+
+ addr = __swab32(addr);
+
+ ret = dm_spi_xfer(dev, 32, &addr, NULL, SPI_XFER_BEGIN);
+ if (ret) {
+ printf("%s ERROR: dm_spi_xfer addr (%u)\n", __func__, ret);
+ goto release_bus;
+ }
+
+ ret = dm_spi_xfer(dev, len * 8, out, in, SPI_XFER_END);
+ if (ret) {
+ printf("%s ERROR: dm_spi_xfer data (%u)\n", __func__, ret);
+ goto release_bus;
+ }
+
+release_bus:
+ /* If an error occurred, release the chip by deasserting the CS */
+ if (ret < 0)
+ dm_spi_xfer(dev, 0, NULL, NULL, SPI_XFER_END);
+
+ dm_spi_release_bus(dev);
+
+ return ret;
+}
+
+static inline int ksz_spi_read(struct udevice *dev, u32 reg, u8 *val, int len)
+{
+ return ksz_spi_xfer(dev, reg, NULL, val, len);
+}
+
+static inline int ksz_spi_write(struct udevice *dev, u32 reg, u8 *val, int len)
+{
+ return ksz_spi_xfer(dev, reg, val, NULL, len);
+}
+
+static struct ksz_phy_ops phy_spi_ops = {
+ .read = ksz_spi_read,
+ .write = ksz_spi_write,
+};
+#endif
+
static inline int ksz_read8(struct udevice *dev, u32 reg, u8 *val)
{
- int ret = dm_i2c_read(dev, reg, val, 1);
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
+
+ int ret = phy_ops->read(dev, reg, val, 1);
dev_dbg(dev, "%s 0x%04x<<0x%02x\n", __func__, reg, *val);
@@ -93,8 +240,11 @@ static inline int ksz_pread8(struct udevice *dev, int port, int reg, u8 *val)
static inline int ksz_write8(struct udevice *dev, u32 reg, u8 val)
{
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
+
dev_dbg(dev, "%s 0x%04x>>0x%02x\n", __func__, reg, val);
- return dm_i2c_write(dev, reg, &val, 1);
+ return phy_ops->write(dev, reg, &val, 1);
}
static inline int ksz_pwrite8(struct udevice *dev, int port, int reg, u8 val)
@@ -104,13 +254,15 @@ static inline int ksz_pwrite8(struct udevice *dev, int port, int reg, u8 val)
static inline int ksz_write16(struct udevice *dev, u32 reg, u16 val)
{
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
u8 buf[2];
buf[1] = val & 0xff;
buf[0] = val >> 8;
dev_dbg(dev, "%s 0x%04x>>0x%04x\n", __func__, reg, val);
- return dm_i2c_write(dev, reg, buf, 2);
+ return phy_ops->write(dev, reg, buf, 2);
}
static inline int ksz_pwrite16(struct udevice *dev, int port, int reg, u16 val)
@@ -120,10 +272,12 @@ static inline int ksz_pwrite16(struct udevice *dev, int port, int reg, u16 val)
static inline int ksz_read16(struct udevice *dev, u32 reg, u16 *val)
{
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
u8 buf[2];
int ret;
- ret = dm_i2c_read(dev, reg, buf, 2);
+ ret = phy_ops->read(dev, reg, buf, 2);
*val = (buf[0] << 8) | buf[1];
dev_dbg(dev, "%s 0x%04x<<0x%04x\n", __func__, reg, *val);
@@ -137,7 +291,10 @@ static inline int ksz_pread16(struct udevice *dev, int port, int reg, u16 *val)
static inline int ksz_read32(struct udevice *dev, u32 reg, u32 *val)
{
- return dm_i2c_read(dev, reg, (u8 *)val, 4);
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
+
+ return phy_ops->read(dev, reg, (u8 *)val, 4);
}
static inline int ksz_pread32(struct udevice *dev, int port, int reg, u32 *val)
@@ -147,6 +304,8 @@ static inline int ksz_pread32(struct udevice *dev, int port, int reg, u32 *val)
static inline int ksz_write32(struct udevice *dev, u32 reg, u32 val)
{
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ struct ksz_phy_ops *phy_ops = priv->phy_ops;
u8 buf[4];
buf[3] = val & 0xff;
@@ -155,7 +314,7 @@ static inline int ksz_write32(struct udevice *dev, u32 reg, u32 val)
buf[0] = (val >> 8) & 0xff;
dev_dbg(dev, "%s 0x%04x>>0x%04x\n", __func__, reg, val);
- return dm_i2c_write(dev, reg, buf, 4);
+ return phy_ops->write(dev, reg, buf, 4);
}
static inline int ksz_pwrite32(struct udevice *dev, int port, int reg, u32 val)
@@ -276,7 +435,7 @@ static int ksz_mdio_probe(struct udevice *dev)
struct ksz_mdio_priv *priv = dev_get_priv(dev);
dev_dbg(dev, "%s\n", __func__);
- priv->ksz = dev_get_parent_priv(dev->parent);
+ priv->ksz = dev_get_priv(dev->parent);
return 0;
}
@@ -355,12 +514,12 @@ static int ksz_port_setup(struct udevice *dev, int port,
phy_interface_t interface)
{
struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
u8 data8;
dev_dbg(dev, "%s P%d %s\n", __func__, port + 1,
(port == pdata->cpu_port) ? "cpu" : "");
- struct ksz_dsa_priv *priv = dev_get_priv(dev);
if (port != pdata->cpu_port) {
if (priv->features & NEW_XMII)
/* phy port: config errata and leds */
@@ -503,23 +662,59 @@ static int ksz_probe_mdio(struct udevice *dev)
return 0;
}
-/*
- * I2C driver
- */
-static int ksz_i2c_probe(struct udevice *dev)
+static void ksz_ops_register(struct udevice *dev, struct ksz_phy_ops *ops)
+{
+ struct ksz_dsa_priv *priv = dev_get_priv(dev);
+
+ priv->phy_ops = ops;
+}
+
+static bool dsa_ksz_check_ops(struct ksz_phy_ops *phy_ops)
+{
+ if (!phy_ops || !phy_ops->read || !phy_ops->write)
+ return false;
+
+ return true;
+}
+
+static int ksz_probe(struct udevice *dev)
{
struct dsa_pdata *pdata = dev_get_uclass_plat(dev);
struct ksz_dsa_priv *priv = dev_get_priv(dev);
+ enum uclass_id parent_id = UCLASS_INVALID;
int i, ret;
u8 data8;
u32 id;
- dev_set_parent_priv(dev, priv);
+ parent_id = device_get_uclass_id(dev_get_parent(dev));
+ switch (parent_id) {
+#if CONFIG_IS_ENABLED(DM_I2C)
+ case UCLASS_I2C: {
+ ksz_ops_register(dev, &phy_i2c_ops);
- ret = i2c_set_chip_offset_len(dev, 2);
- if (ret) {
- printf("i2c_set_chip_offset_len failed: %d\n", ret);
- return ret;
+ ret = i2c_set_chip_offset_len(dev, 2);
+ if (ret) {
+ printf("i2c_set_chip_offset_len failed: %d\n", ret);
+ return ret;
+ }
+ break;
+ }
+#endif
+#if CONFIG_IS_ENABLED(DM_SPI)
+ case UCLASS_SPI: {
+ ksz_ops_register(dev, &phy_spi_ops);
+ break;
+ }
+#endif
+ default:
+ dev_err(dev, "invalid parent bus (%s)\n",
+ uclass_get_name(parent_id));
+ return -EINVAL;
+ }
+
+ if (!dsa_ksz_check_ops(priv->phy_ops)) {
+ printf("Driver bug. No bus ops defined\n");
+ return -EINVAL;
}
/* default config */
@@ -543,6 +738,9 @@ static int ksz_i2c_probe(struct udevice *dev)
case 0x00956700:
puts("KSZ9567R: ");
break;
+ case 0x00989600:
+ puts("KSZ9896C: ");
+ break;
case 0x00989700:
puts("KSZ9897S: ");
break;
@@ -573,19 +771,20 @@ static int ksz_i2c_probe(struct udevice *dev)
return 0;
};
-static const struct udevice_id ksz_i2c_ids[] = {
+static const struct udevice_id ksz_ids[] = {
{ .compatible = "microchip,ksz9897" },
{ .compatible = "microchip,ksz9477" },
{ .compatible = "microchip,ksz9567" },
{ .compatible = "microchip,ksz9893" },
+ { .compatible = "microchip,ksz9896" },
{ }
};
U_BOOT_DRIVER(ksz) = {
.name = "ksz-switch",
.id = UCLASS_DSA,
- .of_match = ksz_i2c_ids,
- .probe = ksz_i2c_probe,
+ .of_match = ksz_ids,
+ .probe = ksz_probe,
.ops = &ksz_dsa_ops,
.priv_auto = sizeof(struct ksz_dsa_priv),
};
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 73064b2af68..13e73810ad6 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -11,7 +11,7 @@ config MV88E6352_SWITCH
menuconfig PHYLIB
bool "Ethernet PHY (physical media interface) support"
- depends on NET
+ depends on NET || NET_LWIP
help
Enable Ethernet PHY (physical media interface) support.
@@ -368,6 +368,7 @@ config PHY_FIXED
config PHY_NCSI
bool "NC-SI based PHY"
+ depends on NET
endif #PHYLIB
diff --git a/drivers/net/phy/motorcomm.c b/drivers/net/phy/motorcomm.c
index a96430cec43..4d67203ee70 100644
--- a/drivers/net/phy/motorcomm.c
+++ b/drivers/net/phy/motorcomm.c
@@ -12,6 +12,7 @@
#define PHY_ID_YT8511 0x0000010a
#define PHY_ID_YT8531 0x4f51e91b
+#define PHY_ID_YT8821 0x4f51ea19
#define PHY_ID_MASK GENMASK(31, 0)
/* Extended Register's Address Offset Register */
@@ -102,8 +103,12 @@
#define YTPHY_SPECIFIC_STATUS_REG 0x11
#define YTPHY_DUPLEX_MASK BIT(13)
#define YTPHY_DUPLEX_SHIFT 13
-#define YTPHY_SPEED_MODE_MASK GENMASK(15, 14)
-#define YTPHY_SPEED_MODE_SHIFT 14
+#define YTPHY_SPEED_MASK ((0x3 << 14) | BIT(9))
+#define YTPHY_SPEED_10M ((0x0 << 14))
+#define YTPHY_SPEED_100M ((0x1 << 14))
+#define YTPHY_SPEED_1000M ((0x2 << 14))
+#define YTPHY_SPEED_10G ((0x3 << 14))
+#define YTPHY_SPEED_2500M ((0x0 << 14) | BIT(9))
#define YT8531_EXTREG_SLEEP_CONTROL1_REG 0x27
#define YT8531_ESC1R_SLEEP_SW BIT(15)
@@ -131,6 +136,91 @@
#define TX_CLK_100_INVERTED BIT(4)
#define TX_CLK_1000_INVERTED BIT(5)
+#define YT8821_SDS_EXT_CSR_CTRL_REG 0x23
+#define YT8821_SDS_EXT_CSR_VCO_LDO_EN BIT(15)
+#define YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN BIT(8)
+
+#define YT8821_UTP_EXT_PI_CTRL_REG 0x56
+#define YT8821_UTP_EXT_PI_RST_N_FIFO BIT(5)
+#define YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE BIT(4)
+#define YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE BIT(3)
+#define YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE BIT(2)
+#define YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE BIT(1)
+#define YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE BIT(0)
+
+#define YT8821_UTP_EXT_VCT_CFG6_CTRL_REG 0x97
+#define YT8821_UTP_EXT_FECHO_AMP_TH_HUGE GENMASK(15, 8)
+
+#define YT8821_UTP_EXT_ECHO_CTRL_REG 0x336
+#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000 GENMASK(14, 8)
+
+#define YT8821_UTP_EXT_GAIN_CTRL_REG 0x340
+#define YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000 GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_RPDN_CTRL_REG 0x34E
+#define YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 BIT(15)
+#define YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 BIT(7)
+#define YT8821_UTP_EXT_RPDN_IPR_SHT_2500 GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG 0x36A
+#define YT8821_UTP_EXT_TH_20DB_2500 GENMASK(15, 0)
+
+#define YT8821_UTP_EXT_TRACE_CTRL_REG 0x372
+#define YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 GENMASK(14, 8)
+#define YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500 GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG 0x374
+#define YT8821_UTP_EXT_ALPHA_SHT_2500 GENMASK(14, 8)
+#define YT8821_UTP_EXT_IPR_LNG_2500 GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_PLL_CTRL_REG 0x450
+#define YT8821_UTP_EXT_PLL_SPARE_CFG GENMASK(7, 0)
+
+#define YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG 0x466
+#define YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG GENMASK(14, 8)
+#define YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG 0x467
+#define YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG GENMASK(14, 8)
+#define YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG 0x468
+#define YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG GENMASK(14, 8)
+#define YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG 0x469
+#define YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG GENMASK(14, 8)
+#define YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG GENMASK(6, 0)
+
+#define YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG 0x4B3
+#define YT8821_UTP_EXT_MU_COARSE_FR_F_FFE GENMASK(14, 12)
+#define YT8821_UTP_EXT_MU_COARSE_FR_F_FBE GENMASK(10, 8)
+
+#define YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG 0x4B5
+#define YT8821_UTP_EXT_MU_FINE_FR_F_FFE GENMASK(14, 12)
+#define YT8821_UTP_EXT_MU_FINE_FR_F_FBE GENMASK(10, 8)
+
+#define YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG 0x4D2
+#define YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER GENMASK(7, 4)
+#define YT8821_UTP_EXT_VGA_LPF1_CAP_2500 GENMASK(3, 0)
+
+#define YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG 0x4D3
+#define YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER GENMASK(7, 4)
+#define YT8821_UTP_EXT_VGA_LPF2_CAP_2500 GENMASK(3, 0)
+
+#define YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG 0x660
+#define YT8821_UTP_EXT_NFR_TX_ABILITY BIT(3)
+
+#define YT8821_CHIP_MODE_FORCE_BX2500 1
+
+/* chip config register */
+#define YTPHY_CCR_MODE_SEL_MASK GENMASK(2, 0)
+
+#define YTPHY_REG_SPACE_SELECT_REG 0xA000
+#define YTPHY_RSSR_SPACE_MASK BIT(1)
+#define YTPHY_RSSR_FIBER_SPACE (0x1 << 1)
+#define YTPHY_RSSR_UTP_SPACE (0x0 << 1)
+
struct ytphy_plat_priv {
u32 rx_delay_ps;
u32 tx_delay_ps;
@@ -295,15 +385,15 @@ static int yt8531_parse_status(struct phy_device *phydev)
if (val < 0)
return val;
- speed_mode = (val & YTPHY_SPEED_MODE_MASK) >> YTPHY_SPEED_MODE_SHIFT;
+ speed_mode = (val & YTPHY_SPEED_MASK);
switch (speed_mode) {
- case 2:
+ case YTPHY_SPEED_1000M:
speed = SPEED_1000;
break;
- case 1:
+ case YTPHY_SPEED_100M:
speed = SPEED_100;
break;
- default:
+ case YTPHY_SPEED_10M:
speed = SPEED_10;
break;
}
@@ -632,6 +722,398 @@ static int yt8531_probe(struct phy_device *phydev)
return 0;
}
+static int ytphy_save_page(struct phy_device *phydev)
+{
+ int old_page;
+
+ old_page = ytphy_read_ext(phydev, YTPHY_REG_SPACE_SELECT_REG);
+ if (old_page < 0)
+ return old_page;
+
+ if ((old_page & YTPHY_RSSR_SPACE_MASK) == YTPHY_RSSR_FIBER_SPACE)
+ return YTPHY_RSSR_FIBER_SPACE;
+
+ return YTPHY_RSSR_UTP_SPACE;
+};
+
+static int ytphy_restore_page(struct phy_device *phydev, int page,
+ int ret)
+{
+ int mask = YTPHY_RSSR_SPACE_MASK;
+ int set;
+ int r;
+
+ if ((page & YTPHY_RSSR_SPACE_MASK) == YTPHY_RSSR_FIBER_SPACE)
+ set = YTPHY_RSSR_FIBER_SPACE;
+ else
+ set = YTPHY_RSSR_UTP_SPACE;
+
+ r = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG, mask,
+ set);
+ if (ret >= 0 && r < 0)
+ ret = r;
+
+ return ret;
+};
+
+static int ytphy_write_ext(struct phy_device *phydev, u16 regnum,
+ u16 val)
+{
+ int ret;
+
+ ret = phy_write(phydev, MDIO_DEVAD_NONE,
+ YTPHY_PAGE_SELECT, regnum);
+ if (ret < 0)
+ return ret;
+
+ return phy_write(phydev, MDIO_DEVAD_NONE, YTPHY_PAGE_DATA, val);
+}
+
+static int yt8821_probe(struct phy_device *phydev)
+{
+ phydev->advertising = PHY_GBIT_FEATURES |
+ SUPPORTED_2500baseX_Full |
+ SUPPORTED_Pause |
+ SUPPORTED_Asym_Pause;
+ phydev->supported = phydev->advertising;
+
+ return 0;
+}
+
+static int yt8821_serdes_init(struct phy_device *phydev)
+{
+ int old_page;
+ u16 mask;
+ u16 set;
+ int ret;
+
+ old_page = ytphy_save_page(phydev);
+ if (old_page < 0)
+ return old_page;
+
+ ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG,
+ YTPHY_RSSR_SPACE_MASK,
+ YTPHY_RSSR_FIBER_SPACE);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = phy_modify(phydev, MDIO_DEVAD_NONE, MII_BMCR,
+ BMCR_ANENABLE, 0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_SDS_EXT_CSR_VCO_LDO_EN |
+ YT8821_SDS_EXT_CSR_VCO_BIAS_LPF_EN;
+ set = YT8821_SDS_EXT_CSR_VCO_LDO_EN;
+ ret = ytphy_modify_ext(phydev, YT8821_SDS_EXT_CSR_CTRL_REG, mask,
+ set);
+
+err_restore_page:
+ return ytphy_restore_page(phydev, old_page, ret);
+}
+
+static int yt8821_utp_init(struct phy_device *phydev)
+{
+ int old_page;
+ u16 mask;
+ u16 save;
+ u16 set;
+ int ret;
+
+ old_page = ytphy_save_page(phydev);
+ if (old_page < 0)
+ return old_page;
+
+ ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG,
+ YTPHY_RSSR_SPACE_MASK,
+ YTPHY_RSSR_UTP_SPACE);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
+ YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500 |
+ YT8821_UTP_EXT_RPDN_IPR_SHT_2500;
+ set = YT8821_UTP_EXT_RPDN_BP_FFE_LNG_2500 |
+ YT8821_UTP_EXT_RPDN_BP_FFE_SHT_2500;
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_RPDN_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_VGA_LPF1_CAP_OTHER |
+ YT8821_UTP_EXT_VGA_LPF1_CAP_2500;
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_VGA_LPF1_CAP_CTRL_REG,
+ mask, 0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_VGA_LPF2_CAP_OTHER |
+ YT8821_UTP_EXT_VGA_LPF2_CAP_2500;
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_VGA_LPF2_CAP_CTRL_REG,
+ mask, 0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500 |
+ YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500;
+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THE_2500, 0x5a) |
+ FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THE_2500, 0x3c);
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_TRACE_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_IPR_LNG_2500;
+ set = FIELD_PREP(YT8821_UTP_EXT_IPR_LNG_2500, 0x6c);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_ALPHA_IPR_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000;
+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_LNG_GAIN_THR_1000, 0x2a);
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_ECHO_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000;
+ set = FIELD_PREP(YT8821_UTP_EXT_TRACE_MED_GAIN_THR_1000, 0x22);
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_GAIN_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_TH_20DB_2500;
+ set = FIELD_PREP(YT8821_UTP_EXT_TH_20DB_2500, 0x8000);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_TH_20DB_2500_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_MU_COARSE_FR_F_FFE |
+ YT8821_UTP_EXT_MU_COARSE_FR_F_FBE;
+ set = FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FFE, 0x7) |
+ FIELD_PREP(YT8821_UTP_EXT_MU_COARSE_FR_F_FBE, 0x7);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_MU_COARSE_FR_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_MU_FINE_FR_F_FFE |
+ YT8821_UTP_EXT_MU_FINE_FR_F_FBE;
+ set = FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FFE, 0x2) |
+ FIELD_PREP(YT8821_UTP_EXT_MU_FINE_FR_F_FBE, 0x2);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_MU_FINE_FR_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* save YT8821_UTP_EXT_PI_CTRL_REG's val for use later */
+ ret = ytphy_read_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG);
+ if (ret < 0)
+ goto err_restore_page;
+
+ save = ret;
+
+ mask = YT8821_UTP_EXT_PI_TX_CLK_SEL_AFE |
+ YT8821_UTP_EXT_PI_RX_CLK_3_SEL_AFE |
+ YT8821_UTP_EXT_PI_RX_CLK_2_SEL_AFE |
+ YT8821_UTP_EXT_PI_RX_CLK_1_SEL_AFE |
+ YT8821_UTP_EXT_PI_RX_CLK_0_SEL_AFE;
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG,
+ mask, 0);
+ if (ret < 0)
+ goto err_restore_page;
+
+ /* restore YT8821_UTP_EXT_PI_CTRL_REG's val */
+ ret = ytphy_write_ext(phydev, YT8821_UTP_EXT_PI_CTRL_REG, save);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_FECHO_AMP_TH_HUGE;
+ set = FIELD_PREP(YT8821_UTP_EXT_FECHO_AMP_TH_HUGE, 0x38);
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_VCT_CFG6_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_NFR_TX_ABILITY;
+ set = YT8821_UTP_EXT_NFR_TX_ABILITY;
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_TXGE_NFR_FR_THP_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_PLL_SPARE_CFG;
+ set = FIELD_PREP(YT8821_UTP_EXT_PLL_SPARE_CFG, 0xe9);
+ ret = ytphy_modify_ext(phydev, YT8821_UTP_EXT_PLL_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG |
+ YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG;
+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_3_10_ORG, 0x64) |
+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_2_10_ORG, 0x64);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_DAC_IMID_CH_2_3_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG |
+ YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG;
+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_1_10_ORG, 0x64) |
+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMID_CH_0_10_ORG, 0x64);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_DAC_IMID_CH_0_1_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG |
+ YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG;
+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_3_10_ORG, 0x64) |
+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_2_10_ORG, 0x64);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_DAC_IMSB_CH_2_3_CTRL_REG,
+ mask, set);
+ if (ret < 0)
+ goto err_restore_page;
+
+ mask = YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG |
+ YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG;
+ set = FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_1_10_ORG, 0x64) |
+ FIELD_PREP(YT8821_UTP_EXT_DAC_IMSB_CH_0_10_ORG, 0x64);
+ ret = ytphy_modify_ext(phydev,
+ YT8821_UTP_EXT_DAC_IMSB_CH_0_1_CTRL_REG,
+ mask, set);
+
+err_restore_page:
+ return ytphy_restore_page(phydev, old_page, ret);
+}
+
+static int yt8821_auto_sleep_config(struct phy_device *phydev,
+ bool enable)
+{
+ int old_page;
+ int ret;
+
+ old_page = ytphy_save_page(phydev);
+ if (old_page < 0)
+ return old_page;
+
+ ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG,
+ YTPHY_RSSR_SPACE_MASK,
+ YTPHY_RSSR_UTP_SPACE);
+ if (ret < 0)
+ goto err_restore_page;
+
+ ret = ytphy_modify_ext(phydev,
+ YT8531_EXTREG_SLEEP_CONTROL1_REG,
+ YT8531_ESC1R_SLEEP_SW,
+ enable ? 1 : 0);
+
+err_restore_page:
+ return ytphy_restore_page(phydev, old_page, ret);
+}
+
+static int yt8821_soft_reset(struct phy_device *phydev)
+{
+ return ytphy_modify_ext(phydev, YT8531_CHIP_CONFIG_REG,
+ YT8531_CCR_SW_RST, 0);
+}
+
+static int yt8821_config(struct phy_device *phydev)
+{
+ u8 mode = YT8821_CHIP_MODE_FORCE_BX2500;
+ int ret;
+ u16 set;
+
+ set = FIELD_PREP(YTPHY_CCR_MODE_SEL_MASK, mode);
+ ret = ytphy_modify_ext(phydev,
+ YT8531_CHIP_CONFIG_REG,
+ YTPHY_CCR_MODE_SEL_MASK,
+ set);
+ if (ret < 0)
+ return ret;
+
+ ret = yt8821_serdes_init(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = yt8821_utp_init(phydev);
+ if (ret < 0)
+ return ret;
+
+ ret = yt8821_auto_sleep_config(phydev, false);
+ if (ret < 0)
+ return ret;
+
+ return yt8821_soft_reset(phydev);
+}
+
+static void yt8821_parse_status(struct phy_device *phydev, int val)
+{
+ int speed_mode;
+ int speed;
+
+ speed_mode = val & YTPHY_SPEED_MASK;
+ switch (speed_mode) {
+ case YTPHY_SPEED_2500M:
+ speed = SPEED_2500;
+ break;
+ case YTPHY_SPEED_1000M:
+ speed = SPEED_1000;
+ break;
+ case YTPHY_SPEED_100M:
+ speed = SPEED_100;
+ break;
+ case YTPHY_SPEED_10M:
+ speed = SPEED_10;
+ break;
+ }
+
+ phydev->speed = speed;
+ phydev->duplex = FIELD_GET(YTPHY_DUPLEX_MASK, val);
+}
+
+static int yt8821_startup(struct phy_device *phydev)
+{
+ u16 val;
+ int ret;
+
+ ret = ytphy_modify_ext(phydev, YTPHY_REG_SPACE_SELECT_REG,
+ YTPHY_RSSR_SPACE_MASK,
+ YTPHY_RSSR_UTP_SPACE);
+ if (ret)
+ return ret;
+
+ ret = genphy_update_link(phydev);
+ if (ret)
+ return ret;
+
+ ret = phy_read(phydev, MDIO_DEVAD_NONE,
+ YTPHY_SPECIFIC_STATUS_REG);
+ if (ret < 0)
+ return ret;
+
+ val = ret;
+
+ if (phydev->link)
+ yt8821_parse_status(phydev, val);
+
+ return 0;
+}
+
U_BOOT_PHY_DRIVER(motorcomm8511) = {
.name = "YT8511 Gigabit Ethernet",
.uid = PHY_ID_YT8511,
@@ -652,3 +1134,14 @@ U_BOOT_PHY_DRIVER(motorcomm8531) = {
.startup = &yt8531_startup,
.shutdown = &genphy_shutdown,
};
+
+U_BOOT_PHY_DRIVER(motorcomm8821) = {
+ .name = "YT8821 2.5G Ethernet",
+ .uid = PHY_ID_YT8821,
+ .mask = PHY_ID_MASK,
+ .mmds = (MDIO_MMD_PMAPMD | MDIO_MMD_PCS | MDIO_MMD_AN),
+ .probe = &yt8821_probe,
+ .config = &yt8821_config,
+ .startup = &yt8821_startup,
+ .shutdown = &genphy_shutdown,
+};
diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c
index 2e0afad089f..5f4b1e2d3a0 100644
--- a/drivers/net/rtl8139.c
+++ b/drivers/net/rtl8139.c
@@ -433,7 +433,7 @@ static int rtl8139_recv_common(struct rtl8139_priv *priv, unsigned char *rxdata,
int length = 0;
if (inb(priv->ioaddr + RTL_REG_CHIPCMD) & RTL_REG_CHIPCMD_RXBUFEMPTY)
- return 0;
+ return -EAGAIN;
priv->rxstatus = inw(priv->ioaddr + RTL_REG_INTRSTATUS);
/* See below for the rest of the interrupt acknowledges. */
diff --git a/drivers/net/sandbox-lwip.c b/drivers/net/sandbox-lwip.c
new file mode 100644
index 00000000000..3721033c310
--- /dev/null
+++ b/drivers/net/sandbox-lwip.c
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2015 National Instruments
+ *
+ * (C) Copyright 2015
+ * Joe Hershberger <joe.hershberger@ni.com>
+ */
+
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/eth.h>
+#include <asm/global_data.h>
+#include <asm/test.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static int sb_lwip_eth_start(struct udevice *dev)
+{
+ debug("eth_sandbox_lwip: Start\n");
+
+ return 0;
+}
+
+static int sb_lwip_eth_send(struct udevice *dev, void *packet, int length)
+{
+ debug("eth_sandbox_lwip: Send packet %d\n", length);
+
+ return -ENOTSUPP;
+}
+
+static int sb_lwip_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+ return -EAGAIN;
+}
+
+static int sb_lwip_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
+{
+ return 0;
+}
+
+static void sb_lwip_eth_stop(struct udevice *dev)
+{
+}
+
+static int sb_lwip_eth_write_hwaddr(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct eth_ops sb_eth_ops = {
+ .start = sb_lwip_eth_start,
+ .send = sb_lwip_eth_send,
+ .recv = sb_lwip_eth_recv,
+ .free_pkt = sb_lwip_eth_free_pkt,
+ .stop = sb_lwip_eth_stop,
+ .write_hwaddr = sb_lwip_eth_write_hwaddr,
+};
+
+static int sb_lwip_eth_remove(struct udevice *dev)
+{
+ return 0;
+}
+
+static int sb_lwip_eth_of_to_plat(struct udevice *dev)
+{
+ return 0;
+}
+
+static const struct udevice_id sb_eth_ids[] = {
+ { .compatible = "sandbox,eth" },
+ { }
+};
+
+U_BOOT_DRIVER(eth_sandbox) = {
+ .name = "eth_lwip_sandbox",
+ .id = UCLASS_ETH,
+ .of_match = sb_eth_ids,
+ .of_to_plat = sb_lwip_eth_of_to_plat,
+ .remove = sb_lwip_eth_remove,
+ .ops = &sb_eth_ops,
+ .priv_auto = 0,
+ .plat_auto = sizeof(struct eth_pdata),
+};
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index fe7d1084450..461805ae53f 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -228,7 +228,6 @@ struct zynq_gem_priv {
struct clk tx_clk;
struct clk pclk;
u32 max_speed;
- bool int_pcs;
bool dma_64bit;
u32 clk_en_info;
struct reset_ctl_bulk resets;
@@ -504,8 +503,7 @@ static int zynq_gem_init(struct udevice *dev)
* Set SGMII enable PCS selection only if internal PCS/PMA
* core is used and interface is SGMII.
*/
- if (priv->interface == PHY_INTERFACE_MODE_SGMII &&
- priv->int_pcs) {
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII) {
nwconfig |= ZYNQ_GEM_NWCFG_SGMII_ENBL |
ZYNQ_GEM_NWCFG_PCS_SEL;
}
@@ -529,8 +527,7 @@ static int zynq_gem_init(struct udevice *dev)
writel(nwcfg, &regs->nwcfg);
#ifdef CONFIG_ARM64
- if (priv->interface == PHY_INTERFACE_MODE_SGMII &&
- priv->int_pcs) {
+ if (priv->interface == PHY_INTERFACE_MODE_SGMII) {
/*
* Disable AN for fixed link configuration, enable otherwise.
* Must be written after PCS_SEL is set in nwconfig,
@@ -992,8 +989,6 @@ static int zynq_gem_of_to_plat(struct udevice *dev)
return -EINVAL;
priv->interface = pdata->phy_interface;
- priv->int_pcs = dev_read_bool(dev, "is-internal-pcspma");
-
priv->clk_en_info = dev_get_driver_data(dev);
return 0;