📄 lan91c111.c
字号:
/*********************************************************************************
Copyright(c) 2004 Analog Devices, Inc. All Rights Reserved.
This software is proprietary and confidential. By using this software you agree
to the terms of the associated Analog Devices License Agreement.
*********************************************************************************/
#define USE_16_BIT
#include <string.h>
#include <stdio.h>
#include <sys/exception.h>
#include <services/services.h>
#include <drivers/adi_dev.h>
#include <services/adi_dcb.h>
#include <services/adi_dma.h>
#include <services/adi_int.h>
#include <services/adi_ebiu.h>
#include <ADI_ETHER_USBLAN.h>
#include "lan91c111.h"
#include "io_sprt.h"
#include <kernel_abs.h>
#ifdef __ADSPBF535__
#include <cdefbf535.h>
#endif /* __ADSPBF535__ */
#ifdef __ADSPBF533__
#include <cdefbf533.h>
#endif /* __ADSPBF533__ */
void dma_protect(ADI_ETHER_LAN91C111_DATA *d,DMA_DIRECTION direction);
void dma_initiate_transfer(unsigned long src_addr,
unsigned long des_addr,
unsigned long num_bytes,
DMA_DIRECTION dir);
void dma_relinquish();
void init_dma(ADI_ETHER_LAN91C111_DATA *dev);
void *drv_CriticalHandle;
#define ACK_LAN_INT(pf) ((*pFIO_FLAG_C = pf))
#define MAX_RCVE_FRAME 1560
#define FLUSH(P) asm volatile("SSYNC;FLUSH[%0++];SSYNC;":"+p"(P));
//###define FLUSH(P) asm volatile("NOP;":"+p"(P));
#define FLUSHINV(P) asm volatile("SSYNC;FLUSHINV[%0++];SSYNC;":"+p"(P));
#define SIMPLEFLUSHINV(P) asm volatile("SSYNC;FLUSHINV[%0++];SSYNC;"::"#p"(P));
#define ENTER_CRITICAL_REGION() (drv_CriticalHandle=adi_int_EnterCriticalRegion(dev->CriticalData))
#define EXIT_CRTICIAL_REGION() (adi_int_ExitCriticalRegion(drv_CriticalHandle))
#define LAN91C111_LOG_NET_ERRORS 1
#define MDMA_STREAM0_INT_NUM 21
#define MDMA_STREAM1_INT_NUM 22
/* The transmission attempt failed due to lack of memory - so queue and retry next time */
#define LAN91C111_TX_RETRY 1
/* The transmission attempt is an unrecoverable error - free the packet, drop it */
#define LAN91C111_TX_ERROR 2
/* The transmission attempt completed successfully */
#define LAN91C111_TX_SUCCESS 3
static ADI_ETHER_LAN91C111_DATA EtherDev={0};
static ADI_ETHER_LAN91C111_DATA *pHandle;
/* function protots */
int QueueNewRcvFrames(ADI_ETHER_LAN91C111_DATA *dev,ADI_ETHER_BUFFER *bfs);
int QueueNewXmtFrames(ADI_ETHER_LAN91C111_DATA *dev,ADI_ETHER_BUFFER *bfs);
void transmit_complete();
void receive_complete();
void dma_interrupt_handler(void *arg,unsigned int v, unsigned int g);
void reset_dma(ADI_ETHER_LAN91C111_DATA *d);
#include <cycle_count_bf.h>
static void FlushArea(void *start, void *nd)
{
start = (void *)(((unsigned int)start)&(~31));
while (start<nd)
FLUSH(start);
}
static void FlushInvArea(void *start, void *nd)
{
start = (void *)(((unsigned int)start)&(~31));
while (start<nd) FLUSHINV(start);
}
static void ker_msec(void)
{
unsigned long long int cur,nd;
_GET_CYCLE_COUNT(cur);
nd = cur + (__PROCESSOR_SPEED__/1000);
while (cur < nd) {
_GET_CYCLE_COUNT(cur);
}
}
static int smsc_sleep(unsigned int msec)
{
while (msec != 0) {
ker_msec();
msec--;
}
return 0;
}
#pragma optimize_off
/****************************************************************************
* Read register from EEPROM
****************************************************************************/
static int eeprom_read_reg(int reg_no)
{
int timeout;
// select bank 2
_outpw(BSR_REG, 2);
_outpw(PTR_REG,reg_no);
// select bank 1
_outpw(BSR_REG, 1);
_outpw(CTL_REG,_inpw(CTL_REG) | CTL_EEPROM_SELECT | CTL_RELOAD);
timeout = 100;
while((_inpw(CTL_REG) & CTL_RELOAD) && --timeout)
{
int t=10000;
while(t>0)
t--;
}
// error in reading from eeprom
if(timeout == 0)
return -1;
return(_inpw(GP_REG));
}
/****************************************************************************
* Write register to EEPROM
****************************************************************************/
static int eeprom_write_reg(int reg_no, int val)
{
int timeout;
// select bank 2
_outpw(BSR_REG, 2);
_outpw(PTR_REG,reg_no);
// select bank 1
_outpw(BSR_REG, 1);
_outpw(GP_REG, val);
_outpw(CTL_REG,_inpw(CTL_REG) | CTL_EEPROM_SELECT | CTL_STORE);
timeout = 100;
while((_inpw(CTL_REG) & CTL_STORE) && --timeout)
{
int t=10000;
while(t>0)
t--;
}
// error in reading from eeprom
if(timeout == 0)
return -1;
return 1;
}
/******************************************************************************
* Set MAC address in the SMSC
*****************************************************************************/
static void set_mac_in_SMSC(const char* mac_addr)
{
unsigned short page;
short wtmp;
// save old page
page = _inpw(BSR_REG);
// select bank 1
_outpw(BSR_REG, 1);
// Set EEPROM Store
_outpw(CTL_REG,CTL_EEPROM_SELECT | CTL_STORE);
wtmp = (((mac_addr[1])<<8)|(mac_addr[0]));
_outpw(ADDR0_REG, wtmp);
wtmp = (((mac_addr[3])<<8)|(mac_addr[2]));
_outpw(ADDR1_REG, wtmp);
wtmp = (((mac_addr[5])<<8)|(mac_addr[4]));
_outpw(ADDR2_REG, wtmp);
// restore bank
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
* Get MAC address From the SMSC
*****************************************************************************/
static void get_mac_frm_SMSC(char* mac_addr)
{
volatile unsigned short addr;
volatile unsigned short page;
page = _inpw(BSR_REG);
_outpw(BSR_REG, 1);
addr = _inpw(ADDR0_REG); // get MAC addr
mac_addr[0] = addr & 0xFF;
mac_addr[1] = addr >> 8;
addr = _inpw(ADDR1_REG); // get MAC addr
mac_addr[2] = addr & 0xFF;
mac_addr[3] = addr >> 8;
addr = _inpw(ADDR2_REG); // get MAC addr
mac_addr[4] = addr & 0xFF;
mac_addr[5] = addr >> 8;
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
* Get MAC address From the EEPROM
*****************************************************************************/
static void set_mac_in_EEPROM(const char* mac_addr)
{
unsigned short page;
short wtmp;
// save old page
page = _inpw(BSR_REG);
wtmp = (((mac_addr[1])<<8)|(mac_addr[0]));
eeprom_write_reg(0x20,wtmp);
wtmp = (((mac_addr[3])<<8)|(mac_addr[2]));
eeprom_write_reg(0x21, wtmp);
wtmp = (((mac_addr[5])<<8)|(mac_addr[4]));
eeprom_write_reg(0x22, wtmp);
// restore bank
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
* Get MAC address From the EEPROM
*****************************************************************************/
static void get_mac_frm_EEPROM(char* mac_addr)
{
volatile unsigned short addr,i,val,j=0;
volatile unsigned short page;
page = _inpw(BSR_REG);
// eeprom offset 20 has mac addr
for(i=0x20;i<0x23;i++)
{
val = eeprom_read_reg(i);
mac_addr[j++] = val & 0xff;
mac_addr[j++] = val >> 8;
}
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
* Change the current IRQ mask
*****************************************************************************/
static void LAN91C111_enable_int (unsigned char IRQ)
{
volatile unsigned short page;
// save old page
page = _inpw(BSR_REG);
// switch to bank 2
_outpw(BSR_REG, 2);
// update current mask
_outp(IM_REG, _inp(IM_REG) | IRQ);
// restore bank
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
* Change the current IRQ mask
*****************************************************************************/
static void LAN91C111_disable_int (unsigned char IRQ)
{
volatile unsigned short page;
volatile unsigned char mask;
// save old page
page = _inpw(BSR_REG);
// switch to bank 2
_outpw(BSR_REG, 2);
// write new mask
_outp(IM_REG, _inp(IM_REG) & ~IRQ);
// restore bank
_outpw(BSR_REG, page);
return;
}
/******************************************************************************
*
* This routine is called from the DMA handler. Once the DMA transfers the
* data the packet is removed from the PLI buffers.
*
*****************************************************************************/
void transmit_complete()
{
unsigned int length;
ADI_ETHER_BUFFER *tmp_q_ele;
unsigned short *buf;
unsigned short *elnth;
unsigned short lnth_first;
ADI_ETHER_BUFFER *bf = pHandle->m_TxEnqueuedHead;
// get length
elnth = (unsigned short *)bf->Data;
length = pHandle->m_TxEnqueuedHead->ElementCount -2;
length = ETH_ZLEN < length ? length : ETH_ZLEN;
// get pointer
buf = (unsigned short *)(((char *)bf->Data)+2);
// we already transferred length number of bytes
// point buffer to the length so tha we can send the remaining.
buf += length>>1 ; // buf is short pointer
/* Send the last byte, if there is one. */
if ((length & 1) == 0)
{
// write 0 as CONTROL unsigned char
_outpw(DATA_REG, 0x0000);
}
else
{
#ifndef USE_16_BIT
// last byte to be sent
if (length & 2) *buf = (*buf>>16);
#endif
// last byte to be sent
_outpw(DATA_REG, 0x2000 | (*buf) & 0xff);
}
// now set the status in the buffer bf
bf->ProcessedFlag = 1;
bf->ProcessedElementCount = (*elnth+2 + bf->ElementWidth-1)/bf->ElementWidth;
bf->StatusWord = 0x3; // completed and OK
pHandle->Stats->cEMAC_TX_CNT_OK++;
tmp_q_ele = pHandle->m_TxEnqueuedHead;
/* Change the Enqueued head */
pHandle->m_TxEnqueuedHead = (ADI_ETHER_BUFFER*)tmp_q_ele->pNext;
pHandle->m_TxEnqueuedCount--;
if (pHandle->m_TxEnqueuedCount == 0)
{
pHandle->m_TxEnqueuedTail = (ADI_ETHER_BUFFER*)NULL;
}
/* Add the packet to dequeued list*/
if (pHandle->m_TxDequeuedCount)
pHandle->m_TxDequeuedTail->pNext = (ADI_ETHER_BUFFER*)tmp_q_ele;
else
pHandle->m_TxDequeuedHead = tmp_q_ele;
//No matter what this is also the tail.
pHandle->m_TxDequeuedTail = tmp_q_ele;
//And tail->next should point to NULL
tmp_q_ele->pNext = (ADI_ETHER_BUFFER*)NULL;
pHandle->m_TxDequeuedCount++;
// and let the chipset deal with it
_outpw(MMU_CMD_REG, MC_ENQUEUE);
LAN91C111_enable_int( (SMC_INTERRUPT_MASK) );
}
void receive_complete()
{
ADI_ETHER_BUFFER *tmp_q_ele;
volatile unsigned short t_val;
unsigned short *elnth;
unsigned short packet_length;
tmp_q_ele = pHandle->m_RxEnqueuedHead;
elnth = (unsigned short *)tmp_q_ele->Data;
packet_length = *elnth;
/* Change the Enqueued head */
pHandle->m_RxEnqueuedHead = (ADI_ETHER_BUFFER*)tmp_q_ele->pNext;
pHandle->m_RxEnqueuedCount--;
if (pHandle->m_RxEnqueuedCount == 0)
pHandle->m_RxEnqueuedTail = (ADI_ETHER_BUFFER*)NULL;
/* Add the packet to dequeued list*/
if (pHandle->m_RxDequeuedCount)
pHandle->m_RxDequeuedTail->pNext =(ADI_ETHER_BUFFER*) tmp_q_ele;
else
pHandle->m_RxDequeuedHead = tmp_q_ele;
//No matter what this is also the tail.
pHandle->m_RxDequeuedTail = tmp_q_ele;
//And tail->next should point to NULL
tmp_q_ele->pNext = (ADI_ETHER_BUFFER*) NULL;
pHandle->m_RxDequeuedCount++;
// finally we have to update the status word etc
tmp_q_ele->ProcessedFlag = 1;
tmp_q_ele->StatusWord = 0x3000 + packet_length;
#if LAN91C111_LOG_NET_ERRORS
pHandle->Stats->cEMAC_RX_CNT_OK++;
#endif
// we received a new packet flush and invalidate the cache line
//
if(pHandle->Cache)
{
FlushInvArea((char*)tmp_q_ele->Data+2,(char*)tmp_q_ele->Data+packet_length);
}
while ( _inpw(MMU_CMD_REG ) & MC_BUSY );
// good or bad, delete this packet */
_outpw(MMU_CMD_REG, MC_RELEASE);
_outpw(BSR_REG, 2);
t_val = pHandle->int_state.saved_mask;
_outp(IM_REG, t_val);
t_val = pHandle->int_state.saved_pointer;
_outp(PTR_REG, t_val);
t_val = pHandle->int_state.saved_bank;
_outp(BSR_REG, t_val);
LAN91C111_enable_int(SMC_INTERRUPT_MASK);
}
/******************************************************************************
* Writes a word through the MII interface to the PHY
*****************************************************************************/
static void LAN91C111_write_phy_register(unsigned char phyreg, unsigned short phydata)
{
volatile int i;
volatile unsigned short oldBank, wmask, mii_reg;
volatile unsigned char bits[65], bmask;
volatile int clk_idx = 0;
// Prepare bit stream for PHY
// 32 consecutive ones on MDO to establish sync
for (i = 0; i < 32; ++i)
bits[clk_idx++] = MII_MDOE | MII_MDO;
// Start code <01>
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE | MII_MDO;
// Write command <01>
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE | MII_MDO;
// Output the PHY address, msb first, internal PHY = 0
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE;
bits[clk_idx++] = MII_MDOE;
// Output the phy register number, msb first
bmask = 0x10;
for (i = 0; i < 5; ++i)
{
if (phyreg & bmask)
bits[clk_idx++] = MII_MDOE | MII_MDO;
else
bits[clk_idx++] = MII_MDOE;
// Shift to next lowest bit
bmask >>= 1;
}
// Tristate and turnaround (2 bit times) <10>
bits[clk_idx++] = MII_MDOE | MII_MDO;;
bits[clk_idx++] = 0;
// Write out 16 bits of data, msb first
wmask = 0x8000;
for (i = 0; i < 16; ++i)
{
if (phydata & wmask)
bits[clk_idx++] = MII_MDOE | MII_MDO;
else
bits[clk_idx++] = MII_MDOE;
// Shift to next lowest bit
wmask >>= 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -