我的arm_linux移植笔记
2016-06-24 15:11
633 查看
一、uboot1.2.0移植
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0或者V3.0
编译器:cross3.2(下载地址ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.2.tar.gz)
Uboot:u-boot-1.2.0(下载地址:ftp://ftp.denx.de/pub/u-boot/)
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址http://blog.chinaunix.net/u1/34474/index.html。
其中uboot的移植参照http://blog.chinaunix.net/u1/34474/showart.php?id=397315做的。
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.用dk登录linux主机,在dk下创建一个myboard文件夹
2.解压cross3.2:解压到/usr/local/arm/文件夹下
最好在/usr/local/arm/下创建一个3.2文件夹,把解压在arm文件夹下的文件(夹)全部移到3.2下,因为后面可能还会用到3.4.1的交叉编译器。
3.解压uboot:将uboot解压到myboard文件夹下
tarxzvfu-boot-1.2.0.tar.bz2–C/home/dk/myboard/
4.进入uboot目录,修改Makefile
cdu-boot-1.2.0
viMakefile
(1)新建我的编译项
在1923行,即smdk2410_config编译项之后增加我的编译项
tekkaman2440_config:unconfig
@$(MKCONFIG)$(@:_config=)armarm920ttekkaman2440tekkamans3c24x0
各项的意思如下:
arm:CPU的架构(ARCH)
arm920t:CPU的类型(CPU),其对应于cpu/arm920t子目录。
tekkaman2440:开发板的型号(BOARD),对应于board/tekkaman/tekkaman2440目录。
tekkaman:开发者/或经销商(vender)。
s3c24x0:片上系统(SOC)。
(2)修改交叉编译器路径,我用的cross3.2是在/usr/local/arm/
修改128行
CROSS_COMPILE=/usr/local/arm/3.2/bin/arm-linux-
5.在/board子目录中建立自己的开发板tekkaman2440目录
由于我在上一步板子的开发者/或经销商(vender)中填了tekkaman,所以开发板tekkaman2440目录一定要建在/board子目录中的tekkaman目录下,否则编译会出错。
$cdboard
$mkdirtekkamantekkaman/tekkaman2440
$cp-arfsbc2410x/*tekkaman/tekkaman2440/
$cdtekkaman/tekkaman2440
$mvsbc2410x.ctekkaman2440.c
还要记得修改自己的开发板tekkaman2440目录下的Makefile文件,不然编译时会出错:
$viMakefile
COBJS:=tekkaman2440.oflash.o
6.在include/configs/中建立配置头文件
$cpinclude/configs/sbc2410x.hinclude/configs/tekkaman2440.h
7.测试编译能否成功
$maketekkaman2440_config
Configuringfortekkaman2440board...
(如果出现:
$maketekkaman2440_config
Makefile:1927:***遗漏分隔符。停止。
请在U-boot的根目录下的Makefile的
@$(MKCONFIG)$(@:_config=)armarm920ttekkaman2440tekkaman)
前加上“Tab”键)
$make
到这一步应该能编译成功,但是我的并没有编译成功,提示/common/cmd_bootm.c文件的464行的U_BOOT_CMD有错误,我是把其中的从#ifdefCONFIG_OF_FLAT_TREE到#endif都屏蔽掉,这样就可以编译过去了。可能还会出现类似的问题,用同样的方法可以解决。
下面修改Uboot中的文件,以匹配开发板
8.修改/cpu/arm920t/start.S
这个函数是arm920t系列的共有启动的汇编代码,UBOOT执行的第一个程序
(0)修改寄存器地址定义
/*turnoffthewatchdog*/
#ifdefined(CONFIG_S3C2400)
#definepWTCON0x15300000
#defineINTMSK0x14400008/*Interupt-Controllerbaseaddresses*/
#defineCLKDIVN0x14800014/*clockdivisorregister*/
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
#definepWTCON0x53000000这个定义了看门狗的寄存器地址
#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/中断掩码的寄存器地址
#defineINTSUBMSK0x4A00001C中断掩码的寄存器地址
#defineCLKDIVN0x4C000014/*clockdivisorregister*/完成时钟分份的寄存器
#endif
(1)修改中断禁止部分
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
ldrr0,=pWTCON把看门狗寄存器地址给了r0
movr1,#0x0r1等于0
strr1,[r0]看门狗寄存器等于0因为在启动时要关闭看门狗,不能让他产生中断影响启动,此时也根本不需要任何中断
/*
*maskallIRQsbysettingallbitsintheINTMR-default
*/
movr1,#0xffffffff关闭所有中断
ldrr0,=INTMSK
strr1,[r0]
#ifdefined(CONFIG_S3C2410)
ldrr1,=0x7ff//根据2410芯片手册,INTSUBMSK有11位可用,
//vivi也是0x7ff,不知为什么U-Boot一直没改过来。
ldrr0,=INTSUBMSK
strr1,[r0]
#endif
#ifdefined(CONFIG_S3C2440)
ldrr1,=0x7fff//根据2440芯片手册,INTSUBMSK有15位可用
ldrr0,=INTSUBMSK
strr1,[r0]
#endif
(2)修改时钟设置(2440的主频可达533MHz,但是我设到533MHz时系统很不稳定,不知是不是SDRAM和总线配置的影响,所以现在先设到405MHz,以后在改进。)
ldrr0,=CLKDIVN
这个值决定了FCLKHCLKPCLK的频率
FCLK是供给CPU的是主频
HCLK是供给AHB总线(主要用于高性能模块(如CPU、DMA和DSP等)之间的连接,作为SoC的片上系统总线)上的外围设备
PCLK是供给APB总线(APB主要用于低带宽的周边外设之间的连接,例如UART、1284等)上的外围设备
UCLK是两路PLL中一路供给USB的频率
ARM总线技术在这里我不多介绍了,对硬件感兴趣的同学建议多多了解,我有一回面试人家就问我这个了,405MHZ已经很高了,基本都够了,2410的200MHZ就能播放Mplayer视频,据说很流畅。
movr1,#5/*FCLK:HCLK:PCLK=1:4:8*/
strr1,[r0]
mrcp15,0,r1,c1,c0,0/*readctrlregistertekkaman*/
orrr1,r1,#0xc0000000/*Asynchronoustekkaman*/
mcrp15,0,r1,c1,c0,0/*writectrlregistertekkaman*/
他是用到了协处理器P15,此处理器主要设置mmu,时钟模式,caches,保护模式的。先把C0
C1的值读出到r1,设置后再写回。FCLK:HCLK:PCLK的比例由CLKDIVN决定的,CLKDIVN寄存器的HDIVN和PDIVN决定比例的大小。因为此时的HDIVH不为0,将快速总线模式改为异步总线模式,操作协处理器P15改变模式即可,如果HDIVH不为0,而且是快速总线模式的话,那么CPU的主频由hclk控制,这样可以实现不改变HCLK和PCLCK的同时就能使CPU的主频减半或更多。网上的大虾说没有以上几句主频会是12MHZ,我的观点不同。这是数据手册原文
IfHDIVNisnot0andtheCPUbusmodeisthefastbusmode,theCPUwilloperatebytheHCLK.ThisfeaturecanbeusedtochangetheCPUfrequencyasahalformorewithoutaffectingtheHCLKandPCLK
#ifdefined(CONFIG_S3C2440)
/*now,CPUclockis405.00Mhztekkaman*/
movr1,#CLK_CTL_BASE/*tekkaman*/这是时钟寄存器的基地址
movr2,#MDIV_405/*mpll_405mhztekkaman*/
addr2,r2,#PSDIV_405/*mpll_405mhztekkaman*/
strr2,[r1,#0x04]/*MPLLCONtekkaman*/设置MPLLCON
#endif
#ifdefined(CONFIG_S3C2410)
/*now,CPUclockis202.8Mhztekkaman*/
movr1,#CLK_CTL_BASE/*tekkaman*/
movr2,#MDIV_200/*mpll_200mhztekkaman*/
addr2,r2,#PSDIV_200/*mpll_200mhztekkaman*/
strr2,[r1,#0x04]/*MPLLCONtekkaman*/
#endif
#endif/*CONFIG_S3C2400||CONFIG_S3C2410||CONFIG_S3C2440*/
红色部分是我添加的,利用vivi的代码,将其设为405.00MHz并在前面加上:
#elifdefined(CONFIG_S3C2410)
#definepWTCON0x53000000
#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/
#defineINTSUBMSK0x4A00001C
#defineCLKDIVN0x4C000014/*clockdivisorregister*/
#defineCLK_CTL_BASE0x4C000000/*tekkaman*/
#ifdefined(CONFIG_S3C2440)
#defineMDIV_4050x7f<<12/*tekkaman*/
#definePSDIV_4050x21/*tekkaman*/
#endif
#ifdefined(CONFIG_S3C2410)
#defineMDIV_2000xa1<<12/*tekkaman*/
#definePSDIV_2000x31/*tekkaman*/
#endif
#endif〕
(3)将从Flash启动改成从NANDFlash启动。(特别注意:这和2410的程序有不同,不可混用!!!是拷贝vivi的代码。)
将以下U-Boot的重定向语句段:
这段代码将uboot搬运到ram中,这个是没有存放在nand的情况,下面咱们来看一下不在nand启动和在nand启动时此处的区别。
#ifndefCONFIG_SKIP_RELOCATE_UBOOT
relocate:/*relocateU-BoottoRAM*/
adrr0,_start/*r0<-currentpositionofcode*/nor中的起始地址给了r0
ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/ram中的uboot代码的起始地址(这里关于uboot搬运这块在内存地址的部分,分了很多段,每一段空间具有不同功能,这是你理解uboot必须掌握的,非常关键,解释后续会提到些)
cmpr0,r1/*don'trelocduringdebug*/比较两个地址是否相同,不同则进行下面的搬运工作
beqstack_setup
在这里你会发现搬运了全部uboot,有的uboot把uboot的c部分搬运到内存_TEXT_BASE里面所放的地址处。
ldrr2,_armboot_start
ldrr3,_bss_start
subr2,r3,r2/*r2<-sizeofarmboot*/_bss_start-_armboot_start=armboot因为_armboot_end的结束位置就是bss区的开始位置所以能计算出uboot代码的大小
addr2,r0,r2/*r2<-sourceendaddress*/
以下就是把整个代码搬运到_TEXT_BASE里面所放的地址处,记住是内存地址,哈哈!!
copy_loop:
ldmiar0!,{r3-r10}/*copyfromsourceaddress[r0]*/
stmiar1!,{r3-r10}/*copytotargetaddress[r1]*/
cmpr0,r2/*untilsourceendaddreee[r2]*/
blecopy_loop
#endif/*CONFIG_SKIP_RELOCATE_UBOOT*/
替换成:因为nand和nor的启动是有区别的,NORFlash储存器较贵,而NAND
Flash则相对便宜,所以很多用户选择在NANDFlash中执行启动代码,在SDRAM中执行主程序。为支持NAND
Flash的BootLader,S3C2440有一个内部SRAM缓冲,称为‘Steppingstone’,启动时,NAND
Flash的最先4K字节将被装载到Steppingstone中,装载到Steppingstone中的启动代码将执行。这都是硬件自动完成的不需要咱们软件参与。一般来说,启动代码将把NAND
Flash的内容拷贝到SDRAM中,ECC将检测NAND的合法性,当拷贝完成时,主程序将在SDRAM中执行电源开启后,或系统重启后,NAND
Flash控制器将自动装载4KB的BootLoader代码,载入代码后将执行。注意在自启动时,ECC不检测,因此,NAND
Flash的头4KB要保证无错,下面我来带你分析它的源代码喽,嘿嘿!!!!忽然想家了,对了nand的硬件连接简单有兴趣的看一下了(NCON-Adv
Flash,GPG13-Pagesize,GPG14-Addresscycle,GPG15-总线宽度)
#ifdefCONFIG_S3C2440_NAND_BOOT@tekkaman@在以后会定义它的,不要忘了
@resetNAND
movr1,#NAND_CTL_BASEnand的寄存器基地址
ldrr2,=((7<<12)|(7<<8)|(7<<4)|(0<<0))CLE&ALE期间设置值|TWRPH0期间设置值|TWRPH0期间设置值|8位总线
strr2,[r1,#oNFCONF]设置NFCONF寄存器,初始化作用
ldrr2,[r1,#oNFCONF]
ldrr2,=((1<<4)|(0<<1)|(1<<0))@ActivelowCEControl初始化ECC解码/编码器(只写)|强制拉低nFCE(允许片选)|允许NAND控制器
strr2,[r1,#oNFCONT]设置NFCONT
ldrr2,[r1,#oNFCONT]
ldrr2,=(0x6)@RnBClear和nandisbusy
strr2,[r1,#oNFSTAT]
ldrr2,[r1,#oNFSTAT]
movr2,#0xff@RESETcommand
strbr2,[r1,#oNFCMD]
movr3,#0@wait就是一下段延时
nand1:
addr3,r3,#0x1
cmpr3,#0xa
bltnand1
nand2:
ldrr2,[r1,#oNFSTAT]@waitready
tstr2,#0x4
beqnand2
ldrr2,[r1,#oNFCONT]
orrr2,r2,#0x2@FlashMemoryChipDisable
strr2,[r1,#oNFCONT]
@getreadtocallCfunctions(fornand_read())
ldrsp,DW_STACK_START@setupstackpointer
movfp,#0@nopreviousframe,sofp=0初始化frame的起始位置
@copyU-BoottoRAM
ldrr0,=TEXT_BASE设置第1个参数:UBOOT在RAM中的起始地址
movr1,#0x0设置第2个参数:NandFlash的起始地址
movr2,#0x20000设置第3个参数:UBOOT的长度(128KB)
blnand_read_ll在board/tekkaman/tekkaman2440/nand_read.c我会解析这个函数的作用
tstr0,#0x0如果函数的返回值为0,表示执行成功.
beqok_nand_read执行内存比较,比较什么呢?他比较搬运到内存中的代码和在内部ram的前4kb是否一样
bad_nand_read:
loop2:bloop2@infiniteloop
ok_nand_read:
@verify
movr0,#0内部RAM的起始地址
ldrr1,=TEXT_BASE
UBOOT在RAM中的起始地址
movr2,#0x400@4bytes*1024=4K-bytes
go_next:
ldrr3,[r0],#4
ldrr4,[r1],#4
teqr3,r4进行比较
bnenotmatch
subsr2,r2,#4
beqstack_setup
bnego_next
notmatch:
内存中的代码和在内部ram的前4kb如果不一样,就无限的循环在这了,如果你不努力的去体会每一句,你的功力就像他一样了,哈哈!
loop3:bloop3@infiniteloop
#endif@CONFIG_S3C2440_NAND_BOOT@tekkaman@@
在“
_start_armboot:.wordstart_armboot”后加入:
.align2二的平方也就是字对齐了存储了
DW_STACK_START:.wordSTACK_BASE+STACK_SIZE-4
9.在board/tekkaman/tekkaman2440加入NANDFlash读函数文件,拷贝vivi中的nand_read.c文件到此文件夹即可:
#include<config.h>
#define__REGb(x)(*(volatileunsignedchar*)(x))
#define__REGi(x)(*(volatileunsignedint*)(x))
#defineNF_BASE0x4e000000
#defineNFCONF__REGi(NF_BASE+0x0)
#defineNFCONT__REGi(NF_BASE+0x4)
#defineNFCMD__REGb(NF_BASE+0x8)
#defineNFADDR__REGb(NF_BASE+0xC)
#defineNFDATA__REGb(NF_BASE+0x10)
#defineNFSTAT__REGb(NF_BASE+0x20)
//#defineGPDAT__REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT)
#defineNAND_CHIP_ENABLE(NFCONT&=~(1<<1))
允许片选
#defineNAND_CHIP_DISABLE(NFCONT|=(1<<1))禁止片选
#defineNAND_CLEAR_RB(NFSTAT|=(1<<2))
#defineNAND_DETECT_RB{while(!(NFSTAT&(1<<2)));}
#defineBUSY4
inlinevoidwait_idle(void){
while(!(NFSTAT&BUSY));等待是否nand忙于上次的操作
NFSTAT|=BUSY;
}
#defineNAND_SECTOR_SIZE512一页大小,我们的nand是这样分的
1设备(Device)=4096块(Blocks)
1块(Block)=32页/行(Pages/rows)
;页与行是相同的意思,叫法不一样
1(Page)=528字节(Bytes)=数据块大小(512Bytes)+OOB块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于NandFlash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过NandFlash命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过OOB部分的第六字节(即517字节)标志是否是坏块,OOB第六字节外,通常至少把OOB的前3个字节存放Nand
Flash硬件ECC码,这个我就不多说了,你要想真正看懂这些代码,必须了解nand的架构啊
NandFlash内置的指针指向各自的首地址。
#defineNAND_BLOCK_MASK(NAND_SECTOR_SIZE-1)
/*lowlevelnandreadfunction*/
int
nand_read_ll(unsignedchar*buf,unsignedlongstart_addr,intsize)
{
inti,j;
if((start_addr&NAND_BLOCK_MASK)||(size&NAND_BLOCK_MASK)){
return-1;/*invalidalignment*/检验开始地址和程序大小是否为512的整数
}
NAND_CHIP_ENABLE;允许NAND
for(i=start_addr;i<(start_addr+size);){直到读取整个uboot代码为止
/*READ0*/
NAND_CLEAR_RB;
NFCMD=0;
NandFlash片内寻址采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行
传送,并进行片内寻址。具体含义如下:
0-7位:字节在上半部、下半部及OOB内的偏移地址
8位:值为0代表对一页内前256个字节进行寻址
值为1代表对一页内后256个字节进行寻址
9-13位:对页进行寻址
14-25位:对块进行寻址
当传送地址时,从位0开始
/*WriteAddress*/
NFADDR=i&0xff;
NFADDR=(i>>9)&0xff;
NFADDR=(i>>17)&0xff;
NFADDR=(i>>25)&0xff;
NAND_DETECT_RB;
/*读出一页(512字节)*/
for(j=0;j<NAND_SECTOR_SIZE;j++,i++){
*buf=(NFDATA&0xff);
buf++;
}
}
NAND_CHIP_DISABLE;禁止片选
return0;
}
注意:s3c2410与s3c2440的NandFlash控制器寄存器不同,不能混用!!
10.修改board/tekkaman/tekkaman2440/Makefile文件
OBJS:=tekkaman2440.onand_read.oflash.o
11.修改include/configs/tekkaman2440.h文件,添加如下内容(注意:s3c2410与s3c2440的NandFlash控制器寄存器不同,不能混用!!):
......
/*
*NandflashBoot
*/
#defineCONFIG_S3C2440_NAND_BOOT1这处告诉从nand启动
#defineSTACK_BASE0x33f00000
#defineSTACK_SIZE0x8000
//#defineUBOOT_RAM_BASE0x33f80000
/*NANDFlashController*/
#defineNAND_CTL_BASE0x4E000000
#definebINT_CTL(Nb)__REG(INT_CTL_BASE+(Nb))
/*Offset*/
#defineoNFCONF0x00
#defineoNFCONT0x04
#defineoNFCMD0x08
#defineoNFADDR0x0c
#defineoNFDATA0x10
#defineoNFSTAT0x20
#defineoNFECC0x2c
/*GPIO*/
#defineGPIO_CTL_BASE0x56000000
#defineoGPIO_B0x10
#defineoGPIO_CON0x0/*R/W,Configuresthepinsoftheport*/
#defineoGPIO_DAT0x4/*R/W,Dataregisterforport*/
#defineoGPIO_UP0x8/*R/W,Pull-updisableregister*/
#endif/*__CONFIG_H*/
12.修改board/tekkaman/tekkaman2440/lowlevel_init.S文件
......
/*REFRESHparameter*/
#defineREFEN0x1/*Refreshenable*/
#defineTREFMD0x0/*CBR(CASbeforeRAS)/Autorefresh*/
#defineTrp0x2/*4clk*/
#defineTrc0x3/*7clk*/
#defineTchr0x2/*3clk*/
#defineREFCNT1012
......
注:参数的值按照SKY提供的对应文件的参数修改过来。
13.修改/board/tekkaman/tekkaman2440/tekkaman2440.c
因为SKY2440和smdk2410的GPIO连接有所不同,修改其对GPIO和PLL的配置(请参阅SKY2440的硬件说明、2440芯片手册和提供的uboot相对应的文件):这个函数我想不用我解释了吧!其实有些IO口在驱动里可以重新设置,但有时没有必要单单写一个IO驱动,例如串口的端口设置需要将他设置为rx或tx用那就可以直接改这了。
......
#elifFCLK_SPEED==1/*Fout=405MHz*/
//#defineM_MDIV0x5c
//#defineM_PDIV0x4
//#defineM_SDIV0x0
#defineM_MDIV0x7f
#defineM_PDIV0x2
#defineM_SDIV0x1
......
#elifUSB_CLOCK==1
//#defineU_M_MDIV0x48
//#defineU_M_PDIV0x3
#defineU_M_MDIV0x38
#defineU_M_PDIV0x2
#defineU_M_SDIV0x2
......
/*setuptheI/Oports*/
gpio->GPACON=0x007FFFFF;
//gpio->GPBCON=0x00044556;
gpio->GPBCON=0x00055556;
......
/*archnumberofS3C2440-Board*/
gd->bd->bi_arch_number=MACH_TYPE_S3C2440;
机码ID号必须和内核的机码对上,我们的是168,你找到他不要另加一个,因为我就犯过这个错误,他本身里面就有一个,你得覆盖他,要不然他还会认他以前的那个号,别忘了他的配置文件,是按照行读的,一旦读到匹配的参数就会跳出循环,导致你在后面加的根本就没起上作用。
/*adressofbootparameters*/
gd->bd->bi_boot_params=0x30000100;
这个是内核的参数的起始地址,我们的板子内核是在0x30008000地址处,在从0x30000000到0x30008000的32kb之间存放的是内核页表和内核的启动参数,
icache_enable();
dcache_enable();
gpio->GPBDAT=0x180;//tekkamanninja
//intboard_init(void)设置完成后,LED1和LED2会亮起!
return0;
}
14.为了实现NANDFlash的读写,再次修改/include/configs/tekkaman2440.h
(请格外注意:如果编译时报错,在Linux下用KWrite等有高亮显示的文本编辑器看看文件的注释是不是为注释应有的颜色(KWrite中为灰色),如果不是,则将注释删除。因为#define后面的注释被认为是程序的一部分。建议注释和#define分行写)
......
/*
*HighLevelConfigurationOptions
*(easytochange)
*/
#defineCONFIG_ARM920T1/*ThisisanARM920TCore*/
#defineCONFIG_S3C24401/*inaSAMSUNGS3C2440SoC*/
#defineCONFIG_tekkaman24401/*onaSAMSUNGtekkaman2440Board*/
......
/***********************************************************
*Commanddefinition
***********************************************************/
#defineCONFIG_COMMANDS\
(CONFIG_CMD_DFL|\
CFG_CMD_CACHE|\
CFG_CMD_NAND|\
CFG_CMD_NET|\
/*CFG_CMD_EEPROM|*/\
/*CFG_CMD_I2C|*/\
/*CFG_CMD_USB|*/\
CFG_CMD_PING|\
CFG_CMD_ENV|\
CFG_CMD_REGINFO|\
CFG_CMD_DATE|\
CFG_CMD_DHCP|\
CFG_CMD_ELF)
/*thismustbeincludedAFTERthedefinitionofCONFIG_COMMANDS(ifany)*/
#include<cmd_confdefs.h>
#defineCFG_LONGHELP
/*undeftosavememory*/
#defineCFG_PROMPT"[Tekkaman2440]#"
/*MonitorCommandPrompt*/
#defineCFG_CBSIZE256
/*ConsoleI/OBufferSize*/
......
#defineCFG_LOAD_ADDR0x30008000
/*defaultloadaddress*/
......
/*TimeoutforFlashWrite*/
#defineCFG_ENV_IS_IN_NAND1
#defineCFG_ENV_OFFSET0X20000
//#defineENV_IS_EMBEDDED1
#defineCFG_NAND_LEGACY定义后便调用我们的board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函数进行nand初始化
#defineCFG_ENV_SIZE0x10000
/*TotalSizeofEnvironmentSector*/
/*----------------------------------------------------------------------
*NANDflashsettings
*/
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
#defineCFG_NAND_BASE0x4E000000
/*NandFlash控制器在SFR区起始寄存器地址*/
#defineCFG_MAX_NAND_DEVICE1
/*支持的最在NandFlash数据*/
#defineSECTORSIZE512
/*1页的大小*/
#defineNAND_SECTOR_SIZESECTORSIZE
#defineNAND_BLOCK_MASK511
/*页掩码*/
#defineADDR_COLUMN1
/*一个字节的Column地址*/
#defineADDR_PAGE3
/*3字节的页块地址!!!!!*/
#defineADDR_COLUMN_PAGE4
/*总共4字节的页块地址!!!!!*/
#defineNAND_ChipID_UNKNOWN0x00
/*未知芯片的ID号*/
#defineNAND_MAX_FLOORS1
#defineNAND_MAX_CHIPS1
/*NandFlash命令层底层接口函数*/
这些前面基本已经提到/*NandFlash命令层底层接口函数*/
#defineWRITE_NAND_COMMAND(d,adr){rNFCMD=d;}
#defineWRITE_NAND_ADDRESS(d,adr){rNFADDR=d;}
#defineWRITE_NAND(d,adr){rNFDATA=d;}
#defineREAD_NAND(adr)(rNFDATA)
#defineNAND_WAIT_READY(nand){while(!(rNFSTAT&(1<<0)));}
#defineNAND_DISABLE_CE(nand){rNFCONT|=(1<<1);}
#defineNAND_ENABLE_CE(nand){rNFCONT&=~(1<<1);}
#defineWRITE_NAND_COMMANDW(d,adr)NF_CmdW(d)
/*thefollowingfunctionsareNOP'sbecauseS3C24X0handlesthisinhardware*/
/*下面一组操作对NandFlash无效*/
#defineNAND_CTL_CLRALE(nandptr)
#defineNAND_CTL_SETALE(nandptr)
#defineNAND_CTL_CLRCLE(nandptr)
#defineNAND_CTL_SETCLE(nandptr)
/*允许NandFlash写校验*/
#defineCONFIG_MTD_NAND_VERIFY_WRITE1
......
定义了各个寄存器
#definerNFCONF(*(volatileunsignedint*)0x4e000000)
#definerNFCONT(*(volatileunsignedint*)0x4e000004)
#definerNFCMD(*(volatileunsignedchar*)0x4e000008)
#definerNFADDR(*(volatileunsignedchar*)0x4e00000c)
#definerNFDATA(*(volatileunsignedchar*)0x4e000010)
#definerNFSTAT(*(volatileunsignedint*)0x4e000020)
#definerNFECC(*(volatileunsignedint*)0x4e00002c)
#endif/*__CONFIG_H*/
注:下面的这些定义是SKY提供的uboot参数,请按照这个参数把/include/configs/tekkaman2440.h修改过来
#defineCONFIG_BOOTDELAY1模式选折延时时间
#defineCONFIG_BOOTARGS"noinitrdroot=/dev/mtdblock2init=/linuxrcconsole=ttySAC0"
这里设置的都是传递给内核的参数,
initrd的最初的目的是为了把kernel的启动分成两个阶段:在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的方式放在initrd中,这样就在启动过程中可以从initrd所mount的根文件系统中装载需要的模块。这样的一个好处就是在保持kernel不变的情况下,通过修改initrd中的内容就可以灵活的支持不同的硬件。在启动完成的最后阶段,根文件系统可以重新mount到其他设备上。如果把需要的功能全都编译到内核中(非模块方式),只需要一个内核文件即可,我们这里就没有用到它,
root=/dev/mtdblock2是指定文件系统路径,在dev/的第二个分区了
init=/linuxrc他是个脚本,放在文件系统的根目录下,里面是文件系统启动时要挂载所要执行的准备console=ttySAC0用哪个串口
#defineCONFIG_ETHADDR0a:1b:2c:3d:4e:5f网卡mac地址I,全国独一个啊
#defineCONFIG_NETMASK255.255.255.0
#defineCONFIG_IPADDR192.168.1.6
#defineCONFIG_SERVERIP192.168.1.8
/*#defineCONFIG_BOOTFILE"elinos-lart"*/
#defineCONFIG_BOOTCOMMAND"nboot0x320000000
0x4C000;bootm0x32000000"0x4C000是变动的值
nbootInAddrdevFlAddr
InAddr:需要装载到的内存的地址。
FlAddr:在nandflash上uImage存放的地址
dev:设备号
需要提前设置环境变量,否则nboot不会调用bootm
Tekkaman2440#setenvautostartyes
0x4C000是内核在nand中起始的地址,看nand分区那就可以了解它的由来,在这里我们将内核搬运到0x32000000处,跳到此处执行什么呢?此时把压缩的内核进行解压,解压代码在内核的头部,解压到0x30008000处,这就是内核的解压后的地址。我们的内核最终是从这里开始执行的。
15.在个文件中添加“CONFIG_S3C2440”,使得原来s3c2410的代码可以编译进来。
(1)/include/common.h文件的第454行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_LH7A40X)||defined(CONFIG_S3C2440)
(2)/include/s3c24x0.h文件的第85、95、99、110、148、404行:
#ifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(3)/cpu/arm920t/s3c24x0/interrupts.c文件的第33行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第38行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(4)/cpu/arm920t/s3c24x0/serial.c文件的第22行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第26行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
voidserial_setbrg(void)
{
S3C24X0_UART*constuart=S3C24X0_GetBase_UART(UART_NR);
inti;
unsignedintreg=0;
/*valueiscalculatedso:(int)(PCLK/16./baudrate)-1*/
reg=get_PCLK()/(16*gd->baudrate)-1;
/*FIFOenable,Tx/RxFIFOclear*/
uart->UFCON=0x00;
uart->UMCON=0x0;
/*Normal,Noparity,1stop,8bit*/
uart->ULCON=0x3;
......
}
(5)/cpu/arm920t/s3c24x0/speed.c文件的第33行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第37行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
顺便修改源代码,以匹配s3c2440:
staticulongget_PLLCLK(intpllreg)
{
......
m=((r&0xFF000)>>12)+8;
p=((r&0x003F0)>>4)+2;
s=r&0x3;
//tekkaman
#ifdefined(CONFIG_S3C2440)
if(pllreg==MPLL)
return((CONFIG_SYS_CLK_FREQ*m*2)/(p<<s));
elseif(pllreg==UPLL)
#endif
//tekkaman
return((CONFIG_SYS_CLK_FREQ*m)/(p<<s));
}
......
/*returnFCLKfrequency*/
ulongget_FCLK(void)
{
return(get_PLLCLK(MPLL));
}
/*returnHCLKfrequency*/
ulongget_HCLK(void)
{
S3C24X0_CLOCK_POWER*constclk_power=S3C24X0_GetBase_CLOCK_POWER();
if(clk_power->CLKDIVN&0x6)
{
if((clk_power->CLKDIVN&0x6)==2)return(get_FCLK()/2);
if((clk_power->CLKDIVN&0x6)==6)return((clk_power->CAMDIVN&0x100)?get_FCLK()/6:get_FCLK()/3);
if((clk_power->CLKDIVN&0x6)==4)return((clk_power->CAMDIVN&0x200)?get_FCLK()/8:get_FCLK()/4);
return(get_FCLK());
}
else{
return(get_FCLK());
}
}
......
(6)/cpu/arm920t/s3c24x0/usb_ohci.c文件的第45行:
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(i2c的文件还没修改,因为没用到)
(7)/rtc/s3c24x0_rtc.c文件的第35行:
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
在个文件中添加“defined(CONFIG_tekkaman2440)”,使得原来SBC2410X的代码可以编译进来。
(1)/cpu/arm920t/s3c24x0/interrupts.c文件的第181行:
defined(CONFIG_VCMA9)||defined(CONFIG_tekkaman2440)
16.在include/linux/mtd/nand_ids.h的结构体nand_flash_ids加入
staticstructnand_flash_devnand_flash_ids[]={
......
{"SamsungKM29N16000",NAND_MFR_SAMSUNG,0x64,21,1,2,0x1000,0},
{"SamsungK9F1208U0B",NAND_MFR_SAMSUNG,0x76,26,0,3,0x4000,0},
{"Samsungunknown4Mb",NAND_MFR_SAMSUNG,0x6b,22,0,2,0x2000,0},
......
};
注:可参照SKY提供的uboot对应文件修改。
17.修改common/env_nand.c
......
[b]#ifdefCONFIG_INFERNO
#errorCONFIG_INFERNOnotsupportedyet
#endif
intnand_legacy_rw(structnand_chip*nand,intcmd,
size_tstart,size_tlen,
size_t*retlen,u_char*buf);
externstructnand_chipnand_dev_desc[CFG_MAX_NAND_DEVICE];
externintnand_legacy_erase(structnand_chip*nand,size_tofs,size_tlen,intclean);
/*infoforNANDchips,definedindrivers/nand/nand.c*/
externnand_info_tnand_info[CFG_MAX_NAND_DEVICE];
......
env将从永久性存储介质中搬到RAM里面,以后对env的操作,比如修改环境变量的值,删除环境变量的值都是对这个
env在RAM中的拷贝进行操作,由于RAM的特性,下次启动时所做的修改将全部消失,u-boot提供了将env写回永久性存储介质的命令支持
:saveenv,不同版本的env(nandflash,flash…)实现方式不同,以NandFlash的实现(未定义CFG_ENV_OFFSET_REDUND)为例,见下面的saveenv函数了,Nand
Flash的saveenv命令实现很简单,调用nand_erase和nand_write进行Nand
Flash的erase,write。nand_write/erase使用的是u-boot的nand驱动框架,我在做开发的过程中使用的是nand_legacy驱动,所以可以把nand_erase和nand_write改成nand_legacy_erase和nand_legacy_rw就可实现nand_legacy驱动的保存环境变量版本,这就是为什么注释掉nand_erase和
nand_write的原因了,哈哈,其实我也是才知道的,以前这块也有点糊涂[/b]
#else/*!CFG_ENV_OFFSET_REDUND*/完成对环境变量的存储
[b]intsaveenv(void)
{
ulongtotal;
intret=0;
puts("ErasingNand...");[/b]
UBOOT对NAND进行读写操作调用的函数在drivers/nand_legacy/nand_legacy。C函数里面的nand_legacy_erase先擦除要写的nand区,再调用nand_legacy_rw进行读写,不是调用nand_erase和
nand_write
//if(nand_erase(&nand_info[0],CFG_ENV_OFFSET,CFG_ENV_SIZE))
[b]if(nand_legacy_erase(nand_dev_desc+0,CFG_ENV_OFFSET,CFG_ENV_SIZE,0))
return1;
puts("WritingtoNand...");
total=CFG_ENV_SIZE;
//ret=nand_write(&nand_info[0],CFG_ENV_OFFSET,&total,(u_char*)env_ptr);[/b]
ret=nand_legacy_rw(nand_dev_desc+0,
0x00|0x02,CFG_ENV_OFFSET,CFG_ENV_SIZE,
&total,(u_char*)env_ptr);
if(ret||total!=CFG_ENV_SIZE)
return1;
puts("done\n");
returnret;
......
#else/*!CFG_ENV_OFFSET_REDUND*/
/*
*ThelegacyNANDcodesavedtheenvironmentinthefirstNANDdevicei.e.,
*nand_dev_desc+0.ThisisalsothebehaviourusingthenewNANDcode.
*/
voidenv_relocate_spec(void)完成环境变量的重新定位,把它从nand搬运到sdram里面
{
#if!defined(ENV_IS_EMBEDDED)env是否存在于u-bootTEXT段中
ulongtotal;
intret;
total=CFG_ENV_SIZE;env块的大小
u-boot在启动的时候会将存储在永久性存储介质中的env重新定位到RAM中,这样可以快速访问,同时可以通过saveenv将
RAM中的env
保存到永久性存储介质中。实际上还需要几个宏来控制u-boot对环境变量的处理。CFG_ENV_OFFSET:env块在
Flash中偏移地址。env_ptr:最终完成将环境变量搬移到内存地址。
//ret=nand_read(&nand_info[0],CFG_ENV_OFFSET,&total,(u_char*)env_ptr);
ret=nand_legacy_rw(nand_dev_desc+0,0x01|0x02,CFG_ENV_OFFSET,CFG_ENV_SIZE,&total,(u_char*)env_ptr);
......
上面的代码很清楚的表明了env_relocate_spec的意图,调用nand_read将环境变量从CFG_ENV_OFFSET处读出,环境变量的大小为
CFG_ENV_SIZE注意CFG_ENV_OFFSET和CFG_ENV_SIZE要和Nand
Flash的块/页边界对齐。读出数据后再调用crc32对env_ptr->data进行校验并与保存在
env_ptr->crc的校验码对比,看数据是否出错,从这里也可以看出在系统第一次启动时,NandFlash里面没有存储任何环境变量,crc校验肯定回出错,当我们保存环境变量后,接下来再启动板子u-boot就不会再报crc32出错了。
18.在/board/tekkaman/tekkaman2440/tekkaman2440.c文件的末尾添加对NandFlash的初始化函数(在后面Nand
Flash的操作都要用到)
u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand
flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用
drivers/nand/nand.c中的nand_init();否则调用自己在board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函数。这里我选择第二种方式。
这些代码很简单的都是操作他的物理地址,对照数据手册就会很清楚他的用意,它主要就是完成对nand的初始化,设置好nand的寄存器。为了便于大家理解他,我把我的参考资料贴在这,看了便知道了!!!!!
Nandflash主要内设命令详细介绍
NandFlash命令执行是通过将命令字送到NandFlash控制器的命令寄存器来执行。
NandFlash的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周
期将要执行的动作。
主要命令有:Read1、Read2、ReadID、Reset、Page
Program、BlockErase、ReadStatus。
详细介绍如下:
1.Read1:
功能:表示将要读取Nandflash存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。
命令代码:00h
2.Read2:
功能:表示将要读取Nandflash存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。
命令代码:01h
3.ReadID:
功能:读取Nandflash芯片的ID号
命令代码:90h
4.Reset:
功能:重启芯片。
命令代码:FFh
5.PageProgram:
功能:对页进行编程命令,用于写操作。
命令代码:首先写入00h(A区)/01h(B区)/05h(C区),表示写入那个区;再写入80h开始编程模式(写入模式),接
下来写入地址和数据;最后写入10h表示编程结束.
6.BlockErase
功能:块擦除命令。
命令代码:首先写入60h进入擦写模式,然后输入块地址;接下来写入D0h,表示擦写结束.
7.ReadStatus
功能:读取内部状态寄存器值命令。
命令代码:70h
NandFlash控制器工作原理
对NandFlash存储芯片进行操作,必须通过NandFlash控制器的专用寄存器才能完成。所以,不能对Nand
Flash进行总线操作。而NandFlash的写操作也必须块方式进行。对NandFlash的读操作可以按字节读取。
NandFlash控制器特性
1.支持对NandFlash芯片的读、检验、编程控制
2.如果支持从NandFlash启动,在每次重启后自动将前Nand
Flash的前4KB数据搬运到ARM的内部RAM中
3.支持ECC校验
NandFlash控制器工作原理
NandFlash控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将Nand
Flash芯片的内设命令写到其特殊功能寄存器中,从而实现对Nandflash芯片读、检验和编程控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。
Nandflash控制器中特殊功能寄存器详细介绍
1.配置寄存器(NFCONF)
功能:用于对NandFlash控制器的配置状态进行控制。
在地址空间中地址:0x4E000000,其中:
Bit15:NandFlash控制器使能位,置0代表禁止Nand
Flash控制器,置1代表激活NandFlash控制器;
要想访问NandFlash芯片上存储空间,必须激活NandFlash控制器。在复位后该位自动置0,因此在初始化时
必须将该位置为1。
Bit12:初始化ECC位,置1为初始化ECC;置0为不初始化ECC。
Bit11:NandFlash芯片存储空间使能位,置0代表可以对存储空间进行操作;置1代表禁止对存储空
间进行操作。在复位后,该位自动为1。
Bit10-8:TACLS位。根据此设定CLE&ALE的周期。TACLS的值范围在0-7之间。
Bit6-4、2-0分别为:TWRPH0、TWRPH1位。设定写操作的访问周期。其值在0-7之间。
2.命令寄存器(NFCMD)
功能:用于存放Nandflash芯片内设的操作命令。
在地址空间中地址:0x4E000004,其中:
Bit0-7:存放具体Nandflash芯片内设的命令值。其余位保留以后用。
3.地址寄存器(NFADDR)
功能:用于存放用于对Nandflash芯片存储单元寻址的地址值。
在地址空间中地址:0x4E000008,其中:
Bit0-7:用于存放地址值。因为本款Nandflash芯片只有I/O0-7的地址/数据复用引脚且地址是四周
期每次8位送入的,所以这里只用到8位。其余位保留待用。
4.数据寄存器(NFDATA)
功能:Nandflash芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入Nandflash
存储空间的值也是放到该寄存器。
在地址空间中地址:0x4E00000C,其中:
Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。
5.状态寄存器(NFSTAT)
功能:用于检测Nandflash芯片上次对其存储空间的操作是否完成。
在地址空间中地址:0x4E000010,其中:
Bit0:置0表示Nandflash芯片正忙于上次对存储空间的操作;置1表示Nand
flash芯片准备好接收新
的对存储空间操作的请求。
6.ECC校验寄存器(NFECC)
功能:ECC校验寄存器
在地址空间中地址:0x4E000014,其中:
Bit0Bit7:
ECC0
Bit8Bit15:
ECC1
Bit16Bit23:
ECC2
操作的函数实现
1.发送命令
#defineNF_CMD(cmd){rNFCMD=cmd;}
2.写入地址
#defineNF_ADDR(addr){rNFADDR=addr;}
3.NandFlash芯片选中
#defineNF_nFCE_L(){rNFCONF&=~(1<<11);}
4.NandFlash芯片不选中
#defineNF_nFCE_H(){rNFCONF|=(1<<11);}
5.初始化ECC
#defineNF_RSTECC(){rNFCONF|=(1<<12);}
6.读数据
#defineNF_RDDATA()(rNFDATA)
7.写数据
#defineNF_WRDATA(data){rNFDATA=data;}
8.获取NandFlash芯片状态
#defineNF_WAITRB(){while(!(rNFSTAT&(1<<0)));}
0/假:表示NandFlash芯片忙状态
1/真:表示NandFlash已经准备好
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
typedefenum{
NFCE_LOW,
NFCE_HIGH
}NFCE_STATE;
staticinlinevoidNF_Conf(u16conf)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONF=conf;
}
staticinlinevoidNF_Cont(u16cont)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONT=cont;
}
staticinlinevoidNF_Cmd(u8cmd)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCMD=cmd;
}
staticinlinevoidNF_CmdW(u8cmd)
{
NF_Cmd(cmd);
udelay(1);
}
staticinlinevoidNF_Addr(u8addr)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFADDR=addr;
}
staticinlinevoidNF_SetCE(NFCE_STATEs)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
switch(s){
caseNFCE_LOW:
nand->NFCONT&=~(1<<1);
break;
caseNFCE_HIGH:
nand->NFCONT|=(1<<1);
break;
}
}
staticinlinevoidNF_WaitRB(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
while(!(nand->NFSTAT&(1<<0)));
}
staticinlinevoidNF_Write(u8data)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFDATA=data;
}
staticinlineu8NF_Read(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
return(nand->NFDATA);
}
staticinlinevoidNF_Init_ECC(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONT|=(1<<4);
}
staticinlineu32NF_Read_ECC(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
return(nand->NFECC);
}
#endif
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
externulongnand_probe(ulongphysadr);
staticinlinevoidNF_Reset(void)
{
inti;
NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF);/*resetcommand*/
for(i=0;i<10;i++);/*tWB=100ns.*/
NF_WaitRB();/*wait200~500us;*/
NF_SetCE(NFCE_HIGH);
}
staticinlinevoidNF_Init(void)
{
#if0/*alittlebittoooptimistic*/
#defineTACLS0
#defineTWRPH03
#defineTWRPH10
#else
#defineTACLS0
#defineTWRPH04
#defineTWRPH12
#endif
NF_Conf((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
NF_Cont((1<<6)|(1<<4)|(1<<1)|(1<<0));
/*nand->NFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);*/
/*1111,1xxx,rxxx,rxxx*/
/*En512B4stepECCRnFCE=HtACLStWRPH0tWRPH1*/
NF_Reset();
}
void
nand_init(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
NF_Init();
#ifdefDEBUG
printf("NANDflashprobingat0x%.8lX\n",(ulong)nand);
#endif
printf("%4luMB\n",nand_probe((ulong)nand)>>20);
}
#endif
19.在/include/s3c24x0.h中加入2440的NANDFLASH寄存器定义和CAMDIVN定义:
......
typedefstruct{
S3C24X0_REG32LOCKTIME;
S3C24X0_REG32MPLLCON;
S3C24X0_REG32UPLLCON;
S3C24X0_REG32CLKCON;
S3C24X0_REG32CLKSLOW;
S3C24X0_REG32CLKDIVN;
S3C24X0_REG32CAMDIVN;
}/*__attribute__((__packed__))*/S3C24X0_CLOCK_POWER;
......
#ifdefined(CONFIG_S3C2410)
/*NANDFLASH(seeS3C2410manualchapter6)*/
typedefstruct{
S3C24X0_REG32NFCONF;
S3C24X0_REG32NFCMD;
S3C24X0_REG32NFADDR;
S3C24X0_REG32NFDATA;
S3C24X0_REG32NFSTAT;
S3C24X0_REG32NFECC;
}/*__attribute__((__packed__))*/S3C2410_NAND;
#endif
#ifdefined(CONFIG_S3C2440)
/*NANDFLASH(seeS3C2440manualchapter6)*/
typedefstruct{
S3C24X0_REG32NFCONF;
S3C24X0_REG32NFCONT;
S3C24X0_REG32NFCMD;
S3C24X0_REG32NFADDR;
S3C24X0_REG32NFDATA;
S3C24X0_REG32NFMECC0;
S3C24X0_REG32NFMECC1;
S3C24X0_REG32NFSECC;
S3C24X0_REG32NFSTAT;
S3C24X0_REG32NFESTAT0;
S3C24X0_REG32NFESTAT1;
S3C24X0_REG32NFECC;
}/*__attribute__((__packed__))*/S3C2410_NAND;
#endif
20.移植DM9000网卡
在/include/configs/tekkaman2440.h文件中修改添加对DM9000的支持,屏蔽CS8900:
/*
*Hardwaredrivers
*/
//#defineCONFIG_DRIVER_CS89001/*wehaveaCS8900on-board*/
//#defineCS8900_BASE0x19000300
//#defineCS8900_BUS161/*theLinuxdriverdoesaccessesasshorts*/
#defineCONFIG_DRIVER_DM90001
#defineCONFIG_DM9000_BASE0x20000300
#defineDM9000_IOCONFIG_DM9000_BASE
#defineDM9000_DATA(CONFIG_DM9000_BASE+4)
#defineCONFIG_DM9000_USE_16BIT
在这里#defineCONFIG_DM9000_BASE的定义最为重要。不同的板子只要修改这个参数即可。
我是按照SKY提供的Uboot代码的对应文件的参数修改的。
修正BUG(修改/drivers/dm9000.c文件)
(1)网卡MAC地址错误的解决方法:
/*Initilizedm9000board
*/
int
eth_init(bd_t*bd)
{
......
/*SetNodeaddress*/
/*for(i=0;i<6;i++)
((u16*)bd->bi_enetaddr)[i]=read_srom_word(i);
*/
//tekkamanninja
char*tmp=getenv("ethaddr");
char*end;
for(i=0;i<6;i++){
bd->bi_enetaddr[i]=tmp?simple_strtoul(tmp,&end,16):0;
if(tmp)
tmp=(*end)?end+1:end;
}
//tekkamanninja
printf("MAC:%02x:%02x:%02x:%02x:%02x:%02x\n",bd->bi_enetaddr[0],
bd->bi_enetaddr[1],bd->bi_enetaddr[2],bd->bi_enetaddr[3],
bd->bi_enetaddr[4],bd->bi_enetaddr[5]);
......
红色的字符是要做的修改:功能是屏蔽原有获取MAC地址的语句,替换成从U-Boot的参数区读取数据并存到bd->bi_enetaddr[i]中。
(2)“couldnotestablishlink”提示和慢响应的解决方法:
/*Initilizedm9000board
*/
int
eth_init(bd_t*bd)
{
......
DM9000_iow(DM9000_RCR,RCR_DIS_LONG|RCR_DIS_CRC|RCR_RXEN);/*RXenable*/
DM9000_iow(DM9000_IMR,IMR_PAR);/*EnableTX/RXinterruptmask*/
#if0
i=0;
while(!(phy_read(1)&0x20)){/*autonegationcompletebit*/
udelay(1000);
i++;
if(i==10000){
printf("couldnotestablishlink\n");
return0;
}
printf("link=%d\n",i);
}
/*seewhatwe'vegot*/
lnk=phy_read(17)>>12;
printf("operatingat");
switch(lnk){
case1:
printf("10Mhalfduplex");
break;
case2:
printf("10Mfullduplex");
break;
case4:
printf("100Mhalfduplex");
break;
case8:
printf("100Mfullduplex");
break;
default:
printf("unknown:%d",lnk);
break;
}
printf("mode\n");
#endif
return0;
}
红色的字符是要做的修改:功能是屏蔽无用的语句。其实被屏蔽的语句是MII接口用的,放在这显然是错误的,无端的浪费了10秒钟。
21.编译修改好的代码:
maketekkaman2440_config;make;
在uboot的根目录下你就可以看到uboot的镜像文件了,烧到flash中就可以了。
以上生成的uboot镜像,网络似乎不大行,ping主机ping不通。SKY提供的uboot也是一样的问题,ping不通。
还有一点需要说明的是:UBOOT在启动内核的时候,还需要识别ID,需要UBOOT的ID和内核的ID相同,这个可以通过uboot的bdinfo命令看到UBOOT里设置的ID。SKY提供的UBOOT的ID和内核的ID是经过修改的。所以前面生成的UBOOT镜像会启动不了SKY提供的内核。
你打开SKY提供的UBOOT代码,include\asm-arm\mach-types.h,你将会发现第183行和377行的改动。
所以如果你想用前面生成的UBOOT启动SKY提供的内核的话,那么include\asm-arm\mach-types.h的377行也要修改成#define
MACH_TYPE_S3C2440168,这样就可以启动了。
现在的uboot只有一些基本的功能,最近从网上(http://www.100ask.net/showtopic-544.aspx)弄了个uboot1.1.6,支持S3C24x0/yaffs/USB/CS8900/DM9000/OpenJTAG/Nor,Nand启动的u-boot,回头再试一试。
二、linux2.6.24.4移植
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址http://blog.chinaunix.net/u1/34474/index.html
另外也参考了http://blog.csdn.net/yang_dk/archive/2008/04/17/2300712.aspx和
http://blog.chinaunix.net/u2/63560/showart_511924.html博客的内容。
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.解压linux-2.6.24.4,和arm-linux-gcc-3.4.1
2.进入linux-2.6.24.4根目录,修改makefile文件
vimakefile
第193行改为:
ARCH=arm
CROSS_COMPILE=/usr/local/arm/3.4.1/bin/arm-linux-告诉交叉编译器的路径
CROSS_COMPILE根据你自己arm-linux-gcc-3.4.1安装的路径设置.
3.修改arch/arm/plat-s3c24xx/common-smdk.c文件,修改NAND_FLASH分区信息和硬件信息.
根据SKY的板子,我设置如下:
这个结构体是设置nand的分区情况的
staticstructmtd_partitionsmdk_default_nand_part[]={
[0]={
.name=“UBOOT”,
.size=SZ_64K*4,//0x0~0x40000,256K
.offset=0,
},
[1]={
.name=“kernel2.6.24.4”,
.size=SZ_2M,//0x4c000~0x200000+0x4c000,2M
.offset=SZ_64K*4+SZ_16K*3,
},
[2]={
.name=“rootfs”,
.size=SZ_64K*987,//0x0024c000~0x03db0000+0x0024c000
.offset=SZ_2M+SZ_64K*4+SZ_16K*3,
}
};
另外修改smdk_nand_info,如下:
staticstructs3c2410_platform_nandsmdk_nand_info={
.tacls=0,
.twrph0=30,
.twrph1=0,
.nr_sets=ARRAY_SIZE(smdk_nand_sets),应该为初始化nand的设置结构体
.sets=smdk_nand_sets,应该为初始化nand的设置结构体
};
4.修改时钟:arch/arm/mach-s3c2440/mach-smdk2440.c
staticvoid__initsmdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000);外部的晶振的频率是12MHz
s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));
}
开发板的mapio的初始化。首先我来讲解一下我对io内存映射的理解,io内存是具有物理地址的
关于IO与内存空间:
在X86处理器中存在着I/O空间的概念,I/O空间是相对于内存空间而言的,它通过特定的指令in、out来访问。端口号标识了外设的寄存器地址。Intel语法的in、out指令格式为:
IN累加器,{端口号│DX}
OUT{端口号│DX},累加器
目前,大多数嵌入式微控制器如ARM、PowerPC等中并不提供I/O空间,而仅存在内存空间。内存空间可以直接通过地址、指针来访问,程序和程序运行中使用的变量和其他数据都存在于内存空间中。
即便是在X86处理器中,虽然提供了I/O空间,如果由我们自己设计电路板,外设仍然可以只挂接在内存空间。此时,CPU可以像访问一个内存单元那样访问外设I/O端口,而不需要设立专门的I/O指令。因此,内存空间是必须的,而I/O空间是可选的。
因此你现在应该明白了大多数嵌入式处理器为什么都采用io内存映射,这样会使操作io口像操作内存一样,并不需要特殊的指令,我们将io的物理地址也就是数据手册上写的寄存器的地址将他进行内存映射,这就是所谓的io内存映射,映射后的地址当然是虚拟地址了,这样我们操作这个虚拟地址就等于操作io。
在Linux设备驱动中,宜使用Linux内核提供的函数来访问定位于I/O空间的端口,这些函数包括:
·读写字节端口(8位宽)
unsignedinb(unsignedport);
voidoutb(unsignedcharbyte,unsignedport);
·读写字端口(16位宽)
unsignedinw(unsignedport);
voidoutw(unsignedshortword,unsignedport);
·读写长字端口(32位宽)
unsignedinl(unsignedport);
voidoutl(unsignedlongword,unsignedport);
·读写一串字节
voidinsb(unsignedport,void*addr,unsignedlongcount);
voidoutsb(unsignedport,void*addr,unsignedlongcount);
·insb()从端口port开始读count个字节端口,并将读取结果写入addr指向的内存;outsb()将addr指向的内存的count个字节连续地写入port开始的端口。
·读写一串字
voidinsw(unsignedport,void*addr,unsignedlongcount);
voidoutsw(unsignedport,void*addr,unsignedlongcount);
·读写一串长字
voidinsl(unsignedport,void*addr,unsignedlongcount);
voidoutsl(unsignedport,void*addr,unsignedlongcount);
上述各函数中I/O端口号port的类型高度依赖于具体的硬件平台,因此,只是写出了unsigned。
(3)readb和writeb:
在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是工程师宜使用Linux内核的如下一组函数来完成设备内存映射的虚拟地址的读写,这些函数包括:
·读I/O内存
unsignedintioread8(void*addr);
unsignedintioread16(void*addr);
unsignedintioread32(void*addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
unsignedreadb(address);
unsignedreadw(address);
unsignedreadl(address);
·写I/O内存
voidiowrite8(u8value,void*addr);
voidiowrite16(u16value,void*addr);
voidiowrite32(u32value,void*addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
voidwriteb(unsignedvalue,address);
voidwritew(unsignedvalue,address);
voidwritel(unsignedvalue,address);
(4)把I/O端口映射到“内存空间”:
void*ioport_map(unsignedlongport,unsignedintcount);
通过这个函数,可以把port开始的count个连续的I/O端口重映射为一段“内存空间”。然后就可以在其返回的地址上像访问I/O内存一样访问这些I/O端口。当不再需要这种映射时,需要调用下面的函数来撤消:
voidioport_unmap(void*addr);
实际上,分析ioport_map()的源代码可发现,所谓的映射到内存空间行为实际上是给开发人员制造的一个“假象”,并没有映射到内核虚拟地址,仅仅是为了让工程师可使用统一的I/O内存访问接口访问I/O端口。
在S3C2410的Linux里面,全部都会做phy->virt的映射。映射方式中的一种是静态映射,ioremap是动态映射。在静态映射之后,仍然可以通过ioremap动态映射,也就是一个IO物理地址可以映射到多个虚拟地址。
其实所谓的内存映射,也不要想的那么复杂,你可以看看上面的从物理地址到虚拟地址的映射,其实就是一个地址变化。建立一个对应关系,那你会纳闷为什么建立这个对应关系,首先你要知道我们这些操作都是在内核里的,内核操作的也是虚拟地址,我们这块用的虚拟地址和物理地址只存在简单的线性关系,在这里我就不多解释了,嘿嘿,懒着写,记住google是你的最好老师!!!
smdk2440_map_io函数中会调用:
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
而开发板相关的内存映射在smdk2440_iodesc,有ISA,声卡,网卡等。
定义如下:
staticstructmap_descsmdk2440_iodesc[]__initdata={
/*ISAIOSpacemap(memoryspaceselectedbyA24)*/
{(u32)S3C24XX_VA_ISA_WORD,S3C2410_CS2,SZ_16M,MT_DEVICE},
{(u32)S3C24XX_VA_ISA_BYTE,S3C2410_CS2,SZ_16M,MT_DEVICE},
};
2.s3c24xx_init_io函数会调用:iotable_init(s3c_iodesc,ARRAY_SIZE(s3c_iodesc));
而s3c_iodesc定义如下:
/*minimalIOmapping*/
staticstructmap_descs3c_iodesc[]__initdata={
IODESC_ENT(GPIO),
IODESC_ENT(IRQ),
IODESC_ENT(MEMCTRL),
IODESC_ENT(UART)
};
这个部分是系统启动必须的映射。
后续会调用(cpu->map_io)(mach_desc,size);来完成其他映射。
这个函数会调用iotable_init(s3c2440_iodesc,ARRAY_SIZE(s3c2440_iodesc));
定义如下:
staticstructmap_descs3c2440_iodesc[]__initdata={
IODESC_ENT(USBHOST),
IODESC_ENT(USBDEV),
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
综合上述发现,如果一个新加驱动,首先要看是否完成了IO映射,如果没有的话,就在开发板部分加入。
5.修改nandflash的校验方式,去掉ECC校验
在drivers/mtd/nand/s3c2410.c的第699行
将chip->ecc.mode=NAND_ECC_SOFT;
改为chip->ecc.mode=NAND_ECC_NONE;
网上有的blog上不用去掉也可以,编译不会出错,但是我没有试验过,我是把ECC校验去掉的了.(经测试,这个不用改也可以)
6.增加Yaffs2文件系统的支持
下载Yaffs2:http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/
解压yaffs2并将其加入linux内核(打补丁的方式):
cdyaffs2
./patch-ker.shc/home/dk/myboard/linux-2.6.24.4/
./patch-ker.shc后面跟的是你linux解压所在的路径.打完包后,在内核fs文件夹下将会多了yaffs文件夹,同事makefile文件也自动修改了.
7.为了内核支持devfs以及在启动是并在/sbin/init运行之前自动挂载/dev为devfs文件系统,编辑fs/Kconfig:
在906行menu“Pseudofilesystems”下面添加如下代码:
configDEVFS_FS
bool“/devfilesystemsupport(OBSOLETE)”
defaulty
configDEVFS_MOUNT
bool“Automaticallymountatboot”
defaulty
dependsonDEVFS_FS
有的blog说不需要增加这一段,因为2.6.24.4已经把devfs的相关代码删除了,即使添加了也没有用.我在移植内核的时候还是加上了这段代码,不加的编译情况还没有试.(经测试,这段现在不加也可以)
8.复制编译配置文件到2.6.24.4内核根目录下.
cparch/arm/configs/s3c2410_defconfig.config
将config覆盖掉,他是内核的配置,我们在图形界面下配置内核后的最终保存结果就是变成了config文件,我们用s3c2410_defconfig的配置,是因为他接近我们的2440的配置,再此基础上修改内核配置。
9.编译内核选项:makemenuconfig
[*]Enableloadablemodulesupport--->
[*]Moduleunloading
[*]Automatickernelmoduleloading
选择这两个,剩下的可以去掉
SystemType---->
[*]S3C2410DMAsupport
[*]SupportARM920Tprocessor
S3C2410Machines--->
[*]SMDK2410/A9M2410
S3C2440Machines--->
[*]SMDK2440
[*]SMDK2440withS3C2440CPUmodule
SystemType这部分,只选这些,其他可以全部去掉。另外,网上一些帖子都说只选上SMDK2440就可以了,其他的都去掉,我没有试,不知道行不行.(经过测试,必须SMDK2410的选项)
Bootoption----->
修改启动参数为:
noinitrdroot=/dev/mtdblock2init=/linuxrcconsole=ttySAC0,115200
可能根据个人板子的设置会不一样,我的是从NandFlash中加载文件系统,其中mtdblock2是存放我的Linux文件系统的分区。不过,在bootloader可以传递内核参数的情况下这个设置是无效的。
Userspacebinaryformats--->
<>Kernelsupportfora.outandECOFFbinaries
(去除该选项,a.out和ECOFF是两种可执行文件的格式,在ARM-Linux下一般都用ELF,所以这两种基本用不上。)
DeviceDrivers--->
<*>MemoryTechnologyDevice(MTD)support--->
[*]MTDpartitioningsupport
<*>NANDDeviceSupport--->
<*>NANDFlashsupportforS3C2410/S3C2440SoC
[]S3C2410NANDHardwareECC//这个要去掉
[*]Networkdevicesupport--->
[*]Ethernet(10or100Mbit)--->
<*>DM9000support
<*>RealTimeClock--->
“N”掉
[]SetsystemtimefromRTConstartupandresume
去掉红字的两个部分,黑子部分选上,其他的选择默认就可以了。
Filesystems-->
<>Secondextendedfssupport#去除对ext2的支持
<>Ext3journallingfilesystemsupport#去除对ext3的支持
<*>Kernelautomountersupport
<*>Kernelautomounterversion4support(alsosupportsv3)
<*>FilesysteminUserspacesupport
Pseudofilesystems-->
[*]Virtualmemoryfilesystemsupport(formershmfs)
<*>Userspace-drivenconfigurationfilesystem(EXPERIMENTAL)
Miscellaneousfilesystems-->
<*>YAFFS2filesystemsupport
“N”掉[]Autoselectyaffs2format和
[]CacheshortnamesinRAM,因为这是给每页大于1024B的NANDFlash设计的
<*>JournallingFlashFileSystemv2(JFFS2)support
(0)JFFS2debuggingverbosity(0=quiet,2=noisy)
[*]JFFS2write-bufferingsupport
[]JFFS2summarysupport(EXPERIMENTAL)
[]JFFS2XATTRsupport(EXPERIMENTAL)
[*]AdvancedcompressionoptionsforJFFS2
[*]JFFS2ZLIBcompressionsupport
[*]JFFS2RTIMEcompressionsupport
[*]JFFS2RUBINcompressionsupport
JFFS2defaultcompressionmode(priority)--->
NetworkFileSystems-->
<*>NFSfilesystemsupport
--以下最好选上,因为在挂载NFS时可能出现protocol不支持的情况--
[*]ProvideNFSv3clientsupport
[*]ProvideclientsupportfortheNFSv3ACLprotocolextension
[*]ProvideNFSv4clientsupport(EXPERIMENTAL)
[*]AllowdirectI/OonNFSfiles
-------------------------------------------------------------------------
<*>NFSserversupport
[*]ProvideNFSv3serversupport
[*]ProvideserversupportfortheNFSv3ACLprotocolextension
[*]ProvideNFSv4serversupport(EXPERIMENTAL)
---ProvideNFSserveroverTCPsupport
[*]RootfilesystemonNFS
注:我后面用到的根文件系统是cramfs或yaffs.
10.ok,先编译一下内核,makezIamge.编译完在arch/arm/boot下将会有一个zImage文件.
11.生成uboot用的uImage.
Uboot使用的镜像和zImage有点区别,具体可以网上搜一下.
先把Uboot编译后生成的tools/mkImage文件copy到主机的/bin下,然后进入到linux-2.6.24.4内核的根目录下,在执行一下makeuImage命令,等上一会就会在arch/arm/boot下将会有一个uImage文件.
最后下载到开发板上试试吧.目前的内核网卡、液晶等驱动都还没有移植。
需要说明的,这个新的内核和SKY提供的yaffs文件不匹配,相比于以前的2.6.13之类,内核中修改了oob的使用,主要就是ECC较验码的位置。但是,yaffs那帮人没有同步修改mkyaffsimg,这需要自己做。好在我在网上(http://www.100ask.net/showtopic-177.aspx)找到了mkyaffsimg的补丁.
另外一个问题就是uboot移植中说到的ID不匹配的问题,如果你用的uboot是SKY提供的,那么需要将arch\arm\tools\mach-types文件中的一行s3c2440ARCH_S3C2440
S3C2440362
改成s3c2440ARCH_S3C2440S3C2440168即可.
三、根文件系统的设计(带用户登录)
移植环境:VMware5.5.2+redhat9(非root登录,需要切换到root下执行的另外指出)
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
Busybox:busybox-1.9.2.tar.bz2(http://busybox.net/downloads/)
Tinylogin:tinylogin-snapshot.tar.bz2(http://tinylogin.busybox.net/)
Cramfs制作工具:cramfs-1.1.tar.gz(http://sourceforge.net/projects/cramfs/)
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址http://blog.chinaunix.net/u1/34474/index.html
其中参照http://blog.chinaunix.net/u1/34474/showart_485837.html做的。
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.创建根文件系统的基本目录结构。
我把这个过程做成了shell脚本(文件名为mkroot),很方便!
#!/bin/sh
echo"creatintrootfsdir......"
mkdirrootfs
cdrootfs
echo"makingdir:bindevetclibprocsbinsysusr"
mkdirbindevetclibprocsbinsysusr#必备的8个目录
mkdirusr/binusr/libusr/sbinlib/modules
#Don'tusemknod,unlessyourunthisScriptasroot
#mknod-m600dev/consolec51
#mknod-m666dev/nullc13
echo"makingdir:mnttmpvar"
mkdirmnttmpvar
chmod1777tmp
mkdirmnt/etcmnt/jffs2mnt/yaffsmnt/datamnt/temp
mkdirvar/libvar/lockvar/logvar/runvar/tmp
chmod1777var/tmp
echo"makingdir:homerootboot"
mkdirhomerootboot
echo"done"
有一点需要注意,在windows下的回车和linux下的回车不一样,如果你是在windows下把这个脚本编辑好的,那么在linux下运行会有点问题。
在你想要建立根文件系统的地方,运行:
./mkroot
2.进入到dev文件夹创建两个设备文件,需要用root登录创建
Mknod–m600consolec51;mknod–m666nullc13;
3.配置、编译、安装busybox-1.9.2
(1)解压busybox-1.9.2
(2)修改makefile文件(在174行附近)
(3)配置busybox:makemenuconfig
在原有的基础上修改如下:
BusyboxSettings--->
InstallationOptions--->
[*]Don'tuse/usr
(前面创建的rootfs所在路径)BusyBoxinstallationprefix
BusyboxLibraryTuning--->
[*]Supportfor/etc/networks
[*]Additionaleditingkeys
[*]vi-stylelineeditingcommands
(15)Historysize
[*]Historysaving
[*]Tabcompletion
[*]Usernamecompletion
[*]Fancyshellprompts
Login/PasswordManagementUtilities--->选项全部N掉,后面单独使用TinyLogin。(因为集成的好像不是很好用,我自己的经验是这样)
LinuxModuleUtilities--->
Supportversion2.2.xto2.4.xLinuxkernels
Shells--->
---AshShellOptions
下的选项全选
(4)编译、安装
执行make;makeinstall
执行之后,将会在你的rootfs的bin,sbin下创建一些文件,同时在rootfs下生成一个linuxrc文件。
4.修改必要的文件
(1)将busybox-1.9.2下的examples/bootfloppy/etc/下的文件copy到rootfs/etc下
cp–a.../examples/bootfloppy/etc/*…/rootfs/etc/
cd…/rootfs/etc
(2)增加为shell导入全局变量的文件/etc/profile
viprofile
修改如下:
#/etc/profile:system-wide.profilefilefortheBourneshells
echo
echo"Processing/etc/profile..."
#no-op
#Setsearchlibrarypath
echo"Setsearchlibrarypathin/etc/profile"
exportLD_LIBRARY_PATH=/lib:/usr/lib
#Setuserpath
echo"Setuserpathin/etc/profile"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
exportPATH
#SetPS1
#注意:ash除了SHELL变量外,支持\u、\h、\W、\$、\!、\n、\w、\nnn(ASCII字符对应的八进制数)
#以及\e[xx;xxm(彩色特效)等等!
#而且前面还要多加一个
'\'!
echo"SetPS1in/etc/profile"
exportPS1="\\e[05;32m[$USER@\\w\\a]\\$\\e[00;34m"
echo"Done"
echo
(3)增加初始化文件/etc/inittab,/etc/fstab
viinittab
Vifstab
(4)增加初始化脚本/etc/init.d/rcS(如果init.d文件夹没有创建,先创建该文件夹)
Viinit.d/rcS
(5)删除etc/下的备份文件
rm*~init.d/*~
(6)为mdev创建配置文件,在etc/下
Vimdev.conf
创建一个mdev.conf文件,内容可有可无。
5.为使用用户登录功能移植tinylogin
(1)下载、解压
(2)修改tinylogin的makefile
(3)编译并安装,需要用root编译安装
makePREFIX=…/rootfsinstall
PREFIX=用来指定安装路径,我这里的路径为rootfs的根目录.安装完之后会在bin,usr/bin下生成几个文件,和用户登录密码相关的.
(4)创建账号和密码文件
将主机的/etc/passwd,/etc/shadow,/etc/group文件复制到…/rootfs/etc/文件下
并修改…/rootfs/etc/下这几个文件,只保留root账户.
Vipasswd
root:x:0:0:root:/root:/bin/sh
vigroup
root:x:0:root
vishadow
root:$xxxxx:xxxx:x:xxxx:x::
注意:这里可能会有个问题,因为从主机下复制过来的那些文件所属组不通,你可能需要将其权限修改一下才能打开修改.
再删除…/rootfs/etc/下的备份文件
rm*~
这样root的登录密码和主机的登录密码一样了.你也可以在刚才那些文件中保留一些另外的用户.
6.拷贝必须的动态库文件
从交叉编译器/usr/local/arm/3.4.1/arm-linux/lib/中拷贝到…/rootfs/lib/中
cp–d/usr/local/arm/3.4.1/arm-linux/lib/ld*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libc-2.3.2.so…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libc.so.6…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libm-*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libm.s*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libcrypt-*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libcrypt.s*…/rootfs/lib/
以上就是最基本的文件,一个最基本的文件系统就构建完成.
7.制作cramfs文件系统
(1)下载cramfs-1.1.tar.gz,解压,编译得到mkcramfs工具
(2)制作cramfs文件系统
./mkcramfs…/rootfsmyrootfs.cramfs
如果在制作的时候提示出错,那么就很有可能是你的/etc/下的passwd,group,shadow文件的权限出问题了.
这样就cramfs文件系统就制作成功了.
8.制作yaffs文件系统
在内核制作最后提到了yaffs自带的mkyaffsimg工具和yaffs文件系统不匹配,好在在网上(http://www.100ask.net/showtopic-177.aspx)找到了一个mkyaffsimg补丁.
解压该补丁,进入yaffs2\utils\下,执行make命令,生成mkyaffsimage工具.
然后就像制作cramfs文件系统一下:
./mkyaffsimage…/rootfsmyrootfs.img
Yaffs文件系统制作完成.
至此uboot-1.2.0,linux-2.6.24.4,根文件系统都简单移植完成了.但是有一个问题,启动后,登录后,如果在切换到另一个用户后,命令提示符那里还是原来的那个用户.这可能是文件系统的/etc/rcS文件有问题了.
四、根文件系统的设计(不用用户登录,即无账户和密码)
移植环境:VMware5.5.2+redhat9(非root登录,需要切换到root下执行的另外指出)
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
Busybox:busybox-1.9.2.tar.bz2(http://busybox.net/downloads/)
Cramfs制作工具:cramfs-1.1.tar.gz(http://sourceforge.net/projects/cramfs/)
先说明一下,移植过程按照是按照书嵌入式linux应用开发完全手册移植的。
Init进程是由内核启动的第一个(也是唯一的一个)用户进程(进程ID为1)它根据配置文件决定启动哪些进程,比如执行某些脚本、启动shell、运行用户指定程序等。Init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。
内核启动init进程时已经打开“/dev/console”设备作为控制台,一般情况下init程序就是用/dev/console。但是如果内核启动init进程的同时设置了环境变量CONSOLE或者console,则使用环境变量所指定的设备。在init程序中,还会检查这个设备是否可以打开,如果不能打开则使用/dev/nul
Init进程只是作为其他进程的发起者和控制者,并不需要控制台与用户交互,如果存在etc/inittab文件,init程序解析他并执行,然后按照他的指示创建各种子进程;否则使用默认的配置创建子进程。
从系统启动过程可以知道,涉及的设备有:dev/mtdblock*(MTD块设备)、/dev/ttySAC*(串口设备)、/dev/null、/dev/console,只要建立以下设备就可以启动系统。
mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件。mdev的主要用途主要有两个:初始化/dev目录、动态更新。动态更新不仅是更新/dev目录,还支持热插拔,即接入、和卸下设备时执行某些动作。要使用mdev,需要内核支持sysfs文件系统,为了减少对Flash的读写,还要支持tmpfs文件系统。先要确保内核已经设置了CONFIG—SYSFS、CONFIG—TMOFS配项。mount
–ttmpfsmdev/dev使用内存文件系统减少对Flash的读写
1.解压busybox,并配置busybox,可参考上一节的做法.
我来介绍一下他吧,busybox是一个集成了一百多个最常用linux命令和工具的软件,他甚至还集成了一个http服务器和一个telnet服务器,而所有这一切功能却只有区区1M左右的大小.我们平时用的那些linux命令就好比是分立式的电子元件,而busybox就好比是一个集成电路,把常用的工具和命令集成压缩在一个可执行文件里,功能基本不变,而大小却小很多倍,在嵌入式linux应用中,busybox有非常广的应用。
2.安装busybox到rootfs/mini_rootfs下
MakeCONFIG_PREFIX=…./rootfs/mini_rootfsinstall
将会在mini_rootfs下生成bin,sbin,linuxrc文件(夹)
3.创建usr,lib,usr/bin,usr/sbin文件夹
4.安装一些库文件
将交叉编译器下的一些库文件复制到mini_rootfs/lib下
cp…/3.4.1/arm-linux/lib/*.so*…../rootfs/mini_rootfs/lib
这些库文件有些可能是多余的.
5.构建etc目录(记住以下etc下的文本内容要用vi编译器,因为复制的内容是xp下的,格式和linux不一样)
(1)创建etc目录:mkdiretc
(2)将busybox下的examples/bootfloopy/etc下的文件copy到mini_rootfs/etc下
(3)修改etc/inittab文件
::sysinit:/etc/init.d/rcS
系统启动最先执行的,rcS是一个脚本
s3c2410_serial0::askfirst:-/bin/shinit进程先输出pleasepressEntertoactivatethisconsole等用户输入回车之后才启动子进程,启动shell脚本,以/dev/
s3c2410_serial0作为控制台,需要注意的是,开发板上通过mdev生成的/dev目录中,s3c2410_serial0不是ttySAC0,所以此处使用的控制台台为s3c2410_serial0
::ctrlaltdel:/sbin/reboot按下ctrl-alt-del键系统会从新启动,不过在串口控制台中是无法输入ctrl-alt-del组合键的
::shutdown:/bin/umount-a–r在关机时卸载所有文件系统
(4)修改etc/init.d/rcS文件
#!/bin/sh
ifconfigeth0192.168.1.6修改本机的ip地址
/bin/mount–a挂载所有/etc/fstab文件指定的所有文件系统
mkdir/dev/ptsdevpfs用来支持外部网络连接telnet的虚拟终端
mount-tdevptsdevpts/dev/pts
echo/sbin/mdev>/proc/sys/kernel/hotplug设置内核当有设备拔插时调用/bin/
mdev程序
mdev–s在/dev目录下生成内核支持的所有设备的节点
要在内核启动时,自动运行mdev。这要修改两个文件:fstab来自动挂载文件系统、修改rcS加入要自动运行的命令。
(5)修改etc/fstab文件
#devicemount—pointtypeoptionsdumpfsckorder这是一一对应的参数,本文件完成所要自动挂载的文件系统
proc/procprocdefaults00
tmpfs/tmptmpfsdefaults00
sysfs/syssysfsdefaults00
tmpfs/devtmpfsdefaults00
(6)修改etc/profile文件,增加一些定义
#/etc/profile:system-wide.profilefilefortheBourneshells
echo
echo-n"Processing/etc/profile..."
exportLD_LIBRARY_PATH=/lib:/usr/lib
exportPATH=/bin:/sbin:/usr/bin:/usr/sbin
PS1='[\u@\h\w]\$'这个你猜猜改一下就知道是什么了。我也是改过才知道
#no-op
echo"Done"
echo
在etc目录下建立vimdev.conf(空文件即可)
6.构建dev目录
执行下列命令
mkdirdev
再切换到root登录控制台
mknodconsolec51
mknodnullc31
7.构建其他目录
mkdirprocmnttmpsysroot
8.制作镜像文件,同上一节的制作方法.
五、移植LCD液晶驱动
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
先说明一下,移植过程按照http://blog.chinaunix.net/u2/63560/showart_520838.html移植的。另外结合sky提供的内核代码。
LCD为三星3.5寸TFT,320×240,在前面移植的内核的基础上进行一下修改:
1.修改文件/arch/arm/mach-s3c2440/mach-smdk2440.c
加入头文件#include<asm/arch/fb.h>
在/*LCDdriverinfo*/后增加自己的液晶驱动代码,参考sky提供的液晶驱动\arch\arm\mach-s3c2410\sky2440.c中的#elifdefined(CONFIG_FB_S3C24X0_S320240)
staticstructs3c2410fb_mach_infosmdk2440_lcdcfg__initdata={。。。。}处的整个结构体的内容替换为:
staticstructs3c2410fb_displaysky2440_lcd_cfg__initdata={
{
/*Configfor320x240LCD*/
.lcdcon5=S3C2410_LCDCON5_FRM565|
S3C2410_LCDCON5_INVVLINE|
S3C2410_LCDCON5_INVVFRAME|
S3C2410_LCDCON5_PWREN|
S3C2410_LCDCON5_HWSWP,
.type=S3C2410_LCDCON1_TFT,
.width=320,
.height=240,
.pixclock=100000,/*HCLK/10*/
.xres=320,
.yres=240,
.bpp=16,
.left_margin=16,
.right_margin=6,
.hsync_len=9,
.upper_margin=4,
.lower_margin=6,
.vsync_len=16,
}
};
staticstructs3c2410fb_mach_infosmdk2440_fb_info__initdata={
。。。。。。。。。}处的整个结构体的内容替换为:
staticstructs3c2410fb_mach_infosky2440_fb_info__initdata={
.displays=&sky2440_lcd_cfg,
.num_displays=1,
.default_display=0,
.gpccon=0xaa955699,
.gpccon_mask=0xffc003cc,
.gpcup=0x0000ffff,
.gpcup_mask=0xffffffff,
.gpdcon=0xaa95aaa1,
.gpdcon_mask=0xffc0fff0,
.gpdup=0x0000faff,
.gpdup_mask=0xffffffff,
.lpcsel=0xf82,
};
在函数smdk2410_init()中加入
s3c24xx_fb_set_platdata(&sky2440_fb_info);
2.配置内核
DeviceDrivers--->
Graphicssupport--->
Displaydevicesupport--->
<*>Displaypanel/monitorsupport
<*>Supportforframebufferdevices
<*>S3C2410LCDframebuffersupport
Consoledisplaydriversupport--->
<*>FramebufferConsolesupport
[*]FramebufferConsoleRotation
[*]Selectcompiled-infonts
[*]VGA8x8font
[*]VGA8x16font
[*]Mini4x6font
[*]Sparcconsole8x16font
[*]Bootuplogo--->
---Bootuplogo
[*]Standard224-colorLinuxlogo
3.重新编译内核,下载,运行,你就会看到液晶上的那个小企鹅了,对应的图片为/drivers/video/logo/logo_linux_clut224.ppm.
另外这时可以把LCD当作一个控制台来使用了,例如执行:echohello>/dev/tty0
将会在LCD的小企鹅下输出hello字符.
六、DM9000网卡驱动移植
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
DM9000的CS是接在nGCS4上的,INT接到EINT7,CMD接到ADDR2上.
1.增加DM9000平台设备,修改arch/arm/plat-s3c24xx/common-smdk.c
(1)添加要包含的头文件
在47行处添加
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
#include<linux/dm9000.h>
#endif
(2)添加DM9000平台设备结构
紧接着前面的地方,添加平台设备结构
/*DM9000*/
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
staticstructresources3c_dm9k_resource[]={
[0]={
.start=S3C2410_CS4,
.end=S3C2410_CS4+3,
.flags=IORESOURCE_MEM,
},
[1]={
.start=S3C2410_CS4+4,
.end=S3C2410_CS4+4+3,
.flags=IORESOURCE_MEM,
},
[2]={
.start=IRQ_EINT7,
.end=IRQ_EINT7,
.flags=IORESOURCE_IRQ,
}
};
staticstructdm9000_plat_datas3c_dm9k_platdata={
.flags=DM9000_PLATF_16BITONLY,
};
staticstructplatform_devices3c_device_dm9k={
.name="dm9000",
.id=0,
.num_resources=ARRAY_SIZE(s3c_dm9k_resource),
.resource=s3c_dm9k_resource,
.dev={
.platform_data=&s3c_dm9k_platdata,
}
};
#endif/*CONFIG_DM9000*/
(3)加入到内核设备列表中
staticstructplatform_device__initdata*smdk_devs[]={
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
};
2.修改drivers/net/dm9000.c
(1)增加包括头文件代码
在74行附近
#ifdefined(CONFIG_ARCH_S3C2410)
#include<asm/arch-s3c2410/regs-mem.h>
#endif
(2)设置存储器控制器BANK4使用,设置默认MAC地址
在dm9000_probe()函数中先增加两个变量定义(大概412行)
#ifdefined(CONFIG_ARCH_S3C2410)
unsignedintoldval_bwscon;
unsignedintoldval_bankcon4;
#endif
再增加Bank4的设置(大概427行)
……
PRINTK2("dm9000_probe()");
#ifdefined(CONFIG_ARCH_S3C2410)
oldval_bwscon=*((volatileunsignedint*)S3C2410_BWSCON);
*((volatileunsignedint*)S3C2410_BWSCON)=(oldval_bwscon&~(3<<16))\
|S3C2410_BWSCON_DW4_16|S3C2410_BWSCON_WS4|S3C2410_BWSCON_ST4;
oldval_bankcon4=*((volatileunsignedint*)S3C2410_BANKCON4);
*((volatileunsignedint*)S3C2410_BANKCON4)=0x1f7c;
#endif
设置默认MAC地址(大概612行)
…..
if(!is_valid_ether_addr(ndev->dev_addr))
printk("%s:InvalidethernetMACaddress.Please"
"setusingifconfig\n",ndev->name);
#ifdefined(CONFIG_ARCH_S3C2410)
printk("nowusethedefaultMACaddress:08:90:90:90:90:90\n");
ndev->dev_addr[0]=0x08;
ndev->dev_addr[1]=0x90;
ndev->dev_addr[2]=0x90;
ndev->dev_addr[3]=0x90;
ndev->dev_addr[4]=0x90;
ndev->dev_addr[5]=0x90;
#endif
………
out:
printk("%s:notfound(%d).\n",CARDNAME,ret);
#ifdefined(CONFIG_ARCH_S3C2410)
*((volatileunsignedint*)S3C2410_BWSCON)=oldval_bwscon;
*((volatileunsignedint*)S3C2410_BANKCON4)=oldval_bankcon4;
#endif
……..
(3)注册终端市,指定触发方式,在dm9000_open()中
staticint
dm9000_open(structnet_device*dev)
{
board_info_t*db=(board_info_t*)dev->priv;
PRINTK2("enteringdm9000_open\n");
#ifdefined(CONFIG_ARCH_S3C2410)
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED|IRQF_TRIGGER_RISING,dev->name,dev))
#else
if(request_irq(dev->irq,&dm9000_interrupt,DM9000_IRQ_FLAGS,dev->name,dev))
#endif
return-EAGAIN;
…….
3.修改内核配置
Makemenuconfig之后,将DM9000编译入内核,或者配置成模块.
DeviceDrivers--à
Networkdevicesupport--à
[*]Networkdevicesupport
Ethernet(10or100Mbit)-à
<*>DM9000support
4.重新编译内核:makeuImage
七、USB驱动
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
没有修改什么文件,只是在内核编译的时候,加入了一些有关usb的选项
Devicedrives---à
SCSIdevicesupport---à
<*>SCSIdevicesupport
[*]legacy/proc/scsi/support
<*>SCSIdisksupport
USBsupport->
<*>supportforHost-sideUSB
[*]USBdevicefilesystem
<*>OHCIHCDsupport
<*>USBMassstoragesupport
HIDdevice--à
<*>USBHumanInterfacedevice(fullHID)support
[*]/dev/hiddevrawHIDdevicesupport
重新编译内核,下载.
启动后,如果将usb鼠标插入叠在一起的那个usb接口的下面那个接口,你将会看到提示
[@(none)/dev]#usb1-1:newlowspeedUSBdeviceusings3c2410-ohciandaddress3
usb1-1:configuration#1chosenfrom1choice
input:USBMouseas/class/input/input1
input:USBHIDv1.00Mouse[USBMouse]onusb-s3c24xx-1
并且在dev下增加了几个文件:usbdev1.2,usbdev1.2_ep00,usbdev1.2_ep81
当拔下的时候:[@(none)/dev]#usb1-1:USBdisconnect,address3
另外拿了块u盘,挂载在上面可以看到内容(需要内核支持相应的文件系统).
八、Qtopia移植(qtopia-2.2.0版本)
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
前面已经移植的内核和文件系统可以在终端下正常操作(除了网络ping的时候还有丢包的问题),下面要在前面的基础上移植qtopia.
首先是一些压缩包的下载:
1.得到本机运行版本uic工具:http://vanille.de/tools/uic-qt2
下载后改变权限chmodu+rxuic-qt2
2.qtopia-free-src-2.2.0.tar.gz下载地址:
ftp://ftp.trolltech.com/pub/qt/source/qtopia-free-src-2.2.0.tar.gz
3.e2fsprogs-1.39.tar.gz下载地址:
http://nchc.dl.sourceforge.net/sourceforge/e2fsprogs/e2fsprogs-1.39.tar.gz
4.jpegsrc.v6b.tar.gz下载地址:
http://superb-east.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.14.tar.bz2
5.libpng-1.2.14.tar.bz2下载地址:
http://superb-east.dl.sourceforge.net/sourceforge/libpng/libpng-1.2.14.tar.bz2
6.tslib-1.3.tar.bz2(触摸屏校正工具:也可以用QT自带的,这样就不必下载)下载地址:
http://mail.pdaxrom.org/download/1.1.0beta4/src/tslib-1.3.tar.bz2
7.zlib-1.2.3.tar.bz2下载地址:
http://www.zlib.net/zlib-1.2.3.tar.gz
移植步骤:
在开始之前需要修改交叉编译器的一个头文件,为/…../3.4.1/armlinux/include/linux/fd.h,在该文件中增加一行:#include<linux/compiler.h>
1.导出编译工具安装路径
exportPATH=$PATH:/...../3.4.1/bin/
source/etc/profile
2.建立qt的文件夹
mkdir/..../myboard/qtopia-arm-home
exportMYHOME=/..../myboard/qtopia-arm-home
3.创建几个文件夹
cd$MYHOME
mkdirarm
cdarm
mkdirlibinclude
4.解压有关库文件
e2fsprogs-1.39.tar.gz.tar.gz,jpegsrc.v6b.tar.gz,libpng-1.2.14.tar.bz2,zlib-1.2.3.tar.bz2解压至$MYHOME/arm目录,并相应更名目录为e2fs,jpeg,libpng,zlib。
5.编译相关库
(1)e2fs
cd$MYHOME/arm/e2fs
./configure--host=arm-linux--enable-elf-shlibs--with-cc=arm-linux-gcc-with-linker=arm-linux-ld--prefix=/..../3.4.1/arm-linux
Make
将lib文件夹下的uuid文件夹复制到../include把libuuid.so*复制到../lib
cp-rlib/uuid../include
cplib/libuuid.so*../lib
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(2)jpeg
cd$MYHOME/arm/jpeg
./config--enable-shared--prefix=/…./3.4.1/arm-linux
geditMakefile
修改
CC=arm-linux-gcc
AR=arm-linux-arrc
AR2=arm-linux-ranlib
Make
Makeinstall-lib
将会在/…./3.4.1/arm-linux/lib和/…./3.4.1/arm-linux/include中生成有关库文件(libjpeg.so*,libjpeg.a,libjpeg.la)和头文件(jpeglib.h)
再同样上面那些文件复制一份到$MYHOME/arm/include和$MYHOME/arm/lib下
(3)zlib
cd$MYHOME/arm/zlib
./configure-shared
geditMakefile
修改
[begin]
......
CC=arm-linux-gcc
......
LDSHARED=arm-linux-gcc-shared-Wl,-soname,libz.so.1
CPP=arm-linux-gcc-E
......
AR=arm-linux-arrc
RANLIB=arm-linux-ranlib
......
prefix=/.../3.4.1/arm-linux
......
[end]
make
cplibz.so*../lib/
cp*.h../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(4)libpng
cd$MYHOME/arm/libpng
cpscripts/makefile.linux./Makefile
geditMakefile
修改:
[begin]
.....
AR_RC=arm-linux-arrc
CC=arm-linux-gcc
.....
RANLIB=arm-linux-ranlib
....
prefix=/.../3.4.1/arm-linux
.....
[end]
make
cplibpng.a../lib/
cplibpng12.so*../lib/
cplibpng12.so../lib/libpng.so
cp*.h../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
6.创建文件夹nfs
cd$MYHOME
mkdirnfs
7.解压qtopia-free-2.2.0.tar.bz2到nfs文件夹
8.编译qtopia
(1)建立安装目录
mkdir$MYHOME/nfs/qtopia
(2)复制uci-qt2文件
cpuic-qt2$MYHOME/nfs/qtopia-free-2.2.0/qt2/bin/uic
(3)修改文件
vi$MYHOME/nfs/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++/qmake.conf
将此行
QMAKE_LIBS_QT=-lqte
修改为
QMAKE_LIBS_QT=-lqte-lpng-lz-luuid-ljpeg
(4)支持usb键盘和鼠标
修改$QPEDIR/src/qt/qconfig-qpe.h文件
注释如下部分:
/*
#ifndefQT_NO_QWS_CURSOR
#defineQT_NO_QWS_CURSOR
#endif
#ifndefQT_NO_QWS_MOUSE_AUTO
#defineQT_NO_QWS_MOUSE_AUTO
#endif
#ifndefQT_NO_QWS_MOUSE_PC
#defineQT_NO_QWS_MOUSE_PC
#endif
*/
(5)准备配置文件:
cp$MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/qt/qconfig-qpe.h$MYHOME/nfs/qtopia-free-2.2.0/qt2/src/tools
cd$MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/libraries/qtopia
cpcustom-linux-ipaq-g++.cppcustom-linux-arm-g++.cpp
cpcustom-linux-ipaq-g++.hcustom-linux-arm-g++.h
(6)开始配置
./configure-qte'-embedded-xplatformlinux-arm-g++-qconfigqpe-no-qvfb-depths16,32-system-jpeg-system-libpng-system-zlib-gif-thread-no-xft-release-I$MYHOME/arm/include-L$MYHOME/arm/lib-lpng-lz-luuid-ljpeg'-qpe'-xplatformlinux-arm-g++-edition
pda-displaysize320x240-I$MYHOME/arm/include-L$MYHOME/arm/lib-prefix=$MYHOME/nfs/qtopia'
../setQpeEnv(两个点号之间有空格)
其中的320*240是对应我的触摸屏的长和宽
(7)make
make过程中可能会有一些错误,根据提示进行修改,但我make时没有出现错误
(8)makeinstall
至此将在$MYHOME/nfs/qtopia中生成一些qt移植所需的文件
9.复制在第四节中得到的文件系统目录(mini_rootfs),改名成qt_rootfs
10.将Qtopia所依赖的库复制到qt_rootfs/lib中
cd$MYHOME/arm
cplib/*……/qt_rootfs/lib
11.复制字库(字库在$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts/中)
cp–rf$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts$MYHOME/nfs/qtopia
12.将qtopia文件夹复制到qt_rootfs中
先在qt_rootfs中创建一个opt文件夹:cd……./qt_rootfs;mkdiropt;
再将$MYHOME/nfs中的qtopia文件夹复制到qt_rootfs/opt中
13.创建时区文件
cd……./qt_rootfs
mkdir–pusr/share/zoneinfo
cp–rf/usr/share/zoneinfo/Americausr/share/zoninfo/
cp/usr/share/zoneinfo/zone.tabusr/share/zoneinfo/
也可以将$MYHOME/nfs/qtopia-free-2.2.0/qtopia/etc/下的zoneinfo文件夹全部copy到usr/share/
14.伪造触摸屏校验文件
Qtopia第一次启动的时候会运行触摸屏校验程序,由于现在还没移植触摸屏驱动,会导致校验失败,无法进入系统,可以在根文件系统中创建一个触摸校验文件etc/pointercal,内容为10101165536
15.建立一个脚本文件,用来运行qtopia
在……qt_rootfs/bin下创建一个qpe.sh文件
#!/bin/sh
exportHOME=/root
exportQTDIR=/opt/qtopia
exportQPEDIR=/opt/qtopia
exportQWS_DISPLAY=LinuxFb:/dev/fb0
exportQWS_KEYBOARD=”TTY:/dev/tty1”
exportQWS_MOUSE_PROTO=”USB:/dev/mouse0”
exportPATH=$QPEDIR/bin:$PATH
exportLD_LIBRARY_PATH=$QPEDIR/lib:$LD_LIBRARY_PATH
$QPEDIR/bin/qpe&
将qpe.sh设置成可执行.另外如果qt_rootfs/下没有root文件夹,要创建一个.HOME变量要用到.
16.修改根文件系统的启动脚本
(1)在qt_rootfs下创建一个tmp目录(如果已经有这么一个目录则跳过这一步)
(2)在etc/fstab中加入这么一行(如果已经有这么一行则跳过这一步)
tmpfs/tmptmpfsdefaults00
(3)修改etc/init.d/rcS,在最后加入这么一行
/bin/qpe.sh&
16.重新制作yaffs文件系统
./mkyaffsimage………/qt_rootfsqt_rootfs.yaffs
17.重新将qt_rootfs.yaffs烧写进开发板,启动即可
注:目前还不支持触摸屏,可能要用到qtopia自带的tslib或者要用到tslib.1.3.tar.bz2.
九、
十、
十一、
十二、
十三、
十四、
十五、
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0或者V3.0
编译器:cross3.2(下载地址ftp://ftp.arm.linux.org.uk/pub/armlinux/toolchain/cross3.2.tar.gz)
Uboot:u-boot-1.2.0(下载地址:
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址
其中uboot的移植参照
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.用dk登录linux主机,在dk下创建一个myboard文件夹
2.解压cross3.2:解压到/usr/local/arm/文件夹下
最好在/usr/local/arm/下创建一个3.2文件夹,把解压在arm文件夹下的文件(夹)全部移到3.2下,因为后面可能还会用到3.4.1的交叉编译器。
3.解压uboot:将uboot解压到myboard文件夹下
tarxzvfu-boot-1.2.0.tar.bz2–C/home/dk/myboard/
4.进入uboot目录,修改Makefile
cdu-boot-1.2.0
viMakefile
(1)新建我的编译项
在1923行,即smdk2410_config编译项之后增加我的编译项
tekkaman2440_config:unconfig
@$(MKCONFIG)$(@:_config=)armarm920ttekkaman2440tekkamans3c24x0
各项的意思如下:
arm:CPU的架构(ARCH)
arm920t:CPU的类型(CPU),其对应于cpu/arm920t子目录。
tekkaman2440:开发板的型号(BOARD),对应于board/tekkaman/tekkaman2440目录。
tekkaman:开发者/或经销商(vender)。
s3c24x0:片上系统(SOC)。
(2)修改交叉编译器路径,我用的cross3.2是在/usr/local/arm/
修改128行
CROSS_COMPILE=/usr/local/arm/3.2/bin/arm-linux-
5.在/board子目录中建立自己的开发板tekkaman2440目录
由于我在上一步板子的开发者/或经销商(vender)中填了tekkaman,所以开发板tekkaman2440目录一定要建在/board子目录中的tekkaman目录下,否则编译会出错。
$cdboard
$mkdirtekkamantekkaman/tekkaman2440
$cp-arfsbc2410x/*tekkaman/tekkaman2440/
$cdtekkaman/tekkaman2440
$mvsbc2410x.ctekkaman2440.c
还要记得修改自己的开发板tekkaman2440目录下的Makefile文件,不然编译时会出错:
$viMakefile
COBJS:=tekkaman2440.oflash.o
6.在include/configs/中建立配置头文件
$cpinclude/configs/sbc2410x.hinclude/configs/tekkaman2440.h
7.测试编译能否成功
$maketekkaman2440_config
Configuringfortekkaman2440board...
(如果出现:
$maketekkaman2440_config
Makefile:1927:***遗漏分隔符。停止。
请在U-boot的根目录下的Makefile的
@$(MKCONFIG)$(@:_config=)armarm920ttekkaman2440tekkaman)
前加上“Tab”键)
$make
到这一步应该能编译成功,但是我的并没有编译成功,提示/common/cmd_bootm.c文件的464行的U_BOOT_CMD有错误,我是把其中的从#ifdefCONFIG_OF_FLAT_TREE到#endif都屏蔽掉,这样就可以编译过去了。可能还会出现类似的问题,用同样的方法可以解决。
下面修改Uboot中的文件,以匹配开发板
8.修改/cpu/arm920t/start.S
这个函数是arm920t系列的共有启动的汇编代码,UBOOT执行的第一个程序
(0)修改寄存器地址定义
/*turnoffthewatchdog*/
#ifdefined(CONFIG_S3C2400)
#definepWTCON0x15300000
#defineINTMSK0x14400008/*Interupt-Controllerbaseaddresses*/
#defineCLKDIVN0x14800014/*clockdivisorregister*/
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
#definepWTCON0x53000000这个定义了看门狗的寄存器地址
#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/中断掩码的寄存器地址
#defineINTSUBMSK0x4A00001C中断掩码的寄存器地址
#defineCLKDIVN0x4C000014/*clockdivisorregister*/完成时钟分份的寄存器
#endif
(1)修改中断禁止部分
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
ldrr0,=pWTCON把看门狗寄存器地址给了r0
movr1,#0x0r1等于0
strr1,[r0]看门狗寄存器等于0因为在启动时要关闭看门狗,不能让他产生中断影响启动,此时也根本不需要任何中断
/*
*maskallIRQsbysettingallbitsintheINTMR-default
*/
movr1,#0xffffffff关闭所有中断
ldrr0,=INTMSK
strr1,[r0]
#ifdefined(CONFIG_S3C2410)
ldrr1,=0x7ff//根据2410芯片手册,INTSUBMSK有11位可用,
//vivi也是0x7ff,不知为什么U-Boot一直没改过来。
ldrr0,=INTSUBMSK
strr1,[r0]
#endif
#ifdefined(CONFIG_S3C2440)
ldrr1,=0x7fff//根据2440芯片手册,INTSUBMSK有15位可用
ldrr0,=INTSUBMSK
strr1,[r0]
#endif
(2)修改时钟设置(2440的主频可达533MHz,但是我设到533MHz时系统很不稳定,不知是不是SDRAM和总线配置的影响,所以现在先设到405MHz,以后在改进。)
ldrr0,=CLKDIVN
这个值决定了FCLKHCLKPCLK的频率
FCLK是供给CPU的是主频
HCLK是供给AHB总线(主要用于高性能模块(如CPU、DMA和DSP等)之间的连接,作为SoC的片上系统总线)上的外围设备
PCLK是供给APB总线(APB主要用于低带宽的周边外设之间的连接,例如UART、1284等)上的外围设备
UCLK是两路PLL中一路供给USB的频率
ARM总线技术在这里我不多介绍了,对硬件感兴趣的同学建议多多了解,我有一回面试人家就问我这个了,405MHZ已经很高了,基本都够了,2410的200MHZ就能播放Mplayer视频,据说很流畅。
movr1,#5/*FCLK:HCLK:PCLK=1:4:8*/
strr1,[r0]
mrcp15,0,r1,c1,c0,0/*readctrlregistertekkaman*/
orrr1,r1,#0xc0000000/*Asynchronoustekkaman*/
mcrp15,0,r1,c1,c0,0/*writectrlregistertekkaman*/
他是用到了协处理器P15,此处理器主要设置mmu,时钟模式,caches,保护模式的。先把C0
C1的值读出到r1,设置后再写回。FCLK:HCLK:PCLK的比例由CLKDIVN决定的,CLKDIVN寄存器的HDIVN和PDIVN决定比例的大小。因为此时的HDIVH不为0,将快速总线模式改为异步总线模式,操作协处理器P15改变模式即可,如果HDIVH不为0,而且是快速总线模式的话,那么CPU的主频由hclk控制,这样可以实现不改变HCLK和PCLCK的同时就能使CPU的主频减半或更多。网上的大虾说没有以上几句主频会是12MHZ,我的观点不同。这是数据手册原文
IfHDIVNisnot0andtheCPUbusmodeisthefastbusmode,theCPUwilloperatebytheHCLK.ThisfeaturecanbeusedtochangetheCPUfrequencyasahalformorewithoutaffectingtheHCLKandPCLK
#ifdefined(CONFIG_S3C2440)
/*now,CPUclockis405.00Mhztekkaman*/
movr1,#CLK_CTL_BASE/*tekkaman*/这是时钟寄存器的基地址
movr2,#MDIV_405/*mpll_405mhztekkaman*/
addr2,r2,#PSDIV_405/*mpll_405mhztekkaman*/
strr2,[r1,#0x04]/*MPLLCONtekkaman*/设置MPLLCON
#endif
#ifdefined(CONFIG_S3C2410)
/*now,CPUclockis202.8Mhztekkaman*/
movr1,#CLK_CTL_BASE/*tekkaman*/
movr2,#MDIV_200/*mpll_200mhztekkaman*/
addr2,r2,#PSDIV_200/*mpll_200mhztekkaman*/
strr2,[r1,#0x04]/*MPLLCONtekkaman*/
#endif
#endif/*CONFIG_S3C2400||CONFIG_S3C2410||CONFIG_S3C2440*/
红色部分是我添加的,利用vivi的代码,将其设为405.00MHz并在前面加上:
#elifdefined(CONFIG_S3C2410)
#definepWTCON0x53000000
#defineINTMSK0x4A000008/*Interupt-Controllerbaseaddresses*/
#defineINTSUBMSK0x4A00001C
#defineCLKDIVN0x4C000014/*clockdivisorregister*/
#defineCLK_CTL_BASE0x4C000000/*tekkaman*/
#ifdefined(CONFIG_S3C2440)
#defineMDIV_4050x7f<<12/*tekkaman*/
#definePSDIV_4050x21/*tekkaman*/
#endif
#ifdefined(CONFIG_S3C2410)
#defineMDIV_2000xa1<<12/*tekkaman*/
#definePSDIV_2000x31/*tekkaman*/
#endif
#endif〕
(3)将从Flash启动改成从NANDFlash启动。(特别注意:这和2410的程序有不同,不可混用!!!是拷贝vivi的代码。)
将以下U-Boot的重定向语句段:
这段代码将uboot搬运到ram中,这个是没有存放在nand的情况,下面咱们来看一下不在nand启动和在nand启动时此处的区别。
#ifndefCONFIG_SKIP_RELOCATE_UBOOT
relocate:/*relocateU-BoottoRAM*/
adrr0,_start/*r0<-currentpositionofcode*/nor中的起始地址给了r0
ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/ram中的uboot代码的起始地址(这里关于uboot搬运这块在内存地址的部分,分了很多段,每一段空间具有不同功能,这是你理解uboot必须掌握的,非常关键,解释后续会提到些)
cmpr0,r1/*don'trelocduringdebug*/比较两个地址是否相同,不同则进行下面的搬运工作
beqstack_setup
在这里你会发现搬运了全部uboot,有的uboot把uboot的c部分搬运到内存_TEXT_BASE里面所放的地址处。
ldrr2,_armboot_start
ldrr3,_bss_start
subr2,r3,r2/*r2<-sizeofarmboot*/_bss_start-_armboot_start=armboot因为_armboot_end的结束位置就是bss区的开始位置所以能计算出uboot代码的大小
addr2,r0,r2/*r2<-sourceendaddress*/
以下就是把整个代码搬运到_TEXT_BASE里面所放的地址处,记住是内存地址,哈哈!!
copy_loop:
ldmiar0!,{r3-r10}/*copyfromsourceaddress[r0]*/
stmiar1!,{r3-r10}/*copytotargetaddress[r1]*/
cmpr0,r2/*untilsourceendaddreee[r2]*/
blecopy_loop
#endif/*CONFIG_SKIP_RELOCATE_UBOOT*/
替换成:因为nand和nor的启动是有区别的,NORFlash储存器较贵,而NAND
Flash则相对便宜,所以很多用户选择在NANDFlash中执行启动代码,在SDRAM中执行主程序。为支持NAND
Flash的BootLader,S3C2440有一个内部SRAM缓冲,称为‘Steppingstone’,启动时,NAND
Flash的最先4K字节将被装载到Steppingstone中,装载到Steppingstone中的启动代码将执行。这都是硬件自动完成的不需要咱们软件参与。一般来说,启动代码将把NAND
Flash的内容拷贝到SDRAM中,ECC将检测NAND的合法性,当拷贝完成时,主程序将在SDRAM中执行电源开启后,或系统重启后,NAND
Flash控制器将自动装载4KB的BootLoader代码,载入代码后将执行。注意在自启动时,ECC不检测,因此,NAND
Flash的头4KB要保证无错,下面我来带你分析它的源代码喽,嘿嘿!!!!忽然想家了,对了nand的硬件连接简单有兴趣的看一下了(NCON-Adv
Flash,GPG13-Pagesize,GPG14-Addresscycle,GPG15-总线宽度)
#ifdefCONFIG_S3C2440_NAND_BOOT@tekkaman@在以后会定义它的,不要忘了
@resetNAND
movr1,#NAND_CTL_BASEnand的寄存器基地址
ldrr2,=((7<<12)|(7<<8)|(7<<4)|(0<<0))CLE&ALE期间设置值|TWRPH0期间设置值|TWRPH0期间设置值|8位总线
strr2,[r1,#oNFCONF]设置NFCONF寄存器,初始化作用
ldrr2,[r1,#oNFCONF]
ldrr2,=((1<<4)|(0<<1)|(1<<0))@ActivelowCEControl初始化ECC解码/编码器(只写)|强制拉低nFCE(允许片选)|允许NAND控制器
strr2,[r1,#oNFCONT]设置NFCONT
ldrr2,[r1,#oNFCONT]
ldrr2,=(0x6)@RnBClear和nandisbusy
strr2,[r1,#oNFSTAT]
ldrr2,[r1,#oNFSTAT]
movr2,#0xff@RESETcommand
strbr2,[r1,#oNFCMD]
movr3,#0@wait就是一下段延时
nand1:
addr3,r3,#0x1
cmpr3,#0xa
bltnand1
nand2:
ldrr2,[r1,#oNFSTAT]@waitready
tstr2,#0x4
beqnand2
ldrr2,[r1,#oNFCONT]
orrr2,r2,#0x2@FlashMemoryChipDisable
strr2,[r1,#oNFCONT]
@getreadtocallCfunctions(fornand_read())
ldrsp,DW_STACK_START@setupstackpointer
movfp,#0@nopreviousframe,sofp=0初始化frame的起始位置
@copyU-BoottoRAM
ldrr0,=TEXT_BASE设置第1个参数:UBOOT在RAM中的起始地址
movr1,#0x0设置第2个参数:NandFlash的起始地址
movr2,#0x20000设置第3个参数:UBOOT的长度(128KB)
blnand_read_ll在board/tekkaman/tekkaman2440/nand_read.c我会解析这个函数的作用
tstr0,#0x0如果函数的返回值为0,表示执行成功.
beqok_nand_read执行内存比较,比较什么呢?他比较搬运到内存中的代码和在内部ram的前4kb是否一样
bad_nand_read:
loop2:bloop2@infiniteloop
ok_nand_read:
@verify
movr0,#0内部RAM的起始地址
ldrr1,=TEXT_BASE
UBOOT在RAM中的起始地址
movr2,#0x400@4bytes*1024=4K-bytes
go_next:
ldrr3,[r0],#4
ldrr4,[r1],#4
teqr3,r4进行比较
bnenotmatch
subsr2,r2,#4
beqstack_setup
bnego_next
notmatch:
内存中的代码和在内部ram的前4kb如果不一样,就无限的循环在这了,如果你不努力的去体会每一句,你的功力就像他一样了,哈哈!
loop3:bloop3@infiniteloop
#endif@CONFIG_S3C2440_NAND_BOOT@tekkaman@@
在“
_start_armboot:.wordstart_armboot”后加入:
.align2二的平方也就是字对齐了存储了
DW_STACK_START:.wordSTACK_BASE+STACK_SIZE-4
9.在board/tekkaman/tekkaman2440加入NANDFlash读函数文件,拷贝vivi中的nand_read.c文件到此文件夹即可:
#include<config.h>
#define__REGb(x)(*(volatileunsignedchar*)(x))
#define__REGi(x)(*(volatileunsignedint*)(x))
#defineNF_BASE0x4e000000
#defineNFCONF__REGi(NF_BASE+0x0)
#defineNFCONT__REGi(NF_BASE+0x4)
#defineNFCMD__REGb(NF_BASE+0x8)
#defineNFADDR__REGb(NF_BASE+0xC)
#defineNFDATA__REGb(NF_BASE+0x10)
#defineNFSTAT__REGb(NF_BASE+0x20)
//#defineGPDAT__REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT)
#defineNAND_CHIP_ENABLE(NFCONT&=~(1<<1))
允许片选
#defineNAND_CHIP_DISABLE(NFCONT|=(1<<1))禁止片选
#defineNAND_CLEAR_RB(NFSTAT|=(1<<2))
#defineNAND_DETECT_RB{while(!(NFSTAT&(1<<2)));}
#defineBUSY4
inlinevoidwait_idle(void){
while(!(NFSTAT&BUSY));等待是否nand忙于上次的操作
NFSTAT|=BUSY;
}
#defineNAND_SECTOR_SIZE512一页大小,我们的nand是这样分的
1设备(Device)=4096块(Blocks)
1块(Block)=32页/行(Pages/rows)
;页与行是相同的意思,叫法不一样
1(Page)=528字节(Bytes)=数据块大小(512Bytes)+OOB块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于NandFlash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过NandFlash命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过OOB部分的第六字节(即517字节)标志是否是坏块,OOB第六字节外,通常至少把OOB的前3个字节存放Nand
Flash硬件ECC码,这个我就不多说了,你要想真正看懂这些代码,必须了解nand的架构啊
NandFlash内置的指针指向各自的首地址。
#defineNAND_BLOCK_MASK(NAND_SECTOR_SIZE-1)
/*lowlevelnandreadfunction*/
int
nand_read_ll(unsignedchar*buf,unsignedlongstart_addr,intsize)
{
inti,j;
if((start_addr&NAND_BLOCK_MASK)||(size&NAND_BLOCK_MASK)){
return-1;/*invalidalignment*/检验开始地址和程序大小是否为512的整数
}
NAND_CHIP_ENABLE;允许NAND
for(i=start_addr;i<(start_addr+size);){直到读取整个uboot代码为止
/*READ0*/
NAND_CLEAR_RB;
NFCMD=0;
NandFlash片内寻址采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行
传送,并进行片内寻址。具体含义如下:
0-7位:字节在上半部、下半部及OOB内的偏移地址
8位:值为0代表对一页内前256个字节进行寻址
值为1代表对一页内后256个字节进行寻址
9-13位:对页进行寻址
14-25位:对块进行寻址
当传送地址时,从位0开始
/*WriteAddress*/
NFADDR=i&0xff;
NFADDR=(i>>9)&0xff;
NFADDR=(i>>17)&0xff;
NFADDR=(i>>25)&0xff;
NAND_DETECT_RB;
/*读出一页(512字节)*/
for(j=0;j<NAND_SECTOR_SIZE;j++,i++){
*buf=(NFDATA&0xff);
buf++;
}
}
NAND_CHIP_DISABLE;禁止片选
return0;
}
注意:s3c2410与s3c2440的NandFlash控制器寄存器不同,不能混用!!
10.修改board/tekkaman/tekkaman2440/Makefile文件
OBJS:=tekkaman2440.onand_read.oflash.o
11.修改include/configs/tekkaman2440.h文件,添加如下内容(注意:s3c2410与s3c2440的NandFlash控制器寄存器不同,不能混用!!):
......
/*
*NandflashBoot
*/
#defineCONFIG_S3C2440_NAND_BOOT1这处告诉从nand启动
#defineSTACK_BASE0x33f00000
#defineSTACK_SIZE0x8000
//#defineUBOOT_RAM_BASE0x33f80000
/*NANDFlashController*/
#defineNAND_CTL_BASE0x4E000000
#definebINT_CTL(Nb)__REG(INT_CTL_BASE+(Nb))
/*Offset*/
#defineoNFCONF0x00
#defineoNFCONT0x04
#defineoNFCMD0x08
#defineoNFADDR0x0c
#defineoNFDATA0x10
#defineoNFSTAT0x20
#defineoNFECC0x2c
/*GPIO*/
#defineGPIO_CTL_BASE0x56000000
#defineoGPIO_B0x10
#defineoGPIO_CON0x0/*R/W,Configuresthepinsoftheport*/
#defineoGPIO_DAT0x4/*R/W,Dataregisterforport*/
#defineoGPIO_UP0x8/*R/W,Pull-updisableregister*/
#endif/*__CONFIG_H*/
12.修改board/tekkaman/tekkaman2440/lowlevel_init.S文件
......
/*REFRESHparameter*/
#defineREFEN0x1/*Refreshenable*/
#defineTREFMD0x0/*CBR(CASbeforeRAS)/Autorefresh*/
#defineTrp0x2/*4clk*/
#defineTrc0x3/*7clk*/
#defineTchr0x2/*3clk*/
#defineREFCNT1012
......
注:参数的值按照SKY提供的对应文件的参数修改过来。
13.修改/board/tekkaman/tekkaman2440/tekkaman2440.c
因为SKY2440和smdk2410的GPIO连接有所不同,修改其对GPIO和PLL的配置(请参阅SKY2440的硬件说明、2440芯片手册和提供的uboot相对应的文件):这个函数我想不用我解释了吧!其实有些IO口在驱动里可以重新设置,但有时没有必要单单写一个IO驱动,例如串口的端口设置需要将他设置为rx或tx用那就可以直接改这了。
......
#elifFCLK_SPEED==1/*Fout=405MHz*/
//#defineM_MDIV0x5c
//#defineM_PDIV0x4
//#defineM_SDIV0x0
#defineM_MDIV0x7f
#defineM_PDIV0x2
#defineM_SDIV0x1
......
#elifUSB_CLOCK==1
//#defineU_M_MDIV0x48
//#defineU_M_PDIV0x3
#defineU_M_MDIV0x38
#defineU_M_PDIV0x2
#defineU_M_SDIV0x2
......
/*setuptheI/Oports*/
gpio->GPACON=0x007FFFFF;
//gpio->GPBCON=0x00044556;
gpio->GPBCON=0x00055556;
......
/*archnumberofS3C2440-Board*/
gd->bd->bi_arch_number=MACH_TYPE_S3C2440;
机码ID号必须和内核的机码对上,我们的是168,你找到他不要另加一个,因为我就犯过这个错误,他本身里面就有一个,你得覆盖他,要不然他还会认他以前的那个号,别忘了他的配置文件,是按照行读的,一旦读到匹配的参数就会跳出循环,导致你在后面加的根本就没起上作用。
/*adressofbootparameters*/
gd->bd->bi_boot_params=0x30000100;
这个是内核的参数的起始地址,我们的板子内核是在0x30008000地址处,在从0x30000000到0x30008000的32kb之间存放的是内核页表和内核的启动参数,
icache_enable();
dcache_enable();
gpio->GPBDAT=0x180;//tekkamanninja
//intboard_init(void)设置完成后,LED1和LED2会亮起!
return0;
}
14.为了实现NANDFlash的读写,再次修改/include/configs/tekkaman2440.h
(请格外注意:如果编译时报错,在Linux下用KWrite等有高亮显示的文本编辑器看看文件的注释是不是为注释应有的颜色(KWrite中为灰色),如果不是,则将注释删除。因为#define后面的注释被认为是程序的一部分。建议注释和#define分行写)
......
/*
*HighLevelConfigurationOptions
*(easytochange)
*/
#defineCONFIG_ARM920T1/*ThisisanARM920TCore*/
#defineCONFIG_S3C24401/*inaSAMSUNGS3C2440SoC*/
#defineCONFIG_tekkaman24401/*onaSAMSUNGtekkaman2440Board*/
......
/***********************************************************
*Commanddefinition
***********************************************************/
#defineCONFIG_COMMANDS\
(CONFIG_CMD_DFL|\
CFG_CMD_CACHE|\
CFG_CMD_NAND|\
CFG_CMD_NET|\
/*CFG_CMD_EEPROM|*/\
/*CFG_CMD_I2C|*/\
/*CFG_CMD_USB|*/\
CFG_CMD_PING|\
CFG_CMD_ENV|\
CFG_CMD_REGINFO|\
CFG_CMD_DATE|\
CFG_CMD_DHCP|\
CFG_CMD_ELF)
/*thismustbeincludedAFTERthedefinitionofCONFIG_COMMANDS(ifany)*/
#include<cmd_confdefs.h>
#defineCFG_LONGHELP
/*undeftosavememory*/
#defineCFG_PROMPT"[Tekkaman2440]#"
/*MonitorCommandPrompt*/
#defineCFG_CBSIZE256
/*ConsoleI/OBufferSize*/
......
#defineCFG_LOAD_ADDR0x30008000
/*defaultloadaddress*/
......
/*TimeoutforFlashWrite*/
#defineCFG_ENV_IS_IN_NAND1
#defineCFG_ENV_OFFSET0X20000
//#defineENV_IS_EMBEDDED1
#defineCFG_NAND_LEGACY定义后便调用我们的board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函数进行nand初始化
#defineCFG_ENV_SIZE0x10000
/*TotalSizeofEnvironmentSector*/
/*----------------------------------------------------------------------
*NANDflashsettings
*/
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
#defineCFG_NAND_BASE0x4E000000
/*NandFlash控制器在SFR区起始寄存器地址*/
#defineCFG_MAX_NAND_DEVICE1
/*支持的最在NandFlash数据*/
#defineSECTORSIZE512
/*1页的大小*/
#defineNAND_SECTOR_SIZESECTORSIZE
#defineNAND_BLOCK_MASK511
/*页掩码*/
#defineADDR_COLUMN1
/*一个字节的Column地址*/
#defineADDR_PAGE3
/*3字节的页块地址!!!!!*/
#defineADDR_COLUMN_PAGE4
/*总共4字节的页块地址!!!!!*/
#defineNAND_ChipID_UNKNOWN0x00
/*未知芯片的ID号*/
#defineNAND_MAX_FLOORS1
#defineNAND_MAX_CHIPS1
/*NandFlash命令层底层接口函数*/
这些前面基本已经提到/*NandFlash命令层底层接口函数*/
#defineWRITE_NAND_COMMAND(d,adr){rNFCMD=d;}
#defineWRITE_NAND_ADDRESS(d,adr){rNFADDR=d;}
#defineWRITE_NAND(d,adr){rNFDATA=d;}
#defineREAD_NAND(adr)(rNFDATA)
#defineNAND_WAIT_READY(nand){while(!(rNFSTAT&(1<<0)));}
#defineNAND_DISABLE_CE(nand){rNFCONT|=(1<<1);}
#defineNAND_ENABLE_CE(nand){rNFCONT&=~(1<<1);}
#defineWRITE_NAND_COMMANDW(d,adr)NF_CmdW(d)
/*thefollowingfunctionsareNOP'sbecauseS3C24X0handlesthisinhardware*/
/*下面一组操作对NandFlash无效*/
#defineNAND_CTL_CLRALE(nandptr)
#defineNAND_CTL_SETALE(nandptr)
#defineNAND_CTL_CLRCLE(nandptr)
#defineNAND_CTL_SETCLE(nandptr)
/*允许NandFlash写校验*/
#defineCONFIG_MTD_NAND_VERIFY_WRITE1
......
定义了各个寄存器
#definerNFCONF(*(volatileunsignedint*)0x4e000000)
#definerNFCONT(*(volatileunsignedint*)0x4e000004)
#definerNFCMD(*(volatileunsignedchar*)0x4e000008)
#definerNFADDR(*(volatileunsignedchar*)0x4e00000c)
#definerNFDATA(*(volatileunsignedchar*)0x4e000010)
#definerNFSTAT(*(volatileunsignedint*)0x4e000020)
#definerNFECC(*(volatileunsignedint*)0x4e00002c)
#endif/*__CONFIG_H*/
注:下面的这些定义是SKY提供的uboot参数,请按照这个参数把/include/configs/tekkaman2440.h修改过来
#defineCONFIG_BOOTDELAY1模式选折延时时间
#defineCONFIG_BOOTARGS"noinitrdroot=/dev/mtdblock2init=/linuxrcconsole=ttySAC0"
这里设置的都是传递给内核的参数,
initrd的最初的目的是为了把kernel的启动分成两个阶段:在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的方式放在initrd中,这样就在启动过程中可以从initrd所mount的根文件系统中装载需要的模块。这样的一个好处就是在保持kernel不变的情况下,通过修改initrd中的内容就可以灵活的支持不同的硬件。在启动完成的最后阶段,根文件系统可以重新mount到其他设备上。如果把需要的功能全都编译到内核中(非模块方式),只需要一个内核文件即可,我们这里就没有用到它,
root=/dev/mtdblock2是指定文件系统路径,在dev/的第二个分区了
init=/linuxrc他是个脚本,放在文件系统的根目录下,里面是文件系统启动时要挂载所要执行的准备console=ttySAC0用哪个串口
#defineCONFIG_ETHADDR0a:1b:2c:3d:4e:5f网卡mac地址I,全国独一个啊
#defineCONFIG_NETMASK255.255.255.0
#defineCONFIG_IPADDR192.168.1.6
#defineCONFIG_SERVERIP192.168.1.8
/*#defineCONFIG_BOOTFILE"elinos-lart"*/
#defineCONFIG_BOOTCOMMAND"nboot0x320000000
0x4C000;bootm0x32000000"0x4C000是变动的值
nbootInAddrdevFlAddr
InAddr:需要装载到的内存的地址。
FlAddr:在nandflash上uImage存放的地址
dev:设备号
需要提前设置环境变量,否则nboot不会调用bootm
Tekkaman2440#setenvautostartyes
0x4C000是内核在nand中起始的地址,看nand分区那就可以了解它的由来,在这里我们将内核搬运到0x32000000处,跳到此处执行什么呢?此时把压缩的内核进行解压,解压代码在内核的头部,解压到0x30008000处,这就是内核的解压后的地址。我们的内核最终是从这里开始执行的。
15.在个文件中添加“CONFIG_S3C2440”,使得原来s3c2410的代码可以编译进来。
(1)/include/common.h文件的第454行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_LH7A40X)||defined(CONFIG_S3C2440)
(2)/include/s3c24x0.h文件的第85、95、99、110、148、404行:
#ifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(3)/cpu/arm920t/s3c24x0/interrupts.c文件的第33行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第38行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(4)/cpu/arm920t/s3c24x0/serial.c文件的第22行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第26行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
voidserial_setbrg(void)
{
S3C24X0_UART*constuart=S3C24X0_GetBase_UART(UART_NR);
inti;
unsignedintreg=0;
/*valueiscalculatedso:(int)(PCLK/16./baudrate)-1*/
reg=get_PCLK()/(16*gd->baudrate)-1;
/*FIFOenable,Tx/RxFIFOclear*/
uart->UFCON=0x00;
uart->UMCON=0x0;
/*Normal,Noparity,1stop,8bit*/
uart->ULCON=0x3;
......
}
(5)/cpu/arm920t/s3c24x0/speed.c文件的第33行:
#ifdefined(CONFIG_S3C2400)||defined(CONFIG_S3C2410)||defined(CONFIG_TRAB)||defined(CONFIG_S3C2440)
第37行:#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
顺便修改源代码,以匹配s3c2440:
staticulongget_PLLCLK(intpllreg)
{
......
m=((r&0xFF000)>>12)+8;
p=((r&0x003F0)>>4)+2;
s=r&0x3;
//tekkaman
#ifdefined(CONFIG_S3C2440)
if(pllreg==MPLL)
return((CONFIG_SYS_CLK_FREQ*m*2)/(p<<s));
elseif(pllreg==UPLL)
#endif
//tekkaman
return((CONFIG_SYS_CLK_FREQ*m)/(p<<s));
}
......
/*returnFCLKfrequency*/
ulongget_FCLK(void)
{
return(get_PLLCLK(MPLL));
}
/*returnHCLKfrequency*/
ulongget_HCLK(void)
{
S3C24X0_CLOCK_POWER*constclk_power=S3C24X0_GetBase_CLOCK_POWER();
if(clk_power->CLKDIVN&0x6)
{
if((clk_power->CLKDIVN&0x6)==2)return(get_FCLK()/2);
if((clk_power->CLKDIVN&0x6)==6)return((clk_power->CAMDIVN&0x100)?get_FCLK()/6:get_FCLK()/3);
if((clk_power->CLKDIVN&0x6)==4)return((clk_power->CAMDIVN&0x200)?get_FCLK()/8:get_FCLK()/4);
return(get_FCLK());
}
else{
return(get_FCLK());
}
}
......
(6)/cpu/arm920t/s3c24x0/usb_ohci.c文件的第45行:
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
(i2c的文件还没修改,因为没用到)
(7)/rtc/s3c24x0_rtc.c文件的第35行:
#elifdefined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
在个文件中添加“defined(CONFIG_tekkaman2440)”,使得原来SBC2410X的代码可以编译进来。
(1)/cpu/arm920t/s3c24x0/interrupts.c文件的第181行:
defined(CONFIG_VCMA9)||defined(CONFIG_tekkaman2440)
16.在include/linux/mtd/nand_ids.h的结构体nand_flash_ids加入
staticstructnand_flash_devnand_flash_ids[]={
......
{"SamsungKM29N16000",NAND_MFR_SAMSUNG,0x64,21,1,2,0x1000,0},
{"SamsungK9F1208U0B",NAND_MFR_SAMSUNG,0x76,26,0,3,0x4000,0},
{"Samsungunknown4Mb",NAND_MFR_SAMSUNG,0x6b,22,0,2,0x2000,0},
......
};
注:可参照SKY提供的uboot对应文件修改。
17.修改common/env_nand.c
......
[b]#ifdefCONFIG_INFERNO
#errorCONFIG_INFERNOnotsupportedyet
#endif
intnand_legacy_rw(structnand_chip*nand,intcmd,
size_tstart,size_tlen,
size_t*retlen,u_char*buf);
externstructnand_chipnand_dev_desc[CFG_MAX_NAND_DEVICE];
externintnand_legacy_erase(structnand_chip*nand,size_tofs,size_tlen,intclean);
/*infoforNANDchips,definedindrivers/nand/nand.c*/
externnand_info_tnand_info[CFG_MAX_NAND_DEVICE];
......
env将从永久性存储介质中搬到RAM里面,以后对env的操作,比如修改环境变量的值,删除环境变量的值都是对这个
env在RAM中的拷贝进行操作,由于RAM的特性,下次启动时所做的修改将全部消失,u-boot提供了将env写回永久性存储介质的命令支持
:saveenv,不同版本的env(nandflash,flash…)实现方式不同,以NandFlash的实现(未定义CFG_ENV_OFFSET_REDUND)为例,见下面的saveenv函数了,Nand
Flash的saveenv命令实现很简单,调用nand_erase和nand_write进行Nand
Flash的erase,write。nand_write/erase使用的是u-boot的nand驱动框架,我在做开发的过程中使用的是nand_legacy驱动,所以可以把nand_erase和nand_write改成nand_legacy_erase和nand_legacy_rw就可实现nand_legacy驱动的保存环境变量版本,这就是为什么注释掉nand_erase和
nand_write的原因了,哈哈,其实我也是才知道的,以前这块也有点糊涂[/b]
#else/*!CFG_ENV_OFFSET_REDUND*/完成对环境变量的存储
[b]intsaveenv(void)
{
ulongtotal;
intret=0;
puts("ErasingNand...");[/b]
UBOOT对NAND进行读写操作调用的函数在drivers/nand_legacy/nand_legacy。C函数里面的nand_legacy_erase先擦除要写的nand区,再调用nand_legacy_rw进行读写,不是调用nand_erase和
nand_write
//if(nand_erase(&nand_info[0],CFG_ENV_OFFSET,CFG_ENV_SIZE))
[b]if(nand_legacy_erase(nand_dev_desc+0,CFG_ENV_OFFSET,CFG_ENV_SIZE,0))
return1;
puts("WritingtoNand...");
total=CFG_ENV_SIZE;
//ret=nand_write(&nand_info[0],CFG_ENV_OFFSET,&total,(u_char*)env_ptr);[/b]
ret=nand_legacy_rw(nand_dev_desc+0,
0x00|0x02,CFG_ENV_OFFSET,CFG_ENV_SIZE,
&total,(u_char*)env_ptr);
if(ret||total!=CFG_ENV_SIZE)
return1;
puts("done\n");
returnret;
......
#else/*!CFG_ENV_OFFSET_REDUND*/
/*
*ThelegacyNANDcodesavedtheenvironmentinthefirstNANDdevicei.e.,
*nand_dev_desc+0.ThisisalsothebehaviourusingthenewNANDcode.
*/
voidenv_relocate_spec(void)完成环境变量的重新定位,把它从nand搬运到sdram里面
{
#if!defined(ENV_IS_EMBEDDED)env是否存在于u-bootTEXT段中
ulongtotal;
intret;
total=CFG_ENV_SIZE;env块的大小
u-boot在启动的时候会将存储在永久性存储介质中的env重新定位到RAM中,这样可以快速访问,同时可以通过saveenv将
RAM中的env
保存到永久性存储介质中。实际上还需要几个宏来控制u-boot对环境变量的处理。CFG_ENV_OFFSET:env块在
Flash中偏移地址。env_ptr:最终完成将环境变量搬移到内存地址。
//ret=nand_read(&nand_info[0],CFG_ENV_OFFSET,&total,(u_char*)env_ptr);
ret=nand_legacy_rw(nand_dev_desc+0,0x01|0x02,CFG_ENV_OFFSET,CFG_ENV_SIZE,&total,(u_char*)env_ptr);
......
上面的代码很清楚的表明了env_relocate_spec的意图,调用nand_read将环境变量从CFG_ENV_OFFSET处读出,环境变量的大小为
CFG_ENV_SIZE注意CFG_ENV_OFFSET和CFG_ENV_SIZE要和Nand
Flash的块/页边界对齐。读出数据后再调用crc32对env_ptr->data进行校验并与保存在
env_ptr->crc的校验码对比,看数据是否出错,从这里也可以看出在系统第一次启动时,NandFlash里面没有存储任何环境变量,crc校验肯定回出错,当我们保存环境变量后,接下来再启动板子u-boot就不会再报crc32出错了。
18.在/board/tekkaman/tekkaman2440/tekkaman2440.c文件的末尾添加对NandFlash的初始化函数(在后面Nand
Flash的操作都要用到)
u-boot运行至第二阶段进入start_armboot()函数。其中nand_init()函数是对nand
flash的最初初始化函数。Nand_init()函数在两个文件中实现。其调用与CFG_NAND_LEGACY宏有关,如果没有定义这个宏,系统调用
drivers/nand/nand.c中的nand_init();否则调用自己在board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函数。这里我选择第二种方式。
这些代码很简单的都是操作他的物理地址,对照数据手册就会很清楚他的用意,它主要就是完成对nand的初始化,设置好nand的寄存器。为了便于大家理解他,我把我的参考资料贴在这,看了便知道了!!!!!
Nandflash主要内设命令详细介绍
NandFlash命令执行是通过将命令字送到NandFlash控制器的命令寄存器来执行。
NandFlash的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周
期将要执行的动作。
主要命令有:Read1、Read2、ReadID、Reset、Page
Program、BlockErase、ReadStatus。
详细介绍如下:
1.Read1:
功能:表示将要读取Nandflash存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。
命令代码:00h
2.Read2:
功能:表示将要读取Nandflash存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。
命令代码:01h
3.ReadID:
功能:读取Nandflash芯片的ID号
命令代码:90h
4.Reset:
功能:重启芯片。
命令代码:FFh
5.PageProgram:
功能:对页进行编程命令,用于写操作。
命令代码:首先写入00h(A区)/01h(B区)/05h(C区),表示写入那个区;再写入80h开始编程模式(写入模式),接
下来写入地址和数据;最后写入10h表示编程结束.
6.BlockErase
功能:块擦除命令。
命令代码:首先写入60h进入擦写模式,然后输入块地址;接下来写入D0h,表示擦写结束.
7.ReadStatus
功能:读取内部状态寄存器值命令。
命令代码:70h
NandFlash控制器工作原理
对NandFlash存储芯片进行操作,必须通过NandFlash控制器的专用寄存器才能完成。所以,不能对Nand
Flash进行总线操作。而NandFlash的写操作也必须块方式进行。对NandFlash的读操作可以按字节读取。
NandFlash控制器特性
1.支持对NandFlash芯片的读、检验、编程控制
2.如果支持从NandFlash启动,在每次重启后自动将前Nand
Flash的前4KB数据搬运到ARM的内部RAM中
3.支持ECC校验
NandFlash控制器工作原理
NandFlash控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将Nand
Flash芯片的内设命令写到其特殊功能寄存器中,从而实现对Nandflash芯片读、检验和编程控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。
Nandflash控制器中特殊功能寄存器详细介绍
1.配置寄存器(NFCONF)
功能:用于对NandFlash控制器的配置状态进行控制。
在地址空间中地址:0x4E000000,其中:
Bit15:NandFlash控制器使能位,置0代表禁止Nand
Flash控制器,置1代表激活NandFlash控制器;
要想访问NandFlash芯片上存储空间,必须激活NandFlash控制器。在复位后该位自动置0,因此在初始化时
必须将该位置为1。
Bit12:初始化ECC位,置1为初始化ECC;置0为不初始化ECC。
Bit11:NandFlash芯片存储空间使能位,置0代表可以对存储空间进行操作;置1代表禁止对存储空
间进行操作。在复位后,该位自动为1。
Bit10-8:TACLS位。根据此设定CLE&ALE的周期。TACLS的值范围在0-7之间。
Bit6-4、2-0分别为:TWRPH0、TWRPH1位。设定写操作的访问周期。其值在0-7之间。
2.命令寄存器(NFCMD)
功能:用于存放Nandflash芯片内设的操作命令。
在地址空间中地址:0x4E000004,其中:
Bit0-7:存放具体Nandflash芯片内设的命令值。其余位保留以后用。
3.地址寄存器(NFADDR)
功能:用于存放用于对Nandflash芯片存储单元寻址的地址值。
在地址空间中地址:0x4E000008,其中:
Bit0-7:用于存放地址值。因为本款Nandflash芯片只有I/O0-7的地址/数据复用引脚且地址是四周
期每次8位送入的,所以这里只用到8位。其余位保留待用。
4.数据寄存器(NFDATA)
功能:Nandflash芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入Nandflash
存储空间的值也是放到该寄存器。
在地址空间中地址:0x4E00000C,其中:
Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。
5.状态寄存器(NFSTAT)
功能:用于检测Nandflash芯片上次对其存储空间的操作是否完成。
在地址空间中地址:0x4E000010,其中:
Bit0:置0表示Nandflash芯片正忙于上次对存储空间的操作;置1表示Nand
flash芯片准备好接收新
的对存储空间操作的请求。
6.ECC校验寄存器(NFECC)
功能:ECC校验寄存器
在地址空间中地址:0x4E000014,其中:
Bit0Bit7:
ECC0
Bit8Bit15:
ECC1
Bit16Bit23:
ECC2
操作的函数实现
1.发送命令
#defineNF_CMD(cmd){rNFCMD=cmd;}
2.写入地址
#defineNF_ADDR(addr){rNFADDR=addr;}
3.NandFlash芯片选中
#defineNF_nFCE_L(){rNFCONF&=~(1<<11);}
4.NandFlash芯片不选中
#defineNF_nFCE_H(){rNFCONF|=(1<<11);}
5.初始化ECC
#defineNF_RSTECC(){rNFCONF|=(1<<12);}
6.读数据
#defineNF_RDDATA()(rNFDATA)
7.写数据
#defineNF_WRDATA(data){rNFDATA=data;}
8.获取NandFlash芯片状态
#defineNF_WAITRB(){while(!(rNFSTAT&(1<<0)));}
0/假:表示NandFlash芯片忙状态
1/真:表示NandFlash已经准备好
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
typedefenum{
NFCE_LOW,
NFCE_HIGH
}NFCE_STATE;
staticinlinevoidNF_Conf(u16conf)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONF=conf;
}
staticinlinevoidNF_Cont(u16cont)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONT=cont;
}
staticinlinevoidNF_Cmd(u8cmd)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCMD=cmd;
}
staticinlinevoidNF_CmdW(u8cmd)
{
NF_Cmd(cmd);
udelay(1);
}
staticinlinevoidNF_Addr(u8addr)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFADDR=addr;
}
staticinlinevoidNF_SetCE(NFCE_STATEs)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
switch(s){
caseNFCE_LOW:
nand->NFCONT&=~(1<<1);
break;
caseNFCE_HIGH:
nand->NFCONT|=(1<<1);
break;
}
}
staticinlinevoidNF_WaitRB(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
while(!(nand->NFSTAT&(1<<0)));
}
staticinlinevoidNF_Write(u8data)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFDATA=data;
}
staticinlineu8NF_Read(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
return(nand->NFDATA);
}
staticinlinevoidNF_Init_ECC(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
nand->NFCONT|=(1<<4);
}
staticinlineu32NF_Read_ECC(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
return(nand->NFECC);
}
#endif
#if(CONFIG_COMMANDS&CFG_CMD_NAND)
externulongnand_probe(ulongphysadr);
staticinlinevoidNF_Reset(void)
{
inti;
NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF);/*resetcommand*/
for(i=0;i<10;i++);/*tWB=100ns.*/
NF_WaitRB();/*wait200~500us;*/
NF_SetCE(NFCE_HIGH);
}
staticinlinevoidNF_Init(void)
{
#if0/*alittlebittoooptimistic*/
#defineTACLS0
#defineTWRPH03
#defineTWRPH10
#else
#defineTACLS0
#defineTWRPH04
#defineTWRPH12
#endif
NF_Conf((TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4));
NF_Cont((1<<6)|(1<<4)|(1<<1)|(1<<0));
/*nand->NFCONF=(1<<15)|(1<<14)|(1<<13)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);*/
/*1111,1xxx,rxxx,rxxx*/
/*En512B4stepECCRnFCE=HtACLStWRPH0tWRPH1*/
NF_Reset();
}
void
nand_init(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
NF_Init();
#ifdefDEBUG
printf("NANDflashprobingat0x%.8lX\n",(ulong)nand);
#endif
printf("%4luMB\n",nand_probe((ulong)nand)>>20);
}
#endif
19.在/include/s3c24x0.h中加入2440的NANDFLASH寄存器定义和CAMDIVN定义:
......
typedefstruct{
S3C24X0_REG32LOCKTIME;
S3C24X0_REG32MPLLCON;
S3C24X0_REG32UPLLCON;
S3C24X0_REG32CLKCON;
S3C24X0_REG32CLKSLOW;
S3C24X0_REG32CLKDIVN;
S3C24X0_REG32CAMDIVN;
}/*__attribute__((__packed__))*/S3C24X0_CLOCK_POWER;
......
#ifdefined(CONFIG_S3C2410)
/*NANDFLASH(seeS3C2410manualchapter6)*/
typedefstruct{
S3C24X0_REG32NFCONF;
S3C24X0_REG32NFCMD;
S3C24X0_REG32NFADDR;
S3C24X0_REG32NFDATA;
S3C24X0_REG32NFSTAT;
S3C24X0_REG32NFECC;
}/*__attribute__((__packed__))*/S3C2410_NAND;
#endif
#ifdefined(CONFIG_S3C2440)
/*NANDFLASH(seeS3C2440manualchapter6)*/
typedefstruct{
S3C24X0_REG32NFCONF;
S3C24X0_REG32NFCONT;
S3C24X0_REG32NFCMD;
S3C24X0_REG32NFADDR;
S3C24X0_REG32NFDATA;
S3C24X0_REG32NFMECC0;
S3C24X0_REG32NFMECC1;
S3C24X0_REG32NFSECC;
S3C24X0_REG32NFSTAT;
S3C24X0_REG32NFESTAT0;
S3C24X0_REG32NFESTAT1;
S3C24X0_REG32NFECC;
}/*__attribute__((__packed__))*/S3C2410_NAND;
#endif
20.移植DM9000网卡
在/include/configs/tekkaman2440.h文件中修改添加对DM9000的支持,屏蔽CS8900:
/*
*Hardwaredrivers
*/
//#defineCONFIG_DRIVER_CS89001/*wehaveaCS8900on-board*/
//#defineCS8900_BASE0x19000300
//#defineCS8900_BUS161/*theLinuxdriverdoesaccessesasshorts*/
#defineCONFIG_DRIVER_DM90001
#defineCONFIG_DM9000_BASE0x20000300
#defineDM9000_IOCONFIG_DM9000_BASE
#defineDM9000_DATA(CONFIG_DM9000_BASE+4)
#defineCONFIG_DM9000_USE_16BIT
在这里#defineCONFIG_DM9000_BASE的定义最为重要。不同的板子只要修改这个参数即可。
我是按照SKY提供的Uboot代码的对应文件的参数修改的。
修正BUG(修改/drivers/dm9000.c文件)
(1)网卡MAC地址错误的解决方法:
/*Initilizedm9000board
*/
int
eth_init(bd_t*bd)
{
......
/*SetNodeaddress*/
/*for(i=0;i<6;i++)
((u16*)bd->bi_enetaddr)[i]=read_srom_word(i);
*/
//tekkamanninja
char*tmp=getenv("ethaddr");
char*end;
for(i=0;i<6;i++){
bd->bi_enetaddr[i]=tmp?simple_strtoul(tmp,&end,16):0;
if(tmp)
tmp=(*end)?end+1:end;
}
//tekkamanninja
printf("MAC:%02x:%02x:%02x:%02x:%02x:%02x\n",bd->bi_enetaddr[0],
bd->bi_enetaddr[1],bd->bi_enetaddr[2],bd->bi_enetaddr[3],
bd->bi_enetaddr[4],bd->bi_enetaddr[5]);
......
红色的字符是要做的修改:功能是屏蔽原有获取MAC地址的语句,替换成从U-Boot的参数区读取数据并存到bd->bi_enetaddr[i]中。
(2)“couldnotestablishlink”提示和慢响应的解决方法:
/*Initilizedm9000board
*/
int
eth_init(bd_t*bd)
{
......
DM9000_iow(DM9000_RCR,RCR_DIS_LONG|RCR_DIS_CRC|RCR_RXEN);/*RXenable*/
DM9000_iow(DM9000_IMR,IMR_PAR);/*EnableTX/RXinterruptmask*/
#if0
i=0;
while(!(phy_read(1)&0x20)){/*autonegationcompletebit*/
udelay(1000);
i++;
if(i==10000){
printf("couldnotestablishlink\n");
return0;
}
printf("link=%d\n",i);
}
/*seewhatwe'vegot*/
lnk=phy_read(17)>>12;
printf("operatingat");
switch(lnk){
case1:
printf("10Mhalfduplex");
break;
case2:
printf("10Mfullduplex");
break;
case4:
printf("100Mhalfduplex");
break;
case8:
printf("100Mfullduplex");
break;
default:
printf("unknown:%d",lnk);
break;
}
printf("mode\n");
#endif
return0;
}
红色的字符是要做的修改:功能是屏蔽无用的语句。其实被屏蔽的语句是MII接口用的,放在这显然是错误的,无端的浪费了10秒钟。
21.编译修改好的代码:
maketekkaman2440_config;make;
在uboot的根目录下你就可以看到uboot的镜像文件了,烧到flash中就可以了。
以上生成的uboot镜像,网络似乎不大行,ping主机ping不通。SKY提供的uboot也是一样的问题,ping不通。
还有一点需要说明的是:UBOOT在启动内核的时候,还需要识别ID,需要UBOOT的ID和内核的ID相同,这个可以通过uboot的bdinfo命令看到UBOOT里设置的ID。SKY提供的UBOOT的ID和内核的ID是经过修改的。所以前面生成的UBOOT镜像会启动不了SKY提供的内核。
你打开SKY提供的UBOOT代码,include\asm-arm\mach-types.h,你将会发现第183行和377行的改动。
所以如果你想用前面生成的UBOOT启动SKY提供的内核的话,那么include\asm-arm\mach-types.h的377行也要修改成#define
MACH_TYPE_S3C2440168,这样就可以启动了。
现在的uboot只有一些基本的功能,最近从网上(http://www.100ask.net/showtopic-544.aspx)弄了个uboot1.1.6,支持S3C24x0/yaffs/USB/CS8900/DM9000/OpenJTAG/Nor,Nand启动的u-boot,回头再试一试。
二、linux2.6.24.4移植
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址
另外也参考了
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.解压linux-2.6.24.4,和arm-linux-gcc-3.4.1
2.进入linux-2.6.24.4根目录,修改makefile文件
vimakefile
第193行改为:
ARCH=arm
CROSS_COMPILE=/usr/local/arm/3.4.1/bin/arm-linux-告诉交叉编译器的路径
CROSS_COMPILE根据你自己arm-linux-gcc-3.4.1安装的路径设置.
3.修改arch/arm/plat-s3c24xx/common-smdk.c文件,修改NAND_FLASH分区信息和硬件信息.
根据SKY的板子,我设置如下:
这个结构体是设置nand的分区情况的
staticstructmtd_partitionsmdk_default_nand_part[]={
[0]={
.name=“UBOOT”,
.size=SZ_64K*4,//0x0~0x40000,256K
.offset=0,
},
[1]={
.name=“kernel2.6.24.4”,
.size=SZ_2M,//0x4c000~0x200000+0x4c000,2M
.offset=SZ_64K*4+SZ_16K*3,
},
[2]={
.name=“rootfs”,
.size=SZ_64K*987,//0x0024c000~0x03db0000+0x0024c000
.offset=SZ_2M+SZ_64K*4+SZ_16K*3,
}
};
另外修改smdk_nand_info,如下:
staticstructs3c2410_platform_nandsmdk_nand_info={
.tacls=0,
.twrph0=30,
.twrph1=0,
.nr_sets=ARRAY_SIZE(smdk_nand_sets),应该为初始化nand的设置结构体
.sets=smdk_nand_sets,应该为初始化nand的设置结构体
};
4.修改时钟:arch/arm/mach-s3c2440/mach-smdk2440.c
staticvoid__initsmdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000);外部的晶振的频率是12MHz
s3c24xx_init_uarts(smdk2440_uartcfgs,ARRAY_SIZE(smdk2440_uartcfgs));
}
开发板的mapio的初始化。首先我来讲解一下我对io内存映射的理解,io内存是具有物理地址的
关于IO与内存空间:
在X86处理器中存在着I/O空间的概念,I/O空间是相对于内存空间而言的,它通过特定的指令in、out来访问。端口号标识了外设的寄存器地址。Intel语法的in、out指令格式为:
IN累加器,{端口号│DX}
OUT{端口号│DX},累加器
目前,大多数嵌入式微控制器如ARM、PowerPC等中并不提供I/O空间,而仅存在内存空间。内存空间可以直接通过地址、指针来访问,程序和程序运行中使用的变量和其他数据都存在于内存空间中。
即便是在X86处理器中,虽然提供了I/O空间,如果由我们自己设计电路板,外设仍然可以只挂接在内存空间。此时,CPU可以像访问一个内存单元那样访问外设I/O端口,而不需要设立专门的I/O指令。因此,内存空间是必须的,而I/O空间是可选的。
因此你现在应该明白了大多数嵌入式处理器为什么都采用io内存映射,这样会使操作io口像操作内存一样,并不需要特殊的指令,我们将io的物理地址也就是数据手册上写的寄存器的地址将他进行内存映射,这就是所谓的io内存映射,映射后的地址当然是虚拟地址了,这样我们操作这个虚拟地址就等于操作io。
在Linux设备驱动中,宜使用Linux内核提供的函数来访问定位于I/O空间的端口,这些函数包括:
·读写字节端口(8位宽)
unsignedinb(unsignedport);
voidoutb(unsignedcharbyte,unsignedport);
·读写字端口(16位宽)
unsignedinw(unsignedport);
voidoutw(unsignedshortword,unsignedport);
·读写长字端口(32位宽)
unsignedinl(unsignedport);
voidoutl(unsignedlongword,unsignedport);
·读写一串字节
voidinsb(unsignedport,void*addr,unsignedlongcount);
voidoutsb(unsignedport,void*addr,unsignedlongcount);
·insb()从端口port开始读count个字节端口,并将读取结果写入addr指向的内存;outsb()将addr指向的内存的count个字节连续地写入port开始的端口。
·读写一串字
voidinsw(unsignedport,void*addr,unsignedlongcount);
voidoutsw(unsignedport,void*addr,unsignedlongcount);
·读写一串长字
voidinsl(unsignedport,void*addr,unsignedlongcount);
voidoutsl(unsignedport,void*addr,unsignedlongcount);
上述各函数中I/O端口号port的类型高度依赖于具体的硬件平台,因此,只是写出了unsigned。
(3)readb和writeb:
在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是工程师宜使用Linux内核的如下一组函数来完成设备内存映射的虚拟地址的读写,这些函数包括:
·读I/O内存
unsignedintioread8(void*addr);
unsignedintioread16(void*addr);
unsignedintioread32(void*addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
unsignedreadb(address);
unsignedreadw(address);
unsignedreadl(address);
·写I/O内存
voidiowrite8(u8value,void*addr);
voidiowrite16(u16value,void*addr);
voidiowrite32(u32value,void*addr);
与上述函数对应的较早版本的函数为(这些函数在Linux2.6中仍然被支持):
voidwriteb(unsignedvalue,address);
voidwritew(unsignedvalue,address);
voidwritel(unsignedvalue,address);
(4)把I/O端口映射到“内存空间”:
void*ioport_map(unsignedlongport,unsignedintcount);
通过这个函数,可以把port开始的count个连续的I/O端口重映射为一段“内存空间”。然后就可以在其返回的地址上像访问I/O内存一样访问这些I/O端口。当不再需要这种映射时,需要调用下面的函数来撤消:
voidioport_unmap(void*addr);
实际上,分析ioport_map()的源代码可发现,所谓的映射到内存空间行为实际上是给开发人员制造的一个“假象”,并没有映射到内核虚拟地址,仅仅是为了让工程师可使用统一的I/O内存访问接口访问I/O端口。
在S3C2410的Linux里面,全部都会做phy->virt的映射。映射方式中的一种是静态映射,ioremap是动态映射。在静态映射之后,仍然可以通过ioremap动态映射,也就是一个IO物理地址可以映射到多个虚拟地址。
其实所谓的内存映射,也不要想的那么复杂,你可以看看上面的从物理地址到虚拟地址的映射,其实就是一个地址变化。建立一个对应关系,那你会纳闷为什么建立这个对应关系,首先你要知道我们这些操作都是在内核里的,内核操作的也是虚拟地址,我们这块用的虚拟地址和物理地址只存在简单的线性关系,在这里我就不多解释了,嘿嘿,懒着写,记住google是你的最好老师!!!
smdk2440_map_io函数中会调用:
s3c24xx_init_io(smdk2440_iodesc,ARRAY_SIZE(smdk2440_iodesc));
而开发板相关的内存映射在smdk2440_iodesc,有ISA,声卡,网卡等。
定义如下:
staticstructmap_descsmdk2440_iodesc[]__initdata={
/*ISAIOSpacemap(memoryspaceselectedbyA24)*/
{(u32)S3C24XX_VA_ISA_WORD,S3C2410_CS2,SZ_16M,MT_DEVICE},
{(u32)S3C24XX_VA_ISA_BYTE,S3C2410_CS2,SZ_16M,MT_DEVICE},
};
2.s3c24xx_init_io函数会调用:iotable_init(s3c_iodesc,ARRAY_SIZE(s3c_iodesc));
而s3c_iodesc定义如下:
/*minimalIOmapping*/
staticstructmap_descs3c_iodesc[]__initdata={
IODESC_ENT(GPIO),
IODESC_ENT(IRQ),
IODESC_ENT(MEMCTRL),
IODESC_ENT(UART)
};
这个部分是系统启动必须的映射。
后续会调用(cpu->map_io)(mach_desc,size);来完成其他映射。
这个函数会调用iotable_init(s3c2440_iodesc,ARRAY_SIZE(s3c2440_iodesc));
定义如下:
staticstructmap_descs3c2440_iodesc[]__initdata={
IODESC_ENT(USBHOST),
IODESC_ENT(USBDEV),
IODESC_ENT(CLKPWR),
IODESC_ENT(LCD),
IODESC_ENT(TIMER),
IODESC_ENT(ADC),
IODESC_ENT(WATCHDOG),
};
综合上述发现,如果一个新加驱动,首先要看是否完成了IO映射,如果没有的话,就在开发板部分加入。
5.修改nandflash的校验方式,去掉ECC校验
在drivers/mtd/nand/s3c2410.c的第699行
将chip->ecc.mode=NAND_ECC_SOFT;
改为chip->ecc.mode=NAND_ECC_NONE;
网上有的blog上不用去掉也可以,编译不会出错,但是我没有试验过,我是把ECC校验去掉的了.(经测试,这个不用改也可以)
6.增加Yaffs2文件系统的支持
下载Yaffs2:
解压yaffs2并将其加入linux内核(打补丁的方式):
cdyaffs2
./patch-ker.shc/home/dk/myboard/linux-2.6.24.4/
./patch-ker.shc后面跟的是你linux解压所在的路径.打完包后,在内核fs文件夹下将会多了yaffs文件夹,同事makefile文件也自动修改了.
7.为了内核支持devfs以及在启动是并在/sbin/init运行之前自动挂载/dev为devfs文件系统,编辑fs/Kconfig:
在906行menu“Pseudofilesystems”下面添加如下代码:
configDEVFS_FS
bool“/devfilesystemsupport(OBSOLETE)”
defaulty
configDEVFS_MOUNT
bool“Automaticallymountatboot”
defaulty
dependsonDEVFS_FS
有的blog说不需要增加这一段,因为2.6.24.4已经把devfs的相关代码删除了,即使添加了也没有用.我在移植内核的时候还是加上了这段代码,不加的编译情况还没有试.(经测试,这段现在不加也可以)
8.复制编译配置文件到2.6.24.4内核根目录下.
cparch/arm/configs/s3c2410_defconfig.config
将config覆盖掉,他是内核的配置,我们在图形界面下配置内核后的最终保存结果就是变成了config文件,我们用s3c2410_defconfig的配置,是因为他接近我们的2440的配置,再此基础上修改内核配置。
9.编译内核选项:makemenuconfig
[*]Enableloadablemodulesupport--->
[*]Moduleunloading
[*]Automatickernelmoduleloading
选择这两个,剩下的可以去掉
SystemType---->
[*]S3C2410DMAsupport
[*]SupportARM920Tprocessor
S3C2410Machines--->
[*]SMDK2410/A9M2410
S3C2440Machines--->
[*]SMDK2440
[*]SMDK2440withS3C2440CPUmodule
SystemType这部分,只选这些,其他可以全部去掉。另外,网上一些帖子都说只选上SMDK2440就可以了,其他的都去掉,我没有试,不知道行不行.(经过测试,必须SMDK2410的选项)
Bootoption----->
修改启动参数为:
noinitrdroot=/dev/mtdblock2init=/linuxrcconsole=ttySAC0,115200
可能根据个人板子的设置会不一样,我的是从NandFlash中加载文件系统,其中mtdblock2是存放我的Linux文件系统的分区。不过,在bootloader可以传递内核参数的情况下这个设置是无效的。
Userspacebinaryformats--->
<>Kernelsupportfora.outandECOFFbinaries
(去除该选项,a.out和ECOFF是两种可执行文件的格式,在ARM-Linux下一般都用ELF,所以这两种基本用不上。)
DeviceDrivers--->
<*>MemoryTechnologyDevice(MTD)support--->
[*]MTDpartitioningsupport
<*>NANDDeviceSupport--->
<*>NANDFlashsupportforS3C2410/S3C2440SoC
[]S3C2410NANDHardwareECC//这个要去掉
[*]Networkdevicesupport--->
[*]Ethernet(10or100Mbit)--->
<*>DM9000support
<*>RealTimeClock--->
“N”掉
[]SetsystemtimefromRTConstartupandresume
去掉红字的两个部分,黑子部分选上,其他的选择默认就可以了。
Filesystems-->
<>Secondextendedfssupport#去除对ext2的支持
<>Ext3journallingfilesystemsupport#去除对ext3的支持
<*>Kernelautomountersupport
<*>Kernelautomounterversion4support(alsosupportsv3)
<*>FilesysteminUserspacesupport
Pseudofilesystems-->
[*]Virtualmemoryfilesystemsupport(formershmfs)
<*>Userspace-drivenconfigurationfilesystem(EXPERIMENTAL)
Miscellaneousfilesystems-->
<*>YAFFS2filesystemsupport
“N”掉[]Autoselectyaffs2format和
[]CacheshortnamesinRAM,因为这是给每页大于1024B的NANDFlash设计的
<*>JournallingFlashFileSystemv2(JFFS2)support
(0)JFFS2debuggingverbosity(0=quiet,2=noisy)
[*]JFFS2write-bufferingsupport
[]JFFS2summarysupport(EXPERIMENTAL)
[]JFFS2XATTRsupport(EXPERIMENTAL)
[*]AdvancedcompressionoptionsforJFFS2
[*]JFFS2ZLIBcompressionsupport
[*]JFFS2RTIMEcompressionsupport
[*]JFFS2RUBINcompressionsupport
JFFS2defaultcompressionmode(priority)--->
NetworkFileSystems-->
<*>NFSfilesystemsupport
--以下最好选上,因为在挂载NFS时可能出现protocol不支持的情况--
[*]ProvideNFSv3clientsupport
[*]ProvideclientsupportfortheNFSv3ACLprotocolextension
[*]ProvideNFSv4clientsupport(EXPERIMENTAL)
[*]AllowdirectI/OonNFSfiles
-------------------------------------------------------------------------
<*>NFSserversupport
[*]ProvideNFSv3serversupport
[*]ProvideserversupportfortheNFSv3ACLprotocolextension
[*]ProvideNFSv4serversupport(EXPERIMENTAL)
---ProvideNFSserveroverTCPsupport
[*]RootfilesystemonNFS
注:我后面用到的根文件系统是cramfs或yaffs.
10.ok,先编译一下内核,makezIamge.编译完在arch/arm/boot下将会有一个zImage文件.
11.生成uboot用的uImage.
Uboot使用的镜像和zImage有点区别,具体可以网上搜一下.
先把Uboot编译后生成的tools/mkImage文件copy到主机的/bin下,然后进入到linux-2.6.24.4内核的根目录下,在执行一下makeuImage命令,等上一会就会在arch/arm/boot下将会有一个uImage文件.
最后下载到开发板上试试吧.目前的内核网卡、液晶等驱动都还没有移植。
需要说明的,这个新的内核和SKY提供的yaffs文件不匹配,相比于以前的2.6.13之类,内核中修改了oob的使用,主要就是ECC较验码的位置。但是,yaffs那帮人没有同步修改mkyaffsimg,这需要自己做。好在我在网上(http://www.100ask.net/showtopic-177.aspx)找到了mkyaffsimg的补丁.
另外一个问题就是uboot移植中说到的ID不匹配的问题,如果你用的uboot是SKY提供的,那么需要将arch\arm\tools\mach-types文件中的一行s3c2440ARCH_S3C2440
S3C2440362
改成s3c2440ARCH_S3C2440S3C2440168即可.
三、根文件系统的设计(带用户登录)
移植环境:VMware5.5.2+redhat9(非root登录,需要切换到root下执行的另外指出)
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
Busybox:busybox-1.9.2.tar.bz2(
Tinylogin:tinylogin-snapshot.tar.bz2(
Cramfs制作工具:cramfs-1.1.tar.gz(http://sourceforge.net/projects/cramfs/)
先说明一下,移植过程按照tekkaman的blog移植的。
博客地址
其中参照http://blog.chinaunix.net/u1/34474/showart_485837.html做的。
所下面写的移植过程,很多都是从blog上copy过来的,有不同的地方,我会另外指出。
1.创建根文件系统的基本目录结构。
我把这个过程做成了shell脚本(文件名为mkroot),很方便!
#!/bin/sh
echo"creatintrootfsdir......"
mkdirrootfs
cdrootfs
echo"makingdir:bindevetclibprocsbinsysusr"
mkdirbindevetclibprocsbinsysusr#必备的8个目录
mkdirusr/binusr/libusr/sbinlib/modules
#Don'tusemknod,unlessyourunthisScriptasroot
#mknod-m600dev/consolec51
#mknod-m666dev/nullc13
echo"makingdir:mnttmpvar"
mkdirmnttmpvar
chmod1777tmp
mkdirmnt/etcmnt/jffs2mnt/yaffsmnt/datamnt/temp
mkdirvar/libvar/lockvar/logvar/runvar/tmp
chmod1777var/tmp
echo"makingdir:homerootboot"
mkdirhomerootboot
echo"done"
有一点需要注意,在windows下的回车和linux下的回车不一样,如果你是在windows下把这个脚本编辑好的,那么在linux下运行会有点问题。
在你想要建立根文件系统的地方,运行:
./mkroot
2.进入到dev文件夹创建两个设备文件,需要用root登录创建
Mknod–m600consolec51;mknod–m666nullc13;
3.配置、编译、安装busybox-1.9.2
(1)解压busybox-1.9.2
(2)修改makefile文件(在174行附近)
ARCH=arm
CROSS_COMPILE=/usr/local/arm/3.4.1/bin/arm-linux-
(3)配置busybox:makemenuconfig
在原有的基础上修改如下:
BusyboxSettings--->
InstallationOptions--->
[*]Don'tuse/usr
(前面创建的rootfs所在路径)BusyBoxinstallationprefix
BusyboxLibraryTuning--->
[*]Supportfor/etc/networks
[*]Additionaleditingkeys
[*]vi-stylelineeditingcommands
(15)Historysize
[*]Historysaving
[*]Tabcompletion
[*]Usernamecompletion
[*]Fancyshellprompts
Login/PasswordManagementUtilities--->选项全部N掉,后面单独使用TinyLogin。(因为集成的好像不是很好用,我自己的经验是这样)
LinuxModuleUtilities--->
Supportversion2.2.xto2.4.xLinuxkernels
Shells--->
---AshShellOptions
下的选项全选
(4)编译、安装
执行make;makeinstall
执行之后,将会在你的rootfs的bin,sbin下创建一些文件,同时在rootfs下生成一个linuxrc文件。
4.修改必要的文件
(1)将busybox-1.9.2下的examples/bootfloppy/etc/下的文件copy到rootfs/etc下
cp–a.../examples/bootfloppy/etc/*…/rootfs/etc/
cd…/rootfs/etc
(2)增加为shell导入全局变量的文件/etc/profile
viprofile
修改如下:
#/etc/profile:system-wide.profilefilefortheBourneshells
echo
echo"Processing/etc/profile..."
#no-op
#Setsearchlibrarypath
echo"Setsearchlibrarypathin/etc/profile"
exportLD_LIBRARY_PATH=/lib:/usr/lib
#Setuserpath
echo"Setuserpathin/etc/profile"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
exportPATH
#SetPS1
#注意:ash除了SHELL变量外,支持\u、\h、\W、\$、\!、\n、\w、\nnn(ASCII字符对应的八进制数)
#以及\e[xx;xxm(彩色特效)等等!
#而且前面还要多加一个
'\'!
echo"SetPS1in/etc/profile"
exportPS1="\\e[05;32m[$USER@\\w\\a]\\$\\e[00;34m"
echo"Done"
echo
(3)增加初始化文件/etc/inittab,/etc/fstab
viinittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/login
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount-a–r
::shutdown:/sbin/swapoff–a
Vifstab
proc/procprocdefaults00
none/tmpramfsdefaults00
mdev/devramfsdefaults00
sysfs/syssysfsdefaults00
(4)增加初始化脚本/etc/init.d/rcS(如果init.d文件夹没有创建,先创建该文件夹)
Viinit.d/rcS
#!/bin/sh
echo"----------mountall"
/bin/mount–a
echo"----------Startingmdev......"
/bin/echo/sbin/mdev>/proc/sys/kernel/hotplug
mdev–s
(5)删除etc/下的备份文件
rm*~init.d/*~
(6)为mdev创建配置文件,在etc/下
Vimdev.conf
创建一个mdev.conf文件,内容可有可无。
5.为使用用户登录功能移植tinylogin
(1)下载、解压
(2)修改tinylogin的makefile
USE_SYSTEM_PWD_GRP=false
......
CROSS=/usr/local/arm/3.4.1/arm-linux-
CC=$(CROSS)gcc
AR=$(CROSS)ar
STRIPTOOL=$(CROSS)strip
(3)编译并安装,需要用root编译安装
makePREFIX=…/rootfsinstall
PREFIX=用来指定安装路径,我这里的路径为rootfs的根目录.安装完之后会在bin,usr/bin下生成几个文件,和用户登录密码相关的.
(4)创建账号和密码文件
将主机的/etc/passwd,/etc/shadow,/etc/group文件复制到…/rootfs/etc/文件下
并修改…/rootfs/etc/下这几个文件,只保留root账户.
Vipasswd
root:x:0:0:root:/root:/bin/sh
vigroup
root:x:0:root
vishadow
root:$xxxxx:xxxx:x:xxxx:x::
注意:这里可能会有个问题,因为从主机下复制过来的那些文件所属组不通,你可能需要将其权限修改一下才能打开修改.
再删除…/rootfs/etc/下的备份文件
rm*~
这样root的登录密码和主机的登录密码一样了.你也可以在刚才那些文件中保留一些另外的用户.
6.拷贝必须的动态库文件
从交叉编译器/usr/local/arm/3.4.1/arm-linux/lib/中拷贝到…/rootfs/lib/中
cp–d/usr/local/arm/3.4.1/arm-linux/lib/ld*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libc-2.3.2.so…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libc.so.6…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libm-*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libm.s*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libcrypt-*…/rootfs/lib/
cp–d/usr/local/arm/3.4.1/arm-linux/lib/libcrypt.s*…/rootfs/lib/
以上就是最基本的文件,一个最基本的文件系统就构建完成.
7.制作cramfs文件系统
(1)下载cramfs-1.1.tar.gz,解压,编译得到mkcramfs工具
(2)制作cramfs文件系统
./mkcramfs…/rootfsmyrootfs.cramfs
如果在制作的时候提示出错,那么就很有可能是你的/etc/下的passwd,group,shadow文件的权限出问题了.
这样就cramfs文件系统就制作成功了.
8.制作yaffs文件系统
在内核制作最后提到了yaffs自带的mkyaffsimg工具和yaffs文件系统不匹配,好在在网上(http://www.100ask.net/showtopic-177.aspx)找到了一个mkyaffsimg补丁.
解压该补丁,进入yaffs2\utils\下,执行make命令,生成mkyaffsimage工具.
然后就像制作cramfs文件系统一下:
./mkyaffsimage…/rootfsmyrootfs.img
Yaffs文件系统制作完成.
至此uboot-1.2.0,linux-2.6.24.4,根文件系统都简单移植完成了.但是有一个问题,启动后,登录后,如果在切换到另一个用户后,命令提示符那里还是原来的那个用户.这可能是文件系统的/etc/rcS文件有问题了.
四、根文件系统的设计(不用用户登录,即无账户和密码)
移植环境:VMware5.5.2+redhat9(非root登录,需要切换到root下执行的另外指出)
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
Busybox:busybox-1.9.2.tar.bz2(
Cramfs制作工具:cramfs-1.1.tar.gz(http://sourceforge.net/projects/cramfs/)
先说明一下,移植过程按照是按照书嵌入式linux应用开发完全手册移植的。
Init进程是由内核启动的第一个(也是唯一的一个)用户进程(进程ID为1)它根据配置文件决定启动哪些进程,比如执行某些脚本、启动shell、运行用户指定程序等。Init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。
内核启动init进程时已经打开“/dev/console”设备作为控制台,一般情况下init程序就是用/dev/console。但是如果内核启动init进程的同时设置了环境变量CONSOLE或者console,则使用环境变量所指定的设备。在init程序中,还会检查这个设备是否可以打开,如果不能打开则使用/dev/nul
Init进程只是作为其他进程的发起者和控制者,并不需要控制台与用户交互,如果存在etc/inittab文件,init程序解析他并执行,然后按照他的指示创建各种子进程;否则使用默认的配置创建子进程。
从系统启动过程可以知道,涉及的设备有:dev/mtdblock*(MTD块设备)、/dev/ttySAC*(串口设备)、/dev/null、/dev/console,只要建立以下设备就可以启动系统。
mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件。mdev的主要用途主要有两个:初始化/dev目录、动态更新。动态更新不仅是更新/dev目录,还支持热插拔,即接入、和卸下设备时执行某些动作。要使用mdev,需要内核支持sysfs文件系统,为了减少对Flash的读写,还要支持tmpfs文件系统。先要确保内核已经设置了CONFIG—SYSFS、CONFIG—TMOFS配项。mount
–ttmpfsmdev/dev使用内存文件系统减少对Flash的读写
1.解压busybox,并配置busybox,可参考上一节的做法.
我来介绍一下他吧,busybox是一个集成了一百多个最常用linux命令和工具的软件,他甚至还集成了一个http服务器和一个telnet服务器,而所有这一切功能却只有区区1M左右的大小.我们平时用的那些linux命令就好比是分立式的电子元件,而busybox就好比是一个集成电路,把常用的工具和命令集成压缩在一个可执行文件里,功能基本不变,而大小却小很多倍,在嵌入式linux应用中,busybox有非常广的应用。
2.安装busybox到rootfs/mini_rootfs下
MakeCONFIG_PREFIX=…./rootfs/mini_rootfsinstall
将会在mini_rootfs下生成bin,sbin,linuxrc文件(夹)
3.创建usr,lib,usr/bin,usr/sbin文件夹
4.安装一些库文件
将交叉编译器下的一些库文件复制到mini_rootfs/lib下
cp…/3.4.1/arm-linux/lib/*.so*…../rootfs/mini_rootfs/lib
这些库文件有些可能是多余的.
5.构建etc目录(记住以下etc下的文本内容要用vi编译器,因为复制的内容是xp下的,格式和linux不一样)
(1)创建etc目录:mkdiretc
(2)将busybox下的examples/bootfloopy/etc下的文件copy到mini_rootfs/etc下
(3)修改etc/inittab文件
::sysinit:/etc/init.d/rcS
系统启动最先执行的,rcS是一个脚本
s3c2410_serial0::askfirst:-/bin/shinit进程先输出pleasepressEntertoactivatethisconsole等用户输入回车之后才启动子进程,启动shell脚本,以/dev/
s3c2410_serial0作为控制台,需要注意的是,开发板上通过mdev生成的/dev目录中,s3c2410_serial0不是ttySAC0,所以此处使用的控制台台为s3c2410_serial0
::ctrlaltdel:/sbin/reboot按下ctrl-alt-del键系统会从新启动,不过在串口控制台中是无法输入ctrl-alt-del组合键的
::shutdown:/bin/umount-a–r在关机时卸载所有文件系统
(4)修改etc/init.d/rcS文件
#!/bin/sh
ifconfigeth0192.168.1.6修改本机的ip地址
/bin/mount–a挂载所有/etc/fstab文件指定的所有文件系统
mkdir/dev/ptsdevpfs用来支持外部网络连接telnet的虚拟终端
mount-tdevptsdevpts/dev/pts
echo/sbin/mdev>/proc/sys/kernel/hotplug设置内核当有设备拔插时调用/bin/
mdev程序
mdev–s在/dev目录下生成内核支持的所有设备的节点
要在内核启动时,自动运行mdev。这要修改两个文件:fstab来自动挂载文件系统、修改rcS加入要自动运行的命令。
(5)修改etc/fstab文件
#devicemount—pointtypeoptionsdumpfsckorder这是一一对应的参数,本文件完成所要自动挂载的文件系统
proc/procprocdefaults00
tmpfs/tmptmpfsdefaults00
sysfs/syssysfsdefaults00
tmpfs/devtmpfsdefaults00
(6)修改etc/profile文件,增加一些定义
#/etc/profile:system-wide.profilefilefortheBourneshells
echo
echo-n"Processing/etc/profile..."
exportLD_LIBRARY_PATH=/lib:/usr/lib
exportPATH=/bin:/sbin:/usr/bin:/usr/sbin
PS1='[\u@\h\w]\$'这个你猜猜改一下就知道是什么了。我也是改过才知道
#no-op
echo"Done"
echo
在etc目录下建立vimdev.conf(空文件即可)
6.构建dev目录
执行下列命令
mkdirdev
再切换到root登录控制台
mknodconsolec51
mknodnullc31
7.构建其他目录
mkdirprocmnttmpsysroot
8.制作镜像文件,同上一节的制作方法.
五、移植LCD液晶驱动
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(http://www.kernel.org/pub/linux/kernel/v2.6)
先说明一下,移植过程按照http://blog.chinaunix.net/u2/63560/showart_520838.html移植的。另外结合sky提供的内核代码。
LCD为三星3.5寸TFT,320×240,在前面移植的内核的基础上进行一下修改:
1.修改文件/arch/arm/mach-s3c2440/mach-smdk2440.c
加入头文件#include<asm/arch/fb.h>
在/*LCDdriverinfo*/后增加自己的液晶驱动代码,参考sky提供的液晶驱动\arch\arm\mach-s3c2410\sky2440.c中的#elifdefined(CONFIG_FB_S3C24X0_S320240)
staticstructs3c2410fb_mach_infosmdk2440_lcdcfg__initdata={。。。。}处的整个结构体的内容替换为:
staticstructs3c2410fb_displaysky2440_lcd_cfg__initdata={
{
/*Configfor320x240LCD*/
.lcdcon5=S3C2410_LCDCON5_FRM565|
S3C2410_LCDCON5_INVVLINE|
S3C2410_LCDCON5_INVVFRAME|
S3C2410_LCDCON5_PWREN|
S3C2410_LCDCON5_HWSWP,
.type=S3C2410_LCDCON1_TFT,
.width=320,
.height=240,
.pixclock=100000,/*HCLK/10*/
.xres=320,
.yres=240,
.bpp=16,
.left_margin=16,
.right_margin=6,
.hsync_len=9,
.upper_margin=4,
.lower_margin=6,
.vsync_len=16,
}
};
staticstructs3c2410fb_mach_infosmdk2440_fb_info__initdata={
。。。。。。。。。}处的整个结构体的内容替换为:
staticstructs3c2410fb_mach_infosky2440_fb_info__initdata={
.displays=&sky2440_lcd_cfg,
.num_displays=1,
.default_display=0,
.gpccon=0xaa955699,
.gpccon_mask=0xffc003cc,
.gpcup=0x0000ffff,
.gpcup_mask=0xffffffff,
.gpdcon=0xaa95aaa1,
.gpdcon_mask=0xffc0fff0,
.gpdup=0x0000faff,
.gpdup_mask=0xffffffff,
.lpcsel=0xf82,
};
在函数smdk2410_init()中加入
s3c24xx_fb_set_platdata(&sky2440_fb_info);
2.配置内核
DeviceDrivers--->
Graphicssupport--->
Displaydevicesupport--->
<*>Displaypanel/monitorsupport
<*>Supportforframebufferdevices
<*>S3C2410LCDframebuffersupport
Consoledisplaydriversupport--->
<*>FramebufferConsolesupport
[*]FramebufferConsoleRotation
[*]Selectcompiled-infonts
[*]VGA8x8font
[*]VGA8x16font
[*]Mini4x6font
[*]Sparcconsole8x16font
[*]Bootuplogo--->
---Bootuplogo
[*]Standard224-colorLinuxlogo
3.重新编译内核,下载,运行,你就会看到液晶上的那个小企鹅了,对应的图片为/drivers/video/logo/logo_linux_clut224.ppm.
另外这时可以把LCD当作一个控制台来使用了,例如执行:echohello>/dev/tty0
将会在LCD的小企鹅下输出hello字符.
六、DM9000网卡驱动移植
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(
DM9000的CS是接在nGCS4上的,INT接到EINT7,CMD接到ADDR2上.
1.增加DM9000平台设备,修改arch/arm/plat-s3c24xx/common-smdk.c
(1)添加要包含的头文件
在47行处添加
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
#include<linux/dm9000.h>
#endif
(2)添加DM9000平台设备结构
紧接着前面的地方,添加平台设备结构
/*DM9000*/
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
staticstructresources3c_dm9k_resource[]={
[0]={
.start=S3C2410_CS4,
.end=S3C2410_CS4+3,
.flags=IORESOURCE_MEM,
},
[1]={
.start=S3C2410_CS4+4,
.end=S3C2410_CS4+4+3,
.flags=IORESOURCE_MEM,
},
[2]={
.start=IRQ_EINT7,
.end=IRQ_EINT7,
.flags=IORESOURCE_IRQ,
}
};
staticstructdm9000_plat_datas3c_dm9k_platdata={
.flags=DM9000_PLATF_16BITONLY,
};
staticstructplatform_devices3c_device_dm9k={
.name="dm9000",
.id=0,
.num_resources=ARRAY_SIZE(s3c_dm9k_resource),
.resource=s3c_dm9k_resource,
.dev={
.platform_data=&s3c_dm9k_platdata,
}
};
#endif/*CONFIG_DM9000*/
(3)加入到内核设备列表中
staticstructplatform_device__initdata*smdk_devs[]={
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
#ifdefined(CONFIG_DM9000)||defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
};
2.修改drivers/net/dm9000.c
(1)增加包括头文件代码
在74行附近
#ifdefined(CONFIG_ARCH_S3C2410)
#include<asm/arch-s3c2410/regs-mem.h>
#endif
(2)设置存储器控制器BANK4使用,设置默认MAC地址
在dm9000_probe()函数中先增加两个变量定义(大概412行)
#ifdefined(CONFIG_ARCH_S3C2410)
unsignedintoldval_bwscon;
unsignedintoldval_bankcon4;
#endif
再增加Bank4的设置(大概427行)
……
PRINTK2("dm9000_probe()");
#ifdefined(CONFIG_ARCH_S3C2410)
oldval_bwscon=*((volatileunsignedint*)S3C2410_BWSCON);
*((volatileunsignedint*)S3C2410_BWSCON)=(oldval_bwscon&~(3<<16))\
|S3C2410_BWSCON_DW4_16|S3C2410_BWSCON_WS4|S3C2410_BWSCON_ST4;
oldval_bankcon4=*((volatileunsignedint*)S3C2410_BANKCON4);
*((volatileunsignedint*)S3C2410_BANKCON4)=0x1f7c;
#endif
设置默认MAC地址(大概612行)
…..
if(!is_valid_ether_addr(ndev->dev_addr))
printk("%s:InvalidethernetMACaddress.Please"
"setusingifconfig\n",ndev->name);
#ifdefined(CONFIG_ARCH_S3C2410)
printk("nowusethedefaultMACaddress:08:90:90:90:90:90\n");
ndev->dev_addr[0]=0x08;
ndev->dev_addr[1]=0x90;
ndev->dev_addr[2]=0x90;
ndev->dev_addr[3]=0x90;
ndev->dev_addr[4]=0x90;
ndev->dev_addr[5]=0x90;
#endif
………
out:
printk("%s:notfound(%d).\n",CARDNAME,ret);
#ifdefined(CONFIG_ARCH_S3C2410)
*((volatileunsignedint*)S3C2410_BWSCON)=oldval_bwscon;
*((volatileunsignedint*)S3C2410_BANKCON4)=oldval_bankcon4;
#endif
……..
(3)注册终端市,指定触发方式,在dm9000_open()中
staticint
dm9000_open(structnet_device*dev)
{
board_info_t*db=(board_info_t*)dev->priv;
PRINTK2("enteringdm9000_open\n");
#ifdefined(CONFIG_ARCH_S3C2410)
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED|IRQF_TRIGGER_RISING,dev->name,dev))
#else
if(request_irq(dev->irq,&dm9000_interrupt,DM9000_IRQ_FLAGS,dev->name,dev))
#endif
return-EAGAIN;
…….
3.修改内核配置
Makemenuconfig之后,将DM9000编译入内核,或者配置成模块.
DeviceDrivers--à
Networkdevicesupport--à
[*]Networkdevicesupport
Ethernet(10or100Mbit)-à
<*>DM9000support
4.重新编译内核:makeuImage
七、USB驱动
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(
没有修改什么文件,只是在内核编译的时候,加入了一些有关usb的选项
Devicedrives---à
SCSIdevicesupport---à
<*>SCSIdevicesupport
[*]legacy/proc/scsi/support
<*>SCSIdisksupport
USBsupport->
<*>supportforHost-sideUSB
[*]USBdevicefilesystem
<*>OHCIHCDsupport
<*>USBMassstoragesupport
HIDdevice--à
<*>USBHumanInterfacedevice(fullHID)support
[*]/dev/hiddevrawHIDdevicesupport
重新编译内核,下载.
启动后,如果将usb鼠标插入叠在一起的那个usb接口的下面那个接口,你将会看到提示
[@(none)/dev]#usb1-1:newlowspeedUSBdeviceusings3c2410-ohciandaddress3
usb1-1:configuration#1chosenfrom1choice
input:USBMouseas/class/input/input1
input:USBHIDv1.00Mouse[USBMouse]onusb-s3c24xx-1
并且在dev下增加了几个文件:usbdev1.2,usbdev1.2_ep00,usbdev1.2_ep81
当拔下的时候:[@(none)/dev]#usb1-1:USBdisconnect,address3
另外拿了块u盘,挂载在上面可以看到内容(需要内核支持相应的文件系统).
八、Qtopia移植(qtopia-2.2.0版本)
移植环境:VMware5.5.2+redhat9
开发板:SKY_2440B_V5.0
编译器:arm-linux-gcc-3.4.1.tar.bz2(http://www.handhelds.org/download/projects/toolchain)
内核:linux-2.6.24.4.tar.bz2(
前面已经移植的内核和文件系统可以在终端下正常操作(除了网络ping的时候还有丢包的问题),下面要在前面的基础上移植qtopia.
首先是一些压缩包的下载:
1.得到本机运行版本uic工具:
下载后改变权限chmodu+rxuic-qt2
2.qtopia-free-src-2.2.0.tar.gz下载地址:
3.e2fsprogs-1.39.tar.gz下载地址:
4.jpegsrc.v6b.tar.gz下载地址:
5.libpng-1.2.14.tar.bz2下载地址:
6.tslib-1.3.tar.bz2(触摸屏校正工具:也可以用QT自带的,这样就不必下载)下载地址:
7.zlib-1.2.3.tar.bz2下载地址:
移植步骤:
在开始之前需要修改交叉编译器的一个头文件,为/…../3.4.1/armlinux/include/linux/fd.h,在该文件中增加一行:#include<linux/compiler.h>
1.导出编译工具安装路径
exportPATH=$PATH:/...../3.4.1/bin/
source/etc/profile
2.建立qt的文件夹
mkdir/..../myboard/qtopia-arm-home
exportMYHOME=/..../myboard/qtopia-arm-home
3.创建几个文件夹
cd$MYHOME
mkdirarm
cdarm
mkdirlibinclude
4.解压有关库文件
e2fsprogs-1.39.tar.gz.tar.gz,jpegsrc.v6b.tar.gz,libpng-1.2.14.tar.bz2,zlib-1.2.3.tar.bz2解压至$MYHOME/arm目录,并相应更名目录为e2fs,jpeg,libpng,zlib。
5.编译相关库
(1)e2fs
cd$MYHOME/arm/e2fs
./configure--host=arm-linux--enable-elf-shlibs--with-cc=arm-linux-gcc-with-linker=arm-linux-ld--prefix=/..../3.4.1/arm-linux
Make
将lib文件夹下的uuid文件夹复制到../include把libuuid.so*复制到../lib
cp-rlib/uuid../include
cplib/libuuid.so*../lib
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(2)jpeg
cd$MYHOME/arm/jpeg
./config--enable-shared--prefix=/…./3.4.1/arm-linux
geditMakefile
修改
CC=arm-linux-gcc
AR=arm-linux-arrc
AR2=arm-linux-ranlib
Make
Makeinstall-lib
将会在/…./3.4.1/arm-linux/lib和/…./3.4.1/arm-linux/include中生成有关库文件(libjpeg.so*,libjpeg.a,libjpeg.la)和头文件(jpeglib.h)
再同样上面那些文件复制一份到$MYHOME/arm/include和$MYHOME/arm/lib下
(3)zlib
cd$MYHOME/arm/zlib
./configure-shared
geditMakefile
修改
[begin]
......
CC=arm-linux-gcc
......
LDSHARED=arm-linux-gcc-shared-Wl,-soname,libz.so.1
CPP=arm-linux-gcc-E
......
AR=arm-linux-arrc
RANLIB=arm-linux-ranlib
......
prefix=/.../3.4.1/arm-linux
......
[end]
make
cplibz.so*../lib/
cp*.h../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(4)libpng
cd$MYHOME/arm/libpng
cpscripts/makefile.linux./Makefile
geditMakefile
修改:
[begin]
.....
AR_RC=arm-linux-arrc
CC=arm-linux-gcc
.....
RANLIB=arm-linux-ranlib
....
prefix=/.../3.4.1/arm-linux
.....
[end]
make
cplibpng.a../lib/
cplibpng12.so*../lib/
cplibpng12.so../lib/libpng.so
cp*.h../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
6.创建文件夹nfs
cd$MYHOME
mkdirnfs
7.解压qtopia-free-2.2.0.tar.bz2到nfs文件夹
8.编译qtopia
(1)建立安装目录
mkdir$MYHOME/nfs/qtopia
(2)复制uci-qt2文件
cpuic-qt2$MYHOME/nfs/qtopia-free-2.2.0/qt2/bin/uic
(3)修改文件
vi$MYHOME/nfs/qtopia-free-2.2.0/qtopia/mkspecs/qws/linux-arm-g++/qmake.conf
将此行
QMAKE_LIBS_QT=-lqte
修改为
QMAKE_LIBS_QT=-lqte-lpng-lz-luuid-ljpeg
(4)支持usb键盘和鼠标
修改$QPEDIR/src/qt/qconfig-qpe.h文件
注释如下部分:
/*
#ifndefQT_NO_QWS_CURSOR
#defineQT_NO_QWS_CURSOR
#endif
#ifndefQT_NO_QWS_MOUSE_AUTO
#defineQT_NO_QWS_MOUSE_AUTO
#endif
#ifndefQT_NO_QWS_MOUSE_PC
#defineQT_NO_QWS_MOUSE_PC
#endif
*/
(5)准备配置文件:
cp$MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/qt/qconfig-qpe.h$MYHOME/nfs/qtopia-free-2.2.0/qt2/src/tools
cd$MYHOME/nfs/qtopia-free-2.2.0/qtopia/src/libraries/qtopia
cpcustom-linux-ipaq-g++.cppcustom-linux-arm-g++.cpp
cpcustom-linux-ipaq-g++.hcustom-linux-arm-g++.h
(6)开始配置
./configure-qte'-embedded-xplatformlinux-arm-g++-qconfigqpe-no-qvfb-depths16,32-system-jpeg-system-libpng-system-zlib-gif-thread-no-xft-release-I$MYHOME/arm/include-L$MYHOME/arm/lib-lpng-lz-luuid-ljpeg'-qpe'-xplatformlinux-arm-g++-edition
pda-displaysize320x240-I$MYHOME/arm/include-L$MYHOME/arm/lib-prefix=$MYHOME/nfs/qtopia'
../setQpeEnv(两个点号之间有空格)
其中的320*240是对应我的触摸屏的长和宽
(7)make
make过程中可能会有一些错误,根据提示进行修改,但我make时没有出现错误
(8)makeinstall
至此将在$MYHOME/nfs/qtopia中生成一些qt移植所需的文件
9.复制在第四节中得到的文件系统目录(mini_rootfs),改名成qt_rootfs
10.将Qtopia所依赖的库复制到qt_rootfs/lib中
cd$MYHOME/arm
cplib/*……/qt_rootfs/lib
11.复制字库(字库在$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts/中)
cp–rf$MYHOME/nfs/qtopia-free-2.2.0/qt2/lib/fonts$MYHOME/nfs/qtopia
12.将qtopia文件夹复制到qt_rootfs中
先在qt_rootfs中创建一个opt文件夹:cd……./qt_rootfs;mkdiropt;
再将$MYHOME/nfs中的qtopia文件夹复制到qt_rootfs/opt中
13.创建时区文件
cd……./qt_rootfs
mkdir–pusr/share/zoneinfo
cp–rf/usr/share/zoneinfo/Americausr/share/zoninfo/
cp/usr/share/zoneinfo/zone.tabusr/share/zoneinfo/
也可以将$MYHOME/nfs/qtopia-free-2.2.0/qtopia/etc/下的zoneinfo文件夹全部copy到usr/share/
14.伪造触摸屏校验文件
Qtopia第一次启动的时候会运行触摸屏校验程序,由于现在还没移植触摸屏驱动,会导致校验失败,无法进入系统,可以在根文件系统中创建一个触摸校验文件etc/pointercal,内容为10101165536
15.建立一个脚本文件,用来运行qtopia
在……qt_rootfs/bin下创建一个qpe.sh文件
#!/bin/sh
exportHOME=/root
exportQTDIR=/opt/qtopia
exportQPEDIR=/opt/qtopia
exportQWS_DISPLAY=LinuxFb:/dev/fb0
exportQWS_KEYBOARD=”TTY:/dev/tty1”
exportQWS_MOUSE_PROTO=”USB:/dev/mouse0”
exportPATH=$QPEDIR/bin:$PATH
exportLD_LIBRARY_PATH=$QPEDIR/lib:$LD_LIBRARY_PATH
$QPEDIR/bin/qpe&
将qpe.sh设置成可执行.另外如果qt_rootfs/下没有root文件夹,要创建一个.HOME变量要用到.
16.修改根文件系统的启动脚本
(1)在qt_rootfs下创建一个tmp目录(如果已经有这么一个目录则跳过这一步)
(2)在etc/fstab中加入这么一行(如果已经有这么一行则跳过这一步)
tmpfs/tmptmpfsdefaults00
(3)修改etc/init.d/rcS,在最后加入这么一行
/bin/qpe.sh&
16.重新制作yaffs文件系统
./mkyaffsimage………/qt_rootfsqt_rootfs.yaffs
17.重新将qt_rootfs.yaffs烧写进开发板,启动即可
注:目前还不支持触摸屏,可能要用到qtopia自带的tslib或者要用到tslib.1.3.tar.bz2.
九、
十、
十一、
十二、
十三、
十四、
十五、
相关文章推荐
- [linux] 进度条
- centos添加防火墙端口
- openstack on centos 7.1(launch an instance)
- centos 7 安装rar,unrar
- linux下文件比较工具,文件夹比较工具
- Linux下文件的三种时间属性
- Windows以及linux系统下如何修改mysql数据库密码
- 通过VMware虚拟机在windows 10 上安装Linux Ubuntu
- Kubernetes部署etcd集群-centos7(新-增加了红色部分的注意事项)
- Linux PATH 设置
- Linux 系统性能分析工具sar一
- CentOS7下部署Ceph集群(版本10.2.2)
- Linux 脚本编写基础
- Pixhawk原生固件Linux环境下编译
- 用iPhone 4S带着Ubuntu Linux上网
- Windows下C++程序移植到Linux上的几个问题及解决方法
- linux下mysql的卸载、安装全过程及遇到"MySQL提示:The server quit without updating PID file问题的解决办法"
- centos 防火墙配置
- linux下opencv 安装配置
- Linux系统内核优化(一)