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