📄 adi_ether_bf537.c
字号:
dev->IntMask = ~((1<<dev->RXIVG) | (1<<dev->TXIVG) | (1<<dev->EtherIntIVG) );
// hook the RX,TX complete interrupts
res = adi_int_CECHook(dev->RXIVG,RxInterruptHandler,dev,true);
if (res == 0) {
res = adi_int_CECHook(dev->TXIVG,TxInterruptHandler,dev,true);
if (res != 0) {
adi_int_CECUnhook(dev->RXIVG,RxInterruptHandler);
}
}
if (res != 0) {
adi_int_CECUnhook(7,DmaErrorInterruptHandler);
adi_int_CECUnhook(dev->EtherIntIVG,EtherInterruptHandler);
}
if (res == 0) {
u32 fcclk,fsclk,fvco;
u32 N,mdc;
vco = ((*pPLL_CTL>>9)&0x3f) * dev->CLKIN;
if (*pPLL_CTL&1) {
vco = vco>>1; // divide by 2
}
cmsel = (*pPLL_DIV>>4)&0x3;
fcclk = vco/(1<<cmsel);
cmsel = *pPLL_DIV&0x0f;
fsclk = vco/cmsel;
N= (((fsclk+4)/5)-1)&0x3f;
mdc = (fsclk*5)/(N+1);
//set up the EMAC controller
// reset counters, clear on read, saturate , enable counters
*pEMAC_MMC_CTL = 0x0d;
// dont enable RX and TX until we have a buffer to start the DMA with
opmode = 0x00000000;
if (dev->StripPads) {
opmode |= 0x0002;
}
if (dev->FullDuplex) {
opmode |= 0x04000000;
}
opmode |= dev->OpMode;
*pEMAC_OPMODE = opmode;
sysctl = 0;
if (dev->GenChksums) {
sysctl |= 0x0004;
}
if (dev->NoRcveLnth) {
sysctl &= (~0x0002);
} else {
sysctl |= 0x0002;
}
sysctl = (N<<8) | sysctl; // or in the SCLK:MDC divisor
*pEMAC_SYSCTL = sysctl;
// set up the PHY
SetPhy(dev);
// now actually enable the interrupts
*pEMAC_MMC_RIRQE = 0x00ffffff; // RX counter interrupts
*pEMAC_MMC_TIRQE = 0x00ffffff; // RX counter interrupts
dev->Started = true;
CriticalResult = EnterCriticalRegion(dev->CriticalData);
QueueFrames(dev,&dev->Tx);
QueueFrames(dev,&dev->Rx);
ExitCriticalRegion(CriticalResult);
}
}
return res;
}
/*********************************************************************
*
* Function: adi_pdd_Control
*
* Description: Configures the EMAC
*
*********************************************************************/
static u32 adi_pdd_Control( // Sets or senses a device specific parameter
ADI_DEV_PDD_HANDLE PDDHandle, // PDD handle
u32 Command, // command ID
void *pArg // pointer to argument
)
{
u32 Result; // return value
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)PDDHandle;
ADI_ETHER_MEM_SIZES *msizes;
ADI_ETHER_SUPPLY_MEM *memsup;
int maxbuf,i;
DMA_DESCRIPTOR *nxt,*lst;
u32 *prefix;
ADI_ETHER_BUFFER_COUNTS *bufcnts;
ADI_ETHER_IVG_MAPPING *ivgs;
ADI_ETHER_DMA_MAPPING *dmas;
char *EndXmit;
ADI_ETHER_BF537_TRACE_INFO *trcinfo;
char *basemem,*obasemem;
u32 lnthmem;
volatile STATUS_AREA *sts,*lsts;
u32 ii = ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT;
ii = ADI_ETHER_CMD_MEM_SIZES;
// 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);
}
#endif
// avoid casts
Result = ADI_DEV_RESULT_SUCCESS;
// CASEOF (Command ID)
switch (Command) {
case ADI_DEV_CMD_SET_DATAFLOW:
// enable or disable accordingly
dev->FlowEnabled = (int)pArg;
break;
case ADI_DEV_CMD_SET_DATAFLOW_METHOD:
break;
case ADI_DEV_CMD_GET_PERIPHERAL_DMA_SUPPORT:
// no we dont want peripheral DMA support
(*(int *)pArg) = false;
break;
case ADI_ETHER_CMD_MEM_SIZES:
msizes = (ADI_ETHER_MEM_SIZES *)(pArg);
msizes->BaseMemSize = sizeof(ADI_ETHER_STATISTICS_COUNTS);
msizes->MemPerRecv = 36+sizeof(DMA_DESCRIPTOR[2]);
msizes->MemPerXmit = 36+sizeof(DMA_DESCRIPTOR[3]);
break;
case ADI_ETHER_CMD_SUPPLY_MEM:
memsup = (ADI_ETHER_SUPPLY_MEM *)(pArg);
if (memsup->BaseMemLength < sizeof(ADI_ETHER_STATISTICS_COUNTS)) {
Result = ADI_DEV_RESULT_NO_MEMORY;
} else {
dev->Stats = memsup->BaseMem;
memset(dev->Stats,0,sizeof(ADI_ETHER_STATISTICS_COUNTS));
}
#if 1
// layout the available RX desciptors
lnthmem = memsup->RcveMemLength;
obasemem = basemem = (char *)memsup->RcveMem;
// round up base mem to be a multiple of 32
basemem = (char *)((((u32)basemem)+31)&(~0x1F));
// adjust the length remaining
lnthmem = lnthmem - (basemem - obasemem);
memsup->MaxRcveFrames = maxbuf = lnthmem/(32+sizeof(DMA_DESCRIPTOR[2]));
if (maxbuf>=1) {
// layout the status words
lsts = NULL;
dev->Rx.AvailStatus = (STATUS_AREA *)basemem;
for (i=0;i<maxbuf;i++) {
sts = (STATUS_AREA *)basemem;
if (lsts!=NULL) lsts->Next = sts;
sts->Next = NULL;
lsts = sts;
basemem += 32;
}
dev->Rx.Avail = (DMA_DESCRIPTOR *)basemem;
dev->Rx.NoAvail = 2*maxbuf;
nxt = dev->Rx.Avail;
for (i=0;i<maxbuf;i++) {
lst = nxt+1;
memset(nxt,0,sizeof(DMA_DESCRIPTOR));
nxt[0].NEXT_DESC_PTR = lst;
lst->NEXT_DESC_PTR = nxt+2;
nxt += 2;
}
lst->NEXT_DESC_PTR = NULL;
} else {
memsup->MaxRcveFrames = 0;
Result = ADI_DEV_RESULT_NO_MEMORY;
}
CheckQueues(&dev->Rx);
// layout the available TX desciptors
lnthmem = memsup->XmitMemLength;
obasemem = basemem = (char *)memsup->XmitMem;
// round up base mem to be a multiple of 32
basemem = (char *)((((u32)basemem)+31)&(~0x1F));
// adjust the length remaining
lnthmem = lnthmem - (basemem - obasemem);
memsup->MaxXmitFrames = maxbuf = lnthmem/(32+sizeof(DMA_DESCRIPTOR[3]));
if (maxbuf>=1) {
// layout the status words
lsts = NULL;
dev->Tx.AvailStatus = (STATUS_AREA *)basemem;
for (i=0;i<maxbuf;i++) {
sts = (STATUS_AREA *)basemem;
if (lsts!=NULL) lsts->Next = sts;
sts->Next = NULL;
lsts = sts;
basemem += 32;
}
dev->Tx.Avail = (DMA_DESCRIPTOR *)basemem;
dev->Tx.NoAvail = 3*maxbuf;
nxt = dev->Tx.Avail;
for (i=0;i<maxbuf;i++) {
memset(nxt,0,sizeof(DMA_DESCRIPTOR));
nxt[0].NEXT_DESC_PTR = nxt+1;
nxt[1].NEXT_DESC_PTR = nxt+2;
lst = &nxt[2];
lst->NEXT_DESC_PTR = nxt+3;
nxt += 3;
}
lst->NEXT_DESC_PTR = NULL;
} else {
memsup->MaxXmitFrames = 0;
Result = ADI_DEV_RESULT_NO_MEMORY;
}
CheckQueues(&dev->Tx);
#else
// layout the available RX desciptors
dev->Rx.Avail = memsup->RcveMem;
memsup->MaxRcveFrames = maxbuf = memsup->RcveMemLength/sizeof(DMA_DESCRIPTOR[2]);
dev->Rx.NoAvail = 2*maxbuf;
if (maxbuf>=1) {
nxt = dev->Rx.Avail;
for (i=0;i<maxbuf;i++) {
lst = nxt+1;
memset(nxt,0,sizeof(DMA_DESCRIPTOR));
nxt[0].NEXT_DESC_PTR = lst;
lst->NEXT_DESC_PTR = nxt+2;
nxt += 2;
}
lst->NEXT_DESC_PTR = NULL;
} else {
memsup->MaxRcveFrames = 0;
Result = ADI_DEV_RESULT_NO_MEMORY;
}
CheckQueues(&dev->Rx);
// layout the available TX desciptors
dev->Tx.Avail = memsup->XmitMem;
EndXmit = (char *)dev->Tx.Avail+memsup->XmitMemLength;
memsup->MaxXmitFrames = maxbuf = memsup->XmitMemLength/sizeof(DMA_DESCRIPTOR[3]);
dev->Tx.NoAvail = 3*maxbuf;
if (maxbuf>=1) {
nxt = dev->Tx.Avail;
for (i=0;i<maxbuf;i++) {
memset(nxt,0,sizeof(DMA_DESCRIPTOR));
nxt[0].NEXT_DESC_PTR = nxt+1;
nxt[1].NEXT_DESC_PTR = nxt+2;
lst = &nxt[2];
lst->NEXT_DESC_PTR = nxt+3;
nxt += 3;
}
lst->NEXT_DESC_PTR = NULL;
} else {
memsup->MaxXmitFrames = 0;
Result = ADI_DEV_RESULT_NO_MEMORY;
}
CheckQueues(&dev->Tx);
#endif
break;
case ADI_ETHER_CMD_GET_MAC_ADDR:
GetMacAddr((unsigned char *)(pArg));
break;
case ADI_ETHER_CMD_SET_MAC_ADDR:
if (*pEMAC_OPMODE&0x00010001) {
Result = ADI_DEV_RESULT_INVALID_SEQUENCE;
} else {
memcpy(dev->Mac,pArg,6);
SetupMacAddr((unsigned char *)(pArg));
}
break;
case ADI_ETHER_CMD_GET_STATISTICS:
UpdateStatistics((u64*)dev->Stats);
memcpy((void *)(pArg),dev->Stats,sizeof(ADI_ETHER_STATISTICS_COUNTS));
break;
case ADI_ETHER_CMD_GET_BUFFER_PREFIX:
prefix = (u32 *)(pArg);
*prefix = 0;
break;
case ADI_ETHER_CMD_UNPROCESSED_BUFFER_COUNTS:
bufcnts = (ADI_ETHER_BUFFER_COUNTS *)(pArg);
bufcnts->RcvrBufferCnt = dev->Rx.UnProcessed;
bufcnts->XmitBufferCnt = dev->Tx.UnProcessed;
break;
case ADI_ETHER_CMD_GET_MIN_RECV_BUFSIZE:
prefix = (u32 *)(pArg);
*prefix = MAX_RCVE_FRAME;
break;
case ADI_ETHER_CMD_SET_SPEED:
i = (int)(pArg);
if ((i <= 0) || (i > 2)) {
Result = ADI_DEV_RESULT_NOT_SUPPORTED;
} else {
dev->Port10 = (i == 1);
dev->Negotiate = false;
}
break;
case ADI_ETHER_CMD_SET_FULL_DUPLEX:
i = (int)(pArg);
dev->FullDuplex = (i!=0);
dev->Negotiate = false;
break;
case ADI_ETHER_CMD_SET_NEGOTIATE:
i = (int)(pArg);
dev->Negotiate = (i!=0);
break;
case ADI_ETHER_CMD_START:
Result = StartMac(dev);
break;
case ADI_ETHER_CMD_GET_PHY_REGS:
GetPhyRegs(dev->PhyAddr,(void *)(pArg));
break;
case ADI_ETHER_CMD_SET_LOOPBACK:
i = (int)(pArg);
dev->Loopback = (i!=0);
if (dev->Started) {
// change the phy
u16 cur;
cur = RdPHYReg(dev->PhyAddr, PHYREG_MODECTL);
if (dev->Loopback) {
cur |= (1 << 14); // enable TX->RX loopback
} else {
cur &= (~(1 << 14));
}
WrPHYReg(dev->PhyAddr, PHYREG_MODECTL,cur);
}
break;
case ADI_ETHER_CMD_BUFFERS_IN_CACHE:
i = (int)(pArg);
dev->Cache = (i!=0);
break;
case ADI_ETHER_CMD_BF537_NO_RCVE_LNTH:
i = (int)(pArg);
dev->NoRcveLnth = (i!=0);
break;
case ADI_ETHER_CMD_BF537_STRIP_PAD:
i = (int)(pArg);
dev->StripPads = (i!=0);
break;
case ADI_ETHER_CMD_BF537_CLKIN:
i = (int)(pArg);
dev->CLKIN = i;
break;
case ADI_ETHER_CMD_BF537_USE_IVG:
ivgs = (ADI_ETHER_IVG_MAPPING *)(pArg);
dev->EtherIntIVG = ivgs->ErrIVG;
dev->RXIVG = ivgs->RxIVG;
dev->TXIVG = ivgs->TxIVG;
break;
case ADI_ETHER_CMD_BF537_USE_DMA:
dmas = (ADI_ETHER_DMA_MAPPING *)(pArg);
dev->Rx.Channel = dmas->RxChannel;
dev->Tx.Channel = dmas->TxChannel;
break;
case ADI_ETHER_CMD_BF537_SET_PHY_ADDR:
i = (int)(pArg);
dev->PhyAddr = i &0xffff;
break;
case ADI_ETHER_CMD_GEN_CHKSUMS:
dev->GenChksums = true;
break;
case ADI_ETHER_CMD_BF537_SET_TRACE:
trcinfo = (ADI_ETHER_BF537_TRACE_INFO *)(pArg);
dev->Trc.BaseEntry = (ADI_ETHER_BF537_TRACE_ENTRY *)trcinfo->Mem;
dev->Trc.EntryLnth = (sizeof(ADI_ETHER_BF537_TRACE_ENTRY)+trcinfo->MaxBytes+3)&(~0x3); // round up to multiple of 4
dev->Trc.NoOfEntries = trcinfo->LnthMem/dev->Trc.EntryLnth;
if (dev->Trc.NoOfEntries <=0) {
dev->Trc.BaseEntry = NULL;
dev->MaxTraceEntries = 0;
Result = ADI_DEV_RESULT_NO_MEMORY;
} else {
dev->Trc.EndOfData = (ADI_ETHER_BF537_TRACE_ENTRY *)(((char *)dev->Trc.BaseEntry) + dev->Trc.EntryLnth*dev->Trc.NoOfEntries);
dev->MaxTraceEntries = dev->Trc.NoOfEntries;
dev->Trc.OldestEntry = dev->Trc.BaseEntry;
dev->Trc.NoOfEntries = 0;
dev->TraceMaxBytes = dev->Trc.EntryLnth - sizeof(ADI_ETHER_BF537_TRACE_ENTRY);
dev->TraceFirstByte = trcinfo->FirstByte;
}
break;
case ADI_ETHER_CMD_BF537_GET_TRACE:
memcpy(pArg,&dev->Trc,sizeof(ADI_ETHER_BF537_TRACE_DATA));
break;
case ADI_DEV_CMD_TABLE:
break;
default:
// we don't understand this command
Result = ADI_DEV_RESULT_NOT_SUPPORTED;
}
// return
return(Result);
}
/*********************************************************************
*
* Function: InterruptHandler
*
* Description: Processes events in response to EMAC interrupts
*
*********************************************************************/
static void DmaError(FRAME_QUEUE *q)
{
int k=10;
k=q->Channel;
k = q->Dma->IRQ_STATUS;
}
static ADI_INT_HANDLER(DmaErrorInterruptHandler)
{
ADI_INT_HANDLER_RESULT result = ADI_INT_RESULT_NOT_PROCESSED;
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)ClientArg;
BUFFER_INFO *bi;
breakpoint(2);
// check our two DMA channels
if (dev->Tx.Dma->IRQ_STATUS & 0x02) {
// error on TX channel
bi = (BUFFER_INFO *)dev->Tx.Active;
DmaError(&dev->Tx);
result = ADI_INT_RESULT_PROCESSED;
}
if (dev->Rx.Dma->IRQ_STATUS & 0x02) {
// error on RX channel
bi = (BUFFER_INFO *)dev->Rx.Active;
DmaError(&dev->Rx);
result = ADI_INT_RESULT_PROCESSED;
}
return result;
}
//
// EMAC ethernet event interrupt handler
//
static ADI_INT_HANDLER(EtherInterruptHandler) // EMAC ethernet event interrupt handler
{
ADI_INT_HANDLER_RESULT result = ADI_INT_RESULT_NOT_PROCESSED;
ADI_ETHER_BF537_DATA *dev = (ADI_ETHER_BF537_DATA *)ClientArg;
u32 systat,mask, rirqs,tirqs,event;
event = ADI_ETHER_EVENT_INTERRUPT;
// Ethernet event interrupt
systat = *pEMAC_SYSTAT;
breakpoint(2);
// ack W1C bits
mask = systat&0xe1;
if (mask) *pEMAC_SYSTAT = mask;
// now to process individual bits
if (systat&0x02) {
// MMC counter interrupt
rirqs = *pEMAC_MMC_RIRQS;
tirqs = *pEMAC_MMC_TIRQS;
UpdateStatistics((u64*)dev->Stats);
// clear the interrupt
*pEMAC_MMC_RIRQS = rirqs;
*pEMAC_MMC_TIRQS = tirqs;
result = ADI_INT_RESULT_PROCESSED;
}
if (systat&0x01) {
//PHY_INT
int full=0;
u32 opmode;
u16 reg3,reg2,reg,phydat;
reg2 = RdPHYReg(dev->PhyAddr,2); // read PHY id 1
reg3 = RdPHYReg(dev->PhyAddr,3); // read PHY id 2
if ((reg2 == 0x07) && ((reg3>>4) == 0xc0a)) {
// SMSC LAN83C185
reg = RdPHYReg(dev->PhyAddr,31); // read special status
full = (reg&0x10);
if (full) {
// does remote link support flow control
phydat = RdPHYReg(dev->PhyAddr,PHYREG_ANLPAR);
dev->FlowControl = (phydat &0x0400);
if (dev->FlowControl) {
// we enable flow control
*pEMAC_FLC = FLCE; /* flow control enabled */
// advertize flow control supported
}
}
}
opmode = *pEMAC_OPMODE;
if (full) {
opmode |= 0x04000000;
} else {
opmode &= 0xfbffffff;
}
*pEMAC_OPMODE = opmode;
systat = RdPHYReg(dev->PhyAddr,29); // read interrupt sources
event = ADI_ETHER_EVENT_INTERRUPT_PHY;
result = ADI_INT_RESULT_PROCESSED;
}
//invoke the callback function
if (dev->DCBHandle) {
#ifdef ADI_ETHER_BF537_DEBUG
ADI_ETHER_BF537_OutstandingPosts++;
#endif
adi_dcb_Post(dev->DCBHandle,0,dev->DMCallback, dev->DeviceHandle, event, (void *)systat);
} else {
(dev->DMCallback)(dev->DeviceHandle, event,(void *)systat);
}
return result;
}
//
// Append Pending queue to the active queue
//
static AppendPending(FRAME_QUEUE *q, ADI_ETHER_BUFFER *lstact)
{
BUFFER_INFO *bi,*bipend;
CheckQueues(q);
{
ADI_ETHER_BUFFER *pnd = q->Active;
while (pnd && pnd->pNext) {
pnd = pnd->pNext;
}
if (lstact != pnd) {
int k=4;
}
}
// update the Active and Pending queues
if (lstact == NULL) {
if (q->Active != NULL) {
int k=4;
}
CheckQueues(q);
q->Active = q->Pending;
} else {
CheckQueues(q);
lstact->pNext = q->Pending;
// chain on the deswcriptors
bi = (BUFFER_INFO*)lstact;
bipend = (BUFFER_INFO*)q->Pending;
bi->Last->NEXT_DESC_PTR = bipend->First;
// update the config in the last desc
if ((q->Rcve==0) && (q->Pending->PayLoad!=NULL)) {
bi->Last->CONFIG &= 0xf0ff; // remove the current ndsize
bi->Last->CONFIG |= 0x7600; // or in flow as 7 and ndsize as 6
} else {
// the previous value will have been 8b
#ifdef USE_SYNC
bi->Last->CONFIG |= 0x7520; // or in flow as 7 and ndsize as 5 as SYNC
#else
bi->Last->CONFIG |= 0x7500; // or in flow as 7 and ndsize as 5
#endif
}
}
#ifdef ADI_ETHER_BF537_DEBUG
{
ADI_ETHER_BUFFER *pnd = q->Pending;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -