X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=cpu%2Fmpc5xxx%2Ffec.c;h=21632722d3f4cbbb958effb5d6d36df874af0f91;hb=151ab83a936e66cf56971a0e0340609528474734;hp=b8e2560cf7c826a53d2b70811b6e55360cc3b6c9;hpb=945af8d723a29e9b6289d84250745ed0dc16fc81;p=u-boot diff --git a/cpu/mpc5xxx/fec.c b/cpu/mpc5xxx/fec.c index b8e2560cf7..21632722d3 100644 --- a/cpu/mpc5xxx/fec.c +++ b/cpu/mpc5xxx/fec.c @@ -14,10 +14,10 @@ #include "sdma.h" #include "fec.h" -#define DEBUG 0x8 +/* #define DEBUG 0x28 */ #if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ - defined(CONFIG_MPC5XXX_FEC) + defined(CONFIG_MPC5xxx_FEC) #if (DEBUG & 0x60) static void tfifo_print(mpc5xxx_fec_priv *fec); @@ -28,25 +28,60 @@ static void rfifo_print(mpc5xxx_fec_priv *fec); static uint32 local_crc32(char *string, unsigned int crc_value, int len); #endif +typedef struct { + uint8 data[1500]; /* actual data */ + int length; /* actual length */ + int used; /* buffer in use or not */ + uint8 head[16]; /* MAC header(6 + 6 + 2) + 2(aligned) */ +} NBUF; + +/********************************************************************/ +#if (DEBUG & 0x2) +static void mpc5xxx_fec_phydump (void) +{ + uint16 phyStatus, i; + uint8 phyAddr = CONFIG_PHY_ADDR; + uint8 reg_mask[] = { +#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */ + /* regs to print: 0...7, 16...19, 21, 23, 24 */ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, +#else + /* regs to print: 0...8, 16...20 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif + }; + + for (i = 0; i < 32; i++) { + if (reg_mask[i]) { + miiphy_read(phyAddr, i, &phyStatus); + printf("Mii reg %d: 0x%04x\n", i, phyStatus); + } + } +} +#endif + /********************************************************************/ static int mpc5xxx_fec_rbd_init(mpc5xxx_fec_priv *fec) { int ix; char *data; + static int once = 0; - /* - * the receive ring is located right after the transmit one - */ for (ix = 0; ix < FEC_RBD_NUM; ix++) { - data = (char *)malloc(FEC_MAX_PKT_SIZE); - if (data == NULL) { - printf ("RBD INIT FAILED\n"); - return -1; + if (!once) { + data = (char *)malloc(FEC_MAX_PKT_SIZE); + if (data == NULL) { + printf ("RBD INIT FAILED\n"); + return -1; + } + fec->rbdBase[ix].dataPointer = (uint32)data; } fec->rbdBase[ix].status = FEC_RBD_EMPTY; fec->rbdBase[ix].dataLength = 0; - fec->rbdBase[ix].dataPointer = (uint32)data; } + once ++; /* * have the last RBD to close the ring @@ -80,7 +115,7 @@ static void mpc5xxx_fec_tbd_init(mpc5xxx_fec_priv *fec) } /********************************************************************/ -static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, FEC_RBD * pRbd) +static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, volatile FEC_RBD * pRbd) { /* * Reset buffer descriptor as empty @@ -106,7 +141,7 @@ static void mpc5xxx_fec_rbd_clean(mpc5xxx_fec_priv *fec, FEC_RBD * pRbd) /********************************************************************/ static void mpc5xxx_fec_tbd_scrub(mpc5xxx_fec_priv *fec) { - FEC_TBD *pUsedTbd; + volatile FEC_TBD *pUsedTbd; #if (DEBUG & 0x1) printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n", @@ -200,9 +235,9 @@ static void mpc5xxx_fec_set_hwaddr(mpc5xxx_fec_priv *fec, char *mac) /********************************************************************/ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) { + DECLARE_GLOBAL_DATA_PTR; mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA; - const uint8 phyAddr = 0; /* Only one PHY */ #if (DEBUG & 0x1) printf ("mpc5xxx_fec_init... Begin\n"); @@ -214,17 +249,6 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) mpc5xxx_fec_rbd_init(fec); mpc5xxx_fec_tbd_init(fec); - /* - * Initialize GPIO pins - */ - if (fec->xcv_type == SEVENWIRE) { - /* 10MBit with 7-wire operation */ - *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000; - } else { - /* 100MBit with MD operation */ - *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000; - } - /* * Clear FEC-Lite interrupt event register(IEVENT) */ @@ -250,21 +274,13 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */ } - if (fec->xcv_type == SEVENWIRE) { - /* - * Set FEC-Lite transmit control register(X_CNTRL): - */ - /*fec->eth->x_cntrl = 0x00000002; */ /* half-duplex, heartbeat */ - fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */ - } else { - /*fec->eth->x_cntrl = 0x00000006; */ /* full-duplex, heartbeat */ - fec->eth->x_cntrl = 0x00000004; /* full-duplex, heartbeat disabled */ - + fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */ + if (fec->xcv_type != SEVENWIRE) { /* - * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock(25Mhz) + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock * and do not drop the Preamble. */ - fec->eth->mii_speed = (0x5 << 1); /* No MII for 7-wire mode */ + fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */ } /* @@ -336,17 +352,80 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) SDMA_CLEAR_IEVENT(FEC_RECV_TASK_NO); /* - * Set SmartDMA intMask register to enable SmartDMA task interrupts + * Initialize SmartDMA parameters stored in SRAM */ - SDMA_INT_ENABLE(FEC_RECV_TASK_NO); + *(volatile int *)FEC_TBD_BASE = (int)fec->tbdBase; + *(volatile int *)FEC_RBD_BASE = (int)fec->rbdBase; + *(volatile int *)FEC_TBD_NEXT = (int)fec->tbdBase; + *(volatile int *)FEC_RBD_NEXT = (int)fec->rbdBase; /* - * Initialize SmartDMA parameters stored in SRAM + * Enable FEC-Lite controller + */ + fec->eth->ecntrl |= 0x00000006; + +#if (DEBUG & 0x2) + if (fec->xcv_type != SEVENWIRE) + mpc5xxx_fec_phydump (); +#endif + + /* + * Enable SmartDMA receive task */ - *(int *)FEC_TBD_BASE = (int)fec->tbdBase; - *(int *)FEC_RBD_BASE = (int)fec->rbdBase; - *(int *)FEC_TBD_NEXT = (int)fec->tbdBase; - *(int *)FEC_RBD_NEXT = (int)fec->rbdBase; + SDMA_TASK_ENABLE(FEC_RECV_TASK_NO); + +#if (DEBUG & 0x1) + printf("mpc5xxx_fec_init... Done \n"); +#endif + + return 1; +} + +/********************************************************************/ +static int mpc5xxx_fec_init_phy(struct eth_device *dev, bd_t * bis) +{ + DECLARE_GLOBAL_DATA_PTR; + mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; + const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */ + +#if (DEBUG & 0x1) + printf ("mpc5xxx_fec_init_phy... Begin\n"); +#endif + + /* + * Initialize GPIO pins + */ + if (fec->xcv_type == SEVENWIRE) { + /* 10MBit with 7-wire operation */ +#if defined(CONFIG_TOTAL5200) + /* 7-wire and USB2 on Ethernet */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00030000; +#else /* !CONFIG_TOTAL5200 */ + /* 7-wire only */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00020000; +#endif /* CONFIG_TOTAL5200 */ + } else { + /* 100MBit with MD operation */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= 0x00050000; + } + + /* + * Clear FEC-Lite interrupt event register(IEVENT) + */ + fec->eth->ievent = 0xffffffff; + + /* + * Set interrupt mask register + */ + fec->eth->imask = 0x00000000; + + if (fec->xcv_type != SEVENWIRE) { + /* + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock + * and do not drop the Preamble. + */ + fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); /* No MII for 7-wire mode */ + } if (fec->xcv_type != SEVENWIRE) { /* @@ -383,7 +462,9 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) /* * Force 10Base-T, FDX operation */ +#if (DEBUG & 0x2) printf("Forcing 10 Mbps ethernet link... "); +#endif miiphy_read(phyAddr, 0x1, &phyStatus); /* miiphy_write(fec, phyAddr, 0x0, 0x0100); @@ -418,7 +499,9 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) #endif } while (!(phyStatus & 0x0004)); /* !link up */ +#if (DEBUG & 0x2) printf ("done.\n"); +#endif } else { /* MII100 */ /* * Set the auto-negotiation advertisement register bits @@ -450,7 +533,7 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) #endif return -1; } - } while ((phyStatus & 0x0020) != 0x0020); + } while (!(phyStatus & 0x0004)); #if (DEBUG & 0x2) printf("PHY auto neg complete! \n"); @@ -459,62 +542,33 @@ static int mpc5xxx_fec_init(struct eth_device *dev, bd_t * bis) } - /* - * Enable FEC-Lite controller - */ - fec->eth->ecntrl |= 0x00000006; - - if (fec->xcv_type != SEVENWIRE) { #if (DEBUG & 0x2) - uint16 phyStatus, i; - uint8 phyAddr = 0; - - for (i = 0; i < 9; i++) { - miiphy_read(phyAddr, i, &phyStatus); - printf("Mii reg %d: 0x%04x\n", i, phyStatus); - } - for (i = 16; i < 21; i++) { - miiphy_read(phyAddr, i, &phyStatus); - printf("Mii reg %d: 0x%04x\n", i, phyStatus); - } + if (fec->xcv_type != SEVENWIRE) + mpc5xxx_fec_phydump (); #endif - } - /* - * Enable SmartDMA receive task - */ - SDMA_TASK_ENABLE(FEC_RECV_TASK_NO); + #if (DEBUG & 0x1) - printf("mpc5xxx_fec_init... Done \n"); + printf("mpc5xxx_fec_init_phy... Done \n"); #endif - return 0; + return 1; } /********************************************************************/ static void mpc5xxx_fec_halt(struct eth_device *dev) { - mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; +#if defined(CONFIG_MPC5200) struct mpc5xxx_sdma *sdma = (struct mpc5xxx_sdma *)MPC5XXX_SDMA; +#endif + mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; int counter = 0xffff; #if (DEBUG & 0x2) - if (fec->xcv_type != SEVENWIRE) { - uint16 phyStatus, i; - uint8 phyAddr = 0; - - for (i = 0; i < 9; i++) { - miiphy_read(phyAddr, i, &phyStatus); - printf("Mii reg %d: 0x%04x\n", i, phyStatus); - } - for (i = 16; i < 21; i++) { - miiphy_read(phyAddr, i, &phyStatus); - printf ("Mii reg %d: 0x%04x\n", i, phyStatus); - } - } + if (fec->xcv_type != SEVENWIRE) + mpc5xxx_fec_phydump (); #endif - /* * mask FEC chip interrupts */ @@ -530,8 +584,6 @@ static void mpc5xxx_fec_halt(struct eth_device *dev) */ while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ; - SDMA_INT_DISABLE (FEC_RECV_TASK_NO); - /* * Disable SmartDMA tasks */ @@ -579,7 +631,7 @@ static void mpc5xxx_fec_halt(struct eth_device *dev) static void tfifo_print(mpc5xxx_fec_priv *fec) { - uint16 phyAddr = 0; + uint16 phyAddr = CONFIG_PHY_ADDR; uint16 phyStatus; if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr) @@ -603,7 +655,7 @@ static void tfifo_print(mpc5xxx_fec_priv *fec) static void rfifo_print(mpc5xxx_fec_priv *fec) { - uint16 phyAddr = 0; + uint16 phyAddr = CONFIG_PHY_ADDR; uint16 phyStatus; if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr) @@ -636,7 +688,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data, * 6-byte Ethernet addresses. */ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; - FEC_TBD *pTbd; + volatile FEC_TBD *pTbd; #if (DEBUG & 0x20) printf("tbd status: 0x%04x\n", fec->tbdBase[0].status); @@ -671,7 +723,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, volatile void *eth_data, pTbd = &fec->tbdBase[fec->tbdIndex]; pTbd->dataLength = data_length; pTbd->dataPointer = (uint32)eth_data; - pTbd->status |= FEC_TBD_READY; + pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM; #if (DEBUG & 0x100) @@ -727,10 +779,11 @@ static int mpc5xxx_fec_recv(struct eth_device *dev) * This command pulls one frame from the card */ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)dev->priv; - FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex]; + volatile FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex]; unsigned long ievent; - int frame_length; - char *frame; + int frame_length, len = 0; + NBUF *frame; + char buff[FEC_MAX_PKT_SIZE]; #if (DEBUG & 0x1) printf ("mpc5xxx_fec_recv %d Start...\n", fec->rbdIndex); @@ -763,41 +816,40 @@ static int mpc5xxx_fec_recv(struct eth_device *dev) } } - /* - * Do we have data in Rx FIFO? - */ - if ((pRbd->status & FEC_RBD_EMPTY) || !(pRbd->status & FEC_RBD_LAST)){ - return 0; - } + if (!(pRbd->status & FEC_RBD_EMPTY)) { + if ((pRbd->status & FEC_RBD_LAST) && !(pRbd->status & FEC_RBD_ERR) && + ((pRbd->dataLength - 4) > 14)) { - /* - * Pass the packet up only if reception was Ok - */ - if ((pRbd->dataLength <= 14) || (pRbd->status & FEC_RBD_ERR)) { - mpc5xxx_fec_rbd_clean(fec, pRbd); -#if (DEBUG & 0x8) - printf( "X0" ); + /* + * Get buffer address and size + */ + frame = (NBUF *)pRbd->dataPointer; + frame_length = pRbd->dataLength - 4; + +#if (DEBUG & 0x20) + { + int i; + printf("recv data hdr:"); + for (i = 0; i < 14; i++) + printf("%x ", *(frame->head + i)); + printf("\n"); + } #endif - return 0; + /* + * Fill the buffer and pass it to upper layers + */ + memcpy(buff, frame->head, 14); + memcpy(buff + 14, frame->data, frame_length); + NetReceive(buff, frame_length); + len = frame_length; + } + /* + * Reset buffer descriptor as empty + */ + mpc5xxx_fec_rbd_clean(fec, pRbd); } - - /* - * Get buffer address and size - */ - frame = (char *)pRbd->dataPointer; - frame_length = pRbd->dataLength; - - /* - * Pass the buffer to upper layers - */ - NetReceive(frame, frame_length); - - /* - * Reset buffer descriptor as empty - */ - mpc5xxx_fec_rbd_clean(fec, pRbd); - - return frame_length; + SDMA_CLEAR_IEVENT (FEC_RECV_TASK_NO); + return len; } @@ -806,15 +858,29 @@ int mpc5xxx_fec_initialize(bd_t * bis) { mpc5xxx_fec_priv *fec; struct eth_device *dev; + char *tmp, *end; + char env_enetaddr[6]; + int i; fec = (mpc5xxx_fec_priv *)malloc(sizeof(*fec)); dev = (struct eth_device *)malloc(sizeof(*dev)); + memset(dev, 0, sizeof *dev); fec->eth = (ethernet_regs *)MPC5XXX_FEC; fec->tbdBase = (FEC_TBD *)FEC_BD_BASE; fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD)); -#ifdef CONFIG_ICECUBE +#if defined(CONFIG_ICECUBE) || defined(CONFIG_PM520) || \ + defined(CONFIG_TOP5200) || defined(CONFIG_TQM5200) || \ + defined(CONFIG_INKA4X0) +# ifndef CONFIG_FEC_10MBIT fec->xcv_type = MII100; +# else + fec->xcv_type = MII10; +# endif +#elif defined(CONFIG_TOTAL5200) + fec->xcv_type = SEVENWIRE; +#else +#error fec->xcv_type not initialized. #endif dev->priv = (void *)fec; @@ -824,8 +890,25 @@ int mpc5xxx_fec_initialize(bd_t * bis) dev->send = mpc5xxx_fec_send; dev->recv = mpc5xxx_fec_recv; + sprintf(dev->name, "FEC ETHERNET"); eth_register(dev); + /* + * Try to set the mac address now. The fec mac address is + * a garbage after reset. When not using fec for booting + * the Linux fec driver will try to work with this garbage. + */ + tmp = getenv("ethaddr"); + if (tmp) { + for (i=0; i<6; i++) { + env_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0; + if (tmp) + tmp = (*end) ? end+1 : end; + } + mpc5xxx_fec_set_hwaddr(fec, env_enetaddr); + } + + mpc5xxx_fec_init_phy(dev, bis); return 1; } @@ -941,4 +1024,4 @@ static uint32 local_crc32(char *string, unsigned int crc_value, int len) } #endif /* DEBUG */ -#endif /* CONFIG_MPC5XXX_FEC */ +#endif /* CONFIG_MPC5xxx_FEC */