X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fngbe%2Fbase%2Fngbe_phy_rtl.c;h=83830921c234fba6484a71751200205958d59a98;hb=60229dcfc4301ce6051b0b1691743e1eff2a0fb1;hp=400fbe8c1ff32cd4e017dd6f92adf669b33fee11;hpb=44e97550ca68785ee3a5af9dbc11c2a932a6e777;p=dpdk.git diff --git a/drivers/net/ngbe/base/ngbe_phy_rtl.c b/drivers/net/ngbe/base/ngbe_phy_rtl.c index 400fbe8c1f..83830921c2 100644 --- a/drivers/net/ngbe/base/ngbe_phy_rtl.c +++ b/drivers/net/ngbe/base/ngbe_phy_rtl.c @@ -38,6 +38,192 @@ s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw, return 0; } +s32 ngbe_init_phy_rtl(struct ngbe_hw *hw) +{ + int i; + u16 value = 0; + + /* enable interrupts, only link status change and an done is allowed */ + value = RTL_INER_LSC | RTL_INER_ANC; + hw->phy.write_reg(hw, RTL_INER, 0xa42, value); + + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); + + for (i = 0; i < 15; i++) { + if (!rd32m(hw, NGBE_STAT, + NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id))) + break; + + msec_delay(10); + } + if (i == 15) { + DEBUGOUT("GPhy reset exceeds maximum times.\n"); + return NGBE_ERR_PHY_TIMEOUT; + } + + for (i = 0; i < 1000; i++) { + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); + if (value & RTL_INSR_ACCESS) + break; + } + + hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE); + for (i = 0; i < 1000; i++) { + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); + if (value & RTL_INSR_ACCESS) + break; + } + if (i == 1000) + return NGBE_ERR_PHY_TIMEOUT; + + hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI); + for (i = 0; i < 1000; i++) { + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); + if (value & RTL_INSR_ACCESS) + break; + } + if (i == 1000) + return NGBE_ERR_PHY_TIMEOUT; + + for (i = 0; i < 1000; i++) { + hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value); + if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON) + break; + } + if (i == 1000) + return NGBE_ERR_PHY_TIMEOUT; + + return 0; +} + +/** + * ngbe_setup_phy_link_rtl - Set and restart auto-neg + * @hw: pointer to hardware structure + * + * Restart auto-negotiation and PHY and waits for completion. + **/ +s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw, + u32 speed, bool autoneg_wait_to_complete) +{ + u16 autoneg_reg = NGBE_MII_AUTONEG_REG; + u16 value = 0; + + DEBUGFUNC("ngbe_setup_phy_link_rtl"); + + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg); + + if (!hw->mac.autoneg) { + hw->phy.reset_hw(hw); + + switch (speed) { + case NGBE_LINK_SPEED_1GB_FULL: + value = RTL_BMCR_SPEED_SELECT1; + break; + case NGBE_LINK_SPEED_100M_FULL: + value = RTL_BMCR_SPEED_SELECT0; + break; + case NGBE_LINK_SPEED_10M_FULL: + value = 0; + break; + default: + value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0; + DEBUGOUT("unknown speed = 0x%x.\n", speed); + break; + } + /* duplex full */ + value |= RTL_BMCR_DUPLEX; + hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value); + + goto skip_an; + } + + /* + * Clear autoneg_advertised and set new values based on input link + * speed. + */ + if (speed) { + hw->phy.autoneg_advertised = 0; + + if (speed & NGBE_LINK_SPEED_1GB_FULL) + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; + + if (speed & NGBE_LINK_SPEED_100M_FULL) + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL; + + if (speed & NGBE_LINK_SPEED_10M_FULL) + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL; + } + + /* disable 10/100M Half Duplex */ + hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg &= 0xFF5F; + hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg); + + /* set advertise enable according to input speed */ + if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) { + hw->phy.read_reg(hw, RTL_GBCR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg &= ~RTL_GBCR_1000F; + hw->phy.write_reg(hw, RTL_GBCR, + RTL_DEV_ZERO, autoneg_reg); + } else { + hw->phy.read_reg(hw, RTL_GBCR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg |= RTL_GBCR_1000F; + hw->phy.write_reg(hw, RTL_GBCR, + RTL_DEV_ZERO, autoneg_reg); + } + + if (!(speed & NGBE_LINK_SPEED_100M_FULL)) { + hw->phy.read_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg &= ~RTL_ANAR_100F; + autoneg_reg &= ~RTL_ANAR_100H; + hw->phy.write_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, autoneg_reg); + } else { + hw->phy.read_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg |= RTL_ANAR_100F; + hw->phy.write_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, autoneg_reg); + } + + if (!(speed & NGBE_LINK_SPEED_10M_FULL)) { + hw->phy.read_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg &= ~RTL_ANAR_10F; + autoneg_reg &= ~RTL_ANAR_10H; + hw->phy.write_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, autoneg_reg); + } else { + hw->phy.read_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, &autoneg_reg); + autoneg_reg |= RTL_ANAR_10F; + hw->phy.write_reg(hw, RTL_ANAR, + RTL_DEV_ZERO, autoneg_reg); + } + + /* restart AN and wait AN done interrupt */ + autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE; + hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg); + +skip_an: + autoneg_reg = 0x205B; + hw->phy.write_reg(hw, RTL_LCR, 0xd04, autoneg_reg); + hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0); + + hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &autoneg_reg); + autoneg_reg = autoneg_reg & 0xFFFC; + /* act led blinking mode set to 60ms */ + autoneg_reg |= 0x2; + hw->phy.write_reg(hw, RTL_LPCR, 0xd04, autoneg_reg); + + return 0; +} + s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw) { u16 value = 0, i; @@ -63,3 +249,41 @@ s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw) return status; } +s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up) +{ + s32 status = 0; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + u16 insr = 0; + + DEBUGFUNC("ngbe_check_phy_link_rtl"); + + hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr); + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = NGBE_LINK_SPEED_UNKNOWN; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data); + phy_link = phy_data & RTL_PHYSR_RTLS; + phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP); + if (phy_link == RTL_PHYSR_RTLS) { + *link_up = true; + + if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP)) + *speed = NGBE_LINK_SPEED_1GB_FULL; + else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP)) + *speed = NGBE_LINK_SPEED_100M_FULL; + else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP)) + *speed = NGBE_LINK_SPEED_10M_FULL; + } + + return status; +} +