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