xref: /dpdk/drivers/net/ngbe/base/ngbe_phy_rtl.c (revision 5f1ab0d529fce519e53d3bda32e1eeed4d61bed7)
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_rtl.h"
644e97550SJiawen Wu 
ngbe_read_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)744e97550SJiawen Wu s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw,
844e97550SJiawen Wu 		u32 reg_addr, u32 device_type, u16 *phy_data)
944e97550SJiawen Wu {
1044e97550SJiawen Wu 	mdi_reg_t reg;
1144e97550SJiawen Wu 	mdi_reg_22_t reg22;
1244e97550SJiawen Wu 
1344e97550SJiawen Wu 	reg.device_type = device_type;
1444e97550SJiawen Wu 	reg.addr = reg_addr;
1544e97550SJiawen Wu 	ngbe_mdi_map_register(&reg, &reg22);
1644e97550SJiawen Wu 
17696a8211SJiawen Wu 	if (!(reg22.page == 0xa43 &&
18696a8211SJiawen Wu 			(reg22.addr == 0x1a || reg22.addr == 0x1d)))
1944e97550SJiawen Wu 		wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
2044e97550SJiawen Wu 	*phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
2144e97550SJiawen Wu 
2244e97550SJiawen Wu 	return 0;
2344e97550SJiawen Wu }
2444e97550SJiawen Wu 
ngbe_write_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)2544e97550SJiawen Wu s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
2644e97550SJiawen Wu 		u32 reg_addr, u32 device_type, u16 phy_data)
2744e97550SJiawen Wu {
2844e97550SJiawen Wu 	mdi_reg_t reg;
2944e97550SJiawen Wu 	mdi_reg_22_t reg22;
3044e97550SJiawen Wu 
3144e97550SJiawen Wu 	reg.device_type = device_type;
3244e97550SJiawen Wu 	reg.addr = reg_addr;
3344e97550SJiawen Wu 	ngbe_mdi_map_register(&reg, &reg22);
3444e97550SJiawen Wu 
35696a8211SJiawen Wu 	if (!(reg22.page == 0xa43 &&
36696a8211SJiawen Wu 			(reg22.addr == 0x1a || reg22.addr == 0x1d)))
3744e97550SJiawen Wu 		wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
3844e97550SJiawen Wu 	wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
3944e97550SJiawen Wu 
4044e97550SJiawen Wu 	return 0;
4144e97550SJiawen Wu }
4244e97550SJiawen Wu 
ngbe_phy_led_ctrl_rtl(struct ngbe_hw * hw)43fbd5ceb0SJiawen Wu static void ngbe_phy_led_ctrl_rtl(struct ngbe_hw *hw)
44fbd5ceb0SJiawen Wu {
45fbd5ceb0SJiawen Wu 	u16 value = 0;
46fbd5ceb0SJiawen Wu 
47fbd5ceb0SJiawen Wu 	if (hw->led_conf != 0xFFFF)
48fbd5ceb0SJiawen Wu 		value = hw->led_conf & 0xFFFF;
49fbd5ceb0SJiawen Wu 	else
50fbd5ceb0SJiawen Wu 		value = 0x205B;
51fbd5ceb0SJiawen Wu 
52fbd5ceb0SJiawen Wu 	hw->phy.write_reg(hw, RTL_LCR, 0xd04, value);
53fbd5ceb0SJiawen Wu 	hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
54fbd5ceb0SJiawen Wu 
55fbd5ceb0SJiawen Wu 	hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &value);
56fbd5ceb0SJiawen Wu 	if (hw->led_conf != 0xFFFF) {
57fbd5ceb0SJiawen Wu 		value &= ~0x73;
58fbd5ceb0SJiawen Wu 		value |= hw->led_conf >> 16;
59fbd5ceb0SJiawen Wu 	} else {
60fbd5ceb0SJiawen Wu 		value &= 0xFFFC;
61fbd5ceb0SJiawen Wu 		/*act led blinking mode set to 60ms*/
62fbd5ceb0SJiawen Wu 		value |= 0x2;
63fbd5ceb0SJiawen Wu 	}
64fbd5ceb0SJiawen Wu 	hw->phy.write_reg(hw, RTL_LPCR, 0xd04, value);
65fbd5ceb0SJiawen Wu }
66fbd5ceb0SJiawen Wu 
ngbe_wait_mdio_access_on(struct ngbe_hw * hw)67696a8211SJiawen Wu static s32 ngbe_wait_mdio_access_on(struct ngbe_hw *hw)
68696a8211SJiawen Wu {
69696a8211SJiawen Wu 	int i;
70696a8211SJiawen Wu 	u16 val = 0;
71696a8211SJiawen Wu 
72696a8211SJiawen Wu 	for (i = 0; i < 100; i++) {
73696a8211SJiawen Wu 		/* irq status */
74696a8211SJiawen Wu 		hw->phy.read_reg(hw, RTL_INSR, 0xa43, &val);
75696a8211SJiawen Wu 		if (val & RTL_INSR_ACCESS)
76696a8211SJiawen Wu 			break;
77696a8211SJiawen Wu 		msec_delay(1);
78696a8211SJiawen Wu 	}
79696a8211SJiawen Wu 
80696a8211SJiawen Wu 	if (i == 100) {
81696a8211SJiawen Wu 		DEBUGOUT("wait_mdio_access_on timeout");
82696a8211SJiawen Wu 		return NGBE_ERR_PHY_TIMEOUT;
83696a8211SJiawen Wu 	}
84696a8211SJiawen Wu 
85696a8211SJiawen Wu 	return 0;
86696a8211SJiawen Wu }
87696a8211SJiawen Wu 
ngbe_efuse_calibration(struct ngbe_hw * hw)88696a8211SJiawen Wu static void ngbe_efuse_calibration(struct ngbe_hw *hw)
89696a8211SJiawen Wu {
90696a8211SJiawen Wu 	u32 efuse[2];
91696a8211SJiawen Wu 
92696a8211SJiawen Wu 	ngbe_wait_mdio_access_on(hw);
93696a8211SJiawen Wu 
94696a8211SJiawen Wu 	efuse[0] = hw->gphy_efuse[0];
95696a8211SJiawen Wu 	efuse[1] = hw->gphy_efuse[1];
96696a8211SJiawen Wu 
97696a8211SJiawen Wu 	if (!efuse[0] && !efuse[1]) {
98696a8211SJiawen Wu 		efuse[0] = 0xFFFFFFFF;
99696a8211SJiawen Wu 		efuse[1] = 0xFFFFFFFF;
100696a8211SJiawen Wu 	}
101696a8211SJiawen Wu 
102696a8211SJiawen Wu 	/* calibration */
103696a8211SJiawen Wu 	efuse[0] |= 0xF0000100;
104696a8211SJiawen Wu 	efuse[1] |= 0xFF807FFF;
105696a8211SJiawen Wu 	DEBUGOUT("port %d efuse[0] = %08x, efuse[1] = %08x",
106696a8211SJiawen Wu 		hw->bus.lan_id, efuse[0], efuse[1]);
107696a8211SJiawen Wu 
108696a8211SJiawen Wu 	/* EODR, Efuse Output Data Register */
109696a8211SJiawen Wu 	hw->phy.write_reg(hw, 16, 0xa46, (efuse[0] >>  0) & 0xFFFF);
110696a8211SJiawen Wu 	hw->phy.write_reg(hw, 17, 0xa46, (efuse[0] >> 16) & 0xFFFF);
111696a8211SJiawen Wu 	hw->phy.write_reg(hw, 18, 0xa46, (efuse[1] >>  0) & 0xFFFF);
112696a8211SJiawen Wu 	hw->phy.write_reg(hw, 19, 0xa46, (efuse[1] >> 16) & 0xFFFF);
113696a8211SJiawen Wu }
114696a8211SJiawen Wu 
ngbe_init_phy_rtl(struct ngbe_hw * hw)1153518df57SJiawen Wu s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
1163518df57SJiawen Wu {
1173518df57SJiawen Wu 	int i;
1183518df57SJiawen Wu 	u16 value = 0;
1193518df57SJiawen Wu 
120696a8211SJiawen Wu 	hw->init_phy = true;
121696a8211SJiawen Wu 	msec_delay(1);
1223518df57SJiawen Wu 
1236f05dc6cSJiawen Wu 	hw->phy.set_phy_power(hw, true);
1246f05dc6cSJiawen Wu 
1253518df57SJiawen Wu 	for (i = 0; i < 15; i++) {
1263518df57SJiawen Wu 		if (!rd32m(hw, NGBE_STAT,
1273518df57SJiawen Wu 			NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
1283518df57SJiawen Wu 			break;
1293518df57SJiawen Wu 
1303518df57SJiawen Wu 		msec_delay(10);
1313518df57SJiawen Wu 	}
1323518df57SJiawen Wu 	if (i == 15) {
133c811e6a4SJiawen Wu 		DEBUGOUT("GPhy reset exceeds maximum times.");
1343518df57SJiawen Wu 		return NGBE_ERR_PHY_TIMEOUT;
1353518df57SJiawen Wu 	}
1363518df57SJiawen Wu 
137696a8211SJiawen Wu 	ngbe_efuse_calibration(hw);
138696a8211SJiawen Wu 
13991bc12c5SJiawen Wu 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE);
14091bc12c5SJiawen Wu 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
14191bc12c5SJiawen Wu 	if (!(value & RTL_SCR_EFUSE)) {
142c811e6a4SJiawen Wu 		DEBUGOUT("Write EFUSE failed.");
14391bc12c5SJiawen Wu 		return NGBE_ERR_PHY_TIMEOUT;
1443518df57SJiawen Wu 	}
1453518df57SJiawen Wu 
146696a8211SJiawen Wu 	ngbe_wait_mdio_access_on(hw);
14791bc12c5SJiawen Wu 
148696a8211SJiawen Wu 	hw->phy.write_reg(hw, 27, 0xa42, 0x8011);
149696a8211SJiawen Wu 	hw->phy.write_reg(hw, 28, 0xa42, 0x5737);
1503518df57SJiawen Wu 
15155ff5045SJiawen Wu 	/* Disable fall to 100m if signal is not good */
15255ff5045SJiawen Wu 	hw->phy.read_reg(hw, 17, 0xa44, &value);
15355ff5045SJiawen Wu 	value &= ~0x8;
15455ff5045SJiawen Wu 	hw->phy.write_reg(hw, 17, 0xa44, value);
15555ff5045SJiawen Wu 
1563518df57SJiawen Wu 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI);
15791bc12c5SJiawen Wu 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
15891bc12c5SJiawen Wu 	if (!(value & RTL_SCR_EXTINI)) {
159c811e6a4SJiawen Wu 		DEBUGOUT("Write EXIINI failed.");
16091bc12c5SJiawen Wu 		return NGBE_ERR_PHY_TIMEOUT;
16191bc12c5SJiawen Wu 	}
16291bc12c5SJiawen Wu 
163696a8211SJiawen Wu 	ngbe_wait_mdio_access_on(hw);
1643518df57SJiawen Wu 
165696a8211SJiawen Wu 	for (i = 0; i < 100; i++) {
1663518df57SJiawen Wu 		hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value);
1673518df57SJiawen Wu 		if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON)
1683518df57SJiawen Wu 			break;
16991bc12c5SJiawen Wu 		msec_delay(1);
1703518df57SJiawen Wu 	}
171696a8211SJiawen Wu 	if (i == 100)
1723518df57SJiawen Wu 		return NGBE_ERR_PHY_TIMEOUT;
1733518df57SJiawen Wu 
174696a8211SJiawen Wu 	/* Disable EEE */
175696a8211SJiawen Wu 	hw->phy.write_reg(hw, 0x11, 0xa4b, 0x1110);
176696a8211SJiawen Wu 	hw->phy.write_reg(hw, 0xd, 0x0, 0x0007);
177696a8211SJiawen Wu 	hw->phy.write_reg(hw, 0xe, 0x0, 0x003c);
178696a8211SJiawen Wu 	hw->phy.write_reg(hw, 0xd, 0x0, 0x4007);
179696a8211SJiawen Wu 	hw->phy.write_reg(hw, 0xe, 0x0, 0x0000);
180696a8211SJiawen Wu 
181696a8211SJiawen Wu 	hw->init_phy = false;
182696a8211SJiawen Wu 
1833518df57SJiawen Wu 	return 0;
1843518df57SJiawen Wu }
1853518df57SJiawen Wu 
1863d0af706SJiawen Wu /**
1873d0af706SJiawen Wu  *  ngbe_setup_phy_link_rtl - Set and restart auto-neg
1883d0af706SJiawen Wu  *  @hw: pointer to hardware structure
1893d0af706SJiawen Wu  *
1903d0af706SJiawen Wu  *  Restart auto-negotiation and PHY and waits for completion.
1913d0af706SJiawen Wu  **/
ngbe_setup_phy_link_rtl(struct ngbe_hw * hw,u32 speed,bool autoneg_wait_to_complete)1923d0af706SJiawen Wu s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
1933d0af706SJiawen Wu 		u32 speed, bool autoneg_wait_to_complete)
1943d0af706SJiawen Wu {
1953d0af706SJiawen Wu 	u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
1963d0af706SJiawen Wu 	u16 value = 0;
1973d0af706SJiawen Wu 
1983d0af706SJiawen Wu 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
1993d0af706SJiawen Wu 
200696a8211SJiawen Wu 	hw->init_phy = true;
201696a8211SJiawen Wu 	msec_delay(1);
202696a8211SJiawen Wu 
2033d0af706SJiawen Wu 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
2043d0af706SJiawen Wu 
2053d0af706SJiawen Wu 	if (!hw->mac.autoneg) {
2063d0af706SJiawen Wu 		hw->phy.reset_hw(hw);
2073d0af706SJiawen Wu 
2083d0af706SJiawen Wu 		switch (speed) {
2093d0af706SJiawen Wu 		case NGBE_LINK_SPEED_1GB_FULL:
2103d0af706SJiawen Wu 			value = RTL_BMCR_SPEED_SELECT1;
2113d0af706SJiawen Wu 			break;
2123d0af706SJiawen Wu 		case NGBE_LINK_SPEED_100M_FULL:
2133d0af706SJiawen Wu 			value = RTL_BMCR_SPEED_SELECT0;
2143d0af706SJiawen Wu 			break;
2153d0af706SJiawen Wu 		case NGBE_LINK_SPEED_10M_FULL:
2163d0af706SJiawen Wu 			value = 0;
2173d0af706SJiawen Wu 			break;
2183d0af706SJiawen Wu 		default:
2193d0af706SJiawen Wu 			value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
220c811e6a4SJiawen Wu 			DEBUGOUT("unknown speed = 0x%x.", speed);
2213d0af706SJiawen Wu 			break;
2223d0af706SJiawen Wu 		}
2233d0af706SJiawen Wu 		/* duplex full */
2243d0af706SJiawen Wu 		value |= RTL_BMCR_DUPLEX;
2253d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
2263d0af706SJiawen Wu 
2273d0af706SJiawen Wu 		goto skip_an;
2283d0af706SJiawen Wu 	}
2293d0af706SJiawen Wu 
2303d0af706SJiawen Wu 	/*
2313d0af706SJiawen Wu 	 * Clear autoneg_advertised and set new values based on input link
2323d0af706SJiawen Wu 	 * speed.
2333d0af706SJiawen Wu 	 */
2343d0af706SJiawen Wu 	if (speed) {
2353d0af706SJiawen Wu 		hw->phy.autoneg_advertised = 0;
2363d0af706SJiawen Wu 
2373d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_1GB_FULL)
2383d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
2393d0af706SJiawen Wu 
2403d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_100M_FULL)
2413d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
2423d0af706SJiawen Wu 
2433d0af706SJiawen Wu 		if (speed & NGBE_LINK_SPEED_10M_FULL)
2443d0af706SJiawen Wu 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
2453d0af706SJiawen Wu 	}
2463d0af706SJiawen Wu 
2473d0af706SJiawen Wu 	/* disable 10/100M Half Duplex */
2483d0af706SJiawen Wu 	hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
2493d0af706SJiawen Wu 	autoneg_reg &= 0xFF5F;
2503d0af706SJiawen Wu 	hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
2513d0af706SJiawen Wu 
2523d0af706SJiawen Wu 	/* set advertise enable according to input speed */
2533d0af706SJiawen Wu 	if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
2543d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_GBCR,
2553d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2563d0af706SJiawen Wu 		autoneg_reg &= ~RTL_GBCR_1000F;
2573d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_GBCR,
2583d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2593d0af706SJiawen Wu 	} else {
2603d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_GBCR,
2613d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2623d0af706SJiawen Wu 		autoneg_reg |= RTL_GBCR_1000F;
2633d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_GBCR,
2643d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2653d0af706SJiawen Wu 	}
2663d0af706SJiawen Wu 
2673d0af706SJiawen Wu 	if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
2683d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_ANAR,
2693d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2703d0af706SJiawen Wu 		autoneg_reg &= ~RTL_ANAR_100F;
2713d0af706SJiawen Wu 		autoneg_reg &= ~RTL_ANAR_100H;
2723d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_ANAR,
2733d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2743d0af706SJiawen Wu 	} else {
2753d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_ANAR,
2763d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2773d0af706SJiawen Wu 		autoneg_reg |= RTL_ANAR_100F;
2783d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_ANAR,
2793d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2803d0af706SJiawen Wu 	}
2813d0af706SJiawen Wu 
2823d0af706SJiawen Wu 	if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
2833d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_ANAR,
2843d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2853d0af706SJiawen Wu 		autoneg_reg &= ~RTL_ANAR_10F;
2863d0af706SJiawen Wu 		autoneg_reg &= ~RTL_ANAR_10H;
2873d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_ANAR,
2883d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2893d0af706SJiawen Wu 	} else {
2903d0af706SJiawen Wu 		hw->phy.read_reg(hw, RTL_ANAR,
2913d0af706SJiawen Wu 			RTL_DEV_ZERO, &autoneg_reg);
2923d0af706SJiawen Wu 		autoneg_reg |= RTL_ANAR_10F;
2933d0af706SJiawen Wu 		hw->phy.write_reg(hw, RTL_ANAR,
2943d0af706SJiawen Wu 			RTL_DEV_ZERO, autoneg_reg);
2953d0af706SJiawen Wu 	}
2963d0af706SJiawen Wu 
2973d0af706SJiawen Wu 	/* restart AN and wait AN done interrupt */
298*5f1ab0d5SJiawen Wu 	if (!hw->ncsi_enabled)
2993d0af706SJiawen Wu 		autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
300*5f1ab0d5SJiawen Wu 	else
301*5f1ab0d5SJiawen Wu 		autoneg_reg = RTL_BMCR_ANE;
3023d0af706SJiawen Wu 	hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
3033d0af706SJiawen Wu 
3043d0af706SJiawen Wu skip_an:
305fbd5ceb0SJiawen Wu 	ngbe_phy_led_ctrl_rtl(hw);
3063d0af706SJiawen Wu 
307696a8211SJiawen Wu 	hw->init_phy = false;
308696a8211SJiawen Wu 
3093d0af706SJiawen Wu 	return 0;
3103d0af706SJiawen Wu }
3113d0af706SJiawen Wu 
ngbe_reset_phy_rtl(struct ngbe_hw * hw)31244e97550SJiawen Wu s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
31344e97550SJiawen Wu {
31491bc12c5SJiawen Wu 	u16 value = 0;
31544e97550SJiawen Wu 	s32 status = 0;
31644e97550SJiawen Wu 
31744e97550SJiawen Wu 	value |= RTL_BMCR_RESET;
31844e97550SJiawen Wu 	status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
31944e97550SJiawen Wu 
32091bc12c5SJiawen Wu 	msec_delay(5);
32144e97550SJiawen Wu 
32244e97550SJiawen Wu 	return status;
32344e97550SJiawen Wu }
32444e97550SJiawen Wu 
ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)325f40e9f0eSJiawen Wu s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
326f40e9f0eSJiawen Wu {
327f40e9f0eSJiawen Wu 	u16 value;
328f40e9f0eSJiawen Wu 	s32 status = 0;
329f40e9f0eSJiawen Wu 
330f40e9f0eSJiawen Wu 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
331f40e9f0eSJiawen Wu 	value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE;
332f40e9f0eSJiawen Wu 	*pause_bit = (u8)(value >> 10);
333f40e9f0eSJiawen Wu 	return status;
334f40e9f0eSJiawen Wu }
335f40e9f0eSJiawen Wu 
ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)336f40e9f0eSJiawen Wu s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
337f40e9f0eSJiawen Wu {
338f40e9f0eSJiawen Wu 	u16 value;
339f40e9f0eSJiawen Wu 	s32 status = 0;
340f40e9f0eSJiawen Wu 
341f40e9f0eSJiawen Wu 	status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
342f40e9f0eSJiawen Wu 
343f40e9f0eSJiawen Wu 	status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value);
344f40e9f0eSJiawen Wu 	value = value & RTL_BMSR_ANC;
345f40e9f0eSJiawen Wu 
346f40e9f0eSJiawen Wu 	/* if AN complete then check lp adv pause */
347f40e9f0eSJiawen Wu 	status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value);
348f40e9f0eSJiawen Wu 	value &= RTL_ANLPAR_LP;
349f40e9f0eSJiawen Wu 	*pause_bit = (u8)(value >> 10);
350f40e9f0eSJiawen Wu 	return status;
351f40e9f0eSJiawen Wu }
352f40e9f0eSJiawen Wu 
ngbe_set_phy_pause_adv_rtl(struct ngbe_hw * hw,u16 pause_bit)353f40e9f0eSJiawen Wu s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit)
354f40e9f0eSJiawen Wu {
355f40e9f0eSJiawen Wu 	u16 value;
356f40e9f0eSJiawen Wu 	s32 status = 0;
357f40e9f0eSJiawen Wu 
358f40e9f0eSJiawen Wu 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
359f40e9f0eSJiawen Wu 	value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE);
360f40e9f0eSJiawen Wu 	value |= pause_bit;
361f40e9f0eSJiawen Wu 
362f40e9f0eSJiawen Wu 	status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value);
363f40e9f0eSJiawen Wu 
364f40e9f0eSJiawen Wu 	return status;
365f40e9f0eSJiawen Wu }
366f40e9f0eSJiawen Wu 
ngbe_check_phy_link_rtl(struct ngbe_hw * hw,u32 * speed,bool * link_up)3673d0af706SJiawen Wu s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
3683d0af706SJiawen Wu {
3693d0af706SJiawen Wu 	s32 status = 0;
3703d0af706SJiawen Wu 	u16 phy_link = 0;
3713d0af706SJiawen Wu 	u16 phy_speed = 0;
3723d0af706SJiawen Wu 	u16 phy_data = 0;
3733d0af706SJiawen Wu 	u16 insr = 0;
3743d0af706SJiawen Wu 
375696a8211SJiawen Wu 	if (hw->init_phy)
376696a8211SJiawen Wu 		return -1;
377696a8211SJiawen Wu 
3783d0af706SJiawen Wu 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
3793d0af706SJiawen Wu 
3803d0af706SJiawen Wu 	/* Initialize speed and link to default case */
3813d0af706SJiawen Wu 	*link_up = false;
3823d0af706SJiawen Wu 	*speed = NGBE_LINK_SPEED_UNKNOWN;
3833d0af706SJiawen Wu 
3843d0af706SJiawen Wu 	/*
3853d0af706SJiawen Wu 	 * Check current speed and link status of the PHY register.
3863d0af706SJiawen Wu 	 * This is a vendor specific register and may have to
3873d0af706SJiawen Wu 	 * be changed for other copper PHYs.
3883d0af706SJiawen Wu 	 */
3893d0af706SJiawen Wu 	status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
3903d0af706SJiawen Wu 	phy_link = phy_data & RTL_PHYSR_RTLS;
3913d0af706SJiawen Wu 	phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
3923d0af706SJiawen Wu 	if (phy_link == RTL_PHYSR_RTLS) {
3933d0af706SJiawen Wu 		*link_up = true;
3943d0af706SJiawen Wu 
3953d0af706SJiawen Wu 		if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
3963d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_1GB_FULL;
3973d0af706SJiawen Wu 		else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
3983d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_100M_FULL;
3993d0af706SJiawen Wu 		else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
4003d0af706SJiawen Wu 			*speed = NGBE_LINK_SPEED_10M_FULL;
4013d0af706SJiawen Wu 	}
4023d0af706SJiawen Wu 
40321f702d5SJiawen Wu 	if (hw->lsc)
40421f702d5SJiawen Wu 		return status;
40521f702d5SJiawen Wu 
40621f702d5SJiawen Wu 	/*
40721f702d5SJiawen Wu 	 * Because of the slow speed of getting link state, RTL_PHYSR
40821f702d5SJiawen Wu 	 * may still be up while the actual link state is down.
40921f702d5SJiawen Wu 	 * So we read RTL_GBSR to get accurate state when speed is 1G
41021f702d5SJiawen Wu 	 * in polling mode.
41121f702d5SJiawen Wu 	 */
41221f702d5SJiawen Wu 	if (*speed == NGBE_LINK_SPEED_1GB_FULL) {
41321f702d5SJiawen Wu 		status = hw->phy.read_reg(hw, RTL_GBSR,
41421f702d5SJiawen Wu 				RTL_DEV_ZERO, &phy_data);
41521f702d5SJiawen Wu 		phy_link = phy_data & RTL_GBSR_LRS;
41621f702d5SJiawen Wu 
41721f702d5SJiawen Wu 		/* Only need to detect link down */
41821f702d5SJiawen Wu 		if (!phy_link) {
41921f702d5SJiawen Wu 			*link_up = false;
42021f702d5SJiawen Wu 			*speed = NGBE_LINK_SPEED_UNKNOWN;
42121f702d5SJiawen Wu 		}
42221f702d5SJiawen Wu 	}
4233d0af706SJiawen Wu 	return status;
4243d0af706SJiawen Wu }
4253d0af706SJiawen Wu 
ngbe_set_phy_power_rtl(struct ngbe_hw * hw,bool on)426abea8974SJiawen Wu s32 ngbe_set_phy_power_rtl(struct ngbe_hw *hw, bool on)
427abea8974SJiawen Wu {
428abea8974SJiawen Wu 	u16 value = 0;
429abea8974SJiawen Wu 
430abea8974SJiawen Wu 	hw->phy.read_reg(hw, RTL_BMCR, 0, &value);
431abea8974SJiawen Wu 	if (on)
432abea8974SJiawen Wu 		value &= ~RTL_BMCR_PWDN;
433abea8974SJiawen Wu 	else
434abea8974SJiawen Wu 		value |= RTL_BMCR_PWDN;
435abea8974SJiawen Wu 	hw->phy.write_reg(hw, RTL_BMCR, 0, value);
436abea8974SJiawen Wu 
437abea8974SJiawen Wu 	return 0;
438abea8974SJiawen Wu }
439