Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2020 Synopsys, Inc. and/or its affiliates.
0004  * Synopsys DesignWare XPCS helpers
0005  *
0006  * Author: Jose Abreu <Jose.Abreu@synopsys.com>
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     /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */
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         /* Nothing to do here */
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     /* By default, in USXGMII mode XPCS operates at 10G baud and
0439      * replicates data to achieve lower speeds. Hereby, in this
0440      * default configuration we need to advertise all supported
0441      * modes and not only the ones we want to use.
0442      */
0443 
0444     /* SR_AN_ADV3 */
0445     adv = 0;
0446     if (xpcs_linkmode_supported(compat, 2500baseX_Full))
0447         adv |= DW_C73_2500KX;
0448 
0449     /* TODO: 5000baseKR */
0450 
0451     ret = xpcs_write(xpcs, MDIO_MMD_AN, DW_SR_AN_ADV3, adv);
0452     if (ret < 0)
0453         return ret;
0454 
0455     /* SR_AN_ADV2 */
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     /* SR_AN_ADV1 */
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         /* Check if Aneg outcome is valid */
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     /* Clause 73 outcome */
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     /* Populate the supported link modes for this PHY interface type.
0667      * FIXME: what about the port modes and autoneg bit? This masks
0668      * all those away.
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     /* Enable EEE */
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     /* For AN for C37 SGMII mode, the settings are :-
0736      * 1) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 0b (Disable SGMII AN in case
0737           it is already enabled)
0738      * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 10b (SGMII AN)
0739      * 3) VR_MII_AN_CTRL Bit(3) [TX_CONFIG] = 0b (MAC side SGMII)
0740      *    DW xPCS used with DW EQoS MAC is always MAC side SGMII.
0741      * 4) VR_MII_DIG_CTRL1 Bit(9) [MAC_AUTO_SW] = 1b (Automatic
0742      *    speed/duplex mode change by HW after SGMII AN complete)
0743      * 5) VR_MII_MMD_CTRL Bit(12) [AN_ENABLE] = 1b (Enable SGMII AN)
0744      *
0745      * Note: Since it is MAC side SGMII, there is no need to set
0746      *   SR_MII_AN_ADV. MAC side SGMII receives AN Tx Config from
0747      *   PHY about the link state change after C28 AN is completed
0748      *   between PHY and Link Partner. There is also no need to
0749      *   trigger AN restart for MAC-side SGMII.
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     /* According to Chap 7.12, to set 1000BASE-X C37 AN, AN must
0805      * be disabled first:-
0806      * 1) VR_MII_MMD_CTRL Bit(12)[AN_ENABLE] = 0b
0807      * 2) VR_MII_AN_CTRL Bit(2:1)[PCS_MODE] = 00b (1000BASE-X C37)
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     /* Check for advertising changes and update the C45 MII ADV
0830      * register accordingly.
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     /* Clear CL37 AN complete status */
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     /* Link needs to be read first ... */
0946     state->link = xpcs_read_link_c73(xpcs, state->an_enabled) > 0 ? 1 : 0;
0947 
0948     /* ... and then we check the faults. */
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     /* Reset link_state */
0979     state->link = false;
0980     state->speed = SPEED_UNKNOWN;
0981     state->duplex = DUPLEX_UNKNOWN;
0982     state->pause = 0;
0983 
0984     /* For C37 SGMII mode, we check DW_VR_MII_AN_INTR_STS for link
0985      * status, speed and duplex.
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         /* Reset link state */
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     /* First, search C73 PCS using PCS MMD */
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     /* If Device IDs are not all zeros or all ones,
1162      * we found C73 AN-type device
1163      */
1164     if ((id | ret) && (id | ret) != 0xffffffff)
1165         return id | ret;
1166 
1167     /* Next, search C37 PCS using Vendor-Specific MII MMD */
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     /* If Device IDs are not all zeros, we found C37 AN-type device */
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");