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