net/ngbe: support OEM customized LED
[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 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