net/ngbe: fix reading M88E1512 PHY mode
[dpdk.git] / drivers / net / ngbe / base / ngbe_phy_yt.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd.
3  */
4
5 #include "ngbe_phy_yt.h"
6
7 #define YT_PHY_RST_WAIT_PERIOD          5
8
9 s32 ngbe_read_phy_reg_yt(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         ngbe_mdi_map_register(&reg, &reg22);
19
20         /* Read MII reg according to media type */
21         if (hw->phy.media_type == ngbe_media_type_fiber) {
22                 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
23                                         reg22.device_type, YT_SMI_PHY_SDS);
24                 ngbe_read_phy_reg_mdi(hw, reg22.addr,
25                                         reg22.device_type, phy_data);
26                 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
27                                         reg22.device_type, 0);
28         } else {
29                 ngbe_read_phy_reg_mdi(hw, reg22.addr,
30                                         reg22.device_type, phy_data);
31         }
32
33         return 0;
34 }
35
36 s32 ngbe_write_phy_reg_yt(struct ngbe_hw *hw,
37                 u32 reg_addr, u32 device_type, u16 phy_data)
38 {
39         mdi_reg_t reg;
40         mdi_reg_22_t reg22;
41
42         reg.device_type = device_type;
43         reg.addr = reg_addr;
44
45         ngbe_mdi_map_register(&reg, &reg22);
46
47         /* Write MII reg according to media type */
48         if (hw->phy.media_type == ngbe_media_type_fiber) {
49                 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
50                                         reg22.device_type, YT_SMI_PHY_SDS);
51                 ngbe_write_phy_reg_mdi(hw, reg22.addr,
52                                         reg22.device_type, phy_data);
53                 ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY,
54                                         reg22.device_type, 0);
55         } else {
56                 ngbe_write_phy_reg_mdi(hw, reg22.addr,
57                                         reg22.device_type, phy_data);
58         }
59
60         return 0;
61 }
62
63 s32 ngbe_read_phy_reg_ext_yt(struct ngbe_hw *hw,
64                 u32 reg_addr, u32 device_type, u16 *phy_data)
65 {
66         ngbe_write_phy_reg_mdi(hw, 0x1E, device_type, reg_addr);
67         ngbe_read_phy_reg_mdi(hw, 0x1F, device_type, phy_data);
68
69         return 0;
70 }
71
72 s32 ngbe_write_phy_reg_ext_yt(struct ngbe_hw *hw,
73                 u32 reg_addr, u32 device_type, u16 phy_data)
74 {
75         ngbe_write_phy_reg_mdi(hw, 0x1E, device_type, reg_addr);
76         ngbe_write_phy_reg_mdi(hw, 0x1F, device_type, phy_data);
77
78         return 0;
79 }
80
81 s32 ngbe_read_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
82                 u32 reg_addr, u32 device_type, u16 *phy_data)
83 {
84         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS);
85         ngbe_read_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data);
86         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0);
87
88         return 0;
89 }
90
91 s32 ngbe_write_phy_reg_sds_ext_yt(struct ngbe_hw *hw,
92                 u32 reg_addr, u32 device_type, u16 phy_data)
93 {
94         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, YT_SMI_PHY_SDS);
95         ngbe_write_phy_reg_ext_yt(hw, reg_addr, device_type, phy_data);
96         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, device_type, 0);
97
98         return 0;
99 }
100
101 s32 ngbe_init_phy_yt(struct ngbe_hw *hw)
102 {
103         /* close sds area register */
104         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
105         /* enable interrupts */
106         ngbe_write_phy_reg_mdi(hw, YT_INTR, 0,
107                                 YT_INTR_ENA_MASK | YT_SDS_INTR_ENA_MASK);
108
109         hw->phy.set_phy_power(hw, false);
110
111         return 0;
112 }
113
114 s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
115                                 bool autoneg_wait_to_complete)
116 {
117         u16 value_r4 = 0;
118         u16 value_r9 = 0;
119         u16 value;
120
121         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
122
123         hw->phy.autoneg_advertised = 0;
124
125         /* check chip_mode first */
126         ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
127         if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(0)) {
128                 /* UTP to rgmii */
129                 if (!hw->mac.autoneg) {
130                         switch (speed) {
131                         case NGBE_LINK_SPEED_1GB_FULL:
132                                 value = YT_BCR_SPEED_SELECT1;
133                                 break;
134                         case NGBE_LINK_SPEED_100M_FULL:
135                                 value = YT_BCR_SPEED_SELECT0;
136                                 break;
137                         case NGBE_LINK_SPEED_10M_FULL:
138                                 value = 0;
139                                 break;
140                         default:
141                                 value = YT_BCR_SPEED_SELECT0 |
142                                         YT_BCR_SPEED_SELECT1;
143                                 DEBUGOUT("unknown speed = 0x%x.",
144                                         speed);
145                                 break;
146                         }
147                         /* duplex full */
148                         value |= YT_BCR_DUPLEX | YT_BCR_RESET;
149                         hw->phy.write_reg(hw, YT_BCR, 0, value);
150
151                         goto skip_an;
152                 }
153
154                 /*disable 100/10base-T Self-negotiation ability*/
155                 hw->phy.read_reg(hw, YT_ANA, 0, &value);
156                 value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
157                         YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
158                 hw->phy.write_reg(hw, YT_ANA, 0, value);
159
160                 /*disable 1000base-T Self-negotiation ability*/
161                 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
162                 value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
163                 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
164
165                 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
166                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
167                         value_r9 |= YT_MS_1000BASET_FULL;
168                 }
169                 if (speed & NGBE_LINK_SPEED_100M_FULL) {
170                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
171                         value_r4 |= YT_ANA_100BASET_FULL;
172                 }
173                 if (speed & NGBE_LINK_SPEED_10M_FULL) {
174                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
175                         value_r4 |= YT_ANA_10BASET_FULL;
176                 }
177
178                 /* enable 1000base-T Self-negotiation ability */
179                 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
180                 value |= value_r9;
181                 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
182
183                 /* enable 100/10base-T Self-negotiation ability */
184                 hw->phy.read_reg(hw, YT_ANA, 0, &value);
185                 value |= value_r4;
186                 hw->phy.write_reg(hw, YT_ANA, 0, value);
187
188                 /* software reset to make the above configuration take effect*/
189                 hw->phy.read_reg(hw, YT_BCR, 0, &value);
190                 value |= YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN;
191                 hw->phy.write_reg(hw, YT_BCR, 0, value);
192 skip_an:
193                 hw->phy.set_phy_power(hw, true);
194         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(1)) {
195                 /* fiber to rgmii */
196                 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
197
198                 /* RGMII_Config1 : Config rx and tx training delay */
199                 value = YT_RGMII_CONF1_RXDELAY |
200                         YT_RGMII_CONF1_TXDELAY_FE |
201                         YT_RGMII_CONF1_TXDELAY;
202                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
203                 value = YT_CHIP_MODE_SEL(1) |
204                         YT_CHIP_SW_LDO_EN |
205                         YT_CHIP_SW_RST;
206                 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
207
208                 /* software reset */
209                 ngbe_write_phy_reg_sds_ext_yt(hw, 0x0, 0, 0x9140);
210
211                 hw->phy.set_phy_power(hw, true);
212         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(2)) {
213                 hw->phy.set_phy_power(hw, true);
214
215                 hw->phy.read_reg(hw, YT_SPST, 0, &value);
216                 if (value & YT_SPST_LINK) {
217                         /* fiber up */
218                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
219                 } else {
220                         /* utp up */
221                         /*disable 100/10base-T Self-negotiation ability*/
222                         hw->phy.read_reg(hw, YT_ANA, 0, &value);
223                         value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
224                                 YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
225                         hw->phy.write_reg(hw, YT_ANA, 0, value);
226
227                         /*disable 1000base-T Self-negotiation ability*/
228                         hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
229                         value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
230                         hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
231
232                         if (speed & NGBE_LINK_SPEED_1GB_FULL) {
233                                 hw->phy.autoneg_advertised |=
234                                                 NGBE_LINK_SPEED_1GB_FULL;
235                                 value_r9 |= YT_MS_1000BASET_FULL;
236                         }
237                         if (speed & NGBE_LINK_SPEED_100M_FULL) {
238                                 hw->phy.autoneg_advertised |=
239                                                 NGBE_LINK_SPEED_100M_FULL;
240                                 value_r4 |= YT_ANA_100BASET_FULL;
241                         }
242                         if (speed & NGBE_LINK_SPEED_10M_FULL) {
243                                 hw->phy.autoneg_advertised |=
244                                                 NGBE_LINK_SPEED_10M_FULL;
245                                 value_r4 |= YT_ANA_10BASET_FULL;
246                         }
247
248                         /* enable 1000base-T Self-negotiation ability */
249                         hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
250                         value |= value_r9;
251                         hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
252
253                         /* enable 100/10base-T Self-negotiation ability */
254                         hw->phy.read_reg(hw, YT_ANA, 0, &value);
255                         value |= value_r4;
256                         hw->phy.write_reg(hw, YT_ANA, 0, value);
257
258                         /* software reset to make the above configuration
259                          * take effect
260                          */
261                         hw->phy.read_reg(hw, YT_BCR, 0, &value);
262                         value |= YT_BCR_RESET;
263                         hw->phy.write_reg(hw, YT_BCR, 0, value);
264                 }
265         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(4)) {
266                 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
267
268                 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, &value);
269                 value |= YT_RGMII_CONF1_MODE;
270                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
271
272                 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, &value);
273                 value &= ~(YT_RGMII_CONF2_SPEED_MASK | YT_RGMII_CONF2_DUPLEX |
274                         YT_RGMII_CONF2_LINKUP);
275                 value |= YT_RGMII_CONF2_SPEED(2) | YT_RGMII_CONF2_DUPLEX |
276                         YT_RGMII_CONF2_LINKUP;
277                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, value);
278
279                 ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
280                 value &= ~YT_SMI_PHY_SW_RST;
281                 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
282
283                 hw->phy.set_phy_power(hw, true);
284         }
285
286         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
287         ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &value);
288
289         return 0;
290 }
291
292 s32 ngbe_reset_phy_yt(struct ngbe_hw *hw)
293 {
294         u32 i;
295         u16 ctrl = 0;
296         s32 status = 0;
297
298         if (hw->phy.type != ngbe_phy_yt8521s &&
299                 hw->phy.type != ngbe_phy_yt8521s_sfi)
300                 return NGBE_ERR_PHY_TYPE;
301
302         /* check chip_mode first */
303         ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &ctrl);
304         if (ctrl & YT_CHIP_MODE_MASK) {
305                 /* fiber to rgmii */
306                 status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
307                 /* sds software reset */
308                 ctrl |= YT_BCR_RESET;
309                 status = hw->phy.write_reg(hw, YT_BCR, 0, ctrl);
310
311                 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
312                         status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
313                         if (!(ctrl & YT_BCR_RESET))
314                                 break;
315                         msleep(1);
316                 }
317         } else {
318                 /* UTP to rgmii */
319                 status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
320                 /* sds software reset */
321                 ctrl |= YT_BCR_RESET;
322                 status = ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, ctrl);
323
324                 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
325                         status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
326                         if (!(ctrl & YT_BCR_RESET))
327                                 break;
328                         msleep(1);
329                 }
330         }
331
332         if (i == YT_PHY_RST_WAIT_PERIOD) {
333                 DEBUGOUT("PHY reset polling failed to complete.");
334                 return NGBE_ERR_RESET_FAILED;
335         }
336
337         return status;
338 }
339
340 s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
341 {
342         u16 value;
343         s32 status = 0;
344
345         status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
346         value &= YT_FANA_PAUSE_MASK;
347         *pause_bit = (u8)(value >> 7);
348
349         return status;
350 }
351
352 s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
353 {
354         u16 value;
355         s32 status = 0;
356
357         status = hw->phy.read_reg(hw, YT_LPAR, 0, &value);
358         value &= YT_FLPAR_PAUSE_MASK;
359         *pause_bit = (u8)(value >> 7);
360
361         return status;
362 }
363
364 s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit)
365 {
366         u16 value;
367         s32 status = 0;
368
369         status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
370         value &= ~YT_FANA_PAUSE_MASK;
371         value |= pause_bit;
372         status = hw->phy.write_reg(hw, YT_ANA, 0, value);
373
374         return status;
375 }
376
377 s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw,
378                 u32 *speed, bool *link_up)
379 {
380         s32 status = 0;
381         u16 phy_link = 0;
382         u16 phy_speed = 0;
383         u16 phy_data = 0;
384         u16 insr = 0;
385
386         /* Initialize speed and link to default case */
387         *link_up = false;
388         *speed = NGBE_LINK_SPEED_UNKNOWN;
389
390         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
391         ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &insr);
392
393         status = hw->phy.read_reg(hw, YT_SPST, 0, &phy_data);
394         phy_link = phy_data & YT_SPST_LINK;
395         phy_speed = phy_data & YT_SPST_SPEED_MASK;
396
397         if (phy_link) {
398                 *link_up = true;
399
400                 if (phy_speed == YT_SPST_SPEED_1000M)
401                         *speed = NGBE_LINK_SPEED_1GB_FULL;
402                 else if (phy_speed == YT_SPST_SPEED_100M)
403                         *speed = NGBE_LINK_SPEED_100M_FULL;
404                 else if (phy_speed == YT_SPST_SPEED_10M)
405                         *speed = NGBE_LINK_SPEED_10M_FULL;
406         }
407
408         return status;
409 }
410
411 s32 ngbe_set_phy_power_yt(struct ngbe_hw *hw, bool on)
412 {
413         u16 value = 0;
414
415         /* power down/up in fiber mode */
416         hw->phy.read_reg(hw, YT_BCR, 0, &value);
417         if (on)
418                 value &= ~YT_BCR_PWDN;
419         else
420                 value |= YT_BCR_PWDN;
421         hw->phy.write_reg(hw, YT_BCR, 0, value);
422
423         value = 0;
424         /* power down/up in UTP mode */
425         ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
426         if (on)
427                 value &= ~YT_BCR_PWDN;
428         else
429                 value |= YT_BCR_PWDN;
430         ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
431
432         return 0;
433 }