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