0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/delay.h>
0010 #include <linux/pcs/pcs-xpcs.h>
0011 #include <linux/mdio.h>
0012 #include <linux/phylink.h>
0013 #include <linux/workqueue.h>
0014 #include "pcs-xpcs.h"
0015
0016 #define phylink_pcs_to_xpcs(pl_pcs) \
0017 container_of((pl_pcs), struct dw_xpcs, pcs)
0018
0019 static const int xpcs_usxgmii_features[] = {
0020 ETHTOOL_LINK_MODE_Pause_BIT,
0021 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0022 ETHTOOL_LINK_MODE_Autoneg_BIT,
0023 ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
0024 ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
0025 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
0026 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
0027 __ETHTOOL_LINK_MODE_MASK_NBITS,
0028 };
0029
0030 static const int xpcs_10gkr_features[] = {
0031 ETHTOOL_LINK_MODE_Pause_BIT,
0032 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0033 ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
0034 __ETHTOOL_LINK_MODE_MASK_NBITS,
0035 };
0036
0037 static const int xpcs_xlgmii_features[] = {
0038 ETHTOOL_LINK_MODE_Pause_BIT,
0039 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0040 ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
0041 ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
0042 ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
0043 ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
0044 ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
0045 ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
0046 ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
0047 ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
0048 ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
0049 ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
0050 ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
0051 ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
0052 ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
0053 ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
0054 ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
0055 ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
0056 ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
0057 ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
0058 ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
0059 ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
0060 ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
0061 ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
0062 ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
0063 ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
0064 __ETHTOOL_LINK_MODE_MASK_NBITS,
0065 };
0066
0067 static const int xpcs_sgmii_features[] = {
0068 ETHTOOL_LINK_MODE_Pause_BIT,
0069 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0070 ETHTOOL_LINK_MODE_Autoneg_BIT,
0071 ETHTOOL_LINK_MODE_10baseT_Half_BIT,
0072 ETHTOOL_LINK_MODE_10baseT_Full_BIT,
0073 ETHTOOL_LINK_MODE_100baseT_Half_BIT,
0074 ETHTOOL_LINK_MODE_100baseT_Full_BIT,
0075 ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
0076 ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
0077 __ETHTOOL_LINK_MODE_MASK_NBITS,
0078 };
0079
0080 static const int xpcs_1000basex_features[] = {
0081 ETHTOOL_LINK_MODE_Pause_BIT,
0082 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0083 ETHTOOL_LINK_MODE_Autoneg_BIT,
0084 ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
0085 __ETHTOOL_LINK_MODE_MASK_NBITS,
0086 };
0087
0088 static const int xpcs_2500basex_features[] = {
0089 ETHTOOL_LINK_MODE_Pause_BIT,
0090 ETHTOOL_LINK_MODE_Asym_Pause_BIT,
0091 ETHTOOL_LINK_MODE_Autoneg_BIT,
0092 ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
0093 ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
0094 __ETHTOOL_LINK_MODE_MASK_NBITS,
0095 };
0096
0097 static const phy_interface_t xpcs_usxgmii_interfaces[] = {
0098 PHY_INTERFACE_MODE_USXGMII,
0099 };
0100
0101 static const phy_interface_t xpcs_10gkr_interfaces[] = {
0102 PHY_INTERFACE_MODE_10GKR,
0103 };
0104
0105 static const phy_interface_t xpcs_xlgmii_interfaces[] = {
0106 PHY_INTERFACE_MODE_XLGMII,
0107 };
0108
0109 static const phy_interface_t xpcs_sgmii_interfaces[] = {
0110 PHY_INTERFACE_MODE_SGMII,
0111 };
0112
0113 static const phy_interface_t xpcs_1000basex_interfaces[] = {
0114 PHY_INTERFACE_MODE_1000BASEX,
0115 };
0116
0117 static const phy_interface_t xpcs_2500basex_interfaces[] = {
0118 PHY_INTERFACE_MODE_2500BASEX,
0119 PHY_INTERFACE_MODE_MAX,
0120 };
0121
0122 enum {
0123 DW_XPCS_USXGMII,
0124 DW_XPCS_10GKR,
0125 DW_XPCS_XLGMII,
0126 DW_XPCS_SGMII,
0127 DW_XPCS_1000BASEX,
0128 DW_XPCS_2500BASEX,
0129 DW_XPCS_INTERFACE_MAX,
0130 };
0131
0132 struct xpcs_compat {
0133 const int *supported;
0134 const phy_interface_t *interface;
0135 int num_interfaces;
0136 int an_mode;
0137 int (*pma_config)(struct dw_xpcs *xpcs);
0138 };
0139
0140 struct xpcs_id {
0141 u32 id;
0142 u32 mask;
0143 const struct xpcs_compat *compat;
0144 };
0145
0146 static const struct xpcs_compat *xpcs_find_compat(const struct xpcs_id *id,
0147 phy_interface_t interface)
0148 {
0149 int i, j;
0150
0151 for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
0152 const struct xpcs_compat *compat = &id->compat[i];
0153
0154 for (j = 0; j < compat->num_interfaces; j++)
0155 if (compat->interface[j] == interface)
0156 return compat;
0157 }
0158
0159 return NULL;
0160 }
0161
0162 int xpcs_get_an_mode(struct dw_xpcs *xpcs, phy_interface_t interface)
0163 {
0164 const struct xpcs_compat *compat;
0165
0166 compat = xpcs_find_compat(xpcs->id, interface);
0167 if (!compat)
0168 return -ENODEV;
0169
0170 return compat->an_mode;
0171 }
0172 EXPORT_SYMBOL_GPL(xpcs_get_an_mode);
0173
0174 static bool __xpcs_linkmode_supported(const struct xpcs_compat *compat,
0175 enum ethtool_link_mode_bit_indices linkmode)
0176 {
0177 int i;
0178
0179 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
0180 if (compat->supported[i] == linkmode)
0181 return true;
0182
0183 return false;
0184 }
0185
0186 #define xpcs_linkmode_supported(compat, mode) \
0187 __xpcs_linkmode_supported(compat, ETHTOOL_LINK_MODE_ ## mode ## _BIT)
0188
0189 int xpcs_read(struct dw_xpcs *xpcs, int dev, u32 reg)
0190 {
0191 struct mii_bus *bus = xpcs->mdiodev->bus;
0192 int addr = xpcs->mdiodev->addr;
0193
0194 return mdiobus_c45_read(bus, addr, dev, reg);
0195 }
0196
0197 int xpcs_write(struct dw_xpcs *xpcs, int dev, u32 reg, u16 val)
0198 {
0199 struct mii_bus *bus = xpcs->mdiodev->bus;
0200 int addr = xpcs->mdiodev->addr;
0201
0202 return mdiobus_c45_write(bus, addr, dev, reg, val);
0203 }
0204
0205 static int xpcs_modify_changed(struct dw_xpcs *xpcs, int dev, u32 reg,
0206 u16 mask, u16 set)
0207 {
0208 u32 reg_addr = mdiobus_c45_addr(dev, reg);
0209
0210 return mdiodev_modify_changed(xpcs->mdiodev, reg_addr, mask, set);
0211 }
0212
0213 static int xpcs_read_vendor(struct dw_xpcs *xpcs, int dev, u32 reg)
0214 {
0215 return xpcs_read(xpcs, dev, DW_VENDOR | reg);
0216 }
0217
0218 static int xpcs_write_vendor(struct dw_xpcs *xpcs, int dev, int reg,
0219 u16 val)
0220 {
0221 return xpcs_write(xpcs, dev, DW_VENDOR | reg, val);
0222 }
0223
0224 static int xpcs_read_vpcs(struct dw_xpcs *xpcs, int reg)
0225 {
0226 return xpcs_read_vendor(xpcs, MDIO_MMD_PCS, reg);
0227 }
0228
0229 static int xpcs_write_vpcs(struct dw_xpcs *xpcs, int reg, u16 val)
0230 {
0231 return xpcs_write_vendor(xpcs, MDIO_MMD_PCS, reg, val);
0232 }
0233
0234 static int xpcs_poll_reset(struct dw_xpcs *xpcs, int dev)
0235 {
0236
0237 unsigned int retries = 12;
0238 int ret;
0239
0240 do {
0241 msleep(50);
0242 ret = xpcs_read(xpcs, dev, MDIO_CTRL1);
0243 if (ret < 0)
0244 return ret;
0245 } while (ret & MDIO_CTRL1_RESET && --retries);
0246
0247 return (ret & MDIO_CTRL1_RESET) ? -ETIMEDOUT : 0;
0248 }
0249
0250 static int xpcs_soft_reset(struct dw_xpcs *xpcs,
0251 const struct xpcs_compat *compat)
0252 {
0253 int ret, dev;
0254
0255 switch (compat->an_mode) {
0256 case DW_AN_C73:
0257 dev = MDIO_MMD_PCS;
0258 break;
0259 case DW_AN_C37_SGMII:
0260 case DW_2500BASEX:
0261 case DW_AN_C37_1000BASEX:
0262 dev = MDIO_MMD_VEND2;
0263 break;
0264 default:
0265 return -1;
0266 }
0267
0268 ret = xpcs_write(xpcs, dev, MDIO_CTRL1, MDIO_CTRL1_RESET);
0269 if (ret < 0)
0270 return ret;
0271
0272 return xpcs_poll_reset(xpcs, dev);
0273 }
0274
0275 #define xpcs_warn(__xpcs, __state, __args...) \
0276 ({ \
0277 if ((__state)->link) \
0278 dev_warn(&(__xpcs)->mdiodev->dev, ##__args); \
0279 })
0280
0281 static int xpcs_read_fault_c73(struct dw_xpcs *xpcs,
0282 struct phylink_link_state *state)
0283 {
0284 int ret;
0285
0286 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
0287 if (ret < 0)
0288 return ret;
0289
0290 if (ret & MDIO_STAT1_FAULT) {
0291 xpcs_warn(xpcs, state, "Link fault condition detected!\n");
0292 return -EFAULT;
0293 }
0294
0295 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT2);
0296 if (ret < 0)
0297 return ret;
0298
0299 if (ret & MDIO_STAT2_RXFAULT)
0300 xpcs_warn(xpcs, state, "Receiver fault detected!\n");
0301 if (ret & MDIO_STAT2_TXFAULT)
0302 xpcs_warn(xpcs, state, "Transmitter fault detected!\n");
0303
0304 ret = xpcs_read_vendor(xpcs, MDIO_MMD_PCS, DW_VR_XS_PCS_DIG_STS);
0305 if (ret < 0)
0306 return ret;
0307
0308 if (ret & DW_RXFIFO_ERR) {
0309 xpcs_warn(xpcs, state, "FIFO fault condition detected!\n");
0310 return -EFAULT;
0311 }
0312
0313 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT1);
0314 if (ret < 0)
0315 return ret;
0316
0317 if (!(ret & MDIO_PCS_10GBRT_STAT1_BLKLK))
0318 xpcs_warn(xpcs, state, "Link is not locked!\n");
0319
0320 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_PCS_10GBRT_STAT2);
0321 if (ret < 0)
0322 return ret;
0323
0324 if (ret & MDIO_PCS_10GBRT_STAT2_ERR) {
0325 xpcs_warn(xpcs, state, "Link has errors!\n");
0326 return -EFAULT;
0327 }
0328
0329 return 0;
0330 }
0331
0332 static int xpcs_read_link_c73(struct dw_xpcs *xpcs, bool an)
0333 {
0334 bool link = true;
0335 int ret;
0336
0337 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MDIO_STAT1);
0338 if (ret < 0)
0339 return ret;
0340
0341 if (!(ret & MDIO_STAT1_LSTATUS))
0342 link = false;
0343
0344 if (an) {
0345 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
0346 if (ret < 0)
0347 return ret;
0348
0349 if (!(ret & MDIO_STAT1_LSTATUS))
0350 link = false;
0351 }
0352
0353 return link;
0354 }
0355
0356 static int xpcs_get_max_usxgmii_speed(const unsigned long *supported)
0357 {
0358 int max = SPEED_UNKNOWN;
0359
0360 if (phylink_test(supported, 1000baseKX_Full))
0361 max = SPEED_1000;
0362 if (phylink_test(supported, 2500baseX_Full))
0363 max = SPEED_2500;
0364 if (phylink_test(supported, 10000baseKX4_Full))
0365 max = SPEED_10000;
0366 if (phylink_test(supported, 10000baseKR_Full))
0367 max = SPEED_10000;
0368
0369 return max;
0370 }
0371
0372 static void xpcs_config_usxgmii(struct dw_xpcs *xpcs, int speed)
0373 {
0374 int ret, speed_sel;
0375
0376 switch (speed) {
0377 case SPEED_10:
0378 speed_sel = DW_USXGMII_10;
0379 break;
0380 case SPEED_100:
0381 speed_sel = DW_USXGMII_100;
0382 break;
0383 case SPEED_1000:
0384 speed_sel = DW_USXGMII_1000;
0385 break;
0386 case SPEED_2500:
0387 speed_sel = DW_USXGMII_2500;
0388 break;
0389 case SPEED_5000:
0390 speed_sel = DW_USXGMII_5000;
0391 break;
0392 case SPEED_10000:
0393 speed_sel = DW_USXGMII_10000;
0394 break;
0395 default:
0396
0397 return;
0398 }
0399
0400 ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
0401 if (ret < 0)
0402 goto out;
0403
0404 ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_EN);
0405 if (ret < 0)
0406 goto out;
0407
0408 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
0409 if (ret < 0)
0410 goto out;
0411
0412 ret &= ~DW_USXGMII_SS_MASK;
0413 ret |= speed_sel | DW_USXGMII_FULL;
0414
0415 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
0416 if (ret < 0)
0417 goto out;
0418
0419 ret = xpcs_read_vpcs(xpcs, MDIO_CTRL1);
0420 if (ret < 0)
0421 goto out;
0422
0423 ret = xpcs_write_vpcs(xpcs, MDIO_CTRL1, ret | DW_USXGMII_RST);
0424 if (ret < 0)
0425 goto out;
0426
0427 return;
0428
0429 out:
0430 pr_err("%s: XPCS access returned %pe\n", __func__, ERR_PTR(ret));
0431 }
0432
0433 static int _xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
0434 const struct xpcs_compat *compat)
0435 {
0436 int ret, adv;
0437
0438
0439
0440
0441
0442
0443
0444
0445 adv = 0;
0446 if (xpcs_linkmode_supported(compat, 2500baseX_Full))
0447 adv |= DW_C73_2500KX;
0448
0449
0450
0451 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
0452 if (ret < 0)
0453 return ret;
0454
0455
0456 adv = 0;
0457 if (xpcs_linkmode_supported(compat, 1000baseKX_Full))
0458 adv |= DW_C73_1000KX;
0459 if (xpcs_linkmode_supported(compat, 10000baseKX4_Full))
0460 adv |= DW_C73_10000KX4;
0461 if (xpcs_linkmode_supported(compat, 10000baseKR_Full))
0462 adv |= DW_C73_10000KR;
0463
0464 ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV2, adv);
0465 if (ret < 0)
0466 return ret;
0467
0468
0469 adv = DW_C73_AN_ADV_SF;
0470 if (xpcs_linkmode_supported(compat, Pause))
0471 adv |= DW_C73_PAUSE;
0472 if (xpcs_linkmode_supported(compat, Asym_Pause))
0473 adv |= DW_C73_ASYM_PAUSE;
0474
0475 return xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV1, adv);
0476 }
0477
0478 static int xpcs_config_aneg_c73(struct dw_xpcs *xpcs,
0479 const struct xpcs_compat *compat)
0480 {
0481 int ret;
0482
0483 ret = _xpcs_config_aneg_c73(xpcs, compat);
0484 if (ret < 0)
0485 return ret;
0486
0487 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_CTRL1);
0488 if (ret < 0)
0489 return ret;
0490
0491 ret |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
0492
0493 return xpcs_write(xpcs, MDIO_MMD_AN, MDIO_CTRL1, ret);
0494 }
0495
0496 static int xpcs_aneg_done_c73(struct dw_xpcs *xpcs,
0497 struct phylink_link_state *state,
0498 const struct xpcs_compat *compat)
0499 {
0500 int ret;
0501
0502 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
0503 if (ret < 0)
0504 return ret;
0505
0506 if (ret & MDIO_AN_STAT1_COMPLETE) {
0507 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
0508 if (ret < 0)
0509 return ret;
0510
0511
0512 if (!(ret & DW_C73_AN_ADV_SF)) {
0513 xpcs_config_aneg_c73(xpcs, compat);
0514 return 0;
0515 }
0516
0517 return 1;
0518 }
0519
0520 return 0;
0521 }
0522
0523 static int xpcs_read_lpa_c73(struct dw_xpcs *xpcs,
0524 struct phylink_link_state *state)
0525 {
0526 int ret;
0527
0528 ret = xpcs_read(xpcs, MDIO_MMD_AN, MDIO_STAT1);
0529 if (ret < 0)
0530 return ret;
0531
0532 if (!(ret & MDIO_AN_STAT1_LPABLE)) {
0533 phylink_clear(state->lp_advertising, Autoneg);
0534 return 0;
0535 }
0536
0537 phylink_set(state->lp_advertising, Autoneg);
0538
0539
0540 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL3);
0541 if (ret < 0)
0542 return ret;
0543
0544 if (ret & DW_C73_2500KX)
0545 phylink_set(state->lp_advertising, 2500baseX_Full);
0546
0547 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL2);
0548 if (ret < 0)
0549 return ret;
0550
0551 if (ret & DW_C73_1000KX)
0552 phylink_set(state->lp_advertising, 1000baseKX_Full);
0553 if (ret & DW_C73_10000KX4)
0554 phylink_set(state->lp_advertising, 10000baseKX4_Full);
0555 if (ret & DW_C73_10000KR)
0556 phylink_set(state->lp_advertising, 10000baseKR_Full);
0557
0558 ret = xpcs_read(xpcs, MDIO_MMD_AN, DW_SR_AN_LP_ABL1);
0559 if (ret < 0)
0560 return ret;
0561
0562 if (ret & DW_C73_PAUSE)
0563 phylink_set(state->lp_advertising, Pause);
0564 if (ret & DW_C73_ASYM_PAUSE)
0565 phylink_set(state->lp_advertising, Asym_Pause);
0566
0567 linkmode_and(state->lp_advertising, state->lp_advertising,
0568 state->advertising);
0569 return 0;
0570 }
0571
0572 static void xpcs_resolve_lpa_c73(struct dw_xpcs *xpcs,
0573 struct phylink_link_state *state)
0574 {
0575 int max_speed = xpcs_get_max_usxgmii_speed(state->lp_advertising);
0576
0577 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
0578 state->speed = max_speed;
0579 state->duplex = DUPLEX_FULL;
0580 }
0581
0582 static int xpcs_get_max_xlgmii_speed(struct dw_xpcs *xpcs,
0583 struct phylink_link_state *state)
0584 {
0585 unsigned long *adv = state->advertising;
0586 int speed = SPEED_UNKNOWN;
0587 int bit;
0588
0589 for_each_set_bit(bit, adv, __ETHTOOL_LINK_MODE_MASK_NBITS) {
0590 int new_speed = SPEED_UNKNOWN;
0591
0592 switch (bit) {
0593 case ETHTOOL_LINK_MODE_25000baseCR_Full_BIT:
0594 case ETHTOOL_LINK_MODE_25000baseKR_Full_BIT:
0595 case ETHTOOL_LINK_MODE_25000baseSR_Full_BIT:
0596 new_speed = SPEED_25000;
0597 break;
0598 case ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT:
0599 case ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT:
0600 case ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT:
0601 case ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT:
0602 new_speed = SPEED_40000;
0603 break;
0604 case ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT:
0605 case ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT:
0606 case ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT:
0607 case ETHTOOL_LINK_MODE_50000baseKR_Full_BIT:
0608 case ETHTOOL_LINK_MODE_50000baseSR_Full_BIT:
0609 case ETHTOOL_LINK_MODE_50000baseCR_Full_BIT:
0610 case ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT:
0611 case ETHTOOL_LINK_MODE_50000baseDR_Full_BIT:
0612 new_speed = SPEED_50000;
0613 break;
0614 case ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT:
0615 case ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT:
0616 case ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT:
0617 case ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT:
0618 case ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT:
0619 case ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT:
0620 case ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT:
0621 case ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT:
0622 case ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT:
0623 new_speed = SPEED_100000;
0624 break;
0625 default:
0626 continue;
0627 }
0628
0629 if (new_speed > speed)
0630 speed = new_speed;
0631 }
0632
0633 return speed;
0634 }
0635
0636 static void xpcs_resolve_pma(struct dw_xpcs *xpcs,
0637 struct phylink_link_state *state)
0638 {
0639 state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
0640 state->duplex = DUPLEX_FULL;
0641
0642 switch (state->interface) {
0643 case PHY_INTERFACE_MODE_10GKR:
0644 state->speed = SPEED_10000;
0645 break;
0646 case PHY_INTERFACE_MODE_XLGMII:
0647 state->speed = xpcs_get_max_xlgmii_speed(xpcs, state);
0648 break;
0649 default:
0650 state->speed = SPEED_UNKNOWN;
0651 break;
0652 }
0653 }
0654
0655 static int xpcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
0656 const struct phylink_link_state *state)
0657 {
0658 __ETHTOOL_DECLARE_LINK_MODE_MASK(xpcs_supported) = { 0, };
0659 const struct xpcs_compat *compat;
0660 struct dw_xpcs *xpcs;
0661 int i;
0662
0663 xpcs = phylink_pcs_to_xpcs(pcs);
0664 compat = xpcs_find_compat(xpcs->id, state->interface);
0665
0666
0667
0668
0669
0670 if (compat)
0671 for (i = 0; compat->supported[i] != __ETHTOOL_LINK_MODE_MASK_NBITS; i++)
0672 set_bit(compat->supported[i], xpcs_supported);
0673
0674 linkmode_and(supported, supported, xpcs_supported);
0675
0676 return 0;
0677 }
0678
0679 void xpcs_get_interfaces(struct dw_xpcs *xpcs, unsigned long *interfaces)
0680 {
0681 int i, j;
0682
0683 for (i = 0; i < DW_XPCS_INTERFACE_MAX; i++) {
0684 const struct xpcs_compat *compat = &xpcs->id->compat[i];
0685
0686 for (j = 0; j < compat->num_interfaces; j++)
0687 if (compat->interface[j] < PHY_INTERFACE_MODE_MAX)
0688 __set_bit(compat->interface[j], interfaces);
0689 }
0690 }
0691 EXPORT_SYMBOL_GPL(xpcs_get_interfaces);
0692
0693 int xpcs_config_eee(struct dw_xpcs *xpcs, int mult_fact_100ns, int enable)
0694 {
0695 int ret;
0696
0697 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0);
0698 if (ret < 0)
0699 return ret;
0700
0701 if (enable) {
0702
0703 ret = DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
0704 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
0705 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
0706 mult_fact_100ns << DW_VR_MII_EEE_MULT_FACT_100NS_SHIFT;
0707 } else {
0708 ret &= ~(DW_VR_MII_EEE_LTX_EN | DW_VR_MII_EEE_LRX_EN |
0709 DW_VR_MII_EEE_TX_QUIET_EN | DW_VR_MII_EEE_RX_QUIET_EN |
0710 DW_VR_MII_EEE_TX_EN_CTRL | DW_VR_MII_EEE_RX_EN_CTRL |
0711 DW_VR_MII_EEE_MULT_FACT_100NS);
0712 }
0713
0714 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL0, ret);
0715 if (ret < 0)
0716 return ret;
0717
0718 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1);
0719 if (ret < 0)
0720 return ret;
0721
0722 if (enable)
0723 ret |= DW_VR_MII_EEE_TRN_LPI;
0724 else
0725 ret &= ~DW_VR_MII_EEE_TRN_LPI;
0726
0727 return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_EEE_MCTRL1, ret);
0728 }
0729 EXPORT_SYMBOL_GPL(xpcs_config_eee);
0730
0731 static int xpcs_config_aneg_c37_sgmii(struct dw_xpcs *xpcs, unsigned int mode)
0732 {
0733 int ret, mdio_ctrl;
0734
0735
0736
0737
0738
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751 mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
0752 if (mdio_ctrl < 0)
0753 return mdio_ctrl;
0754
0755 if (mdio_ctrl & AN_CL37_EN) {
0756 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
0757 mdio_ctrl & ~AN_CL37_EN);
0758 if (ret < 0)
0759 return ret;
0760 }
0761
0762 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
0763 if (ret < 0)
0764 return ret;
0765
0766 ret &= ~(DW_VR_MII_PCS_MODE_MASK | DW_VR_MII_TX_CONFIG_MASK);
0767 ret |= (DW_VR_MII_PCS_MODE_C37_SGMII <<
0768 DW_VR_MII_AN_CTRL_PCS_MODE_SHIFT &
0769 DW_VR_MII_PCS_MODE_MASK);
0770 ret |= (DW_VR_MII_TX_CONFIG_MAC_SIDE_SGMII <<
0771 DW_VR_MII_AN_CTRL_TX_CONFIG_SHIFT &
0772 DW_VR_MII_TX_CONFIG_MASK);
0773 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
0774 if (ret < 0)
0775 return ret;
0776
0777 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
0778 if (ret < 0)
0779 return ret;
0780
0781 if (phylink_autoneg_inband(mode))
0782 ret |= DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
0783 else
0784 ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
0785
0786 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
0787 if (ret < 0)
0788 return ret;
0789
0790 if (phylink_autoneg_inband(mode))
0791 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
0792 mdio_ctrl | AN_CL37_EN);
0793
0794 return ret;
0795 }
0796
0797 static int xpcs_config_aneg_c37_1000basex(struct dw_xpcs *xpcs, unsigned int mode,
0798 const unsigned long *advertising)
0799 {
0800 phy_interface_t interface = PHY_INTERFACE_MODE_1000BASEX;
0801 int ret, mdio_ctrl, adv;
0802 bool changed = 0;
0803
0804
0805
0806
0807
0808
0809 mdio_ctrl = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
0810 if (mdio_ctrl < 0)
0811 return mdio_ctrl;
0812
0813 if (mdio_ctrl & AN_CL37_EN) {
0814 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
0815 mdio_ctrl & ~AN_CL37_EN);
0816 if (ret < 0)
0817 return ret;
0818 }
0819
0820 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL);
0821 if (ret < 0)
0822 return ret;
0823
0824 ret &= ~DW_VR_MII_PCS_MODE_MASK;
0825 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_CTRL, ret);
0826 if (ret < 0)
0827 return ret;
0828
0829
0830
0831
0832 adv = phylink_mii_c22_pcs_encode_advertisement(interface,
0833 advertising);
0834 if (adv >= 0) {
0835 ret = xpcs_modify_changed(xpcs, MDIO_MMD_VEND2,
0836 MII_ADVERTISE, 0xffff, adv);
0837 if (ret < 0)
0838 return ret;
0839
0840 changed = ret;
0841 }
0842
0843
0844 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS, 0);
0845 if (ret < 0)
0846 return ret;
0847
0848 if (phylink_autoneg_inband(mode) &&
0849 linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, advertising)) {
0850 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL,
0851 mdio_ctrl | AN_CL37_EN);
0852 if (ret < 0)
0853 return ret;
0854 }
0855
0856 return changed;
0857 }
0858
0859 static int xpcs_config_2500basex(struct dw_xpcs *xpcs)
0860 {
0861 int ret;
0862
0863 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1);
0864 if (ret < 0)
0865 return ret;
0866 ret |= DW_VR_MII_DIG_CTRL1_2G5_EN;
0867 ret &= ~DW_VR_MII_DIG_CTRL1_MAC_AUTO_SW;
0868 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_DIG_CTRL1, ret);
0869 if (ret < 0)
0870 return ret;
0871
0872 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL);
0873 if (ret < 0)
0874 return ret;
0875 ret &= ~AN_CL37_EN;
0876 ret |= SGMII_SPEED_SS6;
0877 ret &= ~SGMII_SPEED_SS13;
0878 return xpcs_write(xpcs, MDIO_MMD_VEND2, DW_VR_MII_MMD_CTRL, ret);
0879 }
0880
0881 int xpcs_do_config(struct dw_xpcs *xpcs, phy_interface_t interface,
0882 unsigned int mode, const unsigned long *advertising)
0883 {
0884 const struct xpcs_compat *compat;
0885 int ret;
0886
0887 compat = xpcs_find_compat(xpcs->id, interface);
0888 if (!compat)
0889 return -ENODEV;
0890
0891 switch (compat->an_mode) {
0892 case DW_AN_C73:
0893 if (phylink_autoneg_inband(mode)) {
0894 ret = xpcs_config_aneg_c73(xpcs, compat);
0895 if (ret)
0896 return ret;
0897 }
0898 break;
0899 case DW_AN_C37_SGMII:
0900 ret = xpcs_config_aneg_c37_sgmii(xpcs, mode);
0901 if (ret)
0902 return ret;
0903 break;
0904 case DW_AN_C37_1000BASEX:
0905 ret = xpcs_config_aneg_c37_1000basex(xpcs, mode,
0906 advertising);
0907 if (ret)
0908 return ret;
0909 break;
0910 case DW_2500BASEX:
0911 ret = xpcs_config_2500basex(xpcs);
0912 if (ret)
0913 return ret;
0914 break;
0915 default:
0916 return -1;
0917 }
0918
0919 if (compat->pma_config) {
0920 ret = compat->pma_config(xpcs);
0921 if (ret)
0922 return ret;
0923 }
0924
0925 return 0;
0926 }
0927 EXPORT_SYMBOL_GPL(xpcs_do_config);
0928
0929 static int xpcs_config(struct phylink_pcs *pcs, unsigned int mode,
0930 phy_interface_t interface,
0931 const unsigned long *advertising,
0932 bool permit_pause_to_mac)
0933 {
0934 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
0935
0936 return xpcs_do_config(xpcs, interface, mode, advertising);
0937 }
0938
0939 static int xpcs_get_state_c73(struct dw_xpcs *xpcs,
0940 struct phylink_link_state *state,
0941 const struct xpcs_compat *compat)
0942 {
0943 int ret;
0944
0945
0946 state->link = xpcs_read_link_c73(xpcs, state->an_enabled) > 0 ? 1 : 0;
0947
0948
0949 ret = xpcs_read_fault_c73(xpcs, state);
0950 if (ret) {
0951 ret = xpcs_soft_reset(xpcs, compat);
0952 if (ret)
0953 return ret;
0954
0955 state->link = 0;
0956
0957 return xpcs_do_config(xpcs, state->interface, MLO_AN_INBAND, NULL);
0958 }
0959
0960 if (state->an_enabled && xpcs_aneg_done_c73(xpcs, state, compat)) {
0961 state->an_complete = true;
0962 xpcs_read_lpa_c73(xpcs, state);
0963 xpcs_resolve_lpa_c73(xpcs, state);
0964 } else if (state->an_enabled) {
0965 state->link = 0;
0966 } else if (state->link) {
0967 xpcs_resolve_pma(xpcs, state);
0968 }
0969
0970 return 0;
0971 }
0972
0973 static int xpcs_get_state_c37_sgmii(struct dw_xpcs *xpcs,
0974 struct phylink_link_state *state)
0975 {
0976 int ret;
0977
0978
0979 state->link = false;
0980 state->speed = SPEED_UNKNOWN;
0981 state->duplex = DUPLEX_UNKNOWN;
0982 state->pause = 0;
0983
0984
0985
0986
0987 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, DW_VR_MII_AN_INTR_STS);
0988 if (ret < 0)
0989 return ret;
0990
0991 if (ret & DW_VR_MII_C37_ANSGM_SP_LNKSTS) {
0992 int speed_value;
0993
0994 state->link = true;
0995
0996 speed_value = (ret & DW_VR_MII_AN_STS_C37_ANSGM_SP) >>
0997 DW_VR_MII_AN_STS_C37_ANSGM_SP_SHIFT;
0998 if (speed_value == DW_VR_MII_C37_ANSGM_SP_1000)
0999 state->speed = SPEED_1000;
1000 else if (speed_value == DW_VR_MII_C37_ANSGM_SP_100)
1001 state->speed = SPEED_100;
1002 else
1003 state->speed = SPEED_10;
1004
1005 if (ret & DW_VR_MII_AN_STS_C37_ANSGM_FD)
1006 state->duplex = DUPLEX_FULL;
1007 else
1008 state->duplex = DUPLEX_HALF;
1009 }
1010
1011 return 0;
1012 }
1013
1014 static int xpcs_get_state_c37_1000basex(struct dw_xpcs *xpcs,
1015 struct phylink_link_state *state)
1016 {
1017 int lpa, bmsr;
1018
1019 if (state->an_enabled) {
1020
1021 state->link = false;
1022
1023 lpa = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_LPA);
1024 if (lpa < 0 || lpa & LPA_RFAULT)
1025 return lpa;
1026
1027 bmsr = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_BMSR);
1028 if (bmsr < 0)
1029 return bmsr;
1030
1031 phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
1032 }
1033
1034 return 0;
1035 }
1036
1037 static void xpcs_get_state(struct phylink_pcs *pcs,
1038 struct phylink_link_state *state)
1039 {
1040 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1041 const struct xpcs_compat *compat;
1042 int ret;
1043
1044 compat = xpcs_find_compat(xpcs->id, state->interface);
1045 if (!compat)
1046 return;
1047
1048 switch (compat->an_mode) {
1049 case DW_AN_C73:
1050 ret = xpcs_get_state_c73(xpcs, state, compat);
1051 if (ret) {
1052 pr_err("xpcs_get_state_c73 returned %pe\n",
1053 ERR_PTR(ret));
1054 return;
1055 }
1056 break;
1057 case DW_AN_C37_SGMII:
1058 ret = xpcs_get_state_c37_sgmii(xpcs, state);
1059 if (ret) {
1060 pr_err("xpcs_get_state_c37_sgmii returned %pe\n",
1061 ERR_PTR(ret));
1062 }
1063 break;
1064 case DW_AN_C37_1000BASEX:
1065 ret = xpcs_get_state_c37_1000basex(xpcs, state);
1066 if (ret) {
1067 pr_err("xpcs_get_state_c37_1000basex returned %pe\n",
1068 ERR_PTR(ret));
1069 }
1070 break;
1071 default:
1072 return;
1073 }
1074 }
1075
1076 static void xpcs_link_up_sgmii(struct dw_xpcs *xpcs, unsigned int mode,
1077 int speed, int duplex)
1078 {
1079 int val, ret;
1080
1081 if (phylink_autoneg_inband(mode))
1082 return;
1083
1084 val = mii_bmcr_encode_fixed(speed, duplex);
1085 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
1086 if (ret)
1087 pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
1088 }
1089
1090 static void xpcs_link_up_1000basex(struct dw_xpcs *xpcs, unsigned int mode,
1091 int speed, int duplex)
1092 {
1093 int val, ret;
1094
1095 if (phylink_autoneg_inband(mode))
1096 return;
1097
1098 switch (speed) {
1099 case SPEED_1000:
1100 val = BMCR_SPEED1000;
1101 break;
1102 case SPEED_100:
1103 case SPEED_10:
1104 default:
1105 pr_err("%s: speed = %d\n", __func__, speed);
1106 return;
1107 }
1108
1109 if (duplex == DUPLEX_FULL)
1110 val |= BMCR_FULLDPLX;
1111 else
1112 pr_err("%s: half duplex not supported\n", __func__);
1113
1114 ret = xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, val);
1115 if (ret)
1116 pr_err("%s: xpcs_write returned %pe\n", __func__, ERR_PTR(ret));
1117 }
1118
1119 void xpcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
1120 phy_interface_t interface, int speed, int duplex)
1121 {
1122 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1123
1124 if (interface == PHY_INTERFACE_MODE_USXGMII)
1125 return xpcs_config_usxgmii(xpcs, speed);
1126 if (interface == PHY_INTERFACE_MODE_SGMII)
1127 return xpcs_link_up_sgmii(xpcs, mode, speed, duplex);
1128 if (interface == PHY_INTERFACE_MODE_1000BASEX)
1129 return xpcs_link_up_1000basex(xpcs, mode, speed, duplex);
1130 }
1131 EXPORT_SYMBOL_GPL(xpcs_link_up);
1132
1133 static void xpcs_an_restart(struct phylink_pcs *pcs)
1134 {
1135 struct dw_xpcs *xpcs = phylink_pcs_to_xpcs(pcs);
1136 int ret;
1137
1138 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1);
1139 if (ret >= 0) {
1140 ret |= BMCR_ANRESTART;
1141 xpcs_write(xpcs, MDIO_MMD_VEND2, MDIO_CTRL1, ret);
1142 }
1143 }
1144
1145 static u32 xpcs_get_id(struct dw_xpcs *xpcs)
1146 {
1147 int ret;
1148 u32 id;
1149
1150
1151 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID1);
1152 if (ret < 0)
1153 return 0xffffffff;
1154
1155 id = ret << 16;
1156
1157 ret = xpcs_read(xpcs, MDIO_MMD_PCS, MII_PHYSID2);
1158 if (ret < 0)
1159 return 0xffffffff;
1160
1161
1162
1163
1164 if ((id | ret) && (id | ret) != 0xffffffff)
1165 return id | ret;
1166
1167
1168 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID1);
1169 if (ret < 0)
1170 return 0xffffffff;
1171
1172 id = ret << 16;
1173
1174 ret = xpcs_read(xpcs, MDIO_MMD_VEND2, MII_PHYSID2);
1175 if (ret < 0)
1176 return 0xffffffff;
1177
1178
1179 if (id | ret)
1180 return id | ret;
1181
1182 return 0xffffffff;
1183 }
1184
1185 static const struct xpcs_compat synopsys_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1186 [DW_XPCS_USXGMII] = {
1187 .supported = xpcs_usxgmii_features,
1188 .interface = xpcs_usxgmii_interfaces,
1189 .num_interfaces = ARRAY_SIZE(xpcs_usxgmii_interfaces),
1190 .an_mode = DW_AN_C73,
1191 },
1192 [DW_XPCS_10GKR] = {
1193 .supported = xpcs_10gkr_features,
1194 .interface = xpcs_10gkr_interfaces,
1195 .num_interfaces = ARRAY_SIZE(xpcs_10gkr_interfaces),
1196 .an_mode = DW_AN_C73,
1197 },
1198 [DW_XPCS_XLGMII] = {
1199 .supported = xpcs_xlgmii_features,
1200 .interface = xpcs_xlgmii_interfaces,
1201 .num_interfaces = ARRAY_SIZE(xpcs_xlgmii_interfaces),
1202 .an_mode = DW_AN_C73,
1203 },
1204 [DW_XPCS_SGMII] = {
1205 .supported = xpcs_sgmii_features,
1206 .interface = xpcs_sgmii_interfaces,
1207 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1208 .an_mode = DW_AN_C37_SGMII,
1209 },
1210 [DW_XPCS_1000BASEX] = {
1211 .supported = xpcs_1000basex_features,
1212 .interface = xpcs_1000basex_interfaces,
1213 .num_interfaces = ARRAY_SIZE(xpcs_1000basex_interfaces),
1214 .an_mode = DW_AN_C37_1000BASEX,
1215 },
1216 [DW_XPCS_2500BASEX] = {
1217 .supported = xpcs_2500basex_features,
1218 .interface = xpcs_2500basex_interfaces,
1219 .num_interfaces = ARRAY_SIZE(xpcs_2500basex_features),
1220 .an_mode = DW_2500BASEX,
1221 },
1222 };
1223
1224 static const struct xpcs_compat nxp_sja1105_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1225 [DW_XPCS_SGMII] = {
1226 .supported = xpcs_sgmii_features,
1227 .interface = xpcs_sgmii_interfaces,
1228 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1229 .an_mode = DW_AN_C37_SGMII,
1230 .pma_config = nxp_sja1105_sgmii_pma_config,
1231 },
1232 };
1233
1234 static const struct xpcs_compat nxp_sja1110_xpcs_compat[DW_XPCS_INTERFACE_MAX] = {
1235 [DW_XPCS_SGMII] = {
1236 .supported = xpcs_sgmii_features,
1237 .interface = xpcs_sgmii_interfaces,
1238 .num_interfaces = ARRAY_SIZE(xpcs_sgmii_interfaces),
1239 .an_mode = DW_AN_C37_SGMII,
1240 .pma_config = nxp_sja1110_sgmii_pma_config,
1241 },
1242 [DW_XPCS_2500BASEX] = {
1243 .supported = xpcs_2500basex_features,
1244 .interface = xpcs_2500basex_interfaces,
1245 .num_interfaces = ARRAY_SIZE(xpcs_2500basex_interfaces),
1246 .an_mode = DW_2500BASEX,
1247 .pma_config = nxp_sja1110_2500basex_pma_config,
1248 },
1249 };
1250
1251 static const struct xpcs_id xpcs_id_list[] = {
1252 {
1253 .id = SYNOPSYS_XPCS_ID,
1254 .mask = SYNOPSYS_XPCS_MASK,
1255 .compat = synopsys_xpcs_compat,
1256 }, {
1257 .id = NXP_SJA1105_XPCS_ID,
1258 .mask = SYNOPSYS_XPCS_MASK,
1259 .compat = nxp_sja1105_xpcs_compat,
1260 }, {
1261 .id = NXP_SJA1110_XPCS_ID,
1262 .mask = SYNOPSYS_XPCS_MASK,
1263 .compat = nxp_sja1110_xpcs_compat,
1264 },
1265 };
1266
1267 static const struct phylink_pcs_ops xpcs_phylink_ops = {
1268 .pcs_validate = xpcs_validate,
1269 .pcs_config = xpcs_config,
1270 .pcs_get_state = xpcs_get_state,
1271 .pcs_an_restart = xpcs_an_restart,
1272 .pcs_link_up = xpcs_link_up,
1273 };
1274
1275 struct dw_xpcs *xpcs_create(struct mdio_device *mdiodev,
1276 phy_interface_t interface)
1277 {
1278 struct dw_xpcs *xpcs;
1279 u32 xpcs_id;
1280 int i, ret;
1281
1282 xpcs = kzalloc(sizeof(*xpcs), GFP_KERNEL);
1283 if (!xpcs)
1284 return ERR_PTR(-ENOMEM);
1285
1286 xpcs->mdiodev = mdiodev;
1287
1288 xpcs_id = xpcs_get_id(xpcs);
1289
1290 for (i = 0; i < ARRAY_SIZE(xpcs_id_list); i++) {
1291 const struct xpcs_id *entry = &xpcs_id_list[i];
1292 const struct xpcs_compat *compat;
1293
1294 if ((xpcs_id & entry->mask) != entry->id)
1295 continue;
1296
1297 xpcs->id = entry;
1298
1299 compat = xpcs_find_compat(entry, interface);
1300 if (!compat) {
1301 ret = -ENODEV;
1302 goto out;
1303 }
1304
1305 xpcs->pcs.ops = &xpcs_phylink_ops;
1306 xpcs->pcs.poll = true;
1307
1308 ret = xpcs_soft_reset(xpcs, compat);
1309 if (ret)
1310 goto out;
1311
1312 return xpcs;
1313 }
1314
1315 ret = -ENODEV;
1316
1317 out:
1318 kfree(xpcs);
1319
1320 return ERR_PTR(ret);
1321 }
1322 EXPORT_SYMBOL_GPL(xpcs_create);
1323
1324 void xpcs_destroy(struct dw_xpcs *xpcs)
1325 {
1326 kfree(xpcs);
1327 }
1328 EXPORT_SYMBOL_GPL(xpcs_destroy);
1329
1330 MODULE_LICENSE("GPL v2");