⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lan91c111.c

📁 lwip tcp/ip 协议栈 adsp BF533 DSP 移植 用 visual dsp++ 编译
💻 C
📖 第 1 页 / 共 4 页
字号:
/*********************************************************************************

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 + -