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