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