net/ngbe: support custom PHY interfaces
[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         u16 value = 0;
104
105         DEBUGFUNC("ngbe_init_phy_yt");
106
107         /* close sds area register */
108         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
109         /* enable interrupts */
110         ngbe_write_phy_reg_mdi(hw, YT_INTR, 0,
111                                 YT_INTR_ENA_MASK | YT_SDS_INTR_ENA_MASK);
112
113         /* power down in fiber mode */
114         hw->phy.read_reg(hw, YT_BCR, 0, &value);
115         value |= YT_BCR_PWDN;
116         hw->phy.write_reg(hw, YT_BCR, 0, value);
117
118         /* power down in UTP mode */
119         ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
120         value |= YT_BCR_PWDN;
121         ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
122
123         return 0;
124 }
125
126 s32 ngbe_setup_phy_link_yt(struct ngbe_hw *hw, u32 speed,
127                                 bool autoneg_wait_to_complete)
128 {
129         u16 value_r4 = 0;
130         u16 value_r9 = 0;
131         u16 value;
132
133         DEBUGFUNC("ngbe_setup_phy_link_yt");
134         UNREFERENCED_PARAMETER(autoneg_wait_to_complete);
135
136         hw->phy.autoneg_advertised = 0;
137
138         /* check chip_mode first */
139         ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
140         if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(0)) {
141                 /* UTP to rgmii */
142                 if (!hw->mac.autoneg) {
143                         switch (speed) {
144                         case NGBE_LINK_SPEED_1GB_FULL:
145                                 value = YT_BCR_SPEED_SELECT1;
146                                 break;
147                         case NGBE_LINK_SPEED_100M_FULL:
148                                 value = YT_BCR_SPEED_SELECT0;
149                                 break;
150                         case NGBE_LINK_SPEED_10M_FULL:
151                                 value = 0;
152                                 break;
153                         default:
154                                 value = YT_BCR_SPEED_SELECT0 |
155                                         YT_BCR_SPEED_SELECT1;
156                                 DEBUGOUT("unknown speed = 0x%x.\n",
157                                         speed);
158                                 break;
159                         }
160                         /* duplex full */
161                         value |= YT_BCR_DUPLEX | YT_BCR_RESET;
162                         hw->phy.write_reg(hw, YT_BCR, 0, value);
163
164                         goto skip_an;
165                 }
166
167                 /*disable 100/10base-T Self-negotiation ability*/
168                 hw->phy.read_reg(hw, YT_ANA, 0, &value);
169                 value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
170                         YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
171                 hw->phy.write_reg(hw, YT_ANA, 0, value);
172
173                 /*disable 1000base-T Self-negotiation ability*/
174                 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
175                 value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
176                 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
177
178                 if (speed & NGBE_LINK_SPEED_1GB_FULL) {
179                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
180                         value_r9 |= YT_MS_1000BASET_FULL;
181                 }
182                 if (speed & NGBE_LINK_SPEED_100M_FULL) {
183                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL;
184                         value_r4 |= YT_ANA_100BASET_FULL;
185                 }
186                 if (speed & NGBE_LINK_SPEED_10M_FULL) {
187                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL;
188                         value_r4 |= YT_ANA_10BASET_FULL;
189                 }
190
191                 /* enable 1000base-T Self-negotiation ability */
192                 hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
193                 value |= value_r9;
194                 hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
195
196                 /* enable 100/10base-T Self-negotiation ability */
197                 hw->phy.read_reg(hw, YT_ANA, 0, &value);
198                 value |= value_r4;
199                 hw->phy.write_reg(hw, YT_ANA, 0, value);
200
201                 /* software reset to make the above configuration take effect*/
202                 hw->phy.read_reg(hw, YT_BCR, 0, &value);
203                 value |= YT_BCR_RESET | YT_BCR_ANE | YT_BCR_RESTART_AN;
204                 hw->phy.write_reg(hw, YT_BCR, 0, value);
205 skip_an:
206                 /* power on in UTP mode */
207                 ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
208                 value &= ~YT_BCR_PWDN;
209                 ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
210         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(1)) {
211                 /* fiber to rgmii */
212                 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
213
214                 /* RGMII_Config1 : Config rx and tx training delay */
215                 value = YT_RGMII_CONF1_RXDELAY |
216                         YT_RGMII_CONF1_TXDELAY_FE |
217                         YT_RGMII_CONF1_TXDELAY;
218                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
219                 value = YT_CHIP_MODE_SEL(1) |
220                         YT_CHIP_SW_LDO_EN |
221                         YT_CHIP_SW_RST;
222                 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
223
224                 /* software reset */
225                 ngbe_write_phy_reg_sds_ext_yt(hw, 0x0, 0, 0x9140);
226
227                 /* power on phy */
228                 hw->phy.read_reg(hw, YT_BCR, 0, &value);
229                 value &= ~YT_BCR_PWDN;
230                 hw->phy.write_reg(hw, YT_BCR, 0, value);
231         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(2)) {
232                 /* power on in UTP mode */
233                 ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &value);
234                 value &= ~YT_BCR_PWDN;
235                 ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, value);
236                 /* power down in fiber mode */
237                 hw->phy.read_reg(hw, YT_BCR, 0, &value);
238                 value &= ~YT_BCR_PWDN;
239                 hw->phy.write_reg(hw, YT_BCR, 0, value);
240
241                 hw->phy.read_reg(hw, YT_SPST, 0, &value);
242                 if (value & YT_SPST_LINK) {
243                         /* fiber up */
244                         hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
245                 } else {
246                         /* utp up */
247                         /*disable 100/10base-T Self-negotiation ability*/
248                         hw->phy.read_reg(hw, YT_ANA, 0, &value);
249                         value &= ~(YT_ANA_100BASET_FULL | YT_ANA_100BASET_HALF |
250                                 YT_ANA_10BASET_FULL | YT_ANA_10BASET_HALF);
251                         hw->phy.write_reg(hw, YT_ANA, 0, value);
252
253                         /*disable 1000base-T Self-negotiation ability*/
254                         hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
255                         value &= ~(YT_MS_1000BASET_FULL | YT_MS_1000BASET_HALF);
256                         hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
257
258                         if (speed & NGBE_LINK_SPEED_1GB_FULL) {
259                                 hw->phy.autoneg_advertised |=
260                                                 NGBE_LINK_SPEED_1GB_FULL;
261                                 value_r9 |= YT_MS_1000BASET_FULL;
262                         }
263                         if (speed & NGBE_LINK_SPEED_100M_FULL) {
264                                 hw->phy.autoneg_advertised |=
265                                                 NGBE_LINK_SPEED_100M_FULL;
266                                 value_r4 |= YT_ANA_100BASET_FULL;
267                         }
268                         if (speed & NGBE_LINK_SPEED_10M_FULL) {
269                                 hw->phy.autoneg_advertised |=
270                                                 NGBE_LINK_SPEED_10M_FULL;
271                                 value_r4 |= YT_ANA_10BASET_FULL;
272                         }
273
274                         /* enable 1000base-T Self-negotiation ability */
275                         hw->phy.read_reg(hw, YT_MS_CTRL, 0, &value);
276                         value |= value_r9;
277                         hw->phy.write_reg(hw, YT_MS_CTRL, 0, value);
278
279                         /* enable 100/10base-T Self-negotiation ability */
280                         hw->phy.read_reg(hw, YT_ANA, 0, &value);
281                         value |= value_r4;
282                         hw->phy.write_reg(hw, YT_ANA, 0, value);
283
284                         /* software reset to make the above configuration
285                          * take effect
286                          */
287                         hw->phy.read_reg(hw, YT_BCR, 0, &value);
288                         value |= YT_BCR_RESET;
289                         hw->phy.write_reg(hw, YT_BCR, 0, value);
290                 }
291         } else if ((value & YT_CHIP_MODE_MASK) == YT_CHIP_MODE_SEL(4)) {
292                 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL;
293
294                 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, &value);
295                 value |= YT_RGMII_CONF1_MODE;
296                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF1, 0, value);
297
298                 ngbe_read_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, &value);
299                 value &= ~(YT_RGMII_CONF2_SPEED_MASK | YT_RGMII_CONF2_DUPLEX |
300                         YT_RGMII_CONF2_LINKUP);
301                 value |= YT_RGMII_CONF2_SPEED(2) | YT_RGMII_CONF2_DUPLEX |
302                         YT_RGMII_CONF2_LINKUP;
303                 ngbe_write_phy_reg_ext_yt(hw, YT_RGMII_CONF2, 0, value);
304
305                 ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &value);
306                 value &= ~YT_SMI_PHY_SW_RST;
307                 ngbe_write_phy_reg_ext_yt(hw, YT_CHIP, 0, value);
308
309                 /* power on phy */
310                 hw->phy.read_reg(hw, YT_BCR, 0, &value);
311                 value &= ~YT_BCR_PWDN;
312                 hw->phy.write_reg(hw, YT_BCR, 0, value);
313         }
314
315         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
316         ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &value);
317
318         return 0;
319 }
320
321 s32 ngbe_reset_phy_yt(struct ngbe_hw *hw)
322 {
323         u32 i;
324         u16 ctrl = 0;
325         s32 status = 0;
326
327         DEBUGFUNC("ngbe_reset_phy_yt");
328
329         if (hw->phy.type != ngbe_phy_yt8521s &&
330                 hw->phy.type != ngbe_phy_yt8521s_sfi)
331                 return NGBE_ERR_PHY_TYPE;
332
333         /* check chip_mode first */
334         ngbe_read_phy_reg_ext_yt(hw, YT_CHIP, 0, &ctrl);
335         if (ctrl & YT_CHIP_MODE_MASK) {
336                 /* fiber to rgmii */
337                 status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
338                 /* sds software reset */
339                 ctrl |= YT_BCR_RESET;
340                 status = hw->phy.write_reg(hw, YT_BCR, 0, ctrl);
341
342                 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
343                         status = hw->phy.read_reg(hw, YT_BCR, 0, &ctrl);
344                         if (!(ctrl & YT_BCR_RESET))
345                                 break;
346                         msleep(1);
347                 }
348         } else {
349                 /* UTP to rgmii */
350                 status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
351                 /* sds software reset */
352                 ctrl |= YT_BCR_RESET;
353                 status = ngbe_write_phy_reg_mdi(hw, YT_BCR, 0, ctrl);
354
355                 for (i = 0; i < YT_PHY_RST_WAIT_PERIOD; i++) {
356                         status = ngbe_read_phy_reg_mdi(hw, YT_BCR, 0, &ctrl);
357                         if (!(ctrl & YT_BCR_RESET))
358                                 break;
359                         msleep(1);
360                 }
361         }
362
363         if (i == YT_PHY_RST_WAIT_PERIOD) {
364                 DEBUGOUT("PHY reset polling failed to complete.\n");
365                 return NGBE_ERR_RESET_FAILED;
366         }
367
368         return status;
369 }
370
371 s32 ngbe_get_phy_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
372 {
373         u16 value;
374         s32 status = 0;
375
376         DEBUGFUNC("ngbe_get_phy_advertised_pause_yt");
377
378         status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
379         value &= YT_FANA_PAUSE_MASK;
380         *pause_bit = (u8)(value >> 7);
381
382         return status;
383 }
384
385 s32 ngbe_get_phy_lp_advertised_pause_yt(struct ngbe_hw *hw, u8 *pause_bit)
386 {
387         u16 value;
388         s32 status = 0;
389
390         DEBUGFUNC("ngbe_get_phy_lp_advertised_pause_yt");
391
392         status = hw->phy.read_reg(hw, YT_LPAR, 0, &value);
393         value &= YT_FLPAR_PAUSE_MASK;
394         *pause_bit = (u8)(value >> 7);
395
396         return status;
397 }
398
399 s32 ngbe_set_phy_pause_adv_yt(struct ngbe_hw *hw, u16 pause_bit)
400 {
401         u16 value;
402         s32 status = 0;
403
404         DEBUGFUNC("ngbe_set_phy_pause_adv_yt");
405
406
407         status = hw->phy.read_reg(hw, YT_ANA, 0, &value);
408         value &= ~YT_FANA_PAUSE_MASK;
409         value |= pause_bit;
410         status = hw->phy.write_reg(hw, YT_ANA, 0, value);
411
412         return status;
413 }
414
415 s32 ngbe_check_phy_link_yt(struct ngbe_hw *hw,
416                 u32 *speed, bool *link_up)
417 {
418         s32 status = 0;
419         u16 phy_link = 0;
420         u16 phy_speed = 0;
421         u16 phy_data = 0;
422         u16 insr = 0;
423
424         DEBUGFUNC("ngbe_check_phy_link_yt");
425
426         /* Initialize speed and link to default case */
427         *link_up = false;
428         *speed = NGBE_LINK_SPEED_UNKNOWN;
429
430         ngbe_write_phy_reg_ext_yt(hw, YT_SMI_PHY, 0, 0);
431         ngbe_read_phy_reg_mdi(hw, YT_INTR_STATUS, 0, &insr);
432
433         status = hw->phy.read_reg(hw, YT_SPST, 0, &phy_data);
434         phy_link = phy_data & YT_SPST_LINK;
435         phy_speed = phy_data & YT_SPST_SPEED_MASK;
436
437         if (phy_link) {
438                 *link_up = true;
439
440                 if (phy_speed == YT_SPST_SPEED_1000M)
441                         *speed = NGBE_LINK_SPEED_1GB_FULL;
442                 else if (phy_speed == YT_SPST_SPEED_100M)
443                         *speed = NGBE_LINK_SPEED_100M_FULL;
444                 else if (phy_speed == YT_SPST_SPEED_10M)
445                         *speed = NGBE_LINK_SPEED_10M_FULL;
446         }
447
448         return status;
449 }
450