diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/fm/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/fm/b4860.c | 64 | ||||
-rw-r--r-- | drivers/net/fm/eth.c | 23 | ||||
-rw-r--r-- | drivers/net/fm/init.c | 19 | ||||
-rw-r--r-- | drivers/net/fm/memac.c | 12 | ||||
-rw-r--r-- | drivers/net/fm/memac_phy.c | 7 | ||||
-rw-r--r-- | drivers/net/fm/t1024.c | 88 | ||||
-rw-r--r-- | drivers/net/fm/t1040.c | 4 | ||||
-rw-r--r-- | drivers/net/keystone_net.c | 7 | ||||
-rw-r--r-- | drivers/net/macb.c | 17 | ||||
-rw-r--r-- | drivers/net/mpc5xxx_fec.c | 5 | ||||
-rw-r--r-- | drivers/net/netconsole.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/phy/cortina.c | 333 | ||||
-rw-r--r-- | drivers/net/phy/marvell.c | 53 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 3 | ||||
-rw-r--r-- | drivers/net/phy/vitesse.c | 13 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 127 | ||||
-rw-r--r-- | drivers/net/sh_eth.c | 102 | ||||
-rw-r--r-- | drivers/net/sh_eth.h | 14 | ||||
-rw-r--r-- | drivers/net/smc911x.c | 1 | ||||
-rw-r--r-- | drivers/net/uli526x.c | 2 |
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(®s->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 = ®->memac[num].fm_memac; phyregs = ®->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(®s->command_config, MEMAC_CMD_CFG_RXTX_EN); + setbits_be32(®s->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(®s->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 = ð->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 = ð->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 = ð->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 = ð->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) { |