📄 zlg_avalon_rtl8019.c
字号:
/****************************************Copyright (c)**************************************************
** Guangzhou ZHIYUAN ELECTRONIC CO.,LTD.
** Research centre
** http://www.zyinside.com, http://www.zlgmcu.com
**
**---------------------------------------File Info-----------------------------------------------------
** File name: zlg_avalon_rtl8019.c
** Latest modified Date: 2005-09-30
** Latest Version: 1.0
** Descriptions: LWIP ethernet interface for the RTL8019 on the ZLG NiosII board
**
**------------------------------------------------------------------------------------------------------
** Created by: Jing.Zhang
** Created date: 2005-09-30
** Version: 1.0
** Descriptions: The original version
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
********************************************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "zlg_avalon_rtl8019.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/netif.h"
#include "lwip/stats.h"
#include "netif/etharp.h"
#include "system.h"
#include "arch/perf.h"
#include "sys/alt_irq.h"
#ifdef ALT_DEBUG
int reg;
#endif
//#include "debug.h"
/* Unique description of the network interface. */
#define IFNAME0 ZLG_8019AS_CHIP_ID0
#define IFNAME1 ZLG_8019AS_CHIP_ID1
extern sys_mbox_t rx_mbox;
/*------------- Private functions Prototypes ------------*/
static err_t low_level_init(zlg_avalon_rtl8019_if* dev);
static struct pbuf* low_level_input(zlg_avalon_rtl8019_if *dev);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static err_t zlg_avalon_rtl8019_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
static void zlg_avalon_rtl8019_irq(void* context, alt_u32 interrupt);
/*********************************************************************************************************
** Function name: low_level_init
**
** Descriptions: Initialize the rti8019 into the specific mode
**
** input parameters: dev -- a pointer to rti8019 device structure
**
** Returned value: err_t -- error information
**
** Used global variables: None
** Calling modules:
**
** Created by: Jing.Zhang
** Created Date: 2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static err_t low_level_init(zlg_avalon_rtl8019_if* dev)
{
/*
* Need to have a pointer to a generice lwip_dev
* This is so that the get_mac_addr function interface
* is device agnostic
*/
alt_lwip_dev* lwip_dev = &dev->lwip_dev_list.dev;
err_t ret_code = ERR_OK;
alt_u32 i;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init()\n"));
/*
* Disable interrupts
*/
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 0);
/*
* Initialize the MAC address as "00 14 97 0f 02 95"
*/
lwip_dev->netif->hwaddr[0] = 0x00;
lwip_dev->netif->hwaddr[1] = 0x14;
lwip_dev->netif->hwaddr[2] = 0x97;
lwip_dev->netif->hwaddr[3] = 0x0f;
lwip_dev->netif->hwaddr[4] = 0x02;
lwip_dev->netif->hwaddr[5] = 0x95;
/* maximum transfer unit */
lwip_dev->netif->mtu = 1500;
/* broadcast capability */
lwip_dev->netif->flags = NETIF_FLAG_BROADCAST;
/* Set MAC hardware address length */
lwip_dev->netif->hwaddr_len = 6;
/* reset the rtl8019 and power it on*/
RTL8019_HRST(dev->rst_pio_base);
RTL8019_SRST(dev->base_addr);
/* Prepare for configuring rtl8019 */
SET_CR_REG(dev->base_addr,0x21);
usleep(2000);//Wait 2ms for stop command is complete
/* Clear RBCR0 and RBCR1 */
SET_RBCR0_REG(dev->base_addr,0x00);
SET_RBCR1_REG(dev->base_addr,0x00);
SET_RCR_REG(dev->base_addr,0xe0);
SET_TCR_REG(dev->base_addr,0xe2);
/* Set the range of receive buffer ring */
SET_PSTART_REG(dev->base_addr,0x4c);
SET_PSTOP_REG(dev->base_addr,0x80);
SET_BNRY_REG(dev->base_addr,0x4c);
/* Set the start page of transmit buffer */
SET_TPSR_REG(dev->base_addr,0x40);
/* Little endian, word-wide DMA transfer */
SET_DCR_REG(dev->base_addr,0xc9);
/* Clear all the interrupt flags in ISR */
SET_ISR_REG(dev->base_addr,0xff);
SET_IMR_REG(dev->base_addr,0x00);
/* Select register page1 explicitly */
SelectPage(dev->base_addr, 1);
/* Set current page as 0x4d */
SET_CURR_REG(dev->base_addr,0x4d);
/* Disable the multicast address */
for(i=0; i<8; i++)
{
SET_MAR_REG(dev->base_addr,i,0x00);
}
/* START rtl8019 in the normal mode */
SET_CR_REG(dev->base_addr,0x22);
/* Select register page1 explicitly */
SelectPage(dev->base_addr, 1);
for(i=0; i<6; i++)
{
SET_PAR_REG(dev->base_addr,i,lwip_dev->netif->hwaddr[i]);
}
SelectPage(dev->base_addr, 0);
SET_RCR_REG(dev->base_addr,0xc4);
SET_TCR_REG(dev->base_addr,0xe0);
SET_CR_REG(dev->base_addr,0x22);
SET_ISR_REG(dev->base_addr,0xff);
/* Create semaphore for low_level_input and low_level_ouput */
dev->semaphore = sys_sem_new(1);
if (dev->semaphore == NULL)
{
ret_code = ERR_MEM;
goto exit;
}
/* Create semaphore for ARP service */
dev->arp_semaphore = sys_sem_new(1);
if (dev->arp_semaphore == NULL)
{
ret_code = ERR_MEM;
goto exit;
}
/*
* Install ISR and turn on interrupts
*
* If you're counting stats then we also turn on the RCV_OVRN
* interrupt and increment the error counter for each interrupt
*
*/
if (alt_irq_register ( dev->irq, dev, zlg_avalon_rtl8019_irq))
{
ret_code = ERR_IF;
goto exit;
}
exit:
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("low_level_init() exit = %d\n", ret_code));
return ret_code;
}
/*********************************************************************************************************
** Function name: zlg_avalon_rtl8019_init
**
** Descriptions: Should be called at the beginning of the program to set up the
** network interface. It calls the function low_level_init() to do the
** actual setup of the hardware.
**
** input parameters: netif -- a pointer to a net device
**
** Returned value: err_t -- error information
**
** Used global variables: None
** Calling modules:
**
** Created by: Jing.Zhang
** Created Date: 2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
err_t zlg_avalon_rtl8019_init(struct netif *netif)
{
err_t ret_code;
zlg_avalon_rtl8019_if* dev = (zlg_avalon_rtl8019_if*)netif->state;
dev->lwip_dev_list.dev.netif = netif;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("alt_avalon_lan91c111_init()\n"));
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = zlg_avalon_rtl8019_output;
netif->linkoutput = low_level_output;
if (netif->state == NULL )
{
ret_code = ERR_IF;
goto exit;
}
/* Do the actual configuration of hardware */
ret_code = low_level_init(dev);
if (ret_code == ERR_OK)
{
etharp_init();
}
else
{
free(netif->state);
}
/* Enable interrupts */
IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 1);
SelectPage(dev->base_addr, 0);
SET_IMR_REG(dev->base_addr,0x11);
exit:
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("alt_avalon_lan91c111_init() exit = %d\n",ret_code));
return ret_code;
}
/*********************************************************************************************************
** Function name: zlg_avalon_rtl8019_irq
**
** Descriptions: The Interrupt handler
**
** input parameters: context -- a parameter passed to callback function
** interrupt -- interrupt id
**
** Returned value: none
**
** Used global variables: None
** Calling modules:
**
** Created by: Jing.Zhang
** Created Date: 2005/11/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void zlg_avalon_rtl8019_irq(void* context, alt_u32 interrupt)
{
alt_u8 irq_status,curr,bnry;
zlg_avalon_rtl8019_if *dev = (zlg_avalon_rtl8019_if *)context;
SelectPage(dev->base_addr,0);
irq_status = GET_ISR_REG(dev->base_addr);
SET_ISR_REG(dev->base_addr,irq_status); //Acknowledge the Interrupt request
/*
* Rx Overrun, clear the interrupt and increase the stats counter
*/
if(irq_status & ZLG_8019AS_ISR_OVW_MSK)
{
#if LINK_STATS
lwip_stats.link.drop++;
#endif
SelectPage(dev->base_addr,1);
curr = GET_CURR_REG(dev->base_addr);
SelectPage(dev->base_addr,0);
bnry = curr -1; //restore the value of bnry
if(bnry < 0x4c)
{
bnry = 0x7f;
}
SET_BNRY_REG(dev->base_addr,bnry); //restore the bnry register
}
else
{
/*
* Packet to Receive
*
* signal the thread which will read the data and disable interrupts
*
*/
if(irq_status & ZLG_8019AS_ISR_PRX_MSK)
{
/* Disable interrupt */
//IOWR_ALTERA_AVALON_PIO_EDGE_CAP(dev->irq_pio_base, 0);
//IOWR_ALTERA_AVALON_PIO_IRQ_MASK(dev->irq_pio_base, 0);
//SelectPage(dev->base_addr,0);
//SET_IMR_REG(dev->base_addr,0x00);
/* Issue the signal */
sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
}
}
}
/*********************************************************************************************************
** Function name: zlg_avalon_rtl8019_input
**
** Descriptions: This function should be called when a packet is ready to be read
** from the interface. It uses the function low_level_input() that
** should handle the actual reception of bytes from the network
** interface.
**
** input parameters: dev -- a pointer to a rtl8019 device structure
**
** Returned value: none
**
** Used global variables: None
** Calling modules:
**
** Created by: Jing.Zhang
** Created Date: 2005/12/08
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void zlg_avalon_rtl8019_input(zlg_avalon_rtl8019_if *dev)
{
struct eth_hdr *ethhdr;
struct pbuf *p;
struct netif* netif = dev->lwip_dev_list.dev.netif;
/* move received packet into a new pbuf */
p = low_level_input(dev);
/* no packet could be read, silently ignore this */
if (p == NULL) return;
ethhdr = p->payload;
switch (htons(ethhdr->type)) {
/* IP packet? */
case ETHTYPE_IP:
/*
* update ARP table
*/
sys_sem_wait(dev->arp_semaphore);
etharp_ip_input(netif, p);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -