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(®, ®22);
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(®, ®22);
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