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

📄 dm9000x.c

📁 意法半导体ARM7 STR710+DM9000A的TCP/IP实现
💻 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 + -