第一次移植uboot(3)(添加DM9000网卡支持) .

时间:2023-01-12 17:13:20

原文:http://blog.csdn.net/ll_0520/article/details/6046169

 

 

/*在第二次移植基础上添加DM9000网卡支持*/
/*2010.11.30--2010.11.30*/
/*交叉编绎工具:cross-3.3.2.tar.bz2*/
/*默认当前目录为:u-boot-1.1.4*/

 

1. vi include/configs/fl2440.h
   (1)注释56行(#define CONFIG_DRIVER_CS8900    1),57行(#define CS8900_BASE 0x19000300),58行(#define CS8900_BUS16  1)

 

   (2)添加:
#define CONFIG_DRIVER_DM9000    1
#define CONFIG_DM9000_BASE 0x20000000   /*网卡片选地址*/
#define DM9000_IO  CONFIG_DM9000_BASE   /*传输I0数据的
地址,即DM9000的CMD引脚为低电平的地址*/
#define DM9000_DATA  (CONFIG_DM9000_BASE+4)   /*传输DATA数据
的地址,即DM9000的CMD引脚为高电平时的地址*/
#define CONFIG_DM9000_USE_16BIT  1   /*网卡数据传输位数*/


   (3)84行(CFG_CMD_NAND     | /)后添加;
CFG_CMD_PING     | /

 

   (4)去掉注释/*#define CONFIG_ETHADDR        08:00:3e:26:0a:5b */
      (开发板MAC地址)
      修改CONFIG_IPADDR(开发板IP地址)和CONFIG_SERVERIP(主机IP地址)

 

2. 确认board/fl2440/lowlevel_init.S中宏B4_BWSCON定义为(DW16)

 

3. 网卡的MAC地址与你设置的不一样,解决办法:(vi drivers/dm9000x.c)

 

/* Initilize dm9000 board
*/
int
eth_init(bd_t * bd)
{
    ......

    /* Set Node address */
/*    for (i = 0; i < 6; i++)
        ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
*/
//tekkamanninja   
    char *tmp = getenv ("ethaddr");
    char *end;

    for (i=0; i<6; i++) {
        bd->bi_enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
        if (tmp)
            tmp = (*end) ? end+1 : end;
    }
//tekkamanninja
    printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x/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]);
......

红色的字符是要做的修改:功能是屏蔽原有获取MAC地址的语句,替换成从U-Boot的参数区读取数据并存到bd->bi_enetaddr[i]中。


4. 会有“could not establish link” 的提示,而且在显示MAC地址后很久后才响应,解决办法: (vi drivers/dm9000x.c) 

 

/* Initilize dm9000 board
*/
int
eth_init(bd_t * bd)
{
    ......

    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;
        }
        printf(" link=%d/n",i);
    }

    /* 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
    return 0;
}

红色的字符是要做的修改:功能是屏蔽无用的语句。其实被屏蔽的语句是MII接口用的,放在这显然是错误的,无端的浪费了10秒钟。


5. 此时还是PING不通,解决办法:注释掉eth_halt函数的内容.

 

vi drivers/dm9000x.c

 

void eth_halt(void)
{
//      DM9000_DBG("eth_halt/n");

        /* RESET devie */
//      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 */
}

 

6.现在每回上电开发板第一次PING时还是PING不通,但从第二次开始就能PING通了

,因为当使用PING命令时才会掉用网卡初始化函数int eth_init(bd_t * bd),为了

第一次就能PING通可以先初始化下网卡:

 

vi lib_arm/board.c

 

   (1)文件头添加:
#ifdef CONFIG_DRIVER_DM9000
extern int eth_init(bd_t * bd);
#endif

 

   (2)void start_armboot (void)函数中for循环上面添加:
#ifdef CONFIG_DRIVER_DM9000
eth_init(gd->bd);
#endif

 

(由于uboot1.1.4没有ICMP协议,所以主机PING开发板是PING不通的)

 

相关链接:
uboot-2009.08 添加 DM9000X网卡的支持
http://blog.chinaunix.net/u3/117680/showart_2294336.html

 

移植U-Boot.1.2.0到友善之臂SBC2440V4(补:DM9000网卡移植)
http://blog.chinaunix.net/u2/67519/showart_640986.html

 

U-BOOT DM9000驱动完全注释
http://blog.chinaunix.net/u3/114978/showart.php?id=2262658

 

 

/*2010.12.15*/

搞了好几天就是不能通过网口下内核,明明ping主机都是通的,但是ping不通VM上的ubuntu,不过用sniffit抓包ubuntu确实收到开发板发来的ICMP包了,并且也回复了ICMP包,今天才发现原来FL2440用的网卡是DM9000AE,而uboot1.1.4的网卡驱动是DM9000的,这两之间还是有些区别的,晕死啊......

 

再网上找到的解决办法是:

 

无奈参考Linux内核中代码,发现Linux的dm9000在rx函数中添加do while循环,于是按照Linux内核源码在u-boot中也添加do while循环。
do{
/* Check packet ready or not */
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 */
   DM9000_DBG("rx status check: %d/n", rxbyte);
}
DM9000_DBG("receiving packet/n");

/* A packet ready now & Get status/length */
DM9000_outb(DM9000_MRCMD, DM9000_IO);

     /* */
RxStatus = DM9000_inw(DM9000_DATA);
RxLen = DM9000_inw(DM9000_DATA);

     /* */
DM9000_DBG("rx status: 0x%04x rx len: %d/n", RxStatus, RxLen);

/* Move data from DM9000 */
/* Read received packet from RX SRAM */
tmplen = (RxLen + 1) / 2;
for (i = 0; i < tmplen; i++)
   {
    ((u16 *) rdptr)[i] = DM9000_inw(DM9000_DATA);
    //printf("%d ",((u16 *) rdptr)[i]);
   }
     /* */
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 {

   /* Pass to upper layer */
   DM9000_DBG("passing packet to upper layer/n");
   NetReceive(NetRxPackets[0], RxLen);
   //return RxLen;
}
}
while (rxbyte == DM9000_PKT_RDY);
//return 0;

return RxLen;

 

测试结果:
大部分时候都可以ping通了,因为有调试信息,tftp速度十几k。

 

网上还有个建议在tx函数前加入以上内容清空dm9000ae寄存器
DM9000_ior(DM9000_MRRH);
DM9000_ior(DM9000_MRRL);

我放在do的前面,貌似也有一定作用

 

参考链接:

[6410][u-boot]移植dm9000ae驱动

http://www.360doc.com/content/10/0223/15/496343_16556017.shtml

 

dm9000ae 在u-boot上的移植小结

http://weibing.blogbus.com/logs/12146712.html