DM9000初始化过程

来源:互联网 发布:淘宝怎么货到付款啊 编辑:程序博客网 时间:2024/06/07 09:27
drivers/dm9000x.c eth_init()函数 

这里的初始化并不复杂,首先对dm9000进行复位 
static void 
dm9000_reset(void) 

      DM9000_DBG("resetting\n"); 
      DM9000_iow(DM9000_NCR, NCR_RST); 
      udelay(1000);              

这里将NRC寄存器的第0位置1,之后要保持至少20us的延时。这里延时了1ms。 
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) { 
             printf("dm9000 i/o: 0x%x, id: 0x%x \n",CONFIG_DM9000_BASE, 
                    id_val); 
             return 0; 
      } else { 
             printf("dm9000 not found at 0xx id:0xx\n", 
                    CONFIG_DM9000_BASE, id_val); 
             return -1; 
      

复位结束后到网卡的vendor ID寄存器和productID寄存器读取id,检测此网卡是否是dm9000。 
static void 
identify_nic(void) 

      struct board_info *db =&dmfe_info;       
      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) { 
                    db->nic_type =HOMERUN_NIC; 
                    program_dm9801(phy_reg3); 
                    DM9000_DBG("found homerun NIC\n"); 
             } else { 
                    db->nic_type =LONGRUN_NIC; 
                    DM9000_DBG("found longrun NIC\n"); 
                    program_dm9802(); 
             
             break; 
      default: 
             db->nic_type =FASTETHER_NIC; 
             break; 
      
      DM9000_iow(DM9000_NCR, 0); 

接着是检测网卡类型,是FASTETHER,HOMERUN或LONGRUN类型。这里主要是通过phy_read(3)和phy_read(31)读取PHY寄存器的值并进行比较判断。读PHY寄存器的方法将在后面介绍。 
DM9000_iow(DM9000_GPR, 0x00); 
将GPR寄存器的第0位置0。激活内部PHY的功能。 
The default status of the DM9000 is to power down the internal PHYby setting the GPIO0. 
Since the internal PHY have been powered down, the wakeup procedurewill be needed to 
enable the DM9000 
这是官方文档对这个设置的解释。因为其初始化状态是POWER DOWN。在powerdown模式下,除了MDC/MDIO管理接口,其他所有的发送、接收及MII接口功能都被禁止。 
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);  
             phy_write(0, phy_reg0);  
      
      DM9000_iow(DM9000_GPCR,0x01);    
      DM9000_iow(DM9000_GPR,0x00);       

通过写PHY寄存器0和4即BMCR和ANAR来设置phy的工作模式。在我的这个板子上用的是默认的配置。通过写寄存器0使能了dm9000的auto-negotiation状态;通过写寄存器4设置该网卡支持IEEE802.3 CSMA/CD和其他一些工作模式。 
      DM9000_iow(DM9000_GPCR,0x01);    
      DM9000_iow(DM9000_GPR,0x00);       
这最后两行又将PHY进行了一次重启。先将PHY设置为powerdown,再使能。 
下面是对一些控制和状态寄存器的设置,具体含意可参考dm9000datasheet. 
       
      DM9000_iow(DM9000_NCR, 0x0);  
      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; i < 6; i++) 
             ((u16 *) bd->bi_enetaddr)[i] =read_srom_word(i); 
      printf("MAC: x:x:x:x:x:x\n",bd->bi_enetaddr[0], 
             bd->bi_enetaddr[1],bd->bi_enetaddr[2],bd->bi_enetaddr[3], 
             bd->bi_enetaddr[4],bd->bi_enetaddr[5]); 
      for (i = 0, oft = 0x10; i < 6; i++,oft++) 
             DM9000_iow(oft,bd->bi_enetaddr[i]); 
      for (i = 0, oft = 0x16; i < 8; i++,oft++) 
             DM9000_iow(oft, 0xff); 
这段代码是设置dm9000的MAC地址,选是通过read_srom_word(i)到srom中读取MAC地址值,再分别写入板子信息数据结构bd和dm9000的MAC寄存器中,再将MulticastAddress Register寄存器全部置1。 
看一下read_srom_word这个函数 
static u16 
read_srom_word(int offset) 

      DM9000_iow(DM9000_EPAR, offset); 
      DM9000_iow(DM9000_EPCR, 0x4); 
      udelay(200); 
      DM9000_iow(DM9000_EPCR, 0x0); 
      return (DM9000_ior(DM9000_EPDRL) + (DM9000_ior(DM9000_EPDRH)<< 8)); 

这个函数是从srom中读一个word。首先把要读的那个寄存器的偏移地址offset写入EPAR寄存器,然后把读命令0x4写入EPCR寄存器,等待至少150us后,向EPCR寄存器写入0x0,清除读命令,最后从EPDRL和EPDRH寄存器中分别读出数据的低字节和高字节。EPAR是地址寄存器,存入要读/写的寄存器的偏移地址。EPCR是控制寄存器,通过命令控制读/写。读出的数据或要写入的数据放在PEDRL和EPDRH中。 
      DM9000_iow(DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC |RCR_RXEN);      
      DM9000_iow(DM9000_IMR,IMR_PAR);       
现在开始使能网卡的接收功能,设置中断屏蔽寄存器。这里IMR_PAR=10000000b,将IMR寄存器的位7置“1”,使内存数据读取地址的高字节为0ch,即Memory Data Read_addressRegisterF5。这样设置使得接收的数据从内部内存地址0x0c00处开始存放。 
      while (!(phy_read(1) & 0x20)){    
             udelay(1000); 
             i++; 
             if (i == 10000) { 
                    printf("could not establish link\n"); 
                    return 0; 
             
      
读取phy寄存器1,判断auto-negotiation是否完成。我前面贴子说的起动时特别慢原因就在这里。if (i ==10000) 
这里判断的次数太多,延长的等待时间。如果auto-negotiation完成的快,这里是多少也就无所谓了。 
下面看一下phy_read(1)这个函数 
static u16 
phy_read(int reg) 

      u16 val; 
       
      DM9000_iow(DM9000_EPAR, DM9000_PHY |reg); 
      DM9000_iow(DM9000_EPCR,0xc);      
      udelay(100);              
      DM9000_iow(DM9000_EPCR,0x0);      
      val = (DM9000_ior(DM9000_EPDRH) << 8)| DM9000_ior(DM9000_EPDRL); 
       
      DM9000_DBG("phy_read(%d): %d\n", reg,val); 
      return val; 

这段代码是从PHY寄存器中读取一个字。读取的方法和读srom是一样的。但在细节上有些差别。在写PHY寄存器地址时要保证EPAR的第7、6位的值为01b。这样就选中PHY模式。在往EPCR寄存器中写读命令时要保证其位3为1。这也是为了选中PHY模式。 
最后      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"); 
      读PHY寄存器17,检测其工作模式。 
到些网卡初始化结束。

0 0
原创粉丝点击