📄 et9000if.c
字号:
/*
* et9000if.c
* NC9100 Ethernet driver for DM9000E
* 2004-05-05
*/
#include "sysdef.h"
#include "lwip/debug.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "netif/etharp.h"
#include "at91lib.h"
//#include "dump.h"
#include "lwipopts.h"
#include "et9000if.h"
#include "string.h"
#include "schedule.h"
#include "lwip/stats.h"
#include "config.h"
#define IFNAME0 'e'
#define IFNAME1 't'
extern struct stats_ lwip_stats;
// Board/System/Debug information/definition
#define NIC_BASE ((u8_t *)0x03000000)
#define DM9000_ID 0x90000A46
#define DM9000_REG00 0x00
#define DM9000_REG05 0x30 // SKIP_CRC/SKIP_LONG
#define DM9000_REG08 0x27
#define DM9000_REG09 0x38
#define DM9000_REG0A 0xff
#define DM9000_REGFF 0x83 // IMR
#define DM9000_PHY 0x40 // PHY address 0x01
#define DM9000_PKT_MAX 1536 // Received packet max size
#define DM9000_PKT_RDY 0x01 // Packet ready to receive
#define DM9000_INDEX 0x00
#define DM9000_DATA 0x04
#define DM9000_INT_MII 0x00
#define DM9000_EXT_MII 0x80
#define DM9000_VID_L 0x28
#define DM9000_VID_H 0x29
#define DM9000_PID_L 0x2A
#define DM9000_PID_H 0x2B
#define DM9801_NOISE_FLOOR 0x08
#define DM9802_NOISE_FLOOR 0x05
#define DMFE_SUCC 0
#define MAX_PACKET_SIZE 1514
#define DMFE_MAX_MULTICAST 14
#define DM9000_RX_INTR 0x01
#define DM9000_TX_INTR 0x02
#define DM9000_OVERFLOW_INTR 0x04
#define DM9000_DWORD_MODE 1
#define DM9000_BYTE_MODE 2
#define DM9000_WORD_MODE 0
enum DM9000_PHY_mode {
DM9000_10MHD = 0,
DM9000_100MHD = 1,
DM9000_10MFD = 4,
DM9000_100MFD = 5,
DM9000_AUTO = 8,
DM9000_1M_HPNA = 0x10
};
enum DM9000_NIC_TYPE {
FASTETHER_NIC = 0,
HOMERUN_NIC = 1,
LONGRUN_NIC = 2
};
struct dev_mc_list {
struct dev_mc_list *next;
u8_t dmi_addr[8];
unsigned char dmi_addrlen;
int dmi_users;
int dmi_gusers;
};
//_____________________________________________________________________________________
static int media_mode = DM9000_AUTO;
static u8_t nfloor = 0;
Dm9000if_t dm9000if;
static u8_t *ethernetnic = NIC_BASE;
// Help routines_______________________________________________________________________
static u32_t ether_crc_le(int cnt, unsigned char *addr)
{
unsigned int crc = 0xffffffff;
u8_t byte, idx, bit;
for (idx = 0; idx < cnt; idx++)
for (byte = *addr++, bit = 0; bit < 8; bit++, byte >>= 1)
crc = (crc >> 1) ^ (((crc ^ byte) & 1) ? 0xedb88320U : 0);
return crc;
}
// Calculate the CRC valude of the Rx packet
// flag = 1 : return the reverse CRC (for the received packet CRC)
// 0 : return the normal CRC (for Hash Table index)
static u32_t cal_CRC(unsigned char * Data, unsigned int Len, u8_t flag)
{
u32_t crc = ether_crc_le(Len, Data);
if (flag)
return ~crc;
return crc;
}
static inline void udelay(volatile int time)
{
while (--time > 0);
}
static inline u8_t inb(u16_t portno)
{
return *(volatile u8_t *)(ethernetnic + portno);
}
static inline void outb(u8_t value, u16_t portno)
{
*(volatile u8_t *)(ethernetnic + portno) = value;
}
// Read a byte from I/O port
static u8_t ior(int reg)
{
outb(reg, DM9000_INDEX);
return inb(DM9000_DATA);
}
// Write a byte to I/O port
static void iow(int reg, u8_t value)
{
outb(reg, DM9000_INDEX);
outb(value, DM9000_DATA);
}
// Read a word from phyxcer
static u16_t phy_read(int reg)
{
// Fill the phyxcer register into REG_0C
iow(0xc, DM9000_PHY | reg);
iow(0xb, 0xc); // Issue phyxcer read command
udelay(100); // Wait read complete
iow(0xb, 0x0); // Clear phyxcer read command
// The read data keeps on REG_0D & REG_0E
return ( ior(0xe) << 8 ) | ior(0xd);
}
// Write a word to phyxcer
static void phy_write(int reg, u16_t value)
{
/* Fill the phyxcer register into REG_0C */
iow(0xc, DM9000_PHY | reg);
/* Fill the written data into REG_0D & REG_0E */
iow(0xd, (value & 0xff));
iow(0xe, ( (value >> 8) & 0xff));
iow(0xb, 0xa); /* Issue phyxcer write command */
udelay(500); /* Wait write complete */
iow(0xb, 0x0); /* Clear phyxcer write command */
}
static inline u16_t inw(u16_t portno)
{
return *(volatile u16_t *)(ethernetnic + portno);
}
static inline void outw(u16_t value, u16_t portno)
{
*(volatile u16_t *)(ethernetnic + portno) = value;
}
static void outsw(u16_t *p, int len)
{
int i;
len = (len + 1) >> 1;
for (i = 0; i < len; i++)
*(volatile u16_t *)(ethernetnic + DM9000_DATA) = *p++;
}
static void insw(u16_t *p, int len)
{
int i;
len = (len + 1) >> 1;
for (i = 0; i < len; i++)
*p++ = *(volatile u16_t *)(ethernetnic + DM9000_DATA);
}
/*
static u8_t readReg(int reg)
{
u8_t reg_save;
u8_t status;
reg_save = inb(DM9000_INDEX);
status = ior(reg);
outb(reg_save, DM9000_INDEX);
return status;
}
*/
// DM9000 NIC____________________________________________________
static int dmfe_probe(Dm9000if_t *db)
{
u32_t id_val;
/* Id DM9000 NIC */
id_val = ior(DM9000_VID_L);
id_val |= ior(DM9000_VID_H) << 8;
id_val |= ior(DM9000_PID_L) << 16;
id_val |= ior(DM9000_PID_H) << 24;
if (id_val != DM9000_ID)
return -1;
return 0;
}
// Set PHY operationg mode
static void set_PHY_mode(Dm9000if_t *db)
{
u16_t phy_reg4 = 0x01e1, phy_reg0=0x1000;
if (!(db->op_mode & DM9000_AUTO)) {
switch(db->op_mode) {
case DM9000_10MHD:
phy_reg4 = 0x21;
phy_reg0 = 0x0000;
break;
case DM9000_10MFD:
phy_reg4 = 0x41;
phy_reg0 = 0x1100;
break;
case DM9000_100MHD:
phy_reg4 = 0x81;
phy_reg0 = 0x2000;
break;
case DM9000_100MFD:
phy_reg4 = 0x101;
phy_reg0 = 0x3100;
break;
}
phy_write(4, phy_reg4); /* Set PHY media mode */
phy_write(0, phy_reg0); /* Tmp */
}
iow(0x1e, 0x01); /* Let GPIO0 output */
iow(0x1f, 0x00); /* Enable PHY */
}
// Init HomeRun DM9801
static void program_dm9801(u16_t HPNA_rev)
{
u16_t reg16, reg17, reg24, reg25;
if (!nfloor)
nfloor = DM9801_NOISE_FLOOR;
reg16 = phy_read(16);
reg17 = phy_read(17);
reg24 = phy_read(24);
reg25 = phy_read(25);
switch(HPNA_rev) {
case 0xb900: /* DM9801 E3 */
reg16 |= 0x1000;
reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xf000;
break;
case 0xb901: /* DM9801 E4 */
reg25 = ( (reg24 + nfloor) & 0x00ff) | 0xc200;
reg17 = (reg17 & 0xfff0) + nfloor + 3;
break;
case 0xb902: /* DM9801 E5 */
case 0xb903: /* DM9801 E6 */
default:
reg16 |= 0x1000;
reg25 = ( (reg24 + nfloor - 3) & 0x00ff) | 0xc200;
reg17 = (reg17 & 0xfff0) + nfloor;
}
phy_write(16, reg16);
phy_write(17, reg17);
phy_write(25, reg25);
}
// Init LongRun DM9802
static void program_dm9802(void)
{
u16_t reg25;
if (!nfloor)
nfloor = DM9802_NOISE_FLOOR;
reg25 = phy_read(25);
reg25 = (reg25 & 0xff00) + nfloor;
phy_write(25, reg25);
}
// Identify NIC type
static void identify_nic(Dm9000if_t *db)
{
u16_t phy_reg3;
iow(0, DM9000_EXT_MII);
phy_reg3 = phy_read(3);
switch(phy_reg3 & 0xfff0) {
case 0xb900:
if (phy_read(31) == 0x4404) {
db->nic_type = HOMERUN_NIC;
program_dm9801(phy_reg3);
}
else {
db->nic_type = LONGRUN_NIC;
program_dm9802();
}
break;
default:
db->nic_type = FASTETHER_NIC;
break;
}
iow(0, DM9000_INT_MII);
}
// Set DM9000 multicast address
static void dm9000_hash_table(Dm9000if_t *db)
{
struct dev_mc_list *mcptr = NULL;
int mc_cnt = 0;
u32_t hash_val;
u16_t i, oft, hash_table[4];
/* Clear Hash Table */
for (i = 0; i < 4; i++)
hash_table[i] = 0x0;
/* broadcast address */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -