Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
4 * Synopsys DesignWare XPCS helpers
5 *
6 * Author: Jose Abreu <Jose.Abreu@synopsys.com>
7 */
8
9#include <linux/clk.h>
10#include <linux/delay.h>
11#include <linux/pcs/pcs-xpcs.h>
12#include <linux/mdio.h>
13#include <linux/phy.h>
14#include <linux/phylink.h>
15#include <linux/property.h>
16
17#include "pcs-xpcs.h"
18
19#define phylink_pcs_to_xpcs(pl_pcs) \
20 container_of((pl_pcs), struct dw_xpcs, pcs)
21
22static const int xpcs_usxgmii_features[] = {
23 ETHTOOL_LINK_MODE_Pause_BIT,
24 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
25 ETHTOOL_LINK_MODE_Autoneg_BIT,
26 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
27 ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
28 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
29 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
30 __ETHTOOL_LINK_MODE_MASK_NBITS,
31};
32
33static const int xpcs_10gkr_features[] = {
34 ETHTOOL_LINK_MODE_Pause_BIT,
35 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
36 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
37 __ETHTOOL_LINK_MODE_MASK_NBITS,
38};
39
40static const int xpcs_25gbaser_features[] = {
41 ETHTOOL_LINK_MODE_MII_BIT,
42 ETHTOOL_LINK_MODE_Pause_BIT,
43 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
44 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
45 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
46 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
47 __ETHTOOL_LINK_MODE_MASK_NBITS,
48};
49
50static const int xpcs_xlgmii_features[] = {
51 ETHTOOL_LINK_MODE_Pause_BIT,
52 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
53 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
54 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
55 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
56 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
57 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
58 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
59 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
60 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
61 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
62 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
63 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
64 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
65 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
66 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
67 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
68 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
69 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
70 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
71 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
72 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
73 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
74 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
75 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
76 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
77 __ETHTOOL_LINK_MODE_MASK_NBITS,
78};
79
80static const int xpcs_50gbaser_features[] = {
81 ETHTOOL_LINK_MODE_MII_BIT,
82 ETHTOOL_LINK_MODE_Pause_BIT,
83 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
84 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
85 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
86 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
87 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
88 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
89 __ETHTOOL_LINK_MODE_MASK_NBITS,
90};
91
92static const int xpcs_50gbaser2_features[] = {
93 ETHTOOL_LINK_MODE_MII_BIT,
94 ETHTOOL_LINK_MODE_Pause_BIT,
95 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
96 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
97 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
98 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
99 __ETHTOOL_LINK_MODE_MASK_NBITS,
100};
101
102static const int xpcs_100gbasep_features[] = {
103 ETHTOOL_LINK_MODE_MII_BIT,
104 ETHTOOL_LINK_MODE_Pause_BIT,
105 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
106 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
107 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
108 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
109 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
110 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
111 __ETHTOOL_LINK_MODE_MASK_NBITS,
112};
113
114static const int xpcs_10gbaser_features[] = {
115 ETHTOOL_LINK_MODE_Pause_BIT,
116 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
117 ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
118 ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
119 ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
120 ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
121 __ETHTOOL_LINK_MODE_MASK_NBITS,
122};
123
124static const int xpcs_sgmii_features[] = {
125 ETHTOOL_LINK_MODE_Pause_BIT,
126 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
127 ETHTOOL_LINK_MODE_Autoneg_BIT,
128 ETHTOOL_LINK_MODE_10baseT_Half_BIT,
129 ETHTOOL_LINK_MODE_10baseT_Full_BIT,
130 ETHTOOL_LINK_MODE_100baseT_Half_BIT,
131 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
132 ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
133 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
134 __ETHTOOL_LINK_MODE_MASK_NBITS,
135};
136
137static const int xpcs_1000basex_features[] = {
138 ETHTOOL_LINK_MODE_Pause_BIT,
139 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
140 ETHTOOL_LINK_MODE_Autoneg_BIT,
141 ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
142 __ETHTOOL_LINK_MODE_MASK_NBITS,
143};
144
145static const int xpcs_2500basex_features[] = {
146 ETHTOOL_LINK_MODE_Pause_BIT,
147 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
148 ETHTOOL_LINK_MODE_Autoneg_BIT,
149 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
150 ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
151 __ETHTOOL_LINK_MODE_MASK_NBITS,
152};
153
154struct dw_xpcs_compat {
155 phy_interface_t interface;
156 const int *supported;
157 int an_mode;
158 int (*pma_config)(struct dw_xpcs *xpcs);
159};
160
161struct dw_xpcs_desc {
162 u32 id;
163 u32 mask;
164 const struct dw_xpcs_compat *compat;
165};
166
167static const struct dw_xpcs_compat *
168xpcs_find_compat(struct dw_xpcs *xpcs, phy_interface_t interface)
169{
170 const struct dw_xpcs_compat *compat;
171
172 for (compat = xpcs->desc->compat; compat->supported; compat++)
173 if (compat->interface == interface)
174 return compat;
175
176 return NULL;
177}
178
179struct phylink_pcs *xpcs_to_phylink_pcs(struct dw_xpcs *xpcs)
180{
181 return &xpcs->pcs;
182}
183EXPORT_SYMBOL_GPL(xpcs_to_phylink_pcs);
184
185int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
186{
187 const struct dw_xpcs_compat *compat;
188
189 compat = xpcs_find_compat(xpcs, interface);
190 if (!compat)
191 return -ENODEV;
192
193 return compat->an_mode;
194}
195EXPORT_SYMBOL_GPL(xpcs_get_an_mode);
196
197static bool __xpcs_linkmode_supported(const struct dw_xpcs_compat *compat,
198 enum ethtool_link_mode_bit_indices linkmode)
199{
200 int i;
201
202 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
203 if (compat->supported[i] == linkmode)
204 return true;
205
206 return false;
207}
208
209#define xpcs_linkmode_supported(compat, mode) \
210 __xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
211
212int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
213{
214 return mdiodev_c45_read(xpcs->mdiodev, dev, reg);
215}
216
217int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
218{
219 return mdiodev_c45_write(xpcs->mdiodev, dev, reg, val);
220}
221
222int xpcs_modify(struct dw_xpcs *xpcs, int dev, u32 reg, u16 mask, u16 set)
223{
224 return mdiodev_c45_modify(xpcs->mdiodev, dev, reg, mask, set);
225}
226
227static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg,
228 u16 mask, u16 set)
229{
230 return mdiodev_c45_modify_changed(xpcs->mdiodev, dev, reg, mask, set);
231}
232
233static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
234{
235 return xpcs_read(xpcs, dev, DW_VENDOR | reg);
236}
237
238static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
239 u16 val)
240{
241 return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
242}
243
244static int xpcs_modify_vendor(struct dw_xpcs *xpcs, int dev, int reg, u16 mask,
245 u16 set)
246{
247 return xpcs_modify(xpcs, dev, DW_VENDOR | reg, mask, set);
248}
249
250int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
251{
252 return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
253}
254
255int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
256{
257 return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
258}
259
260static int xpcs_modify_vpcs(struct dw_xpcs *xpcs, int reg, u16 mask, u16 val)
261{
262 return xpcs_modify_vendor(xpcs, MDIO_MMD_PCS, reg, mask, val);
263}
264
265static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
266{
267 int ret, val;
268
269 ret = read_poll_timeout(xpcs_read, val,
270 val < 0 || !(val & BMCR_RESET),
271 50000, 600000, true, xpcs, dev, MII_BMCR);
272 if (val < 0)
273 ret = val;
274
275 return ret;
276}
277
278static int xpcs_soft_reset(struct dw_xpcs *xpcs,
279 const struct dw_xpcs_compat *compat)
280{
281 int ret, dev;
282
283 switch (compat->an_mode) {
284 case DW_AN_C73:
285 case DW_10GBASER:
286 dev = MDIO_MMD_PCS;
287 break;
288 case DW_AN_C37_SGMII:
289 case DW_2500BASEX:
290 case DW_AN_C37_1000BASEX:
291 dev = MDIO_MMD_VEND2;
292 break;
293 default:
294 return -EINVAL;
295 }
296
297 ret = xpcs_write(xpcs, dev, MII_BMCR, BMCR_RESET);
298 if (ret < 0)
299 return ret;
300
301 return xpcs_poll_reset(xpcs, dev);
302}
303
304#define xpcs_warn(__xpcs, __state, __args...) \
305({ \
306 if ((__state)->link) \
307 dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
308})
309
310static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
311 struct phylink_link_state *state,
312 u16 pcs_stat1)
313{
314 int ret;
315
316 if (pcs_stat1 & MDIO_STAT1_FAULT) {
317 xpcs_warn(xpcs, state, "Link fault condition detected!\n");
318 return -EFAULT;
319 }
320
321 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
322 if (ret < 0)
323 return ret;
324
325 if (ret & MDIO_STAT2_RXFAULT)
326 xpcs_warn(xpcs, state, "Receiver fault detected!\n");
327 if (ret & MDIO_STAT2_TXFAULT)
328 xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
329
330 ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
331 if (ret < 0)
332 return ret;
333
334 if (ret & DW_RXFIFO_ERR) {
335 xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
336 return -EFAULT;
337 }
338
339 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
340 if (ret < 0)
341 return ret;
342
343 if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
344 xpcs_warn(xpcs, state, "Link is not locked!\n");
345
346 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
347 if (ret < 0)
348 return ret;
349
350 if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
351 xpcs_warn(xpcs, state, "Link has errors!\n");
352 return -EFAULT;
353 }
354
355 return 0;
356}
357
358static void xpcs_link_up_usxgmii(struct dw_xpcs *xpcs, int speed)
359{
360 int ret, speed_sel;
361
362 switch (speed) {
363 case SPEED_10:
364 speed_sel = DW_USXGMII_10;
365 break;
366 case SPEED_100:
367 speed_sel = DW_USXGMII_100;
368 break;
369 case SPEED_1000:
370 speed_sel = DW_USXGMII_1000;
371 break;
372 case SPEED_2500:
373 speed_sel = DW_USXGMII_2500;
374 break;
375 case SPEED_5000:
376 speed_sel = DW_USXGMII_5000;
377 break;
378 case SPEED_10000:
379 speed_sel = DW_USXGMII_10000;
380 break;
381 default:
382 /* Nothing to do here */
383 return;
384 }
385
386 ret = xpcs_modify_vpcs(xpcs, MDIO_CTRL1, DW_USXGMII_EN, DW_USXGMII_EN);
387 if (ret < 0)
388 goto out;
389
390 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, DW_USXGMII_SS_MASK,
391 speed_sel | DW_USXGMII_FULL);
392 if (ret < 0)
393 goto out;
394
395 ret = xpcs_modify_vpcs(xpcs, MDIO_CTRL1, DW_USXGMII_RST,
396 DW_USXGMII_RST);
397 if (ret < 0)
398 goto out;
399
400 return;
401
402out:
403 dev_err(&xpcs->mdiodev->dev, "%s: XPCS access returned %pe\n",
404 __func__, ERR_PTR(ret));
405}
406
407static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
408 const struct dw_xpcs_compat *compat)
409{
410 int ret, adv;
411
412 /* By default, in USXGMII mode XPCS operates at 10G baud and
413 * replicates data to achieve lower speeds. Hereby, in this
414 * default configuration we need to advertise all supported
415 * modes and not only the ones we want to use.
416 */
417
418 /* SR_AN_ADV3 */
419 adv = 0;
420 if (xpcs_linkmode_supported(compat, 2500baseX_Full))
421 adv |= DW_C73_2500KX;
422
423 /* TODO: 5000baseKR */
424
425 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
426 if (ret < 0)
427 return ret;
428
429 /* SR_AN_ADV2 */
430 adv = 0;
431 if (xpcs_linkmode_supported(compat, 1000baseKX_Full))
432 adv |= DW_C73_1000KX;
433 if (xpcs_linkmode_supported(compat, 10000baseKX4_Full))
434 adv |= DW_C73_10000KX4;
435 if (xpcs_linkmode_supported(compat, 10000baseKR_Full))
436 adv |= DW_C73_10000KR;
437
438 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
439 if (ret < 0)
440 return ret;
441
442 /* SR_AN_ADV1 */
443 adv = DW_C73_AN_ADV_SF;
444 if (xpcs_linkmode_supported(compat, Pause))
445 adv |= DW_C73_PAUSE;
446 if (xpcs_linkmode_supported(compat, Asym_Pause))
447 adv |= DW_C73_ASYM_PAUSE;
448
449 return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
450}
451
452static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
453 const struct dw_xpcs_compat *compat)
454{
455 int ret;
456
457 ret = _xpcs_config_aneg_c73(xpcs, compat);
458 if (ret < 0)
459 return ret;
460
461 return xpcs_modify(xpcs, MDIO_MMD_AN, MDIO_CTRL1,
462 MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART,
463 MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
464}
465
466static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,
467 struct phylink_link_state *state,
468 const struct dw_xpcs_compat *compat, u16 an_stat1)
469{
470 int ret;
471
472 if (an_stat1 & MDIO_AN_STAT1_COMPLETE) {
473 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_AN_LPA);
474 if (ret < 0)
475 return ret;
476
477 /* Check if Aneg outcome is valid */
478 if (!(ret & DW_C73_AN_ADV_SF)) {
479 xpcs_config_aneg_c73(xpcs, compat);
480 return 0;
481 }
482
483 return 1;
484 }
485
486 return 0;
487}
488
489static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,
490 struct phylink_link_state *state, u16 an_stat1)
491{
492 u16 lpa[3];
493 int i, ret;
494
495 if (!(an_stat1 & MDIO_AN_STAT1_LPABLE)) {
496 phylink_clear(state->lp_advertising, Autoneg);
497 return 0;
498 }
499
500 phylink_set(state->lp_advertising, Autoneg);
501
502 /* Read Clause 73 link partner advertisement */
503 for (i = ARRAY_SIZE(lpa); --i >= 0; ) {
504 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_AN_LPA + i);
505 if (ret < 0)
506 return ret;
507
508 lpa[i] = ret;
509 }
510
511 mii_c73_mod_linkmode(state->lp_advertising, lpa);
512
513 return 0;
514}
515
516static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
517 struct phylink_link_state *state)
518{
519 unsigned long *adv = state->advertising;
520 int speed = SPEED_UNKNOWN;
521 int bit;
522
523 for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
524 int new_speed = SPEED_UNKNOWN;
525
526 switch (bit) {
527 case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
528 case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
529 case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
530 new_speed = SPEED_25000;
531 break;
532 case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
533 case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
534 case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
535 case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
536 new_speed = SPEED_40000;
537 break;
538 case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
539 case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
540 case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
541 case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
542 case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
543 case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
544 case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
545 case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
546 new_speed = SPEED_50000;
547 break;
548 case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
549 case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
550 case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
551 case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
552 case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
553 case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
554 case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
555 case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
556 case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
557 new_speed = SPEED_100000;
558 break;
559 default:
560 continue;
561 }
562
563 if (new_speed > speed)
564 speed = new_speed;
565 }
566
567 return speed;
568}
569
570static int xpcs_c45_read_pcs_speed(struct dw_xpcs *xpcs,
571 struct phylink_link_state *state)
572{
573 int pcs_ctrl1;
574
575 pcs_ctrl1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_CTRL1);
576 if (pcs_ctrl1 < 0)
577 return pcs_ctrl1;
578
579 switch (pcs_ctrl1 & MDIO_CTRL1_SPEEDSEL) {
580 case MDIO_PCS_CTRL1_SPEED25G:
581 state->speed = SPEED_25000;
582 break;
583 case MDIO_PCS_CTRL1_SPEED50G:
584 state->speed = SPEED_50000;
585 break;
586 case MDIO_PCS_CTRL1_SPEED100G:
587 state->speed = SPEED_100000;
588 break;
589 default:
590 state->speed = SPEED_UNKNOWN;
591 break;
592 }
593
594 return 0;
595}
596
597static int xpcs_resolve_pma(struct dw_xpcs *xpcs,
598 struct phylink_link_state *state)
599{
600 int pmd_rxdet, err = 0;
601
602 /* The Meta Platforms FBNIC PMD will go into a training state for
603 * about 4 seconds when the link first comes up. During this time the
604 * PCS link will bounce. To avoid reporting link up too soon we include
605 * the PMD state provided by the driver.
606 */
607 if (xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID) {
608 pmd_rxdet = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_PMA_RXDET);
609 if (pmd_rxdet < 0) {
610 state->link = false;
611 return pmd_rxdet;
612 }
613
614 /* Verify Rx lanes are trained before reporting link up */
615 if (!(pmd_rxdet & MDIO_PMD_RXDET_GLOBAL)) {
616 state->link = false;
617 return 0;
618 }
619 }
620
621 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
622 state->duplex = DUPLEX_FULL;
623
624 switch (state->interface) {
625 case PHY_INTERFACE_MODE_10GKR:
626 state->speed = SPEED_10000;
627 break;
628 case PHY_INTERFACE_MODE_XLGMII:
629 state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
630 break;
631 case PHY_INTERFACE_MODE_100GBASEP:
632 case PHY_INTERFACE_MODE_LAUI:
633 case PHY_INTERFACE_MODE_50GBASER:
634 case PHY_INTERFACE_MODE_25GBASER:
635 err = xpcs_c45_read_pcs_speed(xpcs, state);
636 break;
637 default:
638 state->speed = SPEED_UNKNOWN;
639 break;
640 }
641
642 return err;
643}
644
645static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
646 const struct phylink_link_state *state)
647{
648 __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
649 const struct dw_xpcs_compat *compat;
650 struct dw_xpcs *xpcs;
651 int i;
652
653 xpcs = phylink_pcs_to_xpcs(pcs);
654 compat = xpcs_find_compat(xpcs, state->interface);
655 if (!compat)
656 return -EINVAL;
657
658 /* Populate the supported link modes for this PHY interface type.
659 * FIXME: what about the port modes and autoneg bit? This masks
660 * all those away.
661 */
662 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
663 set_bit(compat->supported[i], xpcs_supported);
664
665 linkmode_and(supported, supported, xpcs_supported);
666
667 return 0;
668}
669
670static unsigned int xpcs_inband_caps(struct phylink_pcs *pcs,
671 phy_interface_t interface)
672{
673 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
674 const struct dw_xpcs_compat *compat;
675
676 compat = xpcs_find_compat(xpcs, interface);
677 if (!compat)
678 return 0;
679
680 switch (compat->an_mode) {
681 case DW_AN_C73:
682 return LINK_INBAND_ENABLE;
683
684 case DW_AN_C37_SGMII:
685 case DW_AN_C37_1000BASEX:
686 return LINK_INBAND_DISABLE | LINK_INBAND_ENABLE;
687
688 case DW_10GBASER:
689 case DW_2500BASEX:
690 return LINK_INBAND_DISABLE;
691
692 default:
693 return 0;
694 }
695}
696
697static void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
698{
699 const struct dw_xpcs_compat *compat;
700
701 for (compat = xpcs->desc->compat; compat->supported; compat++)
702 __set_bit(compat->interface, interfaces);
703}
704
705static int xpcs_switch_interface_mode(struct dw_xpcs *xpcs,
706 phy_interface_t interface)
707{
708 int ret = 0;
709
710 if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
711 ret = txgbe_xpcs_switch_mode(xpcs, interface);
712 } else if (xpcs->interface != interface) {
713 if (interface == PHY_INTERFACE_MODE_SGMII)
714 xpcs->need_reset = true;
715 xpcs->interface = interface;
716 }
717
718 return ret;
719}
720
721static void xpcs_pre_config(struct phylink_pcs *pcs, phy_interface_t interface)
722{
723 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
724 const struct dw_xpcs_compat *compat;
725 int ret;
726
727 ret = xpcs_switch_interface_mode(xpcs, interface);
728 if (ret)
729 dev_err(&xpcs->mdiodev->dev, "switch interface failed: %pe\n",
730 ERR_PTR(ret));
731
732 if (!xpcs->need_reset)
733 return;
734
735 compat = xpcs_find_compat(xpcs, interface);
736 if (!compat) {
737 dev_err(&xpcs->mdiodev->dev, "unsupported interface %s\n",
738 phy_modes(interface));
739 return;
740 }
741
742 ret = xpcs_soft_reset(xpcs, compat);
743 if (ret)
744 dev_err(&xpcs->mdiodev->dev, "soft reset failed: %pe\n",
745 ERR_PTR(ret));
746
747 xpcs->need_reset = false;
748}
749
750static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs,
751 unsigned int neg_mode)
752{
753 int ret, mdio_ctrl, tx_conf;
754 u16 mask, val;
755
756 /* For AN for C37 SGMII mode, the settings are :-
757 * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
758 it is already enabled)
759 * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
760 * 3) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
761 * DW xPCS used with DW EQoS MAC is always MAC side SGMII.
762 * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
763 * speed/duplex mode change by HW after SGMII AN complete)
764 * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)
765 *
766 * Note that VR_MII_MMD_CTRL is MII_BMCR.
767 *
768 * Note: Since it is MAC side SGMII, there is no need to set
769 * SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from
770 * PHY about the link state change after C28 AN is completed
771 * between PHY and Link Partner. There is also no need to
772 * trigger AN restart for MAC-side SGMII.
773 */
774 mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
775 if (mdio_ctrl < 0)
776 return mdio_ctrl;
777
778 if (mdio_ctrl & BMCR_ANENABLE) {
779 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
780 mdio_ctrl & ~BMCR_ANENABLE);
781 if (ret < 0)
782 return ret;
783 }
784
785 mask = DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK;
786 val = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK,
787 DW_VR_MII_PCS_MODE_C37_SGMII);
788
789 if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
790 mask |= DW_VR_MII_AN_CTRL_8BIT;
791 val |= DW_VR_MII_AN_CTRL_8BIT;
792 /* Hardware requires it to be PHY side SGMII */
793 tx_conf = DW_VR_MII_TX_CONFIG_PHY_SIDE_SGMII;
794 } else {
795 tx_conf = DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII;
796 }
797
798 val |= FIELD_PREP(DW_VR_MII_TX_CONFIG_MASK, tx_conf);
799
800 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, mask, val);
801 if (ret < 0)
802 return ret;
803
804 val = 0;
805 mask = DW_VR_MII_DIG_CTRL1_2G5_EN | DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
806
807 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
808 val = DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
809
810 if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
811 mask |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
812 val |= DW_VR_MII_DIG_CTRL1_PHY_MODE_CTRL;
813 }
814
815 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, mask, val);
816 if (ret < 0)
817 return ret;
818
819 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
820 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
821 mdio_ctrl | BMCR_ANENABLE);
822
823 return ret;
824}
825
826static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs,
827 unsigned int neg_mode,
828 const unsigned long *advertising)
829{
830 phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX;
831 int ret, mdio_ctrl, adv;
832 bool changed = 0;
833 u16 mask, val;
834
835 /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
836 * be disabled first:-
837 * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
838 * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
839 *
840 * Note that VR_MII_MMD_CTRL is MII_BMCR.
841 */
842 mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
843 if (mdio_ctrl < 0)
844 return mdio_ctrl;
845
846 if (mdio_ctrl & BMCR_ANENABLE) {
847 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
848 mdio_ctrl & ~BMCR_ANENABLE);
849 if (ret < 0)
850 return ret;
851 }
852
853 mask = DW_VR_MII_PCS_MODE_MASK;
854 val = FIELD_PREP(DW_VR_MII_PCS_MODE_MASK,
855 DW_VR_MII_PCS_MODE_C37_1000BASEX);
856
857 if (!xpcs->pcs.poll) {
858 mask |= DW_VR_MII_AN_INTR_EN;
859 val |= DW_VR_MII_AN_INTR_EN;
860 }
861
862 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, mask, val);
863 if (ret < 0)
864 return ret;
865
866 /* Check for advertising changes and update the C45 MII ADV
867 * register accordingly.
868 */
869 adv = phylink_mii_c22_pcs_encode_advertisement(interface,
870 advertising);
871 if (adv >= 0) {
872 ret = xpcs_modify_changed(xpcs, MDIO_MMD_VEND2,
873 MII_ADVERTISE, 0xffff, adv);
874 if (ret < 0)
875 return ret;
876
877 changed = ret;
878 }
879
880 /* Clear CL37 AN complete status */
881 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
882 if (ret < 0)
883 return ret;
884
885 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
886 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
887 mdio_ctrl | BMCR_ANENABLE);
888 if (ret < 0)
889 return ret;
890 }
891
892 return changed;
893}
894
895static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
896{
897 int ret;
898
899 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1,
900 DW_VR_MII_DIG_CTRL1_2G5_EN |
901 DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW,
902 DW_VR_MII_DIG_CTRL1_2G5_EN);
903 if (ret < 0)
904 return ret;
905
906 return xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR,
907 BMCR_ANENABLE | BMCR_SPEED1000 | BMCR_SPEED100,
908 BMCR_SPEED1000);
909}
910
911static int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
912 const unsigned long *advertising,
913 unsigned int neg_mode)
914{
915 const struct dw_xpcs_compat *compat;
916 int ret;
917
918 compat = xpcs_find_compat(xpcs, interface);
919 if (!compat)
920 return -ENODEV;
921
922 if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID) {
923 /* Wangxun devices need backplane CL37 AN enabled for
924 * SGMII and 1000base-X
925 */
926 if (interface == PHY_INTERFACE_MODE_SGMII ||
927 interface == PHY_INTERFACE_MODE_1000BASEX)
928 xpcs_write_vpcs(xpcs, DW_VR_XS_PCS_DIG_CTRL1,
929 DW_CL37_BP | DW_EN_VSMMD1);
930 }
931
932 switch (compat->an_mode) {
933 case DW_10GBASER:
934 break;
935 case DW_AN_C73:
936 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED) {
937 ret = xpcs_config_aneg_c73(xpcs, compat);
938 if (ret)
939 return ret;
940 }
941 break;
942 case DW_AN_C37_SGMII:
943 ret = xpcs_config_aneg_c37_sgmii(xpcs, neg_mode);
944 if (ret)
945 return ret;
946 break;
947 case DW_AN_C37_1000BASEX:
948 ret = xpcs_config_aneg_c37_1000basex(xpcs, neg_mode,
949 advertising);
950 if (ret)
951 return ret;
952 break;
953 case DW_2500BASEX:
954 ret = xpcs_config_2500basex(xpcs);
955 if (ret)
956 return ret;
957 break;
958 default:
959 return -EINVAL;
960 }
961
962 if (compat->pma_config) {
963 ret = compat->pma_config(xpcs);
964 if (ret)
965 return ret;
966 }
967
968 return 0;
969}
970
971static int xpcs_config(struct phylink_pcs *pcs, unsigned int neg_mode,
972 phy_interface_t interface,
973 const unsigned long *advertising,
974 bool permit_pause_to_mac)
975{
976 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
977
978 return xpcs_do_config(xpcs, interface, advertising, neg_mode);
979}
980
981static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
982 struct phylink_link_state *state,
983 const struct dw_xpcs_compat *compat)
984{
985 bool an_enabled;
986 int pcs_stat1;
987 int an_stat1;
988 int ret;
989
990 /* The link status bit is latching-low, so it is important to
991 * avoid unnecessary re-reads of this register to avoid missing
992 * a link-down event.
993 */
994 pcs_stat1 = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
995 if (pcs_stat1 < 0) {
996 state->link = false;
997 return pcs_stat1;
998 }
999
1000 /* Link needs to be read first ... */
1001 state->link = !!(pcs_stat1 & MDIO_STAT1_LSTATUS);
1002
1003 /* ... and then we check the faults. */
1004 ret = xpcs_read_fault_c73(xpcs, state, pcs_stat1);
1005 if (ret) {
1006 ret = xpcs_soft_reset(xpcs, compat);
1007 if (ret)
1008 return ret;
1009
1010 state->link = 0;
1011
1012 return xpcs_do_config(xpcs, state->interface, NULL,
1013 PHYLINK_PCS_NEG_INBAND_ENABLED);
1014 }
1015
1016 /* There is no point doing anything else if the link is down. */
1017 if (!state->link)
1018 return 0;
1019
1020 an_enabled = linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
1021 state->advertising);
1022 if (an_enabled) {
1023 /* The link status bit is latching-low, so it is important to
1024 * avoid unnecessary re-reads of this register to avoid missing
1025 * a link-down event.
1026 */
1027 an_stat1 = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
1028 if (an_stat1 < 0) {
1029 state->link = false;
1030 return an_stat1;
1031 }
1032
1033 state->an_complete = xpcs_aneg_done_c73(xpcs, state, compat,
1034 an_stat1);
1035 if (!state->an_complete) {
1036 state->link = false;
1037 return 0;
1038 }
1039
1040 ret = xpcs_read_lpa_c73(xpcs, state, an_stat1);
1041 if (ret < 0) {
1042 state->link = false;
1043 return ret;
1044 }
1045
1046 phylink_resolve_c73(state);
1047 } else {
1048 ret = xpcs_resolve_pma(xpcs, state);
1049 }
1050
1051 return ret;
1052}
1053
1054static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
1055 struct phylink_link_state *state)
1056{
1057 int ret;
1058
1059 /* Reset link_state */
1060 state->link = false;
1061 state->speed = SPEED_UNKNOWN;
1062 state->duplex = DUPLEX_UNKNOWN;
1063 state->pause = 0;
1064
1065 /* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link
1066 * status, speed and duplex.
1067 */
1068 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
1069 if (ret < 0)
1070 return ret;
1071
1072 if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
1073 int speed_value;
1074
1075 state->link = true;
1076
1077 speed_value = FIELD_GET(DW_VR_MII_AN_STS_C37_ANSGM_SP, ret);
1078 if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
1079 state->speed = SPEED_1000;
1080 else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
1081 state->speed = SPEED_100;
1082 else
1083 state->speed = SPEED_10;
1084
1085 if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
1086 state->duplex = DUPLEX_FULL;
1087 else
1088 state->duplex = DUPLEX_HALF;
1089 } else if (ret == DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
1090 int speed, duplex;
1091
1092 state->link = true;
1093
1094 speed = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMCR);
1095 if (speed < 0)
1096 return speed;
1097
1098 speed &= BMCR_SPEED100 | BMCR_SPEED1000;
1099 if (speed == BMCR_SPEED1000)
1100 state->speed = SPEED_1000;
1101 else if (speed == BMCR_SPEED100)
1102 state->speed = SPEED_100;
1103 else if (speed == 0)
1104 state->speed = SPEED_10;
1105
1106 duplex = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_ADVERTISE);
1107 if (duplex < 0)
1108 return duplex;
1109
1110 if (duplex & ADVERTISE_1000XFULL)
1111 state->duplex = DUPLEX_FULL;
1112 else if (duplex & ADVERTISE_1000XHALF)
1113 state->duplex = DUPLEX_HALF;
1114
1115 xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
1116 }
1117
1118 return 0;
1119}
1120
1121static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
1122 unsigned int neg_mode,
1123 struct phylink_link_state *state)
1124{
1125 int lpa, bmsr;
1126
1127 if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
1128 state->advertising)) {
1129 /* Reset link state */
1130 state->link = false;
1131
1132 lpa = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_LPA);
1133 if (lpa < 0 || lpa & LPA_RFAULT)
1134 return lpa;
1135
1136 bmsr = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
1137 if (bmsr < 0)
1138 return bmsr;
1139
1140 /* Clear AN complete interrupt */
1141 if (!xpcs->pcs.poll) {
1142 int an_intr;
1143
1144 an_intr = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
1145 if (an_intr & DW_VR_MII_AN_STS_C37_ANCMPLT_INTR) {
1146 an_intr &= ~DW_VR_MII_AN_STS_C37_ANCMPLT_INTR;
1147 xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, an_intr);
1148 }
1149 }
1150
1151 phylink_mii_c22_pcs_decode_state(state, neg_mode, bmsr, lpa);
1152 }
1153
1154 return 0;
1155}
1156
1157static int xpcs_get_state_2500basex(struct dw_xpcs *xpcs,
1158 struct phylink_link_state *state)
1159{
1160 int ret;
1161
1162 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
1163 if (ret < 0) {
1164 state->link = 0;
1165 return ret;
1166 }
1167
1168 state->link = !!(ret & BMSR_LSTATUS);
1169 if (!state->link)
1170 return 0;
1171
1172 state->speed = SPEED_2500;
1173 state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX;
1174 state->duplex = DUPLEX_FULL;
1175
1176 return 0;
1177}
1178
1179static void xpcs_get_state(struct phylink_pcs *pcs, unsigned int neg_mode,
1180 struct phylink_link_state *state)
1181{
1182 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1183 const struct dw_xpcs_compat *compat;
1184 int ret;
1185
1186 compat = xpcs_find_compat(xpcs, state->interface);
1187 if (!compat)
1188 return;
1189
1190 switch (compat->an_mode) {
1191 case DW_10GBASER:
1192 phylink_mii_c45_pcs_get_state(xpcs->mdiodev, state);
1193 break;
1194 case DW_AN_C73:
1195 ret = xpcs_get_state_c73(xpcs, state, compat);
1196 if (ret)
1197 dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
1198 "xpcs_get_state_c73", ERR_PTR(ret));
1199 break;
1200 case DW_AN_C37_SGMII:
1201 ret = xpcs_get_state_c37_sgmii(xpcs, state);
1202 if (ret)
1203 dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
1204 "xpcs_get_state_c37_sgmii", ERR_PTR(ret));
1205 break;
1206 case DW_AN_C37_1000BASEX:
1207 ret = xpcs_get_state_c37_1000basex(xpcs, neg_mode, state);
1208 if (ret)
1209 dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
1210 "xpcs_get_state_c37_1000basex", ERR_PTR(ret));
1211 break;
1212 case DW_2500BASEX:
1213 ret = xpcs_get_state_2500basex(xpcs, state);
1214 if (ret)
1215 dev_err(&xpcs->mdiodev->dev, "%s returned %pe\n",
1216 "xpcs_get_state_2500basex", ERR_PTR(ret));
1217 break;
1218 default:
1219 return;
1220 }
1221}
1222
1223static void xpcs_link_up_sgmii_1000basex(struct dw_xpcs *xpcs,
1224 unsigned int neg_mode,
1225 phy_interface_t interface,
1226 int speed, int duplex)
1227{
1228 int ret;
1229
1230 if (neg_mode == PHYLINK_PCS_NEG_INBAND_ENABLED)
1231 return;
1232
1233 if (interface == PHY_INTERFACE_MODE_1000BASEX) {
1234 if (speed != SPEED_1000) {
1235 dev_err(&xpcs->mdiodev->dev,
1236 "%s: speed %dMbps not supported\n",
1237 __func__, speed);
1238 return;
1239 }
1240
1241 if (duplex != DUPLEX_FULL)
1242 dev_err(&xpcs->mdiodev->dev,
1243 "%s: half duplex not supported\n",
1244 __func__);
1245 }
1246
1247 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MII_BMCR,
1248 mii_bmcr_encode_fixed(speed, duplex));
1249 if (ret)
1250 dev_err(&xpcs->mdiodev->dev, "%s: xpcs_write returned %pe\n",
1251 __func__, ERR_PTR(ret));
1252}
1253
1254static void xpcs_link_up(struct phylink_pcs *pcs, unsigned int neg_mode,
1255 phy_interface_t interface, int speed, int duplex)
1256{
1257 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1258
1259 switch (interface) {
1260 case PHY_INTERFACE_MODE_USXGMII:
1261 xpcs_link_up_usxgmii(xpcs, speed);
1262 break;
1263
1264 case PHY_INTERFACE_MODE_SGMII:
1265 case PHY_INTERFACE_MODE_1000BASEX:
1266 xpcs_link_up_sgmii_1000basex(xpcs, neg_mode, interface, speed,
1267 duplex);
1268 break;
1269
1270 default:
1271 break;
1272 }
1273}
1274
1275static void xpcs_an_restart(struct phylink_pcs *pcs)
1276{
1277 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1278
1279 xpcs_modify(xpcs, MDIO_MMD_VEND2, MII_BMCR, BMCR_ANRESTART,
1280 BMCR_ANRESTART);
1281}
1282
1283static int xpcs_config_eee(struct dw_xpcs *xpcs, bool enable)
1284{
1285 u16 mask, val;
1286 int ret;
1287
1288 mask = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
1289 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
1290 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
1291 DW_VR_MII_EEE_MULT_FACT_100NS;
1292
1293 if (enable)
1294 val = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
1295 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
1296 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
1297 FIELD_PREP(DW_VR_MII_EEE_MULT_FACT_100NS,
1298 xpcs->eee_mult_fact);
1299 else
1300 val = 0;
1301
1302 ret = xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, mask,
1303 val);
1304 if (ret < 0)
1305 return ret;
1306
1307 return xpcs_modify(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1,
1308 DW_VR_MII_EEE_TRN_LPI,
1309 enable ? DW_VR_MII_EEE_TRN_LPI : 0);
1310}
1311
1312static void xpcs_disable_eee(struct phylink_pcs *pcs)
1313{
1314 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1315
1316 xpcs_config_eee(xpcs, false);
1317}
1318
1319static void xpcs_enable_eee(struct phylink_pcs *pcs)
1320{
1321 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1322
1323 xpcs_config_eee(xpcs, true);
1324}
1325
1326/**
1327 * xpcs_config_eee_mult_fact() - set the EEE clock multiplying factor
1328 * @xpcs: pointer to a &struct dw_xpcs instance
1329 * @mult_fact: the multiplying factor
1330 *
1331 * Configure the EEE clock multiplying factor. This value should be such that
1332 * clk_eee_time_period * (mult_fact + 1) is within the range 80 to 120ns.
1333 */
1334void xpcs_config_eee_mult_fact(struct dw_xpcs *xpcs, u8 mult_fact)
1335{
1336 xpcs->eee_mult_fact = mult_fact;
1337}
1338EXPORT_SYMBOL_GPL(xpcs_config_eee_mult_fact);
1339
1340static int xpcs_read_ids(struct dw_xpcs *xpcs)
1341{
1342 int ret;
1343 u32 id;
1344
1345 /* First, search C73 PCS using PCS MMD 3. Return ENODEV if communication
1346 * failed indicating that device couldn't be reached.
1347 */
1348 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
1349 if (ret < 0)
1350 return -ENODEV;
1351
1352 id = ret << 16;
1353
1354 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
1355 if (ret < 0)
1356 return ret;
1357
1358 id |= ret;
1359
1360 /* If Device IDs are not all zeros or ones, then 10GBase-X/R or C73
1361 * KR/KX4 PCS found. Otherwise fallback to detecting 1000Base-X or C37
1362 * PCS in MII MMD 31.
1363 */
1364 if (!id || id == 0xffffffff) {
1365 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
1366 if (ret < 0)
1367 return ret;
1368
1369 id = ret << 16;
1370
1371 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
1372 if (ret < 0)
1373 return ret;
1374
1375 id |= ret;
1376 }
1377
1378 /* Set the PCS ID if it hasn't been pre-initialized */
1379 if (xpcs->info.pcs == DW_XPCS_ID_NATIVE)
1380 xpcs->info.pcs = id;
1381
1382 /* Find out PMA/PMD ID from MMD 1 device ID registers */
1383 ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID1);
1384 if (ret < 0)
1385 return ret;
1386
1387 id = ret << 16;
1388
1389 ret = xpcs_read(xpcs, MDIO_MMD_PMAPMD, MDIO_DEVID2);
1390 if (ret < 0)
1391 return ret;
1392
1393 /* For now we only record the OUI for the PMAPMD, we may want to
1394 * add the model number at some point in the future.
1395 */
1396 id |= ret & MDIO_DEVID2_OUI;
1397
1398 /* Set the PMA ID if it hasn't been pre-initialized */
1399 if (xpcs->info.pma == DW_XPCS_PMA_ID_NATIVE)
1400 xpcs->info.pma = id;
1401
1402 return 0;
1403}
1404
1405static const struct dw_xpcs_compat synopsys_xpcs_compat[] = {
1406 {
1407 .interface = PHY_INTERFACE_MODE_USXGMII,
1408 .supported = xpcs_usxgmii_features,
1409 .an_mode = DW_AN_C73,
1410 }, {
1411 .interface = PHY_INTERFACE_MODE_10GKR,
1412 .supported = xpcs_10gkr_features,
1413 .an_mode = DW_AN_C73,
1414 }, {
1415 .interface = PHY_INTERFACE_MODE_25GBASER,
1416 .supported = xpcs_25gbaser_features,
1417 .an_mode = DW_AN_C73,
1418 }, {
1419 .interface = PHY_INTERFACE_MODE_XLGMII,
1420 .supported = xpcs_xlgmii_features,
1421 .an_mode = DW_AN_C73,
1422 }, {
1423 .interface = PHY_INTERFACE_MODE_50GBASER,
1424 .supported = xpcs_50gbaser_features,
1425 .an_mode = DW_AN_C73,
1426 }, {
1427 .interface = PHY_INTERFACE_MODE_LAUI,
1428 .supported = xpcs_50gbaser2_features,
1429 .an_mode = DW_AN_C73,
1430 }, {
1431 .interface = PHY_INTERFACE_MODE_100GBASEP,
1432 .supported = xpcs_100gbasep_features,
1433 .an_mode = DW_AN_C73,
1434 }, {
1435 .interface = PHY_INTERFACE_MODE_10GBASER,
1436 .supported = xpcs_10gbaser_features,
1437 .an_mode = DW_10GBASER,
1438 }, {
1439 .interface = PHY_INTERFACE_MODE_SGMII,
1440 .supported = xpcs_sgmii_features,
1441 .an_mode = DW_AN_C37_SGMII,
1442 }, {
1443 .interface = PHY_INTERFACE_MODE_1000BASEX,
1444 .supported = xpcs_1000basex_features,
1445 .an_mode = DW_AN_C37_1000BASEX,
1446 }, {
1447 .interface = PHY_INTERFACE_MODE_2500BASEX,
1448 .supported = xpcs_2500basex_features,
1449 .an_mode = DW_2500BASEX,
1450 }, {
1451 }
1452};
1453
1454static const struct dw_xpcs_compat nxp_sja1105_xpcs_compat[] = {
1455 {
1456 .interface = PHY_INTERFACE_MODE_SGMII,
1457 .supported = xpcs_sgmii_features,
1458 .an_mode = DW_AN_C37_SGMII,
1459 .pma_config = nxp_sja1105_sgmii_pma_config,
1460 }, {
1461 }
1462};
1463
1464static const struct dw_xpcs_compat nxp_sja1110_xpcs_compat[] = {
1465 {
1466 .interface = PHY_INTERFACE_MODE_SGMII,
1467 .supported = xpcs_sgmii_features,
1468 .an_mode = DW_AN_C37_SGMII,
1469 .pma_config = nxp_sja1110_sgmii_pma_config,
1470 }, {
1471 .interface = PHY_INTERFACE_MODE_2500BASEX,
1472 .supported = xpcs_2500basex_features,
1473 .an_mode = DW_2500BASEX,
1474 .pma_config = nxp_sja1110_2500basex_pma_config,
1475 }, {
1476 }
1477};
1478
1479static const struct dw_xpcs_desc xpcs_desc_list[] = {
1480 {
1481 .id = DW_XPCS_ID,
1482 .mask = DW_XPCS_ID_MASK,
1483 .compat = synopsys_xpcs_compat,
1484 }, {
1485 .id = NXP_SJA1105_XPCS_ID,
1486 .mask = DW_XPCS_ID_MASK,
1487 .compat = nxp_sja1105_xpcs_compat,
1488 }, {
1489 .id = NXP_SJA1110_XPCS_ID,
1490 .mask = DW_XPCS_ID_MASK,
1491 .compat = nxp_sja1110_xpcs_compat,
1492 },
1493};
1494
1495static const struct phylink_pcs_ops xpcs_phylink_ops = {
1496 .pcs_validate = xpcs_validate,
1497 .pcs_inband_caps = xpcs_inband_caps,
1498 .pcs_pre_config = xpcs_pre_config,
1499 .pcs_config = xpcs_config,
1500 .pcs_get_state = xpcs_get_state,
1501 .pcs_an_restart = xpcs_an_restart,
1502 .pcs_link_up = xpcs_link_up,
1503 .pcs_disable_eee = xpcs_disable_eee,
1504 .pcs_enable_eee = xpcs_enable_eee,
1505};
1506
1507static int xpcs_identify(struct dw_xpcs *xpcs)
1508{
1509 int i, ret;
1510
1511 ret = xpcs_read_ids(xpcs);
1512 if (ret < 0)
1513 return ret;
1514
1515 for (i = 0; i < ARRAY_SIZE(xpcs_desc_list); i++) {
1516 const struct dw_xpcs_desc *entry = &xpcs_desc_list[i];
1517
1518 if ((xpcs->info.pcs & entry->mask) == entry->id) {
1519 xpcs->desc = entry;
1520 return 0;
1521 }
1522 }
1523
1524 return -ENODEV;
1525}
1526
1527static struct dw_xpcs *xpcs_create_data(struct mdio_device *mdiodev)
1528{
1529 struct dw_xpcs *xpcs;
1530
1531 xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
1532 if (!xpcs)
1533 return ERR_PTR(-ENOMEM);
1534
1535 mdio_device_get(mdiodev);
1536 xpcs->mdiodev = mdiodev;
1537 xpcs->pcs.ops = &xpcs_phylink_ops;
1538 xpcs->pcs.poll = true;
1539
1540 return xpcs;
1541}
1542
1543static void xpcs_free_data(struct dw_xpcs *xpcs)
1544{
1545 mdio_device_put(xpcs->mdiodev);
1546 kfree(xpcs);
1547}
1548
1549static int xpcs_init_clks(struct dw_xpcs *xpcs)
1550{
1551 static const char *ids[DW_XPCS_NUM_CLKS] = {
1552 [DW_XPCS_CORE_CLK] = "core",
1553 [DW_XPCS_PAD_CLK] = "pad",
1554 };
1555 struct device *dev = &xpcs->mdiodev->dev;
1556 int ret, i;
1557
1558 for (i = 0; i < DW_XPCS_NUM_CLKS; ++i)
1559 xpcs->clks[i].id = ids[i];
1560
1561 ret = clk_bulk_get_optional(dev, DW_XPCS_NUM_CLKS, xpcs->clks);
1562 if (ret)
1563 return dev_err_probe(dev, ret, "Failed to get clocks\n");
1564
1565 ret = clk_bulk_prepare_enable(DW_XPCS_NUM_CLKS, xpcs->clks);
1566 if (ret)
1567 return dev_err_probe(dev, ret, "Failed to enable clocks\n");
1568
1569 return 0;
1570}
1571
1572static void xpcs_clear_clks(struct dw_xpcs *xpcs)
1573{
1574 clk_bulk_disable_unprepare(DW_XPCS_NUM_CLKS, xpcs->clks);
1575
1576 clk_bulk_put(DW_XPCS_NUM_CLKS, xpcs->clks);
1577}
1578
1579static int xpcs_init_id(struct dw_xpcs *xpcs)
1580{
1581 const struct dw_xpcs_info *info;
1582
1583 info = dev_get_platdata(&xpcs->mdiodev->dev);
1584 if (!info) {
1585 xpcs->info.pcs = DW_XPCS_ID_NATIVE;
1586 xpcs->info.pma = DW_XPCS_PMA_ID_NATIVE;
1587 } else {
1588 xpcs->info = *info;
1589 }
1590
1591 return xpcs_identify(xpcs);
1592}
1593
1594static struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev)
1595{
1596 struct dw_xpcs *xpcs;
1597 int ret;
1598
1599 xpcs = xpcs_create_data(mdiodev);
1600 if (IS_ERR(xpcs))
1601 return xpcs;
1602
1603 ret = xpcs_init_clks(xpcs);
1604 if (ret)
1605 goto out_free_data;
1606
1607 ret = xpcs_init_id(xpcs);
1608 if (ret)
1609 goto out_clear_clks;
1610
1611 xpcs_get_interfaces(xpcs, xpcs->pcs.supported_interfaces);
1612
1613 if (xpcs->info.pma == WX_TXGBE_XPCS_PMA_10G_ID ||
1614 xpcs->info.pma == MP_FBNIC_XPCS_PMA_100G_ID)
1615 xpcs->pcs.poll = false;
1616 else
1617 xpcs->need_reset = true;
1618
1619 return xpcs;
1620
1621out_clear_clks:
1622 xpcs_clear_clks(xpcs);
1623
1624out_free_data:
1625 xpcs_free_data(xpcs);
1626
1627 return ERR_PTR(ret);
1628}
1629
1630/**
1631 * xpcs_create_mdiodev() - create a DW xPCS instance with the MDIO @addr
1632 * @bus: pointer to the MDIO-bus descriptor for the device to be looked at
1633 * @addr: device MDIO-bus ID
1634 *
1635 * Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
1636 * the PCS device couldn't be found on the bus and other negative errno related
1637 * to the data allocation and MDIO-bus communications.
1638 */
1639struct dw_xpcs *xpcs_create_mdiodev(struct mii_bus *bus, int addr)
1640{
1641 struct mdio_device *mdiodev;
1642 struct dw_xpcs *xpcs;
1643
1644 mdiodev = mdio_device_create(bus, addr);
1645 if (IS_ERR(mdiodev))
1646 return ERR_CAST(mdiodev);
1647
1648 xpcs = xpcs_create(mdiodev);
1649
1650 /* xpcs_create() has taken a refcount on the mdiodev if it was
1651 * successful. If xpcs_create() fails, this will free the mdio
1652 * device here. In any case, we don't need to hold our reference
1653 * anymore, and putting it here will allow mdio_device_put() in
1654 * xpcs_destroy() to automatically free the mdio device.
1655 */
1656 mdio_device_put(mdiodev);
1657
1658 return xpcs;
1659}
1660EXPORT_SYMBOL_GPL(xpcs_create_mdiodev);
1661
1662struct phylink_pcs *xpcs_create_pcs_mdiodev(struct mii_bus *bus, int addr)
1663{
1664 struct dw_xpcs *xpcs;
1665
1666 xpcs = xpcs_create_mdiodev(bus, addr);
1667 if (IS_ERR(xpcs))
1668 return ERR_CAST(xpcs);
1669
1670 return &xpcs->pcs;
1671}
1672EXPORT_SYMBOL_GPL(xpcs_create_pcs_mdiodev);
1673
1674/**
1675 * xpcs_create_fwnode() - Create a DW xPCS instance from @fwnode
1676 * @fwnode: fwnode handle poining to the DW XPCS device
1677 *
1678 * Return: a pointer to the DW XPCS handle if successful, otherwise -ENODEV if
1679 * the fwnode device is unavailable or the PCS device couldn't be found on the
1680 * bus, -EPROBE_DEFER if the respective MDIO-device instance couldn't be found,
1681 * other negative errno related to the data allocations and MDIO-bus
1682 * communications.
1683 */
1684struct dw_xpcs *xpcs_create_fwnode(struct fwnode_handle *fwnode)
1685{
1686 struct mdio_device *mdiodev;
1687 struct dw_xpcs *xpcs;
1688
1689 if (!fwnode_device_is_available(fwnode))
1690 return ERR_PTR(-ENODEV);
1691
1692 mdiodev = fwnode_mdio_find_device(fwnode);
1693 if (!mdiodev)
1694 return ERR_PTR(-EPROBE_DEFER);
1695
1696 xpcs = xpcs_create(mdiodev);
1697
1698 /* xpcs_create() has taken a refcount on the mdiodev if it was
1699 * successful. If xpcs_create() fails, this will free the mdio
1700 * device here. In any case, we don't need to hold our reference
1701 * anymore, and putting it here will allow mdio_device_put() in
1702 * xpcs_destroy() to automatically free the mdio device.
1703 */
1704 mdio_device_put(mdiodev);
1705
1706 return xpcs;
1707}
1708EXPORT_SYMBOL_GPL(xpcs_create_fwnode);
1709
1710void xpcs_destroy(struct dw_xpcs *xpcs)
1711{
1712 if (!xpcs)
1713 return;
1714
1715 xpcs_clear_clks(xpcs);
1716
1717 xpcs_free_data(xpcs);
1718}
1719EXPORT_SYMBOL_GPL(xpcs_destroy);
1720
1721void xpcs_destroy_pcs(struct phylink_pcs *pcs)
1722{
1723 xpcs_destroy(phylink_pcs_to_xpcs(pcs));
1724}
1725EXPORT_SYMBOL_GPL(xpcs_destroy_pcs);
1726
1727MODULE_DESCRIPTION("Synopsys DesignWare XPCS library");
1728MODULE_LICENSE("GPL v2");