Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* Copyright (C) 2021 Maxlinear Corporation
0003  * Copyright (C) 2020 Intel Corporation
0004  *
0005  * Drivers for Maxlinear Ethernet GPY
0006  *
0007  */
0008 
0009 #include <linux/module.h>
0010 #include <linux/bitfield.h>
0011 #include <linux/hwmon.h>
0012 #include <linux/phy.h>
0013 #include <linux/polynomial.h>
0014 #include <linux/netdevice.h>
0015 
0016 /* PHY ID */
0017 #define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
0018 #define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
0019 #define PHY_ID_GPY2xx       0x67C9DC00
0020 #define PHY_ID_GPY115B      0x67C9DF00
0021 #define PHY_ID_GPY115C      0x67C9DF10
0022 #define PHY_ID_GPY211B      0x67C9DE08
0023 #define PHY_ID_GPY211C      0x67C9DE10
0024 #define PHY_ID_GPY212B      0x67C9DE09
0025 #define PHY_ID_GPY212C      0x67C9DE20
0026 #define PHY_ID_GPY215B      0x67C9DF04
0027 #define PHY_ID_GPY215C      0x67C9DF20
0028 #define PHY_ID_GPY241B      0x67C9DE40
0029 #define PHY_ID_GPY241BM     0x67C9DE80
0030 #define PHY_ID_GPY245B      0x67C9DEC0
0031 
0032 #define PHY_MIISTAT     0x18    /* MII state */
0033 #define PHY_IMASK       0x19    /* interrupt mask */
0034 #define PHY_ISTAT       0x1A    /* interrupt status */
0035 #define PHY_FWV         0x1E    /* firmware version */
0036 
0037 #define PHY_MIISTAT_SPD_MASK    GENMASK(2, 0)
0038 #define PHY_MIISTAT_DPX     BIT(3)
0039 #define PHY_MIISTAT_LS      BIT(10)
0040 
0041 #define PHY_MIISTAT_SPD_10  0
0042 #define PHY_MIISTAT_SPD_100 1
0043 #define PHY_MIISTAT_SPD_1000    2
0044 #define PHY_MIISTAT_SPD_2500    4
0045 
0046 #define PHY_IMASK_WOL       BIT(15) /* Wake-on-LAN */
0047 #define PHY_IMASK_ANC       BIT(10) /* Auto-Neg complete */
0048 #define PHY_IMASK_ADSC      BIT(5)  /* Link auto-downspeed detect */
0049 #define PHY_IMASK_DXMC      BIT(2)  /* Duplex mode change */
0050 #define PHY_IMASK_LSPC      BIT(1)  /* Link speed change */
0051 #define PHY_IMASK_LSTC      BIT(0)  /* Link state change */
0052 #define PHY_IMASK_MASK      (PHY_IMASK_LSTC | \
0053                  PHY_IMASK_LSPC | \
0054                  PHY_IMASK_DXMC | \
0055                  PHY_IMASK_ADSC | \
0056                  PHY_IMASK_ANC)
0057 
0058 #define PHY_FWV_REL_MASK    BIT(15)
0059 #define PHY_FWV_MAJOR_MASK  GENMASK(11, 8)
0060 #define PHY_FWV_MINOR_MASK  GENMASK(7, 0)
0061 
0062 /* SGMII */
0063 #define VSPEC1_SGMII_CTRL   0x08
0064 #define VSPEC1_SGMII_CTRL_ANEN  BIT(12)     /* Aneg enable */
0065 #define VSPEC1_SGMII_CTRL_ANRS  BIT(9)      /* Restart Aneg */
0066 #define VSPEC1_SGMII_ANEN_ANRS  (VSPEC1_SGMII_CTRL_ANEN | \
0067                  VSPEC1_SGMII_CTRL_ANRS)
0068 
0069 /* Temperature sensor */
0070 #define VPSPEC1_TEMP_STA    0x0E
0071 #define VPSPEC1_TEMP_STA_DATA   GENMASK(9, 0)
0072 
0073 /* WoL */
0074 #define VPSPEC2_WOL_CTL     0x0E06
0075 #define VPSPEC2_WOL_AD01    0x0E08
0076 #define VPSPEC2_WOL_AD23    0x0E09
0077 #define VPSPEC2_WOL_AD45    0x0E0A
0078 #define WOL_EN          BIT(0)
0079 
0080 struct gpy_priv {
0081     u8 fw_major;
0082     u8 fw_minor;
0083 };
0084 
0085 static const struct {
0086     int major;
0087     int minor;
0088 } ver_need_sgmii_reaneg[] = {
0089     {7, 0x6D},
0090     {8, 0x6D},
0091     {9, 0x73},
0092 };
0093 
0094 #if IS_ENABLED(CONFIG_HWMON)
0095 /* The original translation formulae of the temperature (in degrees of Celsius)
0096  * are as follows:
0097  *
0098  *   T = -2.5761e-11*(N^4) + 9.7332e-8*(N^3) + -1.9165e-4*(N^2) +
0099  *       3.0762e-1*(N^1) + -5.2156e1
0100  *
0101  * where [-52.156, 137.961]C and N = [0, 1023].
0102  *
0103  * They must be accordingly altered to be suitable for the integer arithmetics.
0104  * The technique is called 'factor redistribution', which just makes sure the
0105  * multiplications and divisions are made so to have a result of the operations
0106  * within the integer numbers limit. In addition we need to translate the
0107  * formulae to accept millidegrees of Celsius. Here what it looks like after
0108  * the alterations:
0109  *
0110  *   T = -25761e-12*(N^4) + 97332e-9*(N^3) + -191650e-6*(N^2) +
0111  *       307620e-3*(N^1) + -52156
0112  *
0113  * where T = [-52156, 137961]mC and N = [0, 1023].
0114  */
0115 static const struct polynomial poly_N_to_temp = {
0116     .terms = {
0117         {4,  -25761, 1000, 1},
0118         {3,   97332, 1000, 1},
0119         {2, -191650, 1000, 1},
0120         {1,  307620, 1000, 1},
0121         {0,  -52156,    1, 1}
0122     }
0123 };
0124 
0125 static int gpy_hwmon_read(struct device *dev,
0126               enum hwmon_sensor_types type,
0127               u32 attr, int channel, long *value)
0128 {
0129     struct phy_device *phydev = dev_get_drvdata(dev);
0130     int ret;
0131 
0132     ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VPSPEC1_TEMP_STA);
0133     if (ret < 0)
0134         return ret;
0135     if (!ret)
0136         return -ENODATA;
0137 
0138     *value = polynomial_calc(&poly_N_to_temp,
0139                  FIELD_GET(VPSPEC1_TEMP_STA_DATA, ret));
0140 
0141     return 0;
0142 }
0143 
0144 static umode_t gpy_hwmon_is_visible(const void *data,
0145                     enum hwmon_sensor_types type,
0146                     u32 attr, int channel)
0147 {
0148     return 0444;
0149 }
0150 
0151 static const struct hwmon_channel_info *gpy_hwmon_info[] = {
0152     HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
0153     NULL
0154 };
0155 
0156 static const struct hwmon_ops gpy_hwmon_hwmon_ops = {
0157     .is_visible = gpy_hwmon_is_visible,
0158     .read       = gpy_hwmon_read,
0159 };
0160 
0161 static const struct hwmon_chip_info gpy_hwmon_chip_info = {
0162     .ops        = &gpy_hwmon_hwmon_ops,
0163     .info       = gpy_hwmon_info,
0164 };
0165 
0166 static int gpy_hwmon_register(struct phy_device *phydev)
0167 {
0168     struct device *dev = &phydev->mdio.dev;
0169     struct device *hwmon_dev;
0170     char *hwmon_name;
0171 
0172     hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
0173     if (IS_ERR(hwmon_name))
0174         return PTR_ERR(hwmon_name);
0175 
0176     hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
0177                              phydev,
0178                              &gpy_hwmon_chip_info,
0179                              NULL);
0180 
0181     return PTR_ERR_OR_ZERO(hwmon_dev);
0182 }
0183 #else
0184 static int gpy_hwmon_register(struct phy_device *phydev)
0185 {
0186     return 0;
0187 }
0188 #endif
0189 
0190 static int gpy_config_init(struct phy_device *phydev)
0191 {
0192     int ret;
0193 
0194     /* Mask all interrupts */
0195     ret = phy_write(phydev, PHY_IMASK, 0);
0196     if (ret)
0197         return ret;
0198 
0199     /* Clear all pending interrupts */
0200     ret = phy_read(phydev, PHY_ISTAT);
0201     return ret < 0 ? ret : 0;
0202 }
0203 
0204 static int gpy_probe(struct phy_device *phydev)
0205 {
0206     struct device *dev = &phydev->mdio.dev;
0207     struct gpy_priv *priv;
0208     int fw_version;
0209     int ret;
0210 
0211     if (!phydev->is_c45) {
0212         ret = phy_get_c45_ids(phydev);
0213         if (ret < 0)
0214             return ret;
0215     }
0216 
0217     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0218     if (!priv)
0219         return -ENOMEM;
0220     phydev->priv = priv;
0221 
0222     fw_version = phy_read(phydev, PHY_FWV);
0223     if (fw_version < 0)
0224         return fw_version;
0225     priv->fw_major = FIELD_GET(PHY_FWV_MAJOR_MASK, fw_version);
0226     priv->fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_version);
0227 
0228     ret = gpy_hwmon_register(phydev);
0229     if (ret)
0230         return ret;
0231 
0232     /* Show GPY PHY FW version in dmesg */
0233     phydev_info(phydev, "Firmware Version: %d.%d (0x%04X%s)\n",
0234             priv->fw_major, priv->fw_minor, fw_version,
0235             fw_version & PHY_FWV_REL_MASK ? "" : " test version");
0236 
0237     return 0;
0238 }
0239 
0240 static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
0241 {
0242     struct gpy_priv *priv = phydev->priv;
0243     size_t i;
0244 
0245     for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
0246         if (priv->fw_major != ver_need_sgmii_reaneg[i].major)
0247             continue;
0248         if (priv->fw_minor < ver_need_sgmii_reaneg[i].minor)
0249             return true;
0250         break;
0251     }
0252 
0253     return false;
0254 }
0255 
0256 static bool gpy_2500basex_chk(struct phy_device *phydev)
0257 {
0258     int ret;
0259 
0260     ret = phy_read(phydev, PHY_MIISTAT);
0261     if (ret < 0) {
0262         phydev_err(phydev, "Error: MDIO register access failed: %d\n",
0263                ret);
0264         return false;
0265     }
0266 
0267     if (!(ret & PHY_MIISTAT_LS) ||
0268         FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
0269         return false;
0270 
0271     phydev->speed = SPEED_2500;
0272     phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
0273     phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0274                VSPEC1_SGMII_CTRL_ANEN, 0);
0275     return true;
0276 }
0277 
0278 static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
0279 {
0280     int ret;
0281 
0282     ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
0283     if (ret < 0) {
0284         phydev_err(phydev, "Error: MMD register access failed: %d\n",
0285                ret);
0286         return true;
0287     }
0288 
0289     return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
0290 }
0291 
0292 static int gpy_config_aneg(struct phy_device *phydev)
0293 {
0294     bool changed = false;
0295     u32 adv;
0296     int ret;
0297 
0298     if (phydev->autoneg == AUTONEG_DISABLE) {
0299         /* Configure half duplex with genphy_setup_forced,
0300          * because genphy_c45_pma_setup_forced does not support.
0301          */
0302         return phydev->duplex != DUPLEX_FULL
0303             ? genphy_setup_forced(phydev)
0304             : genphy_c45_pma_setup_forced(phydev);
0305     }
0306 
0307     ret = genphy_c45_an_config_aneg(phydev);
0308     if (ret < 0)
0309         return ret;
0310     if (ret > 0)
0311         changed = true;
0312 
0313     adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
0314     ret = phy_modify_changed(phydev, MII_CTRL1000,
0315                  ADVERTISE_1000FULL | ADVERTISE_1000HALF,
0316                  adv);
0317     if (ret < 0)
0318         return ret;
0319     if (ret > 0)
0320         changed = true;
0321 
0322     ret = genphy_c45_check_and_restart_aneg(phydev, changed);
0323     if (ret < 0)
0324         return ret;
0325 
0326     if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
0327         phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
0328         return 0;
0329 
0330     /* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is
0331      * disabled.
0332      */
0333     if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
0334         !gpy_sgmii_aneg_en(phydev))
0335         return 0;
0336 
0337     /* There is a design constraint in GPY2xx device where SGMII AN is
0338      * only triggered when there is change of speed. If, PHY link
0339      * partner`s speed is still same even after PHY TPI is down and up
0340      * again, SGMII AN is not triggered and hence no new in-band message
0341      * from GPY to MAC side SGMII.
0342      * This could cause an issue during power up, when PHY is up prior to
0343      * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII
0344      * wouldn`t receive new in-band message from GPY with correct link
0345      * status, speed and duplex info.
0346      *
0347      * 1) If PHY is already up and TPI link status is still down (such as
0348      *    hard reboot), TPI link status is polled for 4 seconds before
0349      *    retriggerring SGMII AN.
0350      * 2) If PHY is already up and TPI link status is also up (such as soft
0351      *    reboot), polling of TPI link status is not needed and SGMII AN is
0352      *    immediately retriggered.
0353      * 3) Other conditions such as PHY is down, speed change etc, skip
0354      *    retriggering SGMII AN. Note: in case of speed change, GPY FW will
0355      *    initiate SGMII AN.
0356      */
0357 
0358     if (phydev->state != PHY_UP)
0359         return 0;
0360 
0361     ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
0362                     20000, 4000000, false);
0363     if (ret == -ETIMEDOUT)
0364         return 0;
0365     else if (ret < 0)
0366         return ret;
0367 
0368     /* Trigger SGMII AN. */
0369     return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0370                   VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
0371 }
0372 
0373 static void gpy_update_interface(struct phy_device *phydev)
0374 {
0375     int ret;
0376 
0377     /* Interface mode is fixed for USXGMII and integrated PHY */
0378     if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
0379         phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
0380         return;
0381 
0382     /* Automatically switch SERDES interface between SGMII and 2500-BaseX
0383      * according to speed. Disable ANEG in 2500-BaseX mode.
0384      */
0385     switch (phydev->speed) {
0386     case SPEED_2500:
0387         phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
0388         ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0389                      VSPEC1_SGMII_CTRL_ANEN, 0);
0390         if (ret < 0)
0391             phydev_err(phydev,
0392                    "Error: Disable of SGMII ANEG failed: %d\n",
0393                    ret);
0394         break;
0395     case SPEED_1000:
0396     case SPEED_100:
0397     case SPEED_10:
0398         phydev->interface = PHY_INTERFACE_MODE_SGMII;
0399         if (gpy_sgmii_aneg_en(phydev))
0400             break;
0401         /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
0402          * if ANEG is disabled (in 2500-BaseX mode).
0403          */
0404         ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0405                      VSPEC1_SGMII_ANEN_ANRS,
0406                      VSPEC1_SGMII_ANEN_ANRS);
0407         if (ret < 0)
0408             phydev_err(phydev,
0409                    "Error: Enable of SGMII ANEG failed: %d\n",
0410                    ret);
0411         break;
0412     }
0413 
0414     if (phydev->speed == SPEED_2500 || phydev->speed == SPEED_1000)
0415         genphy_read_master_slave(phydev);
0416 }
0417 
0418 static int gpy_read_status(struct phy_device *phydev)
0419 {
0420     int ret;
0421 
0422     ret = genphy_update_link(phydev);
0423     if (ret)
0424         return ret;
0425 
0426     phydev->speed = SPEED_UNKNOWN;
0427     phydev->duplex = DUPLEX_UNKNOWN;
0428     phydev->pause = 0;
0429     phydev->asym_pause = 0;
0430 
0431     if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
0432         ret = genphy_c45_read_lpa(phydev);
0433         if (ret < 0)
0434             return ret;
0435 
0436         /* Read the link partner's 1G advertisement */
0437         ret = phy_read(phydev, MII_STAT1000);
0438         if (ret < 0)
0439             return ret;
0440         mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
0441     } else if (phydev->autoneg == AUTONEG_DISABLE) {
0442         linkmode_zero(phydev->lp_advertising);
0443     }
0444 
0445     ret = phy_read(phydev, PHY_MIISTAT);
0446     if (ret < 0)
0447         return ret;
0448 
0449     phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0;
0450     phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF;
0451     switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) {
0452     case PHY_MIISTAT_SPD_10:
0453         phydev->speed = SPEED_10;
0454         break;
0455     case PHY_MIISTAT_SPD_100:
0456         phydev->speed = SPEED_100;
0457         break;
0458     case PHY_MIISTAT_SPD_1000:
0459         phydev->speed = SPEED_1000;
0460         break;
0461     case PHY_MIISTAT_SPD_2500:
0462         phydev->speed = SPEED_2500;
0463         break;
0464     }
0465 
0466     if (phydev->link)
0467         gpy_update_interface(phydev);
0468 
0469     return 0;
0470 }
0471 
0472 static int gpy_config_intr(struct phy_device *phydev)
0473 {
0474     u16 mask = 0;
0475 
0476     if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
0477         mask = PHY_IMASK_MASK;
0478 
0479     return phy_write(phydev, PHY_IMASK, mask);
0480 }
0481 
0482 static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
0483 {
0484     int reg;
0485 
0486     reg = phy_read(phydev, PHY_ISTAT);
0487     if (reg < 0) {
0488         phy_error(phydev);
0489         return IRQ_NONE;
0490     }
0491 
0492     if (!(reg & PHY_IMASK_MASK))
0493         return IRQ_NONE;
0494 
0495     phy_trigger_machine(phydev);
0496 
0497     return IRQ_HANDLED;
0498 }
0499 
0500 static int gpy_set_wol(struct phy_device *phydev,
0501                struct ethtool_wolinfo *wol)
0502 {
0503     struct net_device *attach_dev = phydev->attached_dev;
0504     int ret;
0505 
0506     if (wol->wolopts & WAKE_MAGIC) {
0507         /* MAC address - Byte0:Byte1:Byte2:Byte3:Byte4:Byte5
0508          * VPSPEC2_WOL_AD45 = Byte0:Byte1
0509          * VPSPEC2_WOL_AD23 = Byte2:Byte3
0510          * VPSPEC2_WOL_AD01 = Byte4:Byte5
0511          */
0512         ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0513                        VPSPEC2_WOL_AD45,
0514                        ((attach_dev->dev_addr[0] << 8) |
0515                        attach_dev->dev_addr[1]));
0516         if (ret < 0)
0517             return ret;
0518 
0519         ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0520                        VPSPEC2_WOL_AD23,
0521                        ((attach_dev->dev_addr[2] << 8) |
0522                        attach_dev->dev_addr[3]));
0523         if (ret < 0)
0524             return ret;
0525 
0526         ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0527                        VPSPEC2_WOL_AD01,
0528                        ((attach_dev->dev_addr[4] << 8) |
0529                        attach_dev->dev_addr[5]));
0530         if (ret < 0)
0531             return ret;
0532 
0533         /* Enable the WOL interrupt */
0534         ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL);
0535         if (ret < 0)
0536             return ret;
0537 
0538         /* Enable magic packet matching */
0539         ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0540                        VPSPEC2_WOL_CTL,
0541                        WOL_EN);
0542         if (ret < 0)
0543             return ret;
0544 
0545         /* Clear the interrupt status register.
0546          * Only WoL is enabled so clear all.
0547          */
0548         ret = phy_read(phydev, PHY_ISTAT);
0549         if (ret < 0)
0550             return ret;
0551     } else {
0552         /* Disable magic packet matching */
0553         ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
0554                      VPSPEC2_WOL_CTL,
0555                      WOL_EN);
0556         if (ret < 0)
0557             return ret;
0558     }
0559 
0560     if (wol->wolopts & WAKE_PHY) {
0561         /* Enable the link state change interrupt */
0562         ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
0563         if (ret < 0)
0564             return ret;
0565 
0566         /* Clear the interrupt status register */
0567         ret = phy_read(phydev, PHY_ISTAT);
0568         if (ret < 0)
0569             return ret;
0570 
0571         if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC))
0572             phy_trigger_machine(phydev);
0573 
0574         return 0;
0575     }
0576 
0577     /* Disable the link state change interrupt */
0578     return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
0579 }
0580 
0581 static void gpy_get_wol(struct phy_device *phydev,
0582             struct ethtool_wolinfo *wol)
0583 {
0584     int ret;
0585 
0586     wol->supported = WAKE_MAGIC | WAKE_PHY;
0587     wol->wolopts = 0;
0588 
0589     ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL);
0590     if (ret & WOL_EN)
0591         wol->wolopts |= WAKE_MAGIC;
0592 
0593     ret = phy_read(phydev, PHY_IMASK);
0594     if (ret & PHY_IMASK_LSTC)
0595         wol->wolopts |= WAKE_PHY;
0596 }
0597 
0598 static int gpy_loopback(struct phy_device *phydev, bool enable)
0599 {
0600     int ret;
0601 
0602     ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
0603              enable ? BMCR_LOOPBACK : 0);
0604     if (!ret) {
0605         /* It takes some time for PHY device to switch
0606          * into/out-of loopback mode.
0607          */
0608         msleep(100);
0609     }
0610 
0611     return ret;
0612 }
0613 
0614 static int gpy115_loopback(struct phy_device *phydev, bool enable)
0615 {
0616     struct gpy_priv *priv = phydev->priv;
0617 
0618     if (enable)
0619         return gpy_loopback(phydev, enable);
0620 
0621     if (priv->fw_minor > 0x76)
0622         return gpy_loopback(phydev, 0);
0623 
0624     return genphy_soft_reset(phydev);
0625 }
0626 
0627 static struct phy_driver gpy_drivers[] = {
0628     {
0629         PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
0630         .name       = "Maxlinear Ethernet GPY2xx",
0631         .get_features   = genphy_c45_pma_read_abilities,
0632         .config_init    = gpy_config_init,
0633         .probe      = gpy_probe,
0634         .suspend    = genphy_suspend,
0635         .resume     = genphy_resume,
0636         .config_aneg    = gpy_config_aneg,
0637         .aneg_done  = genphy_c45_aneg_done,
0638         .read_status    = gpy_read_status,
0639         .config_intr    = gpy_config_intr,
0640         .handle_interrupt = gpy_handle_interrupt,
0641         .set_wol    = gpy_set_wol,
0642         .get_wol    = gpy_get_wol,
0643         .set_loopback   = gpy_loopback,
0644     },
0645     {
0646         .phy_id     = PHY_ID_GPY115B,
0647         .phy_id_mask    = PHY_ID_GPYx15B_MASK,
0648         .name       = "Maxlinear Ethernet GPY115B",
0649         .get_features   = genphy_c45_pma_read_abilities,
0650         .config_init    = gpy_config_init,
0651         .probe      = gpy_probe,
0652         .suspend    = genphy_suspend,
0653         .resume     = genphy_resume,
0654         .config_aneg    = gpy_config_aneg,
0655         .aneg_done  = genphy_c45_aneg_done,
0656         .read_status    = gpy_read_status,
0657         .config_intr    = gpy_config_intr,
0658         .handle_interrupt = gpy_handle_interrupt,
0659         .set_wol    = gpy_set_wol,
0660         .get_wol    = gpy_get_wol,
0661         .set_loopback   = gpy115_loopback,
0662     },
0663     {
0664         PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
0665         .name       = "Maxlinear Ethernet GPY115C",
0666         .get_features   = genphy_c45_pma_read_abilities,
0667         .config_init    = gpy_config_init,
0668         .probe      = gpy_probe,
0669         .suspend    = genphy_suspend,
0670         .resume     = genphy_resume,
0671         .config_aneg    = gpy_config_aneg,
0672         .aneg_done  = genphy_c45_aneg_done,
0673         .read_status    = gpy_read_status,
0674         .config_intr    = gpy_config_intr,
0675         .handle_interrupt = gpy_handle_interrupt,
0676         .set_wol    = gpy_set_wol,
0677         .get_wol    = gpy_get_wol,
0678         .set_loopback   = gpy115_loopback,
0679     },
0680     {
0681         .phy_id     = PHY_ID_GPY211B,
0682         .phy_id_mask    = PHY_ID_GPY21xB_MASK,
0683         .name       = "Maxlinear Ethernet GPY211B",
0684         .get_features   = genphy_c45_pma_read_abilities,
0685         .config_init    = gpy_config_init,
0686         .probe      = gpy_probe,
0687         .suspend    = genphy_suspend,
0688         .resume     = genphy_resume,
0689         .config_aneg    = gpy_config_aneg,
0690         .aneg_done  = genphy_c45_aneg_done,
0691         .read_status    = gpy_read_status,
0692         .config_intr    = gpy_config_intr,
0693         .handle_interrupt = gpy_handle_interrupt,
0694         .set_wol    = gpy_set_wol,
0695         .get_wol    = gpy_get_wol,
0696         .set_loopback   = gpy_loopback,
0697     },
0698     {
0699         PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
0700         .name       = "Maxlinear Ethernet GPY211C",
0701         .get_features   = genphy_c45_pma_read_abilities,
0702         .config_init    = gpy_config_init,
0703         .probe      = gpy_probe,
0704         .suspend    = genphy_suspend,
0705         .resume     = genphy_resume,
0706         .config_aneg    = gpy_config_aneg,
0707         .aneg_done  = genphy_c45_aneg_done,
0708         .read_status    = gpy_read_status,
0709         .config_intr    = gpy_config_intr,
0710         .handle_interrupt = gpy_handle_interrupt,
0711         .set_wol    = gpy_set_wol,
0712         .get_wol    = gpy_get_wol,
0713         .set_loopback   = gpy_loopback,
0714     },
0715     {
0716         .phy_id     = PHY_ID_GPY212B,
0717         .phy_id_mask    = PHY_ID_GPY21xB_MASK,
0718         .name       = "Maxlinear Ethernet GPY212B",
0719         .get_features   = genphy_c45_pma_read_abilities,
0720         .config_init    = gpy_config_init,
0721         .probe      = gpy_probe,
0722         .suspend    = genphy_suspend,
0723         .resume     = genphy_resume,
0724         .config_aneg    = gpy_config_aneg,
0725         .aneg_done  = genphy_c45_aneg_done,
0726         .read_status    = gpy_read_status,
0727         .config_intr    = gpy_config_intr,
0728         .handle_interrupt = gpy_handle_interrupt,
0729         .set_wol    = gpy_set_wol,
0730         .get_wol    = gpy_get_wol,
0731         .set_loopback   = gpy_loopback,
0732     },
0733     {
0734         PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
0735         .name       = "Maxlinear Ethernet GPY212C",
0736         .get_features   = genphy_c45_pma_read_abilities,
0737         .config_init    = gpy_config_init,
0738         .probe      = gpy_probe,
0739         .suspend    = genphy_suspend,
0740         .resume     = genphy_resume,
0741         .config_aneg    = gpy_config_aneg,
0742         .aneg_done  = genphy_c45_aneg_done,
0743         .read_status    = gpy_read_status,
0744         .config_intr    = gpy_config_intr,
0745         .handle_interrupt = gpy_handle_interrupt,
0746         .set_wol    = gpy_set_wol,
0747         .get_wol    = gpy_get_wol,
0748         .set_loopback   = gpy_loopback,
0749     },
0750     {
0751         .phy_id     = PHY_ID_GPY215B,
0752         .phy_id_mask    = PHY_ID_GPYx15B_MASK,
0753         .name       = "Maxlinear Ethernet GPY215B",
0754         .get_features   = genphy_c45_pma_read_abilities,
0755         .config_init    = gpy_config_init,
0756         .probe      = gpy_probe,
0757         .suspend    = genphy_suspend,
0758         .resume     = genphy_resume,
0759         .config_aneg    = gpy_config_aneg,
0760         .aneg_done  = genphy_c45_aneg_done,
0761         .read_status    = gpy_read_status,
0762         .config_intr    = gpy_config_intr,
0763         .handle_interrupt = gpy_handle_interrupt,
0764         .set_wol    = gpy_set_wol,
0765         .get_wol    = gpy_get_wol,
0766         .set_loopback   = gpy_loopback,
0767     },
0768     {
0769         PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
0770         .name       = "Maxlinear Ethernet GPY215C",
0771         .get_features   = genphy_c45_pma_read_abilities,
0772         .config_init    = gpy_config_init,
0773         .probe      = gpy_probe,
0774         .suspend    = genphy_suspend,
0775         .resume     = genphy_resume,
0776         .config_aneg    = gpy_config_aneg,
0777         .aneg_done  = genphy_c45_aneg_done,
0778         .read_status    = gpy_read_status,
0779         .config_intr    = gpy_config_intr,
0780         .handle_interrupt = gpy_handle_interrupt,
0781         .set_wol    = gpy_set_wol,
0782         .get_wol    = gpy_get_wol,
0783         .set_loopback   = gpy_loopback,
0784     },
0785     {
0786         PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
0787         .name       = "Maxlinear Ethernet GPY241B",
0788         .get_features   = genphy_c45_pma_read_abilities,
0789         .config_init    = gpy_config_init,
0790         .probe      = gpy_probe,
0791         .suspend    = genphy_suspend,
0792         .resume     = genphy_resume,
0793         .config_aneg    = gpy_config_aneg,
0794         .aneg_done  = genphy_c45_aneg_done,
0795         .read_status    = gpy_read_status,
0796         .config_intr    = gpy_config_intr,
0797         .handle_interrupt = gpy_handle_interrupt,
0798         .set_wol    = gpy_set_wol,
0799         .get_wol    = gpy_get_wol,
0800         .set_loopback   = gpy_loopback,
0801     },
0802     {
0803         PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM),
0804         .name       = "Maxlinear Ethernet GPY241BM",
0805         .get_features   = genphy_c45_pma_read_abilities,
0806         .config_init    = gpy_config_init,
0807         .probe      = gpy_probe,
0808         .suspend    = genphy_suspend,
0809         .resume     = genphy_resume,
0810         .config_aneg    = gpy_config_aneg,
0811         .aneg_done  = genphy_c45_aneg_done,
0812         .read_status    = gpy_read_status,
0813         .config_intr    = gpy_config_intr,
0814         .handle_interrupt = gpy_handle_interrupt,
0815         .set_wol    = gpy_set_wol,
0816         .get_wol    = gpy_get_wol,
0817         .set_loopback   = gpy_loopback,
0818     },
0819     {
0820         PHY_ID_MATCH_MODEL(PHY_ID_GPY245B),
0821         .name       = "Maxlinear Ethernet GPY245B",
0822         .get_features   = genphy_c45_pma_read_abilities,
0823         .config_init    = gpy_config_init,
0824         .probe      = gpy_probe,
0825         .suspend    = genphy_suspend,
0826         .resume     = genphy_resume,
0827         .config_aneg    = gpy_config_aneg,
0828         .aneg_done  = genphy_c45_aneg_done,
0829         .read_status    = gpy_read_status,
0830         .config_intr    = gpy_config_intr,
0831         .handle_interrupt = gpy_handle_interrupt,
0832         .set_wol    = gpy_set_wol,
0833         .get_wol    = gpy_get_wol,
0834         .set_loopback   = gpy_loopback,
0835     },
0836 };
0837 module_phy_driver(gpy_drivers);
0838 
0839 static struct mdio_device_id __maybe_unused gpy_tbl[] = {
0840     {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
0841     {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
0842     {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
0843     {PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK},
0844     {PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)},
0845     {PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK},
0846     {PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)},
0847     {PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK},
0848     {PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)},
0849     {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
0850     {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
0851     {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
0852     { }
0853 };
0854 MODULE_DEVICE_TABLE(mdio, gpy_tbl);
0855 
0856 MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver");
0857 MODULE_AUTHOR("Xu Liang");
0858 MODULE_LICENSE("GPL");