一、 uboot 1.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文件夹下
tar xzvf u-boot-1.2.0.tar.bz2–C /home/dk/myboard/
4.进入uboot目录,修改Makefile
cd u-boot-1.2.0
vi Makefile
(1) 新建我的编译项
在1923行,即smdk2410_config编译项之后增加我的编译项
tekkaman2440_config : unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t tekkaman2440tekkaman s3c24x0
各项的意思如下:
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
$mkdir tekkaman tekkaman/tekkaman2440
$cp -arf sbc2410x/* tekkaman/tekkaman2440/
$cd tekkaman/tekkaman2440
$mv sbc2410x.c tekkaman2440.c
还要记得修改自己的开发板tekkaman2440目录下的Makefile文件,不然编译时会出错:
$vi Makefile
COBJS := tekkaman2440.o flash.o
6.在include/configs/中建立配置头文件
$cpinclude/configs/sbc2410x.h include/configs/tekkaman2440.h
7.测试编译能否成功
$make tekkaman2440_config
Configuringfor tekkaman2440 board...
(如果出现:
$ make tekkaman2440_config
Makefile:1927: *** 遗漏分隔符 。 停止。
请在U-boot的根目录下的Makefile的
@$(MKCONFIG) $(@:_config=)arm arm920t tekkaman2440 tekkaman)
前加上“Tab”键)
$make
到这一步应该能编译成功,但是我的并没有编译成功,提示/common/cmd_bootm.c文件的464行的U_BOOT_CMD有错误,我是把其中的从#ifdef CONFIG_OF_FLAT_TREE到#endif都屏蔽掉,这样就可以编译过去了。可能还会出现类似的问题,用同样的方法可以解决。
下面修改Uboot中的文件,以匹配开发板
8.修改/cpu/arm920t/start.S
这个函数是arm920t系列的共有启动的汇编代码,UBOOT执行的第一个程序
(0)修改寄存器地址定义
/* turn off thewatchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clockdivisor register */
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
# define pWTCON 0x53000000这个定义了看门狗的寄存器地址
# define INTMSK 0x4A000008 /* Interupt-Controller baseaddresses */中断掩码的寄存器地址
# define INTSUBMSK 0x4A00001C中断掩码的寄存器地址
# define CLKDIVN 0x4C000014 /* clock divisor register */完成时钟分份的寄存器
#endif
(1)修改中断禁止部分
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)
ldr r0, =pWTCON把看门狗寄存器地址给了r0
mov r1, #0x0 r1等于0
str r1, [r0] 看门狗寄存器等于0因为在启动时要关闭看门狗,不能让他产生中断影响启动,此时也根本不需要任何中断
/*
* mask all IRQs by setting all bits in the INTMR -default
*/
mov r1, #0xffffffff 关闭所有中断
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x7ff //根据2410芯片手册,INTSUBMSK有11位可用,
//vivi也是0x7ff,不知为什么U-Boot一直没改过来。
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
# if defined(CONFIG_S3C2440)
ldr r1, =0x7fff //根据2440芯片手册,INTSUBMSK有15位可用
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
(2)修改时钟设置(2440的主频可达533MHz,但是我设到533MHz时系统很不稳定,不知是不是SDRAM和总线配置的影响,所以现在先设到405MHz,以后在改进。)
ldr r0, =CLKDIVN
这个值决定了FCLK HCLK PCLK的频率
FCLK是供给CPU的是主频
HCLK是供给AHB总线(主要用于高性能模块(如CPU、DMA和DSP等)之间的连接,作为SoC的片上系统总线)上的外围设备
PCLK是供给APB总线(APB主要用于低带宽的周边外设之间的连接,例如UART、1284等)上的外围设备
UCLK是两路PLL中一路供给USB的频率
ARM总线技术在这里我不多介绍了,对硬件感兴趣的同学建议多多了解,我有一回面试人家就问我这个了,405MHZ已经很高了,基本都够了,2410的200MHZ就能播放Mplayer视频,据说很流畅。
mov r1, #5 /* FCLK:HCLK:PCLK = 1:4:8 */
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0 /*read ctrl register tekkaman*/
orr r1, r1, #0xc0000000 /*Asynchronous tekkaman*/
mcr p15, 0, r1, c1, c0,0 /*write ctrl register tekkaman*/
他是用到了协处理器P15,此处理器主要设置mmu,时钟模式,caches,保护模式的。先把C0 C1的值读出到r1,设置后再写回。 FCLK:HCLK:PCLK的比例由CLKDIVN决定的,CLKDIVN寄存器的HDIVN和PDIVN决定比例的大小。因为此时的HDIVH不为0,将快速总线模式改为异步总线模式,操作协处理器P15改变模式即可,如果HDIVH不为0,而且是快速总线模式的话,那么CPU的主频由hclk控制,这样可以实现不改变HCLK和PCLCK的同时就能使CPU的主频减半或更多。网上的大虾说没有以上几句主频会是12MHZ,我的观点不同。这是数据手册原文
If HDIVN is not 0 and the CPU bus mode is the fast busmode, the CPU will operate by the HCLK.This feature can be used to change theCPU frequency as a half or more without affecting the HCLKand PCLK
#ifdefined(CONFIG_S3C2440)
/*now, CPU clock is 405.00 Mhz tekkaman*/
mov r1, #CLK_CTL_BASE /*tekkaman*/这是时钟寄存器的基地址
mov r2, #MDIV_405 /* mpll_405mhz tekkaman*/
add r2, r2, #PSDIV_405 /*mpll_405mhz tekkaman*/
str r2, [r1,#0x04] /* MPLLCON tekkaman */设置 MPLLCON
#endif
#if defined(CONFIG_S3C2410)
/*now, CPU clock is 202.8 Mhz tekkaman*/
mov r1, #CLK_CTL_BASE /*tekkaman*/
mov r2,#MDIV_200 /* mpll_200mhz tekkaman*/
add r2, r2,#PSDIV_200 /* mpll_200mhz tekkaman*/
str r2, [r1,#0x04] /* MPLLCON tekkaman */
#endif
#endif /* CONFIG_S3C2400|| CONFIG_S3C2410||CONFIG_S3C2440 */
红色部分是我添加的,利用vivi的代码,将其设为405.00MHz并在前面加上:
#elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller baseaddresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */
#defineCLK_CTL_BASE 0x4C000000 /* tekkaman */
#if defined(CONFIG_S3C2440)
#define MDIV_405 0x7f << 12 /* tekkaman */
#define PSDIV_405 0x21 /* tekkaman */
#endif
#if defined(CONFIG_S3C2410)
#define MDIV_200 0xa1 <<12 /* tekkaman */
#define PSDIV_200 0x31 /* tekkaman */
#endif
#endif〕
(3)将从Flash启动改成从NAND Flash启动。(特别注意:这和2410的程序有不同,不可混用!!!是拷贝vivi的代码。)
将以下U-Boot的重定向语句段:
这段代码将uboot搬运到ram中,这个是没有存放在nand的情况,下面咱们来看一下不在nand启动和在nand启动时此处的区别。
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */nor中的起始地址给了r0
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ram中的uboot代码的起始地址(这里关于uboot搬运这块在内存地址的部分,分了很多段,每一段空间具有不同功能,这是你理解uboot必须掌握的,非常关键,解释后续会提到些)
cmp r0,r1 /* don't reloc during debug */比较两个地址是否相同,不同则进行下面的搬运工作
beq stack_setup
在这里你会发现搬运了全部uboot,有的uboot把uboot的c部分搬运到内存_TEXT_BASE里面所放的地址处。
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size ofarmboot */_bss_start-_armboot_start= armboot 因为_armboot_end的结束位置就是bss区的开始位置所以能计算出uboot代码的大小
add r2, r0, r2 /* r2 <- source endaddress */
以下就是把整个代码搬运到_TEXT_BASE里面所放的地址处,记住是内存地址,哈哈!!
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee[r2] */
ble copy_loop
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
替换成:因为nand和nor的启动是有区别的,NOR Flash储存器较贵,而NAND Flash则相对便宜,所以很多用户选择在NAND Flash中执行启动代码,在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-Page size,GPG14-Address cycle,GPG15-总线宽度)
#ifdef CONFIG_S3C2440_NAND_BOOT @tekkaman@在以后会定义它的,不要忘了
@ reset NAND
mov r1, #NAND_CTL_BASE nand的寄存器基地址
ldr r2, =((7<<12)|(7<<8)|(7<<4)|(0<<0) ) CLE & ALE期间设置值|TWRPH0期间设置值|TWRPH0期间设置值|8位总线
str r2, [r1, #oNFCONF] 设置NFCONF寄存器,初始化作用
ldr r2, [r1, #oNFCONF]
ldr r2, =((1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control初始化ECC解码/编码器(只写)|强制拉低nFCE(允许片选)|允许NAND控制器
str r2, [r1, #oNFCONT] 设置 NFCONT
ldr r2, [r1,#oNFCONT]
ldr r2, =(0x6) @ RnB Clear和nand isbusy
str r2, [r1, #oNFSTAT]
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3,#0 @ wait就是一下段延时
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @wait ready
tst r2, #0x4
beq nand2
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT]
@ get read to call C functions (for nand_read())
ldr sp,DW_STACK_START @ setup stack pointer
mov fp,#0 @ no previous frame, so fp=0初始化frame的起始位置
@ copy U-Boot to RAM
ldr r0, =TEXT_BASE 设置第1个参数: UBOOT在RAM中的起始地址
mov r1, #0x0 设置第2个参数:NandFlash的起始地址
mov r2, #0x20000 设置第3个参数: UBOOT的长度(128KB)
bl nand_read_ll 在board/tekkaman/tekkaman2440/nand_read.c我会解析这个函数的作用
tst r0, #0x0 如果函数的返回值为0,表示执行成功.
beq ok_nand_read 执行内存比较,比较什么呢?他比较搬运到内存中的代码和在内部ram的前4kb是否一样
bad_nand_read:
loop2: b loop2 @ infinite loop
ok_nand_read:
@ verify
mov r0, #0 内部RAM的起始地址
ldr r1, =TEXT_BASE UBOOT在RAM中的起始地址
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4 进行比较
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
内存中的代码和在内部ram的前4kb如果不一样,就无限的循环在这了,如果你不努力的去体会每一句,你的功力就像他一样了,哈哈!
loop3: b loop3 @ infinite loop
#endif @CONFIG_S3C2440_NAND_BOOT @tekkaman@@
在 “ _start_armboot: .wordstart_armboot ” 后加入:
.align 2 二的平方也就是字对齐了存储了
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
9.在board/tekkaman/tekkaman2440加入NAND Flash读函数文件,拷贝vivi中的nand_read.c文件到此文件夹即可:
#include<config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGi(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xC)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFSTAT __REGb(NF_BASE + 0x20)
//#define GPDAT __REGi(GPIO_CTL_BASE+oGPIO_F+oGPIO_DAT)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1)) 允许片选
#define NAND_CHIP_DISABLE(NFCONT |= (1<<1))禁止片选
#define NAND_CLEAR_RB (NFSTAT |= (1<<2))
#define NAND_DETECT_RB { while(!(NFSTAT&(1<<2)) );}
#define BUSY 4
inline void wait_idle(void) {
while(!(NFSTAT & BUSY));等待是否nand忙于上次的操作
NFSTAT |= BUSY;
}
#define NAND_SECTOR_SIZE 512 一页大小,我们的nand是这样分的
1设备(Device) = 4096块(Blocks)
1块(Block) = 32页/行(Pages/rows) ;页与行是相同的意思,叫法不一样
1(Page) = 528字节(Bytes) =数据块大小(512Bytes) + OOB块大小(16Bytes)
在每一页中,最后16个字节(又称OOB)用于Nand Flash命令执行完后设置状态用,剩余512个字节又
分为前半部分和后半部分。可以通过Nand Flash命令00h/01h/50h分别对前半部、后半部、OOB进行定位,通过OOB部分的第六字节(即517字节)标志是否是坏块,OOB第六字节外,通常至少把OOB的前3个字节存放Nand Flash硬件ECC码,这个我就不多说了,你要想真正看懂这些代码,必须了解nand的架构啊
Nand Flash内置的指针指向各自的首地址。
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE- 1)
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, 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;
Nand Flash片内寻址采用26位地址形式。从第0位开始分四次通过I/O0-I/O7进行
传送,并进行片内寻址。具体含义如下:
0-7位:字节在上半部、下半部及OOB内的偏移地址
8位:值为0代表对一页内前256个字节进行寻址
值为1代表对一页内后256个字节进行寻址
9-13位:对页进行寻址
14-25位:对块进行寻址
当传送地址时,从位0开始
/* Write Address */
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;禁止片选
return 0;
}
注意:s3c2410与s3c2440的Nand Flash控制器寄存器不同,不能混用!!
10. 修改board/tekkaman/tekkaman2440/Makefile文件
OBJS := tekkaman2440.o nand_read.o flash.o
11.修改include/configs/tekkaman2440.h文件,添加如下内容(注意:s3c2410与s3c2440的Nand Flash控制器寄存器不同,不能混用!!):
......
/*
* Nandflash Boot
*/
#define CONFIG_S3C2440_NAND_BOOT1 这处告诉从nand启动
#define STACK_BASE 0x33f00000
#define STACK_SIZE 0x8000
//#define UBOOT_RAM_BASE 0x33f80000
/* NAND Flash Controller */
#define NAND_CTL_BASE 0x4E000000
#define bINT_CTL(Nb) __REG(INT_CTL_BASE +(Nb))
/* Offset */
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFADDR 0x0c
#define oNFDATA 0x10
#define oNFSTAT 0x20
#define oNFECC 0x2c
/*GPIO */
#define GPIO_CTL_BASE 0x56000000
#define oGPIO_B 0x10
#define oGPIO_CON 0x0 /* R/W,Configures the pins of the port */
#define oGPIO_DAT 0x4 /*R/W, Data register for port */
#define oGPIO_UP 0x8 /*R/W, Pull-up disable register */
#endif /*__CONFIG_H */
12. 修改board/tekkaman/tekkaman2440/lowlevel_init.S文件
......
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */
#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */
#defineTrp 0x2 /* 4clk */
#define Trc 0x3 /* 7clk */
#define Tchr 0x2 /* 3clk */
#defineREFCNT 1012
......
注:参数的值按照SKY提供的对应文件的参数修改过来。
13. 修改/board/tekkaman/tekkaman2440/tekkaman2440.c
因为SKY2440和smdk2410的GPIO连接有所不同,修改其对GPIO和PLL的配置(请参阅SKY2440的硬件说明、2440芯片手册和提供的uboot相对应的文件):这个函数我想不用我解释了吧!其实有些IO口在驱动里可以重新设置,但有时没有必要单单写一个IO驱动,例如串口的端口设置需要将他设置为rx或tx用那就可以直接改这了。
......
#elifFCLK_SPEED==1 /* Fout = 405MHz */
//#define M_MDIV 0x5c
//#define M_PDIV 0x4
//#define M_SDIV 0x0
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
......
#elif USB_CLOCK==1
//#defineU_M_MDIV 0x48
//#define U_M_PDIV 0x3
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
......
/* set up the I/O ports */
gpio->GPACON= 0x007FFFFF;
//gpio->GPBCON = 0x00044556;
gpio->GPBCON = 0x00055556;
......
/* arch number of S3C2440-Board */
gd->bd->bi_arch_number = MACH_TYPE_S3C2440 ;
机码ID号必须和内核的机码对上,我们的是168,你找到他不要另加一个,因为我就犯过这个错误,他本身里面就有一个,你得覆盖他,要不然他还会认他以前的那个号,别忘了他的配置文件,是按照行读的,一旦读到匹配的参数就会跳出循环,导致你在后面加的根本就没起上作用。
/*adress of boot parameters */
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. 为了实现NAND Flash的读写,再次修改/include/configs/tekkaman2440.h
(请格外注意:如果编译时报错,在Linux下用KWrite等有高亮显示的文本编辑器看看文件的注释是不是为注释应有的颜色(KWrite中为灰色),如果不是,则将注释删除。因为#define后面的注释被认为是程序的一部分。建议注释和#define分行写)
......
/*
* High Level Configuration Options
* (easy to change)
*/
#define CONFIG_ARM920T 1 /* This is an ARM920T Core */
#define CONFIG_S3C2440 1 /* in a SAMSUNG S3C2440SoC */
#define CONFIG_tekkaman2440 1 /* on aSAMSUNG tekkaman2440 Board */
......
/***********************************************************
* Command definition
***********************************************************/
#define CONFIG_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)
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
#define CFG_LONGHELP
/* undef to save memory */
#define CFG_PROMPT "[Tekkaman2440]#"
/*Monitor Command Prompt */
#define CFG_CBSIZE 256
/* Console I/O Buffer Size */
......
#define CFG_LOAD_ADDR 0x30008000
/* default load address */
......
/* Timeout for Flash Write */
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0X20000
//#define ENV_IS_EMBEDDED 1
#define CFG_NAND_LEGACY 定义后便调用我们的board/tekkaman/tekkaman2440/tekkaman2440.c中的nand_init()函数进行nand初始化
#defineCFG_ENV_SIZE 0x10000
/* Total Size of Environment Sector */
/*----------------------------------------------------------------------
* NAND flash settings
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
#define CFG_NAND_BASE 0x4E000000
/* NandFlash控制器在SFR区起始寄存器地址*/
#define CFG_MAX_NAND_DEVICE 1
/* 支持的最在Nand Flash数据*/
#define SECTORSIZE 512
/* 1页的大小 */
#define NAND_SECTOR_SIZE SECTORSIZE
#define NAND_BLOCK_MASK 511
/* 页掩码 */
#define ADDR_COLUMN 1
/* 一个字节的Column地址*/
#define ADDR_PAGE 3
/*3字节的页块地址!!!!!*/
#defineADDR_COLUMN_PAGE 4
/*总共4字节的页块地址!!!!! */
#defineNAND_ChipID_UNKNOWN 0x00
/*未知芯片的ID号*/
#defineNAND_MAX_FLOORS 1
#defineNAND_MAX_CHIPS 1
/*Nand Flash命令层底层接口函数*/
这些前面基本已经提到/* Nand Flash命令层底层接口函数 */
#defineWRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}
#defineWRITE_NAND_ADDRESS(d, adr) {rNFADDR = d;}
#define WRITE_NAND(d, adr){rNFDATA = d;}
#define READ_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)
/*the following functions are NOP's because S3C24X0handles this in hardware */
/*下面一组操作对Nand Flash无效 */
#define NAND_CTL_CLRALE(nandptr)
#defineNAND_CTL_SETALE(nandptr)
#defineNAND_CTL_CLRCLE(nandptr)
#defineNAND_CTL_SETCLE(nandptr)
/*允许Nand Flash写校验*/
#defineCONFIG_MTD_NAND_VERIFY_WRITE 1
......
定义了各个寄存器
#define rNFCONF (*(volatileunsigned int *)0x4e000000)
#define rNFCONT (*(volatileunsigned int *)0x4e000004)
#define rNFCMD (*(volatileunsigned char *)0x4e000008)
#define rNFADDR (*(volatileunsigned char *)0x4e00000c)
#define rNFDATA (*(volatileunsigned char *)0x4e000010)
#define rNFSTAT (*(volatileunsigned int *)0x4e000020)
#define rNFECC (*(volatileunsigned int *)0x4e00002c)
#endif /*__CONFIG_H */
注:下面的这些定义是SKY提供的uboot参数,请按照这个参数把/include/configs/tekkaman2440.h修改过来
#define CONFIG_BOOTDELAY 1 模式选折延时时间
#define CONFIG_BOOTARGS "noinitrdroot=/dev/mtdblock2 init=/linuxrc console=ttySAC0"
这里设置的都是传递给内核的参数,
initrd的最初的目的是为了把kernel的启动分成两个阶段:在kernel中保留最少最基本的启动代码,然后把对各种各样硬件设备的支持以模块的方式放在initrd中,这样就在启动过程中可以从initrd所mount的根文件系统中装载需要的模块。这样的一个好处就是在保持kernel不变的情况下,通过修改initrd中的内容就可以灵活的支持不同的硬件。在启动完成的最后阶段,根文件系统可以重新mount到其他设备上。如果把需要的功能全都编译到内核中(非模块方式),只需要一个内核文件即可,我们这里就没有用到它,
root=/dev/mtdblock2 是指定文件系统路径,在dev/的第二个分区了
init=/linuxrc他是个脚本,放在文件系统的根目录下,里面是文件系统启动时要挂载所要执行的准备console=ttySAC0用哪个串口
#define CONFIG_ETHADDR 0a:1b:2c:3d:4e:5f 网卡mac地址I ,全国独一个啊
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.6
#define CONFIG_SERVERIP 192.168.1.8
/*#define CONFIG_BOOTFILE "elinos-lart" */
#define CONFIG_BOOTCOMMAND "nboot 0x32000000 0 0x4C000; bootm 0x32000000" 0x4C000是变动的值
nbootInAddr dev FlAddr
InAddr:需要装载到的内存的地址。
FlAddr:在nand flash上uImage存放的地址
dev:设备号
需要提前设置环境变量,否则nboot不会调用bootm
Tekkaman2440#setenv autostart yes
0x4C000是内核在nand中起始的地址,看nand分区那就可以了解它的由来,在这里我们将内核搬运到0x32000000处,跳到此处执行什么呢?此时把压缩的内核进行解压,解压代码在内核的头部,解压到0x30008000处,这就是内核的解压后的地址。我们的内核最终是从这里开始执行的。
15.在个文件中添加“CONFIG_S3C2440”,使得原来s3c2410的代码可以编译进来。
(1)/include/common.h文件的第454行:
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_LH7A40X) ||defined(CONFIG_S3C2440)
(2)/include/s3c24x0.h文件的第85、95、99、110、148、404行:
#if defined(CONFIG_S3C2410)|| defined (CONFIG_S3C2440)
(3)/cpu/arm920t/s3c24x0/interrupts.c文件的第33行:
#if defined(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行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB)||defined (CONFIG_S3C2440)
第26行:#elifdefined(CONFIG_S3C2410)|| defined (CONFIG_S3C2440)
void serial_setbrg (void)
{
S3C24X0_UART * const uart= S3C24X0_GetBase_UART(UART_NR);
int i;
unsigned int reg = 0;
/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
reg = get_PCLK() / (16 * gd->baudrate) - 1;
/* FIFO enable, Tx/Rx FIFO clear */
uart->UFCON = 0x00;
uart->UMCON = 0x0;
/* Normal,Noparity,1 stop,8 bit */
uart->ULCON = 0x3;
......
}
(5)/cpu/arm920t/s3c24x0/speed.c文件的第33行:
#if defined(CONFIG_S3C2400) || defined (CONFIG_S3C2410) || defined (CONFIG_TRAB) || defined (CONFIG_S3C2440)
第37行:#elifdefined(CONFIG_S3C2410)||defined (CONFIG_S3C2440)
顺便修改源代码,以匹配s3c2440:
static ulong get_PLLCLK(int pllreg)
{
......
m =((r & 0xFF000) >> 12) + 8;
p =((r & 0x003F0)>> 4) + 2;
s =r & 0x3;
//tekkaman
#if defined(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));
}
......
/* return FCLK frequency */
ulong get_FCLK(void)
{
return(get_PLLCLK(MPLL));
}
/* return HCLK frequency */
ulong get_HCLK(void)
{
S3C24X0_CLOCK_POWER * const clk_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行:
#elif defined(CONFIG_S3C2410)|| defined(CONFIG_S3C2440)
(i2c的文件还没修改,因为没用到)
(7)/rtc/s3c24x0_rtc.c文件的第35行:
#elif defined(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加入
static structnand_flash_dev nand_flash_ids[] = {
......
{"Samsung KM29N16000",NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000, 0},
{"Samsung K9F1208U0B", NAND_MFR_SAMSUNG, 0x76, 26, 0,3, 0x4000, 0},
{"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000, 0},
......
};
注:可参照SKY提供的uboot对应文件修改。
17.修改common/env_nand.c
......
#ifdef CONFIG_INFERNO
#error CONFIG_INFERNO not supported yet
#endif
int nand_legacy_rw (struct nand_chip* nand, int cmd,
size_t start, size_t len,
size_t * retlen, u_char * buf);
extern struct nand_chipnand_dev_desc[CFG_MAX_NAND_DEVICE];
extern int nand_legacy_erase(struct nand_chip *nand, size_t ofs, size_tlen, int clean);
/* info for NAND chips,defined in drivers/nand/nand.c */
extern nand_info_t nand_info[CFG_MAX_NAND_DEVICE];
......
env 将从永久性存储介质中搬到RAM里面,以后对env的操作,比如修改环境变量的值,删除环境变量的值都是对这个 env在RAM中的拷贝进行操作,由于RAM的特性,下次启动时所做的修改将全部消失,u-boot提供了将env写回永久性存储介质的命令支持 : saveenv,不同版本的 env( nand flash, flash …)实现方式不同,以Nand Flash的实现(未定义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的原因了,哈哈,其实我也是才知道的,以前这块也有点糊涂
#else/* ! CFG_ENV_OFFSET_REDUND */完成对环境变量的存储
int saveenv(void)
{
ulong total;
int ret = 0;
puts("Erasing Nand...");
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))
if (nand_legacy_erase(nand_dev_desc +0, CFG_ENV_OFFSET, CFG_ENV_SIZE, 0))
return 1;
puts("Writing to Nand... ");
total =CFG_ENV_SIZE;
//ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total,(u_char*)env_ptr);
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)
return 1;
puts ("done\n");
return ret;
......
#else /* ! CFG_ENV_OFFSET_REDUND */
/*
* The legacy NAND code saved the environment in the first NAND devicei.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void) 完成环境变量的重新定位,把它从nand搬运到sdram里面
{
#if !defined(ENV_IS_EMBEDDED) env 是否存在于 u-boot TEXT段中
ulong total;
int ret;
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的校验码对比,看数据是否出错,从这里也可以看出在系统第一次启动时,Nand Flash里面没有存储任何环境变量,crc校验肯定回出错,当我们保存环境变量后,接下来再启动板子u-boot就不会再报crc32出错了。
18.在/board/tekkaman/tekkaman2440/tekkaman2440.c文件的末尾添加对Nand Flash的初始化函数(在后面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的寄存器。为了便于大家理解他,我把我的参考资料贴在这,看了便知道了!!!!!
Nand flash主要内设命令详细介绍
Nand Flash命令执行是通过将命令字送到Nand Flash控制器的命令寄存器来执行。
Nand Flash的命令是分周期执行的,每条命令都有一个或多个执行周期,每个执行周期都有相映代码表示该周
期将要执行的动作。
主要命令有:Read 1、Read 2、Read ID、Reset、Page Program、Block Erase、Read Status。
详细介绍如下:
1. Read 1:
功能:表示将要读取Nand flash存储空间中一个页的前半部分,并且将内置指针定位到前半部分的第一个字节。
命令代码:00h
2. Read 2:
功能:表示将要读取Nand flash存储空间中一个页的后半部分,并且将内置指针定位到后半部分的第一个字节。
命令代码:01h
3. Read ID:
功能:读取Nand flash芯片的ID号
命令代码:90h
4. Reset:
功能:重启芯片。
命令代码:FFh
5. Page Program:
功能:对页进行编程命令,用于写操作。
命令代码:首先写入00h(A区)/01h(B区)/05h(C区),表示写入那个区; 再写入80h开始编程模式(写入模式),接
下来写入地址和数据;最后写入10h表示编程结束.
6. Block Erase
功能:块擦除命令。
命令代码:首先写入60h进入擦写模式,然后输入块地址;接下来写入D0h, 表示擦写结束.
7. Read Status
功能:读取内部状态寄存器值命令。
命令代码:70h
Nand Flash 控制器工作原理
对Nand Flash存储芯片进行操作,必须通过Nand Flash控制器的专用寄存器才能完成。所以,不能对Nand
Flash进行总线操作。而Nand Flash的写操作也必须块方式进行。对Nand Flash的读操作可以按字节读取。
Nand Flash控制器特性
1. 支持对Nand Flash芯片的读、检验、编程控制
2. 如果支持从Nand Flash启动,在每次重启后自动将前Nand Flash的前4KB数据搬运到ARM的内部RAM中
3. 支持ECC校验
Nand Flash控制器工作原理
Nand Flash控制器在其专用寄存器区(SFR)地址空间中映射有属于自己的特殊功能寄存器,就是通过将Nand
Flash芯片的内设命令写到其特殊功能寄存器中,从而实现对Nand flash芯片读、检验和编程控制的。特殊功能
寄存器有:NFCONF、NFCMD、NFADDR、NFDATA、NFSTAT、NFECC。寄存详细说明见下一节。
Nand flash 控制器中特殊功能寄存器详细介绍
1. 配置寄存器(NFCONF)
功能:用于对Nand Flash控制器的配置状态进行控制。
在地址空间中地址:0x4E000000,其中:
Bit15:Nand Flash控制器使能位,置0代表禁止Nand Flash控制器,置1代表激活Nand Flash控制器;
要想访问Nand Flash芯片上存储空间,必须激活Nand Flash控制器。在复位后该位自动置0,因此在初始化时
必须将该位置为1。
Bit12:初始化ECC位,置1为初始化ECC;置0为不初始化ECC。
Bit11:Nand Flash芯片存储空间使能位,置0代表可以对存储空间进行操作;置1代表禁止对存储空
间进行操作。在复位后,该位自动为1。
Bit10-8:TACLS位。根据此设定CLE&ALE的周期。TACLS的值范围在0-7之间。
Bit6-4、2-0分别为:TWRPH0、TWRPH1位。设定写操作的访问周期。其值在0-7之间。
2. 命令寄存器(NFCMD)
功能:用于存放Nand flash芯片内设的操作命令。
在地址空间中地址:0x4E000004,其中:
Bit0-7:存放具体Nand flash芯片内设的命令值。其余位保留以后用。
3. 地址寄存器(NFADDR)
功能:用于存放用于对Nand flash芯片存储单元寻址的地址值。
在地址空间中地址:0x4E000008,其中:
Bit0-7:用于存放地址值。因为本款Nand flash芯片只有I/O0-7的地址/数据复用引脚且地址是四周
期每次8位送入的,所以这里只用到8位。其余位保留待用。
4. 数据寄存器(NFDATA)
功能:Nand flash芯片所有内设命令执行后都会将其值放到该寄存器中。同时,读出、写入Nand flash
存储空间的值也是放到该寄存器。
在地址空间中地址:0x4E00000C,其中:
Bit0-7:用于存放需要读出和写入的数据。其余位保留代用。
5. 状态寄存器(NFSTAT)
功能:用于检测Nand flash芯片上次对其存储空间的操作是否完成。
在地址空间中地址:0x4E000010,其中:
Bit0:置0表示Nand flash芯片正忙于上次对存储空间的操作;置1表示Nand flash芯片准备好接收新
的对存储空间操作的请求。
6. ECC校验寄存器(NFECC)
功能:ECC校验寄存器
在地址空间中地址:0x4E000014,其中:
Bit0Bit7:
ECC0
Bit8Bit15:
ECC1
Bit16Bit23:
ECC2
操作的函数实现
1. 发送命令
#define NF_CMD(cmd){rNFCMD=cmd;}
2. 写入地址
#define NF_ADDR(addr) {rNFADDR=addr;}
3. Nand Flash芯片选中
#define NF_nFCE_L(){rNFCONF&=~(1<<11);}
4. Nand Flash芯片不选中
#define NF_nFCE_H(){rNFCONF|=(1<<11);}
5. 初始化ECC
#define NF_RSTECC(){rNFCONF|=(1<<12);}
6. 读数据
#define NF_RDDATA() (rNFDATA)
7. 写数据
#define NF_WRDATA(data) {rNFDATA=data;}
8. 获取Nand Flash芯片状态
#define NF_WAITRB(){while(!(rNFSTAT&(1<<0)));}
0/假:表示Nand Flash芯片忙状态
1/真:表示Nand Flash已经准备好
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
typedef enum {
NFCE_LOW,
NFCE_HIGH
} NFCE_STATE;
static inline void NF_Conf(u16 conf)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCONF = conf;
}
static inline voidNF_Cont(u16 cont)
{
S3C2410_NAND * const nand = S3C2410_GetBase_NAND();
nand->NFCONT = cont;
}
static inline voidNF_Cmd(u8 cmd)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCMD = cmd;
}
static inline voidNF_CmdW(u8 cmd)
{
NF_Cmd(cmd);
udelay(1);
}
static inline voidNF_Addr(u8 addr)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFADDR = addr;
}
static inline voidNF_SetCE(NFCE_STATE s)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
switch (s) {
case NFCE_LOW:
nand->NFCONT &= ~(1<<1);
break;
case NFCE_HIGH:
nand->NFCONT |= (1<<1);
break;
}
}
static inline voidNF_WaitRB(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
while(!(nand->NFSTAT & (1<<0)));
}
static inline voidNF_Write(u8 data)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFDATA = data;
}
static inline u8NF_Read(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
return(nand->NFDATA);
}
static inline voidNF_Init_ECC(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
nand->NFCONT |=(1<<4);
}
static inline u32NF_Read_ECC(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
return(nand->NFECC);
}
#endif
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe(ulong physadr);
static inline void NF_Reset(void)
{
int i;
NF_SetCE(NFCE_LOW);
NF_Cmd(0xFF); /* reset command */
for(i = 0; i < 10; i++); /* tWB = 100ns. */
NF_WaitRB(); /* wait 200~500us; */
NF_SetCE(NFCE_HIGH);
}
static inline void NF_Init(void)
{
#if 0 /* a little bit too optimistic */
#define TACLS 0
#define TWRPH0 3
#define TWRPH1 0
#else
#define TACLS 0
#define TWRPH0 4
#define TWRPH1 2
#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);*/
/* 1 1 1 1, 1 xxx, r xxx, r xxx */
/* En 512B 4step ECCR nFCE=H tACLS tWRPH0 tWRPH1 */
NF_Reset();
}
void
nand_init(void)
{
S3C2410_NAND * const nand= S3C2410_GetBase_NAND();
NF_Init();
#ifdef DEBUG
printf("NAND flash probing at 0x%.8lX\n", (ulong)nand);
#endif
printf ("%4lu MB\n", nand_probe((ulong)nand) >> 20);
}
#endif
19.在/include/s3c24x0.h中加入2440 的NAND FLASH 寄存器定义和CAMDIVN定义:
......
typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
S3C24X0_REG32 CAMDIVN;
}/*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER;
......
#if defined(CONFIG_S3C2410)
/* NAND FLASH (see S3C2410 manual chapter 6) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFECC;
}/*__attribute__((__packed__))*/ S3C2410_NAND;
#endif
#if defined (CONFIG_S3C2440)
/* NAND FLASH (see S3C2440 manual chapter 6) */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFECC;
}/*__attribute__((__packed__))*/ S3C2410_NAND;
#endif
20.移植DM9000网卡
在/include/configs/tekkaman2440.h文件中修改添加对DM9000的支持,屏蔽CS8900:
/*
* Hardware drivers
*/
//#defineCONFIG_DRIVER_CS8900 1 /* we have a CS8900on-board */
//#define CS8900_BASE 0x19000300
//#define CS8900_BUS16 1 /* theLinux driver does accesses as shorts */
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO CONFIG_DM9000_BASE
#define DM9000_DATA (CONFIG_DM9000_BASE+4)
#define CONFIG_DM9000_USE_16BIT
在这里#define CONFIG_DM9000_BASE的定义最为重要。不同的板子只要修改这个参数即可。
我是按照SKY提供的Uboot代码的对应文件的参数修改的。
修正BUG(修改/drivers/dm9000.c文件)
(1)网卡MAC地址错误的解决方法:
/* Initilize dm9000 board
*/
int
eth_init(bd_t * bd)
{
......
/* Set Node address */
/* 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)“could not establish link” 提示和慢响应的解决方法:
/* Initilize dm9000 board
*/
int
eth_init(bd_t * bd)
{
......
DM9000_iow(DM9000_RCR, RCR_DIS_LONG |RCR_DIS_CRC | RCR_RXEN); /* RX enable */
DM9000_iow(DM9000_IMR, IMR_PAR); /* EnableTX/RX interrupt mask */
#if 0
i = 0;
while (!(phy_read(1) & 0x20)) { /*autonegation complete bit */
udelay(1000);
i++;
if (i == 10000) {
printf("could notestablish link\n");
return 0;
}
printf(" link=%d\n",i);
}
/* see what we've got */
lnk = phy_read(17) >> 12;
printf("operating at ");
switch (lnk) {
case 1:
printf("10M half duplex ");
break;
case 2:
printf("10M full duplex ");
break;
case 4:
printf("100M half duplex ");
break;
case 8:
printf("100M full duplex ");
break;
default:
printf("unknown: %d ", lnk);
break;
}
printf("mode\n");
#endif
return 0;
}
红色的字符是要做的修改:功能是屏蔽无用的语句。其实被屏蔽的语句是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_S3C2440 168,这样就可以启动了。
现在的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文件
vi makefile
第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的分区情况的
static struct mtd_partitionsmdk_default_nand_part[]={
[0]= {
.name = “UBOOT”,
.size = SZ_64K*4, //0x0~0x40000,256K
.offset = 0,
},
[1] = {
.name = “kernel 2.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,如下:
static struct s3c2410_platform_nand smdk_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
static void __init smdk2440_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位宽)
unsigned inb(unsigned port);
void outb(unsigned char byte, unsigned port);
· 读写字端口(16位宽)
unsigned inw(unsigned port);
void outw(unsigned short word, unsigned port);
· 读写长字端口(32位宽)
unsigned inl(unsigned port);
void outl(unsigned longword, unsigned port);
· 读写一串字节
void insb(unsigned port, void *addr, unsigned long count);
void outsb(unsigned port, void *addr, unsigned long count);
· insb()从端口port开始读count个字节端口,并将读取结果写入addr指向的内存;outsb()将addr指向的内存的count个字节连续地写入port开始的端口。
· 读写一串字
void insw(unsigned port, void *addr, unsigned long count);
void outsw(unsigned port, void *addr, unsigned long count);
· 读写一串长字
void insl(unsigned port, void *addr, unsigned long count);
void outsl(unsigned port, void *addr, unsigned long count);
上述各函数中I/O端口号port的类型高度依赖于具体的硬件平台,因此,只是写出了unsigned。
(3)readb和writeb:
在设备的物理地址被映射到虚拟地址之后,尽管可以直接通过指针访问这些地址,但是工程师宜使用Linux内核的如下一组函数来完成设备内存映射的虚拟地址的读写,这些函数包括:
· 读I/O内存
unsigned int ioread8(void *addr);
unsigned int ioread16(void *addr);
unsigned int ioread32(void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux 2.6中仍然被支持):
unsigned readb(address);
unsigned readw(address);
unsigned readl(address);
· 写I/O内存
void iowrite8(u8 value, void *addr);
void iowrite16(u16 value, void *addr);
void iowrite32(u32 value, void *addr);
与上述函数对应的较早版本的函数为(这些函数在Linux 2.6中仍然被支持):
void writeb(unsigned value, address);
void writew(unsigned value, address);
void writel(unsigned value, address);
(4)把I/O端口映射到“内存空间”:
void *ioport_map(unsigned long port, unsigned int count);
通过这个函数,可以把port开始的count个连续的I/O端口重映射为一段“内存空间”。然后就可以在其返回的地址上像访问I/O内存一样访问这些I/O端口。当不再需要这种映射时,需要调用下面的函数来撤消:
void ioport_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,声卡,网卡等。
定义如下:
static struct map_desc smdk2440_iodesc[] __initdata = {
/* ISA IO Space map (memory space selected by A24) */
{ (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定义如下:
/* minimal IO mapping */
static struct map_desc s3c_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));
定义如下:
static struct map_desc s3c2440_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.修改nand flash的校验方式,去掉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内核(打补丁的方式):
cd yaffs2
./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 “Pseudo filesystems”下面添加如下代码:
config DEVFS_FS
bool “/dev file system support(OBSOLETE)”
default y
config DEVFS_MOUNT
bool “Automatically mount atboot”
default y
depends on DEVFS_FS
有的blog说不需要增加这一段,因为2.6.24.4已经把devfs的相关代码删除了,即使添加了也没有用.我在移植内核的时候还是加上了这段代码,不加的编译情况还没有试.(经测试,这段现在不加也可以)
8.复制编译配置文件到2.6.24.4内核根目录下.
cparch/arm/configs/s3c2410_defconfig.config
将config覆盖掉,他是内核的配置,我们在图形界面下配置内核后的最终保存结果就是变成了config文件,我们用s3c2410_defconfig的配置,是因为他接近我们的2440的配置,再此基础上修改内核配置。
9.编译内核选项:make menuconfig
[*] Enable loadable module support --->
[*] Module unloading
[*] Automatic kernelmodule loading
选择这两个,剩下的可以去掉
System Type ---->
[*] S3C2410 DMA support
[*] Support ARM920T processor
S3C2410 Machines --->
[*] SMDK2410/A9M2410
S3C2440 Machines --->
[*] SMDK2440
[*] SMDK2440 with S3C2440CPU module
System Type这部分,只选这些,其他可以全部去掉。另外,网上一些帖子都说只选上SMDK2440就可以了,其他的都去掉,我没有试,不知道行不行.(经过测试,必须SMDK2410的选项)
Boot option ----->
修改启动参数为:
noinitrd root=/dev/mtdblock2init=/linuxrc console=ttySAC0,115200
可能根据个人板子的设置会不一样,我的是从Nand Flash中加载文件系统,其中mtdblock2是存放我的Linux文件系统的分区。不过,在bootloader可以传递内核参数的情况下这个设置是无效的。
Userspace binary formats --->
< > Kernel support for a.out andECOFF binaries (去除该选项,a.out和ECOFF是两种可执行文件的格式,在ARM-Linux下一般都用ELF,所以这两种基本用不上。)
Device Drivers --->
<*> Memory Technology Device(MTD) support --->
[*] MTD partitioning support
<*> NAND Device Support --->
<*> NAND Flash support for S3C2410/S3C2440SoC
[ ] S3C2410 NAND Hardware ECC //这个要去掉
[*] Network devicesupport --->
[*] Ethernet (10 or 100Mbit) --->
<*> DM9000 support
<*> Real TimeClock --->
“N”掉 [] Set system time from RTC on startup and resume
去掉红字的两个部分,黑子部分选上,其他的选择默认就可以了。
File systems -->
< > Second extended fs support #去除对ext2的支持
< > Ext3 journalling file systemsupport #去除对ext3的支持
<*> Kernel automounter support
<*> Kernel automounter version 4support (also supports v3)
<*> Filesystem in Userspace support
Pseudo filesystems -->
[*] Virtual memory filesystem support (former shm fs)
<*>Userspace-driven configuration filesystem (EXPERIMENTAL)
Miscellaneous filesystems-->
<*> YAFFS2file system support
“N”掉[ ]Autoselect yaffs2 format和
[ ]Cache short names in RAM ,因为这是给每页大于1024B的NAND Flash设计的
<*> Journalling Flash File System v2 (JFFS2)support
(0) JFFS2 debuggingverbosity (0 = quiet, 2 = noisy)
[*] JFFS2 write-bufferingsupport
[ ] JFFS2 summary support(EXPERIMENTAL)
[ ] JFFS2 XATTR support(EXPERIMENTAL)
[*] Advanced compressionoptions for JFFS2
[*] JFFS2 ZLIBcompression support
[*] JFFS2RTIME compression support
[*] JFFS2RUBIN compression support
JFFS2 default compression mode(priority) --->
Network File Systems -->
<*> NFS file system support
--以下最好选上,因为在挂载NFS时可能出现protocol不支持的情况--
[*]Provide NFSv3 client support
[*]Provide client support for the NFSv3 ACL protocol extension
[*] Provide NFSv4 client support (EXPERIMENTAL)
[*] Allow direct I/O on NFS files
-------------------------------------------------------------------------
<*> NFS serversupport
[*] Provide NFSv3 server support
[*]Provide serversupport for the NFSv3 ACL protocol extension
[*] Provide NFSv4 server support(EXPERIMENTAL)
--- Provide NFS server over TCPsupport
[*] Root file systemon NFS
注:我后面用到的根文件系统是cramfs或yaffs.
10.ok,先编译一下内核,make zIamge.编译完在arch/arm/boot下将会有一个zImage文件.
11.生成uboot用的uImage.
Uboot使用的镜像和zImage有点区别,具体可以网上搜一下.
先把Uboot编译后生成的tools/mkImage文件copy到主机的/bin下,然后进入到linux-2.6.24.4内核的根目录下,在执行一下make uImage命令,等上一会就会在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文件中的一行s3c2440 ARCH_S3C2440 S3C2440 362
改成s3c2440 ARCH_S3C2440 S3C2440 168即可.
三、 根文件系统的设计(带用户登录)
移植环境: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 "creatint rootfs dir......"
mkdir rootfs
cd rootfs
echo "making dir : bin dev etc lib proc sbin sysusr"
mkdir bin dev etc lib proc sbin sys usr #必备的8个目录
mkdir usr/bin usr/lib usr/sbin lib/modules
# Don't use mknod ,unless you run this Script as root
# mknod -m 600 dev/console c 5 1
# mknod -m 666 dev/null c 1 3
echo "making dir : mnt tmp var"
mkdir mnt tmp var
chmod 1777 tmp
mkdir mnt/etc mnt/jffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/log var/run var/tmp
chmod 1777 var/tmp
echo "making dir : home root boot"
mkdir home root boot
echo "done"
有一点需要注意,在windows下的回车和linux下的回车不一样,如果你是在windows下把这个脚本编辑好的,那么在linux下运行会有点问题。
在你想要建立根文件系统的地方,运行:
./mkroot
2.进入到dev文件夹创建两个设备文件,需要用root登录创建
Mknod –m 600 console c 5 1;mknod –m 666 null c 1 3;
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:make menuconfig
在原有的基础上修改如下:
Busybox Settings --->
Installation Options --->
[*] Don't use /usr
(前面创建的rootfs所在路径) BusyBox installation prefix
Busybox Library Tuning --->
[*]Support for /etc/networks
[*] Additional editing keys
[*] vi-style line editing commands
(15) History size
[*] History saving
[*] Tab completion
[*] Username completion
[*] Fancy shell prompts
Login/Password Management Utilities --->选项全部N掉,后面单独使用TinyLogin。(因为集成的好像不是很好用,我自己的经验是这样)
Linux Module Utilities --->
[N]Support version 2.2.x to 2.4.x Linux kernels
Shells --->
--- Ash Shell Options 下的选项全选
(4)编译、安装
执行make;make install
执行之后,将会在你的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
vi profile
修改如下:
# /etc/profile: system-wide .profile file for the Bourneshells
echo
echo "Processing /etc/profile... "
# no-op
# Set search library path
echo "Set search library path in /etc/profile"
export LD_LIBRARY_PATH=/lib:/usr/lib
# Set user path
echo "Set user path in /etc/profile"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Set PS1
#注意:ash除了SHELL变量外,支持\u、\h、\W、\$、\!、\n、\w 、\nnn(ASCII字符对应的八进制数)
#以及\e[xx;xxm(彩色特效)等等!
#而且前面还要多加一个 '\'!
echo "Set PS1 in /etc/profile"
export PS1="\\e[05;32m[$USER@\\w\\a]\\$\\e[00;34m"
echo "Done"
echo
(3)增加初始化文件 /etc/inittab,/etc/fstab
vi inittab
::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 /proc procdefaults 0 0
none /tmp ramfsdefaults 0 0
mdev /dev ramfsdefaults 0 0
sysfs /sys sysfsdefaults 0 0
(4)增加初始化脚本/etc/init.d/rcS(如果init.d文件夹没有创建,先创建该文件夹)
Vi init.d/rcS
#! /bin/sh
echo"----------mount all"
/bin/mount –a
echo "----------Startingmdev......"
/bin/echo /sbin/mdev> /proc/sys/kernel/hotplug
mdev –s
(5)删除etc/下的备份文件
rm *~ init.d/*~
(6)为mdev创建配置文件,在etc/下
Vi mdev.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编译安装
make PREFIX=…/rootfs install
PREFIX=用来指定安装路径,我这里的路径为rootfs的根目录.安装完之后会在bin,usr/bin下生成几个文件,和用户登录密码相关的.
(4)创建账号和密码文件
将主机的/etc/passwd,/etc/shadow,/etc/group文件复制到…/rootfs/etc/文件下
并修改…/rootfs/etc/下这几个文件,只保留root账户.
Vi passwd
root:x:0:0:root:/root:/bin/sh
vi group
root:x:0:root
vi shadow
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 …/rootfs myrootfs.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 …/rootfs myrootfs.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 –t tmpfs mdev /dev 使用内存文件系统减少对Flash的读写
1.解压busybox,并配置busybox,可参考上一节的做法.
我来介绍一下他吧,busybox是一个集成了一百多个最常用linux命令和工具的软件,他甚至还集成了一个http服务器和一个telnet服务器,而所有这一切功能却只有区区1M左右的大小.我们平时用的那些linux命令就好比是分立式的电子元件,而busybox就好比是一个集成电路,把常用的工具和命令集成压缩在一个可执行文件里,功能基本不变,而大小却小很多倍,在嵌入式linux应用中,busybox有非常广的应用。
2.安装busybox到rootfs/mini_rootfs下
MakeCONFIG_PREFIX=…./rootfs/mini_rootfs install
将会在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目录:mkdir etc
(2)将busybox下的examples/bootfloopy/etc下的文件copy到mini_rootfs/etc下
(3)修改etc/inittab文件
::sysinit:/etc/init.d/rcS 系统启动最先执行的,rcS是一个脚本
s3c2410_serial0::askfirst:-/bin/sh init进程先输出please press Enter to activatethis console等用户输入回车之后才启动子进程,启动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
ifconfig eth0192.168.1.6 修改本机的ip地址
/bin/mount –a 挂载所有/etc/fstab文件指定的所有文件系统
mkdir /dev/pts devpfs用来支持外部网络连接telnet的虚拟终端
mount -t devptsdevpts /dev/pts
echo /sbin/mdev> /proc/sys/kernel/hotplug 设置内核当有设备拔插时调用/bin/
mdev程序
mdev –s 在/dev目录下生成内核支持的所有设备的节点
要在内核启动时,自动运行mdev。这要修改两个文件:fstab来自动挂载文件系统、修改rcS加入要自动运行的命令。
(5)修改etc/fstab文件
#device mount—point type options dump fsck order 这是一一对应的参数,本文件完成所要自动挂载的文件系统
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
(6)修改etc/profile文件,增加一些定义
#/etc/profile: system-wide .profile file for the Bourne shells
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登录控制台
mknod console c 5 1
mknod null c 3 1
7.构建其他目录
mkdir proc mnt tmp sys root
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>
在/*LCD driverinfo*/后增加自己的液晶驱动代码,参考sky提供的液晶驱动\arch\arm\mach-s3c2410\sky2440.c中的#elif defined(CONFIG_FB_S3C24X0_S320240)
staticstruct s3c2410fb_mach_info smdk2440_lcdcfg__initdata = {。。。。}处的整个结构体的内容替换为:
static struct s3c2410fb_displaysky2440_lcd_cfg __initdata = {
{
/* Configfor 320x240 LCD */
.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,
}
};
static struct s3c2410fb_mach_infosmdk2440_fb_info__initdata = {
。。。。。。。。。}处的整个结构体的内容替换为:
static struct s3c2410fb_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 --->
Graphics support --->
Display device support --->
<*> Displaypanel/monitor support
<*> Support for frame bufferdevices
<*> S3C2410 LCD framebuffer support
Console display driver support --->
<*> FramebufferConsole support
[*] Framebuffer Console Rotation
[*] Select compiled-infonts
[*] VGA8x8 font
[*] VGA8x16 font
[*] Mini4x6 font
[*] Sparc console 8x16font
[*] Bootup logo --->
--- Bootup logo
[*] Standard 224-color Linux logo
3.重新编译内核,下载,运行,你就会看到液晶上的那个小企鹅了,对应的图片为/drivers/video/logo/logo_linux_clut224.ppm.
另外这时可以把LCD当作一个控制台来使用了,例如执行:echo hello > /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行处添加
#if defined (CONFIG_DM9000) ||defined(CONFIG_DM9000_MODULE)
#include <linux/dm9000.h>
#endif
(2)添加DM9000平台设备结构
紧接着前面的地方,添加平台设备结构
/* DM9000 */
#if defined (CONFIG_DM9000) ||defined(CONFIG_DM9000_MODULE)
static struct resource s3c_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,
}
};
static struct dm9000_plat_data s3c_dm9k_platdata = {
.flags= DM9000_PLATF_16BITONLY,
};
static struct platform_device s3c_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)加入到内核设备列表中
static struct platform_device __initdata *smdk_devs[] ={
&s3c_device_nand,
&smdk_led4,
&smdk_led5,
&smdk_led6,
&smdk_led7,
#if defined(CONFIG_DM9000) || defined(CONFIG_DM9000_MODULE)
&s3c_device_dm9k,
#endif
};
2.修改drivers/net/dm9000.c
(1)增加包括头文件代码
在74行附近
#if defined(CONFIG_ARCH_S3C2410)
#include <asm/arch-s3c2410/regs-mem.h>
#endif
(2)设置存储器控制器BANK4使用,设置默认MAC地址
在dm9000_probe()函数中先增加两个变量定义(大概412行)
#ifdefined(CONFIG_ARCH_S3C2410)
unsignedint oldval_bwscon;
unsignedint oldval_bankcon4;
#endif
再增加Bank4的设置(大概427行)
……
PRINTK2("dm9000_probe()");
#if defined(CONFIG_ARCH_S3C2410)
oldval_bwscon= *((volatile unsigned int *)S3C2410_BWSCON);
*((volatileunsigned int *)S3C2410_BWSCON)= (oldval_bwscon & ~(3<<16)) \
|S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
oldval_bankcon4= *((volatile unsigned int *)S3C2410_BANKCON4);
*((volatileunsigned int *)S3C2410_BANKCON4)= 0x1f7c;
#endif
设置默认MAC地址(大概612行)
…..
if(!is_valid_ether_addr(ndev->dev_addr))
printk("%s: Invalidethernet MAC address. Please "
"set using ifconfig\n",ndev->name);
#if defined(CONFIG_ARCH_S3C2410)
printk("nowuse the default MAC address: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:not found (%d).\n", CARDNAME, ret);
#if defined(CONFIG_ARCH_S3C2410)
*((volatile unsigned int *)S3C2410_BWSCON) = oldval_bwscon;
*((volatile unsigned int *)S3C2410_BANKCON4) = oldval_bankcon4;
#endif
……..
(3)注册终端市,指定触发方式,在dm9000_open()中
static int
dm9000_open(struct net_device *dev)
{
board_info_t*db = (board_info_t *) dev->priv;
PRINTK2("enteringdm9000_open\n");
#if defined(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.修改内核配置
Make menuconfig之后,将DM9000编译入内核,或者配置成模块.
Device Drivers --à
Networkdevice support --à
[*]Networkdevice support
Ethernet(10 or 100Mbit) -à
<*>DM9000support
4.重新编译内核:make uImage
七、 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的选项
Device drives ---à
SCSI device support ---à
<*>SCSI device support
[*]legacy /proc/scsi/ support
<*>SCSI disk support
USB support ->
<*> support for Host-side USB
[*] USB device filesystem
<*>OHCI HCD support
<*>USB Mass storage support
HID device --à
<*>USB Human Interface device(full HID) support
[*] /dev/hiddev raw HID device support
重新编译内核,下载.
启动后,如果将usb鼠标插入叠在一起的那个usb接口的下面那个接口,你将会看到提示
[@(none) /dev]#usb 1-1: newlow speed USB device using s3c2410-ohciand address3
usb 1-1: configuration #1chosen from 1 choice
input: USB Mouse as/class/input/input1
input: USB HID v1.00 Mouse[USB Mouse] on usb-s3c24xx-1
并且在dev下增加了几个文件: usbdev1.2, usbdev1.2_ep00, usbdev1.2_ep81
当拔下的时候: [@(none)/dev]#usb 1-1: USB disconnect, address 3
另外拿了块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
下载后改变权限 chmod u+rx uic-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.导出编译工具安装路径
export PATH=$PATH:/...../3.4.1/bin/
source/etc/profile
2.建立qt的文件夹
mkdir /..../myboard/qtopia-arm-home
exportMYHOME=/..../myboard/qtopia-arm-home
3.创建几个文件夹
cd $MYHOME
mkdir arm
cd arm
mkdir libinclude
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 -r lib/uuid ../include
cp lib/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
gedit Makefile
修改
CC= arm-linux-gcc
AR= arm-linux-ar rc
AR2=arm-linux-ranlib
Make
Make install-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
gedit Makefile
修改
[begin]
......
CC=arm-linux-gcc
......
LDSHARED=arm-linux-gcc -shared-Wl,-soname,libz.so.1
CPP=arm-linux-gcc -E
......
AR=arm-linux-ar rc
RANLIB=arm-linux-ranlib
......
prefix =/.../3.4.1/arm-linux
......
[end]
make
cp libz.so* ../lib/
cp *.h ../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
(4)libpng
cd $MYHOME/arm/libpng
cp scripts/makefile.linux ./Makefile
gedit Makefile
修改:
[begin]
.....
AR_RC=arm-linux-ar rc
CC=arm-linux-gcc
.....
RANLIB=arm-linux-ranlib
....
prefix=/.../3.4.1/arm-linux
.....
[end]
make
cp libpng.a ../lib/
cp libpng12.so* ../lib/
cp libpng12.so ../lib/libpng.so
cp *.h ../include/
再同样复制一份到/.../3.4.1/arm-linux/include和/.../3.4.1/arm-linux/lib下
6.创建文件夹nfs
cd $MYHOME
mkdir nfs
7.解压qtopia-free-2.2.0.tar.bz2到nfs文件夹
8.编译qtopia
(1)建立安装目录
mkdir $MYHOME/nfs/qtopia
(2)复制uci-qt2文件
cp uic-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
cp custom-linux-ipaq-g++.cppcustom-linux-arm-g++.cpp
cp custom-linux-ipaq-g++.hcustom-linux-arm-g++.h
(6) 开始配置
./configure -qte '-embedded -xplatformlinux-arm-g++ -qconfig qpe -no-qvfb -depths 16,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 '-xplatform linux-arm-g++-edition pda -displaysize 320x240 -I$MYHOME/arm/include -L$MYHOME/arm/lib-prefix=$MYHOME/nfs/qtopia'
. ./setQpeEnv(两个点号之间有空格)
其中的320*240是对应我的触摸屏的长和宽
(7)make
make过程中可能会有一些错误,根据提示进行修改,但我make时没有出现错误
(8)make install
至此将在$MYHOME/nfs/qtopia中生成一些qt移植所需的文件
9.复制在第四节中得到的文件系统目录(mini_rootfs),改名成qt_rootfs
10.将Qtopia所依赖的库复制到qt_rootfs/lib中
cd $MYHOME/arm
cp lib/* ……/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;mkdir opt;
再将$MYHOME/nfs中的qtopia文件夹复制到qt_rootfs/opt中
13.创建时区文件
cd ……./qt_rootfs
mkdir –pusr/share/zoneinfo
cp –rf/usr/share/zoneinfo/America usr/share/zoninfo/
cp/usr/share/zoneinfo/zone.tab usr/share/zoneinfo/
也可以将$MYHOME/nfs/qtopia-free-2.2.0/qtopia/etc/下的zoneinfo文件夹全部copy到usr/share/
14.伪造触摸屏校验文件
Qtopia第一次启动的时候会运行触摸屏校验程序,由于现在还没移植触摸屏驱动,会导致校验失败,无法进入系统,可以在根文件系统中创建一个触摸校验文件etc/pointercal,内容为1 0 1 0 1 1 65536
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 /tmp tmpfs defaults 0 0
(3)修改etc/init.d/rcS,在最后加入这么一行
/bin/qpe.sh&
16.重新制作yaffs文件系统
./mkyaffsimage………/qt_rootfs qt_rootfs.yaffs
17.重新将qt_rootfs.yaffs烧写进开发板,启动即可
注:目前还不支持触摸屏,可能要用到qtopia自带的tslib或者要用到tslib.1.3.tar.bz2.
九、
十、
十一、
十二、
十三、
十四、
十五、