linux/drivers/net/phy/marvell10g.c
<<
>>
Prefs
   1/*
   2 * Marvell 10G 88x3310 PHY driver
   3 *
   4 * Based upon the ID registers, this PHY appears to be a mixture of IPs
   5 * from two different companies.
   6 *
   7 * There appears to be several different data paths through the PHY which
   8 * are automatically managed by the PHY.  The following has been determined
   9 * via observation and experimentation for a setup using single-lane Serdes:
  10 *
  11 *       SGMII PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for <= 1G)
  12 *  10GBASE-KR PHYXS -- BASE-T PCS -- 10G PMA -- AN -- Copper (for 10G)
  13 *  10GBASE-KR PHYXS -- BASE-R PCS -- Fiber
  14 *
  15 * With XAUI, observation shows:
  16 *
  17 *        XAUI PHYXS -- <appropriate PCS as above>
  18 *
  19 * and no switching of the host interface mode occurs.
  20 *
  21 * If both the fiber and copper ports are connected, the first to gain
  22 * link takes priority and the other port is completely locked out.
  23 */
  24#include <linux/ctype.h>
  25#include <linux/hwmon.h>
  26#include <linux/marvell_phy.h>
  27#include <linux/phy.h>
  28
  29enum {
  30        MV_PCS_BASE_T           = 0x0000,
  31        MV_PCS_BASE_R           = 0x1000,
  32        MV_PCS_1000BASEX        = 0x2000,
  33
  34        MV_PCS_PAIRSWAP         = 0x8182,
  35        MV_PCS_PAIRSWAP_MASK    = 0x0003,
  36        MV_PCS_PAIRSWAP_AB      = 0x0002,
  37        MV_PCS_PAIRSWAP_NONE    = 0x0003,
  38
  39        /* These registers appear at 0x800X and 0xa00X - the 0xa00X control
  40         * registers appear to set themselves to the 0x800X when AN is
  41         * restarted, but status registers appear readable from either.
  42         */
  43        MV_AN_CTRL1000          = 0x8000, /* 1000base-T control register */
  44        MV_AN_STAT1000          = 0x8001, /* 1000base-T status register */
  45
  46        /* Vendor2 MMD registers */
  47        MV_V2_TEMP_CTRL         = 0xf08a,
  48        MV_V2_TEMP_CTRL_MASK    = 0xc000,
  49        MV_V2_TEMP_CTRL_SAMPLE  = 0x0000,
  50        MV_V2_TEMP_CTRL_DISABLE = 0xc000,
  51        MV_V2_TEMP              = 0xf08c,
  52        MV_V2_TEMP_UNKNOWN      = 0x9600, /* unknown function */
  53};
  54
  55struct mv3310_priv {
  56        struct device *hwmon_dev;
  57        char *hwmon_name;
  58};
  59
  60static int mv3310_modify(struct phy_device *phydev, int devad, u16 reg,
  61                         u16 mask, u16 bits)
  62{
  63        int old, val, ret;
  64
  65        old = phy_read_mmd(phydev, devad, reg);
  66        if (old < 0)
  67                return old;
  68
  69        val = (old & ~mask) | (bits & mask);
  70        if (val == old)
  71                return 0;
  72
  73        ret = phy_write_mmd(phydev, devad, reg, val);
  74
  75        return ret < 0 ? ret : 1;
  76}
  77
  78#ifdef CONFIG_HWMON
  79static umode_t mv3310_hwmon_is_visible(const void *data,
  80                                       enum hwmon_sensor_types type,
  81                                       u32 attr, int channel)
  82{
  83        if (type == hwmon_chip && attr == hwmon_chip_update_interval)
  84                return 0444;
  85        if (type == hwmon_temp && attr == hwmon_temp_input)
  86                return 0444;
  87        return 0;
  88}
  89
  90static int mv3310_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
  91                             u32 attr, int channel, long *value)
  92{
  93        struct phy_device *phydev = dev_get_drvdata(dev);
  94        int temp;
  95
  96        if (type == hwmon_chip && attr == hwmon_chip_update_interval) {
  97                *value = MSEC_PER_SEC;
  98                return 0;
  99        }
 100
 101        if (type == hwmon_temp && attr == hwmon_temp_input) {
 102                temp = phy_read_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP);
 103                if (temp < 0)
 104                        return temp;
 105
 106                *value = ((temp & 0xff) - 75) * 1000;
 107
 108                return 0;
 109        }
 110
 111        return -EOPNOTSUPP;
 112}
 113
 114static const struct hwmon_ops mv3310_hwmon_ops = {
 115        .is_visible = mv3310_hwmon_is_visible,
 116        .read = mv3310_hwmon_read,
 117};
 118
 119static u32 mv3310_hwmon_chip_config[] = {
 120        HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL,
 121        0,
 122};
 123
 124static const struct hwmon_channel_info mv3310_hwmon_chip = {
 125        .type = hwmon_chip,
 126        .config = mv3310_hwmon_chip_config,
 127};
 128
 129static u32 mv3310_hwmon_temp_config[] = {
 130        HWMON_T_INPUT,
 131        0,
 132};
 133
 134static const struct hwmon_channel_info mv3310_hwmon_temp = {
 135        .type = hwmon_temp,
 136        .config = mv3310_hwmon_temp_config,
 137};
 138
 139static const struct hwmon_channel_info *mv3310_hwmon_info[] = {
 140        &mv3310_hwmon_chip,
 141        &mv3310_hwmon_temp,
 142        NULL,
 143};
 144
 145static const struct hwmon_chip_info mv3310_hwmon_chip_info = {
 146        .ops = &mv3310_hwmon_ops,
 147        .info = mv3310_hwmon_info,
 148};
 149
 150static int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
 151{
 152        u16 val;
 153        int ret;
 154
 155        ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_V2_TEMP,
 156                            MV_V2_TEMP_UNKNOWN);
 157        if (ret < 0)
 158                return ret;
 159
 160        val = enable ? MV_V2_TEMP_CTRL_SAMPLE : MV_V2_TEMP_CTRL_DISABLE;
 161        ret = mv3310_modify(phydev, MDIO_MMD_VEND2, MV_V2_TEMP_CTRL,
 162                            MV_V2_TEMP_CTRL_MASK, val);
 163
 164        return ret < 0 ? ret : 0;
 165}
 166
 167static void mv3310_hwmon_disable(void *data)
 168{
 169        struct phy_device *phydev = data;
 170
 171        mv3310_hwmon_config(phydev, false);
 172}
 173
 174static int mv3310_hwmon_probe(struct phy_device *phydev)
 175{
 176        struct device *dev = &phydev->mdio.dev;
 177        struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
 178        int i, j, ret;
 179
 180        priv->hwmon_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
 181        if (!priv->hwmon_name)
 182                return -ENODEV;
 183
 184        for (i = j = 0; priv->hwmon_name[i]; i++) {
 185                if (isalnum(priv->hwmon_name[i])) {
 186                        if (i != j)
 187                                priv->hwmon_name[j] = priv->hwmon_name[i];
 188                        j++;
 189                }
 190        }
 191        priv->hwmon_name[j] = '\0';
 192
 193        ret = mv3310_hwmon_config(phydev, true);
 194        if (ret)
 195                return ret;
 196
 197        ret = devm_add_action_or_reset(dev, mv3310_hwmon_disable, phydev);
 198        if (ret)
 199                return ret;
 200
 201        priv->hwmon_dev = devm_hwmon_device_register_with_info(dev,
 202                                priv->hwmon_name, phydev,
 203                                &mv3310_hwmon_chip_info, NULL);
 204
 205        return PTR_ERR_OR_ZERO(priv->hwmon_dev);
 206}
 207#else
 208static inline int mv3310_hwmon_config(struct phy_device *phydev, bool enable)
 209{
 210        return 0;
 211}
 212
 213static int mv3310_hwmon_probe(struct phy_device *phydev)
 214{
 215        return 0;
 216}
 217#endif
 218
 219static int mv3310_probe(struct phy_device *phydev)
 220{
 221        struct mv3310_priv *priv;
 222        u32 mmd_mask = MDIO_DEVS_PMAPMD | MDIO_DEVS_AN;
 223        int ret;
 224
 225        if (!phydev->is_c45 ||
 226            (phydev->c45_ids.devices_in_package & mmd_mask) != mmd_mask)
 227                return -ENODEV;
 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
 242static int mv3310_suspend(struct phy_device *phydev)
 243{
 244        return 0;
 245}
 246
 247static int mv3310_resume(struct phy_device *phydev)
 248{
 249        return mv3310_hwmon_config(phydev, true);
 250}
 251
 252static int mv3310_config_init(struct phy_device *phydev)
 253{
 254        __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
 255        u32 mask;
 256        int val;
 257
 258        /* Check that the PHY interface type is compatible */
 259        if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
 260            phydev->interface != PHY_INTERFACE_MODE_XAUI &&
 261            phydev->interface != PHY_INTERFACE_MODE_RXAUI &&
 262            phydev->interface != PHY_INTERFACE_MODE_10GKR)
 263                return -ENODEV;
 264
 265        __set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
 266        __set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
 267
 268        if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
 269                val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 270                if (val < 0)
 271                        return val;
 272
 273                if (val & MDIO_AN_STAT1_ABLE)
 274                        __set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
 275        }
 276
 277        val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
 278        if (val < 0)
 279                return val;
 280
 281        /* Ethtool does not support the WAN mode bits */
 282        if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR |
 283                   MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 |
 284                   MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW |
 285                   MDIO_PMA_STAT2_10GBEW))
 286                __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
 287        if (val & MDIO_PMA_STAT2_10GBSR)
 288                __set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
 289        if (val & MDIO_PMA_STAT2_10GBLR)
 290                __set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
 291        if (val & MDIO_PMA_STAT2_10GBER)
 292                __set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
 293
 294        if (val & MDIO_PMA_STAT2_EXTABLE) {
 295                val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
 296                if (val < 0)
 297                        return val;
 298
 299                if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT |
 300                           MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT))
 301                        __set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
 302                if (val & MDIO_PMA_EXTABLE_10GBLRM)
 303                        __set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
 304                if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR |
 305                           MDIO_PMA_EXTABLE_1000BKX))
 306                        __set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported);
 307                if (val & MDIO_PMA_EXTABLE_10GBLRM)
 308                        __set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
 309                                  supported);
 310                if (val & MDIO_PMA_EXTABLE_10GBT)
 311                        __set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
 312                                  supported);
 313                if (val & MDIO_PMA_EXTABLE_10GBKX4)
 314                        __set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
 315                                  supported);
 316                if (val & MDIO_PMA_EXTABLE_10GBKR)
 317                        __set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
 318                                  supported);
 319                if (val & MDIO_PMA_EXTABLE_1000BT)
 320                        __set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
 321                                  supported);
 322                if (val & MDIO_PMA_EXTABLE_1000BKX)
 323                        __set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
 324                                  supported);
 325                if (val & MDIO_PMA_EXTABLE_100BTX) {
 326                        __set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
 327                                  supported);
 328                        __set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
 329                                  supported);
 330                }
 331                if (val & MDIO_PMA_EXTABLE_10BT) {
 332                        __set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
 333                                  supported);
 334                        __set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
 335                                  supported);
 336                }
 337        }
 338
 339        if (!ethtool_convert_link_mode_to_legacy_u32(&mask, supported))
 340                dev_warn(&phydev->mdio.dev,
 341                         "PHY supports (%*pb) more modes than phylib supports, some modes not supported.\n",
 342                         __ETHTOOL_LINK_MODE_MASK_NBITS, supported);
 343
 344        phydev->supported &= mask;
 345        phydev->advertising &= phydev->supported;
 346
 347        return 0;
 348}
 349
 350static int mv3310_config_aneg(struct phy_device *phydev)
 351{
 352        bool changed = false;
 353        u32 advertising;
 354        int ret;
 355
 356        /* We don't support manual MDI control */
 357        phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
 358
 359        if (phydev->autoneg == AUTONEG_DISABLE) {
 360                ret = genphy_c45_pma_setup_forced(phydev);
 361                if (ret < 0)
 362                        return ret;
 363
 364                return genphy_c45_an_disable_aneg(phydev);
 365        }
 366
 367        phydev->advertising &= phydev->supported;
 368        advertising = phydev->advertising;
 369
 370        ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE,
 371                            ADVERTISE_ALL | ADVERTISE_100BASE4 |
 372                            ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
 373                            ethtool_adv_to_mii_adv_t(advertising));
 374        if (ret < 0)
 375                return ret;
 376        if (ret > 0)
 377                changed = true;
 378
 379        ret = mv3310_modify(phydev, MDIO_MMD_AN, MV_AN_CTRL1000,
 380                            ADVERTISE_1000FULL | ADVERTISE_1000HALF,
 381                            ethtool_adv_to_mii_ctrl1000_t(advertising));
 382        if (ret < 0)
 383                return ret;
 384        if (ret > 0)
 385                changed = true;
 386
 387        /* 10G control register */
 388        ret = mv3310_modify(phydev, MDIO_MMD_AN, MDIO_AN_10GBT_CTRL,
 389                            MDIO_AN_10GBT_CTRL_ADV10G,
 390                            advertising & ADVERTISED_10000baseT_Full ?
 391                                MDIO_AN_10GBT_CTRL_ADV10G : 0);
 392        if (ret < 0)
 393                return ret;
 394        if (ret > 0)
 395                changed = true;
 396
 397        if (changed)
 398                ret = genphy_c45_restart_aneg(phydev);
 399
 400        return ret;
 401}
 402
 403static int mv3310_aneg_done(struct phy_device *phydev)
 404{
 405        int val;
 406
 407        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
 408        if (val < 0)
 409                return val;
 410
 411        if (val & MDIO_STAT1_LSTATUS)
 412                return 1;
 413
 414        return genphy_c45_aneg_done(phydev);
 415}
 416
 417static void mv3310_update_interface(struct phy_device *phydev)
 418{
 419        if ((phydev->interface == PHY_INTERFACE_MODE_SGMII ||
 420             phydev->interface == PHY_INTERFACE_MODE_10GKR) && phydev->link) {
 421                /* The PHY automatically switches its serdes interface (and
 422                 * active PHYXS instance) between Cisco SGMII and 10GBase-KR
 423                 * modes according to the speed.  Florian suggests setting
 424                 * phydev->interface to communicate this to the MAC. Only do
 425                 * this if we are already in either SGMII or 10GBase-KR mode.
 426                 */
 427                if (phydev->speed == SPEED_10000)
 428                        phydev->interface = PHY_INTERFACE_MODE_10GKR;
 429                else if (phydev->speed >= SPEED_10 &&
 430                         phydev->speed < SPEED_10000)
 431                        phydev->interface = PHY_INTERFACE_MODE_SGMII;
 432        }
 433}
 434
 435/* 10GBASE-ER,LR,LRM,SR do not support autonegotiation. */
 436static int mv3310_read_10gbr_status(struct phy_device *phydev)
 437{
 438        phydev->link = 1;
 439        phydev->speed = SPEED_10000;
 440        phydev->duplex = DUPLEX_FULL;
 441
 442        mv3310_update_interface(phydev);
 443
 444        return 0;
 445}
 446
 447static int mv3310_read_status(struct phy_device *phydev)
 448{
 449        u32 mmd_mask = phydev->c45_ids.devices_in_package;
 450        int val;
 451
 452        /* The vendor devads do not report link status.  Avoid the PHYXS
 453         * instance as there are three, and its status depends on the MAC
 454         * being appropriately configured for the negotiated speed.
 455         */
 456        mmd_mask &= ~(BIT(MDIO_MMD_VEND1) | BIT(MDIO_MMD_VEND2) |
 457                      BIT(MDIO_MMD_PHYXS));
 458
 459        phydev->speed = SPEED_UNKNOWN;
 460        phydev->duplex = DUPLEX_UNKNOWN;
 461        phydev->lp_advertising = 0;
 462        phydev->link = 0;
 463        phydev->pause = 0;
 464        phydev->asym_pause = 0;
 465        phydev->mdix = 0;
 466
 467        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_BASE_R + MDIO_STAT1);
 468        if (val < 0)
 469                return val;
 470
 471        if (val & MDIO_STAT1_LSTATUS)
 472                return mv3310_read_10gbr_status(phydev);
 473
 474        val = genphy_c45_read_link(phydev, mmd_mask);
 475        if (val < 0)
 476                return val;
 477
 478        phydev->link = val > 0 ? 1 : 0;
 479
 480        val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 481        if (val < 0)
 482                return val;
 483
 484        if (val & MDIO_AN_STAT1_COMPLETE) {
 485                val = genphy_c45_read_lpa(phydev);
 486                if (val < 0)
 487                        return val;
 488
 489                /* Read the link partner's 1G advertisement */
 490                val = phy_read_mmd(phydev, MDIO_MMD_AN, MV_AN_STAT1000);
 491                if (val < 0)
 492                        return val;
 493
 494                phydev->lp_advertising |= mii_stat1000_to_ethtool_lpa_t(val);
 495
 496                if (phydev->autoneg == AUTONEG_ENABLE)
 497                        phy_resolve_aneg_linkmode(phydev);
 498        }
 499
 500        if (phydev->autoneg != AUTONEG_ENABLE) {
 501                val = genphy_c45_read_pma(phydev);
 502                if (val < 0)
 503                        return val;
 504        }
 505
 506        if (phydev->speed == SPEED_10000) {
 507                val = genphy_c45_read_mdix(phydev);
 508                if (val < 0)
 509                        return val;
 510        } else {
 511                val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_PAIRSWAP);
 512                if (val < 0)
 513                        return val;
 514
 515                switch (val & MV_PCS_PAIRSWAP_MASK) {
 516                case MV_PCS_PAIRSWAP_AB:
 517                        phydev->mdix = ETH_TP_MDI_X;
 518                        break;
 519                case MV_PCS_PAIRSWAP_NONE:
 520                        phydev->mdix = ETH_TP_MDI;
 521                        break;
 522                default:
 523                        phydev->mdix = ETH_TP_MDI_INVALID;
 524                        break;
 525                }
 526        }
 527
 528        mv3310_update_interface(phydev);
 529
 530        return 0;
 531}
 532
 533static struct phy_driver mv3310_drivers[] = {
 534        {
 535                .phy_id         = 0x002b09aa,
 536                .phy_id_mask    = MARVELL_PHY_ID_MASK,
 537                .name           = "mv88x3310",
 538                .features       = SUPPORTED_10baseT_Full |
 539                                  SUPPORTED_10baseT_Half |
 540                                  SUPPORTED_100baseT_Full |
 541                                  SUPPORTED_100baseT_Half |
 542                                  SUPPORTED_1000baseT_Full |
 543                                  SUPPORTED_Autoneg |
 544                                  SUPPORTED_TP |
 545                                  SUPPORTED_FIBRE |
 546                                  SUPPORTED_10000baseT_Full |
 547                                  SUPPORTED_Backplane,
 548                .soft_reset     = gen10g_no_soft_reset,
 549                .config_init    = mv3310_config_init,
 550                .probe          = mv3310_probe,
 551                .suspend        = mv3310_suspend,
 552                .resume         = mv3310_resume,
 553                .config_aneg    = mv3310_config_aneg,
 554                .aneg_done      = mv3310_aneg_done,
 555                .read_status    = mv3310_read_status,
 556        },
 557};
 558
 559module_phy_driver(mv3310_drivers);
 560
 561static struct mdio_device_id __maybe_unused mv3310_tbl[] = {
 562        { 0x002b09aa, MARVELL_PHY_ID_MASK },
 563        { },
 564};
 565MODULE_DEVICE_TABLE(mdio, mv3310_tbl);
 566MODULE_DESCRIPTION("Marvell Alaska X 10Gigabit Ethernet PHY driver (MV88X3310)");
 567MODULE_LICENSE("GPL");
 568