以下内容源于朱有鹏嵌入式课程的学习,如有侵权请告知删除。
一、网卡相关的基本知识
1、DM9000网卡芯片和SoC的连接
如上图所示,DM9000网卡芯片是通过SROM总线接口,或者说SROM控制器接入SoC的。下面分别介绍SROM控制器、DM9000网卡芯片的相关内容。
2、SROM控制器的简介
(1)SROM控制器,其实就是由SoC提供的、对外的、总线式连接外部SRAM/ROM的一种接口。
(2)如果SoC要外接一些SRAM/ROM类的存储芯片,或者伪装成SROM接口的芯片,比如网卡芯片,就要通过SROM控制器。网卡芯片接进 SROM控制器中后,就好像存储芯片一样被扩展在SoC的一段地址空间中,主机SoC可以使用地址方式访问网卡芯片内部寄存器。
(3)如下所示,SROM控制器有6个bank。外部的SROM器件通过判断连接到自己的片选信号是否有效,来决定地址和数据是否可用。
(4)网卡芯片内部寄存器使用相对地址访问。网卡芯片内部很多寄存器有一个地址,这个地址是从00开始的,但SoC不能用00地址去访问这个网卡芯片内部寄存器,而应该以“起始地址+00”方式访问。这里的起始地址,与网卡芯片接在哪个bank中有关,是那个bank对应的基地址。
(4)下图是DM9000中的寄存器对应基地址的偏移量,从中可以看出DM9000中的寄存器都是8bit的。
(5)主机SoC上网,其实就是通过操控网卡芯片内部的寄存器、缓冲区等资源来上网的。也就是说其实SoC是通过网卡芯片来间接上网的。
(6)网卡芯片与SoC的连接方式,实际上也是一种总线式连接方式。优势是SoC内部不需要内置网卡控制器,SFR都在外部的网卡芯片中,而且还可以通过地址直接访问(IO与内存统一编址),不用像Nand/SD接口一样使用时序来访问。因此从逻辑上来看,网卡更像是SoC内部的串口模块,而不像是SD/Nand。
3、DM9000网卡芯片的简介
(1)DM9000网卡芯片的引脚
DM9000网卡芯片的原理图如下:
其中重要的引脚有IOR、IOW、AEN、CMD、INT、RST,以及数据引脚 SD0-SD15。
(1)DM9000的CS引脚
CS就是chip select,即片选信号。DM9000网卡芯片的CS引脚要连接主机SoC的片选信号引脚,主机SoC向 DM9000的CS引脚发送有效信号时,DM9000网卡芯片才能正常工作。主机SoC的每个bank中都有一个片选信号CSn(n=0~5),从原理图可以看出,X210开发板将DM9000网卡芯片的CS引脚接到了CSn1上,对应着bank1,因此可以推断出DM9000网卡芯片的总线地址基地址是0x88000000。
(2)DM9000的CMD引脚
DM9000的CMD引脚连接了主机SoC的ADDR2引脚。DM9000为了减少芯片引脚数,数据线和地址线是复用的,也就是说,DATA0~DATA15这16根线有时候用作数据线来传输数据,有时候用作地址线传输地址。通过查询数据手册可知,这由CMD引脚的电平来决定:当CMD为高电平时,DATA0~DATA15这16根线传输的是数据;当CMD为低电平时,DATA0~DATA15这16根线传输的是offset。
- 如果要往DM9000的0x04地址写入数据a,则要执行以下两步:
- 第一步:ADDR2拉低,16位数据写0x04,也就是 *0x8800_0000 = 0x04;(0x8800_0000这个基地址的寄存器存放的是将要访问的某个内存的地址相对该基地址的偏移量?当要往某个地址写入数据时,合成的地址的该基地址+偏移量?)
- 第二步:ADDR2拉高,16位数据写a,也就是 *0x8800_0004 = a。
- 细节理解见博客http://www.cnblogs.com/biaohc/p/6413547.html
(3)DM9000通过HR911105A接口与外部网线相连
- 网线有8根线,但是实际只有4根有效通信线,另外4根都是GND,用来抗干扰的。
- 4根通信线中管发送的是有2根(TX-和TX+),管接收的2根(RX+和RX-),因为网上传输的是差分信号。
(1)IOR:读选择引脚,低电平有效,即低电平是读;IOW:写选择引脚,低电平有效,即低电平写;
(2)cmd引脚是命令/数据切换引脚,低电平时读写命令操作,高电平时读写数据操作其中。
(3)地址引脚配合AEN引脚来选通该网卡芯片,对于大多数的应用来说没有意义,因为在我们的应用中一般只用一个网卡芯片,而这些地址引脚主要用于在多网卡芯片环境下选择其中之一。
(4)DM9000工作的默认基地址为0x300,这里我们按照默认地址选择,将SA9、SA8接高电平,SA7-DA4接低电平。
(5)下面这段话很关键:
dm9000芯片数据总线16根,地址总线只连接了1根,连接的ADDR2,dm9000中的寄存器寻址是通过数据总线来寻址的,并不是通过地址总线寻址。
当addr2为低电平时,data总线发送的是地址,前面提到了9、8地址线为1,4-7地址线为0,所以基地址是0x8800_0300 ;
当addr2为0,那么0x8800_0300地址中的值为地址,这个地址中的值对应的是dm9000芯片中的寄存器,而addr2为1即0x8800_0304这个地址对应的位数据。
(6)总结1
- 0x8800_0300 加上一定的偏移量,用来选择dm9000中的寄存器;
- 0x8800_0304这个寄存器用来给dm9000中的寄存器读写值;
- 配合IOW、IOR两个命令总线,可以读取和写入dm9000寄存器,从而进行对寄存器的操控。
(7)总结2
- 在DM9000中只有两个可以直接被处理器访问的寄存器(为了解释方便,这里命名为CMD端口和DATA端口);
- 访问其他控制或者状态寄存器的方法:1)将寄存器的地址写到CMD端口;2)从DATA端口读写寄存器中的数据;
(8)总结3:读、写寄存器
其实INDEX端口和DATA端口的就是由芯片上的CMD引脚来区分的。低电平为INDEX端口,高电平为DATA端口。所以,要想实现读写寄存器,就必须先控制好CMD引脚。
若使用总线接口连接DM9000,假设总线连接后芯片的基地址为0x800300(24根地址总线),方法如下
#define _REG_DM_ADDR (*(volatile unsigned short *)0x800300) #define _REG_DM_DATA (*(volatile unsigned short *)0x800304)
DM9000寄存器的写读写函数:
void dm9k_reg_write(u16 reg, u16 data) {udelay(20); //延时20um_REG_DM_ADDR = reg;udelay(20); //延时20um_REG_DM_DATA = data; } //这个函数即可把data中的值写入dm9000相应的寄存器中;unsigned int dm9k_reg_read(u16 reg) {udelay(20); //延时20um _REG_DM_ADDR = reg;udelay(20);return _REG_DM_DATA ; }
二、网卡移植的理论与操作
1、DM9000网卡的驱动
(1)drivers/net目录下存放着各类网卡芯片的驱动文件,它们都来源于linux内核。
(2)X210开发板使用的是DM9000网卡,对应的驱动文件是dm9000.h和dm9000.c。
(3)网卡移植的主要工作在于初始化网卡,只要将网卡芯片正确地初始化则网卡芯片就能正常工作。注意“网卡初始化”与“网卡驱动”不是同一个概念,网卡驱动dm9000x.c和dm9000x.h的工作依赖于网卡的初始化。
2、分析网卡初始化函数:dm9000_pre_init
uboot第二阶段的board_init函数中的dm9000_pre_init函数对网卡进行了初始化。
这个dm9000_pre_init函数在/board/samsung/smdkc110/smdkc11.c文件中,内容如上图,被注释掉的是三星版本uboot中的代码,新添的是针对X210开发板的代码。DM9000网卡使用的是bank1,因此新添的代码是对SROM控制器的bank1进行初始化。
下面分析(对SROM控制器的bank1进行初始化的)代码。
(1)SROM_BW寄存器,对SROM控制器进行配置
SROM_BW寄存器每4个位控制一个bank,bank1对应着SROM_BW寄存器的第7~4位。
- 网卡工作在16-bit模式,所以DataWidth1这个bit设置为1 。
- 原理图连接时,SROM控制器的数据data15~0接到网卡的data15~0,因此是字节对齐的,所以AddrMode1这个bit设置为1。
- 第7位和第6位和时序相关,根据经验都设置为1。
(2)SROM_BCn寄存器,设置各个bank的时序信息(n=0~5)
- SROM_BCn寄存器每个bit的含义参考文档,这里的设置见代码。
(3)MP0_1CON寄存器,配置SROM控制器的GPIO的片选功能
通俗地讲,这个寄存器用来设置SROM控制器使能哪些bank。因为dm9000接在bank1,所以要使能bank1。代码中将 MP0_1CON 寄存器的第7~4位设置为 0010,表示将MP01_1这个引脚设置为SROM控制器的bank1的片选引脚,通俗而简单地理解,就是使能bank1。
3、基地址的配置
(1)在/include/configs/smdkv210single.h文件中,关于网卡部分的宏定义如下。
1)CONFIG_DM9000_BASE这个宏的值,是DM9000网卡通过SROM bank映射到SoC中地址空间中的地址。这个地址取决于网卡接到哪个bank。每个bank的基地址是SoC已经定义好而且不能更改的。X210开发板的网卡接到了bank1,而bank1的基地址是0x88000000,所以CONFIG_DM9000_BASE要修改成0x88000000。但实际上要改为0x88000300,否则网卡不能工作。0x300跟DM9000网卡芯片型号版本有关,是DM9000网卡本身的问题,其内部寄存器就有一个0x300的一个偏移量。
2)DM9000_IO这个宏表示访问网卡芯片IO的基地址(网卡芯片中与IO有关的寄存器的开始地址),直接就是CONFIG_DM9000_BASE,不用修改。
3)DM9000_DATA这个表示我们访问数据时的基地址(网卡芯片中与数据有关的寄存器的开始地址)。因为DM9000芯片的CMD引脚接到了ADDR2,因此数据的地址是基地址+4,即这里要+4(0b100对应着ADDR2)。
4、测试网卡移植的效果
三、网卡驱动的典型工作方式
1、网卡在linux系统中的设备名
网卡是一个设备,此设备驱动工作后会生成一个设备名叫ethn(n=0,1,2…),而无线网卡名字一般叫wlanx(x=0,1,2…),然后linux系统用一些专用命令来操作网卡,如ifconfig命令。
2、应用程序如何调用网卡驱动进行网络通信
最通用的方法就是socket接口。Linux系统中有一系列的API和库函数,提供了一个socket编程接口。linux下的应用程序都是通过socket来实现上网的。而socket内部就是间接调用网卡驱动实现网络通信的。
3、应用层和驱动层的分层思想
Linux设计是非常完备的,应用层和驱动层是严格分离的。写网络编程应用层的人根本不用管驱动,只要会用socket接口即可;写底层驱动的人根本不用管应用层,只要面向linux的网络驱动框架模型即可。
4、uboot的ping命令实现
ping命令的实现代码属于应用程序,而dm9000.h和dm9000.c这样的代码属于驱动程序。在uboot中,应用是直接调用驱动实现的,即ping命令是直接调用dm9000的网卡驱动中的函数来实现的。
ping命令的实现函数是do_ping,在common/cmd_net.c中。
do_ping函数调用string_to_ip函数将输入的ip地址转化为IPaddr_t类型值。
do_ping函数接着调用NetLoop函数(在net\net.c中),该函数前面的部分都是在构建ping的包,构建好后使用PingStart函数(在net\net.c中),准备发送ping包。
PingStart函数最后调用PingSend函数(在net\net.c中),将包发出去。
PingSend函数前面在构建数据,最后使用ArpRequest函数(在net\net.c中),将ARP包发送。这是因为ping使用的是ARP包。
ArpRequest函数的前部分也是在做数据的处理,最后调用eth_send函数(在文件drivers/net/dm9000x.c中),将数据包发送出去。
eth_send函数与具体的网卡芯片有关的。该函数将指定的包发送给DM9000网卡,网卡再将该包发送到网络中。这样,就完成了ping的ARP包的发送。
接收从网络回发的ARP包:在net_loop函数的后面,调用eth_rx函数(drivers/net/dm9000x.c中)接收网络数据包。此接收函数和具体网卡有关。