uboot/drivers/net/mcfmii.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004-2008 Freescale Semiconductor, Inc.
   3 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <config.h>
  10#include <net.h>
  11#include <netdev.h>
  12
  13#ifdef CONFIG_MCF547x_8x
  14#include <asm/fsl_mcdmafec.h>
  15#else
  16#include <asm/fec.h>
  17#endif
  18#include <asm/immap.h>
  19
  20DECLARE_GLOBAL_DATA_PTR;
  21
  22#if defined(CONFIG_CMD_NET)
  23#undef MII_DEBUG
  24#undef ET_DEBUG
  25
  26/*extern int fecpin_setclear(struct eth_device *dev, int setclear);*/
  27
  28#if defined(CONFIG_SYS_DISCOVER_PHY) || defined(CONFIG_CMD_MII)
  29#include <miiphy.h>
  30
  31/* Make MII read/write commands for the FEC. */
  32#define mk_mii_read(ADDR, REG)          (0x60020000 | ((ADDR << 23) | \
  33                                         (REG & 0x1f) << 18))
  34#define mk_mii_write(ADDR, REG, VAL)    (0x50020000 | ((ADDR << 23) | \
  35                                         (REG & 0x1f) << 18) | (VAL & 0xffff))
  36
  37#ifndef CONFIG_SYS_UNSPEC_PHYID
  38#       define CONFIG_SYS_UNSPEC_PHYID          0
  39#endif
  40#ifndef CONFIG_SYS_UNSPEC_STRID
  41#       define CONFIG_SYS_UNSPEC_STRID          0
  42#endif
  43
  44#ifdef CONFIG_MCF547x_8x
  45typedef struct fec_info_dma FEC_INFO_T;
  46#define FEC_T fecdma_t
  47#else
  48typedef struct fec_info_s FEC_INFO_T;
  49#define FEC_T fec_t
  50#endif
  51
  52typedef struct phy_info_struct {
  53        u32 phyid;
  54        char *strid;
  55} phy_info_t;
  56
  57phy_info_t phyinfo[] = {
  58        {0x0022561B, "AMD79C784VC"},    /* AMD 79C784VC */
  59        {0x00406322, "BCM5222"},        /* Broadcom 5222 */
  60        {0x02a80150, "Intel82555"},     /* Intel 82555 */
  61        {0x0016f870, "LSI80225"},       /* LSI 80225 */
  62        {0x0016f880, "LSI80225/B"},     /* LSI 80225/B */
  63        {0x78100000, "LXT970"},         /* LXT970 */
  64        {0x001378e0, "LXT971"},         /* LXT971 and 972 */
  65        {0x00221619, "KS8721BL"},       /* Micrel KS8721BL/SL */
  66        {0x00221512, "KSZ8041NL"},      /* Micrel KSZ8041NL */
  67        {0x20005CE1, "N83640"},         /* National 83640 */
  68        {0x20005C90, "N83848"},         /* National 83848 */
  69        {0x20005CA2, "N83849"},         /* National 83849 */
  70        {0x01814400, "QS6612"},         /* QS6612 */
  71#if defined(CONFIG_SYS_UNSPEC_PHYID) && defined(CONFIG_SYS_UNSPEC_STRID)
  72        {CONFIG_SYS_UNSPEC_PHYID, CONFIG_SYS_UNSPEC_STRID},
  73#endif
  74        {0, 0}
  75};
  76
  77/*
  78 * mii_init -- Initialize the MII for MII command without ethernet
  79 * This function is a subset of eth_init
  80 */
  81void mii_reset(FEC_INFO_T *info)
  82{
  83        volatile FEC_T *fecp = (FEC_T *) (info->miibase);
  84        int i;
  85
  86        fecp->ecr = FEC_ECR_RESET;
  87
  88        for (i = 0; (fecp->ecr & FEC_ECR_RESET) && (i < FEC_RESET_DELAY); ++i) {
  89                udelay(1);
  90        }
  91        if (i == FEC_RESET_DELAY)
  92                printf("FEC_RESET_DELAY timeout\n");
  93}
  94
  95/* send command to phy using mii, wait for result */
  96uint mii_send(uint mii_cmd)
  97{
  98        FEC_INFO_T *info;
  99        volatile FEC_T *ep;
 100        struct eth_device *dev;
 101        uint mii_reply;
 102        int j = 0;
 103
 104        /* retrieve from register structure */
 105        dev = eth_get_dev();
 106        info = dev->priv;
 107
 108        ep = (FEC_T *) info->miibase;
 109
 110        ep->mmfr = mii_cmd;     /* command to phy */
 111
 112        /* wait for mii complete */
 113        while (!(ep->eir & FEC_EIR_MII) && (j < MCFFEC_TOUT_LOOP)) {
 114                udelay(1);
 115                j++;
 116        }
 117        if (j >= MCFFEC_TOUT_LOOP) {
 118                printf("MII not complete\n");
 119                return -1;
 120        }
 121
 122        mii_reply = ep->mmfr;   /* result from phy */
 123        ep->eir = FEC_EIR_MII;  /* clear MII complete */
 124#ifdef ET_DEBUG
 125        printf("%s[%d] %s: sent=0x%8.8x, reply=0x%8.8x\n",
 126               __FILE__, __LINE__, __FUNCTION__, mii_cmd, mii_reply);
 127#endif
 128
 129        return (mii_reply & 0xffff);    /* data read from phy */
 130}
 131#endif                          /* CONFIG_SYS_DISCOVER_PHY || (CONFIG_MII) */
 132
 133#if defined(CONFIG_SYS_DISCOVER_PHY)
 134int mii_discover_phy(struct eth_device *dev)
 135{
 136#define MAX_PHY_PASSES 11
 137        FEC_INFO_T *info = dev->priv;
 138        int phyaddr, pass;
 139        uint phyno, phytype;
 140        int i, found = 0;
 141
 142        if (info->phyname_init)
 143                return info->phy_addr;
 144
 145        phyaddr = -1;           /* didn't find a PHY yet */
 146        for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) {
 147                if (pass > 1) {
 148                        /* PHY may need more time to recover from reset.
 149                         * The LXT970 needs 50ms typical, no maximum is
 150                         * specified, so wait 10ms before try again.
 151                         * With 11 passes this gives it 100ms to wake up.
 152                         */
 153                        udelay(10000);  /* wait 10ms */
 154                }
 155
 156                for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) {
 157
 158                        phytype = mii_send(mk_mii_read(phyno, MII_PHYSID1));
 159#ifdef ET_DEBUG
 160                        printf("PHY type 0x%x pass %d type\n", phytype, pass);
 161#endif
 162                        if (phytype == 0xffff)
 163                                continue;
 164                        phyaddr = phyno;
 165                        phytype <<= 16;
 166                        phytype |=
 167                            mii_send(mk_mii_read(phyno, MII_PHYSID2));
 168
 169#ifdef ET_DEBUG
 170                        printf("PHY @ 0x%x pass %d\n", phyno, pass);
 171#endif
 172
 173                        for (i = 0; (i < ARRAY_SIZE(phyinfo))
 174                                && (phyinfo[i].phyid != 0); i++) {
 175                                if (phyinfo[i].phyid == phytype) {
 176#ifdef ET_DEBUG
 177                                        printf("phyid %x - %s\n",
 178                                               phyinfo[i].phyid,
 179                                               phyinfo[i].strid);
 180#endif
 181                                        strcpy(info->phy_name, phyinfo[i].strid);
 182                                        info->phyname_init = 1;
 183                                        found = 1;
 184                                        break;
 185                                }
 186                        }
 187
 188                        if (!found) {
 189#ifdef ET_DEBUG
 190                                printf("0x%08x\n", phytype);
 191#endif
 192                                strcpy(info->phy_name, "unknown");
 193                                info->phyname_init = 1;
 194                                break;
 195                        }
 196                }
 197        }
 198
 199        if (phyaddr < 0)
 200                printf("No PHY device found.\n");
 201
 202        return phyaddr;
 203}
 204#endif                          /* CONFIG_SYS_DISCOVER_PHY */
 205
 206void mii_init(void) __attribute__((weak,alias("__mii_init")));
 207
 208void __mii_init(void)
 209{
 210        FEC_INFO_T *info;
 211        volatile FEC_T *fecp;
 212        struct eth_device *dev;
 213        int miispd = 0, i = 0;
 214        u16 status = 0;
 215        u16 linkgood = 0;
 216
 217        /* retrieve from register structure */
 218        dev = eth_get_dev();
 219        info = dev->priv;
 220
 221        fecp = (FEC_T *) info->miibase;
 222
 223        fecpin_setclear(dev, 1);
 224
 225        mii_reset(info);
 226
 227        /* We use strictly polling mode only */
 228        fecp->eimr = 0;
 229
 230        /* Clear any pending interrupt */
 231        fecp->eir = 0xffffffff;
 232
 233        /* Set MII speed */
 234        miispd = (gd->bus_clk / 1000000) / 5;
 235        fecp->mscr = miispd << 1;
 236
 237        info->phy_addr = mii_discover_phy(dev);
 238
 239        while (i < MCFFEC_TOUT_LOOP) {
 240                status = 0;
 241                i++;
 242                /* Read PHY control register */
 243                miiphy_read(dev->name, info->phy_addr, MII_BMCR, &status);
 244
 245                /* If phy set to autonegotiate, wait for autonegotiation done,
 246                 * if phy is not autonegotiating, just wait for link up.
 247                 */
 248                if ((status & BMCR_ANENABLE) == BMCR_ANENABLE) {
 249                        linkgood = (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
 250                } else {
 251                        linkgood = BMSR_LSTATUS;
 252                }
 253                /* Read PHY status register */
 254                miiphy_read(dev->name, info->phy_addr, MII_BMSR, &status);
 255                if ((status & linkgood) == linkgood)
 256                        break;
 257
 258                udelay(1);
 259        }
 260        if (i >= MCFFEC_TOUT_LOOP) {
 261                printf("Link UP timeout\n");
 262        }
 263
 264        /* adapt to the duplex and speed settings of the phy */
 265        info->dup_spd = miiphy_duplex(dev->name, info->phy_addr) << 16;
 266        info->dup_spd |= miiphy_speed(dev->name, info->phy_addr);
 267}
 268
 269/*
 270 * Read and write a MII PHY register, routines used by MII Utilities
 271 *
 272 * FIXME: These routines are expected to return 0 on success, but mii_send
 273 *        does _not_ return an error code. Maybe 0xFFFF means error, i.e.
 274 *        no PHY connected...
 275 *        For now always return 0.
 276 * FIXME: These routines only work after calling eth_init() at least once!
 277 *        Otherwise they hang in mii_send() !!! Sorry!
 278 */
 279
 280int mcffec_miiphy_read(const char *devname, unsigned char addr, unsigned char reg,
 281                       unsigned short *value)
 282{
 283        short rdreg;            /* register working value */
 284
 285#ifdef MII_DEBUG
 286        printf("miiphy_read(0x%x) @ 0x%x = ", reg, addr);
 287#endif
 288        rdreg = mii_send(mk_mii_read(addr, reg));
 289
 290        *value = rdreg;
 291
 292#ifdef MII_DEBUG
 293        printf("0x%04x\n", *value);
 294#endif
 295
 296        return 0;
 297}
 298
 299int mcffec_miiphy_write(const char *devname, unsigned char addr, unsigned char reg,
 300                        unsigned short value)
 301{
 302#ifdef MII_DEBUG
 303        printf("miiphy_write(0x%x) @ 0x%x = ", reg, addr);
 304#endif
 305
 306        mii_send(mk_mii_write(addr, reg, value));
 307
 308#ifdef MII_DEBUG
 309        printf("0x%04x\n", value);
 310#endif
 311
 312        return 0;
 313}
 314
 315#endif                          /* CONFIG_CMD_NET */
 316