210学习日记(15)_移植DM9000

210学习日记(15)

--移植DM9000网卡驱动

我想,大家学习到这里,写了一些裸板程序,对S5PV210应该算是比较了解了吧,而且已经写出了一个比较满意的bootloader来了,肯定是想上系统玩玩驱动了吧!

我在"Tiny210学习日记(1)"中提过,要在从内核官网上面下载的纯净的Linux系统上面玩驱动,那么你要不得支持网卡,要不得有MTD分区,因为我们要挂接系统。

接下来说说我是怎么一步一步移植DM9000网卡驱动的:

(在看以下具体操作步骤之前,强烈建议大家把韦东山视频里面关于dm9000的类容和在一起,拉通看一次,讲得太详细了)

1.当自己写好的bootloader成功引导内核时,查看内核的启动信息,发现没有任何网卡相关的启动信息;

注意:

问:这里是使用的官方提供的默认的配置文件s5pv210_defconfig去配置编译内核的。可是将编译出的 zImage烧写进开发板,启动的时候,发现串口无任何启动信息输出,这是为什么呢?

答:千万不要怀疑是我提供的bootloader有错误,从而不能够启动内核。而真正的原因是,我们需要make menuconfig中配置一下串口,选为串口0(当然,大家得根据自己使用串口的具体情况)

Location:

-> System Type

(0) S3C UART to use for low-level messages

2.在make menuconfig中添加上DM9000选项,然后重新编译内核,下载新内核到开发板,观察启动信息,发现只打印了一句关于DM9000的信息,类容如下:

dm9000 Ethernet Driver, V1.31

3.分析内核内核自带的DM9000网卡的驱动程序dm9000.c,发现它是采用总线设备驱动模型写的,于是我怀疑网卡驱动的probe函数是不是没有被调用呢?于是加打印语句验证,果然没有被调用。从而说明没有注册平台设备资源。

4.

问:既然发现没有注册平台设备资料,那就自己去注册一个呗。那么需要添加些什么样的资源呢?

答:分析dm9000.cprobe函数,发现以下几行代码:

db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

db->irq_res  = platform_get_resource(pdev, IORESOURCE_IRQ, 0);

一看platform_get_resource()函数,那太熟悉了,获得资源(即获得基地址和中断号),条件反射,我们就应该注册平台资源(提供基地址和中断号)。当然,我们也可以像而且视频里面移植网卡的那样,直接在dm9000.c的初始化函数中ioremap()一下基地址,然后再赋值给对应的基地址变量(我相信这种方法,大家在听了二期视频和阅读完这章日志后,自己能够搞定)。我采用注册平台资源的方式。

问:既然选择了注册平台资源,那么在哪里去注册呢?

答:我们可以单独写一个注册平台资源的程序,然后编译进内核。但是为了省事情,我梦直接在arch\arm\

mach-s5pv210\mach-smdkv210.c中注册就好了。内容如下:

static struct resource dm9000_resources[] = {

[0] = {

.start = 0x88000000,                         /* 用于向DM9000发地址,后面有解释 */

.end = 0x88000000 + 3,                      /* 这里想加多少都可以,只要大于等于3就行 */

.flags = IORESOURCE_MEM,

},

[1] = {

.start = 0x88000000 + 4,                      /* 用于向DM9000发数据,后面有解释 */

.end = 0x88000000 + 7,                      /* 这里想加多少都可以,只要大于等于3就行 */

.flags = IORESOURCE_MEM,

},

[2] = {

.start = IRQ_EINT(7),                        /* 中断号 */

.end = IRQ_EINT(7),

.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,

},

};

static struct dm9000_plat_data dm9000_platdata = {

.flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM, /*位宽是16,EEPROM */

.dev_addr = { 0x08, 0x90, 0x00, 0xa0, 0x02, 0x10 }, /* MAC地址 */

};

struct platform_device tiny210_device_dm9000 = {

.name = "dm9000",

.id = -1,

.num_resources = ARRAY_SIZE(dm9000_resources),

.resource = dm9000_resources,

.dev = {

.platform_data = &dm9000_platdata,

},

};

问:如何知道基地址是多少呢?如何区分基地址是用于向DM9000发地址,还是发数据呢?

答:看Tiny210的原理图得知,DM9000CS引脚接到了s5pv210Xm0CSn1管脚,则对应于Bank 1,地址范围为0x8800_0000 0x8FFF_FFFF,那么我们的基地址到底该设为多少呢?

我们先来看一下dm9000.c中是怎么来用这些地址的吧,以未经过修改的复位函数为例子:

static void dm9000_reset(board_info_t * db)

{

dev_dbg(db->dev, "resetting device\n");  /* 打印信息 */

/* RESET device */

writeb(DM9000_NCR, db->io_addr);    /* DM9000发寄存器地址 */

udelay(200);

writeb(NCR_RST, db->io_data);        /* 往上述寄存器写入数据   */

udelay(200);

}

从上面的复位函数中发现,我们只使用到了基地址(即注册的地址的平台资源的开始的第一地址),这也就.end = 0x88000000 + 3可以加大于等于3的任意地址的原因了,因为只用到了开始的四个字节,后面的无用。

另外,从上面的复位函数中看出,是向一个地址发送一个数据,很像SDRAM的操作。但是原理图上面发现,只用一个地址,即ADDR2(站在S5PV210的角度),那么是不是DM9000里面只有01两个地址呢?

看过视频和DM9000芯片手册的人一定知道,其实DM9000是地址线和数据线复用,通过DM9000上面的CMD引脚来区分(0为地址,1为数据),而该引脚和S5PV210ADDR2连接。

所以,绕了那么远,说了那么多,最终就是告诉大家,发出的地址信息里面,只有ADDR2上面的地址信号(1或者0)有用,因此,如果是作为发地址的基地址的话,在0x8800_0000 0x8FFF_FFFF里面(用的是Xm0CSn1,即Bank 1),任意一个能够让ADDR2输出低电平的地址就行;如果是作为发数据的基地址的话,在0x8800_0000 0x8FFF_FFFF里面(用的是Xm0CSn1,即Bank 1),任意一个能够让ADDR2输出高电平的地址就行;

注意:

这里让ADDR2输出对应电平信号(高或低),而加一个偏移地址(0x88000000 + 4中的4),有两种算法,因为在S5PV210中的基地址有两种对齐方式,我会在下面进行讲解。

5.由于在我的bootloader里面没有初始化Bank 1的相关类容(如位宽,时序等),而且为了让网卡驱动程序独立于其他任何程序,我们得做些初始化操作,类容如下:

static void __init tiny210_dm9000_set(void)

{

SROM_BW = ioremap(0xE8000000,4);

SROM_BC1 = ioremap(0xE8000008,4);

MP0_1CON = ioremap(0xE02002E0,4);

*SROM_BC1 = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0)); /* 设置时序,视频已详细 讲解了 */

*SROM_BW &= ~(0xf << 4);

*SROM_BW |= (0x1 << 4) | (1<<5); /* 位宽为16位,基地址按字节对齐(5位很重要) */

*MP0_1CON |= 0x2<<4; /* 设置对应GPIO用于Bank 1的片选 */

}

既然上面我已经打开了arch\arm\mach-s5pv210\mach-smdkv210.c,就在该文件的入口函数添加该初始化函数吧(即在smdkv210_machine_init函数里添加tiny210_dm9000_set),当然也可以把该初始化函数设置在网卡驱动的入口函数里面。

问:初始化函数中说SROM_BW寄存器的bit5很重要,为什么呢?

答:还记得在4中讲的偏移值有两种算法吧!而这个算法就和该bit5息息相关,即:

bit5设置为1时:(基地址按字节对齐)

开发板发出的地址信息   网卡收到的地址信息

       A0        ------        A0

       A1        ------        A1

       A2        ------        A2

       ...         ------        ....

所以,在这种情况下,和2440的设置基地址没有任何差别,开发板的A2就对应DM9000CMD。上面注册平台资源就是属于这种情况,所以可以加4

bit5设置为0时:(基地址按半字对齐)

开发板发出的地址信息   网卡收到的地址信息

       A0        ------        

       A1        ------        A0

   A2        ------        A1

       ...         ------        ....

所以,在这种情况下,开发板的A0地址是无效的,那么A3才对应CMD,所以偏移值应该加8之类的值。(在我共享的dm9000的驱动中"half_word"文件中的网卡驱动中,就是用的这种方法)

6.在这里我得向大家道歉一下,我上传上传的驱动由于个人整理时的疏忽,编译时有个错误,如下:

drivers/net/dm9000.c:1612: error: 'struct dm9000_plat_data' has no member named 'param_addr'

怎么解决?说没有这个成员,我就给它添加一个这样的成员呗。在include\linux\dm9000.h中的dm9000_plat_data结构体中添加unsigned char param_addr[6]成员。接下来,我就说说该成员的作用吧:

dm9000.cprobe函数里面添加了如下代码:

if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {

mac_src = "param data";

memcpy(ndev->dev_addr, pdata->param_addr, 6);

}

该部分代码就是设置MAC地址的,当然大家也可以按照视频里面的方法进行设置,这里就不多说了。

7.到这里为止,自我感觉已经移植得差不多了,编译一下,实验一下吧,看看能行不?果然就ok了。

注意:

1).在共享的dm9000的驱动中"byte"文件中的驱动,对应基地址按字节对齐的方法;

2).在共享的dm9000的驱动中"half_word"文件中的驱动,对应基地址按字对齐的方法;

3).再在这里解释一下使用"half_word"的方法时,为什么修改了dm9000_reset函数,类容如下:

static void dm9000_reset(board_info_t *db)

{

dev_dbg(db->dev, "resetting device\n");

iow(db, DM9000_GPCR, 0x0f); /* 设置GPIO寄存器作为输出,(类似于单片机对IO端口的控制) */

iow(db, DM9000_GPR, 0); /* GPIO寄存器写值,清除PWER_DOWN信号,使能PHY */

iow(db, DM9000_NCR, 3); /* 复位 */

do {

udelay(100);

} while (ior(db, DM9000_NCR) & 0x1); /* 等待复位成功 */

iow(db, DM9000_NCR, 0);

iow(db, DM9000_NCR, 3); /* 再次服务 */

do {

udelay(100);

} while (ior(db, DM9000_NCR) & 0x1); /* 等待复位成功 */

if ((ior(db, DM9000_PIDL) != 0) || (ior(db, DM9000_PIDH) != 0x90)) /* ID */

printk(KERN_INFO "ERROR : resetting ");

}

注:

如有问题,请到韦东山LINUX视频讨论群里面,我们一起讨论学习,或者加我QQ317312379

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值