X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=cpu%2Fmpc8xx%2Ffec.c;h=37eb481ff16d534d0009b5d06010deb2a0d93e9d;hb=77ff7b7444ceb8022b46114f3d0b6d18e2fd1138;hp=8ac78429283ef24ce7cc8e35b40b2982e85cf463;hpb=2535d60277cc295adf75cd5721dcecd840c69a63;p=u-boot diff --git a/cpu/mpc8xx/fec.c b/cpu/mpc8xx/fec.c index 8ac7842928..37eb481ff1 100644 --- a/cpu/mpc8xx/fec.c +++ b/cpu/mpc8xx/fec.c @@ -27,14 +27,84 @@ #include #include +DECLARE_GLOBAL_DATA_PTR; + #undef ET_DEBUG -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET) +#if defined(CONFIG_CMD_NET) && \ + (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2)) -#ifdef CFG_DISCOVER_PHY +/* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */ +#if defined(FEC_ENET) && !defined(CONFIG_ETHER_ON_FEC1) && !defined(CONFIG_ETHER_ON_FEC2) +#define CONFIG_ETHER_ON_FEC1 1 +#endif + +/* define WANT_MII when MII support is required */ +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_FEC1_PHY) || defined(CONFIG_FEC2_PHY) +#define WANT_MII +#else +#undef WANT_MII +#endif + +#if defined(WANT_MII) #include -static void mii_discover_phy(void); + +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) +#error "CONFIG_MII has to be defined!" +#endif + +#endif + +#if defined(CONFIG_RMII) && !defined(WANT_MII) +#error RMII support is unusable without a working PHY. +#endif + +#ifdef CFG_DISCOVER_PHY +static int mii_discover_phy(struct eth_device *dev); +#endif + +int fec8xx_miiphy_read(char *devname, unsigned char addr, + unsigned char reg, unsigned short *value); +int fec8xx_miiphy_write(char *devname, unsigned char addr, + unsigned char reg, unsigned short value); + +static struct ether_fcc_info_s +{ + int ether_index; + int fecp_offset; + int phy_addr; + int actual_phy_addr; + int initialized; +} + ether_fcc_info[] = { +#if defined(CONFIG_ETHER_ON_FEC1) + { + 0, + offsetof(immap_t, im_cpm.cp_fec1), +#if defined(CONFIG_FEC1_PHY) + CONFIG_FEC1_PHY, +#else + -1, /* discover */ +#endif + -1, + 0, + + }, #endif +#if defined(CONFIG_ETHER_ON_FEC2) + { + 1, + offsetof(immap_t, im_cpm.cp_fec2), +#if defined(CONFIG_FEC2_PHY) + CONFIG_FEC2_PHY, +#else + -1, +#endif + -1, + 0, + }, +#endif +}; /* Ethernet Transmit and Receive Buffers */ #define DBUF_LENGTH 1520 @@ -47,8 +117,11 @@ static void mii_discover_phy(void); #define PKT_MINBUF_SIZE 64 #define PKT_MAXBLR_SIZE 1520 - -static char txbuf[DBUF_LENGTH]; +#ifdef __GNUC__ +static char txbuf[DBUF_LENGTH] __attribute__ ((aligned(8))); +#else +#error txbuf must be aligned. +#endif static uint rxIdx; /* index of the current RX buffer */ static uint txIdx; /* index of the current TX buffer */ @@ -70,32 +143,61 @@ static int fec_send(struct eth_device* dev, volatile void *packet, int length); static int fec_recv(struct eth_device* dev); static int fec_init(struct eth_device* dev, bd_t * bd); static void fec_halt(struct eth_device* dev); +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static void __mii_init(void); +#endif int fec_initialize(bd_t *bis) { struct eth_device* dev; + struct ether_fcc_info_s *efis; + int i; - dev = (struct eth_device*) malloc(sizeof *dev); - memset(dev, 0, sizeof *dev); + for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) { - sprintf(dev->name, "FEC ETHERNET"); - dev->iobase = 0; - dev->priv = 0; - dev->init = fec_init; - dev->halt = fec_halt; - dev->send = fec_send; - dev->recv = fec_recv; + dev = malloc(sizeof(*dev)); + if (dev == NULL) + hang(); - eth_register(dev); + memset(dev, 0, sizeof(*dev)); + + /* for FEC1 make sure that the name of the interface is the same + as the old one for compatibility reasons */ + if (i == 0) { + sprintf (dev->name, "FEC ETHERNET"); + } else { + sprintf (dev->name, "FEC%d ETHERNET", + ether_fcc_info[i].ether_index + 1); + } + + efis = ðer_fcc_info[i]; + + /* + * reset actual phy addr + */ + efis->actual_phy_addr = -1; + dev->priv = efis; + dev->init = fec_init; + dev->halt = fec_halt; + dev->send = fec_send; + dev->recv = fec_recv; + + eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register(dev->name, + fec8xx_miiphy_read, fec8xx_miiphy_write); +#endif + } return 1; } static int fec_send(struct eth_device* dev, volatile void *packet, int length) { int j, rc; - volatile immap_t *immr = (immap_t *) CFG_IMMR; - volatile fec_t *fecp = &(immr->im_cpm.cp_fec); + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); /* section 16.9.23.3 * Wait for ready @@ -142,50 +244,66 @@ static int fec_send(struct eth_device* dev, volatile void *packet, int length) return rc; } -static int fec_recv(struct eth_device* dev) +static int fec_recv (struct eth_device *dev) { + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = + (volatile fec_t *) (CFG_IMMR + efis->fecp_offset); int length; - volatile immap_t *immr = (immap_t *) CFG_IMMR; - volatile fec_t *fecp = &(immr->im_cpm.cp_fec); - for (;;) { - /* section 16.9.23.2 */ - if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { - length = -1; - break; /* nothing received - leave for() loop */ - } + for (;;) { + /* section 16.9.23.2 */ + if (rtx->rxbd[rxIdx].cbd_sc & BD_ENET_RX_EMPTY) { + length = -1; + break; /* nothing received - leave for() loop */ + } - length = rtx->rxbd[rxIdx].cbd_datlen; + length = rtx->rxbd[rxIdx].cbd_datlen; - if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) { + if (rtx->rxbd[rxIdx].cbd_sc & 0x003f) { #ifdef ET_DEBUG - printf("%s[%d] err: %x\n", - __FUNCTION__,__LINE__,rtx->rxbd[rxIdx].cbd_sc); + printf ("%s[%d] err: %x\n", + __FUNCTION__, __LINE__, + rtx->rxbd[rxIdx].cbd_sc); #endif - } else { - /* Pass the packet up to the protocol layers. */ - NetReceive(NetRxPackets[rxIdx], length - 4); - } + } else { + volatile uchar *rx = NetRxPackets[rxIdx]; - /* Give the buffer back to the FEC. */ - rtx->rxbd[rxIdx].cbd_datlen = 0; + length -= 4; - /* wrap around buffer index when necessary */ - if ((rxIdx + 1) >= PKTBUFSRX) { - rtx->rxbd[PKTBUFSRX - 1].cbd_sc = (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); - rxIdx = 0; - } else { - rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; - rxIdx++; - } +#if defined(CONFIG_CMD_CDP) + if ((rx[0] & 1) != 0 + && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0 + && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0) + rx = NULL; +#endif + /* + * Pass the packet up to the protocol layers. + */ + if (rx != NULL) + NetReceive (rx, length); + } - __asm__ ("eieio"); + /* Give the buffer back to the FEC. */ + rtx->rxbd[rxIdx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if ((rxIdx + 1) >= PKTBUFSRX) { + rtx->rxbd[PKTBUFSRX - 1].cbd_sc = + (BD_ENET_RX_WRAP | BD_ENET_RX_EMPTY); + rxIdx = 0; + } else { + rtx->rxbd[rxIdx].cbd_sc = BD_ENET_RX_EMPTY; + rxIdx++; + } - /* Try to fill Buffer Descriptors */ - fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ - } + __asm__ ("eieio"); - return length; + /* Try to fill Buffer Descriptors */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + } + + return length; } /************************************************************** @@ -210,31 +328,224 @@ static int fec_recv(struct eth_device* dev) #define FEC_RESET_DELAY 50 -static int fec_init(struct eth_device* dev, bd_t * bd) +#if defined(CONFIG_RMII) + +static inline void fec_10Mbps(struct eth_device *dev) { + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; - int i; + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr |= mask; +} + +static inline void fec_100Mbps(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + int fecidx = efis->ether_index; + uint mask = (fecidx == 0) ? 0x0000010 : 0x0000008; + + if ((unsigned int)fecidx >= 2) + hang(); + + ((volatile immap_t *)CFG_IMMR)->im_cpm.cp_cptr &= ~mask; +} + +#endif + +static inline void fec_full_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl &= ~FEC_RCNTRL_DRT; + fecp->fec_x_cntrl |= FEC_TCNTRL_FDEN; /* FD enable */ +} + +static inline void fec_half_duplex(struct eth_device *dev) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + + fecp->fec_r_cntrl |= FEC_RCNTRL_DRT; + fecp->fec_x_cntrl &= ~FEC_TCNTRL_FDEN; /* FD disable */ +} + +static void fec_pin_init(int fecidx) +{ + bd_t *bd = gd->bd; volatile immap_t *immr = (immap_t *) CFG_IMMR; - volatile fec_t *fecp = &(immr->im_cpm.cp_fec); + volatile fec_t *fecp; -#if defined(CONFIG_FADS) && \ - ( defined(CONFIG_MPC860T) || defined(CONFIG_MPC866_et_al) ) - /* configure FADS for fast (FEC) ethernet, half-duplex */ - /* The LXT970 needs about 50ms to recover from reset, so - * wait for it by discovering the PHY before leaving eth_init(). + /* + * only two FECs please */ - { - volatile uint *bcsr4 = (volatile uint *) BCSR4; - *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1)) - | (BCSR4_FETHCFG0 | BCSR4_FETHFDE | BCSR4_FETHRST); - - /* reset the LXT970 PHY */ - *bcsr4 &= ~BCSR4_FETHRST; - udelay (10); - *bcsr4 |= BCSR4_FETHRST; - udelay (10); - } + if ((unsigned int)fecidx >= 2) + hang(); + + if (fecidx == 0) + fecp = &immr->im_cpm.cp_fec1; + else + fecp = &immr->im_cpm.cp_fec2; + + /* + * Set MII speed to 2.5 MHz or slightly below. + * * According to the MPC860T (Rev. D) Fast ethernet controller user + * * manual (6.2.14), + * * the MII management interface clock must be less than or equal + * * to 2.5 MHz. + * * This MDC frequency is equal to system clock / (2 * MII_SPEED). + * * Then MII_SPEED = system_clock / 2 * 2,5 Mhz. + * + * All MII configuration is done via FEC1 registers: + */ + immr->im_cpm.cp_fec1.fec_mii_speed = ((bd->bi_intfreq + 4999999) / 5000000) << 1; + +#if defined(CONFIG_NETTA) || defined(CONFIG_NETPHONE) || defined(CONFIG_NETTA2) + /* our PHYs are the limit at 2.5 MHz */ + fecp->fec_mii_speed <<= 1; +#endif + +#if defined(CONFIG_MPC885_FAMILY) && defined(WANT_MII) + /* use MDC for MII */ + immr->im_ioport.iop_pdpar |= 0x0080; + immr->im_ioport.iop_pddir &= ~0x0080; +#endif + + if (fecidx == 0) { +#if defined(CONFIG_ETHER_ON_FEC1) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + + immr->im_ioport.iop_papar |= 0xf830; + immr->im_ioport.iop_padir |= 0x0830; + immr->im_ioport.iop_padir &= ~0xf000; + + immr->im_cpm.cp_pbpar |= 0x00001001; + immr->im_cpm.cp_pbdir &= ~0x00001001; + + immr->im_ioport.iop_pcpar |= 0x000c; + immr->im_ioport.iop_pcdir &= ~0x000c; + + immr->im_cpm.cp_pepar |= 0x00000003; + immr->im_cpm.cp_pedir |= 0x00000003; + immr->im_cpm.cp_peso &= ~0x00000003; + + immr->im_cpm.cp_cptr &= ~0x00000100; + +#else + +#if !defined(CONFIG_FEC1_PHY_NORXERR) + immr->im_ioport.iop_papar |= 0x1000; + immr->im_ioport.iop_padir &= ~0x1000; #endif + immr->im_ioport.iop_papar |= 0xe810; + immr->im_ioport.iop_padir |= 0x0810; + immr->im_ioport.iop_padir &= ~0xe000; + + immr->im_cpm.cp_pbpar |= 0x00000001; + immr->im_cpm.cp_pbdir &= ~0x00000001; + + immr->im_cpm.cp_cptr |= 0x00000100; + immr->im_cpm.cp_cptr &= ~0x00000050; + +#endif /* !CONFIG_RMII */ + +#elif !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210) + /* + * Configure all of port D for MII. + */ + immr->im_ioport.iop_pdpar = 0x1fff; + + /* + * Bits moved from Rev. D onward + */ + if ((get_immr(0) & 0xffff) < 0x0501) + immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ + else + immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ +#else + /* + * Configure port A for MII. + */ + +#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY) + + /* + * On the ICU862 board the MII-MDC pin is routed to PD8 pin + * * of CPU, so for this board we need to configure Utopia and + * * enable PD8 to MII-MDC function + */ + immr->im_ioport.iop_pdpar |= 0x4080; +#endif + + /* + * Has Utopia been configured? + */ + if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) { + /* + * YES - Use MUXED mode for UTOPIA bus. + * This frees Port A for use by MII (see 862UM table 41-6). + */ + immr->im_ioport.utmode &= ~0x80; + } else { + /* + * NO - set SPLIT mode for UTOPIA bus. + * + * This doesn't really effect UTOPIA (which isn't + * enabled anyway) but just tells the 862 + * to use port A for MII (see 862UM table 41-6). + */ + immr->im_ioport.utmode |= 0x80; + } +#endif /* !defined(CONFIG_ICU862) */ + +#endif /* CONFIG_ETHER_ON_FEC1 */ + } else if (fecidx == 1) { + +#if defined(CONFIG_ETHER_ON_FEC2) + +#if defined(CONFIG_MPC885_FAMILY) /* MPC87x/88x have got 2 FECs and different pinout */ + +#if !defined(CONFIG_RMII) + immr->im_cpm.cp_pepar |= 0x0003fffc; + immr->im_cpm.cp_pedir |= 0x0003fffc; + immr->im_cpm.cp_peso &= ~0x000087fc; + immr->im_cpm.cp_peso |= 0x00037800; + + immr->im_cpm.cp_cptr &= ~0x00000080; +#else + +#if !defined(CONFIG_FEC2_PHY_NORXERR) + immr->im_cpm.cp_pepar |= 0x00000010; + immr->im_cpm.cp_pedir |= 0x00000010; + immr->im_cpm.cp_peso &= ~0x00000010; +#endif + immr->im_cpm.cp_pepar |= 0x00039620; + immr->im_cpm.cp_pedir |= 0x00039620; + immr->im_cpm.cp_peso |= 0x00031000; + immr->im_cpm.cp_peso &= ~0x00008620; + + immr->im_cpm.cp_cptr |= 0x00000080; + immr->im_cpm.cp_cptr &= ~0x00000028; +#endif /* CONFIG_RMII */ + +#endif /* CONFIG_MPC885_FAMILY */ + +#endif /* CONFIG_ETHER_ON_FEC2 */ + + } +} + +static int fec_reset(volatile fec_t *fecp) +{ + int i; + /* Whack a reset. * A delay is required between a reset of the FEC block and * initialization of other FEC registers because the reset takes @@ -242,17 +553,65 @@ static int fec_init(struct eth_device* dev, bd_t * bd) * to FEC registers might get killed by the reset routine which is * still in progress. */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; for (i = 0; (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); ++i) { udelay (1); } - if (i == FEC_RESET_DELAY) { - printf ("FEC_RESET_DELAY timeout\n"); - return 0; + if (i == FEC_RESET_DELAY) + return -1; + + return 0; +} + +static int fec_init (struct eth_device *dev, bd_t * bd) +{ + struct ether_fcc_info_s *efis = dev->priv; + volatile immap_t *immr = (immap_t *) CFG_IMMR; + volatile fec_t *fecp = + (volatile fec_t *) (CFG_IMMR + efis->fecp_offset); + int i; + + if (efis->ether_index == 0) { +#if defined(CONFIG_FADS) /* FADS family uses FPGA (BCSR) to control PHYs */ +#if defined(CONFIG_MPC885ADS) + *(vu_char *) BCSR5 &= ~(BCSR5_MII1_EN | BCSR5_MII1_RST); +#else + /* configure FADS for fast (FEC) ethernet, half-duplex */ + /* The LXT970 needs about 50ms to recover from reset, so + * wait for it by discovering the PHY before leaving eth_init(). + */ + { + volatile uint *bcsr4 = (volatile uint *) BCSR4; + + *bcsr4 = (*bcsr4 & ~(BCSR4_FETH_EN | BCSR4_FETHCFG1)) + | (BCSR4_FETHCFG0 | BCSR4_FETHFDE | + BCSR4_FETHRST); + + /* reset the LXT970 PHY */ + *bcsr4 &= ~BCSR4_FETHRST; + udelay (10); + *bcsr4 |= BCSR4_FETHRST; + udelay (10); + } +#endif /* CONFIG_MPC885ADS */ +#endif /* CONFIG_FADS */ } +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + /* the MII interface is connected to FEC1 + * so for the miiphy_xxx function to work we must + * call mii_init since fec_halt messes the thing up + */ + if (efis->ether_index != 0) + __mii_init(); +#endif + + if (fec_reset(fecp) < 0) + printf ("FEC_RESET_DELAY timeout\n"); + /* We use strictly polling mode only */ fecp->fec_imask = 0; @@ -265,16 +624,23 @@ static int fec_init(struct eth_device* dev, bd_t * bd) /* Set station address */ -#define ea eth_get_dev()->enetaddr - fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | - (ea[2] << 8) | (ea[3] ) ; - fecp->fec_addr_high = (ea[4] << 8) | (ea[5] ) ; +#define ea dev->enetaddr + fecp->fec_addr_low = (ea[0] << 24) | (ea[1] << 16) | (ea[2] << 8) | (ea[3]); + fecp->fec_addr_high = (ea[4] << 8) | (ea[5]); #undef ea +#if defined(CONFIG_CMD_CDP) + /* + * Turn on multicast address hash table + */ + fecp->fec_hash_table_high = 0xffffffff; + fecp->fec_hash_table_low = 0xffffffff; +#else /* Clear multicast address hash table */ fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; + fecp->fec_hash_table_low = 0; +#endif /* Set maximum receive buffer size. */ @@ -292,9 +658,10 @@ static int fec_init(struct eth_device* dev, bd_t * bd) if (!rtx) { #ifdef CFG_ALLOC_DPRAM - rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + dpram_alloc_align(sizeof(RTXBD),8)); + rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + + dpram_alloc_align (sizeof (RTXBD), 8)); #else - rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE); + rtx = (RTXBD *) (immr->im_cpm.cp_dpmem + CPM_FEC_BASE); #endif } /* @@ -303,8 +670,8 @@ static int fec_init(struct eth_device* dev, bd_t * bd) * Empty, Wrap */ for (i = 0; i < PKTBUFSRX; i++) { - rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; - rtx->rxbd[i].cbd_datlen = 0; /* Reset */ + rtx->rxbd[i].cbd_sc = BD_ENET_RX_EMPTY; + rtx->rxbd[i].cbd_datlen = 0; /* Reset */ rtx->rxbd[i].cbd_bufaddr = (uint) NetRxPackets[i]; } rtx->rxbd[PKTBUFSRX - 1].cbd_sc |= BD_ENET_RX_WRAP; @@ -315,8 +682,8 @@ static int fec_init(struct eth_device* dev, bd_t * bd) * Last, Tx CRC */ for (i = 0; i < TX_BUF_CNT; i++) { - rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; - rtx->txbd[i].cbd_datlen = 0; /* Reset */ + rtx->txbd[i].cbd_sc = BD_ENET_TX_LAST | BD_ENET_TX_TC; + rtx->txbd[i].cbd_datlen = 0; /* Reset */ rtx->txbd[i].cbd_bufaddr = (uint) (&txbuf[0]); } rtx->txbd[TX_BUF_CNT - 1].cbd_sc |= BD_ENET_TX_WRAP; @@ -328,10 +695,10 @@ static int fec_init(struct eth_device* dev, bd_t * bd) /* Enable MII mode */ -#if 0 /* Full duplex mode */ +#if 0 /* Full duplex mode */ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE; fecp->fec_x_cntrl = FEC_TCNTRL_FDEN; -#else /* Half duplex mode */ +#else /* Half duplex mode */ fecp->fec_r_cntrl = FEC_RCNTRL_MII_MODE | FEC_RCNTRL_DRT; fecp->fec_x_cntrl = 0; #endif @@ -340,98 +707,101 @@ static int fec_init(struct eth_device* dev, bd_t * bd) */ fecp->fec_fun_code = 0x78000000; - /* Set MII speed to 2.5 MHz or slightly below. - * According to the MPC860T (Rev. D) Fast ethernet controller user - * manual (6.2.14), - * the MII management interface clock must be less than or equal - * to 2.5 MHz. - * This MDC frequency is equal to system clock / (2 * MII_SPEED). - * Then MII_SPEED = system_clock / 2 * 2,5 Mhz. - */ - fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1; - -#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210) - /* Configure all of port D for MII. + /* + * Setup the pin configuration of the FEC */ - immr->im_ioport.iop_pdpar = 0x1fff; - - /* Bits moved from Rev. D onward */ - if ((get_immr (0) & 0xffff) < 0x0501) { - immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ - } else { - immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ - } -#else - /* Configure port A for MII. - */ + fec_pin_init (efis->ether_index); -#if defined(CONFIG_ICU862) && defined(CFG_DISCOVER_PHY) + rxIdx = 0; + txIdx = 0; - /* On the ICU862 board the MII-MDC pin is routed to PD8 pin - * of CPU, so for this board we need to configure Utopia and - * enable PD8 to MII-MDC function */ - immr->im_ioport.iop_pdpar |= 0x4080; -#endif + /* + * Now enable the transmit and receive processing + */ + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; - /* Has Utopia been configured? */ - if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) { + if (efis->phy_addr == -1) { +#ifdef CFG_DISCOVER_PHY /* - * YES - Use MUXED mode for UTOPIA bus. - * This frees Port A for use by MII (see 862UM table 41-6). + * wait for the PHY to wake up after reset */ - immr->im_ioport.utmode &= ~0x80; + efis->actual_phy_addr = mii_discover_phy (dev); + + if (efis->actual_phy_addr == -1) { + printf ("Unable to discover phy!\n"); + return -1; + } +#else + efis->actual_phy_addr = -1; +#endif } else { - /* - * NO - set SPLIT mode for UTOPIA bus. - * - * This doesn't really effect UTOPIA (which isn't - * enabled anyway) but just tells the 862 - * to use port A for MII (see 862UM table 41-6). - */ - immr->im_ioport.utmode |= 0x80; + efis->actual_phy_addr = efis->phy_addr; } -#endif /* !defined(CONFIG_ICU862) */ - - rxIdx = 0; - txIdx = 0; - /* Now enable the transmit and receive processing +#if defined(CONFIG_MII) && defined(CONFIG_RMII) + /* + * adapt the RMII speed to the speed of the phy */ - fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; + if (miiphy_speed (dev->name, efis->actual_phy_addr) == _100BASET) { + fec_100Mbps (dev); + } else { + fec_10Mbps (dev); + } +#endif -#ifdef CFG_DISCOVER_PHY - /* wait for the PHY to wake up after reset +#if defined(CONFIG_MII) + /* + * adapt to the half/full speed settings */ - mii_discover_phy(); + if (miiphy_duplex (dev->name, efis->actual_phy_addr) == FULL) { + fec_full_duplex (dev); + } else { + fec_half_duplex (dev); + } #endif /* And last, try to fill Rx Buffer Descriptors */ - fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ + fecp->fec_r_des_active = 0x01000000; /* Descriptor polling active */ - return 1; + efis->initialized = 1; + + return 0; } static void fec_halt(struct eth_device* dev) { -#if 0 - volatile immap_t *immr = (immap_t *)CFG_IMMR; - immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); -#endif -} + struct ether_fcc_info_s *efis = dev->priv; + volatile fec_t *fecp = (volatile fec_t *)(CFG_IMMR + efis->fecp_offset); + int i; -#if 0 -void restart(void) -{ - volatile immap_t *immr = (immap_t *)CFG_IMMR; - immr->im_cpm.cp_scc[SCC_ENET].scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); -} -#endif + /* avoid halt if initialized; mii gets stuck otherwise */ + if (!efis->initialized) + return; -#if defined(CFG_DISCOVER_PHY) || (CONFIG_COMMANDS & CFG_CMD_MII) + /* Whack a reset. + * A delay is required between a reset of the FEC block and + * initialization of other FEC registers because the reset takes + * some time to complete. If you don't delay, subsequent writes + * to FEC registers might get killed by the reset routine which is + * still in progress. + */ -static int phyaddr = -1; /* didn't find a PHY yet */ -static uint phytype; + fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; + for (i = 0; + (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); + ++i) { + udelay (1); + } + if (i == FEC_RESET_DELAY) { + printf ("FEC_RESET_DELAY timeout\n"); + return; + } + + efis->initialized = 0; +} + +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) /* Make MII read/write commands for the FEC. */ @@ -465,7 +835,8 @@ static uint phytype; #define PHY_ID_AMD79C784 0x00225610 /* AMD 79C784 */ #define PHY_ID_LSI80225 0x0016f870 /* LSI 80225 */ #define PHY_ID_LSI80225B 0x0016f880 /* LSI 80225/B */ - +#define PHY_ID_DM9161 0x0181B880 /* Davicom DM9161 */ +#define PHY_ID_KSM8995M 0x00221450 /* MICREL KS8995MA */ /* send command to phy using mii, wait for result */ static uint @@ -473,14 +844,20 @@ mii_send(uint mii_cmd) { uint mii_reply; volatile fec_t *ep; + int cnt; ep = &(((immap_t *)CFG_IMMR)->im_cpm.cp_fec); ep->fec_mii_data = mii_cmd; /* command to phy */ /* wait for mii complete */ - while (!(ep->fec_ievent & FEC_ENET_MII)) - ; /* spin until done */ + cnt = 0; + while (!(ep->fec_ievent & FEC_ENET_MII)) { + if (++cnt > 1000) { + printf("mii_send STUCK!\n"); + break; + } + } mii_reply = ep->fec_mii_data; /* result from phy */ ep->fec_ievent = FEC_ENET_MII; /* clear MII complete */ #if 0 @@ -489,15 +866,16 @@ mii_send(uint mii_cmd) #endif return (mii_reply & 0xffff); /* data read from phy */ } -#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */ +#endif #if defined(CFG_DISCOVER_PHY) -static void -mii_discover_phy(void) +static int mii_discover_phy(struct eth_device *dev) { #define MAX_PHY_PASSES 11 uint phyno; int pass; + uint phytype; + int phyaddr; phyaddr = -1; /* didn't find a PHY yet */ for (pass = 1; pass <= MAX_PHY_PASSES && phyaddr < 0; ++pass) { @@ -510,15 +888,14 @@ mii_discover_phy(void) udelay(10000); /* wait 10ms */ } for (phyno = 0; phyno < 32 && phyaddr < 0; ++phyno) { - phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR1)); + phytype = mii_send(mk_mii_read(phyno, PHY_PHYIDR2)); #ifdef ET_DEBUG printf("PHY type 0x%x pass %d type ", phytype, pass); #endif if (phytype != 0xffff) { phyaddr = phyno; - phytype <<= 16; phytype |= mii_send(mk_mii_read(phyno, - PHY_PHYIDR2)); + PHY_PHYIDR1)) << 16; #ifdef ET_DEBUG printf("PHY @ 0x%x pass %d type ",phyno,pass); @@ -541,6 +918,12 @@ mii_discover_phy(void) case PHY_ID_LSI80225B: printf("LSI L80225/B\n"); break; + case PHY_ID_DM9161: + printf("Davicom DM9161\n"); + break; + case PHY_ID_KSM8995M: + printf("MICREL KS8995M\n"); + break; default: printf("0x%08x\n", phytype); break; @@ -552,49 +935,24 @@ mii_discover_phy(void) if (phyaddr < 0) { printf("No PHY device found.\n"); } + return phyaddr; } #endif /* CFG_DISCOVER_PHY */ -#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII) - -static int mii_init_done = 0; +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII) /**************************************************************************** - * mii_init -- Initialize the MII for MII command without ethernet + * mii_init -- Initialize the MII via FEC 1 for MII command without ethernet * This function is a subset of eth_init **************************************************************************** */ -void mii_init (void) +static void __mii_init(void) { - DECLARE_GLOBAL_DATA_PTR; - bd_t *bd = gd->bd; - volatile immap_t *immr = (immap_t *) CFG_IMMR; volatile fec_t *fecp = &(immr->im_cpm.cp_fec); - int i; - - if (mii_init_done != 0) { - return; - } - - /* Whack a reset. - * A delay is required between a reset of the FEC block and - * initialization of other FEC registers because the reset takes - * some time to complete. If you don't delay, subsequent writes - * to FEC registers might get killed by the reset routine which is - * still in progress. - */ - fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET; - for (i = 0; - (fecp->fec_ecntrl & FEC_ECNTRL_RESET) && (i < FEC_RESET_DELAY); - ++i) { - udelay (1); - } - if (i == FEC_RESET_DELAY) { + if (fec_reset(fecp) < 0) printf ("FEC_RESET_DELAY timeout\n"); - return; - } /* We use strictly polling mode only */ @@ -604,63 +962,23 @@ void mii_init (void) */ fecp->fec_ievent = 0xffc0; - /* Set MII speed to 2.5 MHz or slightly below. - * According to the MPC860T (Rev. D) Fast ethernet controller user - * manual (6.2.14), - * the MII management interface clock must be less than or equal - * to 2.5 MHz. - * This MDC frequency is equal to system clock / (2 * MII_SPEED). - * Then MII_SPEED = system_clock / 2 * 2,5 Mhz. - */ - fecp->fec_mii_speed = ((bd->bi_busfreq + 4999999) / 5000000) << 1; - -#if !defined(CONFIG_ICU862) && !defined(CONFIG_IAD210) - /* Configure all of port D for MII. - */ - immr->im_ioport.iop_pdpar = 0x1fff; - - /* Bits moved from Rev. D onward */ - if ((get_immr (0) & 0xffff) < 0x0501) { - immr->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ - } else { - immr->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ - } -#else - /* Configure port A for MII. - */ - -#if defined(CONFIG_ICU862) - - /* On the ICU862 board the MII-MDC pin is routed to PD8 pin - * of CPU, so for this board we need to configure Utopia and - * enable PD8 to MII-MDC function */ - immr->im_ioport.iop_pdpar |= 0x4080; -#endif - - /* Has Utopia been configured? */ - if (immr->im_ioport.iop_pdpar & (0x8000 >> 1)) { - /* - * YES - Use MUXED mode for UTOPIA bus. - * This frees Port A for use by MII (see 862UM table 41-6). - */ - immr->im_ioport.utmode &= ~0x80; - } else { - /* - * NO - set SPLIT mode for UTOPIA bus. - * - * This doesn't really effect UTOPIA (which isn't - * enabled anyway) but just tells the 862 - * to use port A for MII (see 862UM table 41-6). - */ - immr->im_ioport.utmode |= 0x80; - } -#endif /* !defined(CONFIG_ICU862) */ /* Now enable the transmit and receive processing */ fecp->fec_ecntrl = FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN; +} + +void mii_init (void) +{ + int i; + + __mii_init(); - mii_init_done = 1; + /* Setup the pin configuration of the FEC(s) + */ + for (i = 0; i < sizeof(ether_fcc_info) / sizeof(ether_fcc_info[0]); i++) + fec_pin_init(ether_fcc_info[i].ether_index); } + /***************************************************************************** * Read and write a MII PHY register, routines used by MII Utilities * @@ -672,7 +990,8 @@ void mii_init (void) * Otherwise they hang in mii_send() !!! Sorry! *****************************************************************************/ -int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value) +int fec8xx_miiphy_read(char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) { short rdreg; /* register working value */ @@ -682,30 +1001,26 @@ int miiphy_read(unsigned char addr, unsigned char reg, unsigned short *value) rdreg = mii_send(mk_mii_read(addr, reg)); *value = rdreg; - #ifdef MII_DEBUG printf ("0x%04x\n", *value); #endif - return 0; } -int miiphy_write(unsigned char addr, unsigned char reg, unsigned short value) +int fec8xx_miiphy_write(char *devname, unsigned char addr, + unsigned char reg, unsigned short value) { short rdreg; /* register working value */ - #ifdef MII_DEBUG printf ("miiphy_write(0x%x) @ 0x%x = ", reg, addr); #endif - rdreg = mii_send(mk_mii_write(addr, reg, value)); #ifdef MII_DEBUG printf ("0x%04x\n", value); #endif - return 0; } -#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/ +#endif -#endif /* CFG_CMD_NET, FEC_ENET */ +#endif