root/drivers/net/phy/marvell10g.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mv3310_hwmon_is_visible
  2. mv3310_hwmon_read
  3. mv3310_hwmon_config
  4. mv3310_hwmon_disable
  5. mv3310_hwmon_probe
  6. mv3310_hwmon_config
  7. mv3310_hwmon_probe
  8. mv3310_probe
  9. mv3310_suspend
  10. mv3310_resume
  11. mv3310_has_pma_ngbaset_quirk
  12. mv3310_config_init
  13. mv3310_get_features
  14. mv3310_config_aneg
  15. mv3310_aneg_done
  16. mv3310_update_interface
  17. mv3310_read_10gbr_status
  18. mv3310_read_status

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Marvell 10G 88x3310 PHY driver
   4  *
   5  * Based upon the ID registers, this PHY appears to be a mixture of IPs
   6  * from two different companies.
   7  *
   8  * There appears to be several different data paths through the PHY which
   9  * are automatically managed by the PHY.  The following has been determined
  10  * via observation and experimentation for a setup using single-lane Serdes:
  11  *
  12  *       SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
  13  *  10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
  14  *  10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
  15  *
  16  * With XAUI, observation shows:
  17  *
  18  *        XAUI PHYXS -- <appropriate PCS as above>
  19  *
  20  * and no switching of the host interface mode occurs.
  21  *
  22  * If both the fiber and copper ports are connected, the first to gain
  23  * link takes priority and the other port is completely locked out.
  24  */
  25 #include <linux/ctype.h>
  26 #include <linux/hwmon.h>
  27 #include <linux/marvell_phy.h>
  28 #include <linux/phy.h>
  29 
  30 #define MV_PHY_ALASKA_NBT_QUIRK_MASK    0xfffffffe
  31 #define MV_PHY_ALASKA_NBT_QUIRK_REV     (MARVELL_PHY_ID_88X3310 | 0xa)
  32 
  33 enum {
  34         MV_PMA_BOOT             = 0xc050,
  35         MV_PMA_BOOT_FATAL       = BIT(0),
  36 
  37         MV_PCS_BASE_T           = 0x0000,
  38         MV_PCS_BASE_R           = 0x1000,
  39         MV_PCS_1000BASEX        = 0x2000,
  40 
  41         MV_PCS_PAIRSWAP         = 0x8182,
  42         MV_PCS_PAIRSWAP_MASK    = 0x0003,
  43         MV_PCS_PAIRSWAP_AB      = 0x0002,
  44         MV_PCS_PAIRSWAP_NONE    = 0x0003,
  45 
  46         /* These registers appear at 0x800X and 0xa00X - the 0xa00X control
  47          * registers appear to set themselves to the 0x800X when AN is
  48          * restarted, but status registers appear readable from either.
  49          */
  50         MV_AN_CTRL1000          = 0x8000, /* 1000base-T control register */
  51         MV_AN_STAT1000          = 0x8001, /* 1000base-T status register */
  52 
  53         /* Vendor2 MMD registers */
  54         MV_V2_PORT_CTRL         = 0xf001,
  55         MV_V2_PORT_CTRL_PWRDOWN = 0x0800,
  56         MV_V2_TEMP_CTRL         = 0xf08a,
  57         MV_V2_TEMP_CTRL_MASK    = 0xc000,
  58         MV_V2_TEMP_CTRL_SAMPLE  = 0x0000,
  59         MV_V2_TEMP_CTRL_DISABLE = 0xc000,
  60         MV_V2_TEMP              = 0xf08c,
  61         MV_V2_TEMP_UNKNOWN      = 0x9600, /* unknown function */
  62 };
  63 
  64 struct mv3310_priv {
  65         struct device *hwmon_dev;
  66         char *hwmon_name;
  67 };
  68 
  69 #ifdef CONFIG_HWMON
  70 static umode_t mv3310_hwmon_is_visible(const void *data,
  71                                        enum hwmon_sensor_types type,
  72                                        u32 attr, int channel)
  73 {
  74         if (type == hwmon_chip && attr == hwmon_chip_update_interval)
  75                 return 0444;
  76         if (type == hwmon_temp && attr == hwmon_temp_input)
  77                 return 0444;
  78         return 0;
  79 }
  80 
  81 static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  82                              u32 attr, int channel, long *value)
  83 {
  84         struct phy_device *phydev = dev_get_drvdata(dev);
  85         int temp;
  86 
  87         if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
  88                 *value = MSEC_PER_SEC;
  89                 return 0;
  90         }
  91 
  92         if (type == hwmon_temp && attr == hwmon_temp_input) {
  93                 temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
  94                 if (temp < 0)
  95                         return temp;
  96 
  97                 *value = ((temp & 0xff) - 75) * 1000;
  98 
  99                 return 0;
 100         }
 101 
 102         return -EOPNOTSUPP;
 103 }
 104 
 105 static const struct hwmon_ops mv3310_hwmon_ops = {
 106         .is_visible = mv3310_hwmon_is_visible,
 107         .read = mv3310_hwmon_read,
 108 };
 109 
 110 static u32 mv3310_hwmon_chip_config[] = {
 111         HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
 112         0,
 113 };
 114 
 115 static const struct hwmon_channel_info mv3310_hwmon_chip = {
 116         .type = hwmon_chip,
 117         .config = mv3310_hwmon_chip_config,
 118 };
 119 
 120 static u32 mv3310_hwmon_temp_config[] = {
 121         HWMON_T_INPUT,
 122         0,
 123 };
 124 
 125 static const struct hwmon_channel_info mv3310_hwmon_temp = {
 126         .type = hwmon_temp,
 127         .config = mv3310_hwmon_temp_config,
 128 };
 129 
 130 static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
 131         &mv3310_hwmon_chip,
 132         &mv3310_hwmon_temp,
 133         NULL,
 134 };
 135 
 136 static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
 137         .ops = &mv3310_hwmon_ops,
 138         .info = mv3310_hwmon_info,
 139 };
 140 
 141 static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
 142 {
 143         u16 val;
 144         int ret;
 145 
 146         ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
 147                             MV_V2_TEMP_UNKNOWN);
 148         if (ret < 0)
 149                 return ret;
 150 
 151         val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
 152 
 153         return phy_modify_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
 154                               MV_V2_TEMP_CTRL_MASK, val);
 155 }
 156 
 157 static void mv3310_hwmon_disable(void *data)
 158 {
 159         struct phy_device *phydev = data;
 160 
 161         mv3310_hwmon_config(phydev, false);
 162 }
 163 
 164 static int mv3310_hwmon_probe(struct phy_device *phydev)
 165 {
 166         struct device *dev = &phydev->mdio.dev;
 167         struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
 168         int i, j, ret;
 169 
 170         priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
 171         if (!priv->hwmon_name)
 172                 return -ENODEV;
 173 
 174         for (i = j = 0; priv->hwmon_name[i]; i++) {
 175                 if (isalnum(priv->hwmon_name[i])) {
 176                         if (i != j)
 177                                 priv->hwmon_name[j] = priv->hwmon_name[i];
 178                         j++;
 179                 }
 180         }
 181         priv->hwmon_name[j] = '\0';
 182 
 183         ret = mv3310_hwmon_config(phydev, true);
 184         if (ret)
 185                 return ret;
 186 
 187         ret = devm_add_action_or_reset(dev, mv3310_hwmon_disable, phydev);
 188         if (ret)
 189                 return ret;
 190 
 191         priv->hwmon_dev = devm_hwmon_device_register_with_info(dev,
 192                                 priv->hwmon_name, phydev,
 193                                 &mv3310_hwmon_chip_info, NULL);
 194 
 195         return PTR_ERR_OR_ZERO(priv->hwmon_dev);
 196 }
 197 #else
 198 static inline int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
 199 {
 200         return 0;
 201 }
 202 
 203 static int mv3310_hwmon_probe(struct phy_device *phydev)
 204 {
 205         return 0;
 206 }
 207 #endif
 208 
 209 static int mv3310_probe(struct phy_device *phydev)
 210 {
 211         struct mv3310_priv *priv;
 212         u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
 213         int ret;
 214 
 215         if (!phydev->is_c45 ||
 216             (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
 217                 return -ENODEV;
 218 
 219         ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_BOOT);
 220         if (ret < 0)
 221                 return ret;
 222 
 223         if (ret & MV_PMA_BOOT_FATAL) {
 224                 dev_warn(&phydev->mdio.dev,
 225                          "PHY failed to boot firmware, status=%04x\n", ret);
 226                 return -ENODEV;
 227         }
 228 
 229         priv = devm_kzalloc(&phydev->mdio.dev, sizeof(*priv), GFP_KERNEL);
 230         if (!priv)
 231                 return -ENOMEM;
 232 
 233         dev_set_drvdata(&phydev->mdio.dev, priv);
 234 
 235         ret = mv3310_hwmon_probe(phydev);
 236         if (ret)
 237                 return ret;
 238 
 239         return 0;
 240 }
 241 
 242 static int mv3310_suspend(struct phy_device *phydev)
 243 {
 244         return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
 245                                 MV_V2_PORT_CTRL_PWRDOWN);
 246 }
 247 
 248 static int mv3310_resume(struct phy_device *phydev)
 249 {
 250         int ret;
 251 
 252         ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
 253                                  MV_V2_PORT_CTRL_PWRDOWN);
 254         if (ret)
 255                 return ret;
 256 
 257         return mv3310_hwmon_config(phydev, true);
 258 }
 259 
 260 /* Some PHYs in the Alaska family such as the 88X3310 and the 88E2010
 261  * don't set bit 14 in PMA Extended Abilities (1.11), although they do
 262  * support 2.5GBASET and 5GBASET. For these models, we can still read their
 263  * 2.5G/5G extended abilities register (1.21). We detect these models based on
 264  * the PMA device identifier, with a mask matching models known to have this
 265  * issue
 266  */
 267 static bool mv3310_has_pma_ngbaset_quirk(struct phy_device *phydev)
 268 {
 269         if (!(phydev->c45_ids.devices_in_package & MDIO_DEVS_PMAPMD))
 270                 return false;
 271 
 272         /* Only some revisions of the 88X3310 family PMA seem to be impacted */
 273         return (phydev->c45_ids.device_ids[MDIO_MMD_PMAPMD] &
 274                 MV_PHY_ALASKA_NBT_QUIRK_MASK) == MV_PHY_ALASKA_NBT_QUIRK_REV;
 275 }
 276 
 277 static int mv3310_config_init(struct phy_device *phydev)
 278 {
 279         /* Check that the PHY interface type is compatible */
 280         if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
 281             phydev->interface != PHY_INTERFACE_MODE_2500BASEX &&
 282             phydev->interface != PHY_INTERFACE_MODE_XAUI &&
 283             phydev->interface != PHY_INTERFACE_MODE_RXAUI &&
 284             phydev->interface != PHY_INTERFACE_MODE_10GKR)
 285                 return -ENODEV;
 286 
 287         return 0;
 288 }
 289 
 290 static int mv3310_get_features(struct phy_device *phydev)
 291 {
 292         int ret, val;
 293 
 294         ret = genphy_c45_pma_read_abilities(phydev);
 295         if (ret)
 296                 return ret;
 297 
 298         if (mv3310_has_pma_ngbaset_quirk(phydev)) {
 299                 val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
 300                                    MDIO_PMA_NG_EXTABLE);
 301                 if (val < 0)
 302                         return val;
 303 
 304                 linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
 305                                  phydev->supported,
 306                                  val & MDIO_PMA_NG_EXTABLE_2_5GBT);
 307 
 308                 linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
 309                                  phydev->supported,
 310                                  val & MDIO_PMA_NG_EXTABLE_5GBT);
 311         }
 312 
 313         return 0;
 314 }
 315 
 316 static int mv3310_config_aneg(struct phy_device *phydev)
 317 {
 318         bool changed = false;
 319         u16 reg;
 320         int ret;
 321 
 322         /* We don't support manual MDI control */
 323         phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
 324 
 325         if (phydev->autoneg == AUTONEG_DISABLE)
 326                 return genphy_c45_pma_setup_forced(phydev);
 327 
 328         ret = genphy_c45_an_config_aneg(phydev);
 329         if (ret < 0)
 330                 return ret;
 331         if (ret > 0)
 332                 changed = true;
 333 
 334         /* Clause 45 has no standardized support for 1000BaseT, therefore
 335          * use vendor registers for this mode.
 336          */
 337         reg = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
 338         ret = phy_modify_mmd_changed(phydev, MDIO_MMD_AN, MV_AN_CTRL1000,
 339                              ADVERTISE_1000FULL | ADVERTISE_1000HALF, reg);
 340         if (ret < 0)
 341                 return ret;
 342         if (ret > 0)
 343                 changed = true;
 344 
 345         return genphy_c45_check_and_restart_aneg(phydev, changed);
 346 }
 347 
 348 static int mv3310_aneg_done(struct phy_device *phydev)
 349 {
 350         int val;
 351 
 352         val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
 353         if (val < 0)
 354                 return val;
 355 
 356         if (val & MDIO_STAT1_LSTATUS)
 357                 return 1;
 358 
 359         return genphy_c45_aneg_done(phydev);
 360 }
 361 
 362 static void mv3310_update_interface(struct phy_device *phydev)
 363 {
 364         if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
 365              phydev->interface == PHY_INTERFACE_MODE_2500BASEX ||
 366              phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
 367                 /* The PHY automatically switches its serdes interface (and
 368                  * active PHYXS instance) between Cisco SGMII, 10GBase-KR and
 369                  * 2500BaseX modes according to the speed.  Florian suggests
 370                  * setting phydev->interface to communicate this to the MAC.
 371                  * Only do this if we are already in one of the above modes.
 372                  */
 373                 switch (phydev->speed) {
 374                 case SPEED_10000:
 375                         phydev->interface = PHY_INTERFACE_MODE_10GKR;
 376                         break;
 377                 case SPEED_2500:
 378                         phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
 379                         break;
 380                 case SPEED_1000:
 381                 case SPEED_100:
 382                 case SPEED_10:
 383                         phydev->interface = PHY_INTERFACE_MODE_SGMII;
 384                         break;
 385                 default:
 386                         break;
 387                 }
 388         }
 389 }
 390 
 391 /* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
 392 static int mv3310_read_10gbr_status(struct phy_device *phydev)
 393 {
 394         phydev->link = 1;
 395         phydev->speed = SPEED_10000;
 396         phydev->duplex = DUPLEX_FULL;
 397 
 398         mv3310_update_interface(phydev);
 399 
 400         return 0;
 401 }
 402 
 403 static int mv3310_read_status(struct phy_device *phydev)
 404 {
 405         int val;
 406 
 407         phydev->speed = SPEED_UNKNOWN;
 408         phydev->duplex = DUPLEX_UNKNOWN;
 409         linkmode_zero(phydev->lp_advertising);
 410         phydev->link = 0;
 411         phydev->pause = 0;
 412         phydev->asym_pause = 0;
 413         phydev->mdix = 0;
 414 
 415         val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
 416         if (val < 0)
 417                 return val;
 418 
 419         if (val & MDIO_STAT1_LSTATUS)
 420                 return mv3310_read_10gbr_status(phydev);
 421 
 422         val = genphy_c45_read_link(phydev);
 423         if (val < 0)
 424                 return val;
 425 
 426         val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 427         if (val < 0)
 428                 return val;
 429 
 430         if (val & MDIO_AN_STAT1_COMPLETE) {
 431                 val = genphy_c45_read_lpa(phydev);
 432                 if (val < 0)
 433                         return val;
 434 
 435                 /* Read the link partner's 1G advertisement */
 436                 val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000);
 437                 if (val < 0)
 438                         return val;
 439 
 440                 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
 441 
 442                 if (phydev->autoneg == AUTONEG_ENABLE)
 443                         phy_resolve_aneg_linkmode(phydev);
 444         }
 445 
 446         if (phydev->autoneg != AUTONEG_ENABLE) {
 447                 val = genphy_c45_read_pma(phydev);
 448                 if (val < 0)
 449                         return val;
 450         }
 451 
 452         if (phydev->speed == SPEED_10000) {
 453                 val = genphy_c45_read_mdix(phydev);
 454                 if (val < 0)
 455                         return val;
 456         } else {
 457                 val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PAIRSWAP);
 458                 if (val < 0)
 459                         return val;
 460 
 461                 switch (val & MV_PCS_PAIRSWAP_MASK) {
 462                 case MV_PCS_PAIRSWAP_AB:
 463                         phydev->mdix = ETH_TP_MDI_X;
 464                         break;
 465                 case MV_PCS_PAIRSWAP_NONE:
 466                         phydev->mdix = ETH_TP_MDI;
 467                         break;
 468                 default:
 469                         phydev->mdix = ETH_TP_MDI_INVALID;
 470                         break;
 471                 }
 472         }
 473 
 474         mv3310_update_interface(phydev);
 475 
 476         return 0;
 477 }
 478 
 479 static struct phy_driver mv3310_drivers[] = {
 480         {
 481                 .phy_id         = MARVELL_PHY_ID_88X3310,
 482                 .phy_id_mask    = MARVELL_PHY_ID_MASK,
 483                 .name           = "mv88x3310",
 484                 .get_features   = mv3310_get_features,
 485                 .soft_reset     = genphy_no_soft_reset,
 486                 .config_init    = mv3310_config_init,
 487                 .probe          = mv3310_probe,
 488                 .suspend        = mv3310_suspend,
 489                 .resume         = mv3310_resume,
 490                 .config_aneg    = mv3310_config_aneg,
 491                 .aneg_done      = mv3310_aneg_done,
 492                 .read_status    = mv3310_read_status,
 493         },
 494         {
 495                 .phy_id         = MARVELL_PHY_ID_88E2110,
 496                 .phy_id_mask    = MARVELL_PHY_ID_MASK,
 497                 .name           = "mv88x2110",
 498                 .probe          = mv3310_probe,
 499                 .suspend        = mv3310_suspend,
 500                 .resume         = mv3310_resume,
 501                 .soft_reset     = genphy_no_soft_reset,
 502                 .config_init    = mv3310_config_init,
 503                 .config_aneg    = mv3310_config_aneg,
 504                 .aneg_done      = mv3310_aneg_done,
 505                 .read_status    = mv3310_read_status,
 506         },
 507 };
 508 
 509 module_phy_driver(mv3310_drivers);
 510 
 511 static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
 512         { MARVELL_PHY_ID_88X3310, MARVELL_PHY_ID_MASK },
 513         { MARVELL_PHY_ID_88E2110, MARVELL_PHY_ID_MASK },
 514         { },
 515 };
 516 MODULE_DEVICE_TABLE(mdio, mv3310_tbl);
 517 MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)");
 518 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */