📄 dm9000x.c
字号:
#include "dm9000x.h"
#define DM9000_outb(d,r) ( *(volatile u8 *)r = d )
#define DM9000_outw(d,r) ( *(volatile u16 *)r = d )
#define DM9000_outl(d,r) ( *(volatile u32 *)r = d )
#define DM9000_inb(r) (*(volatile u8 *)r)
#define DM9000_inw(r) (*(volatile u16 *)r)
#define DM9000_inl(r) (*(volatile u32 *)r)
enum DM9000_PHY_mode
{
DM9000_10MHD = 0,
DM9000_100MHD =1,
DM9000_10MFD = 4,
DM9000_100MFD = 5,
DM9000_AUTO =8,
DM9000_1M_HPNA = 0x10
};
u16 media_mode = DM9000_100MFD;
static u8 nfloor = 0;
static u8 local_addr[6] = { 0x22,0x44, 0x66,0x88 , 0xAA,0xCC };
void udelay(u16 count)
{
while (--count > 0);
}
static u8
DM9000_ior(int reg)
{
DM9000_outb(reg, DM9000_IO);
return DM9000_inb(DM9000_DATA);
}
static void
DM9000_iow(int reg, u8 value)
{
DM9000_outb(reg, DM9000_IO);
DM9000_outb(value, DM9000_DATA);
}
int
dm9000_probe(void)
{
u32 id_val;
id_val = DM9000_ior(DM9000_VIDL);
id_val |= DM9000_ior(DM9000_VIDH) << 8;
id_val |= DM9000_ior(DM9000_PIDL) << 16;
id_val |= DM9000_ior(DM9000_PIDH) << 24;
if (id_val == DM9000_ID)
{
return 0;
}
else
{
return -1;
}
}
static u16
phy_read(int reg)
{
u16 val;
DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
DM9000_iow(DM9000_EPCR, 0xc);
udelay(1000);
DM9000_iow(DM9000_EPCR, 0x0);
val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL);
return val;
}
static void
phy_write(int reg, u16 value)
{
DM9000_iow(DM9000_EPAR, DM9000_PHY | reg);
DM9000_iow(DM9000_EPDRL, (value & 0xff));
DM9000_iow(DM9000_EPDRH, ((value >> 8) & 0xff));
DM9000_iow(DM9000_EPCR, 0xa);
udelay(1000);
DM9000_iow(DM9000_EPCR, 0x0);
}
static void
set_PHY_mode(void)
{
u16 phy_reg4 = 0x01e1, phy_reg0 = 0x1000;
if (!(media_mode & DM9000_AUTO)) {
switch (media_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 */
}
DM9000_iow(DM9000_GPCR, 0x01); /* Let GPIO0 output */
DM9000_iow(DM9000_GPR, 0x00); /* Enable PHY */
}
static void
program_dm9801(u16 HPNA_rev)
{
u16 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);
}
static void
program_dm9802(void)
{
u16 reg25;
if (!nfloor)
nfloor = DM9802_NOISE_FLOOR;
reg25 = phy_read(25);
reg25 = (reg25 & 0xff00) + nfloor;
phy_write(25, reg25);
}
static void
identify_nic(void)
{
u16 phy_reg3;
DM9000_iow(DM9000_NCR, NCR_EXT_PHY);
phy_reg3 = phy_read(3);
switch (phy_reg3 & 0xfff0) {
case 0xb900:
if (phy_read(31) == 0x4404)
{
program_dm9801(phy_reg3);
}
else
{
program_dm9802();
}
break;
default:
break;
}
DM9000_iow(DM9000_NCR, 0);
}
static void
dm9000_reset(void)
{
DM9000_iow(DM9000_NCR, NCR_RST);
udelay(1000);
}
int
eth_init(void)
{
int i, oft, lnk;
dm9000_reset();
dm9000_probe();
DM9000_iow(DM9000_GPR, 0x00);
DM9000_iow(DM9000_GPCR, 0x01);
DM9000_iow(DM9000_GPR, 0x00);
DM9000_iow(DM9000_TCR, 0);
DM9000_iow(DM9000_BPTR, 0x3f);
DM9000_iow(DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8));
DM9000_iow(DM9000_FCR, 0x0);
DM9000_iow(DM9000_SMCR, 0);
DM9000_iow(DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
DM9000_iow(DM9000_ISR, 0x0f);
for (i = 0, oft = 0x10; i < 6; i++, oft++)
DM9000_iow(oft, local_addr[i]);
for (i = 0, oft = 0x16; i < 8; i++, oft++)
DM9000_iow(oft, 0xff);
DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */
DM9000_iow(DM9000_IMR, IMR_PAR); /* Enable TX/RX interrupt mask */
#if 0
i = 0;
while (!(phy_read(1) & 0x20)) /* autonegation complete bit */
{
udelay(1000);
i++;
if (i == 10000)
{
//printf("could not establish link\n");
return 0;
}
}
#endif
#if 0
/* see what we've got */
lnk = phy_read(17) >> 12;
printf("operating at ");
switch (lnk) {
case 1:
//printf("10M half duplex ");
break;
case 2:
//printf("10M full duplex ");
break;
case 4:
//printf("100M half duplex ");
break;
case 8:
//printf("100M full duplex ");
break;
default:
//printf("unknown: %d ", lnk);
break;
}
//printf("mode\n");
#endif
//printf("operating at 100M full duplex mode\n");
return 0;
}
void
eth_halt_true(void)
{
phy_write(0, 0x8000); /* PHY RESET */
DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */
DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */
}
int
eth_send(volatile void *packet, int length)
{
char *data_ptr;
u32 tmplen, i;
/* Move data to DM9000 TX RAM */
data_ptr = (char *) packet;
DM9000_outb(DM9000_MWCMD, DM9000_IO);
#ifdef CONFIG_DM9000_USE_8BIT
/* Byte mode */
for (i = 0; i < length; i++)
DM9000_outb((data_ptr[i] & 0xff), DM9000_DATA);
#endif /* */
#ifdef CONFIG_DM9000_USE_16BIT
tmplen = (length + 1) / 2;
for (i = 0; i < tmplen; i++)
DM9000_outw(((u16 *) data_ptr)[i], DM9000_DATA);
#endif /* */
DM9000_iow(DM9000_TXPLL, length & 0xff);
DM9000_iow(DM9000_TXPLH, (length >> 8) & 0xff);
DM9000_iow(DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */
while (DM9000_ior(DM9000_TCR) & TCR_TXREQ); /* wait for end of transmission */
return 0;
}
u16
EMACReadPacket(u16 *buf, u16 RxLen)
{
u8 rxbyte, *rdptr,status;
u16 RxStatus, RxLen = 0;
u32 tmplen, i;
rdptr=(u8 *) buf;
/* Move data from DM9000 */
/* Read received packet from RX SRAM */
#ifdef CONFIG_DM9000_USE_8BIT
for (i = 0; i < RxLen; i++)
rdptr[i] = DM9000_inb(DM9000_DATA);
#endif
/* */
#ifdef CONFIG_DM9000_USE_16BIT
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
((u16 *) rdptr)[i] = DM9000_inw(DM9000_DATA);
#endif /* */
}
u16 GetInputPacketLen(void)
{
status=DM9000_ior(DM9000_ISR);
if(status & 0x01)
{
DM9000_iow(DM9000_ISR,0x01);
}
DM9000_ior(DM9000_MRRH);
DM9000_ior(DM9000_MRRL); //must add this two read,weiyan
DM9000_ior(DM9000_MRCMDX); /* Dummy read */
rxbyte = DM9000_inb(DM9000_DATA); /* Got most updated data */
if (rxbyte == 0)
return 0;
/* Status check: this byte must be 0 or 1 */
if (rxbyte > 1) {
DM9000_iow(DM9000_RCR, 0x00); /* Stop Device */
DM9000_iow(DM9000_ISR, 0x80); /* Stop INT request */
return 0;
}
/* A packet ready now & Get status/length */
DM9000_outb(DM9000_MRCMD, DM9000_IO);
#ifdef CONFIG_DM9000_USE_8BIT
RxStatus = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
RxLen = DM9000_inb(DM9000_DATA) + (DM9000_inb(DM9000_DATA) << 8);
#endif /* */
#ifdef CONFIG_DM9000_USE_16BIT
RxStatus = DM9000_inw(DM9000_DATA);
RxLen = DM9000_inw(DM9000_DATA);
#endif /* */
if ((RxStatus & 0xbf00) || (RxLen < 0x40)
|| (RxLen > DM9000_PKT_MAX)) {
if (RxStatus & 0x100) {
//printf("rx fifo error\n");
}
if (RxStatus & 0x200) {
//printf("rx crc error\n");
}
if (RxStatus & 0x8000) {
//printf("rx length error\n");
}
if (RxLen > DM9000_PKT_MAX) {
//printf("rx length too big\n");
dm9000_reset();
}
} else {
return RxLen;
}
return 0;
}
u8 GetEthISRStatus(void)
{
u8 status;
u8 savedReg;
// Save previous register address
savedReg = DM9000_inb(DM9000_IO);
// Disable all interrupt
DM9000_iow(DM9000_IMR, 0x80);
// Got DM9000 interrupt status
status = DM9000_ior(DM9000_ISR); // Got ISR
DM9000_iow(DM9000_ISR, status); // Clear ISR status
// Re-enable interrupt mask
DM9000_iow(DM9000_IMR, 0x83);
// Restore previous register address
DM9000_outb(savedReg, DM9000_IO);
return status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -