嵌入式Linux开发环境的搭建之:U-Boot移植
扫描二维码
随时随地手机看文章
简单地说,Bootloader就是在操作系统内核运行之前运行的一段程序,它类似于PC机中的BIOS程序。通过这段程序,可以完成硬件设备的初始化,并建立内存空间的映射关系,从而将系统的软硬件环境带到一个合适的状态,为最终加载系统内核做好准备。
通常,Bootloader比较依赖于硬件平台,特别是在嵌入式系统中,更为如此。因此,在嵌入式世界里建立一个通用的Bootloader是一件比较困难的事情。尽管如此,仍然可以对Bootloader归纳出一些通用的概念来指导面向用户定制的Bootloader设计与实现。
(1)Bootloader所支持的CPU和嵌入式开发板。
每种不同的CPU体系结构都有不同的Bootloader。有些Bootloader也支持多种体系结构的CPU,如后面要介绍的U-Boot支持ARM、MIPS、PowerPC等众多体系结构。除了依赖于CPU的体系结构外,Bootloader实际上也依赖于具体的嵌入式板级设备的配置。
(2)Bootloader的存储位置。
系统加电或复位后,所有的CPU通常都从某个由CPU制造商预先安排的地址上取指令。而基于CPU构建的嵌入式系统通常都有某种类型的固态存储设备(比如ROM、EEPROM或Flash等)被映射到这个预先安排的地址上。因此在系统加电后,CPU将首先执行Bootloader程序。
(3)Bootloader的启动过程分为单阶段和多阶段两种。通常多阶段的Bootloader能提供更为复杂的功能,以及更好的可移植性。
(4)Bootloader的操作模式。大多数Bootloader都包含两种不同的操作模式:“启动加载”模式和“下载”模式,这种区别仅对于开发人员才有意义。
n 启动加载模式:这种模式也称为“自主”模式。也就是Bootloader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程并没有用户的介入。这种模式是嵌入式产品发布时的通用模式。
n 下载模式:在这种模式下,目标机上的Bootloader将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被Bootloader保存到目标机的RAM中,然后再被Bootloader写入到目标机上的Flash类固态存储设备中。Bootloader的这种模式在系统更新时使用。工作于这种模式下的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。
(5)Bootloader与主机之间进行文件传输所用的通信设备及协议,最常见的情况就是,目标机上的Bootloader通过串口与主机之间进行文件传输,传输协议通常是xmodem/ymodem/zmodem等。但是,串口传输的速度是有限的,因此通过以太网连接并借助TFTP等协议来下载文件是个更好的选择。
2.Bootloader启动流程Bootloader的启动流程一般分为两个阶段:stage1和stage2,下面分别对这两个阶段进行讲解。
(1)Bootloader的stage1。
在stage1中Bootloader主要完成以下工作。
n 基本的硬件初始化,包括屏蔽所有的中断、设置CPU的速度和时钟频率、RAM初始化、初始化外围设备、关闭CPU内部指令和数据cache等。
n 为加载stage2准备RAM空间,通常为了获得更快的执行速度,通常把stage2加载到RAM空间中来执行,因此必须为加载Bootloader的stage2准备好一段可用的RAM空间。
n 复制stage2到RAM中,在这里要确定两点:①stage2的可执行映像在固态存储设备的存放起始地址和终止地址;②RAM空间的起始地址。
n 设置堆栈指针sp,这是为执行stage2的C语言代码做好准备。
(2)Bootloader的stage2。
在stage2中Bootloader主要完成以下工作。
n 用汇编语言跳转到main入口函数。
由于stage2的代码通常用C语言来实现,目的是实现更复杂的功能和取得更好的代码可读性和可移植性。但是与普通C语言应用程序不同的是,在编译和链接Bootloader这样的程序时,不能使用glibc库中的任何支持函数。
n 初始化本阶段要使用到的硬件设备,包括初始化串口、初始化计时器等。在初始化这些设备之前可以输出一些打印信息。
n 检测系统的内存映射,所谓内存映射就是指在整个4GB物理地址空间中指出哪些地址范围被分配用来寻址系统的内存。
n 加载内核映像和根文件系统映像,这里包括规划内存占用的布局和从Flash上复制数据。
n 设置内核的启动参数。
5.2.2U-Boot概述1.U-Boot简介U-Boot(UniversalBootloader)是遵循GPL条款的开放源码项目。它是从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,事实上,不少U-Boot源码就是相应的Linux内核源程序的简化,尤其是一些设备的驱动程序,这从U-Boot源码的注释中能体现这一点。但是U-Boot不仅仅支持嵌入式Linux系统的引导,而且还支持NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等嵌入式操作系统。其目前要支持的目标操作系统是OpenBSD、NetBSD、FreeBSD、4.4BSD、Linux、SVR4、Esix、Solaris、Irix、SCO、Dell、NCR、VxWorks、LynxOS、pSOS、QNX、RTEMS、ARTOS。这是U-Boot中Universal的一层含义,另外一层含义则是U-Boot除了支持PowerPC系列的处理器外,还能支持MIPS、x86、ARM、NIOS、XScale等诸多常用系列的处理器。这两个特点正是U-Boot项目的开发目标,即支持尽可能多的嵌入式处理器和嵌入式操作系统。就目前为止,U-Boot对PowerPC系列处理器支持最为丰富,对Linux的支持最完善。
2.U-Boot特点U-Boot的特点如下。
n 开放源码;
n 支持多种嵌入式操作系统内核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;
n 支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
n 较高的可靠性和稳定性;
n 高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求和产品发布等;
n 丰富的设备驱动源码,如串口、以太网、SDRAM、Flash、LCD、NVRAM、EEPROM、RTC、键盘等;
n 较为丰富的开发调试文档与强大的网络技术支持。
3.U-Boot主要功能U-Boot可支持的主要功能列表。
n 系统引导:支持NFS挂载、RAMDISK(压缩或非压缩)形式的根文件系统。支持NFS挂载,并从Flash中引导压缩或非压缩系统内核。
n 基本辅助功能:强大的操作系统接口功能;可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤其对Linux支持最为强劲;支持目标板环境参数多种存储方式,如Flash、NVRAM、EEPROM;CRC32校验,可校验Flash中内核、RAMDISK映像文件是否完好。
n 设备驱动:串口、SDRAM、Flash、以太网、LCD、NVRAM、EEPROM、键盘、USB、PCMCIA、PCI、RTC等驱动支持。
n 上电自检功能:SDRAM、Flash大小自动检测;SDRAM故障检测;CPU型号。
n 特殊功能:XIP内核引导。
5.2.3U-Boot源码导读1.U-Boot源码结构U-Boot源码结构如图5.27所示。
图5.27U-Boot源码结构
n board:和一些已有开发板有关的代码,比如makefile和U-Boot.lds等都和具体开发板的硬件和地址分配有关。
n common:与体系结构无关的代码,用来实现各种命令的C程序。
n cpu:包含CPU相关代码,其中的子目录都是以U-BOOT所支持的CPU为名,比如有子目录arm926ejs、mips、mpc8260和nios等,每个特定的子目录中都包括cpu.c和interrupt.c,start.S等。其中cpu.c初始化CPU、设置指令Cache和数据Cache等;interrupt.c设置系统的各种中断和异常,比如快速中断、开关中断、时钟中断、软件中断、预取中止和未定义指令等;汇编代码文件start.S是U-BOOT启动时执行的第一个文件,它主要是设置系统堆栈和工作方式,为进入C程序奠定基础。
n disk:disk驱动的分区相关代码。
n doc:文档。
n drivers:通用设备驱动程序,比如各种网卡、支持CFI的Flash、串口和USB总线等。
n fs:支持文件系统的文件,U-BOOT现在支持cramfs、fat、fdos、jffs2和registerfs等。
n include:头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。
n net:与网络有关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。
n lib_arm:与ARM体系结构相关的代码。
n tools:创建S-Record格式文件和U-BOOTimages的工具。
2.U-Boot重要代码(1)cpu/arm920t/start.S
这是U-Boot的起始位置。在这个文件中设置了处理器的状态、初始化中断向量和内存时序等,从Flash中跳转到定位好的内存位置执行。
.globl_start(起始位置:中断向量设置)
_start:breset
ldrpc,_undefined_instruction
ldrpc,_software_interrupt
ldrpc,_prefetch_abort
ldrpc,_data_abort
ldrpc,_not_used
ldrpc,_irq
ldrpc,_fiq
_undefined_instruction:.wordundefined_instruction
_software_interrupt:.wordsoftware_interrupt
_prefetch_abort:.wordprefetch_abort
_data_abort:.worddata_abort
_not_used:.wordnot_used
_irq:.wordirq
_fiq:.wordfiq
_TEXT_BASE:(代码段起始位置)
.wordTEXT_BASE
.globl_armboot_start
_armboot_start:
.word_start
/*
*Thesearedefinedintheboard-specificlinkerscript.
*/
.globl_bss_start(BSS段起始位置)
_bss_start:
.word__bss_start
.globl_bss_end
_bss_end:
.word_end
reset:(执行入口)
/*
*setthecputoSVC32mode;使处理器进入特权模式
*/
mrsr0,cpsr
bicr0,r0,#0x1f
orrr0,r0,#0xd3
msrcpsr,r0
relocate:(代码的重置)/*relocateU-BoottoRAM*/
adrr0,_start/*r0<-currentpositionofcode*/
ldrr1,_TEXT_BASE/*testifwerunfromflashorRAM*/
cmpr0,r1/*don'trelocduringdebug*/
beqstack_setup
ldrr2,_armboot_start
ldrr3,_bss_start
subr2,r3,r2/*r2<-sizeofarmboot*/
addr2,r0,r2/*r2<-sourceendaddress*/
copy_loop:(拷贝过程)
ldmiar0!,{r3-r10}/*copyfromsourceaddress[r0]*/
stmiar1!,{r3-r10}/*copytotargetaddress[r1]*/
cmpr0,r2/*untilsourceendaddreee[r2]*/
blecopy_loop
/*Setupthestack;设置堆栈*/
stack_setup:
ldrr0,_TEXT_BASE/*upper128KiB:relocateduboot*/
subr0,r0,#CFG_MALLOC_LEN/*mallocarea*/
subr0,r0,#CFG_GBL_DATA_SIZE/*bdinfo*/
clear_bss:(清空BSS段)
ldrr0,_bss_start/*findstartofbsssegment*/
ldrr1,_bss_end/*stophere*/
movr2,#0x00000000/*clear*/
clbss_l:strr2,[r0]/*clearloop...*/
addr0,r0,#4
cmpr0,r1
bneclbss_l
ldrpc,_start_armboot
_start_armboot:.wordstart_armboot
(2)interrupts.c
这个文件是处理中断的,如打开和关闭中断等。
#ifdefCONFIG_USE_IRQ
/*enableIRQinterrupts;中断使能函数*/
voidenable_interrupts(void)
{
unsignedlongtemp;
__asm____volatile__("mrs%0,cpsrn"
"bic%0,%0,#0x80n"
"msrcpsr_c,%0"
:"=r"(temp)
:
:"memory");
}
/*
*disableIRQ/FIQinterrupts;中断屏蔽函数
*returnstrueifinterruptshadbeenenabledbeforewedisabledthem
*/
intdisable_interrupts(void)
{
unsignedlongold,temp;
__asm____volatile__("mrs%0,cpsrn"
"orr%1,%0,#0xc0n"
"msrcpsr_c,%1"
:"=r"(old),"=r"(temp)
:
:"memory");
return(old&0x80)==0;
}
#endif
voidshow_regs(structpt_regs*regs)
{
unsignedlongflags;
constchar*processor_modes[]={
"USER_26","FIQ_26","IRQ_26","SVC_26",
"UK4_26","UK5_26","UK6_26","UK7_26",
"UK8_26","UK9_26","UK10_26","UK11_26",
"UK12_26","UK13_26","UK14_26","UK15_26",
"USER_32","FIQ_32","IRQ_32","SVC_32",
"UK4_32","UK5_32","UK6_32","ABT_32",
"UK8_32","UK9_32","UK10_32","UND_32",
"UK12_32","UK13_32","UK14_32","SYS_32",
};
…
}
/*在U-Boot启动模式下,在原则上要禁止中断处理,所以如果发生中断,当作出错处理*/
voiddo_fiq(structpt_regs*pt_regs)
{
printf("fastinterruptrequestn");
show_regs(pt_regs);
bad_mode();
}
voiddo_irq(structpt_regs*pt_regs)
{
printf("interruptrequestn");
show_regs(pt_regs);
bad_mode();
}
(3)cpu.c
这个文件是对处理器进行操作,如下所示:
intcpu_init(void)
{
/*
*setupupstacksifnecessary;设置需要的堆栈
*/
#ifdefCONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;
IRQ_STACK_START=_armboot_start-CFG_MALLOC_LEN-CFG_GBL_DATA_SIZE-4;
FIQ_STACK_START=IRQ_STACK_START-CONFIG_STACKSIZE_IRQ;
#endif
return0;
}
intcleanup_before_linux(void)/*准备加载linux*/
{
/*
*thisfunctioniscalledjustbeforewecalllinux
*itpreparestheprocessorforlinux
*
*weturnoffcachesetc...
*/
unsignedlongi;
disable_interrupts();
/*turnoffI/D-cache:关闭cache*/
asm("mrcp15,0,%0,c1,c0,0":"=r"(i));
i&=~(C1_DC|C1_IC);
asm("mcrp15,0,%0,c1,c0,0"::"r"(i));
/*flushI/D-cache*/
i=0;
asm("mcrp15,0,%0,c7,c7,0"::"r"(i));
return(0);
}
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
.=0x00000000;
.=ALIGN(4);
.text:
{
cpu/arm920t/start.o(.text)
*(.text)
}
.=ALIGN(4);
.rodata:{*(.rodata)}
.=ALIGN(4);
.data:{*(.data)}
.=ALIGN(4);
.got:{*(.got)}
__u_boot_cmd_start=.;
.u_boot_cmd:{*(.u_boot_cmd)}
__u_boot_cmd_end=.;
.=ALIGN(4);
__bss_start=.;
.bss:{*(.bss)}
_end=.;
}
(4)memsetup.S
这个文件是用于配置开发板参数的,如下所示:
/*memsetup.c*/
/*memorycontrolconfiguration*/
/*maker0relativethecurrentlocationsothatit*/
/*readsSMRDATAoutofFLASHratherthanmemory!*/
ldrr0,=SMRDATA
ldrr1,_TEXT_BASE
subr0,r0,r1
ldrr1,=BWSCON /*BusWidthStatusController*/
addr2,r0,#52
0:
ldrr3,[r0],#4
strr3,[r1],#4
cmpr2,r0
bne0b
/*everythingisfinenow*/
movpc,lr
.ltorg
5.2.4U-Boot移植主要步骤(1)建立自己的开发板类型。
阅读makefile文件,在makefile文件中添加两行,如下所示:
fs2410_config:unconfig
@./mkconfig$(@:_config=)armarm920tfs2410
其中“arm”为表示处理器体系结构的种类,“arm920t”表示处理器体系结构的名称,“fs2410”为主板名称。
在board目录中建立fs2410目录,并将smdk2410目录中的内容(cp–asmdk2410/*fs2410)复制到该目录中。
n 在include/configs/目录下将smdk2410.h复制到(cpsmdk2410.hfs2410.h)。
n 修改ARM编译器的目录名及前缀(都要改成以“fs2410”开头)。
n 完成之后,可以测试配置。
$makefs2410_config;make
(2)修改程序链接地址。
在board/s3c2410中有一个config.mk文件,它是用于设置程序链接的起始地址,因为会在U-Boot中增加功能,所以留下6MB的空间,修改33F80000为33A00000。
为了以后能用U-Boot的“go”命令执行修改过的用loadb或tftp下载的U-Boot,需要在board/s3c2410的memsetup.S中标记符”0:”上加入5句:
movr3,pc
ldrr4,=0x3FFF0000
andr3,r3,r4(以上3句得到实际代码启动的内存地址)
aadr0,r0,r3(用go命令调试u-boot时,启动地址在RAM)
addr2,r2,r3(把初始化内存信息的地址,加上实际启动地址)
(3)将中断禁止的部分应该改为如下所示(/cpu/arm920t/start.S):
#ifdefined(CONFIG_S3C2410)
ldrr1,=0x7ff
ldrr0,=INTSUBMSK
strr1,[r0]
#endif
(4)因为在fs2410开发板启动时是直接从NandFlash加载代码,所以启动代码应该改成如下所示(/cpu/arm920t/start.S):
#ifdefCONFIG_S3C2410_NAND_BOOT@START
@resetNAND
movr1,#NAND_CTL_BASE
ldrr2,=0xf830@initialvalue
strr2,[r1,#oNFCONF]
ldrr2,[r1,#oNFCONF]
bicr2,r2,#0x800@enablechip
strr2,[r1,#oNFCONF]
movr2,#0xff@RESETcommand
strbr2,[r1,#oNFCMD]
movr3,#0@wait
nand1:
addr3,r3,#0x1
cmpr3,#0xa
bltnand1
nand2:
ldrr2,[r1,#oNFSTAT]@waitready
tstr2,#0x1
beqnand2
ldrr2,[r1,#oNFCONF]
orrr2,r2,#0x800@disablechip
strr2,[r1,#oNFCONF]
@getreadtocallCfunctions(fornand_read())
ldrsp,DW_STACK_START@setupstackpointer
movfp,#0@nopreviousframe,sofp=0
@copyU-BoottoRAM
ldrr0,=TEXT_BASE
movr1,#0x0
movr2,#0x20000
blnand_read_ll
tstr0,#0x0
beqok_nand_read
bad_nand_read:
loop2:bloop2@infiniteloop
ok_nand_read:
@verify
movr0,#0
ldrr1,=TEXT_BASE
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:
loop3:bloop3@infiniteloop
#endif@CONFIG_S3C2410_NAND_BOOT@END
在“_start_armboot:.wordstart_armboot”后加入:
.align2
DW_STACK_START:.wordSTACK_BASE+STACK_SIZE-4
(5)修改内存配置(board/fs2410/lowlevel_init.S)。
#defineBWSCON0x48000000
#definePLD_BASE0x2C000000
#defineSDRAM_REG0x2C000106
/*BWSCON*/
#defineDW8 (0x0)
#defineDW16(0x1)
#defineDW32(0x2)
#defineWAIT(0x1<<2)
#defineUBLB(0x1<<3)
/*BANKSIZE*/
#defineBURST_EN(0x1<<7)
#defineB1_BWSCON(DW16+WAIT)
#defineB2_BWSCON(DW32)
#defineB3_BWSCON(DW32)
#defineB4_BWSCON(DW16+WAIT+UBLB)
#defineB5_BWSCON(DW8+UBLB)
#defineB6_BWSCON(DW32)
#defineB7_BWSCON(DW32)
/*BANK0CON*/
#defineB0_Tacs0x0/*0clk*/
#defineB0_Tcos0x1/*1clk*/
#defineB0_Tacc0x7/*14clk*/
#defineB0_Tcoh0x0/*0clk*/
#defineB0_Tah0x0/*0clk*/
#defineB0_Tacp0x0/*pagemodeisnotused*/
#defineB0_PMC0x0/*pagemodedisabled*/
/*BANK1CON*/
#defineB1_Tacs0x0/*0clk*/
#defineB1_Tcos0x1/*1clk*/
#defineB1_Tacc0x7/*14clk*/
#defineB1_Tcoh0x0/*0clk*/
#defineB1_Tah0x0/*0clk*/
#defineB1_Tacp0x0/*pagemodeisnotused*/
#defineB1_PMC0x0/*pagemodedisabled*/
……
/*REFRESHparameter*/
#defineREFEN0x1/*Refreshenable*/
#defineTREFMD0x0/*CBR(CASbeforeRAS)/Autorefresh*/
#defineTrp0x0/*2clk*/
#defineTrc0x3/*7clk*/
#defineTchr0x2/*3clk*/
#defineREFCNT1113/*period=15.6us,HCLK=60Mhz,(2048+1-15.6*60)*/
......
.word((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word0x32
.word0x30
.word0x30
(6)加入NandFlash读函数(创建board/fs2410/nand_read.c文件)。
#include<config.h>
#define__REGb(x)(*(volatileunsignedchar*)(x))
#define__REGi(x)(*(volatileunsignedint*)(x))
#defineNF_BASE0x4e000000
#defineNFCONF__REGi(NF_BASE+0x0)
#defineNFCMD__REGb(NF_BASE+0x4)
#defineNFADDR__REGb(NF_BASE+0x8)
#defineNFDATA__REGb(NF_BASE+0xc)
#defineNFSTAT__REGb(NF_BASE+0x10)
#defineBUSY1
inlinevoidwait_idle(void)
{
Inti;
while(!(NFSTAT&BUSY))
{
for(i=0;i<10;i++);
}
}
/*lowlevelnandreadfunction*/
intnand_read_ll(unsignedchar*buf,unsignedlongstart_addr,intsize)
{
inti,j;
if((start_addr&NAND_BLOCK_MASK)||(size&NAND_BLOCK_MASK))
{
return-1;/*invalidalignment*/
}
/*chipEnable*/
NFCONF&=~0x800;
for(i=0;i<10;i++);
for(i=start_addr;i<(start_addr+size);)
{
/*READ0*/
NFCMD=0;
/*WriteAddress*/
NFADDR=i&0xff;
NFADDR=(i>>9)&0xff;
NFADDR=(i>>17)&0xff;
NFADDR=(i>>25)&0xff;
wait_idle();
for(j=0;j<NAND_SECTOR_SIZE;j++,i++)
{
*buf=(NFDATA&0xff);
buf++;
}
}
/*chipDisable*/
NFCONF|=0x800;/*chipdisable*/
return0;
}
修改board/fs2410/makefile文件,以增加nand_read()函数。
OBJS:=fs2410.oflash.onand_read.o
(7)加入NandFlash的初始化函数(board/fs2410/fs2410.c)。
#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_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->NFCONF&=~(1<<11);
break;
caseNFCE_HIGH:
nand->NFCONF|=(1<<11);
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->NFCONF|=(1<<12);
}
staticinlineu32NF_Read_ECC(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
return(nand->NFECC);
}
#endif
/*
*NANDflashinitialization.
*/
#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)
{
#defineTACLS0
#defineTWRPH04
#defineTWRPH12
NF_Conf((1<<15)|(0<<14)|(0<<13)|(1<<12)
|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0));
/*1111,1xxx,rxxx,rxxx*/
/*En512B4stepECCRnFCE=HtACLStWRPH0tWRPH1*/
NF_Reset();
}
voidnand_init(void)
{
S3C2410_NAND*constnand=S3C2410_GetBase_NAND();
NF_Init();
#ifdefDEBUG
printf("NANDflashprobingat0x%.8lXn",(ulong)nand);
#endif
printf("%4luMBn",nand_probe((ulong)nand)>>20);
}
#endif
(8)修改GPIO配置(board/fs2410/fs2410.c)。
/*setuptheI/Oports*/
gpio->GPACON=0x007FFFFF;
gpio->GPBCON=0x002AAAAA;
gpio->GPBUP=0x000002BF;
gpio->GPCCON=0xAAAAAAAA;
gpio->GPCUP=0x0000FFFF;
gpio->GPDCON=0xAAAAAAAA;
gpio->GPDUP=0x0000FFFF;
gpio->GPECON=0xAAAAAAAA;
gpio->GPEUP=0x000037F7;
gpio->GPFCON=0x00000000;
gpio->GPFUP=0x00000000;
gpio->GPGCON=0xFFEAFF5A;
gpio->GPGUP=0x0000F0DC;
gpio->GPHCON=0x0018AAAA;
gpio->GPHDAT=0x000001FF;
gpio->GPHUP=0x00000656
(9)提供nandflash相关宏定义(include/configs/fs2410.h),具体参考源码。
(10)加入NandFlash设备(include/linux/mtd/nand_ids.h)
staticstructnand_flash_devnand_flash_ids[]=
{
......
{"SamsungKM29N16000",NAND_MFR_SAMSUNG,0x64,21,1,2,0x1000,0},
{"SamsungK9F1208U0M",NAND_MFR_SAMSUNG,0x76,26,0,3,0x4000,0},
{"Samsungunknown4Mb",NAND_MFR_SAMSUNG,0x6b,22,0,2,0x2000,0},
......
{NULL,}
};
(11)设置NandFlash环境(common/env_nand.c)
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];
......
#else/*!CFG_ENV_OFFSET_REDUND*/
intsaveenv(void)
{
ulongtotal;
intret=0;
puts("ErasingNand...");
if(nand_legacy_erase(nand_dev_desc+0,
CFG_ENV_OFFSET,CFG_ENV_SIZE,0))
{
return1;
}
puts("WritingtoNand...");
total=CFG_ENV_SIZE;
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("donen");
returnret;
......
#else/*!CFG_ENV_OFFSET_REDUND*/
voidenv_relocate_spec(void)
{
#if!defined(ENV_IS_EMBEDDED)
ulongtotal;
intret;
total=CFG_ENV_SIZE;
ret=nand_legacy_rw(nand_dev_desc+0,0x01|0x02,CFG_ENV_OFFSET,
CFG_ENV_SIZE,&total,(u_char*)env_ptr);