📄 emac.c
字号:
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : main.c
//* Object : main application written in C
//* Creation : Hi 11/18/2002
//* Update : JGe 08/02/2005 : SAM7X port
//*----------------------------------------------------------------------------
#include "board.h"
#include "Emac.h"
#include "mii.h"
#include <string.h>
#include <stdio.h>
//extern unsigned int AT91F_GetTickCount(void);
extern void AT91F_DBGU_Printk(char *buffer);
extern void AT91F_DisplayIpPacket(AT91PS_IPheader pIpHeader);
extern char MsgBuffer[256];
extern int AT91F_ProcessEmacPacket(AT91PS_IPheader pHeader);
extern void LED_TurnOn(unsigned int led);
extern void LED_TurnOff(unsigned int led);
// Our Ethernet MAC address and IP address
char OurEmacAddr[6] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
unsigned char OurIpAddr[4] = {192, 168, 0, 18}; // {0x0A, 0xD7, 0xF5, 0xAC}
//Buffer descriptor address must be word aligned
#define AT91C_EMAC_RX_TDLIST_BASE 0x00204000 // take care that RxtdList[NB_RCV_BUFFERS] area is available
#define AT91C_EMAC_TX_TDLIST_BASE (AT91C_EMAC_RX_TDLIST_BASE + NB_RX_BUFFERS * sizeof(AT91S_RxTdDescriptor))
#define AT91C_EMAC_RX_PACKET_BASE (AT91C_EMAC_TX_TDLIST_BASE + NB_TX_BUFFERS * sizeof(AT91S_TxTdDescriptor))
#define AT91C_EMAC_TX_PACKET_BASE (AT91C_EMAC_RX_PACKET_BASE + NB_RX_BUFFERS * ETH_RX_BUFFER_SIZE)
char *RxPacket = (char *)AT91C_EMAC_RX_PACKET_BASE;
char *TxPacket = (char *)AT91C_EMAC_TX_PACKET_BASE;
AT91PS_RxTdDescriptor RxtdList = (AT91PS_RxTdDescriptor) AT91C_EMAC_RX_TDLIST_BASE;
AT91PS_TxTdDescriptor TxtdList = (AT91PS_TxTdDescriptor)AT91C_EMAC_TX_TDLIST_BASE;
unsigned int TxBuffIndex = 0;
// mapping
// 0x00204000 - 0x0020431F : RX descriptor list : 800 bytes
// 0x00204320 - 0x0020432F : TX descriptor list : 16 bytes
// 0x00204330 - 0x0020752F : RX packets : 12800 bytes
// 0x00207530 - 0x0020762F : TX packets : 256 bytes
// ****************************************************************************************************
// ** EMAC lowlevel functions
// ****************************************************************************************************
// Enable the MDIO bit in MAC control register
void AT91F_Enable_Mdi(AT91PS_EMAC pEmac)
{
pEmac->EMAC_NCR |= AT91C_EMAC_MPE; // enable management port
pEmac->EMAC_NCFGR |= (2)<<10; // MDC = MCK/32
}
// Disable the MDIO bit in the MAC control register
void AT91F_Disable_Mdi(AT91PS_EMAC pEmac)
{
pEmac->EMAC_NCR &= ~AT91C_EMAC_MPE; // disable management port
}
// Write value to the a PHY register
// Note: MDI interface is assumed to already have been enabled.
void write_phy(AT91PS_EMAC pEmac, unsigned char phy_addr, unsigned char address, unsigned int value)
{
pEmac->EMAC_MAN = ((AT91C_EMAC_SOF & (0x01<<30)) | (2 << 16) | (1 << 28)
| ((phy_addr & 0x1f) << 23) | (address << 18)) | (value & 0xffff);
/* Wait until IDLE bit in Network Status register is cleared */
while (!(pEmac->EMAC_NSR & AT91C_EMAC_IDLE));
}
// Read value stored in a PHY register.
// Note: MDI interface is assumed to already have been enabled.
void read_phy(AT91PS_EMAC pEmac, unsigned char phy_addr, unsigned char address, unsigned int *value)
{
pEmac->EMAC_MAN = (AT91C_EMAC_SOF & (0x01<<30)) | (2 << 16) | (2 << 28)
| ((phy_addr & 0x1f) << 23) | (address << 18);
/* Wait until IDLE bit in Network Status register is cleared */
while (!(pEmac->EMAC_NSR & AT91C_EMAC_IDLE));
*value = (pEmac->EMAC_MAN & 0x0000ffff);
}
//*----------------------------------------------------------------------------
//* \fn AT91F_GetLinkSpeed
//* \brief This function configure the link speed
//*----------------------------------------------------------------------------
int AT91F_GetLinkSpeed( AT91PS_EMAC pEmac) // \arg Pointer to AT91PS_EMAC service
{
unsigned int bmsr, bmcr, lpa, mac_cfg;
unsigned int speed, duplex;
/* Link status is latched, so read twice to get current value */
read_phy(pEmac, AT91C_PHY_ADDR, MII_BMSR, &bmsr);
read_phy(pEmac, AT91C_PHY_ADDR, MII_BMSR, &bmsr);
if (!(bmsr & BMSR_LSTATUS))
return -1; /* no link */
read_phy(pEmac, AT91C_PHY_ADDR, MII_BMCR, &bmcr);
if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */
if (!(bmsr & BMSR_ANEGCOMPLETE))
return -2; /* auto-negotitation in progress */
read_phy(pEmac, AT91C_PHY_ADDR, MII_LPA, &lpa);
if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF))
speed = SPEED_100;
else
speed = SPEED_10;
if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL))
duplex = DUPLEX_FULL;
else duplex = DUPLEX_HALF;
} else {
speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
}
/* Update the MAC */
mac_cfg = pEmac->EMAC_NCFGR & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD);
if (speed == SPEED_100) {
if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
pEmac->EMAC_NCFGR = mac_cfg | AT91C_EMAC_SPD | AT91C_EMAC_FD;
else /* 100 Half Duplex */
pEmac->EMAC_NCFGR = mac_cfg | AT91C_EMAC_SPD;
} else {
if (duplex == DUPLEX_FULL) /* 10 Full Duplex */
pEmac->EMAC_NCFGR = mac_cfg | AT91C_EMAC_FD;
else /* 10 Half Duplex */
pEmac->EMAC_NCFGR = mac_cfg;
}
#if 1
if (duplex == DUPLEX_FULL)
sprintf(MsgBuffer, "\n\r EMAC Init : %d Mbit/s FULL DUPLEX", speed);
else
sprintf(MsgBuffer, "\n\r EMAC Init : %d Mbit/s HALF DUPLEX", speed);
AT91F_DBGU_Printk(MsgBuffer);
#endif
return 0;
}
//Detect MAC and PHY and perform initialization
int AT91F_Ether_Probe(
AT91PS_EMAC pEmac) // \arg Pointer to AT91PS_EMAC service
{
unsigned int phyid1, phyid2;
unsigned int status;
// Read the PHY ID registers
AT91F_Enable_Mdi(pEmac);
read_phy(pEmac, AT91C_PHY_ADDR, MII_PHYSID1, &phyid1);
read_phy(pEmac, AT91C_PHY_ADDR, MII_PHYSID2, &phyid2);
/* AMD AM79C875: PHY_ID1 = 0x0022 PHY_ID2 = 0x5541
Bits 3:0 Revision Number Four bit manufacturer抯 revision number. 0001 stands for Rev. A, etc.
These bits are masked.
*/
if (((phyid1 << 16) | (phyid2 & 0xfff0)) != MII_DM9161_ID) {
AT91F_Disable_Mdi(pEmac);
return -1;
}
status = AT91F_GetLinkSpeed(pEmac);
AT91F_Disable_Mdi(pEmac);
return status;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_EMACInit
//* \brief This function initialise the ethernet
//*----------------------------------------------------------------------------
int AT91F_EMACInit( // \return Status ( Success = 0)
AT91PS_EMAC pEmac, // \arg Pointer to AT91PS_EMAC service
unsigned int pRxTdList,
unsigned int pTxTdList)
{
if (AT91F_Ether_Probe(pEmac))
return -1;
// the sequence write EMAC_SA1L and write EMAC_SA1H must be respected
pEmac->EMAC_SA1L = ((int)OurEmacAddr[3] << 24) | ((int)OurEmacAddr[2] << 16) | ((int)OurEmacAddr[1] << 8) | OurEmacAddr[0];
pEmac->EMAC_SA1H = ((int)OurEmacAddr[5] << 8) | OurEmacAddr[4];
pEmac->EMAC_RBQP = pRxTdList;
pEmac->EMAC_TBQP = pTxTdList;
//Clear receive status register
pEmac->EMAC_RSR = (AT91C_EMAC_OVR | AT91C_EMAC_REC | AT91C_EMAC_BNA);
pEmac->EMAC_NCFGR |= (AT91C_EMAC_CAF | AT91C_EMAC_NBC );// | AT91C_EMAC_RBOF_OFFSET_2);
pEmac->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE | AT91C_EMAC_WESTAT);
return 0;
}
#define AT91C_RCV_OFFSET 0
//*----------------------------------------------------------------------------
//* \fn AT91F_EmacEntry
//* \brief Initialise Emac to receive packets
//*----------------------------------------------------------------------------
int AT91F_EmacEntry(void)
{
unsigned int i;
unsigned int val;
// Initialise RxtdList descriptor
for (i = 0; i < NB_RX_BUFFERS; ++i) {
val = (unsigned int)(RxPacket + (i * ETH_RX_BUFFER_SIZE));
RxtdList[i].addr = val & 0xFFFFFFF8;
RxtdList[i].U_Status.status = 0;
}
// Set the WRAP bit at the end of the list descriptor
RxtdList[NB_RX_BUFFERS-1].addr |= 0x02;
// Initialise TxtdList descriptor
for (i = 0; i < NB_TX_BUFFERS; ++i) {
val = (unsigned int)(TxPacket + (i * ETH_TX_BUFFER_SIZE));
TxtdList[i].addr = val & 0xFFFFFFF8;
TxtdList[i].U_Status.status = 0;
}
// Set the WRAP bit at the end of the list descriptor
TxtdList[NB_TX_BUFFERS-1].U_Status.S_Status.Wrap = 1;
return(AT91F_EMACInit(AT91C_BASE_EMAC, (unsigned int) RxtdList, (unsigned int) TxtdList));
}
//*----------------------------------------------------------------------------
//* \fn AT91F_TransmitPacket
//* \brief Send a packet
//*----------------------------------------------------------------------------
int AT91F_TransmitPacket(char *pData, unsigned int length)
{
AT91PS_EMAC pEmac = (AT91PS_EMAC)AT91C_BASE_EMAC;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -