📄 adi_ether_bf537.c
字号:
// poll the STABUSY bit
while((*pEMAC_STAADD) & STABUSY) {};
}
//
// Read an off-chip register in a PHY through the MDC/MDIO port
//
static u16 RdPHYReg(u16 PHYAddr, u16 RegAddr)
{
PollMdcDone();
*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
EMAC2_STAOP_RD | STABUSY;
PollMdcDone();
return (u16)*pEMAC_STADAT;
}
//
// Write an off-chip register in a PHY through the MDC/MDIO port
//
static void RawWrPHYReg(u16 PHYAddr, u16 RegAddr, u32 Data)
{
*pEMAC_STADAT = Data;
*pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) |
EMAC2_STAOP_WR | STABUSY;
PollMdcDone();
}
static void WrPHYReg(u16 PHYAddr, u16 RegAddr, u32 Data)
{
PollMdcDone();
RawWrPHYReg(PHYAddr,RegAddr,Data);
}
//
// set up the phy
//
static SetPhy(ADI_ETHER_BF537_DATA *dev)
{
u16 phydat,phydat1;
clock_t ndtime;
clock_t period = ((clock_t)CLOCKS_PER_SEC)/2;
// Program PHY registers
phydat = 0;
int pha;
// issue a reset
RawWrPHYReg(dev->PhyAddr, PHYREG_MODECTL, 0x8000);
// wait half a second
period = 30000000; // assume 600 MHZ
ndtime = clock()+period;
while (clock()<ndtime);
phydat = RdPHYReg(dev->PhyAddr, PHYREG_MODECTL);
// advertise flow control supported
phydat = RdPHYReg(dev->PhyAddr, PHYREG_ANAR);
phydat |= (1 << 10);
WrPHYReg(dev->PhyAddr, PHYREG_ANAR, phydat);
phydat = 0;
if (dev->Negotiate) {
phydat |= 0x1000; // enable auto negotiation
} else {
if (dev->FullDuplex) {
phydat |= (1 << 8); // full duplex
} else {
phydat &= (~(1 << 8)); // half duplex
}
if (!dev->Port10) {
phydat |= (1 << 13); // 100 Mbps
} else {
phydat &= (~(1 << 13)); // 10 Mbps
}
}
if (dev->Loopback) {
phydat |= (1 << 14); // enable TX->RX loopback
//WrPHYReg(dev->PhyAddr, PHYREG_MODECTL, phydat);
}
WrPHYReg(dev->PhyAddr, PHYREG_MODECTL, phydat);
period = 100000000; // assume 600 MHZ
ndtime = clock()+period;
while (clock()<ndtime);
phydat = RdPHYReg(dev->PhyAddr, PHYREG_MODECTL);
// check for SMSC PHY
if ((RdPHYReg(dev->PhyAddr, PHYREG_PHYID1) == 0x7) && ((RdPHYReg(dev->PhyAddr, PHYREG_PHYID2)&0xfff0 ) == 0xC0A0)) {
// we have SMSC PHY so reqest interrupt on link down condition
WrPHYReg(dev->PhyAddr, 30, 0x0ff); // enable interrupts
// enable PHY_INT
u32 sysctl = *pEMAC_SYSCTL;
sysctl |= 0x1;
*pEMAC_SYSCTL = sysctl;
}
}
#if 1
static void DumpQueue(char *str1, char *str2, ADI_ETHER_BUFFER *buf)
{
BUFFER_INFO *bi = (BUFFER_INFO *)buf;
DMA_DESCRIPTOR *dmr;
printf("%s %s\n",str1,str2);
if (bi != NULL) {
dmr = bi->First;
while (dmr != NULL) {
printf(" NEXT_DESC_PTR:%8.8x\n",dmr->NEXT_DESC_PTR);
printf(" CONFIG:%4.4x\n",dmr->CONFIG);
printf(" COUNT:%4.4x\n",dmr->X_COUNT);
printf("\n");
dmr = dmr->NEXT_DESC_PTR;
}
}
}
static void DumpDesc(char *str, FRAME_QUEUE *q)
{
DumpQueue(str,"Active",q->Active);
DumpQueue(str,"Pending",q->Pending);
DumpQueue(str,"Queued",q->Queued);
}
static int DumpAllQueues;
#endif
static void GetPhyRegs(u16 addr, u16 *regs)
{
int pha;
for (pha = 0; pha < NO_PHY_REGS; pha++) {
regs[pha] = RdPHYReg(addr, pha);
}
#if 1
{
FRAME_QUEUE *q;
if (DumpAllQueues) {
DumpDesc("TX",&EtherDev.Tx);
DumpDesc("RX",&EtherDev.Rx);
}
}
#endif
}
/*********************************************************************
*
* Function: adi_pdd_Open
*
* Description: Opens the BF537 EMAC for use
*
*********************************************************************/
static u32 adi_pdd_Open( // Open a device
ADI_DEV_MANAGER_HANDLE ManagerHandle, // device manager handle
u32 DeviceNumber, // device number
ADI_DEV_DEVICE_HANDLE DeviceHandle, // device handle
ADI_DEV_PDD_HANDLE *pPDDHandle, // pointer to PDD handle location
ADI_DEV_DIRECTION Direction, // data direction
void *pEnterCriticalArg, // enter critical region parameter
ADI_DMA_MANAGER_HANDLE DMAHandle, // handle to the DMA manager
ADI_DCB_HANDLE DCBHandle, // callback handle
ADI_DCB_CALLBACK_FN DMCallback // client callback function
)
{
u32 Result; // return value
void *CriticalResult;
ADI_ETHER_BF537_DATA *dev= &EtherDev;
// check for errors if required
#ifdef ADI_ETHER_ERROR_CHECKING_ENABLED
if (DeviceNumber > 0) { // check the device number
return (ADI_DEV_RESULT_BAD_DEVICE_NUMBER);
}
#endif
EtherDev.IntMask = 0; // disable all interrupts
// insure the device the client wants is available
Result = ADI_DEV_RESULT_DEVICE_IN_USE;
CriticalResult = EnterCriticalRegion(pEnterCriticalArg);
if (!dev->Open) {
// initialize the device settings
memset(dev,0,sizeof(ADI_ETHER_BF537_DATA));
dev->CriticalData = pEnterCriticalArg;
dev->DeviceHandle = DeviceHandle;
dev->DCBHandle = DCBHandle;
dev->DMCallback = DMCallback;
dev->Direction = Direction;
dev->Started = false;
dev->PhyAddr = 0x01; // 0x01 1.1 EZ kit and BUB
dev->CLKIN = 25; //Ezkit
dev->FullDuplex=false;
dev->Negotiate = true;
dev->FlowControl = false;
dev->EtherIntIVG = 7;
dev->RXIVG = 11;
dev->Rx.Channel = 1;
dev->Rx.Rcve = true;
dev->Rx.CompletedStatus = 0x01000;
dev->Rx.EnableMac = 0x0001;
dev->TXIVG = 11;
dev->Tx.Channel = 2;
dev->Tx.CompletedStatus = 0x0001;
dev->Tx.EnableMac = 0x010000;
dev->Trc.BaseEntry = NULL;
dev->MaxTraceEntries = 0;
dev->TraceSequence = 0;
dev->Open = true;
// we set the GPIO pins to Ethernet mode
SetupPinMux();
*pEMAC_OPMODE = 0;
Result = ADI_DEV_RESULT_SUCCESS;
}
ExitCriticalRegion(CriticalResult);
if (Result != ADI_DEV_RESULT_SUCCESS) return (Result);
// save the physical device handle in the client supplied location
*pPDDHandle = (ADI_DEV_PDD_HANDLE *)dev;
// return
return(ADI_DEV_RESULT_SUCCESS);
}
/*********************************************************************
*
* Function: adi_pdd_Close
*
* Description: Closes down EMAC
*
*********************************************************************/
static u32 adi_pdd_Close( // Closes a device
ADI_DEV_PDD_HANDLE PDDHandle // PDD handle
)
{
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)PDDHandle;
u32 Result = ADI_DEV_RESULT_SUCCESS; // return value
bool active=true;
FRAME_QUEUE *q;
// check for errors if required
#if defined(ADI_ETHER_DEBUG)
if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
#endif
dev->Closing = true;
dev->Open = false;
if (dev->Started) {
dev->Started = false;
// wait for the current frames to complete
while (active) {
active = false;
q = &dev->Tx;
if ((q->Active!=NULL) || (q->Pending!=NULL) || (q->Completed !=NULL) || (q->Queued!=NULL)) active = true;
q = &dev->Rx;
if ((q->Active!=NULL) || (q->Pending!=NULL) || (q->Completed !=NULL) || (q->Queued!=NULL)) active = true;
}
// unhook interrupts
adi_int_CECUnhook(dev->RXIVG,RxInterruptHandler);
adi_int_CECUnhook(dev->TXIVG,TxInterruptHandler);
adi_int_CECUnhook(dev->EtherIntIVG,EtherInterruptHandler);
adi_int_CECUnhook(7,DmaErrorInterruptHandler);
}
// return
return(Result);
}
//
// Queue new frames
//
static void QueueNewFrames(ADI_ETHER_BF537_DATA *dev, FRAME_QUEUE *q,ADI_ETHER_BUFFER *bfs)
{
ADI_ETHER_BUFFER *lstq,*buf;
void *CriticalResult;
int no_frames=0;
// mark all the buffers as unprocessed
buf = bfs;
while (buf != NULL) {
no_frames++;
buf->StatusWord = 0;
buf->ProcessedFlag = 0;
buf->ProcessedElementCount = 0;
buf = buf->pNext;
}
CriticalResult = EnterCriticalRegion(dev->CriticalData);
lstq = NULL;
buf = q->Queued;
while (buf != NULL) {
lstq = buf;
buf = buf->pNext;
}
// now append on the Queued queue
if (lstq == NULL) {
q->Queued = bfs;
} else {
lstq->pNext = bfs;
}
#ifdef ADI_ETHER_BF537_DEBUG
bfs->usage = Queued;
bfs->rxusage = q->Rcve;
#endif
if (dev->Started) QueueFrames(dev,q);
q->UnProcessed += no_frames;
ExitCriticalRegion(CriticalResult);
}
/*********************************************************************
*
* Function: adi_pdd_Read
*
* Description: Provides buffers to store data when data is received
* from the EMAC
*
*********************************************************************/
static u32 adi_pdd_Read( // Reads data or queues an inbound buffer to a device
ADI_DEV_PDD_HANDLE PDDHandle, // PDD handle
ADI_DEV_BUFFER_TYPE BufferType, // buffer type
ADI_DEV_BUFFER *pBuffer // pointer to buffer
)
{
u32 Result; // return value
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)PDDHandle;
// check for errors if required
#if defined(ADI_ETHER_DEBUG)
if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
if (BufferType != DEV_1D) {
return (ADI_DEV_BUFFER_TYPE_INCOMPATIBLE);
}
if (((ADI_ETHER_BUFFER *)pBuffer->Data & 0x03) || ((ADI_ETHER_BUFFER *)pBuffer->Payload & 0x03) ) {
return ADI_ETHER_RESULT_MEMORY_NOT_ALIGNED;
}
#endif
QueueNewFrames(dev,&dev->Rx,(ADI_ETHER_BUFFER *)pBuffer);
return(ADI_DEV_RESULT_SUCCESS);
}
/*********************************************************************
*
* Function: adi_pdd_Write
*
* Description: Provides buffers containing data to be transmitted
* out through the EMAC
*
*********************************************************************/
static u32 adi_pdd_Write( // Writes data or queues an outbound buffer to a device
ADI_DEV_PDD_HANDLE PDDHandle, // PDD handle
ADI_DEV_BUFFER_TYPE BufferType, // buffer type
ADI_DEV_BUFFER *pBuffer // pointer to buffer
)
{
u32 Result; // return value
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)PDDHandle;
char *src;
ADI_ETHER_BUFFER *act = (ADI_ETHER_BUFFER *)pBuffer;
// check for errors if required
#if defined(ADI_ETHER_DEBUG)
if ((Result = ValidatePDDHandle(PDDHandle)) != ADI_DEV_RESULT_SUCCESS) return (Result);
if (BufferType != DEV_1D) {
return (ADI_DEV_BUFFER_TYPE_INCOMPATIBLE);
}
if (((ADI_ETHER_BUFFER *)pBuffer->Data & 0x03) || ((ADI_ETHER_BUFFER *)pBuffer->Payload & 0x03) ) {
return ADI_ETHER_RESULT_MEMORY_NOT_ALIGNED;
}
if (((ADI_ETHER_BUFFER *)pBuffer->ElementCount*(ADI_ETHER_BUFFER *)pBuffer->ElementWidth) & 0x03) {
return ADI_ETHER_RESULT_MEMORY_LENGTH_INVALID;
}
#endif
while (act != NULL) {
// Plant the source MAC address
src = 8+(char *)(act->Data);
memcpy(src,dev->Mac,6);
FlushArea(src,src+6);
act = act->pNext;
}
QueueNewFrames(dev,&dev->Tx,(ADI_ETHER_BUFFER *)pBuffer);
return(ADI_DEV_RESULT_SUCCESS);
}
//
// Set MAC address
//
static void SetupMacAddr(unsigned char *mac)
{
unsigned int lo;
int i;
lo = 0;
for (i=3;i>=0; i--) {
lo = (lo<<8) | mac[i];
}
*pEMAC_ADDRLO = lo;
lo = 0;
for (i=5;i>=4; i--) {
lo = (lo<<8) | mac[i];
}
*pEMAC_ADDRHI = lo;
}
//
// Get MAC address
//
static void GetMacAddr(unsigned char *mac)
{
unsigned int lo;
int i;
lo = *pEMAC_ADDRLO;
for (i=0;i<4; i++) {
mac[i] = lo&0xff;
lo = lo >> 8;
}
lo = *pEMAC_ADDRHI;
for (i=4;i<6; i++) {
mac[i] = lo&0xff;
lo = lo >> 8;
}
}
//
// Update statistics
//
static void UpdateStatistics(u64 *stats)
{
volatile unsigned long *cnts = pEMAC_RXC_OK;
int ncnts = sizeof(ADI_ETHER_STATISTICS_COUNTS)/sizeof(u64);
int rxcnts = offsetof(ADI_ETHER_STATISTICS_COUNTS,cEMAC_TX_CNT_OK)/sizeof(u64);
ncnts -= rxcnts; // no. of TX counts
while (rxcnts>0) {
*stats++ += *cnts++;
rxcnts--;
}
cnts = pEMAC_TXC_OK;
while (ncnts>0) {
*stats++ += *cnts++;
ncnts--;
}
}
//
// Configure and start the MAC
//
static int StartMac(ADI_ETHER_BF537_DATA *dev)
{
int res;
u32 opmode;
u16 sysctl;
void *CriticalResult;
static DMA_DESCRIPTOR txfirst,txlast;
u16 vrctl;
unsigned int vco,cmsel,msk;
u16 fer_val;
memset(dev->Stats,0,sizeof(ADI_ETHER_STATISTICS_COUNTS));
UpdateStatistics((u64*)dev->Stats);
vrctl = *pVR_CTL;
if ((vrctl&0x4000)==0) {
*pVR_CTL = 0x4000|vrctl; //enable CLKBFOE to enable clock for the PHY
msk = cli();
ssync();
idle();
sti(msk);
}
// Set FER regs to MUX in Ethernet pins
// FER reg bug work-around
// read it once
fer_val = *pPORTH_FER;
// MUX all of these pins to Ethernet
fer_val = 0xFFFF;
// write it twice to the same value
*pPORTH_FER = fer_val;
*pPORTH_FER = fer_val;
// enable the interrupts in the SIC
res = adi_int_SICSetIVG(ADI_INT_DMA1_ETHERNET_RX_PORTH_A,dev->RXIVG);
CHECK_RES = adi_int_SICEnable(ADI_INT_DMA1_ETHERNET_RX_PORTH_A);
CHECK_RES = adi_int_SICSetIVG(ADI_INT_DMA2_ETHERNET_TX_PORTH_B,dev->TXIVG);
CHECK_RES = adi_int_SICEnable(ADI_INT_DMA2_ETHERNET_TX_PORTH_B);
CHECK_RES = adi_int_SICSetIVG(ADI_INT_PERIPHERAL_ERROR,dev->EtherIntIVG);
CHECK_RES = adi_int_SICEnable(ADI_INT_PERIPHERAL_ERROR);
CHECK_RES = adi_int_SICSetIVG(ADI_INT_DMA_ERROR,7);
CHECK_RES = adi_int_SICEnable(ADI_INT_DMA_ERROR);
// hook the DMA error interrupt
CHECK_RES = adi_int_CECHook(7,DmaErrorInterruptHandler,dev,true);
// hook the ether interrupt
CHECK_RES = adi_int_CECHook(dev->EtherIntIVG,EtherInterruptHandler,dev,true);
if (res == 0) {
if (dev->Rx.Dma == NULL ) {
dev->Rx.Dma = (DMA_REGISTERS *)(DMA0_NEXT_DESC_PTR+0x40*dev->Rx.Channel);
//dev->Rx.Dma->CONFIG = 0;
dev->Rx.Dma->X_COUNT = 0;
dev->Rx.Dma->X_MODIFY = 4;
dev->Rx.Dma->Y_COUNT = 0;
}
if (dev->Tx.Dma == NULL) {
dev->Tx.Dma = (DMA_REGISTERS *)(DMA0_NEXT_DESC_PTR+0x40*dev->Tx.Channel);
//dev->Tx.Dma->CONFIG = 0;
dev->Tx.Dma->X_COUNT = 0;
dev->Tx.Dma->X_MODIFY = 4;
dev->Tx.Dma->Y_COUNT = 0;
}
// set the imask
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -