分类: LINUX
2009-05-20 18:14:17
AX88796网卡移植参考资料:
1、《linux2.6内核在s3c2410平台上移植中修改的文件》
URL:http://blog.chinaunix.net/u/22630/showart_282770.html
2、《linux-2.6.14下cs8900的移植(部分板子是ne2000,可以参考)》
URL:http://blog.csdn.net/hongjiujing/archive/2007/08/17/1747655.aspx
3、《CS8900A驱动在linux-2.6.16上的变化》
URL:http://bibu.blogchina.com/bibu/4914641.html
4、《cs8900 移植Linux-2.6.19.2》
URL: http://weibing.blogbus.com/logs/4467465.html
5、
《嵌入式系统接口设计与Linux驱动程序开发》(刘淼
编著)第十五章:以太网接口与Linux网络驱动程序设计(重点参考,是针对博创2410-S平台+Linux2.4.18编写的,而且很多NE2000
的移植有参考这份资料。你也可以到 刘淼 的博客,上面也有一份NE2000网卡移植的资料可供参考:http://threewater.blog.com.cn/archives/2005/168931.shtml)
一、将Linux2.6.22.2内核源码放到工作目录的kernel文件夹下,并解压。
#tar xzvf linux2.6.22.2.tar.gz
#pwd
/home/tekkaman/working/kernel
# cd linux2.6.22.2
进入内核解压后的目录,以后示例中,只要是相对路径全部是相对于
/home/tekkaman/working/kernel/linux2.6.22.2/此目录
二、修改内核源码根目录下的Makefile文件(CROSS_COMPILE =的值因个人情况而定,其他可以照做。)
#vi Makefile
......
#SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
# -e s/arm.*/arm/ -e s/sa110/arm/ \
# -e s/s390x/s390/ -e s/parisc64/parisc/ \
# -e s/ppc.*/powerpc/ -e s/mips.*/mips/ )
......
#ARCH ?= $(SUBARCH)
#CROSS_COMPILE ?=
ARCH = arm
CROSS_COMPILE
=
/home/tekkaman/working/crosstool-gcc410-k26222/gcc-4.1.0-glibc-2.3.2/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu-
三、修改arch/arm/plat-s3c24xx/common-smdk.c文件,修改Nand Flash的分区信息和Nand Flash的硬件信息。
(LED 器件的初始化也在这个文件里,但是博创的平台没有那四个LED管,所以要不要那些程序都无所谓。我就把它们放在那里,反正启动时不会有影响,也没有出错信息。)
注意:请不要画蛇添足地在进行自定义nand flash分区时仍然按照以前内核的移植步骤,在devs.c中自己添加分区信息,不然系统启动时会有出错信息。我一开始就犯了这个毛病。具体情况请参阅:http://blog.chinaunix.net/u/17218/showart_262438.html以及/arch/arm/plat-s3c24xx文件夹下的common-smdk.c和devs.c。
......
/* NAND parititon from 2.4.18-swl5 */
static struct mtd_partition smdk_default_nand_part[] = {
[0] = {
.name = "U-Boot-1.2.0",
.size = SZ_128K,
.offset = 0,
},
[1] = {
.name = "U-Boot-1.2.0 Parameter",
.offset = SZ_128K,
.size = SZ_64K,
},
[2] = {
.name = "Linux2.6.22.2 Kernel",
.offset = SZ_128K+SZ_64K,
.size = SZ_4M+(SZ_1M-SZ_128K-SZ_64K),
},
[3] = {
.name = "Root-JFFS2",
.offset = SZ_1M * 5,
.size = SZ_1M * 5,
},
[4] = {
.name = "Boot-Root(cramfs)",
.offset = SZ_1M * 10,
.size = SZ_1M * 10,
},
[5] = {
.name = "YAFFS",
.offset = SZ_1M * 20,
.size = SZ_1M * 44,
}
/*,
[6] = {
.name = "S3C2410 flash partition 6",
.offset = SZ_1M * 24,
.size = SZ_1M * 24,
},
[7] = {
.name = "S3C2410 flash partition 7",
.offset = SZ_1M * 48,
.size = SZ_16M,
}
*/
};
......
static struct s3c2410_platform_nand smdk_nand_info = {
.tacls = 0,
.twrph0 = 30,
.twrph1 = 0,
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
};
......
四、 修改drivers/mtd/nand/s3c2410.c,去掉nand flash 的ECC。
我的内核是通过U-BOOT写到Nand Flash的, U-BOOT 通过的软件ECC算法产生ECC校验码, 这与内核校验的ECC码不一样, 内核中的ECC码是由S3C2410中Nand Flash控制器产生的。所以,我在这里选择禁止内核ECC校验。
(不过我不了解内核中的ECC码生成原理,在查资料的过程中我看到了《成功移植最新的2.6.22.3的linux kernel到S3C2410上》,链接是http://www.cnitblog.com/zouzheng/archive/2007/08/28/32545.html和http://hi.baidu.com/wangy0919/blog/item/0058652ae8c3133b5343c1cf.html,都是转载的,但都没找到原作者是谁。其中有这样一段活:
“第三步:修改ECC校验:
根据kernel官方网站上的说明,从2.6.22.3已经修改了ECC校验的问题(这也是我移植2.6.22.3的一个重要原因)。但实验下来发现,不管是用软件ECC还是硬件ECC都不行。只好改成NAND_ECC_NONE:
在driver/mtd/nand/s3c2410.c中找到s3c2410_nand_init_chip()函数,将其中的
chip->ecc.mode=NAND_ECC_SOFT;
改成
chip->ecc.mode=NAND_ECC_NONE; ”
后来我就到网上找关于2.6.22.3的ECC校验的资料,始终没找到上面所说的修改,那位高人看到了通知一声。看来要好好看看这方面的内容了。)
搜索关键字NAND_ECC_SOFT,在s3c2410_nand_init_chip函数里,修改NAND_ECC_SOFT为NAND_ECC_NONE
五、增加Yaffs2文件系统的支持
对
于YAFFS文件系统,我在移植时查阅了许多资料。有的博客上说没有必要移植YAFFS2,因为它是为每页大于1024B的NAND
Flash设计的。即使移植了YAFFS2,如果你的NAND
Flash是每页512+16B的那系统也会自动挂载YAFFS。所以在这里要移植YAFFS2或是YAFFS 随你的便。我移植的是YAFFS2。
1、下载Yaffs2
2、解压Yaffs2并将其加入Linux内核(打补丁的方式)
#cd yaffs2
#./patch-ker.sh c /home/tekkaman/working/kernel/linux-2.6.22.2/
六、博创2410-S所配网卡AX88796(NE2000兼容网卡)驱动的移植。
(1)修改arch/arm/目录下的Kconfig文件,增加ISA总线支持,使其在make menuconfig 时出现NE2000的网卡配置选项。
config ARCH_S3C2410
bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443"
select GENERIC_GPIO
select ISA
help
Samsung S3C2410X CPU based systems, such as the Simtec Electronics
BAST (<), the IPAQ 1940 or
the Samsung SMDK2410 development board (and derivatives).
(2)修改include/asm-arm/arch-s3c2410文件夹下的map.h文件。加入AX88796的地址映射。
/***************tekkaman****************************/
#define S3C2410_VA_ISA_NET S3C2410_ADDR(0x02100000)
#define S3C2410_PA_ISA_NET __phys_to_pfn(0x10000000)
#define S3C2410_SZ_ISA_NET SZ_1M
/**********************tekkaman********************/
说明:
a、根据网上的资料,“#define S3C2410_VA_ISA_NET S3C2410_ADDR(0x02100000)”的地址可以自己修改,只要不和别的虚拟地址冲突就行。我有试过将起改成“#define S3C2410_VA_ISA_NET (0xd1000000)”,也就是博创的2.6.18的定义,也可以正常启动。
b、“#define S3C2410_PA_ISA_NET __phys_to_pfn(0x10000000)”这句困扰了我很久。一开始我的定义是“#define S3C2410_PA_ISA_NET (0x10000000)”,所以启动后系统就死在了网卡的初始化上,出现“Unable to handle kernel paging request at virtual address ”的错误。后来我上网查找资料,才知道:原来实地址与虚地址的映射结构 smdk2410_iodesc 里有所变化。第二个参数从原来的 unsigned long physical 变为 unsigned long pfn (Page Frame Number 页帧号)。而从 smdk2410_iodesc 传入的S3C2410_PA_ISA_NET 仍然是一个 physical 值,因此出现以上的错误。只要在物理地址前加上“__phys_to_pfn”就可以解决这个问题。较详细的讲解请看我的参考资料(文章前面有链接地址)。
(3)修改arch/arm/mach-s3c2410文件夹下的mach-smdk2410.c文件。在smdk2410_iodesc 中加入AX88796的地址信息。
static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */
{
.virtual = S3C2410_VA_ISA_NET,
.pfn = S3C2410_PA_ISA_NET,
.length = S3C2410_SZ_ISA_NET,
.type = MT_DEVICE,
}
};
以下修改为选做,可以不改:
随便在这里取消LCD的初始化,不然启动时会有出错信息(因为我现在的项目用不到,以后有空我会添上LCD的移植和GUI的移植):
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
// &s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};
修改开发板的名称(可以自定义):
MACHINE_START(SMDK2410, "Tekkaman2410")
(4)修改网卡驱动的主要文件drivers/net/ne.c。
a、添加头文件和定义
#include
#include
//**********************tekkaman*************************
#include
#include
#include
#include
#include
#include
#define AX88796_BASE (vAX88796_BASE+0x200)
#define AX88796_IRQ IRQ_EINT2
#define pAX88796_BASE S3C2410_PA_ISA_NET
#define vAX88796_BASE S3C2410_VA_ISA_NET
#define EXTINT_OFF (IRQ_EINT4 - 4)
//**********************tekkaman*****************************
......
在static struct { const char *name8, *name16; unsigned char SAprefix[4];}
bad_clone_list[] __initdata 中增加AX88796 的MAC地址前三位(不一定需要):
{"AX88796", "NE2000-compatible", {0x08, 0x08, 0x08}},
b、确保定义总线宽度为16位。
将
#if defined(CONFIG_PLAT_MAPPI)
# define DCR_VAL 0x4b
#elif defined(CONFIG_PLAT_OAKS32R) || \
defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
# define DCR_VAL 0x48 /* 8-bit mode */
#else
# define DCR_VAL 0x49
#endif
修改为
#if 0
#if defined(CONFIG_PLAT_MAPPI)
# define DCR_VAL 0x4b
#elif defined(CONFIG_PLAT_OAKS32R) || \
defined(CONFIG_TOSHIBA_RBTX4927) || defined(CONFIG_TOSHIBA_RBTX4938)
# define DCR_VAL 0x48 /* 8-bit mode */
#else
#endif
#endif
# define DCR_VAL 0x49
c、在do_ne_probe函数中增加配置总线参数、基地址和中断的语句(其参数参考 刘淼 的书)
static int __init do_ne_probe(struct net_device *dev)
{
unsigned long base_addr = dev->base_addr;
#ifdef NEEDS_PORTLIST
int orig_irq = dev->irq;
#endif
//******************************tekkaman********************************
static int once=0;
if (once) {
return -ENXIO;
}
unsigned int value;
value = __raw_readl(S3C2410_BWSCON);
value &= ~(S3C2410_BWSCON_WS2|S3C2410_BWSCON_ST2|S3C2410_BWSCON_DW2_32);
value |= (S3C2410_BWSCON_ST2|S3C2410_BWSCON_DW2_16);
__raw_writel(value, S3C2410_BWSCON);
value=0;
value
=
(S3C2410_BANKCON_Tacs4|S3C2410_BANKCON_Tcos4|S3C2410_BANKCON_Tacc14|S3C2410_BANKCON_Tcoh4|S3C2410_BANKCON_Tcah4|S3C2410_BANKCON_Tacp6|S3C2410_BANKCON_PMCnorm);
__raw_writel(value,S3C2410_BANKCON2);
set_irq_type(AX88796_IRQ,IRQ_TYPE_LEVEL_LOW );
s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_EINT2);
s3c2410_gpio_pullup(S3C2410_GPF2, 0);
if(base_addr==0){
dev->base_addr = base_addr = AX88796_BASE ;
dev->irq = AX88796_IRQ;
once++;
}
//***********************************tekkaman************************************
SET_MODULE_OWNER(dev);
/* First check any supplied i/o locations. User knows best.
if (base_addr > 0x1ff) /* Check a single specified location. */
return ne_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
return -ENXIO;
......
d、修改ne_probe1函数
增加自定义的网卡MAC地址(这个地址可以自行修改,但是MAC也有一定的规则,最重要的是千万不要把它配置为广播或组播地址,请参考网络的相关书籍):
static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr)
{
int i;
unsigned char ne_defethaddr[]={0x08,0x08,0x08,0x08,0x12,0x27,0};//tekkaman
unsigned char SA_prom[32];
int wordlength = 2;
......
增加网卡MAC地址的配置语句,屏蔽通过EEPROM配置网卡的语句
......
struct {unsigned char value, offset; } program_seq[] =
{
{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
{0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */
{0x00, EN0_RCNTLO}, /* Clear the count regs. */
{0x00, EN0_RCNTHI},
{0x00, EN0_IMR}, /* Mask completion irq. */
{0xFF, EN0_ISR},
{E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */
{E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */
{32, EN0_RCNTLO},
{0x00, EN0_RCNTHI},
{0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */
{0x00, EN0_RSARHI},
{E8390_RREAD+E8390_START, E8390_CMD},
};
for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
}
//****************************************tekkaman*********************************
{
unsigned char *ep;
ep = (unsigned char * ) &ne_defethaddr[0];
ne_defethaddr[5]++;
for(i=0;i<6;i++) {
SA_prom[i] = ep[i];
}
SA_prom[14] = SA_prom[15]=0x57;
wordlength =2;
}
//****************************************tekkaman*********************************
#if 0 //tekkaman
for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) {
SA_prom[i] = inb(ioaddr + NE_DATAPORT);
SA_prom[i+1] = inb(ioaddr + NE_DATAPORT);
if (SA_prom[i] != SA_prom[i+1])
wordlength = 1;
}
#endif //tekkaman
if (wordlength == 2)
{
#if 0 //tekkaman
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
/* We must set the 8390 for word mode. */
outb_p(DCR_VAL, ioaddr + EN0_DCFG);
start_page = NESM_START_PG;
/*
* Realtek RTL8019AS datasheet says that the PSTOP register
* shouldn't exceed 0x60 in 8-bit mode.
* This chip can be identified by reading the signature from
* the remote byte count registers (otherwise write-only)...
*/
if ((DCR_VAL & 0x01) == 0 && /* 8-bit mode */
inb(ioaddr + EN0_RCNTLO) == 0x50 &&
inb(ioaddr + EN0_RCNTHI) == 0x70)
stop_page = 0x60;
else
stop_page = NESM_STOP_PG;
#endif //tekkaman
outb_p(0x49, ioaddr + EN0_DCFG);
start_page = NESM_START_PG;
stop_page = NESM_STOP_PG;
} else {
start_page = NE1SM_START_PG;
stop_page = NE1SM_STOP_PG;
}
......
屏蔽自定检测中断号的语句(参考 刘淼 的书):
......
#if 0 //tekkaman
if (dev->irq < 2)
{
unsigned long cookie = probe_irq_on();
outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */
outb_p(0x00, ioaddr + EN0_RCNTLO);
outb_p(0x00, ioaddr + EN0_RCNTHI);
outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */
mdelay(10); /* wait 10ms for interrupt to propagate */
outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */
dev->irq = probe_irq_off(cookie);
if (ei_debug > 2)
printk(" autoirq is %d\n", dev->irq);
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
or don't know which one to set. */
dev->irq = 9;
#endif //tekkaman
if (! dev->irq) {
printk(" failed to detect IRQ line.\n");
ret = -EAGAIN;
goto err_out;
}
AX88697的移植到此结束!