linux/drivers/net/ethernet/ibm/emac/phy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * drivers/net/ethernet/ibm/emac/phy.c
   4 *
   5 * Driver for PowerPC 4xx on-chip ethernet controller, PHY support.
   6 * Borrowed from sungem_phy.c, though I only kept the generic MII
   7 * driver for now.
   8 *
   9 * This file should be shared with other drivers or eventually
  10 * merged as the "low level" part of miilib
  11 *
  12 * Copyright 2007 Benjamin Herrenschmidt, IBM Corp.
  13 *                <benh@kernel.crashing.org>
  14 *
  15 * Based on the arch/ppc version of the driver:
  16 *
  17 * (c) 2003, Benjamin Herrenscmidt (benh@kernel.crashing.org)
  18 * (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
  19 *
  20 */
  21#include <linux/module.h>
  22#include <linux/kernel.h>
  23#include <linux/types.h>
  24#include <linux/netdevice.h>
  25#include <linux/mii.h>
  26#include <linux/ethtool.h>
  27#include <linux/delay.h>
  28
  29#include "emac.h"
  30#include "phy.h"
  31
  32#define phy_read _phy_read
  33#define phy_write _phy_write
  34
  35static inline int _phy_read(struct mii_phy *phy, int reg)
  36{
  37        return phy->mdio_read(phy->dev, phy->address, reg);
  38}
  39
  40static inline void _phy_write(struct mii_phy *phy, int reg, int val)
  41{
  42        phy->mdio_write(phy->dev, phy->address, reg, val);
  43}
  44
  45static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
  46{
  47        return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
  48}
  49
  50static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
  51{
  52        phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
  53}
  54
  55int emac_mii_reset_phy(struct mii_phy *phy)
  56{
  57        int val;
  58        int limit = 10000;
  59
  60        val = phy_read(phy, MII_BMCR);
  61        val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
  62        val |= BMCR_RESET;
  63        phy_write(phy, MII_BMCR, val);
  64
  65        udelay(300);
  66
  67        while (--limit) {
  68                val = phy_read(phy, MII_BMCR);
  69                if (val >= 0 && (val & BMCR_RESET) == 0)
  70                        break;
  71                udelay(10);
  72        }
  73        if ((val & BMCR_ISOLATE) && limit > 0)
  74                phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
  75
  76        return limit <= 0;
  77}
  78
  79int emac_mii_reset_gpcs(struct mii_phy *phy)
  80{
  81        int val;
  82        int limit = 10000;
  83
  84        val = gpcs_phy_read(phy, MII_BMCR);
  85        val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
  86        val |= BMCR_RESET;
  87        gpcs_phy_write(phy, MII_BMCR, val);
  88
  89        udelay(300);
  90
  91        while (--limit) {
  92                val = gpcs_phy_read(phy, MII_BMCR);
  93                if (val >= 0 && (val & BMCR_RESET) == 0)
  94                        break;
  95                udelay(10);
  96        }
  97        if ((val & BMCR_ISOLATE) && limit > 0)
  98                gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
  99
 100        if (limit > 0 && phy->mode == PHY_INTERFACE_MODE_SGMII) {
 101                /* Configure GPCS interface to recommended setting for SGMII */
 102                gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
 103                gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
 104                gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX     */
 105        }
 106
 107        return limit <= 0;
 108}
 109
 110static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
 111{
 112        int ctl, adv;
 113
 114        phy->autoneg = AUTONEG_ENABLE;
 115        phy->speed = SPEED_10;
 116        phy->duplex = DUPLEX_HALF;
 117        phy->pause = phy->asym_pause = 0;
 118        phy->advertising = advertise;
 119
 120        ctl = phy_read(phy, MII_BMCR);
 121        if (ctl < 0)
 122                return ctl;
 123        ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
 124
 125        /* First clear the PHY */
 126        phy_write(phy, MII_BMCR, ctl);
 127
 128        /* Setup standard advertise */
 129        adv = phy_read(phy, MII_ADVERTISE);
 130        if (adv < 0)
 131                return adv;
 132        adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
 133                 ADVERTISE_PAUSE_ASYM);
 134        if (advertise & ADVERTISED_10baseT_Half)
 135                adv |= ADVERTISE_10HALF;
 136        if (advertise & ADVERTISED_10baseT_Full)
 137                adv |= ADVERTISE_10FULL;
 138        if (advertise & ADVERTISED_100baseT_Half)
 139                adv |= ADVERTISE_100HALF;
 140        if (advertise & ADVERTISED_100baseT_Full)
 141                adv |= ADVERTISE_100FULL;
 142        if (advertise & ADVERTISED_Pause)
 143                adv |= ADVERTISE_PAUSE_CAP;
 144        if (advertise & ADVERTISED_Asym_Pause)
 145                adv |= ADVERTISE_PAUSE_ASYM;
 146        phy_write(phy, MII_ADVERTISE, adv);
 147
 148        if (phy->features &
 149            (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
 150                adv = phy_read(phy, MII_CTRL1000);
 151                if (adv < 0)
 152                        return adv;
 153                adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
 154                if (advertise & ADVERTISED_1000baseT_Full)
 155                        adv |= ADVERTISE_1000FULL;
 156                if (advertise & ADVERTISED_1000baseT_Half)
 157                        adv |= ADVERTISE_1000HALF;
 158                phy_write(phy, MII_CTRL1000, adv);
 159        }
 160
 161        /* Start/Restart aneg */
 162        ctl = phy_read(phy, MII_BMCR);
 163        ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
 164        phy_write(phy, MII_BMCR, ctl);
 165
 166        return 0;
 167}
 168
 169static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
 170{
 171        int ctl;
 172
 173        phy->autoneg = AUTONEG_DISABLE;
 174        phy->speed = speed;
 175        phy->duplex = fd;
 176        phy->pause = phy->asym_pause = 0;
 177
 178        ctl = phy_read(phy, MII_BMCR);
 179        if (ctl < 0)
 180                return ctl;
 181        ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
 182
 183        /* First clear the PHY */
 184        phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
 185
 186        /* Select speed & duplex */
 187        switch (speed) {
 188        case SPEED_10:
 189                break;
 190        case SPEED_100:
 191                ctl |= BMCR_SPEED100;
 192                break;
 193        case SPEED_1000:
 194                ctl |= BMCR_SPEED1000;
 195                break;
 196        default:
 197                return -EINVAL;
 198        }
 199        if (fd == DUPLEX_FULL)
 200                ctl |= BMCR_FULLDPLX;
 201        phy_write(phy, MII_BMCR, ctl);
 202
 203        return 0;
 204}
 205
 206static int genmii_poll_link(struct mii_phy *phy)
 207{
 208        int status;
 209
 210        /* Clear latched value with dummy read */
 211        phy_read(phy, MII_BMSR);
 212        status = phy_read(phy, MII_BMSR);
 213        if (status < 0 || (status & BMSR_LSTATUS) == 0)
 214                return 0;
 215        if (phy->autoneg == AUTONEG_ENABLE && !(status & BMSR_ANEGCOMPLETE))
 216                return 0;
 217        return 1;
 218}
 219
 220static int genmii_read_link(struct mii_phy *phy)
 221{
 222        if (phy->autoneg == AUTONEG_ENABLE) {
 223                int glpa = 0;
 224                int lpa = phy_read(phy, MII_LPA) & phy_read(phy, MII_ADVERTISE);
 225                if (lpa < 0)
 226                        return lpa;
 227
 228                if (phy->features &
 229                    (SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half)) {
 230                        int adv = phy_read(phy, MII_CTRL1000);
 231                        glpa = phy_read(phy, MII_STAT1000);
 232
 233                        if (glpa < 0 || adv < 0)
 234                                return adv;
 235
 236                        glpa &= adv << 2;
 237                }
 238
 239                phy->speed = SPEED_10;
 240                phy->duplex = DUPLEX_HALF;
 241                phy->pause = phy->asym_pause = 0;
 242
 243                if (glpa & (LPA_1000FULL | LPA_1000HALF)) {
 244                        phy->speed = SPEED_1000;
 245                        if (glpa & LPA_1000FULL)
 246                                phy->duplex = DUPLEX_FULL;
 247                } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
 248                        phy->speed = SPEED_100;
 249                        if (lpa & LPA_100FULL)
 250                                phy->duplex = DUPLEX_FULL;
 251                } else if (lpa & LPA_10FULL)
 252                        phy->duplex = DUPLEX_FULL;
 253
 254                if (phy->duplex == DUPLEX_FULL) {
 255                        phy->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
 256                        phy->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
 257                }
 258        } else {
 259                int bmcr = phy_read(phy, MII_BMCR);
 260                if (bmcr < 0)
 261                        return bmcr;
 262
 263                if (bmcr & BMCR_FULLDPLX)
 264                        phy->duplex = DUPLEX_FULL;
 265                else
 266                        phy->duplex = DUPLEX_HALF;
 267                if (bmcr & BMCR_SPEED1000)
 268                        phy->speed = SPEED_1000;
 269                else if (bmcr & BMCR_SPEED100)
 270                        phy->speed = SPEED_100;
 271                else
 272                        phy->speed = SPEED_10;
 273
 274                phy->pause = phy->asym_pause = 0;
 275        }
 276        return 0;
 277}
 278
 279/* Generic implementation for most 10/100/1000 PHYs */
 280static const struct mii_phy_ops generic_phy_ops = {
 281        .setup_aneg     = genmii_setup_aneg,
 282        .setup_forced   = genmii_setup_forced,
 283        .poll_link      = genmii_poll_link,
 284        .read_link      = genmii_read_link
 285};
 286
 287static struct mii_phy_def genmii_phy_def = {
 288        .phy_id         = 0x00000000,
 289        .phy_id_mask    = 0x00000000,
 290        .name           = "Generic MII",
 291        .ops            = &generic_phy_ops
 292};
 293
 294/* CIS8201 */
 295#define MII_CIS8201_10BTCSR     0x16
 296#define  TENBTCSR_ECHO_DISABLE  0x2000
 297#define MII_CIS8201_EPCR        0x17
 298#define  EPCR_MODE_MASK         0x3000
 299#define  EPCR_GMII_MODE         0x0000
 300#define  EPCR_RGMII_MODE        0x1000
 301#define  EPCR_TBI_MODE          0x2000
 302#define  EPCR_RTBI_MODE         0x3000
 303#define MII_CIS8201_ACSR        0x1c
 304#define  ACSR_PIN_PRIO_SELECT   0x0004
 305
 306static int cis8201_init(struct mii_phy *phy)
 307{
 308        int epcr;
 309
 310        epcr = phy_read(phy, MII_CIS8201_EPCR);
 311        if (epcr < 0)
 312                return epcr;
 313
 314        epcr &= ~EPCR_MODE_MASK;
 315
 316        switch (phy->mode) {
 317        case PHY_INTERFACE_MODE_TBI:
 318                epcr |= EPCR_TBI_MODE;
 319                break;
 320        case PHY_INTERFACE_MODE_RTBI:
 321                epcr |= EPCR_RTBI_MODE;
 322                break;
 323        case PHY_INTERFACE_MODE_GMII:
 324                epcr |= EPCR_GMII_MODE;
 325                break;
 326        case PHY_INTERFACE_MODE_RGMII:
 327        default:
 328                epcr |= EPCR_RGMII_MODE;
 329        }
 330
 331        phy_write(phy, MII_CIS8201_EPCR, epcr);
 332
 333        /* MII regs override strap pins */
 334        phy_write(phy, MII_CIS8201_ACSR,
 335                  phy_read(phy, MII_CIS8201_ACSR) | ACSR_PIN_PRIO_SELECT);
 336
 337        /* Disable TX_EN -> CRS echo mode, otherwise 10/HDX doesn't work */
 338        phy_write(phy, MII_CIS8201_10BTCSR,
 339                  phy_read(phy, MII_CIS8201_10BTCSR) | TENBTCSR_ECHO_DISABLE);
 340
 341        return 0;
 342}
 343
 344static const struct mii_phy_ops cis8201_phy_ops = {
 345        .init           = cis8201_init,
 346        .setup_aneg     = genmii_setup_aneg,
 347        .setup_forced   = genmii_setup_forced,
 348        .poll_link      = genmii_poll_link,
 349        .read_link      = genmii_read_link
 350};
 351
 352static struct mii_phy_def cis8201_phy_def = {
 353        .phy_id         = 0x000fc410,
 354        .phy_id_mask    = 0x000ffff0,
 355        .name           = "CIS8201 Gigabit Ethernet",
 356        .ops            = &cis8201_phy_ops
 357};
 358
 359static struct mii_phy_def bcm5248_phy_def = {
 360
 361        .phy_id         = 0x0143bc00,
 362        .phy_id_mask    = 0x0ffffff0,
 363        .name           = "BCM5248 10/100 SMII Ethernet",
 364        .ops            = &generic_phy_ops
 365};
 366
 367static int m88e1111_init(struct mii_phy *phy)
 368{
 369        pr_debug("%s: Marvell 88E1111 Ethernet\n", __func__);
 370        phy_write(phy, 0x14, 0x0ce3);
 371        phy_write(phy, 0x18, 0x4101);
 372        phy_write(phy, 0x09, 0x0e00);
 373        phy_write(phy, 0x04, 0x01e1);
 374        phy_write(phy, 0x00, 0x9140);
 375        phy_write(phy, 0x00, 0x1140);
 376
 377        return  0;
 378}
 379
 380static int m88e1112_init(struct mii_phy *phy)
 381{
 382        /*
 383         * Marvell 88E1112 PHY needs to have the SGMII MAC
 384         * interace (page 2) properly configured to
 385         * communicate with the 460EX/GT GPCS interface.
 386         */
 387
 388        u16 reg_short;
 389
 390        pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
 391
 392        /* Set access to Page 2 */
 393        phy_write(phy, 0x16, 0x0002);
 394
 395        phy_write(phy, 0x00, 0x0040); /* 1Gbps */
 396        reg_short = (u16)(phy_read(phy, 0x1a));
 397        reg_short |= 0x8000; /* bypass Auto-Negotiation */
 398        phy_write(phy, 0x1a, reg_short);
 399        emac_mii_reset_phy(phy); /* reset MAC interface */
 400
 401        /* Reset access to Page 0 */
 402        phy_write(phy, 0x16, 0x0000);
 403
 404        return  0;
 405}
 406
 407static int et1011c_init(struct mii_phy *phy)
 408{
 409        u16 reg_short;
 410
 411        reg_short = (u16)(phy_read(phy, 0x16));
 412        reg_short &= ~(0x7);
 413        reg_short |= 0x6;       /* RGMII Trace Delay*/
 414        phy_write(phy, 0x16, reg_short);
 415
 416        reg_short = (u16)(phy_read(phy, 0x17));
 417        reg_short &= ~(0x40);
 418        phy_write(phy, 0x17, reg_short);
 419
 420        phy_write(phy, 0x1c, 0x74f0);
 421        return 0;
 422}
 423
 424static const struct mii_phy_ops et1011c_phy_ops = {
 425        .init           = et1011c_init,
 426        .setup_aneg     = genmii_setup_aneg,
 427        .setup_forced   = genmii_setup_forced,
 428        .poll_link      = genmii_poll_link,
 429        .read_link      = genmii_read_link
 430};
 431
 432static struct mii_phy_def et1011c_phy_def = {
 433        .phy_id         = 0x0282f000,
 434        .phy_id_mask    = 0x0fffff00,
 435        .name           = "ET1011C Gigabit Ethernet",
 436        .ops            = &et1011c_phy_ops
 437};
 438
 439
 440
 441
 442
 443static const struct mii_phy_ops m88e1111_phy_ops = {
 444        .init           = m88e1111_init,
 445        .setup_aneg     = genmii_setup_aneg,
 446        .setup_forced   = genmii_setup_forced,
 447        .poll_link      = genmii_poll_link,
 448        .read_link      = genmii_read_link
 449};
 450
 451static struct mii_phy_def m88e1111_phy_def = {
 452
 453        .phy_id         = 0x01410CC0,
 454        .phy_id_mask    = 0x0ffffff0,
 455        .name           = "Marvell 88E1111 Ethernet",
 456        .ops            = &m88e1111_phy_ops,
 457};
 458
 459static const struct mii_phy_ops m88e1112_phy_ops = {
 460        .init           = m88e1112_init,
 461        .setup_aneg     = genmii_setup_aneg,
 462        .setup_forced   = genmii_setup_forced,
 463        .poll_link      = genmii_poll_link,
 464        .read_link      = genmii_read_link
 465};
 466
 467static struct mii_phy_def m88e1112_phy_def = {
 468        .phy_id         = 0x01410C90,
 469        .phy_id_mask    = 0x0ffffff0,
 470        .name           = "Marvell 88E1112 Ethernet",
 471        .ops            = &m88e1112_phy_ops,
 472};
 473
 474static int ar8035_init(struct mii_phy *phy)
 475{
 476        phy_write(phy, 0x1d, 0x5); /* Address debug register 5 */
 477        phy_write(phy, 0x1e, 0x2d47); /* Value copied from u-boot */
 478        phy_write(phy, 0x1d, 0xb);    /* Address hib ctrl */
 479        phy_write(phy, 0x1e, 0xbc20); /* Value copied from u-boot */
 480
 481        return 0;
 482}
 483
 484static const struct mii_phy_ops ar8035_phy_ops = {
 485        .init           = ar8035_init,
 486        .setup_aneg     = genmii_setup_aneg,
 487        .setup_forced   = genmii_setup_forced,
 488        .poll_link      = genmii_poll_link,
 489        .read_link      = genmii_read_link,
 490};
 491
 492static struct mii_phy_def ar8035_phy_def = {
 493        .phy_id         = 0x004dd070,
 494        .phy_id_mask    = 0xfffffff0,
 495        .name           = "Atheros 8035 Gigabit Ethernet",
 496        .ops            = &ar8035_phy_ops,
 497};
 498
 499static struct mii_phy_def *mii_phy_table[] = {
 500        &et1011c_phy_def,
 501        &cis8201_phy_def,
 502        &bcm5248_phy_def,
 503        &m88e1111_phy_def,
 504        &m88e1112_phy_def,
 505        &ar8035_phy_def,
 506        &genmii_phy_def,
 507        NULL
 508};
 509
 510int emac_mii_phy_probe(struct mii_phy *phy, int address)
 511{
 512        struct mii_phy_def *def;
 513        int i;
 514        u32 id;
 515
 516        phy->autoneg = AUTONEG_DISABLE;
 517        phy->advertising = 0;
 518        phy->address = address;
 519        phy->speed = SPEED_10;
 520        phy->duplex = DUPLEX_HALF;
 521        phy->pause = phy->asym_pause = 0;
 522
 523        /* Take PHY out of isolate mode and reset it. */
 524        if (emac_mii_reset_phy(phy))
 525                return -ENODEV;
 526
 527        /* Read ID and find matching entry */
 528        id = (phy_read(phy, MII_PHYSID1) << 16) | phy_read(phy, MII_PHYSID2);
 529        for (i = 0; (def = mii_phy_table[i]) != NULL; i++)
 530                if ((id & def->phy_id_mask) == def->phy_id)
 531                        break;
 532        /* Should never be NULL (we have a generic entry), but... */
 533        if (!def)
 534                return -ENODEV;
 535
 536        phy->def = def;
 537
 538        /* Determine PHY features if needed */
 539        phy->features = def->features;
 540        if (!phy->features) {
 541                u16 bmsr = phy_read(phy, MII_BMSR);
 542                if (bmsr & BMSR_ANEGCAPABLE)
 543                        phy->features |= SUPPORTED_Autoneg;
 544                if (bmsr & BMSR_10HALF)
 545                        phy->features |= SUPPORTED_10baseT_Half;
 546                if (bmsr & BMSR_10FULL)
 547                        phy->features |= SUPPORTED_10baseT_Full;
 548                if (bmsr & BMSR_100HALF)
 549                        phy->features |= SUPPORTED_100baseT_Half;
 550                if (bmsr & BMSR_100FULL)
 551                        phy->features |= SUPPORTED_100baseT_Full;
 552                if (bmsr & BMSR_ESTATEN) {
 553                        u16 esr = phy_read(phy, MII_ESTATUS);
 554                        if (esr & ESTATUS_1000_TFULL)
 555                                phy->features |= SUPPORTED_1000baseT_Full;
 556                        if (esr & ESTATUS_1000_THALF)
 557                                phy->features |= SUPPORTED_1000baseT_Half;
 558                }
 559                phy->features |= SUPPORTED_MII;
 560        }
 561
 562        /* Setup default advertising */
 563        phy->advertising = phy->features;
 564
 565        return 0;
 566}
 567
 568MODULE_LICENSE("GPL");
 569