pipeline: add check against loops
[dpdk.git] / drivers / net / ngbe / base / ngbe_phy_mvl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  */
4
5 #include "ngbe_phy_mvl.h"
6
7 #define MVL_PHY_RST_WAIT_PERIOD  5
8
9 s32 ngbe_read_phy_reg_mvl(struct ngbe_hw *hw,
10                 u32 reg_addr, u32 device_type, u16 *phy_data)
11 {
12         mdi_reg_t reg;
13         mdi_reg_22_t reg22;
14
15         reg.device_type = device_type;
16         reg.addr = reg_addr;
17
18         if (hw->phy.media_type == ngbe_media_type_fiber)
19                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
20         else
21                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
22
23         ngbe_mdi_map_register(&reg, &reg22);
24
25         ngbe_read_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
26
27         return 0;
28 }
29
30 s32 ngbe_write_phy_reg_mvl(struct ngbe_hw *hw,
31                 u32 reg_addr, u32 device_type, u16 phy_data)
32 {
33         mdi_reg_t reg;
34         mdi_reg_22_t reg22;
35
36         reg.device_type = device_type;
37         reg.addr = reg_addr;
38
39         if (hw->phy.media_type == ngbe_media_type_fiber)
40                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 1);
41         else
42                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 0);
43
44         ngbe_mdi_map_register(&reg, &reg22);
45
46         ngbe_write_phy_reg_mdi(hw, reg22.addr, reg22.device_type, phy_data);
47
48         return 0;
49 }
50
51 s32 ngbe_check_phy_mode_mvl(struct ngbe_hw *hw)
52 {
53         u16 value = 0;
54
55         /* select page 18 reg 20 */
56         ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
57         ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &value);
58         if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_COPPER) {
59                 /* mode select to RGMII-to-copper */
60                 hw->phy.type = ngbe_phy_mvl;
61                 hw->phy.media_type = ngbe_media_type_copper;
62                 hw->mac.link_type = ngbe_link_copper;
63         } else if (MVL_GEN_CTL_MODE(value) == MVL_GEN_CTL_MODE_FIBER) {
64                 /* mode select to RGMII-to-sfi */
65                 hw->phy.type = ngbe_phy_mvl_sfi;
66                 hw->phy.media_type = ngbe_media_type_fiber;
67                 hw->mac.link_type = ngbe_link_fiber;
68         } else {
69                 DEBUGOUT("marvell 88E1512 mode %x is not supported.\n", value);
70                 return NGBE_ERR_DEVICE_NOT_SUPPORTED;
71         }
72
73         return 0;
74 }
75
76 s32 ngbe_init_phy_mvl(struct ngbe_hw *hw)
77 {
78         s32 ret_val = 0;
79         u16 value = 0;
80         int i;
81
82         DEBUGFUNC("ngbe_init_phy_mvl");
83
84         /* enable interrupts, only link status change and an done is allowed */
85         ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 2);
86         ngbe_read_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, &value);
87         value &= ~MVL_RGM_CTL2_TTC;
88         value |= MVL_RGM_CTL2_RTC;
89         ngbe_write_phy_reg_mdi(hw, MVL_RGM_CTL2, 0, value);
90
91         hw->phy.write_reg(hw, MVL_CTRL, 0, MVL_CTRL_RESET);
92         for (i = 0; i < 15; i++) {
93                 ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
94                 if (value & MVL_CTRL_RESET)
95                         msleep(1);
96                 else
97                         break;
98         }
99
100         if (i == 15) {
101                 DEBUGOUT("phy reset exceeds maximum waiting period.\n");
102                 return NGBE_ERR_TIMEOUT;
103         }
104
105         ret_val = hw->phy.reset_hw(hw);
106         if (ret_val)
107                 return ret_val;
108
109         /* set LED2 to interrupt output and INTn active low */
110         ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
111         ngbe_read_phy_reg_mdi(hw, MVL_LEDTCR, 0, &value);
112         value |= MVL_LEDTCR_INTR_EN;
113         value &= ~(MVL_LEDTCR_INTR_POL);
114         ngbe_write_phy_reg_mdi(hw, MVL_LEDTCR, 0, value);
115
116         if (hw->phy.type == ngbe_phy_mvl_sfi) {
117                 hw->phy.read_reg(hw, MVL_CTRL1, 0, &value);
118                 value &= ~MVL_CTRL1_INTR_POL;
119                 ngbe_write_phy_reg_mdi(hw, MVL_CTRL1, 0, value);
120         }
121
122         /* enable link status change and AN complete interrupts */
123         value = MVL_INTR_EN_ANC | MVL_INTR_EN_LSC;
124         hw->phy.write_reg(hw, MVL_INTR_EN, 0, value);
125
126         ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
127         value |= MVL_CTRL_PWDN;
128         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
129
130         return ret_val;
131 }
132
133 s32 ngbe_setup_phy_link_mvl(struct ngbe_hw *hw, u32 speed,
134                                 bool autoneg_wait_to_complete)
135 {
136         u16 value_r4 = 0;
137         u16 value_r9 = 0;
138         u16 value;
139
140         DEBUGFUNC("ngbe_setup_phy_link_mvl");
141         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
142
143         if (hw->led_conf == 0xFFFF) {
144                 /* LED control */
145                 ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 3);
146                 ngbe_read_phy_reg_mdi(hw, MVL_LEDFCR, 0, &value);
147                 value &= ~(MVL_LEDFCR_CTL0 | MVL_LEDFCR_CTL1);
148                 value |= MVL_LEDFCR_CTL0_CONF | MVL_LEDFCR_CTL1_CONF;
149                 ngbe_write_phy_reg_mdi(hw, MVL_LEDFCR, 0, value);
150                 ngbe_read_phy_reg_mdi(hw, MVL_LEDPCR, 0, &value);
151                 value &= ~(MVL_LEDPCR_CTL0 | MVL_LEDPCR_CTL1);
152                 value |= MVL_LEDPCR_CTL0_CONF | MVL_LEDPCR_CTL1_CONF;
153                 ngbe_write_phy_reg_mdi(hw, MVL_LEDPCR, 0, value);
154         }
155
156         hw->phy.autoneg_advertised = 0;
157
158         if (hw->phy.type == ngbe_phy_mvl) {
159                 if (!hw->mac.autoneg) {
160                         switch (speed) {
161                         case NGBE_LINK_SPEED_1GB_FULL:
162                                 value = MVL_CTRL_SPEED_SELECT1;
163                                 break;
164                         case NGBE_LINK_SPEED_100M_FULL:
165                                 value = MVL_CTRL_SPEED_SELECT0;
166                                 break;
167                         case NGBE_LINK_SPEED_10M_FULL:
168                                 value = 0;
169                                 break;
170                         default:
171                                 value = MVL_CTRL_SPEED_SELECT0 |
172                                         MVL_CTRL_SPEED_SELECT1;
173                                 DEBUGOUT("unknown speed = 0x%x.\n", speed);
174                                 break;
175                         }
176                         /* duplex full */
177                         value |= MVL_CTRL_DUPLEX | MVL_CTRL_RESET;
178                         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
179
180                         goto skip_an;
181                 }
182                 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
183                         value_r9 |= MVL_PHY_1000BASET_FULL;
184                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
185                 }
186
187                 if (speed & NGBE_LINK_SPEED_100M_FULL) {
188                         value_r4 |= MVL_PHY_100BASET_FULL;
189                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
190                 }
191
192                 if (speed & NGBE_LINK_SPEED_10M_FULL) {
193                         value_r4 |= MVL_PHY_10BASET_FULL;
194                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
195                 }
196
197                 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
198                 value &= ~(MVL_PHY_100BASET_FULL |
199                            MVL_PHY_100BASET_HALF |
200                            MVL_PHY_10BASET_FULL |
201                            MVL_PHY_10BASET_HALF);
202                 value_r4 |= value;
203                 hw->phy.write_reg(hw, MVL_ANA, 0, value_r4);
204
205                 hw->phy.read_reg(hw, MVL_PHY_1000BASET, 0, &value);
206                 value &= ~(MVL_PHY_1000BASET_FULL |
207                            MVL_PHY_1000BASET_HALF);
208                 value_r9 |= value;
209                 hw->phy.write_reg(hw, MVL_PHY_1000BASET, 0, value_r9);
210         } else {
211                 hw->phy.autoneg_advertised = 1;
212
213                 hw->phy.read_reg(hw, MVL_ANA, 0, &value);
214                 value &= ~(MVL_PHY_1000BASEX_HALF | MVL_PHY_1000BASEX_FULL);
215                 value |= MVL_PHY_1000BASEX_FULL;
216                 hw->phy.write_reg(hw, MVL_ANA, 0, value);
217         }
218
219         value = MVL_CTRL_RESTART_AN | MVL_CTRL_ANE | MVL_CTRL_RESET;
220         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
221
222 skip_an:
223         ngbe_read_phy_reg_mdi(hw, MVL_CTRL, 0, &value);
224         value |= MVL_CTRL_PWDN;
225         ngbe_write_phy_reg_mdi(hw, MVL_CTRL, 0, value);
226
227         hw->phy.read_reg(hw, MVL_INTR, 0, &value);
228
229         return 0;
230 }
231
232 s32 ngbe_reset_phy_mvl(struct ngbe_hw *hw)
233 {
234         u32 i;
235         u16 ctrl = 0;
236         s32 status = 0;
237
238         DEBUGFUNC("ngbe_reset_phy_mvl");
239
240         if (hw->phy.type != ngbe_phy_mvl && hw->phy.type != ngbe_phy_mvl_sfi)
241                 return NGBE_ERR_PHY_TYPE;
242
243         /* select page 18 reg 20 */
244         status = ngbe_write_phy_reg_mdi(hw, MVL_PAGE_SEL, 0, 18);
245
246         /* mode select to RGMII-to-copper or RGMII-to-sfi*/
247         if (hw->phy.type == ngbe_phy_mvl)
248                 ctrl = MVL_GEN_CTL_MODE_COPPER;
249         else
250                 ctrl = MVL_GEN_CTL_MODE_FIBER;
251         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
252         /* mode reset */
253         ctrl |= MVL_GEN_CTL_RESET;
254         status = ngbe_write_phy_reg_mdi(hw, MVL_GEN_CTL, 0, ctrl);
255
256         for (i = 0; i < MVL_PHY_RST_WAIT_PERIOD; i++) {
257                 status = ngbe_read_phy_reg_mdi(hw, MVL_GEN_CTL, 0, &ctrl);
258                 if (!(ctrl & MVL_GEN_CTL_RESET))
259                         break;
260                 msleep(1);
261         }
262
263         if (i == MVL_PHY_RST_WAIT_PERIOD) {
264                 DEBUGOUT("PHY reset polling failed to complete.\n");
265                 return NGBE_ERR_RESET_FAILED;
266         }
267
268         return status;
269 }
270
271 s32 ngbe_get_phy_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
272 {
273         u16 value;
274         s32 status = 0;
275
276         if (hw->phy.type == ngbe_phy_mvl) {
277                 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
278                 value &= MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE;
279                 *pause_bit = (u8)(value >> 10);
280         } else {
281                 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
282                 value &= MVL_FANA_PAUSE_MASK;
283                 *pause_bit = (u8)(value >> 7);
284         }
285
286         return status;
287 }
288
289 s32 ngbe_get_phy_lp_advertised_pause_mvl(struct ngbe_hw *hw, u8 *pause_bit)
290 {
291         u16 value;
292         s32 status = 0;
293
294         if (hw->phy.type == ngbe_phy_mvl) {
295                 status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
296                 value &= MVL_CLPAR_ASM_PAUSE | MVL_CLPAR_PAUSE;
297                 *pause_bit = (u8)(value >> 10);
298         } else {
299                 status = hw->phy.read_reg(hw, MVL_LPAR, 0, &value);
300                 value &= MVL_FLPAR_PAUSE_MASK;
301                 *pause_bit = (u8)(value >> 7);
302         }
303
304         return status;
305 }
306
307 s32 ngbe_set_phy_pause_adv_mvl(struct ngbe_hw *hw, u16 pause_bit)
308 {
309         u16 value;
310         s32 status = 0;
311
312         DEBUGFUNC("ngbe_set_phy_pause_adv_mvl");
313
314         if (hw->phy.type == ngbe_phy_mvl) {
315                 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
316                 value &= ~(MVL_CANA_ASM_PAUSE | MVL_CANA_PAUSE);
317         } else {
318                 status = hw->phy.read_reg(hw, MVL_ANA, 0, &value);
319                 value &= ~MVL_FANA_PAUSE_MASK;
320         }
321
322         value |= pause_bit;
323         status = hw->phy.write_reg(hw, MVL_ANA, 0, value);
324
325         return status;
326 }
327
328 s32 ngbe_check_phy_link_mvl(struct ngbe_hw *hw,
329                 u32 *speed, bool *link_up)
330 {
331         s32 status = 0;
332         u16 phy_link = 0;
333         u16 phy_speed = 0;
334         u16 phy_data = 0;
335         u16 insr = 0;
336
337         DEBUGFUNC("ngbe_check_phy_link_mvl");
338
339         /* Initialize speed and link to default case */
340         *link_up = false;
341         *speed = NGBE_LINK_SPEED_UNKNOWN;
342
343         hw->phy.read_reg(hw, MVL_INTR, 0, &insr);
344
345         /*
346          * Check current speed and link status of the PHY register.
347          * This is a vendor specific register and may have to
348          * be changed for other copper PHYs.
349          */
350         status = hw->phy.read_reg(hw, MVL_PHYSR, 0, &phy_data);
351         phy_link = phy_data & MVL_PHYSR_LINK;
352         phy_speed = phy_data & MVL_PHYSR_SPEED_MASK;
353
354         if (phy_link == MVL_PHYSR_LINK) {
355                 *link_up = true;
356
357                 if (phy_speed == MVL_PHYSR_SPEED_1000M)
358                         *speed = NGBE_LINK_SPEED_1GB_FULL;
359                 else if (phy_speed == MVL_PHYSR_SPEED_100M)
360                         *speed = NGBE_LINK_SPEED_100M_FULL;
361                 else if (phy_speed == MVL_PHYSR_SPEED_10M)
362                         *speed = NGBE_LINK_SPEED_10M_FULL;
363         }
364
365         return status;
366 }
367