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