📄 freedev_lan91c111.c
字号:
/*
* Register definitions for the Rtl8019as ethernet chip used on the Nios II
* FreeDev2.1 development boards
* Create by Free-electron
* author:liu-jun-sheng
* address:MoGanShan road HangZhou ZheJiang China
* tel:0571-88846603
* www.Free-Electron.com.cn
* date:2005/12/02
*/
#ifdef LWIP
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "alt_types.h"
#include "freedev_lan91c111_regs.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"
#include "freedev_lan91c111.h"
/* Unique descricption of the network interface. */
#define IFNAME0 'n'
#define IFNAME1 '9'
extern sys_mbox_t rx_mbox;
/*
* Prototypes
*/
static err_t low_level_init(freedev_lan91c111_if* dev);
static struct pbuf* low_level_input(freedev_lan91c111_if *dev);
static err_t low_level_output(struct netif *netif, struct pbuf *p);
static err_t freedev_lan91c111_output(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
/*-----------------------------------------------------------------------------------*
*
* freedev_lan91c111_input():
*
* 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.
*
*
*-----------------------------------------------------------------------------------*/
static void freedev_lan91c111_input(freedev_lan91c111_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
*
* The code which updates the ARP tables does not appear to be thread safe
* so I've added a MUTEX around all calls to the arp code
*
*/
sys_sem_wait(dev->arp_semaphore);
etharp_ip_input(netif, p);
sys_sem_signal(dev->arp_semaphore);
/* skip Ethernet header */
pbuf_header(p, -(s16_t)sizeof(struct eth_hdr));
/* pass to network layer */
netif->input(p, netif);
break;
case ETHTYPE_ARP:
/*
* pass p to ARP module
*
* The code which updates the ARP tables does not appear to be thread safe
* so I've added a MUTEX around all calls to the arp code
*
*/
sys_sem_wait(dev->arp_semaphore);
etharp_arp_input(netif, (struct eth_addr *)&netif->hwaddr, p);
sys_sem_signal(dev->arp_semaphore);
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
/*-----------------------------------------------------------------------------------*
*
* freedev_lan91c111_init():
*
* 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.
*
*
*-----------------------------------------------------------------------------------*/
err_t freedev_lan91c111_init(struct netif *netif)
{
err_t ret_code;
freedev_lan91c111_if* dev = (freedev_lan91c111_if*)netif->state;
dev->lwip_dev_list.dev.netif = netif;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("freedev_lan91c111_init()\n"));
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = freedev_lan91c111_output;
netif->linkoutput = low_level_output;
if (netif->state == NULL )
{
ret_code = ERR_IF;
goto exit;
}
/* 20051227 modify by free_electron
if (dev->bus_width != 32)
{
printf("This driver doesn't support the Ethernet add on card at present\n");
ret_code = ERR_IF;
goto exit;
}
*/
ret_code = low_level_init(dev);
if (ret_code == ERR_OK)
{
etharp_init();
}
else
{
free(netif->state);
}
exit:
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("freedev_lan91c111_init() exit = %d\n",ret_code));
return ret_code;
}
/*
* freedev_lan91c111_irq
*
* The Interrupt handler
*/
static void freedev_lan91c111_irq(void* context, alt_u32 interrupt)
{
alt_u8 irq_status;
alt_u8 irq_msk;
freedev_lan91c111_if *dev = (freedev_lan91c111_if *)context;
irq_status = IORD_FREEDEV_LAN91C111_IST(dev->base_addr);
/*
* Rx Overrun, clear the interrupt and increment the stats counter
*/
#if LINK_STATS
if(irq_status & FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK)
{
lwip_stats.link.drop++;
IOWR_FREEDEV_LAN91C111_ACK(dev->base_addr,
FREEDEV_LAN91C111_INT_RX_OVRN_INT_MSK);
}
#endif /* LINK_STATS */
/*
* Packet to Receive
*
* signal the thread which will read the data and disable interrupts
*
*/
irq_msk = IORD_FREEDEV_LAN91C111_MSK(dev->base_addr);
if((irq_status & FREEDEV_LAN91C111_INT_RCV_INT_MSK) &&
(irq_msk & FREEDEV_LAN91C111_INT_RCV_INT_MSK))
{
irq_msk &= ~FREEDEV_LAN91C111_INT_RCV_INT_MSK;
IOWR_FREEDEV_LAN91C111_MSK(dev->base_addr, irq_msk);
sys_mbox_post(rx_mbox, &dev->lwip_dev_list.dev);
}
return;
}
/*
* freedev_lan91c111_rx
* Handle all the receives
*/
void freedev_lan91c111_rx( alt_lwip_dev* dev )
{
alt_u8 irq_msk;
alt_u8 irq_status;
freedev_lan91c111_if *lan_dev = (freedev_lan91c111_if *)dev->netif->state;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("lan91c111_rx()"));
irq_status = IORD_FREEDEV_LAN91C111_IST(lan_dev->base_addr);
while(irq_status & FREEDEV_LAN91C111_INT_RCV_INT_MSK)
{
freedev_lan91c111_input(lan_dev);
irq_status = IORD_FREEDEV_LAN91C111_IST(lan_dev->base_addr);
}
/* Re-enable RX interrupts */
irq_msk = IORD_FREEDEV_LAN91C111_MSK(lan_dev->base_addr);
irq_msk |= FREEDEV_LAN91C111_INT_RCV_INT_MSK;
IOWR_FREEDEV_LAN91C111_MSK(lan_dev->base_addr, irq_msk);
}
/*
* Clock one bit of data to the PHY
*/
static void clock_phy_bit(freedev_lan91c111_if* dev, const unsigned value)
{
IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, value);
IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, value |
FREEDEV_LAN91C111_MGMT_MCLK_MSK);
}
/*
* Read a PHY register, this involves manually clocking lots
* of data.
*/
static alt_u16 read_phy_register(freedev_lan91c111_if* dev,
const unsigned phy_register)
{
alt_u16 register_value;
alt_u16 old_bank;
alt_u16 mgmt_value;
int i;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("read_phy_register (%d)=", phy_register));
/*
* Swap to bank 3
*/
old_bank = IORD_FREEDEV_LAN91C111_BSR(dev->base_addr);
IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,3);
mgmt_value = IORD_FREEDEV_LAN91C111_MGMT( dev->base_addr);
mgmt_value &= 0xfff0;
/* Output an Idle of 32 1's */
for(i=0;i<32;i++)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
}
/* Ouput 01 which marks the change of cycle */
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
/* Output the command, 10 = read */
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
/* Output the PHY address, 0 is the internal PHY */
for(i=0;i<5;i++)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
}
/* Write the Register Address, MSB first */
for(i=4;i>=0;i--)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
((phy_register >> i) & 0x1));
}
/*
* The datasheet says we output Z0 here, however Application Note 79 mentions a chip bug
* which configuring the Nat Semi in built PHY we only output Z, if using an off chip PHY
* uncomment the second line
*/
clock_phy_bit(dev, mgmt_value);
/*
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
*/
register_value = 0;
/* Read in the data */
for(i=15;i>=0;i--)
{
clock_phy_bit(dev, mgmt_value);
register_value |=
((IORD_FREEDEV_LAN91C111_MGMT(dev->base_addr)
& FREEDEV_LAN91C111_MGMT_MDI_MSK) >> 1) << i;
}
/* Output the Turnaround bit */
clock_phy_bit(dev, mgmt_value);
IOWR_FREEDEV_LAN91C111_MGMT(dev->base_addr, mgmt_value);
IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,old_bank);
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, (" %#x\n", register_value));
return register_value;
}
/*
* Write to a PHY register, this involves manually clocking out lots
* of data.
*/
static void write_phy_register(freedev_lan91c111_if* dev,
const unsigned phy_register,
const alt_u16 value)
{
alt_u16 old_bank;
alt_u16 mgmt_value;
int i;
LWIP_DEBUGF(NETIF_DEBUG | DBG_TRACE, ("write_phy_register (%d, %#x)\n", phy_register, value));
/*
* Swap to bank 3, if this code is ever changed to run with interrups we will
* need a critical section here
*/
old_bank = IORD_FREEDEV_LAN91C111_BSR(dev->base_addr);
IOWR_FREEDEV_LAN91C111_BSR( dev->base_addr,3);
mgmt_value = IORD_FREEDEV_LAN91C111_MGMT(dev->base_addr);
mgmt_value &= 0xfff0;
/* Output an Idle of 32 1's */
for(i=0;i<32;i++)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
}
/* Ouput 01 which marks the change of cycle */
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
/* Output the command, 01 = write */
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
/* Output the PHY address, 0 is the internal PHY */
for(i=0;i<5;i++)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
}
/* Write the Register Address, MSB first */
for(i=4;i>=0;i--)
{
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
((phy_register >> i) & 0x1));
}
/* Write 10 to the turnaround bit */
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK |
FREEDEV_LAN91C111_MGMT_MDO_MSK );
clock_phy_bit(dev, mgmt_value |
FREEDEV_LAN91C111_MGMT_MDOE_MSK );
/* Now write the data MSB first */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -