uboot/arch/powerpc/cpu/ppc4xx/miiphy.c
<<
>>
Prefs
   1/*
   2 * SPDX-License-Identifier:     GPL-2.0 IBM-pibs
   3 */
   4/*-----------------------------------------------------------------------------+
   5  |
   6  |  File Name:  miiphy.c
   7  |
   8  |  Function:   This module has utilities for accessing the MII PHY through
   9  |            the EMAC3 macro.
  10  |
  11  |  Author:     Mark Wisner
  12  |
  13  +-----------------------------------------------------------------------------*/
  14
  15/* define DEBUG for debugging output (obviously ;-)) */
  16#if 0
  17#define DEBUG
  18#endif
  19
  20#include <common.h>
  21#include <asm/processor.h>
  22#include <asm/io.h>
  23#include <ppc_asm.tmpl>
  24#include <commproc.h>
  25#include <asm/ppc4xx-emac.h>
  26#include <asm/ppc4xx-mal.h>
  27#include <miiphy.h>
  28
  29#if !defined(CONFIG_PHY_CLK_FREQ)
  30#define CONFIG_PHY_CLK_FREQ     0
  31#endif
  32
  33/***********************************************************/
  34/* Dump out to the screen PHY regs                         */
  35/***********************************************************/
  36
  37void miiphy_dump (char *devname, unsigned char addr)
  38{
  39        unsigned long i;
  40        unsigned short data;
  41
  42        for (i = 0; i < 0x1A; i++) {
  43                if (miiphy_read (devname, addr, i, &data)) {
  44                        printf ("read error for reg %lx\n", i);
  45                        return;
  46                }
  47                printf ("Phy reg %lx ==> %4x\n", i, data);
  48
  49                /* jump to the next set of regs */
  50                if (i == 0x07)
  51                        i = 0x0f;
  52
  53        }                       /* end for loop */
  54}                               /* end dump */
  55
  56/***********************************************************/
  57/* (Re)start autonegotiation                               */
  58/***********************************************************/
  59int phy_setup_aneg (char *devname, unsigned char addr)
  60{
  61        u16 bmcr;
  62
  63#if defined(CONFIG_PHY_DYNAMIC_ANEG)
  64        /*
  65         * Set up advertisement based on capablilities reported by the PHY.
  66         * This should work for both copper and fiber.
  67         */
  68        u16 bmsr;
  69#if defined(CONFIG_PHY_GIGE)
  70        u16 exsr = 0x0000;
  71#endif
  72
  73        miiphy_read (devname, addr, MII_BMSR, &bmsr);
  74
  75#if defined(CONFIG_PHY_GIGE)
  76        if (bmsr & BMSR_ESTATEN)
  77                miiphy_read (devname, addr, MII_ESTATUS, &exsr);
  78
  79        if (exsr & (ESTATUS_1000XF | ESTATUS_1000XH)) {
  80                /* 1000BASE-X */
  81                u16 anar = 0x0000;
  82
  83                if (exsr & ESTATUS_1000XF)
  84                        anar |= ADVERTISE_1000XFULL;
  85
  86                if (exsr & ESTATUS_1000XH)
  87                        anar |= ADVERTISE_1000XHALF;
  88
  89                miiphy_write (devname, addr, MII_ADVERTISE, anar);
  90        } else
  91#endif
  92        {
  93                u16 anar, btcr;
  94
  95                miiphy_read (devname, addr, MII_ADVERTISE, &anar);
  96                anar &= ~(0x5000 | LPA_100BASE4 | LPA_100FULL |
  97                          LPA_100HALF | LPA_10FULL | LPA_10HALF);
  98
  99                miiphy_read (devname, addr, MII_CTRL1000, &btcr);
 100                btcr &= ~(0x00FF | PHY_1000BTCR_1000FD | PHY_1000BTCR_1000HD);
 101
 102                if (bmsr & BMSR_100BASE4)
 103                        anar |= LPA_100BASE4;
 104
 105                if (bmsr & BMSR_100FULL)
 106                        anar |= LPA_100FULL;
 107
 108                if (bmsr & BMSR_100HALF)
 109                        anar |= LPA_100HALF;
 110
 111                if (bmsr & BMSR_10FULL)
 112                        anar |= LPA_10FULL;
 113
 114                if (bmsr & BMSR_10HALF)
 115                        anar |= LPA_10HALF;
 116
 117                miiphy_write (devname, addr, MII_ADVERTISE, anar);
 118
 119#if defined(CONFIG_PHY_GIGE)
 120                if (exsr & ESTATUS_1000_TFULL)
 121                        btcr |= PHY_1000BTCR_1000FD;
 122
 123                if (exsr & ESTATUS_1000_THALF)
 124                        btcr |= PHY_1000BTCR_1000HD;
 125
 126                miiphy_write (devname, addr, MII_CTRL1000, btcr);
 127#endif
 128        }
 129
 130#else /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
 131        /*
 132         * Set up standard advertisement
 133         */
 134        u16 adv;
 135
 136        miiphy_read (devname, addr, MII_ADVERTISE, &adv);
 137        adv |= (LPA_LPACK  | LPA_100FULL | LPA_100HALF |
 138                LPA_10FULL | LPA_10HALF);
 139        miiphy_write (devname, addr, MII_ADVERTISE, adv);
 140
 141        miiphy_read (devname, addr, MII_CTRL1000, &adv);
 142        adv |= (0x0300);
 143        miiphy_write (devname, addr, MII_CTRL1000, adv);
 144
 145#endif /* defined(CONFIG_PHY_DYNAMIC_ANEG) */
 146
 147        /* Start/Restart aneg */
 148        miiphy_read (devname, addr, MII_BMCR, &bmcr);
 149        bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
 150        miiphy_write (devname, addr, MII_BMCR, bmcr);
 151
 152        return 0;
 153}
 154
 155/***********************************************************/
 156/* read a phy reg and return the value with a rc           */
 157/***********************************************************/
 158/* AMCC_TODO:
 159 * Find out of the choice for the emac for MDIO is from the bridges,
 160 * i.e. ZMII or RGMII as approporiate.  If the bridges are not used
 161 * to determine the emac for MDIO, then is the SDR0_ETH_CFG[MDIO_SEL]
 162 * used?  If so, then this routine below does not apply to the 460EX/GT.
 163 *
 164 * sr: Currently on 460EX only EMAC0 works with MDIO, so we always
 165 * return EMAC0 offset here
 166 * vg: For 460EX/460GT if internal GPCS PHY address is specified
 167 * return appropriate EMAC offset
 168 */
 169unsigned int miiphy_getemac_offset(u8 addr)
 170{
 171#if defined(CONFIG_440) && \
 172    !defined(CONFIG_440SP) && !defined(CONFIG_440SPE) && \
 173    !defined(CONFIG_460EX) && !defined(CONFIG_460GT)
 174        unsigned long zmii;
 175        unsigned long eoffset;
 176
 177        /* Need to find out which mdi port we're using */
 178        zmii = in_be32((void *)ZMII0_FER);
 179
 180        if (zmii & (ZMII_FER_MDI << ZMII_FER_V (0)))
 181                /* using port 0 */
 182                eoffset = 0;
 183
 184        else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (1)))
 185                /* using port 1 */
 186                eoffset = 0x100;
 187
 188        else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (2)))
 189                /* using port 2 */
 190                eoffset = 0x400;
 191
 192        else if (zmii & (ZMII_FER_MDI << ZMII_FER_V (3)))
 193                /* using port 3 */
 194                eoffset = 0x600;
 195
 196        else {
 197                /* None of the mdi ports are enabled! */
 198                /* enable port 0 */
 199                zmii |= ZMII_FER_MDI << ZMII_FER_V (0);
 200                out_be32((void *)ZMII0_FER, zmii);
 201                eoffset = 0;
 202                /* need to soft reset port 0 */
 203                zmii = in_be32((void *)EMAC0_MR0);
 204                zmii |= EMAC_MR0_SRST;
 205                out_be32((void *)EMAC0_MR0, zmii);
 206        }
 207
 208        return (eoffset);
 209#else
 210
 211#if defined(CONFIG_405EX)
 212        unsigned long rgmii;
 213        int devnum = 1;
 214
 215        rgmii = in_be32((void *)RGMII_FER);
 216        if (rgmii & (1 << (19 - devnum)))
 217                return 0x100;
 218#endif
 219
 220#if defined(CONFIG_460EX) || defined(CONFIG_460GT)
 221        u32 eoffset = 0;
 222
 223        switch (addr) {
 224#if defined(CONFIG_HAS_ETH1) && defined(CONFIG_GPCS_PHY1_ADDR)
 225        case CONFIG_GPCS_PHY1_ADDR:
 226                if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x100)))
 227                        eoffset = 0x100;
 228                break;
 229#endif
 230#if defined(CONFIG_HAS_ETH2) && defined(CONFIG_GPCS_PHY2_ADDR)
 231        case CONFIG_GPCS_PHY2_ADDR:
 232                if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x300)))
 233                        eoffset = 0x300;
 234                break;
 235#endif
 236#if defined(CONFIG_HAS_ETH3) && defined(CONFIG_GPCS_PHY3_ADDR)
 237        case CONFIG_GPCS_PHY3_ADDR:
 238                if (addr == EMAC_MR1_IPPA_GET(in_be32((void *)EMAC0_MR1 + 0x400)))
 239                        eoffset = 0x400;
 240                break;
 241#endif
 242        default:
 243                eoffset = 0;
 244                break;
 245        }
 246        return eoffset;
 247#endif
 248
 249        return 0;
 250#endif
 251}
 252
 253static int emac_miiphy_wait(u32 emac_reg)
 254{
 255        u32 sta_reg;
 256        int i;
 257
 258        /* wait for completion */
 259        i = 0;
 260        do {
 261                sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
 262                if (i++ > 5) {
 263                        debug("%s [%d]: Timeout! EMAC0_STACR=0x%0x\n", __func__,
 264                              __LINE__, sta_reg);
 265                        return -1;
 266                }
 267                udelay(10);
 268        } while ((sta_reg & EMAC_STACR_OC) == EMAC_STACR_OC_MASK);
 269
 270        return 0;
 271}
 272
 273static int emac_miiphy_command(u8 addr, u8 reg, int cmd, u16 value)
 274{
 275        u32 emac_reg;
 276        u32 sta_reg;
 277
 278        emac_reg = miiphy_getemac_offset(addr);
 279
 280        /* wait for completion */
 281        if (emac_miiphy_wait(emac_reg) != 0)
 282                return -1;
 283
 284        sta_reg = reg;          /* reg address */
 285
 286        /* set clock (50MHz) and read flags */
 287#if defined(CONFIG_440GX) || defined(CONFIG_440SPE) || \
 288    defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \
 289    defined(CONFIG_460EX) || defined(CONFIG_460GT) || \
 290    defined(CONFIG_405EX)
 291#if defined(CONFIG_IBM_EMAC4_V4)        /* EMAC4 V4 changed bit setting */
 292        sta_reg = (sta_reg & ~EMAC_STACR_OP_MASK) | cmd;
 293#else
 294        sta_reg |= cmd;
 295#endif
 296#else
 297        sta_reg = (sta_reg | cmd) & ~EMAC_STACR_CLK_100MHZ;
 298#endif
 299
 300        /* Some boards (mainly 405EP based) define the PHY clock freqency fixed */
 301        sta_reg = sta_reg | CONFIG_PHY_CLK_FREQ;
 302        sta_reg = sta_reg | ((u32)addr << 5);   /* Phy address */
 303        sta_reg = sta_reg | EMAC_STACR_OC_MASK; /* new IBM emac v4 */
 304        if (cmd == EMAC_STACR_WRITE)
 305                memcpy(&sta_reg, &value, 2);    /* put in data */
 306
 307        out_be32((void *)EMAC0_STACR + emac_reg, sta_reg);
 308        debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
 309
 310        /* wait for completion */
 311        if (emac_miiphy_wait(emac_reg) != 0)
 312                return -1;
 313
 314        debug("%s [%d]: sta_reg=%08x\n", __func__, __LINE__, sta_reg);
 315        if ((sta_reg & EMAC_STACR_PHYE) != 0)
 316                return -1;
 317
 318        return 0;
 319}
 320
 321int emac4xx_miiphy_read (const char *devname, unsigned char addr, unsigned char reg,
 322                         unsigned short *value)
 323{
 324        unsigned long sta_reg;
 325        unsigned long emac_reg;
 326
 327        emac_reg = miiphy_getemac_offset(addr);
 328
 329        if (emac_miiphy_command(addr, reg, EMAC_STACR_READ, 0) != 0)
 330                return -1;
 331
 332        sta_reg = in_be32((void *)EMAC0_STACR + emac_reg);
 333        *value = sta_reg >> 16;
 334
 335        return 0;
 336}
 337
 338/***********************************************************/
 339/* write a phy reg and return the value with a rc           */
 340/***********************************************************/
 341
 342int emac4xx_miiphy_write (const char *devname, unsigned char addr, unsigned char reg,
 343                          unsigned short value)
 344{
 345        return emac_miiphy_command(addr, reg, EMAC_STACR_WRITE, value);
 346}
 347