diff --git a/drivers/net/ngbe/base/ngbe_dummy.h b/drivers/net/ngbe/base/ngbe_dummy.h index 634e9a69c1..1b74710b09 100644 --- a/drivers/net/ngbe/base/ngbe_dummy.h +++ b/drivers/net/ngbe/base/ngbe_dummy.h @@ -64,6 +64,11 @@ static inline void ngbe_mac_release_swfw_sync_dummy(struct ngbe_hw *TUP0, u32 TUP1) { } +static inline s32 ngbe_mac_setup_link_dummy(struct ngbe_hw *TUP0, u32 TUP1, + bool TUP2) +{ + return NGBE_ERR_OPS_DUMMY; +} static inline s32 ngbe_mac_check_link_dummy(struct ngbe_hw *TUP0, u32 *TUP1, bool *TUP3, bool TUP4) { @@ -129,6 +134,16 @@ static inline s32 ngbe_phy_write_reg_unlocked_dummy(struct ngbe_hw *TUP0, { return NGBE_ERR_OPS_DUMMY; } +static inline s32 ngbe_phy_setup_link_dummy(struct ngbe_hw *TUP0, + u32 TUP1, bool TUP2) +{ + return NGBE_ERR_OPS_DUMMY; +} +static inline s32 ngbe_phy_check_link_dummy(struct ngbe_hw *TUP0, u32 *TUP1, + bool *TUP2) +{ + return NGBE_ERR_OPS_DUMMY; +} static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) { hw->bus.set_lan_id = ngbe_bus_set_lan_id_dummy; @@ -140,6 +155,7 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) hw->mac.get_mac_addr = ngbe_mac_get_mac_addr_dummy; hw->mac.acquire_swfw_sync = ngbe_mac_acquire_swfw_sync_dummy; hw->mac.release_swfw_sync = ngbe_mac_release_swfw_sync_dummy; + hw->mac.setup_link = ngbe_mac_setup_link_dummy; hw->mac.check_link = ngbe_mac_check_link_dummy; hw->mac.set_rar = ngbe_mac_set_rar_dummy; hw->mac.clear_rar = ngbe_mac_clear_rar_dummy; @@ -154,6 +170,8 @@ static inline void ngbe_init_ops_dummy(struct ngbe_hw *hw) hw->phy.write_reg = ngbe_phy_write_reg_dummy; hw->phy.read_reg_unlocked = ngbe_phy_read_reg_unlocked_dummy; hw->phy.write_reg_unlocked = ngbe_phy_write_reg_unlocked_dummy; + hw->phy.setup_link = ngbe_phy_setup_link_dummy; + hw->phy.check_link = ngbe_phy_check_link_dummy; } #endif /* _NGBE_TYPE_DUMMY_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_hw.c b/drivers/net/ngbe/base/ngbe_hw.c index 2daddaaf05..3683475970 100644 --- a/drivers/net/ngbe/base/ngbe_hw.c +++ b/drivers/net/ngbe/base/ngbe_hw.c @@ -599,6 +599,54 @@ s32 ngbe_init_uta_tables(struct ngbe_hw *hw) return 0; } +/** + * ngbe_check_mac_link_em - Determine link and speed status + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @link_up: true when link is up + * @link_up_wait_to_complete: bool used to wait for link up or not + * + * Reads the links register to determine if link is up and the current speed + **/ +s32 ngbe_check_mac_link_em(struct ngbe_hw *hw, u32 *speed, + bool *link_up, bool link_up_wait_to_complete) +{ + u32 i, reg; + s32 status = 0; + + DEBUGFUNC("ngbe_check_mac_link_em"); + + reg = rd32(hw, NGBE_GPIOINTSTAT); + wr32(hw, NGBE_GPIOEOI, reg); + + if (link_up_wait_to_complete) { + for (i = 0; i < hw->mac.max_link_up_time; i++) { + status = hw->phy.check_link(hw, speed, link_up); + if (*link_up) + break; + msec_delay(100); + } + } else { + status = hw->phy.check_link(hw, speed, link_up); + } + + return status; +} + +s32 ngbe_setup_mac_link_em(struct ngbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete) +{ + s32 status; + + DEBUGFUNC("\n"); + + /* Setup the PHY according to input speed */ + status = hw->phy.setup_link(hw, speed, autoneg_wait_to_complete); + + return status; +} + /** * ngbe_init_thermal_sensor_thresh - Inits thermal sensor thresholds * @hw: pointer to hardware structure @@ -806,6 +854,10 @@ s32 ngbe_init_ops_pf(struct ngbe_hw *hw) mac->set_vmdq = ngbe_set_vmdq; mac->clear_vmdq = ngbe_clear_vmdq; + /* Link */ + mac->check_link = ngbe_check_mac_link_em; + mac->setup_link = ngbe_setup_mac_link_em; + /* Manageability interface */ mac->init_thermal_sensor_thresh = ngbe_init_thermal_sensor_thresh; mac->check_overtemp = ngbe_mac_check_overtemp; @@ -853,6 +905,7 @@ s32 ngbe_init_shared_code(struct ngbe_hw *hw) status = NGBE_ERR_DEVICE_NOT_SUPPORTED; break; } + hw->mac.max_link_up_time = NGBE_LINK_UP_TIME; hw->bus.set_lan_id(hw); diff --git a/drivers/net/ngbe/base/ngbe_hw.h b/drivers/net/ngbe/base/ngbe_hw.h index 875bfa1add..9b71e4b0dd 100644 --- a/drivers/net/ngbe/base/ngbe_hw.h +++ b/drivers/net/ngbe/base/ngbe_hw.h @@ -20,6 +20,12 @@ s32 ngbe_get_mac_addr(struct ngbe_hw *hw, u8 *mac_addr); void ngbe_set_lan_id_multi_port(struct ngbe_hw *hw); +s32 ngbe_check_mac_link_em(struct ngbe_hw *hw, u32 *speed, + bool *link_up, bool link_up_wait_to_complete); +s32 ngbe_setup_mac_link_em(struct ngbe_hw *hw, + u32 speed, + bool autoneg_wait_to_complete); + s32 ngbe_set_rar(struct ngbe_hw *hw, u32 index, u8 *addr, u32 vmdq, u32 enable_addr); s32 ngbe_clear_rar(struct ngbe_hw *hw, u32 index); diff --git a/drivers/net/ngbe/base/ngbe_phy.c b/drivers/net/ngbe/base/ngbe_phy.c index 61bb953b6a..f0265d83b8 100644 --- a/drivers/net/ngbe/base/ngbe_phy.c +++ b/drivers/net/ngbe/base/ngbe_phy.c @@ -420,7 +420,29 @@ s32 ngbe_init_phy(struct ngbe_hw *hw) /* Identify the PHY */ err = phy->identify(hw); + if (err == NGBE_ERR_PHY_ADDR_INVALID) + goto init_phy_ops_out; + /* Set necessary function pointers based on PHY type */ + switch (hw->phy.type) { + case ngbe_phy_rtl: + hw->phy.check_link = ngbe_check_phy_link_rtl; + hw->phy.setup_link = ngbe_setup_phy_link_rtl; + break; + case ngbe_phy_mvl: + case ngbe_phy_mvl_sfi: + hw->phy.check_link = ngbe_check_phy_link_mvl; + hw->phy.setup_link = ngbe_setup_phy_link_mvl; + break; + case ngbe_phy_yt8521s: + case ngbe_phy_yt8521s_sfi: + hw->phy.check_link = ngbe_check_phy_link_yt; + hw->phy.setup_link = ngbe_setup_phy_link_yt; + default: + break; + } + +init_phy_ops_out: return err; } diff --git a/drivers/net/ngbe/base/ngbe_phy.h b/drivers/net/ngbe/base/ngbe_phy.h index 226e0189ec..5d6ff1711c 100644 --- a/drivers/net/ngbe/base/ngbe_phy.h +++ b/drivers/net/ngbe/base/ngbe_phy.h @@ -22,6 +22,8 @@ #define NGBE_MD_PHY_ID_LOW 0x3 /* PHY ID Low Reg*/ #define NGBE_PHY_REVISION_MASK 0xFFFFFFF0 +#define NGBE_MII_AUTONEG_REG 0x0 + /* IEEE 802.3 Clause 22 */ struct mdi_reg_22 { u16 page; diff --git a/drivers/net/ngbe/base/ngbe_phy_mvl.c b/drivers/net/ngbe/base/ngbe_phy_mvl.c index 1248478252..f8cb6cd38a 100644 --- a/drivers/net/ngbe/base/ngbe_phy_mvl.c +++ b/drivers/net/ngbe/base/ngbe_phy_mvl.c @@ -48,6 +48,64 @@ s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw, return 0; } +s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed, + bool autoneg_wait_to_complete) +{ + u16 value_r4 = 0; + u16 value_r9 = 0; + u16 value; + + DEBUGFUNC("ngbe_setup_phy_link_mvl"); + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + hw->phy.autoneg_advertised = 0; + + if (hw->phy.type == ngbe_phy_mvl) { + if (speed & NGBE_LINK_SPEED_1GB_FULL) { + value_r9 |= MVL_PHY_1000BASET_FULL; + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; + } + + if (speed & NGBE_LINK_SPEED_100M_FULL) { + value_r4 |= MVL_PHY_100BASET_FULL; + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL; + } + + if (speed & NGBE_LINK_SPEED_10M_FULL) { + value_r4 |= MVL_PHY_10BASET_FULL; + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL; + } + + hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= ~(MVL_PHY_100BASET_FULL | + MVL_PHY_100BASET_HALF | + MVL_PHY_10BASET_FULL | + MVL_PHY_10BASET_HALF); + value_r4 |= value; + hw->phy.write_reg(hw, MVL_ANA, 0, value_r4); + + hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value); + value &= ~(MVL_PHY_1000BASET_FULL | + MVL_PHY_1000BASET_HALF); + value_r9 |= value; + hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9); + } else { + hw->phy.autoneg_advertised = 1; + + hw->phy.read_reg(hw, MVL_ANA, 0, &value); + value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL); + value |= MVL_PHY_1000BASEX_FULL; + hw->phy.write_reg(hw, MVL_ANA, 0, value); + } + + value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE; + ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value); + + hw->phy.read_reg(hw, MVL_INTR, 0, &value); + + return 0; +} + s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw) { u32 i; @@ -87,3 +145,43 @@ s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw) return status; } +s32 ngbe_check_phy_link_mvl(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_mvl"); + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = NGBE_LINK_SPEED_UNKNOWN; + + hw->phy.read_reg(hw, MVL_INTR, 0, &insr); + + /* + * 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, MVL_PHYSR, 0, &phy_data); + phy_link = phy_data & MVL_PHYSR_LINK; + phy_speed = phy_data & MVL_PHYSR_SPEED_MASK; + + if (phy_link == MVL_PHYSR_LINK) { + *link_up = true; + + if (phy_speed == MVL_PHYSR_SPEED_1000M) + *speed = NGBE_LINK_SPEED_1GB_FULL; + else if (phy_speed == MVL_PHYSR_SPEED_100M) + *speed = NGBE_LINK_SPEED_100M_FULL; + else if (phy_speed == MVL_PHYSR_SPEED_10M) + *speed = NGBE_LINK_SPEED_10M_FULL; + } + + return status; +} + diff --git a/drivers/net/ngbe/base/ngbe_phy_mvl.h b/drivers/net/ngbe/base/ngbe_phy_mvl.h index ca39f3cd58..c8155c39a0 100644 --- a/drivers/net/ngbe/base/ngbe_phy_mvl.h +++ b/drivers/net/ngbe/base/ngbe_phy_mvl.h @@ -89,4 +89,8 @@ s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw); +s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw, + u32 *speed, bool *link_up); +s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, + u32 speed, bool autoneg_wait_to_complete); #endif /* _NGBE_PHY_MVL_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_phy_rtl.c b/drivers/net/ngbe/base/ngbe_phy_rtl.c index 400fbe8c1f..a45b0f0a55 100644 --- a/drivers/net/ngbe/base/ngbe_phy_rtl.c +++ b/drivers/net/ngbe/base/ngbe_phy_rtl.c @@ -38,6 +38,134 @@ s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw, 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 +191,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; +} + diff --git a/drivers/net/ngbe/base/ngbe_phy_rtl.h b/drivers/net/ngbe/base/ngbe_phy_rtl.h index 2da5c7b626..ee5e03e9f3 100644 --- a/drivers/net/ngbe/base/ngbe_phy_rtl.h +++ b/drivers/net/ngbe/base/ngbe_phy_rtl.h @@ -78,6 +78,10 @@ s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); +s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw, + u32 speed, bool autoneg_wait_to_complete); s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw); +s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, + u32 *speed, bool *link_up); #endif /* _NGBE_PHY_RTL_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.c b/drivers/net/ngbe/base/ngbe_phy_yt.c index a5b032240c..4a44414c64 100644 --- a/drivers/net/ngbe/base/ngbe_phy_yt.c +++ b/drivers/net/ngbe/base/ngbe_phy_yt.c @@ -78,6 +78,104 @@ s32 ngbe_write_phy_reg_ext_yt(struct ngbe_hw *hw, return 0; } +s32 ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw *hw, + u32 reg_addr, u32 device_type, u16 *phy_data) +{ + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS); + ngbe_read_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data); + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0); + + return 0; +} + +s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw, + u32 reg_addr, u32 device_type, u16 phy_data) +{ + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS); + ngbe_write_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data); + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0); + + return 0; +} + +s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed, + bool autoneg_wait_to_complete) +{ + u16 value_r4 = 0; + u16 value_r9 = 0; + u16 value; + + DEBUGFUNC("ngbe_setup_phy_link_yt"); + UNREFERENCED_PARAMETER(autoneg_wait_to_complete); + + hw->phy.autoneg_advertised = 0; + + if (hw->phy.type == ngbe_phy_yt8521s) { + /*disable 100/10base-T Self-negotiation ability*/ + hw->phy.read_reg(hw, YT_ANA, 0, &value); + value &= ~(YT_ANA_100BASET_FULL | YT_ANA_10BASET_FULL); + hw->phy.write_reg(hw, YT_ANA, 0, value); + + /*disable 1000base-T Self-negotiation ability*/ + hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value); + value &= ~YT_MS_1000BASET_FULL; + hw->phy.write_reg(hw, YT_MS_CTRL, 0, value); + + if (speed & NGBE_LINK_SPEED_1GB_FULL) { + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; + value_r9 |= YT_MS_1000BASET_FULL; + } + if (speed & NGBE_LINK_SPEED_100M_FULL) { + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL; + value_r4 |= YT_ANA_100BASET_FULL; + } + if (speed & NGBE_LINK_SPEED_10M_FULL) { + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL; + value_r4 |= YT_ANA_10BASET_FULL; + } + + /* enable 1000base-T Self-negotiation ability */ + hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value); + value |= value_r9; + hw->phy.write_reg(hw, YT_MS_CTRL, 0, value); + + /* enable 100/10base-T Self-negotiation ability */ + hw->phy.read_reg(hw, YT_ANA, 0, &value); + value |= value_r4; + hw->phy.write_reg(hw, YT_ANA, 0, value); + + /* software reset to make the above configuration take effect*/ + hw->phy.read_reg(hw, YT_BCR, 0, &value); + value |= YT_BCR_RESET; + hw->phy.write_reg(hw, YT_BCR, 0, value); + } else { + hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; + + /* RGMII_Config1 : Config rx and tx training delay */ + value = YT_RGMII_CONF1_RXDELAY | + YT_RGMII_CONF1_TXDELAY_FE | + YT_RGMII_CONF1_TXDELAY; + ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value); + value = YT_CHIP_MODE_SEL(1) | + YT_CHIP_SW_LDO_EN | + YT_CHIP_SW_RST; + ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value); + + /* software reset */ + ngbe_write_phy_reg_sds_ext_yt(hw, 0x0, 0, 0x9140); + + /* power on phy */ + hw->phy.read_reg(hw, YT_BCR, 0, &value); + value &= ~YT_BCR_PWDN; + hw->phy.write_reg(hw, YT_BCR, 0, value); + } + + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0); + ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &value); + + return 0; +} + s32 ngbe_reset_phy_yt(struct ngbe_hw *hw) { u32 i; @@ -110,3 +208,39 @@ s32 ngbe_reset_phy_yt(struct ngbe_hw *hw) return status; } +s32 ngbe_check_phy_link_yt(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_yt"); + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = NGBE_LINK_SPEED_UNKNOWN; + + ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0); + ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &insr); + + status = hw->phy.read_reg(hw, YT_SPST, 0, &phy_data); + phy_link = phy_data & YT_SPST_LINK; + phy_speed = phy_data & YT_SPST_SPEED_MASK; + + if (phy_link) { + *link_up = true; + + if (phy_speed == YT_SPST_SPEED_1000M) + *speed = NGBE_LINK_SPEED_1GB_FULL; + else if (phy_speed == YT_SPST_SPEED_100M) + *speed = NGBE_LINK_SPEED_100M_FULL; + else if (phy_speed == YT_SPST_SPEED_10M) + *speed = NGBE_LINK_SPEED_10M_FULL; + } + + return status; +} + diff --git a/drivers/net/ngbe/base/ngbe_phy_yt.h b/drivers/net/ngbe/base/ngbe_phy_yt.h index 6d49464d6d..f7a0cb873c 100644 --- a/drivers/net/ngbe/base/ngbe_phy_yt.h +++ b/drivers/net/ngbe/base/ngbe_phy_yt.h @@ -61,7 +61,15 @@ s32 ngbe_read_phy_reg_ext_yt(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, u16 *phy_data); s32 ngbe_write_phy_reg_ext_yt(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); +s32 ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw *hw, + u32 reg_addr, u32 device_type, u16 *phy_data); +s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw, + u32 reg_addr, u32 device_type, u16 phy_data); s32 ngbe_reset_phy_yt(struct ngbe_hw *hw); +s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw, + u32 *speed, bool *link_up); +s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, + u32 speed, bool autoneg_wait_to_complete); #endif /* _NGBE_PHY_YT_H_ */ diff --git a/drivers/net/ngbe/base/ngbe_type.h b/drivers/net/ngbe/base/ngbe_type.h index 554c57c845..472c0c1bea 100644 --- a/drivers/net/ngbe/base/ngbe_type.h +++ b/drivers/net/ngbe/base/ngbe_type.h @@ -6,6 +6,8 @@ #ifndef _NGBE_TYPE_H_ #define _NGBE_TYPE_H_ +#define NGBE_LINK_UP_TIME 90 /* 9.0 Seconds */ + #define NGBE_FRAME_SIZE_DFT (1522) /* Default frame size, +FCS */ #define NGBE_ALIGN 128 /* as intel did */ @@ -97,6 +99,8 @@ struct ngbe_mac_info { s32 (*acquire_swfw_sync)(struct ngbe_hw *hw, u32 mask); void (*release_swfw_sync)(struct ngbe_hw *hw, u32 mask); + s32 (*setup_link)(struct ngbe_hw *hw, u32 speed, + bool autoneg_wait_to_complete); s32 (*check_link)(struct ngbe_hw *hw, u32 *speed, bool *link_up, bool link_up_wait_to_complete); /* RAR */ @@ -122,6 +126,9 @@ struct ngbe_mac_info { bool get_link_status; struct ngbe_thermal_sensor_data thermal_sensor_data; bool set_lben; + u32 max_link_up_time; + + bool autoneg; }; struct ngbe_phy_info { @@ -135,6 +142,9 @@ struct ngbe_phy_info { u32 device_type, u16 *phy_data); s32 (*write_reg_unlocked)(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data); + s32 (*setup_link)(struct ngbe_hw *hw, u32 speed, + bool autoneg_wait_to_complete); + s32 (*check_link)(struct ngbe_hw *hw, u32 *speed, bool *link_up); enum ngbe_media_type media_type; enum ngbe_phy_type type; @@ -143,6 +153,7 @@ struct ngbe_phy_info { u32 revision; u32 phy_semaphore_mask; bool reset_disable; + u32 autoneg_advertised; }; enum ngbe_isb_idx {