summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/fm/Makefile2
-rw-r--r--drivers/net/fm/b4860.c64
-rw-r--r--drivers/net/fm/eth.c23
-rw-r--r--drivers/net/fm/init.c19
-rw-r--r--drivers/net/fm/memac.c12
-rw-r--r--drivers/net/fm/memac_phy.c7
-rw-r--r--drivers/net/fm/t1024.c88
-rw-r--r--drivers/net/fm/t1040.c4
-rw-r--r--drivers/net/keystone_net.c7
-rw-r--r--drivers/net/macb.c17
-rw-r--r--drivers/net/mpc5xxx_fec.c5
-rw-r--r--drivers/net/netconsole.c2
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/cortina.c333
-rw-r--r--drivers/net/phy/marvell.c53
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/phy/vitesse.c13
-rw-r--r--drivers/net/rtl8169.c127
-rw-r--r--drivers/net/sh_eth.c102
-rw-r--r--drivers/net/sh_eth.h14
-rw-r--r--drivers/net/smc911x.c1
-rw-r--r--drivers/net/uli526x.c2
22 files changed, 776 insertions, 123 deletions
diff --git a/drivers/net/fm/Makefile b/drivers/net/fm/Makefile
index 5ae3b167a9..d052fcb372 100644
--- a/drivers/net/fm/Makefile
+++ b/drivers/net/fm/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_PPC_T1040) += t1040.o
obj-$(CONFIG_PPC_T1042) += t1040.o
obj-$(CONFIG_PPC_T1020) += t1040.o
obj-$(CONFIG_PPC_T1022) += t1040.o
+obj-$(CONFIG_PPC_T1023) += t1024.o
+obj-$(CONFIG_PPC_T1024) += t1024.o
obj-$(CONFIG_PPC_T2080) += t2080.o
obj-$(CONFIG_PPC_T2081) += t2080.o
obj-$(CONFIG_PPC_T4240) += t4240.o
diff --git a/drivers/net/fm/b4860.c b/drivers/net/fm/b4860.c
index 373cc4f424..eb058c9c3d 100644
--- a/drivers/net/fm/b4860.c
+++ b/drivers/net/fm/b4860.c
@@ -10,6 +10,7 @@
#include <asm/io.h>
#include <asm/immap_85xx.h>
#include <asm/fsl_serdes.h>
+#include <hwconfig.h>
u32 port_to_devdisr[] = {
[FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
@@ -46,15 +47,76 @@ void fman_enable_port(enum fm_port port)
phy_interface_t fman_port_enet_if(enum fm_port port)
{
+#if defined(CONFIG_B4860QDS)
+ u32 serdes2_prtcl;
+ char buffer[HWCONFIG_BUFFER_SIZE];
+ char *buf = NULL;
+ ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+
if (is_device_disabled(port))
return PHY_INTERFACE_MODE_NONE;
/*B4860 has two 10Gig Mac*/
if ((port == FM1_10GEC1 || port == FM1_10GEC2) &&
((is_serdes_configured(XAUI_FM1_MAC9)) ||
- (is_serdes_configured(XAUI_FM1_MAC10))))
+ #if !defined(CONFIG_B4860QDS)
+ (is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10)) ||
+ #endif
+ (is_serdes_configured(XAUI_FM1_MAC10))
+ ))
return PHY_INTERFACE_MODE_XGMII;
+#if defined(CONFIG_B4860QDS)
+ serdes2_prtcl = in_be32(&gur->rcwsr[4]) &
+ FSL_CORENET2_RCWSR4_SRDS2_PRTCL;
+
+ if (serdes2_prtcl) {
+ serdes2_prtcl >>= FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT;
+ switch (serdes2_prtcl) {
+ case 0x80:
+ case 0x81:
+ case 0x82:
+ case 0x83:
+ case 0x84:
+ case 0x85:
+ case 0x86:
+ case 0x87:
+ case 0x88:
+ case 0x89:
+ case 0x8a:
+ case 0x8b:
+ case 0x8c:
+ case 0x8d:
+ case 0x8e:
+ case 0xb1:
+ case 0xb2:
+ /*
+ * Extract hwconfig from environment since environment
+ * is not setup yet
+ */
+ getenv_f("hwconfig", buffer, sizeof(buffer));
+ buf = buffer;
+
+ /* check if XFI interface enable in hwconfig for 10g */
+ if (hwconfig_subarg_cmp_f("fsl_b4860_serdes2",
+ "sfp_amc", "sfp", buf)) {
+ if ((port == FM1_10GEC1 ||
+ port == FM1_10GEC2) &&
+ ((is_serdes_configured(XFI_FM1_MAC9)) ||
+ (is_serdes_configured(XFI_FM1_MAC10))))
+ return PHY_INTERFACE_MODE_XGMII;
+ else if ((port == FM1_DTSEC1) ||
+ (port == FM1_DTSEC2) ||
+ (port == FM1_DTSEC3) ||
+ (port == FM1_DTSEC4))
+ return PHY_INTERFACE_MODE_NONE;
+ }
+ }
+ }
+#endif
+
/* Fix me need to handle RGMII here first */
switch (port) {
diff --git a/drivers/net/fm/eth.c b/drivers/net/fm/eth.c
index 218a5ed175..f1e39b982a 100644
--- a/drivers/net/fm/eth.c
+++ b/drivers/net/fm/eth.c
@@ -39,9 +39,14 @@ static void dtsec_configure_serdes(struct fm_eth *priv)
u32 value;
struct mii_dev bus;
bus.priv = priv->mac->phyregs;
+ bool sgmii_2500 = (priv->enet_if ==
+ PHY_INTERFACE_MODE_SGMII_2500) ? true : false;
+
+ /* SGMII IF mode + AN enable only for 1G SGMII, not for 2.5G */
+ value = PHY_SGMII_IF_MODE_SGMII;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_IF_MODE_AN;
- /* SGMII IF mode + AN enable */
- value = PHY_SGMII_IF_MODE_AN | PHY_SGMII_IF_MODE_SGMII;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x14, value);
/* Dev ability according to SGMII specification */
@@ -54,7 +59,9 @@ static void dtsec_configure_serdes(struct fm_eth *priv)
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0x12, 0xd40);
/* Restart AN */
- value = PHY_SGMII_CR_DEF_VAL | PHY_SGMII_CR_RESET_AN;
+ value = PHY_SGMII_CR_DEF_VAL;
+ if (!sgmii_2500)
+ value |= PHY_SGMII_CR_RESET_AN;
memac_mdio_write(&bus, 0, MDIO_DEVAD_NONE, 0, value);
#else
struct dtsec *regs = priv->mac->base;
@@ -83,7 +90,8 @@ static void dtsec_init_phy(struct eth_device *dev)
out_be32(&regs->tbipa, CONFIG_SYS_TBIPA_VALUE);
#endif
- if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII)
+ if (fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII ||
+ fm_eth->enet_if == PHY_INTERFACE_MODE_SGMII_2500)
dtsec_configure_serdes(fm_eth);
}
@@ -557,9 +565,11 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
num = fm_eth->num;
#ifdef CONFIG_SYS_FMAN_V3
+#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
if (fm_eth->type == FM_ETH_10G_E) {
- /* 10GEC1/10GEC2 use mEMAC9/mEMAC10
- * 10GEC3/10GEC4 use mEMAC1/mEMAC2
+ /* 10GEC1/10GEC2 use mEMAC9/mEMAC10 on T2080/T4240.
+ * 10GEC3/10GEC4 use mEMAC1/mEMAC2 on T2080.
+ * 10GEC1 uses mEMAC1 on T1024.
* so it needs to change the num.
*/
if (fm_eth->num >= 2)
@@ -567,6 +577,7 @@ static int fm_eth_init_mac(struct fm_eth *fm_eth, struct ccsr_fman *reg)
else
num += 8;
}
+#endif
base = &reg->memac[num].fm_memac;
phyregs = &reg->memac[num].fm_memac_mdio;
#else
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index 6cf21c6f65..9a8a007861 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -247,10 +247,12 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
}
#ifdef CONFIG_SYS_FMAN_V3
+#ifndef CONFIG_FSL_FM_10GEC_REGULAR_NOTATION
/*
- * Physically FM1_DTSEC9 and FM1_10GEC1 use the same dual-role MAC, when
- * FM1_10GEC1 is enabled and FM1_DTSEC9 is disabled, ensure that the
- * dual-role MAC is not disabled, ditto for other dual-role MACs.
+ * On T2/T4 SoCs, physically FM1_DTSEC9 and FM1_10GEC1 use the same
+ * dual-role MAC, when FM1_10GEC1 is enabled and FM1_DTSEC9
+ * is disabled, ensure that the dual-role MAC is not disabled,
+ * ditto for other dual-role MACs.
*/
if (((info->port == FM1_DTSEC9) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
((info->port == FM1_DTSEC10) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
@@ -267,6 +269,17 @@ static void ft_fixup_port(void *blob, struct fm_eth_info *info, char *prop)
((info->port == FM2_10GEC1) && (PORT_IS_ENABLED(FM2_DTSEC9))) ||
((info->port == FM2_10GEC2) && (PORT_IS_ENABLED(FM2_DTSEC10)))
#endif
+#else
+ /* FM1_DTSECx and FM1_10GECx use the same dual-role MAC */
+ if (((info->port == FM1_DTSEC1) && (PORT_IS_ENABLED(FM1_10GEC1))) ||
+ ((info->port == FM1_DTSEC2) && (PORT_IS_ENABLED(FM1_10GEC2))) ||
+ ((info->port == FM1_DTSEC3) && (PORT_IS_ENABLED(FM1_10GEC3))) ||
+ ((info->port == FM1_DTSEC4) && (PORT_IS_ENABLED(FM1_10GEC4))) ||
+ ((info->port == FM1_10GEC1) && (PORT_IS_ENABLED(FM1_DTSEC1))) ||
+ ((info->port == FM1_10GEC2) && (PORT_IS_ENABLED(FM1_DTSEC2))) ||
+ ((info->port == FM1_10GEC3) && (PORT_IS_ENABLED(FM1_DTSEC3))) ||
+ ((info->port == FM1_10GEC4) && (PORT_IS_ENABLED(FM1_DTSEC4)))
+#endif
)
return;
#endif
diff --git a/drivers/net/fm/memac.c b/drivers/net/fm/memac.c
index 9499290bba..60e898cd7c 100644
--- a/drivers/net/fm/memac.c
+++ b/drivers/net/fm/memac.c
@@ -37,7 +37,8 @@ static void memac_enable_mac(struct fsl_enet_mac *mac)
{
struct memac *regs = mac->base;
- setbits_be32(&regs->command_config, MEMAC_CMD_CFG_RXTX_EN);
+ setbits_be32(&regs->command_config,
+ MEMAC_CMD_CFG_RXTX_EN | MEMAC_CMD_CFG_NO_LEN_CHK);
}
static void memac_disable_mac(struct fsl_enet_mac *mac)
@@ -93,11 +94,16 @@ static void memac_set_interface_mode(struct fsl_enet_mac *mac,
if_mode &= ~IF_MODE_MASK;
if_mode |= (IF_MODE_GMII);
break;
+ case PHY_INTERFACE_MODE_XGMII:
+ if_mode &= ~IF_MODE_MASK;
+ if_mode |= IF_MODE_XGMII;
+ break;
default:
break;
}
- /* Enable automatic speed selection */
- if_mode |= IF_MODE_EN_AUTO;
+ /* Enable automatic speed selection for Non-XGMII */
+ if (type != PHY_INTERFACE_MODE_XGMII)
+ if_mode |= IF_MODE_EN_AUTO;
if (type == PHY_INTERFACE_MODE_RGMII) {
if_mode &= ~IF_MODE_EN_AUTO;
diff --git a/drivers/net/fm/memac_phy.c b/drivers/net/fm/memac_phy.c
index 5f910c2cdd..a155d8930b 100644
--- a/drivers/net/fm/memac_phy.c
+++ b/drivers/net/fm/memac_phy.c
@@ -71,6 +71,8 @@ int memac_mdio_read(struct mii_dev *bus, int port_addr, int dev_addr,
u32 c45 = 1;
if (dev_addr == MDIO_DEVAD_NONE) {
+ if (!strcmp(bus->name, DEFAULT_FM_TGEC_MDIO_NAME))
+ return 0xffff;
c45 = 0; /* clause 22 */
dev_addr = regnum & 0x1f;
clrbits_be32(&regs->mdio_stat, MDIO_STAT_ENC);
@@ -137,9 +139,12 @@ int fm_memac_mdio_init(bd_t *bis, struct memac_mdio_info *info)
* is zero, so MDIO clock is disabled.
* So, for proper functioning of MDIO, MDIO_CLK_DIV bits needs to
* be properly initialized.
+ * NEG bit default should be '1' as per FMAN-v3 RM, but on platform
+ * like T2080QDS, this bit default is '0', which leads to MDIO failure
+ * on XAUI PHY, so set this bit definitely.
*/
setbits_be32(&((struct memac_mdio_controller *)info->regs)->mdio_stat,
- MDIO_STAT_CLKDIV(258));
+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG);
return mdio_register(bus);
}
diff --git a/drivers/net/fm/t1024.c b/drivers/net/fm/t1024.c
new file mode 100644
index 0000000000..9b3117341e
--- /dev/null
+++ b/drivers/net/fm/t1024.c
@@ -0,0 +1,88 @@
+/* Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * Shengzhou Liu <Shengzhou.Liu@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <phy.h>
+#include <fm_eth.h>
+#include <asm/immap_85xx.h>
+#include <asm/fsl_serdes.h>
+
+u32 port_to_devdisr[] = {
+ [FM1_DTSEC1] = FSL_CORENET_DEVDISR2_DTSEC1_1,
+ [FM1_DTSEC2] = FSL_CORENET_DEVDISR2_DTSEC1_2,
+ [FM1_DTSEC3] = FSL_CORENET_DEVDISR2_DTSEC1_3,
+ [FM1_DTSEC4] = FSL_CORENET_DEVDISR2_DTSEC1_4,
+ [FM1_10GEC1] = FSL_CORENET_DEVDISR2_10GEC1_1, /* MAC1 */
+};
+
+static int is_device_disabled(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 devdisr2 = in_be32(&gur->devdisr2);
+
+ return port_to_devdisr[port] & devdisr2;
+}
+
+void fman_disable_port(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+
+ setbits_be32(&gur->devdisr2, port_to_devdisr[port]);
+}
+
+phy_interface_t fman_port_enet_if(enum fm_port port)
+{
+ ccsr_gur_t *gur = (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+ u32 rcwsr13 = in_be32(&gur->rcwsr[13]);
+
+ if (is_device_disabled(port))
+ return PHY_INTERFACE_MODE_NONE;
+
+ if ((port == FM1_10GEC1) && (is_serdes_configured(XFI_FM1_MAC1)))
+ return PHY_INTERFACE_MODE_XGMII;
+
+ if ((port == FM1_DTSEC3) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC2) ==
+ FSL_CORENET_RCWSR13_EC2_RGMII) &&
+ (!is_serdes_configured(QSGMII_FM1_A)))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ if ((port == FM1_DTSEC4) && ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
+ FSL_CORENET_RCWSR13_EC1_RGMII) &&
+ (!is_serdes_configured(QSGMII_FM1_A)))
+ return PHY_INTERFACE_MODE_RGMII;
+
+ /* handle SGMII */
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ if (is_serdes_configured(SGMII_FM1_DTSEC1 + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII;
+ else if (is_serdes_configured(SGMII_2500_FM1_DTSEC1
+ + port - FM1_DTSEC1))
+ return PHY_INTERFACE_MODE_SGMII_2500;
+ break;
+ default:
+ break;
+ }
+
+ /* handle QSGMII */
+ switch (port) {
+ case FM1_DTSEC1:
+ case FM1_DTSEC2:
+ case FM1_DTSEC3:
+ case FM1_DTSEC4:
+ /* check lane A on SerDes1 */
+ if (is_serdes_configured(QSGMII_FM1_A))
+ return PHY_INTERFACE_MODE_QSGMII;
+ break;
+ default:
+ break;
+ }
+
+ return PHY_INTERFACE_MODE_NONE;
+}
diff --git a/drivers/net/fm/t1040.c b/drivers/net/fm/t1040.c
index 4cce46d7f8..d2a097e0e5 100644
--- a/drivers/net/fm/t1040.c
+++ b/drivers/net/fm/t1040.c
@@ -25,8 +25,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
return PHY_INTERFACE_MODE_MII;
- else
- return PHY_INTERFACE_MODE_NONE;
}
if ((port == FM1_DTSEC4) &&
@@ -38,8 +36,6 @@ phy_interface_t fman_port_enet_if(enum fm_port port)
else if ((rcwsr13 & FSL_CORENET_RCWSR13_EC1) ==
FSL_CORENET_RCWSR13_EC1_FM1_DTSEC4_MII)
return PHY_INTERFACE_MODE_MII;
- else
- return PHY_INTERFACE_MODE_NONE;
}
if (port == FM1_DTSEC5) {
diff --git a/drivers/net/keystone_net.c b/drivers/net/keystone_net.c
index c8681d0223..bedab1d606 100644
--- a/drivers/net/keystone_net.c
+++ b/drivers/net/keystone_net.c
@@ -315,7 +315,7 @@ int mac_sl_config(u_int16_t port, struct mac_sl_cfg *cfg)
writel(cfg->max_rx_len, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_MAXLEN);
writel(cfg->ctl, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_CTL);
-#ifdef CONFIG_K2E_EVM
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
/* Map RX packet flow priority to 0 */
writel(0, DEVICE_EMACSL_BASE(port) + CPGMACSL_REG_RX_PRI_MAP);
#endif
@@ -400,6 +400,9 @@ static int keystone2_eth_open(struct eth_device *dev, bd_t *bis)
keystone2_net_serdes_setup();
+ if (sys_has_mdio)
+ keystone2_mdio_reset(mdio_bus);
+
keystone_sgmii_config(phy_dev, eth_priv->slave_port - 1,
eth_priv->sgmii_link_type);
@@ -582,7 +585,7 @@ static void keystone2_net_serdes_setup(void)
&ks2_serdes_sgmii_156p25mhz,
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
-#ifdef CONFIG_SOC_K2E
+#if defined(CONFIG_SOC_K2E) || defined(CONFIG_SOC_K2L)
ks2_serdes_init(CONFIG_KSNET_SERDES_SGMII2_BASE,
&ks2_serdes_sgmii_156p25mhz,
CONFIG_KSNET_SERDES_LANES_PER_SGMII);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 375c8a4454..9c2ff487a7 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -525,6 +525,7 @@ static int macb_phy_init(struct macb_device *macb)
return 1;
}
+static int macb_write_hwaddr(struct eth_device *dev);
static int macb_init(struct eth_device *netdev, bd_t *bd)
{
struct macb_device *macb = to_macb(netdev);
@@ -565,7 +566,13 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
macb_writel(macb, TBQP, macb->tx_ring_dma);
if (macb_is_gem(macb)) {
-#ifdef CONFIG_RGMII
+ /*
+ * When the GMAC IP with GE feature, this bit is used to
+ * select interface between RGMII and GMII.
+ * When the GMAC IP without GE feature, this bit is used
+ * to select interface between RMII and MII.
+ */
+#if defined(CONFIG_RGMII) || defined(CONFIG_RMII)
gem_writel(macb, UR, GEM_BIT(RGMII));
#else
gem_writel(macb, UR, 0);
@@ -587,6 +594,14 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
#endif /* CONFIG_RMII */
}
+ /* update the ethaddr */
+ if (is_valid_ether_addr(netdev->enetaddr)) {
+ macb_write_hwaddr(netdev);
+ } else {
+ printf("%s: mac address is not valid\n", netdev->name);
+ return -1;
+ }
+
if (!macb_phy_init(macb))
return -1;
diff --git a/drivers/net/mpc5xxx_fec.c b/drivers/net/mpc5xxx_fec.c
index 1093ba59da..d9d6f4f28b 100644
--- a/drivers/net/mpc5xxx_fec.c
+++ b/drivers/net/mpc5xxx_fec.c
@@ -476,11 +476,6 @@ static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis)
miiphy_write(dev->name, phyAddr, 0x0, 0x8000);
udelay(1000);
-#if defined(CONFIG_UC101) || defined(CONFIG_MUCMC52)
- /* Set the LED configuration Register for the UC101
- and MUCMC52 Board */
- miiphy_write(dev->name, phyAddr, 0x14, 0x4122);
-#endif
if (fec->xcv_type == MII10) {
/*
* Force 10Base-T, FDX operation
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 623f7492c7..677c89f048 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -256,7 +256,7 @@ static void nc_puts(struct stdio_dev *dev, const char *s)
len = strlen(s);
while (len) {
- int send_len = min(len, sizeof(input_buffer));
+ int send_len = min(len, (int)sizeof(input_buffer));
nc_send_packet(s, send_len);
len -= send_len;
s += send_len;
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 9556536b77..f46bf00abe 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_PHYLIB) += phy.o
obj-$(CONFIG_PHYLIB_10G) += generic_10g.o
obj-$(CONFIG_PHY_ATHEROS) += atheros.o
obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
+obj-$(CONFIG_PHY_CORTINA) += cortina.o
obj-$(CONFIG_PHY_DAVICOM) += davicom.o
obj-$(CONFIG_PHY_ET1011C) += et1011c.o
obj-$(CONFIG_PHY_LXT) += lxt.o
diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c
new file mode 100644
index 0000000000..254f056df4
--- /dev/null
+++ b/drivers/net/phy/cortina.c
@@ -0,0 +1,333 @@
+/*
+ * Cortina CS4315/CS4340 10G PHY drivers
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ *
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <malloc.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <phy.h>
+#include <cortina.h>
+#ifdef CONFIG_SYS_CORTINA_FW_IN_NAND
+#include <nand.h>
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
+#include <spi_flash.h>
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
+#include <mmc.h>
+#endif
+
+#ifndef CONFIG_PHYLIB_10G
+#error The Cortina PHY needs 10G support
+#endif
+
+struct cortina_reg_config cortina_reg_cfg[] = {
+ /* CS4315_enable_sr_mode */
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
+ {VILLA_MSEQ_OPTIONS, 0xf},
+ {VILLA_MSEQ_PC, 0x0},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_CPA, 0x55},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_LOOP_FILTER, 0x30},
+ {VILLA_DSP_SDS_SERDES_SRX_DFE0_SELECT, 0x1},
+ {VILLA_DSP_SDS_DSP_COEF_DFE0_SELECT, 0x2},
+ {VILLA_LINE_SDS_COMMON_SRX0_RX_CPB, 0x2003},
+ {VILLA_DSP_SDS_SERDES_SRX_FFE_DELAY_CTRL, 0xF047},
+ {VILLA_MSEQ_ENABLE_MSB, 0x0000},
+ {VILLA_MSEQ_SPARE21_LSB, 0x6},
+ {VILLA_MSEQ_RESET_COUNT_LSB, 0x0},
+ {VILLA_MSEQ_SPARE12_MSB, 0x0000},
+ /*
+ * to invert the receiver path, uncomment the next line
+ * write (VILLA_MSEQ_SPARE12_MSB, 0x4000)
+ *
+ * SPARE2_LSB is used to configure the device while in sr mode to
+ * enable power savings and to use the optical module LOS signal.
+ * in power savings mode, the internal prbs checker can not be used.
+ * if the optical module LOS signal is used as an input to the micro
+ * code, then the micro code will wait until the optical module
+ * LOS = 0 before turning on the adaptive equalizer.
+ * Setting SPARE2_LSB bit 0 to 1 places the devie in power savings mode
+ * while setting bit 0 to 0 disables power savings mode.
+ * Setting SPARE2_LSB bit 2 to 0 configures the device to use the
+ * optical module LOS signal while setting bit 2 to 1 configures the
+ * device so that it will ignore the optical module LOS SPARE2_LSB = 0
+ */
+
+ /* enable power savings, ignore optical module LOS */
+ {VILLA_MSEQ_SPARE2_LSB, 0x5},
+
+ {VILLA_MSEQ_SPARE7_LSB, 0x1e},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_MSEQ_SPARE9_LSB, 0x2},
+ {VILLA_MSEQ_SPARE3_LSB, 0x0F53},
+ {VILLA_MSEQ_SPARE3_MSB, 0x2006},
+ {VILLA_MSEQ_SPARE8_LSB, 0x3FF7},
+ {VILLA_MSEQ_SPARE8_MSB, 0x0A46},
+ {VILLA_MSEQ_COEF8_FFE0_LSB, 0xD500},
+ {VILLA_MSEQ_COEF8_FFE1_LSB, 0x0200},
+ {VILLA_MSEQ_COEF8_FFE2_LSB, 0xBA00},
+ {VILLA_MSEQ_COEF8_FFE3_LSB, 0x0100},
+ {VILLA_MSEQ_COEF8_FFE4_LSB, 0x0300},
+ {VILLA_MSEQ_COEF8_FFE5_LSB, 0x0300},
+ {VILLA_MSEQ_COEF8_DFE0_LSB, 0x0700},
+ {VILLA_MSEQ_COEF8_DFE0N_LSB, 0x0E00},
+ {VILLA_MSEQ_COEF8_DFE1_LSB, 0x0B00},
+ {VILLA_DSP_SDS_DSP_COEF_LARGE_LEAK, 0x2},
+ {VILLA_DSP_SDS_SERDES_SRX_DAC_ENABLEB_LSB, 0xD000},
+ {VILLA_MSEQ_POWER_DOWN_LSB, 0xFFFF},
+ {VILLA_MSEQ_POWER_DOWN_MSB, 0x0},
+ {VILLA_MSEQ_CAL_RX_SLICER, 0x80},
+ {VILLA_DSP_SDS_SERDES_SRX_DAC_BIAS_SELECT1_MSB, 0x3f},
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
+ {VILLA_MSEQ_OPTIONS, 0x7},
+
+ /* set up min value for ffe1 */
+ {VILLA_MSEQ_COEF_INIT_SEL, 0x2},
+ {VILLA_DSP_SDS_DSP_PRECODEDINITFFE21, 0x41},
+
+ /* CS4315_sr_rx_pre_eq_set_4in */
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x8004},
+ {VILLA_MSEQ_OPTIONS, 0xf},
+ {VILLA_MSEQ_BANKSELECT, 0x4},
+ {VILLA_MSEQ_PC, 0x0},
+
+ /* for lengths from 3.5 to 4.5inches */
+ {VILLA_MSEQ_SERDES_PARAM_LSB, 0x0306},
+ {VILLA_MSEQ_SPARE25_LSB, 0x0306},
+ {VILLA_MSEQ_SPARE21_LSB, 0x2},
+ {VILLA_MSEQ_SPARE23_LSB, 0x2},
+ {VILLA_MSEQ_CAL_RX_DFE_EQ, 0x0},
+
+ {VILLA_GLOBAL_MSEQCLKCTRL, 0x4},
+ {VILLA_MSEQ_OPTIONS, 0x7},
+
+ /* CS4315_rx_drive_4inch */
+ /* for length 4inches */
+ {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
+ {VILLA_HOST_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
+
+ /* CS4315_tx_drive_4inch */
+ /* for length 4inches */
+ {VILLA_GLOBAL_VILLA2_COMPATIBLE, 0x0000},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLA, 0x3023},
+ {VILLA_LINE_SDS_COMMON_STX0_TX_OUTPUT_CTRLB, 0xc01E},
+};
+
+void cs4340_upload_firmware(struct phy_device *phydev)
+{
+ char line_temp[0x50] = {0};
+ char reg_addr[0x50] = {0};
+ char reg_data[0x50] = {0};
+ int i, line_cnt = 0, column_cnt = 0;
+ struct cortina_reg_config fw_temp;
+ char *addr = NULL;
+
+#if defined(CONFIG_SYS_CORTINA_FW_IN_NOR) || \
+ defined(CONFIG_SYS_CORTINA_FW_IN_REMOTE)
+
+ addr = (char *)CONFIG_CORTINA_FW_ADDR;
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_NAND)
+ int ret;
+ size_t fw_length = CONFIG_CORTINA_FW_LENGTH;
+
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ ret = nand_read(&nand_info[0], (loff_t)CONFIG_CORTINA_FW_ADDR,
+ &fw_length, (u_char *)addr);
+ if (ret == -EUCLEAN) {
+ printf("NAND read of Cortina firmware at 0x%x failed %d\n",
+ CONFIG_CORTINA_FW_ADDR, ret);
+ }
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_SPIFLASH)
+ int ret;
+ struct spi_flash *ucode_flash;
+
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
+ CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
+ if (!ucode_flash) {
+ puts("SF: probe for Cortina ucode failed\n");
+ } else {
+ ret = spi_flash_read(ucode_flash, CONFIG_CORTINA_FW_ADDR,
+ CONFIG_CORTINA_FW_LENGTH, addr);
+ if (ret)
+ puts("SF: read for Cortina ucode failed\n");
+ spi_flash_free(ucode_flash);
+ }
+#elif defined(CONFIG_SYS_CORTINA_FW_IN_MMC)
+ int dev = CONFIG_SYS_MMC_ENV_DEV;
+ u32 cnt = CONFIG_CORTINA_FW_LENGTH / 512;
+ u32 blk = CONFIG_CORTINA_FW_ADDR / 512;
+ struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
+
+ if (!mmc) {
+ puts("Failed to find MMC device for Cortina ucode\n");
+ } else {
+ addr = malloc(CONFIG_CORTINA_FW_LENGTH);
+ printf("MMC read: dev # %u, block # %u, count %u ...\n",
+ dev, blk, cnt);
+ mmc_init(mmc);
+ (void)mmc->block_dev.block_read(dev, blk, cnt, addr);
+ /* flush cache after read */
+ flush_cache((ulong)addr, cnt * 512);
+ }
+#endif
+
+ while (*addr != 'Q') {
+ i = 0;
+
+ while (*addr != 0x0a) {
+ line_temp[i++] = *addr++;
+ if (0x50 < i) {
+ printf("Not found Cortina PHY ucode at 0x%x\n",
+ CONFIG_CORTINA_FW_ADDR);
+ return;
+ }
+ }
+
+ addr++; /* skip '\n' */
+ line_cnt++;
+ column_cnt = i;
+ line_temp[column_cnt] = '\0';
+
+ if (CONFIG_CORTINA_FW_LENGTH < line_cnt)
+ return;
+
+ for (i = 0; i < column_cnt; i++) {
+ if (isspace(line_temp[i++]))
+ break;
+ }
+
+ memcpy(reg_addr, line_temp, i);
+ memcpy(reg_data, &line_temp[i], column_cnt - i);
+ strim(reg_addr);
+ strim(reg_data);
+ fw_temp.reg_addr = (simple_strtoul(reg_addr, NULL, 0)) & 0xffff;
+ fw_temp.reg_value = (simple_strtoul(reg_data, NULL, 0)) &
+ 0xffff;
+ phy_write(phydev, 0x00, fw_temp.reg_addr, fw_temp.reg_value);
+ }
+}
+
+int cs4340_phy_init(struct phy_device *phydev)
+{
+ int timeout = 100; /* 100ms */
+ int reg_value;
+
+ /* step1: BIST test */
+ phy_write(phydev, 0x00, VILLA_GLOBAL_MSEQCLKCTRL, 0x0004);
+ phy_write(phydev, 0x00, VILLA_GLOBAL_LINE_SOFT_RESET, 0x0000);
+ phy_write(phydev, 0x00, VILLA_GLOBAL_BIST_CONTROL, 0x0001);
+ while (--timeout) {
+ reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_BIST_STATUS);
+ if (reg_value & mseq_edc_bist_done) {
+ if (0 == (reg_value & mseq_edc_bist_fail))
+ break;
+ }
+ udelay(1000);
+ }
+
+ if (!timeout) {
+ printf("%s BIST mseq_edc_bist_done timeout!\n", __func__);
+ return -1;
+ }
+
+ /* setp2: upload ucode */
+ cs4340_upload_firmware(phydev);
+ reg_value = phy_read(phydev, 0x00, VILLA_GLOBAL_DWNLD_CHECKSUM_STATUS);
+ if (reg_value) {
+ debug("%s checksum status failed.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int cs4340_config(struct phy_device *phydev)
+{
+ cs4340_phy_init(phydev);
+ return 0;
+}
+
+int cs4340_startup(struct phy_device *phydev)
+{
+ phydev->link = 1;
+
+ /* For now just lie and say it's 10G all the time */
+ phydev->speed = SPEED_10000;
+ phydev->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+struct phy_driver cs4340_driver = {
+ .name = "Cortina CS4315/CS4340",
+ .uid = PHY_UID_CS4340,
+ .mask = 0xfffffff0,
+ .features = PHY_10G_FEATURES,
+ .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS |
+ MDIO_DEVS_PHYXS | MDIO_DEVS_AN |
+ MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2),
+ .config = &cs4340_config,
+ .startup = &cs4340_startup,
+ .shutdown = &gen10g_shutdown,
+};
+
+int phy_cortina_init(void)
+{
+ phy_register(&cs4340_driver);
+ return 0;
+}
+
+int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)
+{
+ int phy_reg;
+ bool is_cortina_phy = false;
+
+ switch (addr) {
+#ifdef CORTINA_PHY_ADDR1
+ case CORTINA_PHY_ADDR1:
+#endif
+#ifdef CORTINA_PHY_ADDR2
+ case CORTINA_PHY_ADDR2:
+#endif
+#ifdef CORTINA_PHY_ADDR3
+ case CORTINA_PHY_ADDR3:
+#endif
+#ifdef CORTINA_PHY_ADDR4
+ case CORTINA_PHY_ADDR4:
+#endif
+ is_cortina_phy = true;
+ break;
+ default:
+ break;
+ }
+
+ /* Cortina PHY has non-standard offset of PHY ID registers */
+ if (is_cortina_phy)
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_LSB);
+ else
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID1);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id = (phy_reg & 0xffff) << 16;
+ if (is_cortina_phy)
+ phy_reg = bus->read(bus, addr, 0, VILLA_GLOBAL_CHIP_ID_MSB);
+ else
+ phy_reg = bus->read(bus, addr, devad, MII_PHYSID2);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index d2ecadc890..9437c3bbcc 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -276,6 +276,57 @@ static int m88e1111s_config(struct phy_device *phydev)
return 0;
}
+/**
+ * m88e1518_phy_writebits - write bits to a register
+ */
+void m88e1518_phy_writebits(struct phy_device *phydev,
+ u8 reg_num, u16 offset, u16 len, u16 data)
+{
+ u16 reg, mask;
+
+ if ((len + offset) >= 16)
+ mask = 0 - (1 << offset);
+ else
+ mask = (1 << (len + offset)) - (1 << offset);
+
+ reg = phy_read(phydev, MDIO_DEVAD_NONE, reg_num);
+
+ reg &= ~mask;
+ reg |= data << offset;
+
+ phy_write(phydev, MDIO_DEVAD_NONE, reg_num, reg);
+}
+
+static int m88e1518_config(struct phy_device *phydev)
+{
+ /*
+ * As per Marvell Release Notes - Alaska 88E1510/88E1518/88E1512
+ * /88E1514 Rev A0, Errata Section 3.1
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x00ff); /* page 0xff */
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x214B);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2144);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0x0C28);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2146);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xB233);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x214D);
+ phy_write(phydev, MDIO_DEVAD_NONE, 17, 0xCC0C);
+ phy_write(phydev, MDIO_DEVAD_NONE, 16, 0x2159);
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0x0000); /* reg page 0 */
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 18); /* reg page 18 */
+ /* Write HWCFG_MODE = SGMII to Copper */
+ m88e1518_phy_writebits(phydev, 20, 0, 3, 1);
+
+ /* Phy reset */
+ m88e1518_phy_writebits(phydev, 20, 15, 1, 1);
+ phy_write(phydev, MDIO_DEVAD_NONE, 22, 0); /* reg page 18 */
+ udelay(100);
+ }
+
+ return m88e1111s_config(phydev);
+}
+
/* Marvell 88E1118 */
static int m88e1118_config(struct phy_device *phydev)
{
@@ -493,7 +544,7 @@ static struct phy_driver M88E1518_driver = {
.uid = 0x1410dd1,
.mask = 0xffffff0,
.features = PHY_GBIT_FEATURES,
- .config = &m88e1111s_config,
+ .config = &m88e1518_config,
.startup = &m88e1011s_startup,
.shutdown = &genphy_shutdown,
};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 467c972243..5b04c85939 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -448,6 +448,9 @@ int phy_init(void)
#ifdef CONFIG_PHY_BROADCOM
phy_broadcom_init();
#endif
+#ifdef CONFIG_PHY_CORTINA
+ phy_cortina_init();
+#endif
#ifdef CONFIG_PHY_DAVICOM
phy_davicom_init();
#endif
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 2b29cd89f8..20a67466a7 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -1,8 +1,8 @@
/*
* Vitesse PHY drivers
*
- * Copyright 2010-2012 Freescale Semiconductor, Inc.
- * Author: Andy Fleming
+ * Copyright 2010-2014 Freescale Semiconductor, Inc.
+ * Original Author: Andy Fleming
* Add vsc8662 phy support - Priyanka Jain
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -50,6 +50,7 @@
#define MIIM_VSC8574_18G_CMDSTAT 0x8000
/* Vitesse VSC8514 control register */
+#define MIIM_VSC8514_MAC_SERDES_CON 0x10
#define MIIM_VSC8514_GENERAL18 0x12
#define MIIM_VSC8514_GENERAL19 0x13
#define MIIM_VSC8514_GENERAL23 0x17
@@ -246,6 +247,14 @@ static int vsc8514_config(struct phy_device *phydev)
val = (val & 0xf8ff);
phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_GENERAL23, val);
+ /* Enable Serdes Auto-negotiation */
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
+ PHY_EXT_PAGE_ACCESS_EXTENDED3);
+ val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
+ val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
+ phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
+ phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0);
+
genphy_config_aneg(phydev);
return 0;
diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c
index c3ce17516c..cea6701203 100644
--- a/drivers/net/rtl8169.c
+++ b/drivers/net/rtl8169.c
@@ -41,6 +41,7 @@
* Modified to use le32_to_cpu and cpu_to_le32 properly
*/
#include <common.h>
+#include <errno.h>
#include <malloc.h>
#include <net.h>
#include <netdev.h>
@@ -79,7 +80,11 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
#define NUM_TX_DESC 1 /* Number of Tx descriptor registers */
-#define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
+#ifdef CONFIG_SYS_RX_ETH_BUFFER
+ #define NUM_RX_DESC CONFIG_SYS_RX_ETH_BUFFER
+#else
+ #define NUM_RX_DESC 4 /* Number of Rx descriptor registers */
+#endif
#define RX_BUF_SIZE 1536 /* Rx Buffer size */
#define RX_BUF_LEN 8192
@@ -248,6 +253,7 @@ static struct {
{"RTL-8168b/8111sb", 0x38, 0xff7e1880,},
{"RTL-8168d/8111d", 0x28, 0xff7e1880,},
{"RTL-8168evl/8111evl", 0x2e, 0xff7e1880,},
+ {"RTL-8168/8111g", 0x4c, 0xff7e1880,},
{"RTL-8101e", 0x34, 0xff7e1880,},
{"RTL-8100e", 0x32, 0xff7e1880,},
};
@@ -273,23 +279,40 @@ struct RxDesc {
u32 buf_Haddr;
};
-/* Define the TX Descriptor */
-static u8 tx_ring[NUM_TX_DESC * sizeof(struct TxDesc) + 256];
-/* __attribute__ ((aligned(256))); */
+#define RTL8169_DESC_SIZE 16
-/* Create a static buffer of size RX_BUF_SZ for each
-TX Descriptor. All descriptors point to a
-part of this buffer */
-static unsigned char txb[NUM_TX_DESC * RX_BUF_SIZE];
+#if ARCH_DMA_MINALIGN > 256
+# define RTL8169_ALIGN ARCH_DMA_MINALIGN
+#else
+# define RTL8169_ALIGN 256
+#endif
-/* Define the RX Descriptor */
-static u8 rx_ring[NUM_RX_DESC * sizeof(struct TxDesc) + 256];
- /* __attribute__ ((aligned(256))); */
+/*
+ * Warn if the cache-line size is larger than the descriptor size. In such
+ * cases the driver will likely fail because the CPU needs to flush the cache
+ * when requeuing RX buffers, therefore descriptors written by the hardware
+ * may be discarded.
+ *
+ * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause
+ * the driver to allocate descriptors from a pool of non-cached memory.
+ */
+#if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN
+#if !defined(CONFIG_SYS_NONCACHED_MEMORY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#warning cache-line size is larger than descriptor size
+#endif
+#endif
-/* Create a static buffer of size RX_BUF_SZ for each
-RX Descriptor All descriptors point to a
-part of this buffer */
-static unsigned char rxb[NUM_RX_DESC * RX_BUF_SIZE];
+/*
+ * Create a static buffer of size RX_BUF_SZ for each TX Descriptor. All
+ * descriptors point to a part of this buffer.
+ */
+DEFINE_ALIGN_BUFFER(u8, txb, NUM_TX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
+
+/*
+ * Create a static buffer of size RX_BUF_SZ for each RX Descriptor. All
+ * descriptors point to a part of this buffer.
+ */
+DEFINE_ALIGN_BUFFER(u8, rxb, NUM_RX_DESC * RX_BUF_SIZE, RTL8169_ALIGN);
struct rtl8169_private {
void *mmio_addr; /* memory map physical address */
@@ -297,8 +320,6 @@ struct rtl8169_private {
unsigned long cur_rx; /* Index into the Rx descriptor buffer of next Rx pkt. */
unsigned long cur_tx; /* Index into the Tx descriptor buffer of next Rx pkt. */
unsigned long dirty_tx;
- unsigned char *TxDescArrays; /* Index of Tx Descriptor buffer */
- unsigned char *RxDescArrays; /* Index of Rx Descriptor buffer */
struct TxDesc *TxDescArray; /* Index of 256-alignment Tx Descriptor buffer */
struct RxDesc *RxDescArray; /* Index of 256-alignment Rx Descriptor buffer */
unsigned char *RxBufferRings; /* Index of Rx Buffer */
@@ -398,34 +419,71 @@ match:
}
/*
+ * TX and RX descriptors are 16 bytes. This causes problems with the cache
+ * maintenance on CPUs where the cache-line size exceeds the size of these
+ * descriptors. What will happen is that when the driver receives a packet
+ * it will be immediately requeued for the hardware to reuse. The CPU will
+ * therefore need to flush the cache-line containing the descriptor, which
+ * will cause all other descriptors in the same cache-line to be flushed
+ * along with it. If one of those descriptors had been written to by the
+ * device those changes (and the associated packet) will be lost.
+ *
+ * To work around this, we make use of non-cached memory if available. If
+ * descriptors are mapped uncached there's no need to manually flush them
+ * or invalidate them.
+ *
+ * Note that this only applies to descriptors. The packet data buffers do
+ * not have the same constraints since they are 1536 bytes large, so they
+ * are unlikely to share cache-lines.
+ */
+static void *rtl_alloc_descs(unsigned int num)
+{
+ size_t size = num * RTL8169_DESC_SIZE;
+
+#ifdef CONFIG_SYS_NONCACHED_MEMORY
+ return (void *)noncached_alloc(size, RTL8169_ALIGN);
+#else
+ return memalign(RTL8169_ALIGN, size);
+#endif
+}
+
+/*
* Cache maintenance functions. These are simple wrappers around the more
* general purpose flush_cache() and invalidate_dcache_range() functions.
*/
static void rtl_inval_rx_desc(struct RxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
invalidate_dcache_range(start, end);
+#endif
}
static void rtl_flush_rx_desc(struct RxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
}
static void rtl_inval_tx_desc(struct TxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN - 1);
unsigned long end = ALIGN(start + sizeof(*desc), ARCH_DMA_MINALIGN);
invalidate_dcache_range(start, end);
+#endif
}
static void rtl_flush_tx_desc(struct TxDesc *desc)
{
+#ifndef CONFIG_SYS_NONCACHED_MEMORY
flush_cache((unsigned long)desc, sizeof(*desc));
+#endif
}
static void rtl_inval_buffer(void *buf, size_t size)
@@ -707,16 +765,6 @@ static int rtl_reset(struct eth_device *dev, bd_t *bis)
printf ("%s\n", __FUNCTION__);
#endif
- tpc->TxDescArrays = tx_ring;
- /* Tx Desscriptor needs 256 bytes alignment; */
- tpc->TxDescArray = (struct TxDesc *) ((unsigned long)(tpc->TxDescArrays +
- 255) & ~255);
-
- tpc->RxDescArrays = rx_ring;
- /* Rx Desscriptor needs 256 bytes alignment; */
- tpc->RxDescArray = (struct RxDesc *) ((unsigned long)(tpc->RxDescArrays +
- 255) & ~255);
-
rtl8169_init_ring(dev);
rtl8169_hw_start(dev);
/* Construct a perfect filter frame with the mac address as first match
@@ -758,10 +806,6 @@ static void rtl_halt(struct eth_device *dev)
RTL_W32(RxMissed, 0);
- tpc->TxDescArrays = NULL;
- tpc->RxDescArrays = NULL;
- tpc->TxDescArray = NULL;
- tpc->RxDescArray = NULL;
for (i = 0; i < NUM_RX_DESC; i++) {
tpc->RxBufferRing[i] = NULL;
}
@@ -906,7 +950,16 @@ static int rtl_init(struct eth_device *dev, bd_t *bis)
#endif
}
- return 1;
+
+ tpc->RxDescArray = rtl_alloc_descs(NUM_RX_DESC);
+ if (!tpc->RxDescArray)
+ return -ENOMEM;
+
+ tpc->TxDescArray = rtl_alloc_descs(NUM_TX_DESC);
+ if (!tpc->TxDescArray)
+ return -ENOMEM;
+
+ return 0;
}
int rtl8169_initialize(bd_t *bis)
@@ -920,6 +973,7 @@ int rtl8169_initialize(bd_t *bis)
while(1){
unsigned int region;
u16 device;
+ int err;
/* Find RTL8169 */
if ((devno = pci_find_devices(supported, idx++)) < 0)
@@ -958,9 +1012,14 @@ int rtl8169_initialize(bd_t *bis)
dev->send = rtl_send;
dev->recv = rtl_recv;
- eth_register (dev);
+ err = rtl_init(dev, bis);
+ if (err < 0) {
+ printf(pr_fmt("failed to initialize card: %d\n"), err);
+ free(dev);
+ continue;
+ }
- rtl_init(dev, bis);
+ eth_register (dev);
card_number++;
}
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index 451c33e1a1..4bf493ed45 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -2,9 +2,9 @@
* sh_eth.c - Driver for Renesas ethernet controler.
*
* Copyright (C) 2008, 2011 Renesas Solutions Corp.
- * Copyright (c) 2008, 2011 Nobuhiro Iwamatsu
+ * Copyright (c) 2008, 2011, 2014 2014 Nobuhiro Iwamatsu
* Copyright (c) 2007 Carlos Munoz <carlos@kenati.com>
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013, 2014 Renesas Electronics Corporation
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -83,6 +83,8 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len)
else
port_info->tx_desc_cur->td0 = TD_TACT | TD_TFP;
+ flush_cache_wback(port_info->tx_desc_cur, sizeof(struct tx_desc_s));
+
/* Restart the transmitter if disabled */
if (!(sh_eth_read(eth, EDTRR) & EDTRR_TRNS))
sh_eth_write(eth, EDTRR_TRNS, EDTRR);
@@ -133,6 +135,10 @@ int sh_eth_recv(struct eth_device *dev)
port_info->rx_desc_cur->rd0 = RD_RACT | RD_RDLE;
else
port_info->rx_desc_cur->rd0 = RD_RACT;
+
+ flush_cache_wback(port_info->rx_desc_cur,
+ sizeof(struct rx_desc_s));
+
/* Point to the next descriptor */
port_info->rx_desc_cur++;
if (port_info->rx_desc_cur >=
@@ -181,27 +187,27 @@ static int sh_eth_reset(struct sh_eth_dev *eth)
static int sh_eth_tx_desc_init(struct sh_eth_dev *eth)
{
int port = eth->port, i, ret = 0;
- u32 tmp_addr;
+ u32 alloc_desc_size = NUM_TX_DESC * sizeof(struct tx_desc_s);
struct sh_eth_info *port_info = &eth->port_info[port];
struct tx_desc_s *cur_tx_desc;
/*
- * Allocate tx descriptors. They must be TX_DESC_SIZE bytes aligned
+ * Allocate rx descriptors. They must be aligned to size of struct
+ * tx_desc_s.
*/
- port_info->tx_desc_malloc = malloc(NUM_TX_DESC *
- sizeof(struct tx_desc_s) +
- TX_DESC_SIZE - 1);
- if (!port_info->tx_desc_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->tx_desc_alloc =
+ memalign(sizeof(struct tx_desc_s), alloc_desc_size);
+ if (!port_info->tx_desc_alloc) {
+ printf(SHETHER_NAME ": memalign failed\n");
ret = -ENOMEM;
goto err;
}
- tmp_addr = (u32) (((int)port_info->tx_desc_malloc + TX_DESC_SIZE - 1) &
- ~(TX_DESC_SIZE - 1));
- flush_cache_wback(tmp_addr, NUM_TX_DESC * sizeof(struct tx_desc_s));
+ flush_cache_wback((u32)port_info->tx_desc_alloc, alloc_desc_size);
+
/* Make sure we use a P2 address (non-cacheable) */
- port_info->tx_desc_base = (struct tx_desc_s *)ADDR_TO_P2(tmp_addr);
+ port_info->tx_desc_base =
+ (struct tx_desc_s *)ADDR_TO_P2((u32)port_info->tx_desc_alloc);
port_info->tx_desc_cur = port_info->tx_desc_base;
/* Initialize all descriptors */
@@ -232,47 +238,44 @@ err:
static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
{
int port = eth->port, i , ret = 0;
+ u32 alloc_desc_size = NUM_RX_DESC * sizeof(struct rx_desc_s);
struct sh_eth_info *port_info = &eth->port_info[port];
struct rx_desc_s *cur_rx_desc;
- u32 tmp_addr;
u8 *rx_buf;
/*
- * Allocate rx descriptors. They must be RX_DESC_SIZE bytes aligned
+ * Allocate rx descriptors. They must be aligned to size of struct
+ * rx_desc_s.
*/
- port_info->rx_desc_malloc = malloc(NUM_RX_DESC *
- sizeof(struct rx_desc_s) +
- RX_DESC_SIZE - 1);
- if (!port_info->rx_desc_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->rx_desc_alloc =
+ memalign(sizeof(struct rx_desc_s), alloc_desc_size);
+ if (!port_info->rx_desc_alloc) {
+ printf(SHETHER_NAME ": memalign failed\n");
ret = -ENOMEM;
goto err;
}
- tmp_addr = (u32) (((int)port_info->rx_desc_malloc + RX_DESC_SIZE - 1) &
- ~(RX_DESC_SIZE - 1));
- flush_cache_wback(tmp_addr, NUM_RX_DESC * sizeof(struct rx_desc_s));
+ flush_cache_wback(port_info->rx_desc_alloc, alloc_desc_size);
+
/* Make sure we use a P2 address (non-cacheable) */
- port_info->rx_desc_base = (struct rx_desc_s *)ADDR_TO_P2(tmp_addr);
+ port_info->rx_desc_base =
+ (struct rx_desc_s *)ADDR_TO_P2((u32)port_info->rx_desc_alloc);
port_info->rx_desc_cur = port_info->rx_desc_base;
/*
- * Allocate rx data buffers. They must be 32 bytes aligned and in
- * P2 area
+ * Allocate rx data buffers. They must be RX_BUF_ALIGNE_SIZE bytes
+ * aligned and in P2 area.
*/
- port_info->rx_buf_malloc = malloc(
- NUM_RX_DESC * MAX_BUF_SIZE + RX_BUF_ALIGNE_SIZE - 1);
- if (!port_info->rx_buf_malloc) {
- printf(SHETHER_NAME ": malloc failed\n");
+ port_info->rx_buf_alloc =
+ memalign(RX_BUF_ALIGNE_SIZE, NUM_RX_DESC * MAX_BUF_SIZE);
+ if (!port_info->rx_buf_alloc) {
+ printf(SHETHER_NAME ": alloc failed\n");
ret = -ENOMEM;
- goto err_buf_malloc;
+ goto err_buf_alloc;
}
- tmp_addr = (u32)(((int)port_info->rx_buf_malloc
- + (RX_BUF_ALIGNE_SIZE - 1)) &
- ~(RX_BUF_ALIGNE_SIZE - 1));
- port_info->rx_buf_base = (u8 *)ADDR_TO_P2(tmp_addr);
+ port_info->rx_buf_base = (u8 *)ADDR_TO_P2((u32)port_info->rx_buf_alloc);
/* Initialize all descriptors */
for (cur_rx_desc = port_info->rx_desc_base,
@@ -297,9 +300,9 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth)
return ret;
-err_buf_malloc:
- free(port_info->rx_desc_malloc);
- port_info->rx_desc_malloc = NULL;
+err_buf_alloc:
+ free(port_info->rx_desc_alloc);
+ port_info->rx_desc_alloc = NULL;
err:
return ret;
@@ -310,9 +313,9 @@ static void sh_eth_tx_desc_free(struct sh_eth_dev *eth)
int port = eth->port;
struct sh_eth_info *port_info = &eth->port_info[port];
- if (port_info->tx_desc_malloc) {
- free(port_info->tx_desc_malloc);
- port_info->tx_desc_malloc = NULL;
+ if (port_info->tx_desc_alloc) {
+ free(port_info->tx_desc_alloc);
+ port_info->tx_desc_alloc = NULL;
}
}
@@ -321,14 +324,14 @@ static void sh_eth_rx_desc_free(struct sh_eth_dev *eth)
int port = eth->port;
struct sh_eth_info *port_info = &eth->port_info[port];
- if (port_info->rx_desc_malloc) {
- free(port_info->rx_desc_malloc);
- port_info->rx_desc_malloc = NULL;
+ if (port_info->rx_desc_alloc) {
+ free(port_info->rx_desc_alloc);
+ port_info->rx_desc_alloc = NULL;
}
- if (port_info->rx_buf_malloc) {
- free(port_info->rx_buf_malloc);
- port_info->rx_buf_malloc = NULL;
+ if (port_info->rx_buf_alloc) {
+ free(port_info->rx_buf_alloc);
+ port_info->rx_buf_alloc = NULL;
}
}
@@ -414,7 +417,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
#if defined(CONFIG_CPU_SH7734) || defined(CONFIG_R8A7740)
sh_eth_write(eth, CONFIG_SH_ETHER_SH7734_MII, RMII_MII);
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
sh_eth_write(eth, sh_eth_read(eth, RMIIMR) | 0x1, RMIIMR);
#endif
/* Configure phy */
@@ -440,7 +443,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd)
#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752)
sh_eth_write(eth, 1, RTRATE);
#elif defined(CONFIG_CPU_SH7724) || defined(CONFIG_R8A7790) || \
- defined(CONFIG_R8A7791) || defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7791) || defined(CONFIG_R8A7793) || \
+ defined(CONFIG_R8A7794)
val = ECMR_RTM;
#endif
} else if (phy->speed == 10) {
diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h
index e325a39aac..5cb520c63e 100644
--- a/drivers/net/sh_eth.h
+++ b/drivers/net/sh_eth.h
@@ -51,8 +51,6 @@
/* The size of the tx descriptor is determined by how much padding is used.
4, 20, or 52 bytes of padding can be used */
#define TX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
-/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
-#define TX_DESC_SIZE (12 + TX_DESC_PADDING)
/* Tx descriptor. We always use 3 bytes of padding */
struct tx_desc_s {
@@ -68,8 +66,6 @@ struct tx_desc_s {
/* The size of the rx descriptor is determined by how much padding is used.
4, 20, or 52 bytes of padding can be used */
#define RX_DESC_PADDING (CONFIG_SH_ETHER_ALIGNE_SIZE - 12)
-/* same as CONFIG_SH_ETHER_ALIGNE_SIZE */
-#define RX_DESC_SIZE (12 + RX_DESC_PADDING)
/* aligned cache line size */
#define RX_BUF_ALIGNE_SIZE (CONFIG_SH_ETHER_ALIGNE_SIZE > 32 ? 64 : 32)
@@ -82,13 +78,13 @@ struct rx_desc_s {
};
struct sh_eth_info {
- struct tx_desc_s *tx_desc_malloc;
+ struct tx_desc_s *tx_desc_alloc;
struct tx_desc_s *tx_desc_base;
struct tx_desc_s *tx_desc_cur;
- struct rx_desc_s *rx_desc_malloc;
+ struct rx_desc_s *rx_desc_alloc;
struct rx_desc_s *rx_desc_base;
struct rx_desc_s *rx_desc_cur;
- u8 *rx_buf_malloc;
+ u8 *rx_buf_alloc;
u8 *rx_buf_base;
u8 mac_addr[6];
u8 phy_addr;
@@ -359,7 +355,7 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = {
#define SH_ETH_TYPE_GETHER
#define BASE_IO_ADDR 0xE9A00000
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
#define SH_ETH_TYPE_ETHER
#define BASE_IO_ADDR 0xEE700200
#elif defined(CONFIG_R7S72100)
@@ -571,7 +567,7 @@ enum FELIC_MODE_BIT {
#ifdef CONFIG_CPU_SH7724
ECMR_RTM = 0x00000010,
#elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) || \
- defined(CONFIG_R8A7794)
+ defined(CONFIG_R8A7793) || defined(CONFIG_R8A7794)
ECMR_RTM = 0x00000004,
#endif
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index b097c1a56f..5959672370 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -187,6 +187,7 @@ static int smc911x_send(struct eth_device *dev, void *packet, int length)
static void smc911x_halt(struct eth_device *dev)
{
smc911x_reset(dev);
+ smc911x_handle_mac_address(dev);
}
static int smc911x_rx(struct eth_device *dev)
diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c
index 538f11e3eb..9526faa4af 100644
--- a/drivers/net/uli526x.c
+++ b/drivers/net/uli526x.c
@@ -548,7 +548,7 @@ static int uli526x_rx_packet(struct eth_device *dev)
rdes0 = le32_to_cpu(rxptr->rdes0);
#ifdef RX_DEBUG
- printf("%s(): rxptr->rdes0=%x:%x\n", __FUNCTION__, rxptr->rdes0);
+ printf("%s(): rxptr->rdes0=%x\n", __FUNCTION__, rxptr->rdes0);
#endif
if (!(rdes0 & 0x80000000)) { /* packet owner check */
if ((rdes0 & 0x300) != 0x300) {