DM9000C 确定相异性
差异性 和 寄存器设置:
DM9000C 并不能使用内核提供的驱动,所以要从厂家提供的 DM9000C 的驱动上移植:
一,分析厂家提供的 DM9000C 网卡驱动程序:
若定义了宏“MODULE”才会使用到初始化“init_module”函数。
1,入口函数:
2,dmfe_probe1 函数:设置 硬件 。
网卡接口与内存接口一样,所以只需要去读某个地址即可。地址就表示网卡的某些寄存
器。对里面寄存器的操作只有厂家才知道。所以网卡驱动程序厂家一般都会提供一个
demo。各个开发板的“iobase”基地址肯定不一样。中断引脚可能也不一样。
3,int dmfe_open(struct net_device *dev)
下面是自已修改过的代码:
对于 2440 来说可以配置此中断是“上升沿”触发还是“下降沿”触发。
在入口函数“int __init dm9000c_init(void)”中有修改过的:
1,具体开发板的基地址:下面显示物理基地址是“0x20000000”,接着 ioremap。 2,也设置了中断号,此开发板的中断号是“IRQ_EINT7”
以上便为简单的厂家 DM9000C 驱动程序的分析。
二,从厂家提供的驱动程序上修改移植:
移植:找出差异性来修改。
DM9000 是一个内存接口的芯片,两个同样接有 DM9000 的开发板,最小差异:基地址、位
宽和中断引脚。
1,用什么地址访问此网卡芯片:
看片选引脚–nGCS4。
地址线和数据线上挂有网卡芯片、内存和 NORFLASH。如何访问一个网卡设备而不被其他
诸如“内存”或“NORFLASH”影响,则是将每个设备选中再访问。
让“nGCS4”片选信号为低电平。
看 2440 芯片手册“MEMORY CONTROLLER”一章:
只要 CPU 发出的物理地址是“0x2000_0000 - 0x2800_0000”之间时,引脚
“(nGCS4)”就会变成低电平。
(1). 接上板子上的外设,怎么确定它的地址?
- CPU 发出一个地址 A
- 存储控制器根据地址 A 的范围,决定让 nGCS0~nGCS7 中的哪个引脚输出低电平,假设是
nGCS3 - 接在 nGCS3 的芯片就被选中
- 访问这个被选中的芯片的哪个地址呢?由地址线 A26~A0 决定。
A26~A0 有 27 条地址线,寻址芯片是 128M
修改源代码:
Ioremap 0x20000000 ,是因为基地址就是 0x20000000 。
让片选引脚是低电平,CPU 发出来的地址必须是位于“0x2000_0000 - 0x2800_0000”之
间。所以上面就把基地址设置为“0x2000_0000”。
2,入口函数 与 出口函数:
原来的入口与出口函数在一个“#ifden”下面:
移植修改:
去掉 #ifden 。。。#endif ; 将 init_module()改为“dm9000c_init()”入口
函数。
将出口函数“cleanup_module()”改成“dm9000c_exit()”,再加上修饰函数。如
下:
3,查看入口函数中的“probe”函数:
找到设置结构体的函数。
int __init dm9000c_init(void)
–>dmfe_dev = dmfe_probe();
–>struct net_device *dev = alloc_etherdev(sizeof(struct board_info)); 分配结构体
–>dmfe_probe1(dev); 设置
–>register_netdev(dev); 注册
int __init dmfe_probe1(struct net_device *dev)
–>outb(DM9KS_VID_L, iobase); 往iobase地址处写入一个值“DM9KS_VID_L”。DM9000C的索引寄存器
(cmd引脚为0)
id_val = inb(iobase + 4); 从iobase+4处读出某个值。读DM9000C的数据寄存器(cmd引脚为1)
outb(DM9KS_VID_H, iobase);
id_val |= inb(iobase + 4) << 8;
outb(DM9KS_PID_L, iobase);
id_val |= inb(iobase + 4) << 16;
outb(DM9KS_PID_H, iobase);
id_val |= inb(iobase + 4) << 24;
上面要设置“iobase”,这样就能outb(),和inb()能访问。
1,差异性:基地址。要设置 iobase :
当只要 CPU 发出的物理地址是“0x2000_0000 - 0x2800_0000”之间时,引脚“(nGCS4)”
就会变成低电平。所以基地址根据这个物理地址“0x2000_0000 - 0x2800_0000”设置而
来。
最后要看宏“MST_ETH_PHYS”。
下面修改“基地址”:在“入口函数”中设置。
大小的设置有些随意性,就是看用到了多少地址。这里用的不是很多,就直接把大小设置
民了 1M。因为 iobase 定义的是 int 型,ioremap()后要强制转换下,不然编译时会
有一个警告:
2.关于芯片版本
若芯片版本不是“0x1A”等“chip_info”条件不满足时就返回一个错误。实际中的开
发板网卡不适合这个条件,但注释掉也能使用此驱动,所以这里直接注释去。
//if((db->chip_revision!=0x1A) || ((chip_info&(1<<5))!=0) ||
((chip_info&(1<<2))!=1)) return -ENODEV;
在实际的移植中,因为此句的条件判断而返回时,在不同的地址加打印语句来判断的出错
的地方而发现此句要修改。
3,中断号:
网卡芯片接收到数据后,会产生一个中断(网卡芯片里面也会有内存,因为它接收到数据
后是先放在自已的内存里,然后再产生一个中断)。在“中断服务程序”里再将此缓存的
数据从网卡芯片里拿出来构造成一个“skb_buff”,然后才提交上去(网络 7 层模型的
其他层)。发送时也是从“skb_buff”里拿出数据交给网卡芯片。网卡芯片硬件就会再
把数据从 skb_buff 中取出发送出去,发送完成后就会产生一个中断。
4,dev->open = &dmfe_open; 里面有使用中断。
–>if (request_irq(dev->irq,&dmfe_interrupt, IRQF_TRIGGER_RISING,dev->name,dev)) return -
EAGAIN;
对于 2440 来说,中断可以设置成“上升沿触发”或“下降沿触发”。可以参考以前“按键
中断”驱动中的代码
以上设置了差异性的部分:iobase 基地址,中断号。
在完成基地址,中断号的设置后,直接在厂家驱动的基础上编译驱动成功。
编译通过。但这个驱动程序还是有一个缺点,就是各信号间时序的设置。但这里没有设置
前,也能使用,是因为 UBOOT 中设置好了。要是想写一个不依赖于 UBOOT 的网卡驱动程
序,就得自已设置
网卡是内存一样的接口,地址信号,读写脉冲,这些信号的读写时序会有要求。
CPU 发指令给内存控制器,再由“内存控制器”负责发读写、地址等信号给网卡芯片,这
些信号间的时间要设置。所以还要设置一项“MEMORY CONTROLLER”。
等待信号:
当 CPU 访问网卡芯片时,若此时 DM9000 还没准备就绪,这时网卡就可以给 CPU 发出一
个等待信号(nWAIT).从原理图上看 DM9000 没有“nWAIT”等待信号。
③,BUS WIDTH & WAIT CONTROL REGISTER (BWSCON):
总线位宽 和 等待寄存器。BWSCON 寄存器主要用来设置外接存储器的总线宽度和等待状
态。
a.STx:启动/禁止 SDRAM 的数据掩码引脚,对于 SDRAM,此位为 0;对于 SRAM,此位为 1。
b.WSx:是否使用存储器的 WAIT 信号,通常设为 0 c.DWx:使用两位来设置存储器的位宽:00-8 位,01-16 位,10-32 位,11-保留。
d.比较特殊的是 BANK0 对应的 4 位,它们由硬件跳线决定,只读。
DW4 的描述为 BANK4 的带宽,DM9000 接了 16 条地址线,呢么带宽就是 16,这里选 01
WS4 的描述为是否为 BANK4 使用等待状态,DM9000 没有接 WAIT 引脚,所以可以不管这个字段
ST4 的描述为是否为 BANK4 使用 UB/LB(写高/低字节使能),DM9000 没有接 nWBE[3:0]这 4 个
引脚,所以也不管这个字段.
设置位宽 DW4 bit[17:16]:
看原理图上 DM9000 使用了多少条数据线。看上面的 DM9000 原理图,数据线是“LDATA0
~ 15”一共 16 条 即 16 位。
设置等待 WS4 bit[18]:不等待.
设置功能引脚 ST4 bit[19]:这个不很了解,就直接按默认写“0”。
DM9000C 设置时序
位宽&等待状态寄存器 BWSCON(BUS WIDTH&WAIT STATUS CONTROL REGISTER),每四
位控制一个 memory bank,根据 S3C2440 手册,涉及 dm9000 的 4 个引脚是 16~19。默认值
是 0x000000。
- ST4[19]:SRAM 是否使用 UB/LB(upper byte/lower byte)。 0:不使用 UB/LB;1:使用 UB/LB。
- WS4[18]:WAIT 状态。
0:禁止 WAIT;1:使能 WAIT。 - DW4[16:17]:数据总线宽度。
00:8 位;01:16 位;10:32 位;11:保留。
接着,BANK4 控制寄存器 BANKCON4(BANK CONTROL REGISTER),用于控制 BANK4 外接设备的
访问时序。默认值是 0x0700。
设置 BANK4 寄存器
- Tacs[14:13]:地址建立时间。
00:0 时钟周期;01:1 时钟周期;10:2 时钟周期;11:4 时钟周期。 - Tcos[12:11]:
片选建立时间。00:0 时钟周期;01:1 时钟周期;10:2 时钟周期;11:4 时钟周期。 - Tacc[10:8]:地址周期。
000:1 时钟周期;001:2 时钟周期;… 111:14 时钟周期。 - Tcoh[7:6]:片选保持时间。
00:0 时钟周期;01:1 时钟周期;10:2 时钟周期;11:4 时钟周期。 - Tcah[5:4]:地址保持时间。
00:0 时钟周期;01:1 时钟周期;10:2 时钟周期;11:4 时钟周期。 - Tcap[3:2]:页模式存取周期。
00:2 时钟周期;01:3 时钟周期;10:4 时钟周期;11:6 时钟周期。 - PMC[1:0]:页模式配置。
00:1 data;01:4 data;10:8 data;11:16 data。
最后,在 arch/arm/mach-s3c2410/include/mach/regs-mem.h 中,
#define S3C2410_BWSCON_DW4_16 (1<<16)
#define S3C2410_BWSCON_WS4 (1<<18)
#define S3C2410_BWSCON_ST4 (1<<19)
理解了寄存器 BWSCON 和 BANKCON4 的含义之后,上述代码的作用就很明显了。
看“时间参数”:
这些值如何设置,只能看 DM9000 的芯片手册。若不想看,则可以使用上面 bit[0-14]
中每个位域的最大值。如 PMC bit[1:0]就使用“11=16data”这个值。用起来之后,
你想让 DM9000 的访问速度更快时,就得去看 DM9000 的芯片手册来修改上面的值。
设置这个时间值的过程,先找到寄存器的位域定义,再找到 2440 上这些时间的时序
图,按照时序图知道它们的关系。然后再找到 DM9000 的芯片手册看芯片上的规定读写时
序,两两时序对比计算,得出这些寄存器位域值的设置结果。
2440,PROGRAMMABLE ACCESS CYCLE