http://blog.csdn.net/turui/article/details/6635509
我们获得的UBOOT的代码中实际是有DM9000的网口驱动的,位于:driver/dm9000x.c
在S3C6410的配置中,中并没有将之打开,而其他的芯片中有使用
特别需要注意的是dm9000的驱动与dm9000AE的驱动还是有区别的,如果直接使用代码中自带的dm9000驱动流程,会出现无法收到数据的情况
一、添加dm9000AE的驱动
- 修改include/configs/smdk6410.h,参考 include/configs/scb9328.h 中的定义,添加如下宏定义
修改include/configs/smdk6410.h,参考 include/configs/scb9328.h 中的定义,添加如下宏定义
- #define CONFIG_DRIVER_DM9000 1
- #define CONFIG_DM9000_BASE 0x18000000
- #define DM9000_IO CONFIG_DM9000_BASE
- #define DM9000_DATA (CONFIG_DM9000_BASE+4)
- #define CONFIG_DM9000_USE_16BIT
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x18000000
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
#define CONFIG_DM9000_USE_16BIT
DM9000的基地址(CONFIG_DRIVER_DM9000的值)与硬件设计相关
查看《OK6410底板原理图.pdf》,看到,CS挂在CSN1上
查看《s3c6410_rev12.pdf》,118页,2.2 DEVICE SPECIFIC ADDRESS SPACE ,0x1800_0000 0x1FFF_FFFF 128MB SROMC Bank 1 ,可以确定CONFIG_DM9000_BASE的值
查看drivers/Makefile,可以看到dm9000x的驱动已经被编译进去
整个driver/dm9000x.c 的代码时靠CONFIG_DRIVER_DM9000这个宏定义决定其内容的
配合着我们可以去修改如下可能用到的一些地址
- #define CONFIG_ETHADDR 00:40:5c:26:0a:5b
- #define CONFIG_NETMASK 255.255.255.0
- #define CONFIG_IPADDR 192.168.30.233
- #define CONFIG_SERVERIP 192.168.30.95
#define CONFIG_ETHADDR 00:40:5c:26:0a:5b
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.30.233
#define CONFIG_SERVERIP 192.168.30.95
二、修改dm9000AE的驱动
查看DM9000AE的手册《DM9000AE.pdf》,可以看到,DM9000AE包括了,MAC,PHY,没有带EEPROM,可以通过引脚来控制外部的EEPROM
看到第11页,5.2 EEPROM Interface,看到操作DM9000的EEPROM的PIN脚为19 20 21这3个
查看《OK6410底板原理图.pdf》,看到ethernet部分 19 20 21 这3个PIN脚是悬空的,额。。。,这意味着我们无法通过DM9000AE将MAC地址保存在EEPROM中
查看《DM9000AE.pdf》 6. Vendor Control and Status Register Set 这个章节,看到 PAR Physical Address Register 10H-15H 这部分是用来设置MAC地址的
也就是说我们必须将MAC地址写入到这几个寄存器中,下面我们来完成这个工作,打开driver/dm9000x.c这个文件,看到代码如下
- eth_init(bd_t * bd) 函数中
- for (i = 0; i < 6; i++)
- ((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
eth_init(bd_t * bd) 函数中
for (i = 0; i < 6; i++)
((u16 *) bd->bi_enetaddr)[i] = read_srom_word(i);
- for (i = 0, oft = 0x10; i < 6; i++, oft++)
- DM9000_iow(oft, bd->bi_enetaddr[i]);
for (i = 0, oft = 0x10; i < 6; i++, oft++)
DM9000_iow(oft, bd->bi_enetaddr[i]);
测试可以先做如下处理吧,回头我们再改成从其他地方读取,比如外部的EEPROM,NANDFLASH,等地方好了,毕竟不应该在这个单纯的网卡驱动中增加其他驱动的代码
- u16 default_enetaddr[6] = { 0x00, 0x40, 0x5c, 0x26, 0x0a, 0x5b };
- for (i = 0; i < 6; i++)
- bd->bi_enetaddr[i] = default_enetaddr[i];
u16 default_enetaddr[6] = { 0x00, 0x40, 0x5c, 0x26, 0x0a, 0x5b };
for (i = 0; i < 6; i++)
bd->bi_enetaddr[i] = default_enetaddr[i];
如果要修改成从环境变量中读取MAC地址,则可以这样做
- {
- char *s, *e;
- s = getenv ("ethaddr");
- for (i = 0; i < 6; ++i)
- {
- bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
- if (s)
- s = (*e) ? e + 1 : e;
- }
- }
{
char *s, *e;
s = getenv ("ethaddr");
for (i = 0; i < 6; ++i)
{
bd->bi_enetaddr[i] = s ? simple_strtoul (s, &e, 16) : 0;
if (s)
s = (*e) ? e + 1 : e;
}
}
修改MAR寄存器(Multicast Address Register)的值,修正第一次收不到数据的错误
- for (i = 0, oft = 0x16; i < 8; i++, oft++)
- // by tr modify
- DM9000_iow(oft,0x00);
- //DM9000_iow(oft, 0xff);
for (i = 0, oft = 0x16; i < 8; i++, oft++)
// by tr modify
DM9000_iow(oft,0x00);
//DM9000_iow(oft, 0xff);
修改void eth_halt(void) 函数将以下两行注释掉,修正一直无法收到数据的错误
- 不要每次调用halt的时候都对PHY进行复位操作,否则会引起无法接受到数据的情况
- //phy_write(0, 0x8000); /* PHY RESET */
- //DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
不要每次调用halt的时候都对PHY进行复位操作,否则会引起无法接受到数据的情况
//phy_write(0, 0x8000); /* PHY RESET */
//DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */
查找定位ping不通,数据无法接收的问题还是也让人着实头疼了一番,看到这个结果,可以发现,跟网上的其他描述都不大相同,也是幸亏有一些可以参考的代码,根据这些可以成功运行的代码,一步一步的定位,到底是那些地方出现了问题。
另外说明一下,DM9000这样的芯片是MAC+PHY,现在有很多SOC都内置MAC,只用外挂PHY就可以了
一般来说,这种情况下,对PHY的配置,主要还是要根据硬件的设计,找到PHY的ADDR,在OK6410的配置中PHYADDR为1,跟代码一致,这里就没再做任何修改了
三、参考资料
《OK6410底板原理图.pdf》
《s3c6410_rev12.pdf》
《DM9000AE.pdf》
移植OK6410'S dm9000ae驱动到u-boot
http://lagignition.blog.163.com/blog/static/12873002320110443341961/
Linux DM9000网卡驱动程序完全分析
http://blog.csdn.net/ypoflyer/article/details/6209922
dm9000ae 在u-boot上的移植小结