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