blob: af7488e04a5f4cdc6ae67e5a2cdeabe844d3ec6d [file] [log] [blame]
/** -----------------------------------------------------------------------------------------------------------------@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