1
2
3
4
5
6
7
8
9#include <linux/delay.h>
10#include <linux/pcs/pcs-xpcs.h>
11#include <linux/mdio.h>
12#include <linux/phylink.h>
13#include <linux/workqueue.h>
14#include "pcs-xpcs.h"
15
16#define phylink_pcs_to_xpcs(pl_pcs) \
17 container_of((pl_pcs), struct dw_xpcs, pcs)
18
19static const int xpcs_usxgmii_features[] = {
20 ETHTOOL_LINK_MODE_Pause_BIT,
21 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
22 ETHTOOL_LINK_MODE_Autoneg_BIT,
23 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
24 ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
25 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
26 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
27 __ETHTOOL_LINK_MODE_MASK_NBITS,
28};
29
30static const int xpcs_10gkr_features[] = {
31 ETHTOOL_LINK_MODE_Pause_BIT,
32 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
33 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
34 __ETHTOOL_LINK_MODE_MASK_NBITS,
35};
36
37static const int xpcs_xlgmii_features[] = {
38 ETHTOOL_LINK_MODE_Pause_BIT,
39 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
40 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
41 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
42 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
43 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
44 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
45 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
46 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
47 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
48 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
49 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
50 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
51 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
52 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
53 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
54 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
55 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
56 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
57 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
58 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
59 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
60 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
61 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
62 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
63 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
64 __ETHTOOL_LINK_MODE_MASK_NBITS,
65};
66
67static const int xpcs_sgmii_features[] = {
68 ETHTOOL_LINK_MODE_Pause_BIT,
69 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
70 ETHTOOL_LINK_MODE_Autoneg_BIT,
71 ETHTOOL_LINK_MODE_10baseT_Half_BIT,
72 ETHTOOL_LINK_MODE_10baseT_Full_BIT,
73 ETHTOOL_LINK_MODE_100baseT_Half_BIT,
74 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
75 ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
76 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
77 __ETHTOOL_LINK_MODE_MASK_NBITS,
78};
79
80static const int xpcs_2500basex_features[] = {
81 ETHTOOL_LINK_MODE_Pause_BIT,
82 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
83 ETHTOOL_LINK_MODE_Autoneg_BIT,
84 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
85 ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
86 __ETHTOOL_LINK_MODE_MASK_NBITS,
87};
88
89static const phy_interface_t xpcs_usxgmii_interfaces[] = {
90 PHY_INTERFACE_MODE_USXGMII,
91};
92
93static const phy_interface_t xpcs_10gkr_interfaces[] = {
94 PHY_INTERFACE_MODE_10GKR,
95};
96
97static const phy_interface_t xpcs_xlgmii_interfaces[] = {
98 PHY_INTERFACE_MODE_XLGMII,
99};
100
101static const phy_interface_t xpcs_sgmii_interfaces[] = {
102 PHY_INTERFACE_MODE_SGMII,
103};
104
105static const phy_interface_t xpcs_2500basex_interfaces[] = {
106 PHY_INTERFACE_MODE_2500BASEX,
107 PHY_INTERFACE_MODE_MAX,
108};
109
110enum {
111 DW_XPCS_USXGMII,
112 DW_XPCS_10GKR,
113 DW_XPCS_XLGMII,
114 DW_XPCS_SGMII,
115 DW_XPCS_2500BASEX,
116 DW_XPCS_INTERFACE_MAX,
117};
118
119struct xpcs_compat {
120 const int *supported;
121 const phy_interface_t *interface;
122 int num_interfaces;
123 int an_mode;
124 int (*pma_config)(struct dw_xpcs *xpcs);
125};
126
127struct xpcs_id {
128 u32 id;
129 u32 mask;
130 const struct xpcs_compat *compat;
131};
132
133static const struct xpcs_compat *xpcs_find_compat(const struct xpcs_id *id,
134 phy_interface_t interface)
135{
136 int i, j;
137
138 for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
139 const struct xpcs_compat *compat = &id->compat[i];
140
141 for (j = 0; j < compat->num_interfaces; j++)
142 if (compat->interface[j] == interface)
143 return compat;
144 }
145
146 return NULL;
147}
148
149int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
150{
151 const struct xpcs_compat *compat;
152
153 compat = xpcs_find_compat(xpcs->id, interface);
154 if (!compat)
155 return -ENODEV;
156
157 return compat->an_mode;
158}
159EXPORT_SYMBOL_GPL(xpcs_get_an_mode);
160
161static bool __xpcs_linkmode_supported(const struct xpcs_compat *compat,
162 enum ethtool_link_mode_bit_indices linkmode)
163{
164 int i;
165
166 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
167 if (compat->supported[i] == linkmode)
168 return true;
169
170 return false;
171}
172
173#define xpcs_linkmode_supported(compat, mode) \
174 __xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
175
176int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
177{
178 u32 reg_addr = mdiobus_c45_addr(dev, reg);
179 struct mii_bus *bus = xpcs->mdiodev->bus;
180 int addr = xpcs->mdiodev->addr;
181
182 return mdiobus_read(bus, addr, reg_addr);
183}
184
185int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
186{
187 u32 reg_addr = mdiobus_c45_addr(dev, reg);
188 struct mii_bus *bus = xpcs->mdiodev->bus;
189 int addr = xpcs->mdiodev->addr;
190
191 return mdiobus_write(bus, addr, reg_addr, val);
192}
193
194static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
195{
196 return xpcs_read(xpcs, dev, DW_VENDOR | reg);
197}
198
199static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
200 u16 val)
201{
202 return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
203}
204
205static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
206{
207 return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
208}
209
210static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
211{
212 return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
213}
214
215static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
216{
217
218 unsigned int retries = 12;
219 int ret;
220
221 do {
222 msleep(50);
223 ret = xpcs_read(xpcs, dev, MDIO_CTRL1);
224 if (ret < 0)
225 return ret;
226 } while (ret & MDIO_CTRL1_RESET && --retries);
227
228 return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
229}
230
231static int xpcs_soft_reset(struct dw_xpcs *xpcs,
232 const struct xpcs_compat *compat)
233{
234 int ret, dev;
235
236 switch (compat->an_mode) {
237 case DW_AN_C73:
238 dev = MDIO_MMD_PCS;
239 break;
240 case DW_AN_C37_SGMII:
241 case DW_2500BASEX:
242 dev = MDIO_MMD_VEND2;
243 break;
244 default:
245 return -1;
246 }
247
248 ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
249 if (ret < 0)
250 return ret;
251
252 return xpcs_poll_reset(xpcs, dev);
253}
254
255#define xpcs_warn(__xpcs, __state, __args...) \
256({ \
257 if ((__state)->link) \
258 dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
259})
260
261static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
262 struct phylink_link_state *state)
263{
264 int ret;
265
266 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
267 if (ret < 0)
268 return ret;
269
270 if (ret & MDIO_STAT1_FAULT) {
271 xpcs_warn(xpcs, state, "Link fault condition detected!\n");
272 return -EFAULT;
273 }
274
275 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
276 if (ret < 0)
277 return ret;
278
279 if (ret & MDIO_STAT2_RXFAULT)
280 xpcs_warn(xpcs, state, "Receiver fault detected!\n");
281 if (ret & MDIO_STAT2_TXFAULT)
282 xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
283
284 ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
285 if (ret < 0)
286 return ret;
287
288 if (ret & DW_RXFIFO_ERR) {
289 xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
290 return -EFAULT;
291 }
292
293 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
294 if (ret < 0)
295 return ret;
296
297 if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
298 xpcs_warn(xpcs, state, "Link is not locked!\n");
299
300 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
301 if (ret < 0)
302 return ret;
303
304 if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
305 xpcs_warn(xpcs, state, "Link has errors!\n");
306 return -EFAULT;
307 }
308
309 return 0;
310}
311
312static int xpcs_read_link_c73(struct dw_xpcs *xpcs, bool an)
313{
314 bool link = true;
315 int ret;
316
317 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
318 if (ret < 0)
319 return ret;
320
321 if (!(ret & MDIO_STAT1_LSTATUS))
322 link = false;
323
324 if (an) {
325 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
326 if (ret < 0)
327 return ret;
328
329 if (!(ret & MDIO_STAT1_LSTATUS))
330 link = false;
331 }
332
333 return link;
334}
335
336static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
337{
338 int max = SPEED_UNKNOWN;
339
340 if (phylink_test(supported, 1000baseKX_Full))
341 max = SPEED_1000;
342 if (phylink_test(supported, 2500baseX_Full))
343 max = SPEED_2500;
344 if (phylink_test(supported, 10000baseKX4_Full))
345 max = SPEED_10000;
346 if (phylink_test(supported, 10000baseKR_Full))
347 max = SPEED_10000;
348
349 return max;
350}
351
352static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed)
353{
354 int ret, speed_sel;
355
356 switch (speed) {
357 case SPEED_10:
358 speed_sel = DW_USXGMII_10;
359 break;
360 case SPEED_100:
361 speed_sel = DW_USXGMII_100;
362 break;
363 case SPEED_1000:
364 speed_sel = DW_USXGMII_1000;
365 break;
366 case SPEED_2500:
367 speed_sel = DW_USXGMII_2500;
368 break;
369 case SPEED_5000:
370 speed_sel = DW_USXGMII_5000;
371 break;
372 case SPEED_10000:
373 speed_sel = DW_USXGMII_10000;
374 break;
375 default:
376
377 return;
378 }
379
380 ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
381 if (ret < 0)
382 goto out;
383
384 ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
385 if (ret < 0)
386 goto out;
387
388 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
389 if (ret < 0)
390 goto out;
391
392 ret &= ~DW_USXGMII_SS_MASK;
393 ret |= speed_sel | DW_USXGMII_FULL;
394
395 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
396 if (ret < 0)
397 goto out;
398
399 ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
400 if (ret < 0)
401 goto out;
402
403 ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
404 if (ret < 0)
405 goto out;
406
407 return;
408
409out:
410 pr_err("%s: XPCS access returned %pe\n", __func__, ERR_PTR(ret));
411}
412
413static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
414 const struct xpcs_compat *compat)
415{
416 int ret, adv;
417
418
419
420
421
422
423
424
425 adv = 0;
426 if (xpcs_linkmode_supported(compat, 2500baseX_Full))
427 adv |= DW_C73_2500KX;
428
429
430
431 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
432 if (ret < 0)
433 return ret;
434
435
436 adv = 0;
437 if (xpcs_linkmode_supported(compat, 1000baseKX_Full))
438 adv |= DW_C73_1000KX;
439 if (xpcs_linkmode_supported(compat, 10000baseKX4_Full))
440 adv |= DW_C73_10000KX4;
441 if (xpcs_linkmode_supported(compat, 10000baseKR_Full))
442 adv |= DW_C73_10000KR;
443
444 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
445 if (ret < 0)
446 return ret;
447
448
449 adv = DW_C73_AN_ADV_SF;
450 if (xpcs_linkmode_supported(compat, Pause))
451 adv |= DW_C73_PAUSE;
452 if (xpcs_linkmode_supported(compat, Asym_Pause))
453 adv |= DW_C73_ASYM_PAUSE;
454
455 return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
456}
457
458static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
459 const struct xpcs_compat *compat)
460{
461 int ret;
462
463 ret = _xpcs_config_aneg_c73(xpcs, compat);
464 if (ret < 0)
465 return ret;
466
467 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1);
468 if (ret < 0)
469 return ret;
470
471 ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
472
473 return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
474}
475
476static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,
477 struct phylink_link_state *state,
478 const struct xpcs_compat *compat)
479{
480 int ret;
481
482 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
483 if (ret < 0)
484 return ret;
485
486 if (ret & MDIO_AN_STAT1_COMPLETE) {
487 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
488 if (ret < 0)
489 return ret;
490
491
492 if (!(ret & DW_C73_AN_ADV_SF)) {
493 xpcs_config_aneg_c73(xpcs, compat);
494 return 0;
495 }
496
497 return 1;
498 }
499
500 return 0;
501}
502
503static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,
504 struct phylink_link_state *state)
505{
506 int ret;
507
508 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
509 if (ret < 0)
510 return ret;
511
512 if (!(ret & MDIO_AN_STAT1_LPABLE)) {
513 phylink_clear(state->lp_advertising, Autoneg);
514 return 0;
515 }
516
517 phylink_set(state->lp_advertising, Autoneg);
518
519
520 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3);
521 if (ret < 0)
522 return ret;
523
524 if (ret & DW_C73_2500KX)
525 phylink_set(state->lp_advertising, 2500baseX_Full);
526
527 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2);
528 if (ret < 0)
529 return ret;
530
531 if (ret & DW_C73_1000KX)
532 phylink_set(state->lp_advertising, 1000baseKX_Full);
533 if (ret & DW_C73_10000KX4)
534 phylink_set(state->lp_advertising, 10000baseKX4_Full);
535 if (ret & DW_C73_10000KR)
536 phylink_set(state->lp_advertising, 10000baseKR_Full);
537
538 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
539 if (ret < 0)
540 return ret;
541
542 if (ret & DW_C73_PAUSE)
543 phylink_set(state->lp_advertising, Pause);
544 if (ret & DW_C73_ASYM_PAUSE)
545 phylink_set(state->lp_advertising, Asym_Pause);
546
547 linkmode_and(state->lp_advertising, state->lp_advertising,
548 state->advertising);
549 return 0;
550}
551
552static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs,
553 struct phylink_link_state *state)
554{
555 int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
556
557 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
558 state->speed = max_speed;
559 state->duplex = DUPLEX_FULL;
560}
561
562static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
563 struct phylink_link_state *state)
564{
565 unsigned long *adv = state->advertising;
566 int speed = SPEED_UNKNOWN;
567 int bit;
568
569 for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
570 int new_speed = SPEED_UNKNOWN;
571
572 switch (bit) {
573 case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
574 case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
575 case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
576 new_speed = SPEED_25000;
577 break;
578 case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
579 case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
580 case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
581 case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
582 new_speed = SPEED_40000;
583 break;
584 case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
585 case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
586 case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
587 case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
588 case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
589 case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
590 case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
591 case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
592 new_speed = SPEED_50000;
593 break;
594 case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
595 case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
596 case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
597 case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
598 case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
599 case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
600 case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
601 case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
602 case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
603 new_speed = SPEED_100000;
604 break;
605 default:
606 continue;
607 }
608
609 if (new_speed > speed)
610 speed = new_speed;
611 }
612
613 return speed;
614}
615
616static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
617 struct phylink_link_state *state)
618{
619 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
620 state->duplex = DUPLEX_FULL;
621
622 switch (state->interface) {
623 case PHY_INTERFACE_MODE_10GKR:
624 state->speed = SPEED_10000;
625 break;
626 case PHY_INTERFACE_MODE_XLGMII:
627 state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
628 break;
629 default:
630 state->speed = SPEED_UNKNOWN;
631 break;
632 }
633}
634
635static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
636 const struct phylink_link_state *state)
637{
638 __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
639 const struct xpcs_compat *compat;
640 struct dw_xpcs *xpcs;
641 int i;
642
643 xpcs = phylink_pcs_to_xpcs(pcs);
644 compat = xpcs_find_compat(xpcs->id, state->interface);
645
646
647
648
649
650 if (compat)
651 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
652 set_bit(compat->supported[i], xpcs_supported);
653
654 linkmode_and(supported, supported, xpcs_supported);
655
656 return 0;
657}
658
659void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
660{
661 int i, j;
662
663 for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
664 const struct xpcs_compat *compat = &xpcs->id->compat[i];
665
666 for (j = 0; j < compat->num_interfaces; j++)
667 if (compat->interface[j] < PHY_INTERFACE_MODE_MAX)
668 __set_bit(compat->interface[j], interfaces);
669 }
670}
671EXPORT_SYMBOL_GPL(xpcs_get_interfaces);
672
673int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
674{
675 int ret;
676
677 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
678 if (ret < 0)
679 return ret;
680
681 if (enable) {
682
683 ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
684 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
685 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
686 mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
687 } else {
688 ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
689 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
690 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
691 DW_VR_MII_EEE_MULT_FACT_100NS);
692 }
693
694 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
695 if (ret < 0)
696 return ret;
697
698 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
699 if (ret < 0)
700 return ret;
701
702 if (enable)
703 ret |= DW_VR_MII_EEE_TRN_LPI;
704 else
705 ret &= ~DW_VR_MII_EEE_TRN_LPI;
706
707 return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
708}
709EXPORT_SYMBOL_GPL(xpcs_config_eee);
710
711static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
712{
713 int ret, mdio_ctrl;
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731 mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
732 if (mdio_ctrl < 0)
733 return mdio_ctrl;
734
735 if (mdio_ctrl & AN_CL37_EN) {
736 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
737 mdio_ctrl & ~AN_CL37_EN);
738 if (ret < 0)
739 return ret;
740 }
741
742 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
743 if (ret < 0)
744 return ret;
745
746 ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
747 ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
748 DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
749 DW_VR_MII_PCS_MODE_MASK);
750 ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
751 DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
752 DW_VR_MII_TX_CONFIG_MASK);
753 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
754 if (ret < 0)
755 return ret;
756
757 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
758 if (ret < 0)
759 return ret;
760
761 if (phylink_autoneg_inband(mode))
762 ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
763 else
764 ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
765
766 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
767 if (ret < 0)
768 return ret;
769
770 if (phylink_autoneg_inband(mode))
771 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
772 mdio_ctrl | AN_CL37_EN);
773
774 return ret;
775}
776
777static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
778{
779 int ret;
780
781 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
782 if (ret < 0)
783 return ret;
784 ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
785 ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
786 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
787 if (ret < 0)
788 return ret;
789
790 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
791 if (ret < 0)
792 return ret;
793 ret &= ~AN_CL37_EN;
794 ret |= SGMII_SPEED_SS6;
795 ret &= ~SGMII_SPEED_SS13;
796 return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
797}
798
799int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
800 unsigned int mode)
801{
802 const struct xpcs_compat *compat;
803 int ret;
804
805 compat = xpcs_find_compat(xpcs->id, interface);
806 if (!compat)
807 return -ENODEV;
808
809 switch (compat->an_mode) {
810 case DW_AN_C73:
811 if (phylink_autoneg_inband(mode)) {
812 ret = xpcs_config_aneg_c73(xpcs, compat);
813 if (ret)
814 return ret;
815 }
816 break;
817 case DW_AN_C37_SGMII:
818 ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
819 if (ret)
820 return ret;
821 break;
822 case DW_2500BASEX:
823 ret = xpcs_config_2500basex(xpcs);
824 if (ret)
825 return ret;
826 break;
827 default:
828 return -1;
829 }
830
831 if (compat->pma_config) {
832 ret = compat->pma_config(xpcs);
833 if (ret)
834 return ret;
835 }
836
837 return 0;
838}
839EXPORT_SYMBOL_GPL(xpcs_do_config);
840
841static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
842 phy_interface_t interface,
843 const unsigned long *advertising,
844 bool permit_pause_to_mac)
845{
846 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
847
848 return xpcs_do_config(xpcs, interface, mode);
849}
850
851static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
852 struct phylink_link_state *state,
853 const struct xpcs_compat *compat)
854{
855 int ret;
856
857
858 state->link = xpcs_read_link_c73(xpcs, state->an_enabled) > 0 ? 1 : 0;
859
860
861 ret = xpcs_read_fault_c73(xpcs, state);
862 if (ret) {
863 ret = xpcs_soft_reset(xpcs, compat);
864 if (ret)
865 return ret;
866
867 state->link = 0;
868
869 return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND);
870 }
871
872 if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) {
873 state->an_complete = true;
874 xpcs_read_lpa_c73(xpcs, state);
875 xpcs_resolve_lpa_c73(xpcs, state);
876 } else if (state->an_enabled) {
877 state->link = 0;
878 } else if (state->link) {
879 xpcs_resolve_pma(xpcs, state);
880 }
881
882 return 0;
883}
884
885static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
886 struct phylink_link_state *state)
887{
888 int ret;
889
890
891 state->link = false;
892 state->speed = SPEED_UNKNOWN;
893 state->duplex = DUPLEX_UNKNOWN;
894 state->pause = 0;
895
896
897
898
899 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
900 if (ret < 0)
901 return false;
902
903 if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
904 int speed_value;
905
906 state->link = true;
907
908 speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >>
909 DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT;
910 if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
911 state->speed = SPEED_1000;
912 else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
913 state->speed = SPEED_100;
914 else
915 state->speed = SPEED_10;
916
917 if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
918 state->duplex = DUPLEX_FULL;
919 else
920 state->duplex = DUPLEX_HALF;
921 }
922
923 return 0;
924}
925
926static void xpcs_get_state(struct phylink_pcs *pcs,
927 struct phylink_link_state *state)
928{
929 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
930 const struct xpcs_compat *compat;
931 int ret;
932
933 compat = xpcs_find_compat(xpcs->id, state->interface);
934 if (!compat)
935 return;
936
937 switch (compat->an_mode) {
938 case DW_AN_C73:
939 ret = xpcs_get_state_c73(xpcs, state, compat);
940 if (ret) {
941 pr_err("xpcs_get_state_c73 returned %pe\n",
942 ERR_PTR(ret));
943 return;
944 }
945 break;
946 case DW_AN_C37_SGMII:
947 ret = xpcs_get_state_c37_sgmii(xpcs, state);
948 if (ret) {
949 pr_err("xpcs_get_state_c37_sgmii returned %pe\n",
950 ERR_PTR(ret));
951 }
952 break;
953 default:
954 return;
955 }
956}
957
958static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
959 int speed, int duplex)
960{
961 int val, ret;
962
963 if (phylink_autoneg_inband(mode))
964 return;
965
966 switch (speed) {
967 case SPEED_1000:
968 val = BMCR_SPEED1000;
969 break;
970 case SPEED_100:
971 val = BMCR_SPEED100;
972 break;
973 case SPEED_10:
974 val = BMCR_SPEED10;
975 break;
976 default:
977 return;
978 }
979
980 if (duplex == DUPLEX_FULL)
981 val |= BMCR_FULLDPLX;
982
983 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
984 if (ret)
985 pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
986}
987
988void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
989 phy_interface_t interface, int speed, int duplex)
990{
991 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
992
993 if (interface == PHY_INTERFACE_MODE_USXGMII)
994 return xpcs_config_usxgmii(xpcs, speed);
995 if (interface == PHY_INTERFACE_MODE_SGMII)
996 return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
997}
998EXPORT_SYMBOL_GPL(xpcs_link_up);
999
1000static u32 xpcs_get_id(struct dw_xpcs *xpcs)
1001{
1002 int ret;
1003 u32 id;
1004
1005
1006 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
1007 if (ret < 0)
1008 return 0xffffffff;
1009
1010 id = ret << 16;
1011
1012 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
1013 if (ret < 0)
1014 return 0xffffffff;
1015
1016
1017
1018
1019 if ((id | ret) && (id | ret) != 0xffffffff)
1020 return id | ret;
1021
1022
1023 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
1024 if (ret < 0)
1025 return 0xffffffff;
1026
1027 id = ret << 16;
1028
1029 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
1030 if (ret < 0)
1031 return 0xffffffff;
1032
1033
1034 if (id | ret)
1035 return id | ret;
1036
1037 return 0xffffffff;
1038}
1039
1040static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1041 [DW_XPCS_USXGMII] = {
1042 .supported = xpcs_usxgmii_features,
1043 .interface = xpcs_usxgmii_interfaces,
1044 .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces),
1045 .an_mode = DW_AN_C73,
1046 },
1047 [DW_XPCS_10GKR] = {
1048 .supported = xpcs_10gkr_features,
1049 .interface = xpcs_10gkr_interfaces,
1050 .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces),
1051 .an_mode = DW_AN_C73,
1052 },
1053 [DW_XPCS_XLGMII] = {
1054 .supported = xpcs_xlgmii_features,
1055 .interface = xpcs_xlgmii_interfaces,
1056 .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces),
1057 .an_mode = DW_AN_C73,
1058 },
1059 [DW_XPCS_SGMII] = {
1060 .supported = xpcs_sgmii_features,
1061 .interface = xpcs_sgmii_interfaces,
1062 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1063 .an_mode = DW_AN_C37_SGMII,
1064 },
1065 [DW_XPCS_2500BASEX] = {
1066 .supported = xpcs_2500basex_features,
1067 .interface = xpcs_2500basex_interfaces,
1068 .num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
1069 .an_mode = DW_2500BASEX,
1070 },
1071};
1072
1073static const struct xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1074 [DW_XPCS_SGMII] = {
1075 .supported = xpcs_sgmii_features,
1076 .interface = xpcs_sgmii_interfaces,
1077 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1078 .an_mode = DW_AN_C37_SGMII,
1079 .pma_config = nxp_sja1105_sgmii_pma_config,
1080 },
1081};
1082
1083static const struct xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1084 [DW_XPCS_SGMII] = {
1085 .supported = xpcs_sgmii_features,
1086 .interface = xpcs_sgmii_interfaces,
1087 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1088 .an_mode = DW_AN_C37_SGMII,
1089 .pma_config = nxp_sja1110_sgmii_pma_config,
1090 },
1091 [DW_XPCS_2500BASEX] = {
1092 .supported = xpcs_2500basex_features,
1093 .interface = xpcs_2500basex_interfaces,
1094 .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces),
1095 .an_mode = DW_2500BASEX,
1096 .pma_config = nxp_sja1110_2500basex_pma_config,
1097 },
1098};
1099
1100static const struct xpcs_id xpcs_id_list[] = {
1101 {
1102 .id = SYNOPSYS_XPCS_ID,
1103 .mask = SYNOPSYS_XPCS_MASK,
1104 .compat = synopsys_xpcs_compat,
1105 }, {
1106 .id = NXP_SJA1105_XPCS_ID,
1107 .mask = SYNOPSYS_XPCS_MASK,
1108 .compat = nxp_sja1105_xpcs_compat,
1109 }, {
1110 .id = NXP_SJA1110_XPCS_ID,
1111 .mask = SYNOPSYS_XPCS_MASK,
1112 .compat = nxp_sja1110_xpcs_compat,
1113 },
1114};
1115
1116static const struct phylink_pcs_ops xpcs_phylink_ops = {
1117 .pcs_validate = xpcs_validate,
1118 .pcs_config = xpcs_config,
1119 .pcs_get_state = xpcs_get_state,
1120 .pcs_link_up = xpcs_link_up,
1121};
1122
1123struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
1124 phy_interface_t interface)
1125{
1126 struct dw_xpcs *xpcs;
1127 u32 xpcs_id;
1128 int i, ret;
1129
1130 xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
1131 if (!xpcs)
1132 return ERR_PTR(-ENOMEM);
1133
1134 xpcs->mdiodev = mdiodev;
1135
1136 xpcs_id = xpcs_get_id(xpcs);
1137
1138 for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
1139 const struct xpcs_id *entry = &xpcs_id_list[i];
1140 const struct xpcs_compat *compat;
1141
1142 if ((xpcs_id & entry->mask) != entry->id)
1143 continue;
1144
1145 xpcs->id = entry;
1146
1147 compat = xpcs_find_compat(entry, interface);
1148 if (!compat) {
1149 ret = -ENODEV;
1150 goto out;
1151 }
1152
1153 xpcs->pcs.ops = &xpcs_phylink_ops;
1154 xpcs->pcs.poll = true;
1155
1156 ret = xpcs_soft_reset(xpcs, compat);
1157 if (ret)
1158 goto out;
1159
1160 return xpcs;
1161 }
1162
1163 ret = -ENODEV;
1164
1165out:
1166 kfree(xpcs);
1167
1168 return ERR_PTR(ret);
1169}
1170EXPORT_SYMBOL_GPL(xpcs_create);
1171
1172void xpcs_destroy(struct dw_xpcs *xpcs)
1173{
1174 kfree(xpcs);
1175}
1176EXPORT_SYMBOL_GPL(xpcs_destroy);
1177
1178MODULE_LICENSE("GPL v2");
1179