【转】基于linux下的dm9000网卡移植全分析
转自:http://blog.sina.com.cn/s/blog_6abf2c04010189ui.html
DM9000可以直接与ISA总线相连,也可以与大多数CPU直接相连。Mini2440采用的是dm9000直接连接CPU(s3c2440)上。就像是nandflash一样直接被挂在CUP上,被挂在s3c2440的bank4上。
小插曲1:s3c2440芯片把存储系统分为了8个Bank,由nGCS0[0]~nGCS[7] 这8根引脚决定当前访问的是哪一个Bank对应的存储器。其中,前6个Bank用于连接ROM或者SRAM(或者类似SRAM接口的存储器,如Nor Flash),而第7和第8个Bank用于连接SDRAM,并且规定由第7个Bank地址作为SDRAM的起始地址(即0x30000000)。S3c2440有27根地址线:2^27=128MB,所以一个bank最大可寻址128M, 8个bank说明s3c2440最大可寻址1G。

图一
小插曲2:当OM[1:0]=01时,bootingROM data width是16位,当[1:0]=10时,booting ROM datawidth是32位,当OM[1:0]=00时,从NAND FLASH启动。在友善之臂S3C2440开发板上,OM1引脚直接接地。所以说启动bank主要跟nGCS0[0]~nGCS[7]有关,但是OM【1:0】变化的话也会有细微的变化.

小插曲3:注意:不同的启动方式,内存的映射是不同的,当从Nand Flash启动时,片上的BootSRAM被映射到了高位地址(0x40000000),而非Nand Flash方式启动时,则映射到了0x00000000.

图二

图三
首先看一下DM9000的引脚和MINI2440的引脚连接
DM9000 MINI2440 功能描述
SD0 DATA0 数据信号
| |
SD15 DATA15 数据信号
CMD ADDR2 识别为地址还是数据
INT EINT7 中断
IOR# nOE 读命令使能
IOW# nWE 写命令使能
AEN nGCS4 片选使能
可以看出连接了16条数据线,1条地址线,而这唯一的一条地址线用于判断数据线传输的是地址还是数据,所以这16条数据线为数据和地址复用
画个简图吧:

图四
现在开始移植吧:
因为dm9000也是基于平台驱动的,所以我们移植起来会比较方便。
标准驱动移植和修改方法:了解驱动程序框架,确定外设使用的资源,然后将它“告诉”驱动程序,并进行适当设置使它们“可用“。
我们现在已经把外设连接原理图列在上面来了,硬件连接一目了然,所以可以开始移植了。
Linux-2.6.32.2 已经自带了DM9000 网卡驱动驱动,我们需要把mini2440使用到的硬件资源告诉它。
首先添加驱动所需的头文件 dm9000.h:
arch/arm/mach-s3c2440/mach-mini2440.c(在你的开发板体系结构板级初始化文件上添加,我的位置是mach-s3c2440/mach-mini2440.c,你的如果不是就自己找一下)
#include
再定义DM9000 网卡设备的物理基地址,以便后面用到:
#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 +0x300)
问题一:s3c2410_cs4是什么?
见原理图三,nGCS3(也就是nLANLCS)被作为dm9000的选通引脚了,nGCS3选通的是bank4。bank4的起始坡地是:0x2000 0000即:s3c2410_cs4。
问题二:为什么要加0x300?
先看网上的回答吧:
1、 因为dm9000在板子上的地址是0x20000300.
2、 因为dm9000的TX0—TX2为悬空,iobase为0x300.
3、 这个需要看原理图,DM9000A中有一个16KB SRAM,所以0x20000000~0x20000000+16K之间。
唉,没有一个像样的答案,写的文章倒看似水平很高的样子,真是悲哀。可都是所谓的csdn专家呀!
我想上面的人,不知道是完全不懂硬件还是不懂装懂,自欺欺人!
首先,Mini2440只有27根地址线,addr0---addr26。可寻址范围是128M。
有八个bank用做为内存芯片的选通脚,可以寻址128M*8=1G.

即可寻址范围是:0x20000000-------0x20000000+128M(即:0x27FFFFFF)
所以地址写成0x20000000-------0x20000000+128M之间都是可以的,但是注意:addr2必须为0,为什么呢?呆会儿再分析。
上面的答案1,答案2,简直是无稽之谈,无中生有,混蛋答案。迷惑自己更迷惑大家。
上面的答案3,说DM9000A中有一个16KB SRAM,那这个地址应该和cup的地址线地址没有任何关系,因为dm9000是地址线和数据线复用的,
它根本没有用到cup的地址线,他的地址只根驱动写地址命令里面的数据有关。
再填充该平台设备的资源设置,以便和 DM9000 网卡驱动接口配合起来,如下
static struct resource mini2440_dm9k_resource[]= {
[0] = {
.start = MACH_MINI2440_DM9K_BASE, //addr2=0,此空间存放的是要发送的地址
.end = MACH_MINI2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = MACH_MINI2440_DM9K_BASE + 4, //addr2=1,此空间存放的是要发送的数据
.end = MACH_MINI2440_DM9K_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = {
.start = IRQ_EINT7, //要使用的外部中断
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ |IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct dm9000_plat_data mini2440_dm9k_pdata = {
.flags = (DM9000_PLATF_16BITONLY |DM9000_PLATF_NO_EEPROM), //传送数据总线为16位宽度
};
static struct platform_device mini2440_device_eth = { //平台设备注册函数,告诉内核设备使用了这些硬件资源
.name = "dm9000",
.id = -1,
.num_resources =ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource,
.dev = {
.platform_data = &mini2440_dm9k_pdata,
},
};
这样我们把要发送的dm9000的地址信息固定放在了0x20000300,把要存放在该地址的数据存放在0x2000 0304。(因为地址和数据线复用,所以地址和数据需要分两次传送),即:数组【0】是dm9000要取的地址,数组【1】存放dm9000地址对应要存放的数据。数组[2]外部中断号
问题三:.end= MACH_MINI2440_DM9K_BASE + 3,为什么尾地址是+3?
因为一个地址需要四个字节。
问题四:数组【1】.start= MACH_MINI2440_DM9K_BASE + 4,为什么?
注意这个地址是不能随便选的,必须根据数组【0】.start地址和硬件连接情况进行对应的。现在来回答之前提到的问题,为什么MACH_MINI2440_DM9K_BASE定义的时候addr2为能为0.?
请看原理图三,或者图四。
注意这里非常重要,一语双关。Addr2即是Cup的地址线addr0-----addr26中的一员:
1、它的任何一位变化都会使得当前CPU访问的地址发生变化。
2、他连接着dm9000的数据/地址选通引脚,即:addr2=0则写的是地址,addr2=1则写的是数据。
因为当我们的基址是:0x2000 0300的时候,我们现在要写数据了,这时候把addr2置高电平也就是1就开始写数据了,同时cup的访问地址发生改变,变成0x20000304了。(这样做有一个好处,就是我们要写地址了就写到0x2000 0300,要写数据了就写到0x20000300+4,而不需要特意的去改变选通脚状态。不需要写地址的时候特意置0,在写数据的时候特意置1,因为我们访问方式改变的时候选通也会随着改变。)
反过来,我们要设这个地址存放是dm9000的地址还是数据时要考虑addr2的情况。也就MACH_MINI2440_DM9K_BASEp这个地址可以设addr2=0的,0x20000000-------0x20000000+128M的任何一个地址。当然不同的开发板可能会不一样,我们硬件可以换成addr2----addr26中的任何一位。
(addr0,addr1,因为一个数据需要四个字节存放,所以这两位不能做为选通引脚,不然两个存放地址就有重叠的地方了,如果一个数据是一个字节大小则可以)
比如说:我们硬件设定addr3为dm9000读写选通引脚,MACH_MINI2440_DM9K_BASEp就设成0x20000000,那么可以这样写:
[0] = {
.start = MACH_MINI2440_DM9K_BASE, //addr3=0,此空间存放的是要发送的地址
.end = MACH_MINI2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = MACH_MINI2440_DM9K_BASE + 8, //addr3=1,此空间存放的是要发送的数据
.end = MACH_MINI2440_DM9K_BASE + 11,
.flags = IORESOURCE_MEM
},
数组【2】则是跟中断有关的硬件资源,这个查看上面的原理图与之对应就可以了。
问题六:.flags = (DM9000_PLATF_16BITONLY |DM9000_PLATF_NO_EEPROM),传送数据总线为什么选择16位宽度?
S2c2440支持8位,16位,32位数据传送。看上面的原理图三可知:dm9000只用了LDATA0----LDATA15即16位宽度。
继续移植:把网卡设备在开机的时候进行注册
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&mini2440_device_eth,
&s3c_device_nand,
&test2440_device_eth, //这里添加dm9000网卡设备
};
到此为止我们已经把设备注册完毕了,按理来说dm9000可以在s3c2440里面启动起来了,可是这里我们还需要对驱动进行修改。
问题七:不是平台驱动吗,内核已经实现了完整的设备无关的驱动吗,我们已经把设备物理信息告诉内核了为什么还要修改驱动呢?
别忘记了,我们这里注册的16位数据宽度,s3c2440默认的是32位数据宽度。还有不同的处理芯片时钟频率是不一样的,网卡使用的频率是有一个范围的。
接着我们修改驱动:
打开 linux-2.6.32.2/drivers/net/dm9000.c,头文件处添加2410 相关的配置定义,如下
红色部分:
#include
#include
#include
#if defined(CONFIG_ARCH_S3C2410)
#include
#endif
#include "dm9000.h"
下面我们应该修改总线宽度和时序了。
dm9000_init(void)
{
#if defined(CONFIG_ARCH_S3C2410)
unsigned int oldval_bwscon = *(volatileunsigned int *)S3C2410_BWSCON;
unsigned int oldval_bankcon4 = *(volatileunsigned int *)S3C2410_BANKCON4;
*((volatile unsigned int *)S3C2410_BWSCON) =
(oldval_bwscon & ~(3<<16)) |S3C2410_BWSCON_DW4_16 |
S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4; //使能总线宽度为16位,使能nWAIT
*((volatile unsigned int *)S3C2410_BANKCON4) =0x1f7c; // BANK4控制寄存器,用于控制BANK4外接设备的访问时序。
#endif
printk(KERN_INFO "%s Ethernet Driver,V%s\n", CARDNAME, DRV_VERSION);
returnplatform_driver_register(&dm9000_driver);
}
分析:
unsigned int oldval_bwscon = *(volatileunsigned int *)S3C2410_BWSCON;
unsigned int oldval_bankcon4 = *(volatileunsigned int *)S3C2410_BANKCON4;
这里不用管,是先把这个寄存器的值做好保存,然后等网卡操作结束后再恢复它。
具体分析下两两条就可以了。这里设及的bank寄存器也是硬件相关的,在arch\arm\mach-s3c2410\include\mach\ regs-mem.h
文件里有定义。
如:
……
#define S3C2410_BWSCON_DW3_8 (0<<12)
#define S3C2410_BWSCON_DW3_16 (1<<12)
#define S3C2410_BWSCON_DW3_32 (2<<12)
#define S3C2410_BWSCON_WS3 (1<<14)
#define S3C2410_BWSCON_ST3 (1<<15)
#define S3C2410_BWSCON_DW4_8 (0<<16)
#define S3C2410_BWSCON_DW4_16 (1<<16)
#define S3C2410_BWSCON_DW4_32 (2<<16)
#define S3C2410_BWSCON_WS4 (1<<18)
#define S3C2410_BWSCON_ST4 (1<<19)
……
具体查阅该文件与之对应。
*((volatile unsigned int *)S3C2410_BWSCON) =
(oldval_bwscon & ~(3<<16)) |S3C2410_BWSCON_DW4_16 |
S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
上面语句为使能总线宽度为16位,使能nWAIT
*((volatile unsigned int *)S3C2410_BANKCON4)= 0x1f7c; // BANK4控制寄存器,用于控制BANK4外接设备的访问时序。
问题八:时序的设置为什么是0x1f7c?
这需要查看dm9000数据手册了解该时序过程到底占用了几个时钟周期,并根据CUP时钟速度进行计算,然后用示波器观察结果反复微调。如果不知道怎么算可以学习《计算组成原理》该书有关于时钟,脉冲,指令,总线……响应时间的计算介绍。上面我们设定的是一个很宽松的值,一般的处理器设置成那个值都可以用,但是响应速度当然会有所减慢因为我们是设置最宽松的值嘛。
网上有朋友计算过这个过程,复制过程贴到文章的最下方,如需了解可以查看。
移植完毕,下面对DM9000进行配制编译进内核。
#make menuconfig
开始在内核中配置网卡驱动,依次选择如下菜单项
Device Drivers --->Network device support ---> Ethernet (10 or100Mbit) --->
即可找到DM9000的配置项,加入了DM9000 的支持
然后执行:
#make zImage
到此为止dm9000所有的移植原理全部解析,并且用MINI2440的开发板,内核为linux2.6.32.2 进行过反复测试没有问题。
Over!
Over!
Over!
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
网上朋友计算dm9000时序分析如下:http://blog.chinaunix.net/space.php?uid=13321460&do=blog&id=2902457
【转】基于linux下的dm9000网卡移植全分析的更多相关文章
- 基于Linux下catalog方式的 Oracle 备份策略(RMAN)
--********************************** -- 基于Linux下 Oracle 备份策略(RMAN) --******************************* ...
- 基于Linux下Iptables限制BT下载的研究
基于Linux下Iptables限制BT下载的研究 摘要: 当前BT下载技术和软件飞速发展,给人们网上冲浪获取资源带来了极大的便利, 但同时BT占用大量的网络带宽等资源也给网络和网络管理员 ...
- 基于linux下的NIST数字测试包安装过程
基于linux下的NIST数字测试包安装过程 1. 首先解决windows文件不能粘贴到Ubuntu的问题 选择利用VMware Tools进行解决 打开虚拟机VMware Workstation,启 ...
- 【转】基于Linux下的TCP编程
http://blog.csdn.net/tigerjibo/article/details/6775534 一.Linux下TCP编程框架 TCP网络编程的流程包含服务器和客户端两种模式.服务器模式 ...
- linux下简单限制网卡速度
Linux下限制网卡的带宽,可用来模拟服务器带宽耗尽,从而测试服务器在此时的访问效果. 1.安装iproute yum -y install iproute 2.限制eth0网卡的带宽为50kbit: ...
- linux下安装编译网卡驱动的方法
安装linux操作系统后发现没有网卡驱动,表现为 system → Administration → Network下Hardware列表为空. 以下为安装编译网卡驱动的过程,本人是菜鸟,以下是我从网 ...
- 基于Linux下的UDP编程
一. Linux下UDP编程框架 使用UDP进行程序设计可以分为客户端和服务器端两部分. 1.服务器端程序包括: Ø 建立套接字 Ø 将套接字地址结构进行绑定 Ø 读写数据 Ø 关闭套接字 2 ...
- Linux下使用虚拟网卡的ingress流控(入口流控)
Linux内核实现了数据包的队列机制,配合多种不同的排队策略,可以实现完美的流量控制和流量整形(以下统称流控).流控可以在两个地方实现,分别为egress和ingress,egress是在数据包发出前 ...
- Linux下双物理网卡设置成虚拟网卡
为了提供网络的高可用我们须要将多块网卡绑定设置成一块虚拟的网卡对外提供服务,这样能够防止一块网卡损坏或者防止网线连接故障造成的连接中断. 以下我们使用eth0与eth1来虚拟成为bond0为例:--- ...
随机推荐
- Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数
上一篇:Angular2入门系列教程-服务 上一篇文章我们将Angular2的数据服务分离出来,学习了Angular2的依赖注入,这篇文章我们将要学习Angualr2的路由 为了编写样式方便,我们这篇 ...
- ASP.NET Aries 入门开发教程8:树型列表及自定义右键菜单
前言: 前面几篇重点都在讲普通列表的相关操作. 本篇主要讲树型列表的操作. 框架在设计时,已经把树型列表和普通列表全面统一了操作,用法几乎是一致的. 下面介绍一些差距化的内容: 1:树型列表绑定: v ...
- dll文件32位64位检测工具以及Windows文件夹SysWow64的坑
自从操作系统升级到64位以后,就要不断的需要面对32位.64位的问题.相信有很多人并不是很清楚32位程序与64位程序的区别,以及Program Files (x86),Program Files的区别 ...
- “不给力啊,老湿!”:RSA加密与破解
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 加密和解密是自古就有技术了.经常看到侦探电影的桥段,勇敢又机智的主角,拿着一长串毫 ...
- 【原】AFNetworking源码阅读(六)
[原]AFNetworking源码阅读(六) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这一篇的想讲的,一个就是分析一下AFSecurityPolicy文件,看看AF ...
- 前端学HTTP之日志记录
前面的话 几乎所有的服务器和代理都会记录下它们所处理的HTTP事务摘要.这么做出于一系列的原因:跟踪使用情况.安全性.计费.错误检测等等.本文将谥介绍日志记录 记录内容 大多数情况下,日志的记录出于两 ...
- kafka配置与使用实例
kafka作为消息队列,在与netty.多线程配合使用时,可以达到高效的消息队列
- JS继承之原型继承
许多OO语言都支持两种继承方式:接口继承和实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在ECMAScript中无法实现接口继承.ECMAScript只支 ...
- js 基础篇(点击事件轮播图的实现)
轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...
- Android之解析XML
1.XML:可扩展标记语言. 可扩展标记语言是一种很像超文本标记语言的标记语言. 它的设计宗旨是传输数据,而不是显示数据. 它的标记没有被预定义.需要自行定义标签. 它被设计为具有自我描述性. 是W3 ...