📄 emac.c
字号:
{
/* two words at a time, packet and control */
rx_desc_addr = (DWORD *)(RX_DESCRIPTOR_ADDR + i * 8);
*rx_desc_addr = (DWORD)(EMAC_RX_BUFFER_ADDR + i * EMAC_BLOCK_SIZE);
*(rx_desc_addr+1) = (DWORD)(EMAC_RX_DESC_INT | (EMAC_BLOCK_SIZE - 1)); /* set size only */
}
for ( i = 0; i < EMAC_RX_DESCRIPTOR_COUNT; i++ )
{
/* RX status, two words, status info. and status hash CRC. */
rx_status_addr = (DWORD *)(RX_STATUS_ADDR + i * 8);
*rx_status_addr = (DWORD)0; /* initially, set both status info and hash CRC to 0 */
*(rx_status_addr+1) = (DWORD)0;
}
MAC_RXCONSUMEINDEX = 0x0; /* RX descriptor points to zero */
return;
}
/*****************************************************************************
** Function name: EMACInit
**
** Descriptions: initialize EMAC port
**
** parameters: None
** Returned value: None
**
*****************************************************************************/
DWORD EMACInit( void )
{
DWORD regVal;
DWORD i;
/* turn on the ethernet MAC clock in PCONP, bit 30 */
regVal = PCONP;
regVal |= PCONP_EMAC_CLOCK;
PCONP = regVal;
/*------------------------------------------------------------------------------
* write to PINSEL2/3 to select the PHY functions on P1[17:0]
*-----------------------------------------------------------------------------*/
/* documentation needs to be updated */
#if RMII
/* P1.6, ENET-TX_CLK, has to be set for EMAC to address a BUG in the engineering
version, even if this pin is not used for RMII interface. This bug has been fixed,
and this port pin can be used as GPIO pin in the future release. */
/* Unfortunately, this MCB2300 board still has the old eng. version LPC23xx chip
on it. */
PINSEL2 = 0x50151105; /* selects P1[0,1,4,8,9,10,14,15] */
PINSEL3 = 0x00000005; /* selects P1[17:16] */
#else
PINSEL2 = 0x55555555; /* selects P1[15:0] */
PINSEL3 = 0x00000005; /* selects P1[17:16] */
#endif
/*-----------------------------------------------------------------------------
* write the MAC config registers
*----------------------------------------------------------------------------*/
MAC_MAC1 = 0xCF00; /* [15],[14],[11:8] -> soft resets all MAC internal modules */
MAC_COMMAND = 0x0038; /* reset all datapaths and host registers */
for ( i = 0; i < 0x04; i++ ); /* short delay after reset */
MAC_MAC1 = 0x0; /* deassert all of the above soft resets in MAC1 */
/* after the EMAC reset, if the module ID doesn't match, no need to
go any further. The major and minor revisions are in bit 0~15, not checked here. */
regVal = MAC_MODULEID;
if ( regVal != PHILIPS_EMAC_MODULE_ID )
{
return ( FALSE );
}
EMAC_TxDisable();
EMAC_RxDisable();
MAC_MAC2 = 0x00; /* initialize MAC2 register to default value */
/* Non back to back inter-packet gap */
MAC_IPGR = 0x0012; /* use the default value recommended in the users manual */
MAC_CLRT = 0x370F; /* Use the default value in the users manual */
MAC_MAXF = 0x0600; /* Use the default value in the users manual */
/* by default, in MAC_COMMAND, bit 9 is set to zero, in MII mode */
if ( PHYInit() == FALSE )
{
return ( FALSE );
}
/* write the station address registers */
MAC_SA0 = EMAC_ADDR12;
MAC_SA1 = EMAC_ADDR34;
MAC_SA2 = EMAC_ADDR56;
if ( (Speed == SPEED_10) && (Duplex == HALF_DUPLEX) )
{
MAC_MAC2 = 0x30; /* half duplex, CRC and PAD enabled. */
MAC_SUPP &= ~0x0100; /* RMII Support Reg. speed is set to 10M */
#if RMII
MAC_COMMAND |= 0x0240;
#else
MAC_COMMAND |= 0x0040; /* [10]-half duplex,[9]-MII mode,[6]-Pass runt frame,
[5]-RxReset */
#endif
/* back to back int-packet gap */
MAC_IPGT = 0x0012; /* IPG setting in half duplex mode */
}
else if ( (Speed == SPEED_100) && (Duplex == HALF_DUPLEX) )
{
MAC_MAC2 = 0x30; /* half duplex, CRC and PAD enabled. */
MAC_SUPP |= 0x0100; /* RMII Support Reg. speed is set to 100M */
#if RMII
MAC_COMMAND |= 0x0240;
#else
MAC_COMMAND |= 0x0040; /* [10]-half duplex,[9]-MII mode,[6]-Pass runt frame,
[5]-RxReset */
#endif
/* back to back int-packet gap */
MAC_IPGT = 0x0012; /* IPG setting in half duplex mode */
}
else if ( (Speed == SPEED_10) && (Duplex == FULL_DUPLEX) )
{
MAC_MAC2 = 0x31; /* full duplex, CRC and PAD enabled. */
MAC_SUPP &= ~0x0100; /* RMII Support Reg. speed is set to 10M */
#if RMII
MAC_COMMAND |= 0x0640;
#else
MAC_COMMAND |= 0x0440; /* [10]-full duplex,[9]-MII mode,[6]-Pass runt frame,
[5]-RxReset */
#endif
/* back to back int-packet gap */
MAC_IPGT = 0x0015; /* IPG setting in full duplex mode */
}
else if ( (Speed == SPEED_100) && (Duplex == FULL_DUPLEX) )
/* default setting, 100 BASE, FULL DUPLEX */
{
MAC_MAC2 = 0x31; /* full duplex, CRC and PAD enabled. */
MAC_SUPP |= 0x0100; /* RMII Support Reg. speed is set to 100M */
#if RMII
MAC_COMMAND |= 0x0640;
#else
MAC_COMMAND |= 0x0440; /* [10]-full duplex,[9]-MII mode,[6]-Pass runt frame,
[5]-RxReset */
#endif
/* back to back int-packet gap */
MAC_IPGT = 0x0015; /* IPG setting in full duplex mode */
}
EMACTxDescriptorInit();
EMACRxDescriptorInit();
MAC_MAC1 |= 0x0002; /* [1]-Pass All Rx Frame */
/* Set up RX filter, accept broadcast and perfect station */
#if ACCEPT_BROADCAST
MAC_RXFILTERCTRL = 0x0022; /* [1]-accept broadcast, [5]accept perfect */
#else
MAC_RXFILTERCTRL = 0x0020; /* accept perfect match only */
#endif
#if MULTICAST_UNICAST
MAC_RXFILTERCTRL |= 0x0005;
#endif
#if ENABLE_HASH
MAC_RXFILTERCTRL |= 0x0018;
#endif
MAC_INTCLEAR = 0xFFFF; /* clear all MAC interrupts */
/* MAC interrupt related register setting */
if ( install_irq( EMAC_INT, (void *)EMACHandler, HIGHEST_PRIORITY ) == FALSE )
{
return (FALSE);
}
#if ENABLE_WOL
MAC_RXFILTERWOLCLR = 0xFFFF;/* set all bits to clear receive filter WOLs */
MAC_RXFILTERCTRL |= 0x2000; /* enable Rx Magic Packet and RxFilter Enable WOL */
MAC_INTENABLE = 0x2000; /* only enable WOL interrupt */
#else
MAC_INTENABLE = 0x00FF; /* Enable all interrupts except SOFTINT and WOL */
#endif
return ( TRUE );
}
/*****************************************************************************
** Function name: EMACReceiveFractions
**
** Descriptions: Dealing with a fraction of EMAC packet
**
** parameters: StartIndex and End Index
** Returned value: packet length
**
*****************************************************************************/
DWORD EMACReceiveFractions( DWORD StartIndex, DWORD EndIndex )
{
DWORD i, RxLength = 0;
DWORD RxSize;
DWORD *rx_status_addr;
for ( i = StartIndex; i < EndIndex; i++ )
{
/* Get RX status, two words, status info. and status hash CRC. */
rx_status_addr = (DWORD *)(RX_STATUS_ADDR + StartIndex * 8);
RxSize = (*rx_status_addr & DESC_SIZE_MASK) - 1;
/* two words at a time, packet and control */
CurrentRxPtr += EMAC_BLOCK_SIZE;
StartIndex++;
/* last fragment of a frame */
if ( *rx_status_addr & RX_DESC_STATUS_LAST )
{
/* set INT bit and RX packet size */
MAC_RXCONSUMEINDEX = StartIndex;
RxLength += RxSize;
break;
}
else /* In the middle of the frame, the RxSize should be EMAC_BLOCK_SIZE */
/* In the emac.h, the EMAC_BLOCK_SIZE has been set to the largest
ethernet packet length to simplify the process, so, it should not
come here in any case to deal with fragmentation. Otherwise,
fragmentation and repacking will be needed. */
{
/* set INT bit and maximum block size */
MAC_RXCONSUMEINDEX = StartIndex;
/* wait until the whole block is received, size is EMAC_BLOCK_SIZE. */
while ( (*rx_status_addr & DESC_SIZE_MASK) != (EMAC_BLOCK_SIZE - 1));
RxLength += RxSize;
}
}
return( RxLength );
}
/*****************************************************************************
** Function name: EMACReceive
**
** Descriptions: Receive a EMAC packet, called by ISR
**
** parameters: buffer pointer
** Returned value: packet length
**
*****************************************************************************/
DWORD EMACReceive( DWORD *EMACBuf )
{
DWORD RxProduceIndex, RxConsumeIndex;
DWORD RxLength = 0;
DWORD Counter = 0;
/* the input parameter, EMCBuf, needs to be word aligned */
RxProduceIndex = MAC_RXPRODUCEINDEX;
RxConsumeIndex = MAC_RXCONSUMEINDEX;
if ( RxProduceIndex == EMAC_RX_DESCRIPTOR_COUNT )
{
/* reach the limit, that probably should never happen */
MAC_RXPRODUCEINDEX = 0;
CurrentRxPtr = EMAC_RX_BUFFER_ADDR;
}
/* a packet has arrived. */
if ( RxProduceIndex != RxConsumeIndex )
{
if ( RxProduceIndex < RxConsumeIndex ) /* Wrapped around already */
{
/* take care of unwrapped, RxConsumeIndex to EMAC_RX_DESCERIPTOR_COUNT */
RxLength += EMACReceiveFractions( RxConsumeIndex, EMAC_RX_DESCRIPTOR_COUNT );
Counter++;
PacketReceived = TRUE;
/* then take care of wrapped, 0 to RxProduceIndex */
if ( RxProduceIndex > 0 )
{
RxLength += EMACReceiveFractions( 0, RxProduceIndex );
Counter++;
}
}
else /* Normal process */
{
RxLength += EMACReceiveFractions( RxConsumeIndex, RxProduceIndex );
Counter++;
}
}
return( RxLength );
}
/*****************************************************************************
** Function name: EMACSend
**
** Descriptions: Send a EMAC packet
**
** parameters: buffer pointer, buffer length
** Returned value: true or false
**
*****************************************************************************/
DWORD EMACSend( DWORD *EMACBuf, DWORD length )
{
DWORD *tx_desc_addr;
DWORD TxProduceIndex;
DWORD TxConsumeIndex;
DWORD i, templen;
TxProduceIndex = MAC_TXPRODUCEINDEX;
TxConsumeIndex = MAC_TXCONSUMEINDEX;
if ( TxConsumeIndex != TxProduceIndex )
{
return ( FALSE );
}
if ( TxProduceIndex == EMAC_TX_DESCRIPTOR_COUNT )
{
/* reach the limit, that probably should never happen */
/* To be tested */
MAC_TXPRODUCEINDEX = 0;
}
if ( length > EMAC_BLOCK_SIZE )
{
templen = length;
for ( i = 0; (DWORD)(length/EMAC_BLOCK_SIZE) + 1; i++ )
{
templen = length - EMAC_BLOCK_SIZE;
/* two words at a time, packet and control */
tx_desc_addr = (DWORD *)(TX_DESCRIPTOR_ADDR + TxProduceIndex * 8);
/* descriptor status needs to be checked first */
if ( templen % EMAC_BLOCK_SIZE )
{
/* full block */
*tx_desc_addr = (DWORD)(EMACBuf + i * EMAC_BLOCK_SIZE);
/* set TX descriptor control field */
*(tx_desc_addr+1) = (DWORD)(EMAC_TX_DESC_INT | (EMAC_BLOCK_SIZE - 1));
TxProduceIndex++;
if ( TxProduceIndex == EMAC_TX_DESCRIPTOR_COUNT )
{
TxProduceIndex = 0;
}
MAC_TXPRODUCEINDEX = TxProduceIndex; /* transmit now */
}
else
{
/* last fragment */
*tx_desc_addr = (DWORD)(EMACBuf + i * EMAC_BLOCK_SIZE);
/* set TX descriptor control field */
*(tx_desc_addr+1) = (DWORD)(EMAC_TX_DESC_INT | EMAC_TX_DESC_LAST | (templen -1) );
TxProduceIndex++; /* transmit now */
if ( TxProduceIndex == EMAC_TX_DESCRIPTOR_COUNT )
{
TxProduceIndex = 0;
}
MAC_TXPRODUCEINDEX = TxProduceIndex; /* transmit now */
break;
}
}
}
else
{
tx_desc_addr = (DWORD *)(TX_DESCRIPTOR_ADDR + TxProduceIndex * 8);
/* descriptor status needs to be checked first */
*tx_desc_addr = (DWORD)(EMACBuf);
/* set TX descriptor control field */
*(tx_desc_addr+1) = (DWORD)(EMAC_TX_DESC_INT | EMAC_TX_DESC_LAST | (length -1));
TxProduceIndex++; /* transmit now */
if ( TxProduceIndex == EMAC_TX_DESCRIPTOR_COUNT )
{
TxProduceIndex = 0;
}
MAC_TXPRODUCEINDEX = TxProduceIndex;
}
return ( TRUE );
}
/*********************************************************************************
** End Of File
*********************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -