xref: /dpdk/drivers/net/ngbe/base/ngbe_phy_rtl.c (revision fbd5ceb0eff0dbb67127caddddd40d35dd7e926c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  */
4 
5 #include "ngbe_phy_rtl.h"
6 
7 s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw,
8 		u32 reg_addr, u32 device_type, u16 *phy_data)
9 {
10 	mdi_reg_t reg;
11 	mdi_reg_22_t reg22;
12 
13 	reg.device_type = device_type;
14 	reg.addr = reg_addr;
15 	ngbe_mdi_map_register(&reg, &reg22);
16 
17 	wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
18 	*phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
19 
20 	return 0;
21 }
22 
23 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
24 		u32 reg_addr, u32 device_type, u16 phy_data)
25 {
26 	mdi_reg_t reg;
27 	mdi_reg_22_t reg22;
28 
29 	reg.device_type = device_type;
30 	reg.addr = reg_addr;
31 	ngbe_mdi_map_register(&reg, &reg22);
32 
33 	wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
34 	wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
35 
36 	return 0;
37 }
38 
39 static void ngbe_phy_led_ctrl_rtl(struct ngbe_hw *hw)
40 {
41 	u16 value = 0;
42 
43 	if (hw->led_conf != 0xFFFF)
44 		value = hw->led_conf & 0xFFFF;
45 	else
46 		value = 0x205B;
47 
48 	hw->phy.write_reg(hw, RTL_LCR, 0xd04, value);
49 	hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
50 
51 	hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &value);
52 	if (hw->led_conf != 0xFFFF) {
53 		value &= ~0x73;
54 		value |= hw->led_conf >> 16;
55 	} else {
56 		value &= 0xFFFC;
57 		/*act led blinking mode set to 60ms*/
58 		value |= 0x2;
59 	}
60 	hw->phy.write_reg(hw, RTL_LPCR, 0xd04, value);
61 }
62 
63 s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
64 {
65 	int i;
66 	u16 value = 0;
67 
68 	/* enable interrupts, only link status change and an done is allowed */
69 	value = RTL_INER_LSC | RTL_INER_ANC;
70 	hw->phy.write_reg(hw, RTL_INER, 0xa42, value);
71 
72 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
73 
74 	for (i = 0; i < 15; i++) {
75 		if (!rd32m(hw, NGBE_STAT,
76 			NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
77 			break;
78 
79 		msec_delay(10);
80 	}
81 	if (i == 15) {
82 		DEBUGOUT("GPhy reset exceeds maximum times.\n");
83 		return NGBE_ERR_PHY_TIMEOUT;
84 	}
85 
86 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE);
87 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
88 	if (!(value & RTL_SCR_EFUSE)) {
89 		DEBUGOUT("Write EFUSE failed.\n");
90 		return NGBE_ERR_PHY_TIMEOUT;
91 	}
92 
93 	for (i = 0; i < 1000; i++) {
94 		hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
95 		if (value & RTL_INSR_ACCESS)
96 			break;
97 		msec_delay(1);
98 	}
99 	if (i == 1000)
100 		DEBUGOUT("PHY wait mdio 1 access timeout.\n");
101 
102 
103 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI);
104 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
105 	if (!(value & RTL_SCR_EXTINI)) {
106 		DEBUGOUT("Write EXIINI failed.\n");
107 		return NGBE_ERR_PHY_TIMEOUT;
108 	}
109 
110 	for (i = 0; i < 1000; i++) {
111 		hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
112 		if (value & RTL_INSR_ACCESS)
113 			break;
114 		msec_delay(1);
115 	}
116 	if (i == 1000)
117 		DEBUGOUT("PHY wait mdio 2 access timeout.\n");
118 
119 	for (i = 0; i < 1000; i++) {
120 		hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value);
121 		if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON)
122 			break;
123 		msec_delay(1);
124 	}
125 	if (i == 1000)
126 		return NGBE_ERR_PHY_TIMEOUT;
127 
128 	return 0;
129 }
130 
131 /**
132  *  ngbe_setup_phy_link_rtl - Set and restart auto-neg
133  *  @hw: pointer to hardware structure
134  *
135  *  Restart auto-negotiation and PHY and waits for completion.
136  **/
137 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
138 		u32 speed, bool autoneg_wait_to_complete)
139 {
140 	u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
141 	u16 value = 0;
142 
143 	DEBUGFUNC("ngbe_setup_phy_link_rtl");
144 
145 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
146 
147 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
148 
149 	if (!hw->mac.autoneg) {
150 		hw->phy.reset_hw(hw);
151 
152 		switch (speed) {
153 		case NGBE_LINK_SPEED_1GB_FULL:
154 			value = RTL_BMCR_SPEED_SELECT1;
155 			break;
156 		case NGBE_LINK_SPEED_100M_FULL:
157 			value = RTL_BMCR_SPEED_SELECT0;
158 			break;
159 		case NGBE_LINK_SPEED_10M_FULL:
160 			value = 0;
161 			break;
162 		default:
163 			value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
164 			DEBUGOUT("unknown speed = 0x%x.\n", speed);
165 			break;
166 		}
167 		/* duplex full */
168 		value |= RTL_BMCR_DUPLEX;
169 		hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
170 
171 		goto skip_an;
172 	}
173 
174 	/*
175 	 * Clear autoneg_advertised and set new values based on input link
176 	 * speed.
177 	 */
178 	if (speed) {
179 		hw->phy.autoneg_advertised = 0;
180 
181 		if (speed & NGBE_LINK_SPEED_1GB_FULL)
182 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
183 
184 		if (speed & NGBE_LINK_SPEED_100M_FULL)
185 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
186 
187 		if (speed & NGBE_LINK_SPEED_10M_FULL)
188 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
189 	}
190 
191 	/* disable 10/100M Half Duplex */
192 	hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
193 	autoneg_reg &= 0xFF5F;
194 	hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
195 
196 	/* set advertise enable according to input speed */
197 	if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
198 		hw->phy.read_reg(hw, RTL_GBCR,
199 			RTL_DEV_ZERO, &autoneg_reg);
200 		autoneg_reg &= ~RTL_GBCR_1000F;
201 		hw->phy.write_reg(hw, RTL_GBCR,
202 			RTL_DEV_ZERO, autoneg_reg);
203 	} else {
204 		hw->phy.read_reg(hw, RTL_GBCR,
205 			RTL_DEV_ZERO, &autoneg_reg);
206 		autoneg_reg |= RTL_GBCR_1000F;
207 		hw->phy.write_reg(hw, RTL_GBCR,
208 			RTL_DEV_ZERO, autoneg_reg);
209 	}
210 
211 	if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
212 		hw->phy.read_reg(hw, RTL_ANAR,
213 			RTL_DEV_ZERO, &autoneg_reg);
214 		autoneg_reg &= ~RTL_ANAR_100F;
215 		autoneg_reg &= ~RTL_ANAR_100H;
216 		hw->phy.write_reg(hw, RTL_ANAR,
217 			RTL_DEV_ZERO, autoneg_reg);
218 	} else {
219 		hw->phy.read_reg(hw, RTL_ANAR,
220 			RTL_DEV_ZERO, &autoneg_reg);
221 		autoneg_reg |= RTL_ANAR_100F;
222 		hw->phy.write_reg(hw, RTL_ANAR,
223 			RTL_DEV_ZERO, autoneg_reg);
224 	}
225 
226 	if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
227 		hw->phy.read_reg(hw, RTL_ANAR,
228 			RTL_DEV_ZERO, &autoneg_reg);
229 		autoneg_reg &= ~RTL_ANAR_10F;
230 		autoneg_reg &= ~RTL_ANAR_10H;
231 		hw->phy.write_reg(hw, RTL_ANAR,
232 			RTL_DEV_ZERO, autoneg_reg);
233 	} else {
234 		hw->phy.read_reg(hw, RTL_ANAR,
235 			RTL_DEV_ZERO, &autoneg_reg);
236 		autoneg_reg |= RTL_ANAR_10F;
237 		hw->phy.write_reg(hw, RTL_ANAR,
238 			RTL_DEV_ZERO, autoneg_reg);
239 	}
240 
241 	/* restart AN and wait AN done interrupt */
242 	autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
243 	hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
244 
245 skip_an:
246 	ngbe_phy_led_ctrl_rtl(hw);
247 
248 	return 0;
249 }
250 
251 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
252 {
253 	u16 value = 0;
254 	s32 status = 0;
255 
256 	DEBUGFUNC("ngbe_reset_phy_rtl");
257 
258 	value |= RTL_BMCR_RESET;
259 	status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
260 
261 	msec_delay(5);
262 
263 	return status;
264 }
265 
266 s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
267 {
268 	u16 value;
269 	s32 status = 0;
270 
271 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
272 	value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE;
273 	*pause_bit = (u8)(value >> 10);
274 	return status;
275 }
276 
277 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
278 {
279 	u16 value;
280 	s32 status = 0;
281 
282 	status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
283 
284 	status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value);
285 	value = value & RTL_BMSR_ANC;
286 
287 	/* if AN complete then check lp adv pause */
288 	status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value);
289 	value &= RTL_ANLPAR_LP;
290 	*pause_bit = (u8)(value >> 10);
291 	return status;
292 }
293 
294 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit)
295 {
296 	u16 value;
297 	s32 status = 0;
298 
299 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
300 	value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE);
301 	value |= pause_bit;
302 
303 	status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value);
304 
305 	return status;
306 }
307 
308 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
309 {
310 	s32 status = 0;
311 	u16 phy_link = 0;
312 	u16 phy_speed = 0;
313 	u16 phy_data = 0;
314 	u16 insr = 0;
315 
316 	DEBUGFUNC("ngbe_check_phy_link_rtl");
317 
318 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
319 
320 	/* Initialize speed and link to default case */
321 	*link_up = false;
322 	*speed = NGBE_LINK_SPEED_UNKNOWN;
323 
324 	/*
325 	 * Check current speed and link status of the PHY register.
326 	 * This is a vendor specific register and may have to
327 	 * be changed for other copper PHYs.
328 	 */
329 	status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
330 	phy_link = phy_data & RTL_PHYSR_RTLS;
331 	phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
332 	if (phy_link == RTL_PHYSR_RTLS) {
333 		*link_up = true;
334 
335 		if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
336 			*speed = NGBE_LINK_SPEED_1GB_FULL;
337 		else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
338 			*speed = NGBE_LINK_SPEED_100M_FULL;
339 		else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
340 			*speed = NGBE_LINK_SPEED_10M_FULL;
341 	}
342 
343 	return status;
344 }
345 
346