xref: /dpdk/drivers/net/ngbe/base/ngbe_phy_rtl.c (revision 5f1ab0d529fce519e53d3bda32e1eeed4d61bed7)
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 
ngbe_read_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 * phy_data)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 	if (!(reg22.page == 0xa43 &&
18 			(reg22.addr == 0x1a || reg22.addr == 0x1d)))
19 		wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
20 	*phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr));
21 
22 	return 0;
23 }
24 
ngbe_write_phy_reg_rtl(struct ngbe_hw * hw,u32 reg_addr,u32 device_type,u16 phy_data)25 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw,
26 		u32 reg_addr, u32 device_type, u16 phy_data)
27 {
28 	mdi_reg_t reg;
29 	mdi_reg_22_t reg22;
30 
31 	reg.device_type = device_type;
32 	reg.addr = reg_addr;
33 	ngbe_mdi_map_register(&reg, &reg22);
34 
35 	if (!(reg22.page == 0xa43 &&
36 			(reg22.addr == 0x1a || reg22.addr == 0x1d)))
37 		wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page);
38 	wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data);
39 
40 	return 0;
41 }
42 
ngbe_phy_led_ctrl_rtl(struct ngbe_hw * hw)43 static void ngbe_phy_led_ctrl_rtl(struct ngbe_hw *hw)
44 {
45 	u16 value = 0;
46 
47 	if (hw->led_conf != 0xFFFF)
48 		value = hw->led_conf & 0xFFFF;
49 	else
50 		value = 0x205B;
51 
52 	hw->phy.write_reg(hw, RTL_LCR, 0xd04, value);
53 	hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0);
54 
55 	hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &value);
56 	if (hw->led_conf != 0xFFFF) {
57 		value &= ~0x73;
58 		value |= hw->led_conf >> 16;
59 	} else {
60 		value &= 0xFFFC;
61 		/*act led blinking mode set to 60ms*/
62 		value |= 0x2;
63 	}
64 	hw->phy.write_reg(hw, RTL_LPCR, 0xd04, value);
65 }
66 
ngbe_wait_mdio_access_on(struct ngbe_hw * hw)67 static s32 ngbe_wait_mdio_access_on(struct ngbe_hw *hw)
68 {
69 	int i;
70 	u16 val = 0;
71 
72 	for (i = 0; i < 100; i++) {
73 		/* irq status */
74 		hw->phy.read_reg(hw, RTL_INSR, 0xa43, &val);
75 		if (val & RTL_INSR_ACCESS)
76 			break;
77 		msec_delay(1);
78 	}
79 
80 	if (i == 100) {
81 		DEBUGOUT("wait_mdio_access_on timeout");
82 		return NGBE_ERR_PHY_TIMEOUT;
83 	}
84 
85 	return 0;
86 }
87 
ngbe_efuse_calibration(struct ngbe_hw * hw)88 static void ngbe_efuse_calibration(struct ngbe_hw *hw)
89 {
90 	u32 efuse[2];
91 
92 	ngbe_wait_mdio_access_on(hw);
93 
94 	efuse[0] = hw->gphy_efuse[0];
95 	efuse[1] = hw->gphy_efuse[1];
96 
97 	if (!efuse[0] && !efuse[1]) {
98 		efuse[0] = 0xFFFFFFFF;
99 		efuse[1] = 0xFFFFFFFF;
100 	}
101 
102 	/* calibration */
103 	efuse[0] |= 0xF0000100;
104 	efuse[1] |= 0xFF807FFF;
105 	DEBUGOUT("port %d efuse[0] = %08x, efuse[1] = %08x",
106 		hw->bus.lan_id, efuse[0], efuse[1]);
107 
108 	/* EODR, Efuse Output Data Register */
109 	hw->phy.write_reg(hw, 16, 0xa46, (efuse[0] >>  0) & 0xFFFF);
110 	hw->phy.write_reg(hw, 17, 0xa46, (efuse[0] >> 16) & 0xFFFF);
111 	hw->phy.write_reg(hw, 18, 0xa46, (efuse[1] >>  0) & 0xFFFF);
112 	hw->phy.write_reg(hw, 19, 0xa46, (efuse[1] >> 16) & 0xFFFF);
113 }
114 
ngbe_init_phy_rtl(struct ngbe_hw * hw)115 s32 ngbe_init_phy_rtl(struct ngbe_hw *hw)
116 {
117 	int i;
118 	u16 value = 0;
119 
120 	hw->init_phy = true;
121 	msec_delay(1);
122 
123 	hw->phy.set_phy_power(hw, true);
124 
125 	for (i = 0; i < 15; i++) {
126 		if (!rd32m(hw, NGBE_STAT,
127 			NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id)))
128 			break;
129 
130 		msec_delay(10);
131 	}
132 	if (i == 15) {
133 		DEBUGOUT("GPhy reset exceeds maximum times.");
134 		return NGBE_ERR_PHY_TIMEOUT;
135 	}
136 
137 	ngbe_efuse_calibration(hw);
138 
139 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE);
140 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
141 	if (!(value & RTL_SCR_EFUSE)) {
142 		DEBUGOUT("Write EFUSE failed.");
143 		return NGBE_ERR_PHY_TIMEOUT;
144 	}
145 
146 	ngbe_wait_mdio_access_on(hw);
147 
148 	hw->phy.write_reg(hw, 27, 0xa42, 0x8011);
149 	hw->phy.write_reg(hw, 28, 0xa42, 0x5737);
150 
151 	/* Disable fall to 100m if signal is not good */
152 	hw->phy.read_reg(hw, 17, 0xa44, &value);
153 	value &= ~0x8;
154 	hw->phy.write_reg(hw, 17, 0xa44, value);
155 
156 	hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI);
157 	hw->phy.read_reg(hw, RTL_SCR, 0xa46, &value);
158 	if (!(value & RTL_SCR_EXTINI)) {
159 		DEBUGOUT("Write EXIINI failed.");
160 		return NGBE_ERR_PHY_TIMEOUT;
161 	}
162 
163 	ngbe_wait_mdio_access_on(hw);
164 
165 	for (i = 0; i < 100; i++) {
166 		hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value);
167 		if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON)
168 			break;
169 		msec_delay(1);
170 	}
171 	if (i == 100)
172 		return NGBE_ERR_PHY_TIMEOUT;
173 
174 	/* Disable EEE */
175 	hw->phy.write_reg(hw, 0x11, 0xa4b, 0x1110);
176 	hw->phy.write_reg(hw, 0xd, 0x0, 0x0007);
177 	hw->phy.write_reg(hw, 0xe, 0x0, 0x003c);
178 	hw->phy.write_reg(hw, 0xd, 0x0, 0x4007);
179 	hw->phy.write_reg(hw, 0xe, 0x0, 0x0000);
180 
181 	hw->init_phy = false;
182 
183 	return 0;
184 }
185 
186 /**
187  *  ngbe_setup_phy_link_rtl - Set and restart auto-neg
188  *  @hw: pointer to hardware structure
189  *
190  *  Restart auto-negotiation and PHY and waits for completion.
191  **/
ngbe_setup_phy_link_rtl(struct ngbe_hw * hw,u32 speed,bool autoneg_wait_to_complete)192 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw,
193 		u32 speed, bool autoneg_wait_to_complete)
194 {
195 	u16 autoneg_reg = NGBE_MII_AUTONEG_REG;
196 	u16 value = 0;
197 
198 	UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
199 
200 	hw->init_phy = true;
201 	msec_delay(1);
202 
203 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg);
204 
205 	if (!hw->mac.autoneg) {
206 		hw->phy.reset_hw(hw);
207 
208 		switch (speed) {
209 		case NGBE_LINK_SPEED_1GB_FULL:
210 			value = RTL_BMCR_SPEED_SELECT1;
211 			break;
212 		case NGBE_LINK_SPEED_100M_FULL:
213 			value = RTL_BMCR_SPEED_SELECT0;
214 			break;
215 		case NGBE_LINK_SPEED_10M_FULL:
216 			value = 0;
217 			break;
218 		default:
219 			value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0;
220 			DEBUGOUT("unknown speed = 0x%x.", speed);
221 			break;
222 		}
223 		/* duplex full */
224 		value |= RTL_BMCR_DUPLEX;
225 		hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
226 
227 		goto skip_an;
228 	}
229 
230 	/*
231 	 * Clear autoneg_advertised and set new values based on input link
232 	 * speed.
233 	 */
234 	if (speed) {
235 		hw->phy.autoneg_advertised = 0;
236 
237 		if (speed & NGBE_LINK_SPEED_1GB_FULL)
238 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
239 
240 		if (speed & NGBE_LINK_SPEED_100M_FULL)
241 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
242 
243 		if (speed & NGBE_LINK_SPEED_10M_FULL)
244 			hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
245 	}
246 
247 	/* disable 10/100M Half Duplex */
248 	hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg);
249 	autoneg_reg &= 0xFF5F;
250 	hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg);
251 
252 	/* set advertise enable according to input speed */
253 	if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) {
254 		hw->phy.read_reg(hw, RTL_GBCR,
255 			RTL_DEV_ZERO, &autoneg_reg);
256 		autoneg_reg &= ~RTL_GBCR_1000F;
257 		hw->phy.write_reg(hw, RTL_GBCR,
258 			RTL_DEV_ZERO, autoneg_reg);
259 	} else {
260 		hw->phy.read_reg(hw, RTL_GBCR,
261 			RTL_DEV_ZERO, &autoneg_reg);
262 		autoneg_reg |= RTL_GBCR_1000F;
263 		hw->phy.write_reg(hw, RTL_GBCR,
264 			RTL_DEV_ZERO, autoneg_reg);
265 	}
266 
267 	if (!(speed & NGBE_LINK_SPEED_100M_FULL)) {
268 		hw->phy.read_reg(hw, RTL_ANAR,
269 			RTL_DEV_ZERO, &autoneg_reg);
270 		autoneg_reg &= ~RTL_ANAR_100F;
271 		autoneg_reg &= ~RTL_ANAR_100H;
272 		hw->phy.write_reg(hw, RTL_ANAR,
273 			RTL_DEV_ZERO, autoneg_reg);
274 	} else {
275 		hw->phy.read_reg(hw, RTL_ANAR,
276 			RTL_DEV_ZERO, &autoneg_reg);
277 		autoneg_reg |= RTL_ANAR_100F;
278 		hw->phy.write_reg(hw, RTL_ANAR,
279 			RTL_DEV_ZERO, autoneg_reg);
280 	}
281 
282 	if (!(speed & NGBE_LINK_SPEED_10M_FULL)) {
283 		hw->phy.read_reg(hw, RTL_ANAR,
284 			RTL_DEV_ZERO, &autoneg_reg);
285 		autoneg_reg &= ~RTL_ANAR_10F;
286 		autoneg_reg &= ~RTL_ANAR_10H;
287 		hw->phy.write_reg(hw, RTL_ANAR,
288 			RTL_DEV_ZERO, autoneg_reg);
289 	} else {
290 		hw->phy.read_reg(hw, RTL_ANAR,
291 			RTL_DEV_ZERO, &autoneg_reg);
292 		autoneg_reg |= RTL_ANAR_10F;
293 		hw->phy.write_reg(hw, RTL_ANAR,
294 			RTL_DEV_ZERO, autoneg_reg);
295 	}
296 
297 	/* restart AN and wait AN done interrupt */
298 	if (!hw->ncsi_enabled)
299 		autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE;
300 	else
301 		autoneg_reg = RTL_BMCR_ANE;
302 	hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg);
303 
304 skip_an:
305 	ngbe_phy_led_ctrl_rtl(hw);
306 
307 	hw->init_phy = false;
308 
309 	return 0;
310 }
311 
ngbe_reset_phy_rtl(struct ngbe_hw * hw)312 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw)
313 {
314 	u16 value = 0;
315 	s32 status = 0;
316 
317 	value |= RTL_BMCR_RESET;
318 	status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value);
319 
320 	msec_delay(5);
321 
322 	return status;
323 }
324 
ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)325 s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
326 {
327 	u16 value;
328 	s32 status = 0;
329 
330 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
331 	value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE;
332 	*pause_bit = (u8)(value >> 10);
333 	return status;
334 }
335 
ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw * hw,u8 * pause_bit)336 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit)
337 {
338 	u16 value;
339 	s32 status = 0;
340 
341 	status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value);
342 
343 	status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value);
344 	value = value & RTL_BMSR_ANC;
345 
346 	/* if AN complete then check lp adv pause */
347 	status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value);
348 	value &= RTL_ANLPAR_LP;
349 	*pause_bit = (u8)(value >> 10);
350 	return status;
351 }
352 
ngbe_set_phy_pause_adv_rtl(struct ngbe_hw * hw,u16 pause_bit)353 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit)
354 {
355 	u16 value;
356 	s32 status = 0;
357 
358 	status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value);
359 	value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE);
360 	value |= pause_bit;
361 
362 	status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value);
363 
364 	return status;
365 }
366 
ngbe_check_phy_link_rtl(struct ngbe_hw * hw,u32 * speed,bool * link_up)367 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up)
368 {
369 	s32 status = 0;
370 	u16 phy_link = 0;
371 	u16 phy_speed = 0;
372 	u16 phy_data = 0;
373 	u16 insr = 0;
374 
375 	if (hw->init_phy)
376 		return -1;
377 
378 	hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr);
379 
380 	/* Initialize speed and link to default case */
381 	*link_up = false;
382 	*speed = NGBE_LINK_SPEED_UNKNOWN;
383 
384 	/*
385 	 * Check current speed and link status of the PHY register.
386 	 * This is a vendor specific register and may have to
387 	 * be changed for other copper PHYs.
388 	 */
389 	status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data);
390 	phy_link = phy_data & RTL_PHYSR_RTLS;
391 	phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP);
392 	if (phy_link == RTL_PHYSR_RTLS) {
393 		*link_up = true;
394 
395 		if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP))
396 			*speed = NGBE_LINK_SPEED_1GB_FULL;
397 		else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP))
398 			*speed = NGBE_LINK_SPEED_100M_FULL;
399 		else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP))
400 			*speed = NGBE_LINK_SPEED_10M_FULL;
401 	}
402 
403 	if (hw->lsc)
404 		return status;
405 
406 	/*
407 	 * Because of the slow speed of getting link state, RTL_PHYSR
408 	 * may still be up while the actual link state is down.
409 	 * So we read RTL_GBSR to get accurate state when speed is 1G
410 	 * in polling mode.
411 	 */
412 	if (*speed == NGBE_LINK_SPEED_1GB_FULL) {
413 		status = hw->phy.read_reg(hw, RTL_GBSR,
414 				RTL_DEV_ZERO, &phy_data);
415 		phy_link = phy_data & RTL_GBSR_LRS;
416 
417 		/* Only need to detect link down */
418 		if (!phy_link) {
419 			*link_up = false;
420 			*speed = NGBE_LINK_SPEED_UNKNOWN;
421 		}
422 	}
423 	return status;
424 }
425 
ngbe_set_phy_power_rtl(struct ngbe_hw * hw,bool on)426 s32 ngbe_set_phy_power_rtl(struct ngbe_hw *hw, bool on)
427 {
428 	u16 value = 0;
429 
430 	hw->phy.read_reg(hw, RTL_BMCR, 0, &value);
431 	if (on)
432 		value &= ~RTL_BMCR_PWDN;
433 	else
434 		value |= RTL_BMCR_PWDN;
435 	hw->phy.write_reg(hw, RTL_BMCR, 0, value);
436 
437 	return 0;
438 }
439