X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fnet%2Ftsec.c;h=bc2707f17a7d15a2c4d5277660a72f3c1dc08be9;hb=5b1b1883ffcb75de71a0b4e66b279c88ae1e15fc;hp=6a444186880160b68a0926cca4013d286e5040a1;hpb=c6dbdfda5393c155bb13a90d9d6be4fe75ec3498;p=u-boot diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 6a44418688..bc2707f17a 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -281,12 +281,16 @@ static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs, | TBIANA_FULL_DUPLEX \ ) -/* Force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ +/* By default force the TBI PHY into 1000Mbps full duplex when in SGMII mode */ +#ifndef CONFIG_TSEC_TBICR_SETTINGS #define TBICR_SETTINGS ( \ TBICR_PHY_RESET \ | TBICR_FULL_DUPLEX \ | TBICR_SPEED1_SET \ ) +#else +#define TBICR_SETTINGS CONFIG_TSEC_TBICR_SETTINGS +#endif /* CONFIG_TSEC_TBICR_SETTINGS */ /* Configure the TBI for SGMII operation */ static void tsec_configure_serdes(struct tsec_private *priv) @@ -530,8 +534,106 @@ static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv) } return 0; +} +/* + * Find out if PHY is in copper or serdes mode by looking at Expansion Reg + * 0x42 - "Operating Mode Status Register" + */ +static int BCM8482_is_serdes(struct tsec_private *priv) +{ + u16 val; + int serdes = 0; + + write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); + + switch (val & 0x1f) { + case 0x0d: /* RGMII-to-100Base-FX */ + case 0x0e: /* RGMII-to-SGMII */ + case 0x0f: /* RGMII-to-SerDes */ + case 0x12: /* SGMII-to-SerDes */ + case 0x13: /* SGMII-to-100Base-FX */ + case 0x16: /* SerDes-to-Serdes */ + serdes = 1; + break; + case 0x6: /* RGMII-to-Copper */ + case 0x14: /* SGMII-to-Copper */ + case 0x17: /* SerDes-to-Copper */ + break; + default: + printf("ERROR, invalid PHY mode (0x%x\n)", val); + break; + } + + return serdes; } + +/* + * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating + * Mode Status Register" + */ +uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv) +{ + u16 val; + int i = 0; + + /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ + while (1) { + write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); + + if (val & 0x8000) + break; + + if (i++ > 1000) { + priv->link = 0; + return 1; + } + + udelay(1000); /* 1 ms */ + } + + priv->link = 1; + switch ((val >> 13) & 0x3) { + case (0x00): + priv->speed = 10; + break; + case (0x01): + priv->speed = 100; + break; + case (0x02): + priv->speed = 1000; + break; + } + + priv->duplexity = (val & 0x1000) == 0x1000; + + return 0; +} + +/* + * Figure out if BCM5482 is in serdes or copper mode and determine link + * configuration accordingly + */ +static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv) +{ + if (BCM8482_is_serdes(priv)) { + mii_parse_BCM5482_serdes_sr(priv); + priv->flags |= TSEC_FIBER; + } else { + /* Wait for auto-negotiation to complete or fail */ + mii_parse_sr(mii_reg, priv); + + /* Parse BCM54xx copper aux status register */ + mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS); + mii_parse_BCM54xx_sr(mii_reg, priv); + } + + return 0; +} + /* Parse the 88E1011's status register for speed and duplex * information */ @@ -843,8 +945,9 @@ static void adjust_link(struct eth_device *dev) break; } - printf("Speed: %d, %s duplex\n", priv->speed, - (priv->duplexity) ? "full" : "half"); + printf("Speed: %d, %s duplex%s\n", priv->speed, + (priv->duplexity) ? "full" : "half", + (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); } else { printf("%s: No link.\n", dev->name); @@ -983,7 +1086,8 @@ static void tsec_halt(struct eth_device *dev) regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); - while (!(regs->ievent & (IEVENT_GRSC | IEVENT_GTSC))) ; + while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)) + != (IEVENT_GRSC | IEVENT_GTSC)) ; regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); @@ -1091,15 +1195,20 @@ static struct phy_info phy_info_BCM5482S = { /* Read Misc Control register and or in Ethernet@Wirespeed */ {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + /* Initial config/enable of secondary SerDes interface */ + {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL}, + /* Write intial value to secondary SerDes Contol */ + {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL}, + {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL}, + /* Enable copper/fiber auto-detect */ + {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)}, {miim_end,} }, (struct phy_cmd[]) { /* startup */ /* Status is read once to clear old link state */ {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, + /* Determine copper/fiber, auto-negotiate, and read the result */ + {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr}, {miim_end,} }, (struct phy_cmd[]) { /* shutdown */ @@ -1522,6 +1631,27 @@ static struct phy_info phy_info_dm9161 = { }, }; +/* micrel KSZ804 */ +static struct phy_info phy_info_ksz804 = { + 0x0022151, + "Micrel KSZ804 PHY", + 4, + (struct phy_cmd[]) { /* config */ + {PHY_BMCR, PHY_BMCR_RESET, NULL}, + {PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL}, + {miim_end,} + }, + (struct phy_cmd[]) { /* startup */ + {PHY_BMSR, miim_read, NULL}, + {PHY_BMSR, miim_read, &mii_parse_sr}, + {PHY_BMSR, miim_read, &mii_parse_link}, + {miim_end,} + }, + (struct phy_cmd[]) { /* shutdown */ + {miim_end,} + } +}; + /* a generic flavor. */ static struct phy_info phy_info_generic = { 0, @@ -1685,6 +1815,7 @@ static struct phy_info *phy_info[] = { &phy_info_M88E1145, &phy_info_M88E1149S, &phy_info_dm9161, + &phy_info_ksz804, &phy_info_lxt971, &phy_info_VSC8211, &phy_info_VSC8244,