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