| /** -----------------------------------------------------------------------------------------------------------------@n |
| * °æÈ¨ËùÓÐ(C)2000-2011, ÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾ |
| * |
| * ÎÄ ¼þ Ãû: drv_gmac.c @defgroup DRV_GMAC |
| * |
| * ×÷ Õß: ÕÔÀû±ó10113809 |
| * |
| * Ä£¿é¸ÅÊö: |
| * - <´Ë´¦ÌîÄ£¿é¸ÅÊö, ÌîÍêºó¿ÕÒ»ÐÐ> |
| * |
| * Ä£¿éÏêÊö: |
| * - <´Ë´¦ÌîÄ£¿éÏêÊö, ÌîÍêºó¿ÕÒ»ÐÐ> |
| * |
| * ÓÃÀý1: |
| * @code |
| * |
| * |
| * @endcode |
| * |
| * °æ ±¾: v0.0 |
| * |
| * ------------------------------------------------------------------------------------------------------------------ |
| * |
| * ÐÞ¸ÄÈÕÆÚ ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ |
| * @li 20120114 ÕÔÀû±ó10113809 ´´½¨ |
| * @li 20120907 ÕÔÀû±ó10113809 Ð޸ĴúÂëÖеÄbug |
| * @li 20120908 ÕÔÀû±ó10113809 Ð޸ĴúÂë¹æ·¶£¬µ÷Õû´úÂë½á¹¹ |
| * @li 20120910 ÕÔÀû±ó10113809 µ÷Õû´úÂë½á¹¹£¬Ôö¼Ó×¢ÊÍ£¬Ìí¼Ó¹¦ÄÜ |
| * @li 20120925 ÕÔÀû±ó10113809 µ÷Õû´úÂë½á¹¹£¬Ôö¼Ó×¢ÊÍ£¬Ìí¼Ó¹¦ÄÜ£¬ÓÃalignedÊôÐÔ½øÐÐ×Ö½Ú¶ÔÆë |
| * 20150302 ÐìÏÄÃô10180991 Ϊ7520sÐÞ¸Ä |
| * |
| * |
| * @n@{ --------------------------------------------------------------------------------------------------------------- */ |
| |
| #include <linux/string.h> /* ʹÓÃÀïÃæµÄmemcpyº¯Êý */ |
| #include <asm/arch/gmac.h> /* ʹÓÃÀïÃæµÄÊý¾ÝÀàÐͶ¨Òå BYTE WORD32Ö®ÀàµÄ */ |
| #include <common.h> |
| |
| //#define PHY_CLOCK 5 |
| #define GMAC_RX_DES_ADDR CONFIG_GMAC_DMA_BUF_ADDR |
| #define GMAC_TX_DES_ADDR (CONFIG_GMAC_DMA_BUF_ADDR+GMAC_RX_BUF_NUM*128) |
| |
| #define GMAC_RX_BUF_ADDR (CONFIG_GMAC_DMA_BUF_ADDR+0x800) |
| #define GMAC_TX_BUF_ADDR (CONFIG_GMAC_DMA_BUF_ADDR+0x1800) |
| //#define GMAC_TX_BUF_ADDR (CONFIG_GMAC_DMA_BUF_ADDR+0x8000) |
| |
| volatile unsigned int g_dwRxBdOffset = 0; |
| volatile unsigned int g_dwTxBdOffset = 0; |
| |
| /*--------------------------------------------------------------------------------------------------------------------- |
| * ÒÔÏÂͨ¹ý±àÒëÆ÷alignedÊôÐÔÉùÃ÷×Ö½Ú¶ÔÆë£¬´¦Àí·½Ê½±È½Ï·½±ã£¬´¦Àí´úÂë²»Ò׳ö´í£¬Ê¡È¥Á˲»ÉÙÈßÓàµÄ¼ÆË㣬µ«ÐèÒª±àÒëÆ÷Ö§ |
| * ³ÖcÀ©Õ¹ÊôÐÔ¡£ÃèÊö·û´óСΪ×Ö½Ú¶ÔÆëµÄÕûÊý±¶£¬±£Ö¤ÁËÊ×µØÖ·×Ö½Ú¶ÔÆëµÄÇé¿öÏÂÿ¸öÃèÊö·ûµØÖ·¶¼ÊÇ×Ö½Ú¶ÔÆëµÄ¡£Îª±£Ö¤Ã¿¸ö |
| * »º³åÇøµØÖ·¶¼ÊÇ×Ö½Ú¶ÔÆëµÄÐèÒª»º³åÇø´óСΪ×Ö½Ú¶ÔÆëµÄÕûÊý±¶¡£ |
| * |
| * ÔÚʵ¼ÊʹÓÃÖпª±ÙÊÕ·¢»º³åÇøÒ²¿ÉÒÔÔÚϵͳ¹æ»®ÄÚ´æÊ¹ÓõÄʱºò½øÐпª±Ù£¬Ö»ÒªÄܱ£Ö¤Ê×µØÖ··ûºÏmacÇý¶¯µÄµØÖ·¶ÔÆëÒªÇó¼´¿É£¬ |
| * È»ºóͨ¹ý²ÎÊý´«µÝµ½ÃèÊö·û³õʼ»¯º¯ÊýÖС£Êµ¼ÊÉÏ»º³åÇøÒ²¿ÉÒÔ²»¶ÔÆëÖ±½ÓʹÓ㬲»¹ýÐèÒª×öÒ»Ð©ÌØÊâ´¦Àí£¬ÌØ±ðÊǽÓÊÕ¶Ë¡£ |
| * |
| *--------------------------------------------------------------------------------------------------------------------*/ |
| //T_GMAC_RxDescr g_tRxDes[GMAC_RX_BUF_NUM]__attribute__((aligned(8))); |
| //T_GMAC_TxDescr g_tTxDes[GMAC_TX_BUF_NUM]__attribute__((aligned(8))); |
| |
| |
| T_GMAC_RxDescr *g_tRxDes = (T_GMAC_RxDescr *) GMAC_RX_DES_ADDR; |
| T_GMAC_TxDescr *g_tTxDes = (T_GMAC_TxDescr *) GMAC_TX_DES_ADDR; |
| |
| T_GMAC_DmaRegs *g_ptGmacDmaRegs = (T_GMAC_DmaRegs *) GMAC_DMA_ADDR_BASE; |
| T_GMAC_GmacRegs *g_ptGmacGmacRegs = (T_GMAC_GmacRegs *) GMAC_MAC_ADDR_BASE; |
| |
| |
| /*data in DDR*/ |
| //volatile BYTE g_RxBuf[GMAC_RX_BUF_SIZE * GMAC_RX_BUF_NUM]__attribute__((aligned(8))); |
| //volatile BYTE g_TxBuf[GMAC_TX_BUF_SIZE * GMAC_TX_BUF_NUM]__attribute__((aligned(8))); |
| |
| /*data in IRAM*/ |
| volatile BYTE *g_RxBuf = (volatile BYTE *) GMAC_RX_BUF_ADDR; |
| volatile BYTE *g_TxBuf = (volatile BYTE *) GMAC_TX_BUF_ADDR; |
| |
| WORD16 phyid = 0; |
| WORD32 autotimeout = 100000; |
| |
| static WORD16 mii_read(WORD32 tPhyAddr, WORD32 tPhyReg); |
| |
| static void zx_gmac_initBd(void) |
| { |
| unsigned int dwIdx; |
| T_GMAC_TxDescr *ptTxTmp; |
| T_GMAC_RxDescr *ptRxTmp; |
| |
| ptTxTmp = g_tTxDes; |
| g_dwTxBdOffset = 0; |
| for (dwIdx = 0; dwIdx < GMAC_TX_DESC_NUM; dwIdx++) |
| { |
| /* Initialize Tx descriptor ring */ |
| //ptTxTmp->dwDescr0 =0; |
| ptTxTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_TXINT | GMAC_DESC_TXSTS_TXCHAIN); |
| //ptTxTmp->dwDescr0 = GMAC_ENDIAN32_SWAP( GMAC_DESC_TXSTS_TXCHAIN); |
| //ptTxTmp->dwDescr0 |= ~ GMAC_ENDIAN32_SWAP( GMAC_DESC_TXSTS_OWNBYDMA); |
| ptTxTmp->dwDescr1 = GMAC_ENDIAN32_SWAP(GMAC_TX_BUF_SIZE & GMAC_DESC_TXCTRL_SIZE1MASK); |
| ptTxTmp->dwBuf1Addr = GMAC_ENDIAN32_SWAP((WORD32)&g_TxBuf[dwIdx * GMAC_TX_BUF_SIZE]); |
| ptTxTmp->ptNext = (T_GMAC_TxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(ptTxTmp+1))); |
| ptTxTmp++; |
| } |
| ptTxTmp--; |
| ptTxTmp->ptNext = (T_GMAC_TxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(g_tTxDes))); |
| ptTxTmp->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_TXRINGEND); |
| |
| ptRxTmp = g_tRxDes; |
| g_dwRxBdOffset = 0; |
| for(dwIdx = 0; dwIdx < GMAC_RX_DESC_NUM; dwIdx++) |
| { |
| //±êÃ÷½ÓÊÕÃèÊö·û±»dmaÕ¼Óà |
| ptRxTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(GMAC_DESC_RXSTS_OWNBYDMA); |
| ptRxTmp->dwDescr1 = GMAC_ENDIAN32_SWAP((GMAC_RX_BUF_SIZE & GMAC_DESC_RXCTRL_SIZE1MASK) | GMAC_DESC_RXCTRL_RXCHAIN); |
| ptRxTmp->dwBuf1Addr = GMAC_ENDIAN32_SWAP((WORD32)&g_RxBuf[dwIdx * GMAC_RX_BUF_SIZE]); |
| ptRxTmp->ptNext = (T_GMAC_RxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(ptRxTmp+1))); |
| ptRxTmp++; |
| } |
| |
| ptRxTmp--; |
| ptRxTmp->ptNext = (T_GMAC_RxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(g_tRxDes))); |
| ptRxTmp->dwDescr1 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_RXCTRL_RXRINGEND); |
| } |
| |
| |
| int zx_gmac_init(void) |
| { |
| |
| g_ptGmacDmaRegs->dwBusMode = GMAC_BUSMODE_SRST; // software reset all gmac subsystem inter registers and logic |
| |
| zx_gmac_initBd(); |
| |
| /* ËÙÂÊģʽҪÓëPHYµÄËÙÂÊÆ¥Åä */ |
| /*PS: Port Select Selects between GMII and MII:*/ |
| g_ptGmacGmacRegs->dwMacConfig = (GMAC_POART_MODE); |
| |
| /* µÈ´ý¸´Î»Íê³É*/ |
| /*SWR: Software Reset*/ |
| while((g_ptGmacDmaRegs->dwBusMode & GMAC_BUSMODE_SRST_MASK) == GMAC_BUSMODE_SRST) |
| { |
| /* cpuËٶȺܿ죬ÉÏÃæ½øÐÐËÙÂÊÆ¥Åäʱ¼Ä´æÆ÷Ä£¿é»¹Ã»Óи´Î»³É¹¦£¬ÕâÀïÖØÐÂÆ¥Åä */ |
| g_ptGmacGmacRegs->dwMacConfig = (GMAC_POART_MODE); |
| } |
| |
| //É趨PBL: Programmable Burst Length |
| g_ptGmacDmaRegs->dwBusMode &= (~GMAC_BUSMODE_PBL_MASK); |
| g_ptGmacDmaRegs->dwBusMode |= ( GMAC_BUSMODE_PBL_8& GMAC_BUSMODE_PBL_MASK); |
| |
| //g_ptGmacDmaRegs->dwRxDesListAddr = ((WORD32)&g_RxBd[0] + 0x7) & 0xFFFFFFF8; |
| //g_ptGmacDmaRegs->dwTxDesListAddr = ((WORD32)&g_TxBd[0] + 0x7) & 0xFFFFFFF8; |
| //g_ptGmacDmaRegs->dwRxDesListAddr = ((WORD32)g_ptRxDes); |
| //g_ptGmacDmaRegs->dwTxDesListAddr = ((WORD32)g_ptTxDes); |
| g_ptGmacDmaRegs->dwRxDesListAddr = ((WORD32)g_tRxDes); |
| g_ptGmacDmaRegs->dwTxDesListAddr = ((WORD32)g_tTxDes); |
| |
| g_ptGmacDmaRegs->dwStatus = 0x0001ffff; //write 1 to clear init |
| g_ptGmacDmaRegs->dwIntEnable = (GMAC_INT_TIE|GMAC_INT_RIE|GMAC_INT_NIE); //interrupt is disable |
| //g_ptGmacDmaRegs->dwIntEnable = (GMAC_INT_ERE|GMAC_INT_ETE|GMAC_INT_TIE|GMAC_INT_RIE|GMAC_INT_NIE); |
| //g_ptGmacDmaRegs->dwIntEnable = 0x1e7ff; |
| //g_ptGmacDmaRegs->dwIntEnable = 0x180f5; // linux gmac |
| |
| |
| while(g_ptGmacGmacRegs->dwGMIIAddr & GMAC_GMII_BUSY); |
| |
| /* ¸´Î»ÉèÖÃport selectºóÆäËû±ÈÌØÎ»¶¼Îª0 Òò´ËûÓнøÐÐÇå0²Ù×÷ */ |
| g_ptGmacGmacRegs->dwMacConfig |= (GMAC_MAC_100M | GMAC_MAC_NORMAL | GMAC_MAC_DUPLEX_MODE ); |
| //g_ptGmacGmacRegs->dwMacConfig |= (GMAC_MAC_10M | GMAC_MAC_NORMAL | GMAC_MAC_DUPLEX_MODE ); |
| |
| //g_ptGmacGmacRegs->dwMacConfig |= (GMAC_MAC_100M | GMAC_MAC_LOOP | GMAC_MAC_DUPLEX_MODE ); |
| g_ptGmacGmacRegs->dwMacFrameFilter &= ~(GMAC_MAC_RCVALL_EN); |
| g_ptGmacGmacRegs->dwMacFrameFilter |= (GMAC_MAC_RCVALL_EN); |
| //g_ptGmacGmacRegs->dwMacFrameFilter |= (1 << 0); |
| |
| //TSF: Transmit Store and Forward |
| //g_ptGmacDmaRegs->dwOpMode |= (dwMode & (GMAC_DMA_TSF | GMAC_DMA_RSF)); |
| |
| g_ptGmacDmaRegs->dwOpMode |= (1 << 1); //enable dma |
| g_ptGmacDmaRegs->dwOpMode |= (1 << 13); |
| |
| g_ptGmacDmaRegs->dwOpMode |= (1 << 3); //useful when rsf |
| g_ptGmacDmaRegs->dwOpMode |= (1 << 4); |
| g_ptGmacDmaRegs->dwOpMode |= (1 << 14);//useful when tsf |
| // g_ptGmacDmaRegs->dwOpMode = 0x601a; |
| |
| g_ptGmacGmacRegs->dwMacConfig |= (1 << 3); //enable mac rt tx |
| g_ptGmacGmacRegs->dwMacConfig |= (1 << 2); |
| printf("Mac Config = %x\n",g_ptGmacGmacRegs->dwMacConfig); |
| //g_ptGmacGmacRegs->dwMacConfig = 0x0040c80c; |
| return 0; |
| } |
| |
| void zx_gmac_stop(void) |
| { |
| g_ptGmacDmaRegs->dwOpMode &= ~ ((1 << 1)|(1 << 13)); //disable dma |
| g_ptGmacGmacRegs->dwMacConfig &= ~ ((1 << 2)|(1 << 3)); //disable mac rxtx |
| g_ptGmacDmaRegs->dwIntEnable = 0x00; //disable dma interrupt |
| |
| g_ptGmacDmaRegs->dwOpMode |= 1 << 20; //clear tx fifo |
| while(g_ptGmacDmaRegs->dwOpMode & (1 << 20)); //wait for clear tx fifo |
| } |
| |
| int zx_gmac_send(BYTE *const txdata,const WORD32 txlen) |
| { |
| T_GMAC_TxDescr *ptTmp; |
| T_GMAC_TxDescr *ptFirstBd; |
| BYTE *pBuf; |
| WORD32 dwBdNum = 0; |
| WORD32 dwTmplen = txlen; |
| WORD32 dwBdOffset = g_dwTxBdOffset; |
| WORD32 dwIdx; |
| |
| WORD16 tval=0; |
| |
| /* Ö»Óûñȡһ´Î¾Í¿ÉÒÔ Öмä¹ý³Ì»áͬ²½È«¾Ö±äÁ¿rd_bd_offsetÓëÃèÊö·ûÁ´±í */ |
| //ptTmp = (T_GMAC_TxDescr *)(((WORD32)&g_TxBd[g_dwTxBdOffset*sizeof(T_GMAC_TxDescr)] + 0x7) & 0xFFFFFFF8); |
| ptTmp = &g_tTxDes[g_dwTxBdOffset]; |
| |
| if((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_TXSTS_OWNBYDMAMASK) == GMAC_DESC_TXSTS_OWNBYDMA) |
| { |
| printf("ERROR: GMAC DESC TXSTS OWN BY DMA\n"); |
| return 1; |
| } |
| |
| ptFirstBd = ptTmp; |
| pBuf = txdata; |
| |
| while(1) |
| { |
| /* »¹ÐèÒªÅÐ¶Ï ÒòΪ²»Ö»ÊÇÉÏÃæÐèÒªÅжÏownλ */ |
| if ((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_TXSTS_OWNBYDMAMASK) != GMAC_DESC_TXSTS_OWNBYDMA) |
| { |
| ptTmp->dwDescr0 &= GMAC_ENDIAN32_SWAP(~(GMAC_DESC_TXSTS_TXLAST | GMAC_DESC_TXSTS_TXFIRST)); |
| if(dwTmplen == txlen) |
| { |
| ptTmp->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_TXFIRST); |
| ptFirstBd->dwDescr0 &= GMAC_ENDIAN32_SWAP(~(GMAC_DESC_TXSTS_OWNBYDMAMASK)); //show this bd has data wait for tx |
| } |
| |
| if(dwTmplen > GMAC_TX_BUF_SIZE) |
| { |
| memcpy((void *)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), (void *)pBuf, GMAC_TX_BUF_SIZE);//long frame |
| // ptTmp->dwBuf1Addr = (WORD32)pBuf; |
| ptTmp->dwDescr1 &= GMAC_ENDIAN32_SWAP(~GMAC_DESC_TXCTRL_SIZE1MASK); |
| ptTmp->dwDescr1 |= GMAC_ENDIAN32_SWAP(GMAC_TX_BUF_SIZE & GMAC_DESC_TXCTRL_SIZE1MASK); |
| pBuf += GMAC_TX_BUF_SIZE; |
| if(ptFirstBd != ptTmp) |
| { |
| ptTmp->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_OWNBYDMA); |
| } |
| |
| ptTmp = (T_GMAC_TxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(ptTmp->ptNext))); |
| dwTmplen -= GMAC_TX_BUF_SIZE; |
| dwBdNum++; |
| g_dwTxBdOffset = (g_dwTxBdOffset+1)%GMAC_TX_DESC_NUM; |
| } |
| else |
| { |
| memcpy((void *)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), (void *)pBuf, dwTmplen); |
| //ptTmp->dwBuf1Addr = (WORD32)pBuf; |
| pBuf += dwTmplen; |
| /* Ôö¼ÓÏÂÃæÒ»ÐдúÂë, ½â¾öbug, ½«Êý¾Ý³¤¶È×Ö¶ÎÏÈÇå0ÔÙ¸³Öµ, ·ñÔò²»Äܵõ½Ô¤ÆÚµÄÊý¾Ý³¤¶È */ |
| /* »·»Ø²âÊÔÖе¼ÖÂÃèÊö·ûËùÔÚÄÚ´æµØÖ·±»¸²¸Ç£¬µ±È»Ò²¿ÉÄܲúÉúÆäËûÏÖÏ󣬱¾ÖʾÍÊÇÉÏÊöÔÒò 2010.09.07 */ |
| ptTmp->dwDescr1 &= GMAC_ENDIAN32_SWAP(~GMAC_DESC_TXCTRL_SIZE1MASK); |
| ptTmp->dwDescr1 |= GMAC_ENDIAN32_SWAP(dwTmplen & GMAC_DESC_TXCTRL_SIZE1MASK); |
| ptTmp->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_TXLAST); |
| ptTmp->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_OWNBYDMA); |
| |
| for ( dwIdx = 0; dwIdx < 100; dwIdx++ ); /* delay */ |
| //ptFirstBd->dwDescr0 |= GMAC_ENDIAN32_SWAP(GMAC_DESC_TXSTS_OWNBYDMA); //due to bd only two ,not necessary |
| |
| if(((g_ptGmacDmaRegs->dwStatus >> 20) & 0x7) == 0x6) /*Èç¹ûDMAÍ£Ö¹¹¤×÷£¬Æô¶¯DMA¹¤×÷*/ |
| { |
| //Print("Reg = %x\n",g_ptGmacDmaRegs->dwStatus); |
| g_ptGmacDmaRegs->dwTxPollDemand = 1; |
| |
| } |
| else |
| { |
| printf("Reg = %x\n",g_ptGmacDmaRegs->dwStatus); |
| //g_ptGmacDmaRegs->dwTxPollDemand = 1; |
| } |
| //mac_tx_enable(); |
| //memset((void *)ptTmp->Buf1Addr, 0, dwTmplen); |
| g_dwTxBdOffset = (g_dwTxBdOffset+1)%GMAC_TX_DESC_NUM; |
| |
| return 0; |
| } |
| } |
| else |
| { |
| ptTmp = ptFirstBd; |
| while(dwBdNum--) |
| { |
| ptTmp->dwDescr0 &= GMAC_ENDIAN32_SWAP(~(GMAC_DESC_TXSTS_OWNBYDMAMASK)); |
| ptTmp = (T_GMAC_TxDescr *)(GMAC_ENDIAN32_SWAP((WORD32)(ptTmp->ptNext))); |
| } |
| g_ptGmacDmaRegs->dwTxPollDemand = 1; |
| g_dwTxBdOffset = dwBdOffset; |
| return 1; |
| } |
| } |
| } |
| |
| int zx_gmac_getbd(WORD32 bdnum) |
| { |
| T_GMAC_RxDescr *ptTmp; |
| if(bdnum > GMAC_RX_DESC_NUM) |
| { |
| printf("buffer description num error\n"); |
| return 1; |
| } |
| ptTmp = &g_tRxDes[bdnum]; |
| if((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_OWNBYDMAMASK) != GMAC_DESC_RXSTS_OWNBYDMA) //check rx bd descr0 bit31 is 0 ,show that data come |
| return 1; |
| |
| return 0; |
| } |
| |
| int zx_gmac_rx(BYTE *const prxbuf, WORD32 *const prxlen,WORD32 bdnum) |
| { |
| T_GMAC_RxDescr *ptTmp; |
| WORD32 dwRet; |
| WORD32 dwTmpLen; |
| BYTE *pBuf = NULL; |
| int sdFirstBd=0; |
| |
| /* Ö»Óûñȡһ´Î¾Í¿ÉÒÔ Öмä¹ý³Ì»áͬ²½È«¾Ö±äÁ¿rd_bd_offsetÓëÃèÊö·ûÁ´±í */ |
| //ptTmp = (T_GMAC_RxDescr *)(((WORD32)&g_RxBd[g_dwRxBdOffset*sizeof(T_GMAC_RxDescr)] + 0x7) & 0xFFFFFFF8); |
| //ptTmp = &g_tRxDes[g_dwRxBdOffset]; |
| ptTmp = &g_tRxDes[bdnum]; |
| if(ptTmp == 0) |
| { |
| printf("ERROR: g_tRxDes == 0\n"); |
| return 0; |
| } |
| |
| if((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_OWNBYDMAMASK) == GMAC_DESC_RXSTS_OWNBYDMA) |
| { |
| printf("ERROR: GMAC DESC RXSTS OWN BY DMA\n"); |
| return 0; |
| } |
| |
| pBuf = prxbuf; |
| dwTmpLen = 0; |
| |
| //memset((void*)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)),0,0x200); |
| |
| while((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_OWNBYDMAMASK) != GMAC_DESC_RXSTS_OWNBYDMA) |
| { |
| if((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXES) == GMAC_DESC_RXSTS_RXES) |
| { |
| printf("ERROR: GMAC RX DESC ERROR : "); |
| if((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXCE) == GMAC_DESC_RXSTS_RXCE) |
| { |
| printf("CRC Error\n"); |
| return 0; |
| } |
| else |
| { |
| //printf("\nRX DESC: GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0)=%x\n", GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0)); |
| } |
| } |
| |
| //Èç¹ûÖ»ÓÐÒ»¸ö½ÓÊÕÃèÊö·ûÓÐÊý¾Ý(¼ÈÊǵÚÒ»¸ö£¬ÓÖÊÇ×îºóÒ»¸ö) |
| if(((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXFIRST) == GMAC_DESC_RXSTS_RXFIRST) |
| && ((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXLAST) == GMAC_DESC_RXSTS_RXLAST)) |
| { |
| dwRet = (((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_FRAMELENMASK) |
| >> GMAC_DESC_RXSTS_FRAMELENSHFT)-4); // remove 4 bytes crc |
| |
| memcpy((void*)pBuf,(void*)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), dwRet); |
| |
| //memset((void*)ptTmp->dwBuf1Addr, 0, (ptTmp->dwDescr1 & 0x1FFF)); |
| ptTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(GMAC_DESC_RXSTS_OWNBYDMA); |
| /*Èç¹ûDMAÍ£Ö¹¹¤×÷£¬Æô¶¯DMA¹¤×÷*/ |
| if(((g_ptGmacDmaRegs->dwStatus >> 17) & 0x7) == 0x4) |
| { |
| g_ptGmacDmaRegs->dwRxPollDemand = 1; |
| } |
| |
| //g_dwRxBdOffset = (g_dwRxBdOffset+1)%GMAC_RX_DESC_NUM; |
| return dwRet; |
| } |
| |
| //Èç¹ûÊǵÚÒ»¸ö½ÓÊÕÃèÊö·û(ºóÃæ»¹ÓнÓÊÕÃèÊö·û) |
| if(((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXFIRST) == GMAC_DESC_RXSTS_RXFIRST) |
| && ((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXLAST) != GMAC_DESC_RXSTS_RXLAST)) |
| { |
| memcpy((void*)pBuf,(void*)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), (GMAC_ENDIAN32_SWAP(ptTmp->dwDescr1) & 0x1FFF)); |
| pBuf += (GMAC_ENDIAN32_SWAP(ptTmp->dwDescr1) & 0x1FFF); |
| dwTmpLen += GMAC_RX_BUF_SIZE; |
| ptTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(0x1u << 31); |
| /*Èç¹ûDMAÍ£Ö¹¹¤×÷£¬Æô¶¯DMA¹¤×÷*/ |
| if(((g_ptGmacDmaRegs->dwStatus >> 17) & 0x7) == 0x4) |
| { |
| g_ptGmacDmaRegs->dwRxPollDemand = 1; |
| } |
| |
| //g_dwRxBdOffset = (g_dwRxBdOffset+1)%GMAC_RX_DESC_NUM; |
| sdFirstBd = 1; |
| ptTmp = (T_GMAC_RxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(ptTmp->ptNext))); |
| |
| continue; |
| } |
| |
| //Èç¹ûÊÇ×îºóÒ»¸ö½ÓÊÕÃèÊö·û(µ«²»ÊǵÚÒ»¸ö½ÓÊÕÃèÊö·û) |
| if(((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXFIRST) != GMAC_DESC_RXSTS_RXFIRST) |
| && ((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXLAST) == GMAC_DESC_RXSTS_RXLAST) |
| && sdFirstBd == 1) |
| { |
| dwRet = (((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) >> 16) & 0x3FFF)-4); |
| memcpy((void*)pBuf,(void*)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), (dwRet-dwTmpLen)); |
| ptTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(GMAC_DESC_RXSTS_OWNBYDMA); |
| /*Èç¹ûDMAÍ£Ö¹¹¤×÷£¬Æô¶¯DMA¹¤×÷*/ |
| if(((g_ptGmacDmaRegs->dwStatus >> 17) & 0x7) == 0x4) |
| { |
| g_ptGmacDmaRegs->dwRxPollDemand = 1; |
| } |
| |
| //g_dwRxBdOffset = (g_dwRxBdOffset+1)%GMAC_RX_DESC_NUM; |
| return dwRet; |
| } |
| |
| //Èç¹û¼È²»ÊǵÚÒ»¸ö£¬Ò²²»ÊÇ×îºóÒ»¸ö½ÓÊÕÃèÊö·û |
| if(((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXFIRST) != GMAC_DESC_RXSTS_RXFIRST) |
| && ((GMAC_ENDIAN32_SWAP(ptTmp->dwDescr0) & GMAC_DESC_RXSTS_RXLAST) != GMAC_DESC_RXSTS_RXLAST) |
| && sdFirstBd == 1) |
| { |
| memcpy((void*)pBuf,(void*)(GMAC_ENDIAN32_SWAP(ptTmp->dwBuf1Addr)), (GMAC_ENDIAN32_SWAP(ptTmp->dwDescr1) & 0x1FFF)); |
| pBuf += (GMAC_ENDIAN32_SWAP(ptTmp->dwDescr1) & 0x1FFF); |
| dwTmpLen += GMAC_RX_BUF_SIZE; |
| ptTmp->dwDescr0 = GMAC_ENDIAN32_SWAP(GMAC_DESC_RXSTS_OWNBYDMA); |
| /*Èç¹ûDMAÍ£Ö¹¹¤×÷£¬Æô¶¯DMA¹¤×÷*/ |
| if(((g_ptGmacDmaRegs->dwStatus >> 17) & 0x7) == 0x4) |
| { |
| g_ptGmacDmaRegs->dwRxPollDemand = 1; |
| } |
| //g_dwRxBdOffset = (g_dwRxBdOffset+1)%GMAC_RX_DESC_NUM; |
| ptTmp = (T_GMAC_RxDescr*)(GMAC_ENDIAN32_SWAP((WORD32)(ptTmp->ptNext))); |
| } |
| |
| if(sdFirstBd == 0) |
| { |
| printf("ERROR: RX DESC lost first bd\n");/*lost first bd */ |
| break; |
| } |
| } |
| return dwTmpLen; |
| } |
| |
| static void mii_write(WORD32 tPhyAddr, WORD32 tPhyReg, WORD16 tData) |
| { |
| while(g_ptGmacGmacRegs->dwGMIIAddr & GMAC_GMII_BUSY); |
| |
| g_ptGmacGmacRegs->dwGMIIData = (WORD32)tData; |
| |
| g_ptGmacGmacRegs->dwGMIIAddr = (GMAC_GMII_MDC << GMAC_GMII_MDC_SHIFT); |
| |
| g_ptGmacGmacRegs->dwGMIIAddr |= ((tPhyAddr << GMAC_GMII_ADDR_SHIFT) & GMAC_GMII_ADDR_MSK) |
| | ((tPhyReg << GMAC_GMII_PHYREG_SHIFT) & GMAC_GMII_PHYREG_MSK) |
| | GMAC_GMII_WRITE |
| | GMAC_GMII_BUSY; |
| |
| while(g_ptGmacGmacRegs->dwGMIIAddr & GMAC_GMII_BUSY); |
| } |
| |
| |
| static WORD16 mii_read(WORD32 tPhyAddr, WORD32 tPhyReg) |
| { |
| while(g_ptGmacGmacRegs->dwGMIIAddr & GMAC_GMII_BUSY); |
| |
| g_ptGmacGmacRegs->dwGMIIAddr = (GMAC_GMII_MDC << GMAC_GMII_MDC_SHIFT);//clock 3 35~60MHZ ʱÖÓλ |
| |
| g_ptGmacGmacRegs->dwGMIIAddr |= ((tPhyAddr << GMAC_GMII_ADDR_SHIFT) & GMAC_GMII_ADDR_MSK) |
| | ((tPhyReg << GMAC_GMII_PHYREG_SHIFT) & GMAC_GMII_PHYREG_MSK) |
| | GMAC_GMII_BUSY; |
| |
| while(g_ptGmacGmacRegs->dwGMIIAddr & GMAC_GMII_BUSY); |
| |
| return (WORD16)(g_ptGmacGmacRegs->dwGMIIData&0xFFFF); /* 0xFFFF: 16λÊý¾ÝÑÚÂë */ |
| |
| } |
| |
| #if (GMAC_PHY_USE == GMAC_PHY_88E1111) |
| int gmac_phy_led(WORD32 tphyid,WORD32 ledctrl,WORD32 lednum) |
| { |
| WORD32 tphy; |
| WORD16 tval=0; |
| WORD16 tctrl=0; |
| WORD32 tcount=0; |
| |
| tphy = tphyid; |
| if(lednum > GMAC_PHY_LED_MAX) |
| return 1; |
| |
| if(ledctrl) |
| { |
| tctrl = mii_read(tphy, GMAC_PHY_LED_CTRL_REG); |
| tval = mii_read(tphy, GMAC_PHY_LED_MANUAL_REG); |
| |
| mii_write(tphy, GMAC_PHY_LED_CTRL_REG, tctrl|(1<<15)); /*¿ªÆôled ¹¦ÄÜÜ */ |
| |
| tval &= ~(0x1 << (lednum-1)); |
| mii_write(tphy, GMAC_PHY_LED_MANUAL_REG,tval); |
| tcount++; |
| } |
| else |
| { |
| tctrl = mii_read(tphy, GMAC_PHY_LED_CTRL_REG); |
| tval = mii_read(tphy, GMAC_PHY_LED_MANUAL_REG); |
| |
| tval |= (0x1 << (lednum-1)); |
| mii_write(tphy, GMAC_PHY_LED_MANUAL_REG,tval); |
| tcount--; |
| |
| if(tcount == 0) |
| mii_write(tphy, GMAC_PHY_LED_CTRL_REG, tctrl&(~(1<<15))); /* ½ûÖ¹Led ¹¦ÄÜ¿ */ |
| } |
| return 0; |
| |
| } |
| |
| void gmac_phy_setclock(WORD32 tphyid) |
| { |
| WORD32 tphy; |
| WORD16 tval=0; |
| |
| tphy = tphyid; |
| |
| mii_write(tphy, 27, 0x800F); /* GMII PORT to Copper */ |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| mii_write(tphy, 22, 0x00); /* */ |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| mii_write(tphy, 30, 0x00); /* */ |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| mii_write(tphy, 20, 0x51); /* 100M 25MHZ*/ |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| //mii_write(tphy, 0, 0x3100); /* 100M Full Duplex, Autonegotiation */ |
| mii_write(tphy, 0, 0x3100); /* 100M half Duplex, Autonegotiation */ |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| } |
| |
| int gmac_phy_init(void) |
| { |
| WORD32 i; |
| WORD32 tphy; |
| WORD16 tval=0; |
| // »ñÈ¡µÚÒ»¸öPHYµÄÐòºÅ¼°ID |
| WORD32 val; |
| |
| val = *(volatile WORD32 *)(0x01306114); |
| //*(volatile WORD32 *)(0x01306114) = val & 0xFFFE; //¸´Î»gmac top |
| //*(volatile WORD32 *)(0x01306114) = val | 0x01; |
| |
| //*(volatile WORD32 *)(0x01306114) = val & 0xFFFd; //¸´Î»gmac bus |
| //*(volatile WORD32 *)(0x01306114) = val | 0x02; |
| |
| *(volatile WORD32 *)(0x01306114) = val & 0xFFDF; //¸´Î»gmac |
| *(volatile WORD32 *)(0x01306114) = val | 0x20; |
| |
| |
| for(i = 0; i < PHY_88E1111_MAX_NUM; i++) |
| { |
| tval = mii_read(i, PHY_88E1111_PHYIDR1); |
| if(tval == GMAC_PHY_88E1111_ID) |
| { |
| tphy = i; |
| break; |
| } |
| } |
| if(PHY_88E1111_MAX_NUM == i) |
| { |
| printf("Error: can not find phy 88E1111\n"); |
| return 1; |
| } |
| phyid = tphy; |
| gmac_phy_setclock(tphy); |
| |
| mii_write(tphy, 16, 0x38); |
| |
| /* Disable Auto-Selection when loopback */ |
| tval = mii_read(tphy, 27); |
| tval = tval | (0x1<<15); |
| mii_write(tphy, 27, tval); |
| |
| /*software reset*/ |
| tval = mii_read(tphy, 0); |
| mii_write(tphy, 0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| /* Disable Autonegotiation */ |
| tval = mii_read(tphy, 0x0); |
| tval = tval & (~(0x1 << 12)); |
| mii_write(tphy, 0x0, tval); |
| /*software reset*/ |
| tval = mii_read(tphy, 0x0); |
| mii_write(tphy, 0x0, tval | ( 1 << 15)); |
| while( mii_read(tphy, 0x0) & ( 1 << 15)); |
| |
| /* enable led,set tx led*/ |
| tval = mii_read(tphy, 24); |
| mii_write(tphy, 24, tval & 0x7fbe); |
| tval = mii_read(tphy, 24); |
| mii_write(tphy, 24, tval | ( 1 << 1)); |
| |
| /* set phy tx and crc error count*/ |
| //tval = mii_read(tphy, 29); |
| mii_write(tphy, 29, 0x0010); |
| //tval = mii_read(tphy, 30); |
| mii_write(tphy, 30, 0x0001); |
| //tval = mii_read(tphy, 29); |
| mii_write(tphy, 29, 0x000c); |
| |
| // tval = mii_read(tphy, 29); |
| mii_write(tphy, 18, 0xff); |
| |
| /* enable phyloopback */ |
| //tval = mii_read(tphy, 0x0); |
| //tval = tval | (0x1 << 14); |
| //mii_write(tphy, 0x0, tval); |
| |
| |
| /* Debug */ |
| tval = mii_read(tphy, 0x0); |
| printf("Phy Reg0 = %x\n",(u32)tval); |
| return 0; |
| } |
| #endif |
| |
| #if (GMAC_PHY_USE == GMAC_PHY_IP101A) |
| void gmac_phy_setclock(WORD32 tphyid) |
| { |
| WORD32 tphy; |
| WORD16 tval=0; |
| |
| tphy = tphyid; |
| |
| /*software reset*/ |
| mii_write(tphy, MII_BMCR, BMCR_RESET); |
| while( mii_read(tphy, MII_BMCR) & BMCR_RESET); |
| #if 0 |
| #if 1 |
| tval = mii_read(tphy, MII_BMCR); |
| tval |= (BMCR_LOOPBACK); /* enable loopback */ |
| mii_write(tphy, MII_BMCR, tval); |
| #endif |
| |
| tval = mii_read(tphy, MII_BMCR); |
| tval |= (BMCR_FULLDPLX | BMCR_SPEED100); /* 100M Full Duplex, disAutonegotiation */ |
| tval &= ~BMCR_ANENABLE; //disable auto-negotiation |
| mii_write(tphy, MII_BMCR, tval); |
| |
| tval = mii_read(tphy, 16); |
| tval |= (0x1<<11); /* disAutonegotiation dis midx*/ |
| mii_write(tphy, 16, tval); |
| #endif |
| |
| } |
| |
| //char TYPE = 0; |
| int gmac_phy_init(void) |
| { |
| WORD32 i = 0,j = 0; |
| WORD32 tphy = 0,autospeed = 0,autoduplex = 0; |
| WORD16 tval=0; |
| WORD32 val = 0,utmp = 0; |
| |
| val = *(volatile WORD32 *)(0x013C020); |
| *(volatile WORD32 *)(0x013C020) = val | (0x1<9); // GPIO cfg rmii_clk_o |
| *(volatile WORD32 *)(0x0013B11C) = 0x00000005; //enable rmii clock RMII_CLOCK_CFG |
| |
| val = *(volatile WORD32 *)(0x013C020); |
| *(volatile WORD32 *)(0x013C020) = val | (0x1<18); // GPIO cfg rmii_clk_o |
| |
| val = *(volatile WORD32 *)(0x00140150); |
| //*(volatile WORD32 *)(0x00140150) = val & 0xFFFFFFEF ; // GMAC_MOD_CFG gmac phy reset |
| |
| *(volatile WORD32 *)(0x00140150) = val | 0x10 ; |
| udelay(200); //IP101A phy delay >10ms ²Åok |
| |
| |
| // »ñÈ¡µÚÒ»¸öPHYµÄÐòºÅ¼°ID |
| for(i = 0; i < IP101A_PHY_MAX_NUM; i++) |
| { |
| tval = mii_read(i, MII_PHYSID1); |
| printf("Phy Reg%d = %x\n",(s32)i,(u32)tval); |
| if(tval == IP101A_PHY_ID) |
| { |
| tphy = i; |
| phyid = tphy; |
| break; |
| } |
| } |
| if(IP101A_PHY_MAX_NUM == i) |
| { |
| printf("Error: can not find phy IP101A\n"); |
| return -1; |
| } |
| |
| gmac_phy_setclock(tphy); |
| |
| mii_write(tphy, MII_ADVERTISE, 0x1E1); |
| tval = BMCR_ANENABLE | BMCR_ANRESTART; |
| mii_write(tphy, MII_BMCR, tval); |
| |
| /* ²éѯ×ÔÐÉÌÊÇ·ñÍê³É */ |
| while(autotimeout) |
| //while(1) |
| { |
| tval = mii_read(tphy, MII_BMSR); |
| if(tval&BMSR_ANEGCOMPLETE) |
| { |
| break; |
| } |
| autotimeout--; |
| } |
| if(autotimeout == 0) |
| { |
| printf("phy IP101A auto negotiation failed\n"); |
| return -1; |
| } |
| /* ²éѯÊÇ·ñÁ¬½ÓÉÏ*/ |
| tval = mii_read(tphy, MII_LPA); |
| autospeed = tval & LPA_100 ? GMAC_PHY_SPEED_100 : GMAC_PHY_SPEED_10; |
| autoduplex = (mii_read(tphy, MII_BMCR) & 0x0100) >> 8; |
| if(autospeed == GMAC_PHY_SPEED_100) |
| { |
| printf("phy IP101A auto negotiation speed is 100M\n"); |
| } |
| else |
| { |
| printf("phy IP101A auto negotiation speed is 10M\n"); |
| } |
| |
| if(autoduplex == GMAC_PHY_DUPLEX_FULL) |
| { |
| printf("phy IP101A auto negotiation duplex is full\n"); |
| } |
| else |
| { |
| printf("phy IP101A auto negotiation duplex is half\n"); |
| } |
| |
| return 0; |
| } |
| #endif |
| |