?
5.2??U-Boot移植
5.2.1??Bootloader介紹
1.概念
簡(jiǎn)單地說(shuō),Bootloader就是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一段程序,它類(lèi)似于PC機(jī)中的BIOS程序。通過(guò)這段程序,可以完成硬件設(shè)備的初始化,并建立內(nèi)存空間的映射關(guān)系,從而將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適的狀態(tài),為最終加載系統(tǒng)內(nèi)核做好準(zhǔn)備。
通常,Bootloader比較依賴于硬件平臺(tái),特別是在嵌入式系統(tǒng)中,更為如此。因此,在嵌入式世界里建立一個(gè)通用的Bootloader是一件比較困難的事情。盡管如此,仍然可以對(duì)Bootloader歸納出一些通用的概念來(lái)指導(dǎo)面向用戶定制的Bootloader設(shè)計(jì)與實(shí)現(xiàn)。
(1)Bootloader所支持的CPU和嵌入式開(kāi)發(fā)板。
每種不同的CPU體系結(jié)構(gòu)都有不同的Bootloader。有些Bootloader也支持多種體系結(jié)構(gòu)的CPU,如后面要介紹的U-Boot支持ARM、MIPS、PowerPC等眾多體系結(jié)構(gòu)。除了依賴于CPU的體系結(jié)構(gòu)外,Bootloader實(shí)際上也依賴于具體的嵌入式板級(jí)設(shè)備的配置。
(2)Bootloader的存儲(chǔ)位置。
系統(tǒng)加電或復(fù)位后,所有的CPU通常都從某個(gè)由CPU制造商預(yù)先安排的地址上取指令。而基于CPU構(gòu)建的嵌入式系統(tǒng)通常都有某種類(lèi)型的固態(tài)存儲(chǔ)設(shè)備(比如ROM、EEPROM或Flash等)被映射到這個(gè)預(yù)先安排的地址上。因此在系統(tǒng)加電后,CPU將首先執(zhí)行Bootloader程序。
(3)Bootloader的啟動(dòng)過(guò)程分為單階段和多階段兩種。通常多階段的Bootloader能提供更為復(fù)雜的功能,以及更好的可移植性。
(4)Bootloader的操作模式。大多數(shù)Bootloader都包含兩種不同的操作模式:“啟動(dòng)加載”模式和“下載”模式,這種區(qū)別僅對(duì)于開(kāi)發(fā)人員才有意義。
n 啟動(dòng)加載模式:這種模式也稱為“自主”模式。也就是Bootloader從目標(biāo)機(jī)上的某個(gè)固態(tài)存儲(chǔ)設(shè)備上將操作系統(tǒng)加載到RAM中運(yùn)行,整個(gè)過(guò)程并沒(méi)有用戶的介入。這種模式是嵌入式產(chǎn)品發(fā)布時(shí)的通用模式。
n 下載模式:在這種模式下,目標(biāo)機(jī)上的Bootloader將通過(guò)串口連接或網(wǎng)絡(luò)連接等通信手段從主機(jī)(Host)下載文件,比如:下載內(nèi)核映像和根文件系統(tǒng)映像等。從主機(jī)下載的文件通常首先被Bootloader保存到目標(biāo)機(jī)的RAM中,然后再被Bootloader寫(xiě)入到目標(biāo)機(jī)上的Flash類(lèi)固態(tài)存儲(chǔ)設(shè)備中。Bootloader的這種模式在系統(tǒng)更新時(shí)使用。工作于這種模式下的Bootloader通常都會(huì)向它的終端用戶提供一個(gè)簡(jiǎn)單的命令行接口。
(5)Bootloader與主機(jī)之間進(jìn)行文件傳輸所用的通信設(shè)備及協(xié)議,最常見(jiàn)的情況就是,目標(biāo)機(jī)上的Bootloader通過(guò)串口與主機(jī)之間進(jìn)行文件傳輸,傳輸協(xié)議通常是xmodem/?ymodem/zmodem等。但是,串口傳輸?shù)乃俣仁怯邢薜模虼送ㄟ^(guò)以太網(wǎng)連接并借助TFTP等協(xié)議來(lái)下載文件是個(gè)更好的選擇。
2.Bootloader啟動(dòng)流程
Bootloader的啟動(dòng)流程一般分為兩個(gè)階段:stage1和stage2,下面分別對(duì)這兩個(gè)階段進(jìn)行講解。
(1)Bootloader的stage1。
在stage1中Bootloader主要完成以下工作。
n 基本的硬件初始化,包括屏蔽所有的中斷、設(shè)置CPU的速度和時(shí)鐘頻率、RAM初始化、初始化外圍設(shè)備、關(guān)閉CPU內(nèi)部指令和數(shù)據(jù)cache等。
n 為加載stage2準(zhǔn)備RAM空間,通常為了獲得更快的執(zhí)行速度,通常把stage2加載到RAM空間中來(lái)執(zhí)行,因此必須為加載Bootloader的stage2準(zhǔn)備好一段可用的RAM空間。
n 復(fù)制stage2到RAM中,在這里要確定兩點(diǎn):①stage2的可執(zhí)行映像在固態(tài)存儲(chǔ)設(shè)備的存放起始地址和終止地址;②RAM空間的起始地址。
n 設(shè)置堆棧指針sp,這是為執(zhí)行stage2的C語(yǔ)言代碼做好準(zhǔn)備。
(2)Bootloader的stage2。
在stage2中Bootloader主要完成以下工作。
n 用匯編語(yǔ)言跳轉(zhuǎn)到main入口函數(shù)。
由于stage2的代碼通常用C語(yǔ)言來(lái)實(shí)現(xiàn),目的是實(shí)現(xiàn)更復(fù)雜的功能和取得更好的代碼可讀性和可移植性。但是與普通C語(yǔ)言應(yīng)用程序不同的是,在編譯和鏈接Bootloader這樣的程序時(shí),不能使用glibc庫(kù)中的任何支持函數(shù)。
n 初始化本階段要使用到的硬件設(shè)備,包括初始化串口、初始化計(jì)時(shí)器等。在初始化這些設(shè)備之前可以輸出一些打印信息。
n 檢測(cè)系統(tǒng)的內(nèi)存映射,所謂內(nèi)存映射就是指在整個(gè)4GB物理地址空間中指出哪些地址范圍被分配用來(lái)尋址系統(tǒng)的內(nèi)存。
n 加載內(nèi)核映像和根文件系統(tǒng)映像,這里包括規(guī)劃內(nèi)存占用的布局和從Flash上復(fù)制數(shù)據(jù)。
n 設(shè)置內(nèi)核的啟動(dòng)參數(shù)。
5.2.2??U-Boot概述
1.U-Boot簡(jiǎn)介
U-Boot(UniversalBootloader)是遵循GPL條款的開(kāi)放源碼項(xiàng)目。它是從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來(lái)。其源碼目錄、編譯形式與Linux內(nèi)核很相似,事實(shí)上,不少U-Boot源碼就是相應(yīng)的Linux內(nèi)核源程序的簡(jiǎn)化,尤其是一些設(shè)備的驅(qū)動(dòng)程序,這從U-Boot源碼的注釋中能體現(xiàn)這一點(diǎn)。但是U-Boot不僅僅支持嵌入式Linux系統(tǒng)的引導(dǎo),而且還支持NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS等嵌入式操作系統(tǒng)。其目前要支持的目標(biāo)操作系統(tǒng)是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等諸多常用系列的處理器。這兩個(gè)特點(diǎn)正是U-Boot項(xiàng)目的開(kāi)發(fā)目標(biāo),即支持盡可能多的嵌入式處理器和嵌入式操作系統(tǒng)。就目前為止,U-Boot對(duì)PowerPC系列處理器支持最為豐富,對(duì)Linux的支持最完善。
2.U-Boot特點(diǎn)
U-Boot的特點(diǎn)如下。
n 開(kāi)放源碼;
n 支持多種嵌入式操作系統(tǒng)內(nèi)核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;
n 支持多個(gè)處理器系列,如PowerPC、ARM、x86、MIPS、XScale;
n 較高的可靠性和穩(wěn)定性;
n 高度靈活的功能設(shè)置,適合U-Boot調(diào)試、操作系統(tǒng)不同引導(dǎo)要求和產(chǎn)品發(fā)布等;
n 豐富的設(shè)備驅(qū)動(dòng)源碼,如串口、以太網(wǎng)、SDRAM、Flash、LCD、NVRAM、EEPROM、RTC、鍵盤(pán)等;
n 較為豐富的開(kāi)發(fā)調(diào)試文檔與強(qiáng)大的網(wǎng)絡(luò)技術(shù)支持。
3.U-Boot主要功能
U-Boot可支持的主要功能列表。
n 系統(tǒng)引導(dǎo):支持NFS掛載、RAMDISK(壓縮或非壓縮)形式的根文件系統(tǒng)。支持NFS掛載,并從Flash中引導(dǎo)壓縮或非壓縮系統(tǒng)內(nèi)核。
n 基本輔助功能:強(qiáng)大的操作系統(tǒng)接口功能;可靈活設(shè)置、傳遞多個(gè)關(guān)鍵參數(shù)給操作系統(tǒng),適合系統(tǒng)在不同開(kāi)發(fā)階段的調(diào)試要求與產(chǎn)品發(fā)布,尤其對(duì)Linux支持最為強(qiáng)勁;支持目標(biāo)板環(huán)境參數(shù)多種存儲(chǔ)方式,如Flash、NVRAM、EEPROM;CRC32校驗(yàn),可校驗(yàn)Flash中內(nèi)核、RAMDISK映像文件是否完好。
n 設(shè)備驅(qū)動(dòng):串口、SDRAM、Flash、以太網(wǎng)、LCD、NVRAM、EEPROM、鍵盤(pán)、USB、PCMCIA、PCI、RTC等驅(qū)動(dòng)支持。
n 上電自檢功能:SDRAM、Flash大小自動(dòng)檢測(cè);SDRAM故障檢測(cè);CPU型號(hào)。
n 特殊功能:XIP內(nèi)核引導(dǎo)。
5.2.3??U-Boot源碼導(dǎo)讀
1.U-Boot源碼結(jié)構(gòu)
U-Boot源碼結(jié)構(gòu)如圖5.27所示。
圖5.27??U-Boot源碼結(jié)構(gòu)
?
n board:和一些已有開(kāi)發(fā)板有關(guān)的代碼,比如makefile和U-Boot.lds等都和具體開(kāi)發(fā)板的硬件和地址分配有關(guān)。
n common:與體系結(jié)構(gòu)無(wú)關(guān)的代碼,用來(lái)實(shí)現(xiàn)各種命令的C程序。
n cpu:包含CPU相關(guān)代碼,其中的子目錄都是以U-BOOT所支持的CPU為名,比如有子目錄arm926ejs、mips、mpc8260和nios等,每個(gè)特定的子目錄中都包括cpu.c和interrupt.c,start.S等。其中cpu.c初始化CPU、設(shè)置指令Cache和數(shù)據(jù)Cache等;interrupt.c設(shè)置系統(tǒng)的各種中斷和異常,比如快速中斷、開(kāi)關(guān)中斷、時(shí)鐘中斷、軟件中斷、預(yù)取中止和未定義指令等;匯編代碼文件start.S是U-BOOT啟動(dòng)時(shí)執(zhí)行的第一個(gè)文件,它主要是設(shè)置系統(tǒng)堆棧和工作方式,為進(jìn)入C程序奠定基礎(chǔ)。
n disk:disk驅(qū)動(dòng)的分區(qū)相關(guān)代碼。
n doc:文檔。
n drivers:通用設(shè)備驅(qū)動(dòng)程序,比如各種網(wǎng)卡、支持CFI的Flash、串口和USB總線等。
n fs:支持文件系統(tǒng)的文件,U-BOOT現(xiàn)在支持cramfs、fat、fdos、jffs2和registerfs等。
n include:頭文件,還有對(duì)各種硬件平臺(tái)支持的匯編文件,系統(tǒng)的配置文件和對(duì)文件系統(tǒng)支持的文件。
n net:與網(wǎng)絡(luò)有關(guān)的代碼,BOOTP協(xié)議、TFTP協(xié)議、RARP協(xié)議和NFS文件系統(tǒng)的實(shí)現(xiàn)。
n lib_arm:與ARM體系結(jié)構(gòu)相關(guān)的代碼。
n tools:創(chuàng)建S-Record格式文件和U-BOOT?images的工具。
?
2.U-Boot重要代碼
(1)cpu/arm920t/start.S
這是U-Boot的起始位置。在這個(gè)文件中設(shè)置了處理器的狀態(tài)、初始化中斷向量和內(nèi)存時(shí)序等,從Flash中跳轉(zhuǎn)到定位好的內(nèi)存位置執(zhí)行。
.globl_start?(起始位置:中斷向量設(shè)置)
_start:?????b?????????reset
??????ldr????pc,?_undefined_instruction
??????ldr????pc,?_software_interrupt
??????ldr????pc,?_prefetch_abort
??????ldr????pc,?_data_abort
??????ldr????pc,?_not_used
??????ldr????pc,?_irq
??????ldr????pc,?_fiq
_undefined_instruction:???.word?undefined_instruction
_software_interrupt:???.word?software_interrupt
_prefetch_abort:???.word?prefetch_abort
_data_abort:???????.word?data_abort
_not_used:??????.word?not_used
_irq:????????????.word?irq
_fiq:????????????.word?fiq
????_TEXT_BASE:?(代碼段起始位置)
.word???TEXT_BASE
.globl?_armboot_start
_armboot_start:
????.word?_start
/*
?*?These?are?defined?in?the?board-specific?linker?script.
?*/
.globl?_bss_start?(BSS段起始位置)
_bss_start:
??????.word?__bss_start
.globl?_bss_end
_bss_end:
?????.word?_end
reset:?(執(zhí)行入口)
???????/*
???????*?set?the?cpu?to?SVC32?mode;使處理器進(jìn)入特權(quán)模式
???????*/
???????mrs????r0,cpsr
???????bic????r0,r0,#0x1f
???????orr????r0,r0,#0xd3
???????msr????cpsr,r0
relocate:????(代碼的重置)???????????/*?relocate?U-Boot?to?RAM?????*/
??????adr????r0,?_start??????/*?r0?<-?current?position?of?code???*/
??????ldr????r1,?_TEXT_BASE??????/*?test?if?we?run?from?flash?or?RAM?*/
??????cmp?????r0,?r1??????????????????/*?don't?reloc?during?debug?????????*/
??????beq?????stack_setup
??????ldr????r2,?_armboot_start
??????ldr????r3,?_bss_start
??????sub????r2,?r3,?r2?????/*?r2?<-?size?of?armboot????????????*/
??????add????r2,?r0,?r2?????/*?r2?<-?source?end?address?????????*/
copy_loop:?(拷貝過(guò)程)
??????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
??????/*?Set?up?the?stack;設(shè)置堆棧??*/
stack_setup:
??????ldr???r0,?_TEXT_BASE??????/*?upper?128?KiB:?relocated?uboot???*/
??????sub???r0,?r0,?#CFG_MALLOC_LEN????/*?malloc?area??????????????????????*/
??????sub???r0,?r0,?#CFG_GBL_DATA_SIZE?/*?bdinfo????????????????????????*/
clear_bss:?(清空BSS段)
??????ldr????r0,?_bss_start?????/*?find?start?of?bss?segment????????*/
??????ldr????r1,?_bss_end????????/*?stop?here????????????????????????*/
??????mov?????r2,?#0x00000000?????/*?clear????????????????????????????*/
clbss_l:str????r2,?[r0]????????/*?clear?loop...????????????????????*/
??????add???r0,?r0,?#4
??????cmp???r0,?r1
??????bne???clbss_l
??????ldr???pc,?_start_armboot
_start_armboot:?????.word?start_armboot
(2)interrupts.c
這個(gè)文件是處理中斷的,如打開(kāi)和關(guān)閉中斷等。
#ifdef?CONFIG_USE_IRQ
/*?enable?IRQ?interrupts;中斷使能函數(shù)?*/
void?enable_interrupts?(void)
{
?????unsigned?long?temp;
?????__asm__?__volatile__("mrs?%0,?cpsrn"
?????????????????????????"bic?%0,?%0,?#0x80n"
?????????????????????????"msr?cpsr_c,?%0"
?????????????????????????:?"=r"?(temp)
?????????????????????????:
?????????????????????????:?"memory");
}
/*
?*?disable?IRQ/FIQ?interrupts;中斷屏蔽函數(shù)
?*?returns?true?if?interrupts?had?been?enabled?before?we?disabled?them
?*/
int?disable_interrupts?(void)
{
?????unsigned?long?old,temp;
?????__asm__?__volatile__("mrs?%0,?cpsrn"
?????????????????????????"orr?%1,?%0,?#0xc0n"
?????????????????????????"msr?cpsr_c,?%1"
?????????????????????????:?"=r"?(old),?"=r"?(temp)
?????????????????????????:
?????????????????????????:?"memory");
?????return?(old?&?0x80)?==?0;
}
#endif
void?show_regs?(struct?pt_regs?*regs)
{
?????unsigned?long?flags;
?????const?char?*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啟動(dòng)模式下,在原則上要禁止中斷處理,所以如果發(fā)生中斷,當(dāng)作出錯(cuò)處理?*/
void?do_fiq?(struct?pt_regs?*pt_regs)
{
?????printf?("fast?interrupt?requestn");
?????show_regs?(pt_regs);
?????bad_mode?();
}
void?do_irq?(struct?pt_regs?*pt_regs)
{
?????printf?("interrupt?requestn");
?????show_regs?(pt_regs);
?????bad_mode?();
}
(3)cpu.c
這個(gè)文件是對(duì)處理器進(jìn)行操作,如下所示:
int?cpu_init?(void)
{
?????/*
???????*?setup?up?stacks?if?necessary;設(shè)置需要的堆棧
?????*/
#ifdef?CONFIG_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
?????return?0;
}
int?cleanup_before_linux?(void)?/*?準(zhǔn)備加載linux?*/
{
?????/*
??????*?this?function?is?called?just?before?we?call?linux
??????*?it?prepares?the?processor?for?linux
??????*
??????*?we?turn?off?caches?etc?...
??????*/
?????unsigned?long?i;
?????disable_interrupts?();
?????/*?turn?off?I/D-cache:關(guān)閉cache?*/
?????asm?("mrc?p15,?0,?%0,?c1,?c0,?0":"=r"?(i));
?????i?&=?~(C1_DC?|?C1_IC);
?????asm?("mcr?p15,?0,?%0,?c1,?c0,?0":?:"r"?(i));
?????/*?flush?I/D-cache?*/
?????i?=?0;
?????asm?("mcr?p15,?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
這個(gè)文件是用于配置開(kāi)發(fā)板參數(shù)的,如下所示:
/*?memsetup.c?*/
?????/*?memory?control?configuration?*/
?????/*?make?r0?relative?the?current?location?so?that?it?*/
?????/*?reads?SMRDATA?out?of?FLASH?rather?than?memory?!?*/
?????ldr?????r0,?=SMRDATA
????ldr?r1,?_TEXT_BASE
????sub?r0,?r0,?r1
????ldr?r1,?=BWSCON /*?Bus?Width?Status?Controller?*/
?????add?????r2,?r0,?#52
0:
?????ldr?????r3,?[r0],?#4
?????str?????r3,?[r1],?#4
?????cmp?????r2,?r0
?????bne?????0b
??
?????/*?everything?is?fine?now?*/
????mov?pc,?lr
?????.ltorg
5.2.4??U-Boot移植主要步驟
(1)建立自己的開(kāi)發(fā)板類(lèi)型。
閱讀makefile文件,在makefile文件中添加兩行,如下所示:
fs2410_config:?unconfig?
????@./mkconfig?$(@:_config=)?arm?arm920t?fs2410
其中“arm”為表示處理器體系結(jié)構(gòu)的種類(lèi),“arm920t”表示處理器體系結(jié)構(gòu)的名稱,“fs2410”為主板名稱。
在board目錄中建立fs2410目錄,并將smdk2410目錄中的內(nèi)容(cp?–a?smdk2410/*??fs2410)復(fù)制到該目錄中。
n 在include/configs/目錄下將smdk2410.h復(fù)制到(cp?smdk2410.h?fs2410.h)。
n 修改ARM編譯器的目錄名及前綴(都要改成以“fs2410”開(kāi)頭)。
n 完成之后,可以測(cè)試配置。
$?make?fs2410_config;make
(2)修改程序鏈接地址。
在board/s3c2410中有一個(gè)config.mk文件,它是用于設(shè)置程序鏈接的起始地址,因?yàn)闀?huì)在U-Boot中增加功能,所以留下6MB的空間,修改33F80000為33A00000。
為了以后能用U-Boot的“go”命令執(zhí)行修改過(guò)的用loadb或tftp下載的U-Boot,需要在board/?s3c2410的memsetup.S中標(biāo)記符”0:”上加入5句:
mov?r3,?pc
ldr?r4,?=0x3FFF0000
and?r3,?r3,?r4?(以上3句得到實(shí)際代碼啟動(dòng)的內(nèi)存地址)
aad?r0,?r0,?r3?(用go命令調(diào)試u-boot時(shí),啟動(dòng)地址在RAM)
add?r2,?r2,?r3?(把初始化內(nèi)存信息的地址,加上實(shí)際啟動(dòng)地址)
(3)將中斷禁止的部分應(yīng)該改為如下所示(/cpu/arm920t/start.S):
#?if?defined(CONFIG_S3C2410)
?????ldr????r1,?=0x7ff??
?????ldr????r0,?=INTSUBMSK
?????str????r1,?[r0]
#?endif
(4)因?yàn)樵趂s2410開(kāi)發(fā)板啟動(dòng)時(shí)是直接從Nand?Flash加載代碼,所以啟動(dòng)代碼應(yīng)該改成如下所示(/cpu/arm920t/start.S):
#ifdef?CONFIG_S3C2410_NAND_BOOT???@START
@?reset?NAND
????mov?r1,?#NAND_CTL_BASE
????ldr???r2,?=0xf830???????????@?initial?value
????str???r2,?[r1,?#oNFCONF]
????ldr???r2,?[r1,?#oNFCONF]
????bic??r2,?r2,?#0x800??????????????@?enable?chip
????str???r2,?[r1,?#oNFCONF]
????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,?#0x1
????beq??nand2
????ldr???r2,?[r1,?#oNFCONF]
????orr??r2,?r2,?#0x800??????????????@?disable?chip
????str???r2,?[r1,?#oNFCONF]
????@?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
@?copy?U-Boot?to?RAM
????ldr???r0,?=TEXT_BASE
????mov?????r1,?#0x0
????mov?r2,?#0x20000
????bl????nand_read_ll
????tst????r0,?#0x0
????beq??ok_nand_read
bad_nand_read:
????loop2:????b?????loop2??????????@?infinite?loop
ok_nand_read:
@?verify
????mov?r0,?#0
????ldr???r1,?=TEXT_BASE
????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:
loop3:?????b?????loop3?????????@?infinite?loop
#endif?@?CONFIG_S3C2410_NAND_BOOT??@END
在?“?_start_armboot:????.word?start_armboot??”?后加入:
.align?????2
DW_STACK_START:??.word??STACK_BASE+STACK_SIZE-4
(5)修改內(nèi)存配置(board/fs2410/lowlevel_init.S)。
#define?BWSCON?????0x48000000
#define?PLD_BASE???0x2C000000
#define?SDRAM_REG??0x2C000106
/*?BWSCON?*/
#define?DW8 ?????????????(0x0)
#define?DW16????????????(0x1)
#define?DW32????????????(0x2)
#define?WAIT????????????(0x1<<2)
#define?UBLB????????????(0x1<<3)
/*?BANKSIZE?*/
#define?BURST_EN????????(0x1<<7)
#define?B1_BWSCON??????(DW16?+?WAIT)
#define?B2_BWSCON??????(DW32)
#define?B3_BWSCON??????(DW32)
#define?B4_BWSCON??????(DW16?+?WAIT?+?UBLB)
#define?B5_BWSCON??????(DW8?+?UBLB)
#define?B6_BWSCON??????(DW32)
#define?B7_BWSCON??????(DW32)
/*?BANK0CON?*/
#define?B0_Tacs?????????????0x0?/*??0clk?*/
#define?B0_Tcos?????????????0x1?/*??1clk?*/
#define?B0_Tacc?????????????0x7?/*??14clk?*/
#define?B0_Tcoh?????????????0x0?/*??0clk?*/
#define?B0_Tah???????0x0???/*??0clk?*/
#define?B0_Tacp????????????0x0?????/*?page?mode?is?not?used?*/
#define?B0_PMC??????????0x0?/*?page?mode?disabled?*/
/*?BANK1CON?*/
#define?B1_Tacs?????????????0x0?/*??0clk?*/
#define?B1_Tcos?????????????0x1?/*??1clk?*/
#define?B1_Tacc?????????????0x7?/*??14clk?*/
#define?B1_Tcoh?????????????0x0?/*??0clk?*/
#define?B1_Tah??????????0x0?/*??0clk?*/
#define?B1_Tacp????????????0x0?????/*?page?mode?is?not?used?*/
#define?B1_PMC??????????0x0?/*?page?mode?disabled?*/
……
/*?REFRESH?parameter?*/
#define?REFEN???????????0x1?/*?Refresh?enable?*/
#define?TREFMD??????????0x0?/*?CBR(CAS?before?RAS)/Auto?refresh?*/
#define?Trp?????????0x0?/*?2clk?*/
#define?Trc?????????0x3?/*?7clk?*/
#define?Tchr????????????0x2?/*?3clk?*/
#define?REFCNT???????????1113?/*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)
????.word?0x32?
????.word?0x30
????.word?0x30
(6)加入Nand?Flash讀函數(shù)(創(chuàng)建board/fs2410/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?NFCMD??__REGb(NF_BASE?+?0x4)
#define?NFADDR??__REGb(NF_BASE?+?0x8)
#define?NFDATA??__REGb(NF_BASE?+?0xc)
#define?NFSTAT??__REGb(NF_BASE?+?0x10)
#define?BUSY?1
inline?void?wait_idle(void)?
{
?????Int?i;
?????while(!(NFSTAT?&?BUSY))
?????{
?????????for?(i?=?0;?i?<?10;?i++);
?????}
}
/*?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;?/*?invalid?alignment?*/
?????}
?????/*?chip?Enable?*/
?????NFCONF?&=?~0x800;
?????for?(i?=?0;?i?<?10;?i++);
?????for?(i?=?start_addr;?i?<?(start_addr?+?size);)?
?????{
?????????/*?READ0?*/
?????????NFCMD?=?0;
?????????/*?Write?Address?*/
?????????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++;
?????????}
?????}
?????/*?chip?Disable?*/
?????NFCONF?|=?0x800;?/*?chip?disable?*/
?????return?0;
}
修改board/fs2410/makefile文件,以增加nand_read()函數(shù)。
OBJS?:=?fs2410.o??flash.o??nand_read.o
?
(7)加入Nand?Flash的初始化函數(shù)(board/fs2410/fs2410.c)。
#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?void?NF_Cmd(u8?cmd)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????nand->NFCMD?=?cmd;
}
static?inline?void?NF_CmdW(u8?cmd)
{
?????NF_Cmd(cmd);
?????udelay(1);
}
static?inline?void?NF_Addr(u8?addr)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????nand->NFADDR?=?addr;
}
static?inline?void?NF_SetCE(NFCE_STATE?s)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????switch?(s)?
?????{
??????????case?NFCE_LOW:
?????????????nand->NFCONF?&=?~(1<<11);
?????????????break;
??????????case?NFCE_HIGH:
?????????????nand->NFCONF?|=?(1<<11);
?????????????break;
?????}
}
static?inline?void?NF_WaitRB(void)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????while?(!(nand->NFSTAT?&?(1<<0)));
}
static?inline?void?NF_Write(u8?data)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????nand->NFDATA?=?data;
}
static?inline?u8?NF_Read(void)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????return(nand->NFDATA);
}
static?inline?void?NF_Init_ECC(void)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????nand->NFCONF?|=?(1<<12);
}
static?inline?u32?NF_Read_ECC(void)
{
?????S3C2410_NAND?*?const?nand?=?S3C2410_GetBase_NAND();
?????return(nand->NFECC);
}
#endif
/*
*?NAND?flash?initialization.
*/
#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)
{
?????#define?TACLS?0
?????#define?TWRPH0?4
?????#define?TWRPH1?2
?????NF_Conf((1<<15)|(0<<14)|(0<<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%.8lXn",?(ulong)nand);
?????#endif
?????printf?("%4lu?MBn",?nand_probe((ulong)nand)?>>?20);
}
#endif
(8)修改GPIO配置(board/fs2410/fs2410.c)。
/*?set?up?the?I/O?ports?*/
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)提供nand?flash相關(guān)宏定義(include/configs/fs2410.h),具體參考源碼。
(10)加入Nand?Flash設(shè)備(include/linux/mtd/nand_ids.h)
static?struct?nand_flash_dev?nand_flash_ids[]?=?
{
?????......
????{"Samsung?KM29N16000",NAND_MFR_SAMSUNG,?0x64,?21,?1,?2,?0x1000,?0},?
????{"Samsung?K9F1208U0M",??NAND_MFR_SAMSUNG,?0x76,?26,?0,?3,?0x4000,?0},
????{"Samsung?unknown?4Mb",?NAND_MFR_SAMSUNG,?0x6b,?22,?0,?2,?0x2000,?0},
?????......?
?????{NULL,}
};
(11)設(shè)置Nand?Flash環(huán)境(common/env_nand.c)
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_chip?nand_dev_desc[CFG_MAX_NAND_DEVICE];
extern?int?nand_legacy_erase(struct?nand_chip?*nand,?
???????????????????????????????size_t?ofs,?size_t?len,?int?clean);
/*?info?for?NAND?chips,?defined?in?drivers/nand/nand.c?*/
extern?nand_info_t?nand_info[CFG_MAX_NAND_DEVICE];
......
#else?/*?!?CFG_ENV_OFFSET_REDUND?*/
int?saveenv(void)
{
????ulong?total;
????int?ret?=?0;
????puts?("Erasing?Nand...");
?????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_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?("donen");
?????return?ret;
?????......
#else?/*?!?CFG_ENV_OFFSET_REDUND?*/
void?env_relocate_spec?(void)
{
#if?!defined(ENV_IS_EMBEDDED)
?????ulong?total;
?????int?ret;
?????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);