本帖最后由 陌路绝途 于 2014-8-4 23:28 编辑
1.简单介绍下DM9000A:
DM9000A是一款由中国台湾DAVICOM公司推出的一款高速以太网接口芯片,该芯片完全集成的和符合成本效益单芯片快速以太网MAC控制器与一般处理接口,一个10/100M自适应的PHY和4K DWORD值的SRAM 。它的目的是在低功耗和高性能进程的3.3V与5V的支持宽容。
DM9000AEP还提供了介质无关的接口,来连接所有提供支持介质无关接口功能的家用电话线网络设备或其他收发器。该DM9000AEP支持8位, 16位和32 -位接口访问内部存储器,以支持不同的处理器。DM9000Aep物理协议层接口完全支持使用10MBps下3类、4类、5类非屏蔽双绞线和100MBps下5类非屏蔽双绞线。这是完全符合IEEE 802.3u规格。它的自动协调功能将自动完成配置以最大限度地适合其线路带宽。还支持IEEE 802.3x全双工流量控制。这个工作里面DM9000AEP是非常简单的,所以用户可以容易的移植任何系统下的端口驱动程序。
特点:
支持处理器读写内部存储器的数据操作命令以 字节/ 字/ 双字的长度进行
集成10/100M自适应收发器
支持介质无关接口
支持背压模式半双工流量控制模式
IEEE802.3x流量控制的全双工模式
支持唤醒帧,链路状态改变和远程的唤醒
16K双字SRAM
支持自动加载EEPROM里面生产商ID和产品ID
支持4个通用输入输出口
超低功耗模式
功率降低模式
电源故障模式
可选择1:1YL18-2050s YT37-1107S或5:4变压比例的变压器降低格外功率
兼容3.3v和5.0v输入输出电压
100脚CMOS LQFP封装工艺
2.DM9000A的框图
重要的是物理层PHY receiver,MAC(media access control)层,这里与软件中的协议栈不同,在硬件上MAC是PHY的下一层。DM9000A将MAC和PHY做到一起,也可以像IIS设备那样,SOC内有IIS的控制器,而声卡UDA1341放在片外。网卡当然也有这种设计,它是把PHY的下层MAC放入SOC内,片外的是PHY,当然我暂时还没见过这种的。DM9000A的输入是并行的总线,可以和CPU直接IO。而IIS那种需要通过:CPU CORE BUS->I2S控制器->外设。通过对比,应该了解DM9000A怎样进行IO了吧。其中PHYreceiver中的AUTO-MDIX控制网卡的自适应,也就是说它能自动检测连接的是什么速度的网络,切换100,10。如果双方都是自适应的,那就依据误码率来选择。图中的EEPROM当然存放的是MAC的地址,那么驱动从哪里得到MAC地址的?1)你手工设置的,然后他给你写入到EEPROM里2)要么就是EEPROM里面应该好了。图中的MII是一种称为媒体独立接口的东西,是为了和PHY连接而设计的。
再来看一下上边这个DM9000A的原理图,它的CMD引脚接在CPU的LADDR0上。这里的地址线和数据线是进行复用的。当CMD为0时,SD0~SD15传的是地址,当CMD为1时,SD0~SD15传的是数据。
DM9000A的驱动作为platform_driver注册到内核中,根据Linux设备驱动模型,还应该有一个platform_device,但是源码里没有这个,这就需要我们自己来添加了,在arch/arm/plat-s3c24xx/devs.c中,添加:
#include
static struct resource dm9000_resources[] = {[0] = {
.start = S3C24XX_PA_DM9000,
.end = S3C24XX_PA_DM9000+0x3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C24XX_PA_DM9000+0x4,
//.end = S3C64XX_PA_DM9000 + 0x4 + 0x7c,
.end = S3C24XX_PA_DM9000+S3C24XX_SZ_DM9000 -1,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT4,
.end = IRQ_EINT4,
//.flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
//.flags = IORESOURCE_IRQ | IRQF_TRIGGER_LOW
.flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH,
},
};
staticstruct dm9000_plat_data dm9000_setup = {
.flags =DM9000_PLATF_16BITONLY
// .flags = (DM9000_PLATF_16BITONLY |DM9000_PLATF_NO_EEPROM),
};
structplatform_device s3c_device_dm9000 = {
.name ="dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(dm9000_resources),
.resource = dm9000_resources,
.dev =
{
.platform_data = &dm9000_setup,
}
};
EXPORT_SYMBOL(s3c_device_dm9000);
注意这里第一个IO内存资源的范围是从S3C24XX_PA_DM9000~S3C24XX_PA_DM9000+ 0x3,第二个IO内存资源的范围是从S3C24XX_PA_DM9000 +S3C24XX_PA_DM9000+S3C24XX_SZ_DM9000 -1。这相当于两个32位的寄存器。一个是地址寄存器,一个是数据寄存器。向地址寄存器中写入0x1相当于选中了offset为1的NCR。向数据寄存器中写入数据他会自动写入TX RAM中。什么是TX RAM在DM9000A的驱动框架源码分析文档中已经解释了,这里就不再赘述。在这个文件中添加了平台设备的资源和平台设备。那么这个平台设备又是什么时候注册进内核的呢?我们继续往下看。在设备列表添加对DM9000A设备的支持,在arch/arm/mach-s3c2416/mach-smdk2416.c文件中,添加红色这一行:
static struct platform_device*smdk2416_devices[] __initdata = {
/&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_lcd,
&s3c_device_rtc,
&s3c_device_adc,
&s3c_device_iis,
&s3c_device_usbgadget,
&s3c_device_usb,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
//&s3c_device_smc911x
&s3c_device_dm9000,
};
那么这些platform_device是什么时候注册的呢,看这个文件下边的代码,很明了了,在系统初始化的时候会注册这个设备列表中的每一个设备。
staticstruct s3c24xx_board smdk2416_board __initdata = {
.devices =smdk2416_devices,
.devices_count =ARRAY_SIZE(smdk2416_devices)
};
static void __init smdk2416_map_io(void)
{
s3c24xx_init_io(smdk2416_iodesc,ARRAY_SIZE(smdk2416_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2416_uartcfgs,ARRAY_SIZE(smdk2416_uartcfgs));
s3c24xx_set_board(&smdk2416_board);
}
然后修改include/asm-arm/plat-s3c24xx/devs.h ,添加:
#if defined(CONFIG_CPU_S3C6410) ||defined(CONFIG_CPU_S3C2450)|| defined(CONFIG_CPU_S3C2416)
extern struct platform_devices3c_device_smc911x;
extern struct platform_device s3c_device_dm9000;
#endif
修改include/linux/dm9000.h 文件
/* DM9000 */
#define S3C24XX_VA_DM9000 (0xe0000000)
#define S3C24XX_PA_DM9000 (0x08000000)
#define S3C24XX_SZ_DM9000 SZ_1M
这里设定了网卡的物理地址和虚拟地址,在arch/arm/mach-s3c2416/mach-smdk2416.c中进行静态映射,在static struct platform_device *smdk2416_devices[]__initdata中添加:
static struct map_desc smdk2416_iodesc[] __initdata = {
/* add by grubly 20110713------------------------------------- */
//IODESC_ENT(CS8900),
#ifdef CONFIG_DM9000
{
.virtual = (u32)S3C24XX_VA_DM9000,
.pfn = __phys_to_pfn(S3C24XX_PA_DM9000),
.length = S3C24XX_SZ_DM9000,
.type = MT_DEVICE,
},
#endif
/* add end------------------------------------- */
};
这样在程序中访问S3C24XX_PA_DM9000,S3C24XX_PA_DM9000 + 0x4对应的物理地址,就直接转换到相应的虚拟地址了。至此DM9000A平台设备的添加和IO地址的静态映射完成。然后就是修改DM9000A中的MAC地址等了。
修改drivers/net/dm9000.c 文件,增加3行:
#include
#include
#include
修改dm9000_probe函数,添加
static charnet_mac_addr[]={0x00,0xe0,0x3d,0xf4,0xdd,0xf7};//MAC
static void *extint0,*intmsk,*eintmsk,*eintmod;
#define EINTMASK (0x560000a4) //外部中断屏蔽
#define EXTINT0 (0x56000088) //外部中断方式
#define INTMSK (0x4A000008)//中断屏蔽
#define INTMOD (0x4A000004)//
extint0=ioremap_nocache(EXTINT0,4);//
intmsk=ioremap_nocache(INTMSK,4);
eintmsk=ioremap_nocache(EINTMASK,4);
eintmod=ioremap_nocache(INTMOD,4);
s3c2410_gpio_cfgpin(S3C2410_GPF4,S3C2410_GPF4_EINT4);
writel(readl(extint0)&0xfff1ffff,extint0);//高电平触发中断
writel(readl(intmsk)&(~(1<<4)),intmsk);//
writel(readl(eintmsk)&(~(1<<4)),eintmsk);
writel(readl(eintmod)&(~(1<<4)),eintmod);
iounmap(intmsk);
iounmap(extint0);
iounmap(eintmsk);
这里主要设置了总线宽度&等待寄存器,设置相应的GPIO引脚为EXINT4,中断为高电平触发。
DM9000打开函数有一个申请中断的函数,在这个函数中加入中断触发类型的申请。
dm9000_open(structnet_device *dev)
{
board_info_t *db = (board_info_t *) dev->priv;
unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
PRINTK2("enteringdm9000_open\n");
irqflags |= IRQF_SHARED;
if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name,dev))
return -EAGAIN;
在这个函数的最后需要修改:
if(!is_valid_ether_addr(ndev->dev_addr)) {
/* try reading from mac */
mac_src = "chip";
for (i = 0; i < 6; i++)
//ndev->dev_addr = ior(db, i+DM9000_PAR);
ndev->dev_addr = net_mac_addr;
在文件系统中添加网络配置文件,使系统在开机过程中自动完成对网卡的配置
1)在文件系统/etc/net.conf文件中添加内容
IPADDR=192.168.0.105
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
MAC=00:11:22:33:44:55
2)在文件系统/sbin/目录下新建一个可执行的脚本文件net_config,注意文件的权限(可执行)
#!/bin/sh
echoTry to bring eth0 interface up ...>/dev/s3c2410_serial0
if [-f /etc/net.conf ] ; then
source /etc/net.conf
ifconfigeth0 down
ifconfigeth0 hw ether $MAC
echoifconfig eth0 hw ether $MAC >/dev/s3c2410_serial0
ifconfigeth0 $IPADDR netmask $NETMASK up
echoifconfig eth0 $IPADDR netmask $NETMASK up >/dev/s3c2410_serial0
routeadd default gw $GATEWAY
echoadd default gw $GATEWAY >/dev/s3c2410_serial0
else
ifconfigeth0 hw ether 00:11:22:33:44:55
ifconfigeth0 192.168.1.105 netmask 255.255.255.0 up
routeadd default gw 192.168.0.1
echoifconfig eth0 hw ether 00:11:22:33:44:55 >/dev/s3c2410_serial0
echoifconfig eth0 192.168.0.105 netmask 255.255.255.0 up>/dev/s3c2410_serial0
echo route add default gw 192.168.0.1>/dev/s3c2410_serial0
fi
echoDone > /dev/s3c2410_serial0
3)在文件系统/etc/init.d/rcS文件中添加网络配置语句
/sbin/ifconfiglo 127.0.0.1 #设置本地回环设备的IP地址
net_config& #执行上面的net_config文件对网卡进行设置
在文件系统中添加完上述网卡配置信息后重新编译文件系统下载到开发板,系统上电启动后就会对网卡自动配置,并执行#ifconfig命令可以看到网卡的配置信息。
测试与主机的通信,开发板的IP地址可以在/etc/net.conf中修改