xref: /dpdk/drivers/net/ngbe/base/ngbe_phy_mvl.c (revision 91e64c0e5d7ee7eaf39df9510bfc60bbcae14ca9)
144e97550SJiawen Wu /* SPDX-License-Identifier: BSD-3-Clause
244e97550SJiawen Wu  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
344e97550SJiawen Wu  */
444e97550SJiawen Wu 
544e97550SJiawen Wu #include "ngbe_phy_mvl.h"
644e97550SJiawen Wu 
744e97550SJiawen Wu #define MVL_PHY_RST_WAIT_PERIOD  5
844e97550SJiawen Wu 
944e97550SJiawen Wu s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw,
1044e97550SJiawen Wu 		u32 reg_addr, u32 device_type, u16 *phy_data)
1144e97550SJiawen Wu {
1244e97550SJiawen Wu 	mdi_reg_t reg;
1344e97550SJiawen Wu 	mdi_reg_22_t reg22;
1444e97550SJiawen Wu 
1544e97550SJiawen Wu 	reg.device_type = device_type;
1644e97550SJiawen Wu 	reg.addr = reg_addr;
1744e97550SJiawen Wu 
1844e97550SJiawen Wu 	if (hw->phy.media_type == ngbe_media_type_fiber)
1944e97550SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
2044e97550SJiawen Wu 	else
2144e97550SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
2244e97550SJiawen Wu 
2344e97550SJiawen Wu 	ngbe_mdi_map_register(&reg, &reg22);
2444e97550SJiawen Wu 
2544e97550SJiawen Wu 	ngbe_read_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
2644e97550SJiawen Wu 
2744e97550SJiawen Wu 	return 0;
2844e97550SJiawen Wu }
2944e97550SJiawen Wu 
3044e97550SJiawen Wu s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
3144e97550SJiawen Wu 		u32 reg_addr, u32 device_type, u16 phy_data)
3244e97550SJiawen Wu {
3344e97550SJiawen Wu 	mdi_reg_t reg;
3444e97550SJiawen Wu 	mdi_reg_22_t reg22;
3544e97550SJiawen Wu 
3644e97550SJiawen Wu 	reg.device_type = device_type;
3744e97550SJiawen Wu 	reg.addr = reg_addr;
3844e97550SJiawen Wu 
3944e97550SJiawen Wu 	if (hw->phy.media_type == ngbe_media_type_fiber)
4044e97550SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
4144e97550SJiawen Wu 	else
4244e97550SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
4344e97550SJiawen Wu 
4444e97550SJiawen Wu 	ngbe_mdi_map_register(&reg, &reg22);
4544e97550SJiawen Wu 
4644e97550SJiawen Wu 	ngbe_write_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
4744e97550SJiawen Wu 
4844e97550SJiawen Wu 	return 0;
4944e97550SJiawen Wu }
5044e97550SJiawen Wu 
511c44384fSJiawen Wu s32 ngbe_check_phy_mode_mvl(struct ngbe_hw *hw)
521c44384fSJiawen Wu {
536dcfb19fSJiawen Wu 	u8 value = 0;
546dcfb19fSJiawen Wu 	u32 phy_mode = 0;
551c44384fSJiawen Wu 
56*91e64c0eSJiawen Wu 	ngbe_flash_read_dword(hw, 0xFF010, &phy_mode);
576dcfb19fSJiawen Wu 	value = (u8)(phy_mode >> (hw->bus.lan_id * 8));
586dcfb19fSJiawen Wu 
591c44384fSJiawen Wu 	if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_COPPER) {
601c44384fSJiawen Wu 		/* mode select to RGMII-to-copper */
611c44384fSJiawen Wu 		hw->phy.type = ngbe_phy_mvl;
621c44384fSJiawen Wu 		hw->phy.media_type = ngbe_media_type_copper;
631c44384fSJiawen Wu 		hw->mac.link_type = ngbe_link_copper;
641c44384fSJiawen Wu 	} else if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_FIBER) {
651c44384fSJiawen Wu 		/* mode select to RGMII-to-sfi */
661c44384fSJiawen Wu 		hw->phy.type = ngbe_phy_mvl_sfi;
671c44384fSJiawen Wu 		hw->phy.media_type = ngbe_media_type_fiber;
681c44384fSJiawen Wu 		hw->mac.link_type = ngbe_link_fiber;
691c44384fSJiawen Wu 	} else {
70c811e6a4SJiawen Wu 		DEBUGOUT("marvell 88E1512 mode %x is not supported.", value);
711c44384fSJiawen Wu 		return NGBE_ERR_DEVICE_NOT_SUPPORTED;
721c44384fSJiawen Wu 	}
731c44384fSJiawen Wu 
741c44384fSJiawen Wu 	return 0;
751c44384fSJiawen Wu }
761c44384fSJiawen Wu 
773518df57SJiawen Wu s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
783518df57SJiawen Wu {
793518df57SJiawen Wu 	s32 ret_val = 0;
803518df57SJiawen Wu 	u16 value = 0;
813518df57SJiawen Wu 	int i;
823518df57SJiawen Wu 
833518df57SJiawen Wu 	/* enable interrupts, only link status change and an done is allowed */
843518df57SJiawen Wu 	ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
853518df57SJiawen Wu 	ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
863518df57SJiawen Wu 	value &= ~MVL_RGM_CTL2_TTC;
873518df57SJiawen Wu 	value |= MVL_RGM_CTL2_RTC;
883518df57SJiawen Wu 	ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
893518df57SJiawen Wu 
903518df57SJiawen Wu 	hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
913518df57SJiawen Wu 	for (i = 0; i < 15; i++) {
923518df57SJiawen Wu 		ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
933518df57SJiawen Wu 		if (value & MVL_CTRL_RESET)
943518df57SJiawen Wu 			msleep(1);
953518df57SJiawen Wu 		else
963518df57SJiawen Wu 			break;
973518df57SJiawen Wu 	}
983518df57SJiawen Wu 
993518df57SJiawen Wu 	if (i == 15) {
100c811e6a4SJiawen Wu 		DEBUGOUT("phy reset exceeds maximum waiting period.");
1013518df57SJiawen Wu 		return NGBE_ERR_TIMEOUT;
1023518df57SJiawen Wu 	}
1033518df57SJiawen Wu 
1043518df57SJiawen Wu 	ret_val = hw->phy.reset_hw(hw);
1053518df57SJiawen Wu 	if (ret_val)
1063518df57SJiawen Wu 		return ret_val;
1073518df57SJiawen Wu 
1083518df57SJiawen Wu 	/* set LED2 to interrupt output and INTn active low */
1093518df57SJiawen Wu 	ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
1103518df57SJiawen Wu 	ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
1113518df57SJiawen Wu 	value |= MVL_LEDTCR_INTR_EN;
1123518df57SJiawen Wu 	value &= ~(MVL_LEDTCR_INTR_POL);
1133518df57SJiawen Wu 	ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
1143518df57SJiawen Wu 
1153518df57SJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl_sfi) {
1163518df57SJiawen Wu 		hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
1173518df57SJiawen Wu 		value &= ~MVL_CTRL1_INTR_POL;
1183518df57SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
1193518df57SJiawen Wu 	}
1203518df57SJiawen Wu 
1213518df57SJiawen Wu 	/* enable link status change and AN complete interrupts */
1223518df57SJiawen Wu 	value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
1233518df57SJiawen Wu 	hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
1243518df57SJiawen Wu 
125708ebe7dSJiawen Wu 	hw->phy.set_phy_power(hw, false);
1263518df57SJiawen Wu 
1273518df57SJiawen Wu 	return ret_val;
1283518df57SJiawen Wu }
1293518df57SJiawen Wu 
1303d0af706SJiawen Wu s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
1313d0af706SJiawen Wu 				bool autoneg_wait_to_complete)
1323d0af706SJiawen Wu {
1333d0af706SJiawen Wu 	u16 value_r4 = 0;
1343d0af706SJiawen Wu 	u16 value_r9 = 0;
1353d0af706SJiawen Wu 	u16 value;
1363d0af706SJiawen Wu 
1373d0af706SJiawen Wu 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
1383d0af706SJiawen Wu 
139fbd5ceb0SJiawen Wu 	if (hw->led_conf == 0xFFFF) {
140fbd5ceb0SJiawen Wu 		/* LED control */
141fbd5ceb0SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
142fbd5ceb0SJiawen Wu 		ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
143fbd5ceb0SJiawen Wu 		value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
144fbd5ceb0SJiawen Wu 		value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
145fbd5ceb0SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
146fbd5ceb0SJiawen Wu 		ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
147fbd5ceb0SJiawen Wu 		value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
148fbd5ceb0SJiawen Wu 		value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
149fbd5ceb0SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
150fbd5ceb0SJiawen Wu 	}
151fbd5ceb0SJiawen Wu 
1523d0af706SJiawen Wu 	hw->phy.autoneg_advertised = 0;
1533d0af706SJiawen Wu 
1543d0af706SJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl) {
1551c44384fSJiawen Wu 		if (!hw->mac.autoneg) {
1561c44384fSJiawen Wu 			switch (speed) {
1571c44384fSJiawen Wu 			case NGBE_LINK_SPEED_1GB_FULL:
1581c44384fSJiawen Wu 				value = MVL_CTRL_SPEED_SELECT1;
1591c44384fSJiawen Wu 				break;
1601c44384fSJiawen Wu 			case NGBE_LINK_SPEED_100M_FULL:
1611c44384fSJiawen Wu 				value = MVL_CTRL_SPEED_SELECT0;
1621c44384fSJiawen Wu 				break;
1631c44384fSJiawen Wu 			case NGBE_LINK_SPEED_10M_FULL:
1641c44384fSJiawen Wu 				value = 0;
1651c44384fSJiawen Wu 				break;
1661c44384fSJiawen Wu 			default:
1671c44384fSJiawen Wu 				value = MVL_CTRL_SPEED_SELECT0 |
1681c44384fSJiawen Wu 					MVL_CTRL_SPEED_SELECT1;
169c811e6a4SJiawen Wu 				DEBUGOUT("unknown speed = 0x%x.", speed);
1701c44384fSJiawen Wu 				break;
1711c44384fSJiawen Wu 			}
1721c44384fSJiawen Wu 			/* duplex full */
1731c44384fSJiawen Wu 			value |= MVL_CTRL_DUPLEX | MVL_CTRL_RESET;
1741c44384fSJiawen Wu 			ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
1751c44384fSJiawen Wu 
1761c44384fSJiawen Wu 			goto skip_an;
1771c44384fSJiawen Wu 		}
1783d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_1GB_FULL) {
1793d0af706SJiawen Wu 			value_r9 |= MVL_PHY_1000BASET_FULL;
1803d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
1813d0af706SJiawen Wu 		}
1823d0af706SJiawen Wu 
1833d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_100M_FULL) {
1843d0af706SJiawen Wu 			value_r4 |= MVL_PHY_100BASET_FULL;
1853d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
1863d0af706SJiawen Wu 		}
1873d0af706SJiawen Wu 
1883d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_10M_FULL) {
1893d0af706SJiawen Wu 			value_r4 |= MVL_PHY_10BASET_FULL;
1903d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
1913d0af706SJiawen Wu 		}
1923d0af706SJiawen Wu 
1933d0af706SJiawen Wu 		hw->phy.read_reg(hw, MVL_ANA, 0, &value);
1943d0af706SJiawen Wu 		value &= ~(MVL_PHY_100BASET_FULL |
1953d0af706SJiawen Wu 			   MVL_PHY_100BASET_HALF |
1963d0af706SJiawen Wu 			   MVL_PHY_10BASET_FULL |
1973d0af706SJiawen Wu 			   MVL_PHY_10BASET_HALF);
1983d0af706SJiawen Wu 		value_r4 |= value;
1993d0af706SJiawen Wu 		hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
2003d0af706SJiawen Wu 
2013d0af706SJiawen Wu 		hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
2023d0af706SJiawen Wu 		value &= ~(MVL_PHY_1000BASET_FULL |
2033d0af706SJiawen Wu 			   MVL_PHY_1000BASET_HALF);
2043d0af706SJiawen Wu 		value_r9 |= value;
2053d0af706SJiawen Wu 		hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
206f1268369SJiawen Wu 
207f1268369SJiawen Wu 		value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE |
208f1268369SJiawen Wu 			MVL_CTRL_RESET | MVL_CTRL_DUPLEX;
209f1268369SJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
2103d0af706SJiawen Wu 	} else {
211708ebe7dSJiawen Wu 		hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
2123d0af706SJiawen Wu 
2133d0af706SJiawen Wu 		hw->phy.read_reg(hw, MVL_ANA, 0, &value);
2143d0af706SJiawen Wu 		value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
2153d0af706SJiawen Wu 		value |= MVL_PHY_1000BASEX_FULL;
2163d0af706SJiawen Wu 		hw->phy.write_reg(hw, MVL_ANA, 0, value);
2173d0af706SJiawen Wu 
218f1268369SJiawen Wu 		if (hw->mac.autoneg)
219f1268369SJiawen Wu 			value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE |
220f1268369SJiawen Wu 				MVL_CTRL_RESET | MVL_CTRL_DUPLEX |
221f1268369SJiawen Wu 				MVL_CTRL_SPEED_SELECT1;
222f1268369SJiawen Wu 		else
223f1268369SJiawen Wu 			value = MVL_CTRL_RESET | MVL_CTRL_DUPLEX |
224f1268369SJiawen Wu 				MVL_CTRL_SPEED_SELECT1;
2251c44384fSJiawen Wu 		ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
226f1268369SJiawen Wu 	}
2271c44384fSJiawen Wu 
2281c44384fSJiawen Wu skip_an:
229708ebe7dSJiawen Wu 	hw->phy.set_phy_power(hw, true);
2303d0af706SJiawen Wu 
2313d0af706SJiawen Wu 	hw->phy.read_reg(hw, MVL_INTR, 0, &value);
2323d0af706SJiawen Wu 
2333d0af706SJiawen Wu 	return 0;
2343d0af706SJiawen Wu }
2353d0af706SJiawen Wu 
23644e97550SJiawen Wu s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
23744e97550SJiawen Wu {
23844e97550SJiawen Wu 	u32 i;
23944e97550SJiawen Wu 	u16 ctrl = 0;
24044e97550SJiawen Wu 	s32 status = 0;
24144e97550SJiawen Wu 
24244e97550SJiawen Wu 	if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
24344e97550SJiawen Wu 		return NGBE_ERR_PHY_TYPE;
24444e97550SJiawen Wu 
24544e97550SJiawen Wu 	/* select page 18 reg 20 */
24644e97550SJiawen Wu 	status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
24744e97550SJiawen Wu 
24844e97550SJiawen Wu 	/* mode select to RGMII-to-copper or RGMII-to-sfi*/
24944e97550SJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl)
25044e97550SJiawen Wu 		ctrl = MVL_GEN_CTL_MODE_COPPER;
25144e97550SJiawen Wu 	else
25244e97550SJiawen Wu 		ctrl = MVL_GEN_CTL_MODE_FIBER;
25344e97550SJiawen Wu 	status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
25444e97550SJiawen Wu 	/* mode reset */
25544e97550SJiawen Wu 	ctrl |= MVL_GEN_CTL_RESET;
25644e97550SJiawen Wu 	status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
25744e97550SJiawen Wu 
25844e97550SJiawen Wu 	for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
25944e97550SJiawen Wu 		status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
26044e97550SJiawen Wu 		if (!(ctrl & MVL_GEN_CTL_RESET))
26144e97550SJiawen Wu 			break;
26244e97550SJiawen Wu 		msleep(1);
26344e97550SJiawen Wu 	}
26444e97550SJiawen Wu 
26544e97550SJiawen Wu 	if (i == MVL_PHY_RST_WAIT_PERIOD) {
266c811e6a4SJiawen Wu 		DEBUGOUT("PHY reset polling failed to complete.");
26744e97550SJiawen Wu 		return NGBE_ERR_RESET_FAILED;
26844e97550SJiawen Wu 	}
26944e97550SJiawen Wu 
27044e97550SJiawen Wu 	return status;
27144e97550SJiawen Wu }
27244e97550SJiawen Wu 
273f40e9f0eSJiawen Wu s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
274f40e9f0eSJiawen Wu {
275f40e9f0eSJiawen Wu 	u16 value;
276f40e9f0eSJiawen Wu 	s32 status = 0;
277f40e9f0eSJiawen Wu 
278f40e9f0eSJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl) {
279f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
280f40e9f0eSJiawen Wu 		value &= MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE;
281f40e9f0eSJiawen Wu 		*pause_bit = (u8)(value >> 10);
282f40e9f0eSJiawen Wu 	} else {
283f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
284f40e9f0eSJiawen Wu 		value &= MVL_FANA_PAUSE_MASK;
285f40e9f0eSJiawen Wu 		*pause_bit = (u8)(value >> 7);
286f40e9f0eSJiawen Wu 	}
287f40e9f0eSJiawen Wu 
288f40e9f0eSJiawen Wu 	return status;
289f40e9f0eSJiawen Wu }
290f40e9f0eSJiawen Wu 
291f40e9f0eSJiawen Wu s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
292f40e9f0eSJiawen Wu {
293f40e9f0eSJiawen Wu 	u16 value;
294f40e9f0eSJiawen Wu 	s32 status = 0;
295f40e9f0eSJiawen Wu 
296f40e9f0eSJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl) {
297f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
298f40e9f0eSJiawen Wu 		value &= MVL_CLPAR_ASM_PAUSE | MVL_CLPAR_PAUSE;
299f40e9f0eSJiawen Wu 		*pause_bit = (u8)(value >> 10);
300f40e9f0eSJiawen Wu 	} else {
301f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
302f40e9f0eSJiawen Wu 		value &= MVL_FLPAR_PAUSE_MASK;
303f40e9f0eSJiawen Wu 		*pause_bit = (u8)(value >> 7);
304f40e9f0eSJiawen Wu 	}
305f40e9f0eSJiawen Wu 
306f40e9f0eSJiawen Wu 	return status;
307f40e9f0eSJiawen Wu }
308f40e9f0eSJiawen Wu 
309f40e9f0eSJiawen Wu s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit)
310f40e9f0eSJiawen Wu {
311f40e9f0eSJiawen Wu 	u16 value;
312f40e9f0eSJiawen Wu 	s32 status = 0;
313f40e9f0eSJiawen Wu 
314f40e9f0eSJiawen Wu 	if (hw->phy.type == ngbe_phy_mvl) {
315f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
316f40e9f0eSJiawen Wu 		value &= ~(MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE);
317f40e9f0eSJiawen Wu 	} else {
318f40e9f0eSJiawen Wu 		status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
319f40e9f0eSJiawen Wu 		value &= ~MVL_FANA_PAUSE_MASK;
320f40e9f0eSJiawen Wu 	}
321f40e9f0eSJiawen Wu 
322f40e9f0eSJiawen Wu 	value |= pause_bit;
323f40e9f0eSJiawen Wu 	status = hw->phy.write_reg(hw, MVL_ANA, 0, value);
324f40e9f0eSJiawen Wu 
325f40e9f0eSJiawen Wu 	return status;
326f40e9f0eSJiawen Wu }
327f40e9f0eSJiawen Wu 
3283d0af706SJiawen Wu s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
3293d0af706SJiawen Wu 		u32 *speed, bool *link_up)
3303d0af706SJiawen Wu {
3313d0af706SJiawen Wu 	s32 status = 0;
3323d0af706SJiawen Wu 	u16 phy_link = 0;
3333d0af706SJiawen Wu 	u16 phy_speed = 0;
3343d0af706SJiawen Wu 	u16 phy_data = 0;
3353d0af706SJiawen Wu 	u16 insr = 0;
3363d0af706SJiawen Wu 
3373d0af706SJiawen Wu 	/* Initialize speed and link to default case */
3383d0af706SJiawen Wu 	*link_up = false;
3393d0af706SJiawen Wu 	*speed = NGBE_LINK_SPEED_UNKNOWN;
3403d0af706SJiawen Wu 
3413d0af706SJiawen Wu 	hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
3423d0af706SJiawen Wu 
3433d0af706SJiawen Wu 	/*
3443d0af706SJiawen Wu 	 * Check current speed and link status of the PHY register.
3453d0af706SJiawen Wu 	 * This is a vendor specific register and may have to
3463d0af706SJiawen Wu 	 * be changed for other copper PHYs.
3473d0af706SJiawen Wu 	 */
3483d0af706SJiawen Wu 	status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
3493d0af706SJiawen Wu 	phy_link = phy_data & MVL_PHYSR_LINK;
3503d0af706SJiawen Wu 	phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
3513d0af706SJiawen Wu 
3523d0af706SJiawen Wu 	if (phy_link == MVL_PHYSR_LINK) {
3533d0af706SJiawen Wu 		*link_up = true;
3543d0af706SJiawen Wu 
3553d0af706SJiawen Wu 		if (phy_speed == MVL_PHYSR_SPEED_1000M)
3563d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_1GB_FULL;
3573d0af706SJiawen Wu 		else if (phy_speed == MVL_PHYSR_SPEED_100M)
3583d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_100M_FULL;
3593d0af706SJiawen Wu 		else if (phy_speed == MVL_PHYSR_SPEED_10M)
3603d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_10M_FULL;
3613d0af706SJiawen Wu 	}
3623d0af706SJiawen Wu 
3633d0af706SJiawen Wu 	return status;
3643d0af706SJiawen Wu }
3653d0af706SJiawen Wu 
366708ebe7dSJiawen Wu s32 ngbe_set_phy_power_mvl(struct ngbe_hw *hw, bool on)
367708ebe7dSJiawen Wu {
368708ebe7dSJiawen Wu 	u16 value = 0;
369708ebe7dSJiawen Wu 
370708ebe7dSJiawen Wu 	hw->phy.read_reg(hw, MVL_CTRL, 0, &value);
371708ebe7dSJiawen Wu 	if (on)
372708ebe7dSJiawen Wu 		value &= ~MVL_CTRL_PWDN;
373708ebe7dSJiawen Wu 	else
374708ebe7dSJiawen Wu 		value |= MVL_CTRL_PWDN;
375708ebe7dSJiawen Wu 	hw->phy.write_reg(hw, MVL_CTRL, 0, value);
376708ebe7dSJiawen Wu 
377708ebe7dSJiawen Wu 	return 0;
378708ebe7dSJiawen Wu }
379