当前位置:首页 > 嵌入式 > 嵌入式教程
[导读]简单地说,Bootloader就是在操作系统内核运行之前运行的一段程序,它类似于PC机中的BIOS程序。通过这段程序,可以完成硬件设备的初始化,并建立内存空间的映射关系,从而将系统的软硬件环境带到一个合适的状态,为最终加载系统内核做好准备。

5.2U-Boot移植5.2.1Bootloader介绍1.概念

简单地说,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);

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

嵌入式 linux将是下述内容的主要介绍对象,通过这篇文章,小编希望大家可以对它的相关情况以及信息有所认识和了解,详细内容如下。

关键字: 嵌入式 嵌入式linux Linux

  随着半导体技术的不断进步(按照摩尔定律),MCU内部集成的逻辑功能外设越来越多,存储器也越来越大。消费者对于汽车节能(经济和法规对排放的要求)型、舒适性、互联性、安全性(功能安全和信息安全)

关键字: bootloader 汽车电子

一般来讲,我们平时了解到的linux的是指linux语言,其实不是。

关键字: Linux 嵌入式linux

好的单片机编程软件受到众多开发人员青睐,而对单片机编程软件了解较多的朋友都知道,目前市场上主要流通的单片机编程软件为Keil和IAR。本文中,主要为大家讲解IAR单片机编程软件的基础教程。如果你对IAR存在一定兴趣,不妨...

关键字: iar 单片机编程软件 基础教程

所谓动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序...

关键字: 内存 动态内存 基础教程 存储空间

PC在刚诞生的时候,其实是没有GPU的,所有的图形计算都由CPU来计算。后来人们意识到CPU做图形计算太慢了,于是他们设计了专门的图形加速卡用来帮忙处理图形计算,再后来,NVIDIA提出了GPU的概念,将GPU提升到了一...

关键字: CPU GPU pc 基础教程

我们都知道固态硬盘采用闪存颗粒NAND Flash作为存储介质,所以它是固态硬盘中最重要的构成部分,其好坏也就决定着固态硬盘质量的好坏,而我们目前常见的NAND闪存主要有四种类型:Single Level Cell(SL...

关键字: qlc 固态硬盘 基础教程 闪存芯片

随着电子技术、无线通信技术的蓬勃发展,出现了各种非接触式无线数据传输标准。技术的不断推进升级,使得人们对这些标准提出了更加严格的要求,一种低成本实现非接触式无线数据传输的技术也由此应运而生。

关键字: NFC 基础教程 无线传输 无线技术

HDMI(高清晰度多媒体接口)是首个也是业界唯一支持的不压缩全数字的音频/ 视频接口。HDMI 通过在一条线缆中传输高清晰、全数字的音频和视频内容,极大简化了布线,为消费者提供最高质量的家庭影院体验。HDMI 在单线缆中...

关键字: dtv hdmi 基础教程 音频接口

在有对Flash写入或擦除操作的代码中,如果用户误调用了写入或擦除函数或者由于程序跑飞而恰好执行了Flash擦除或写入函数,这自然会导致数据丢失或改变。

关键字: Flash rom 基础教程 存储器
关闭
关闭