加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 5.2  U-Boot移植
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

嵌入式Linux開發(fā)環(huán)境的搭建之:U-Boot移植

2013/09/13
1
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

?

5.2??U-Boot移植

5.2.1??Bootloader介紹

1.概念

簡單地說,Bootloader就是在操作系統(tǒng)內(nèi)核運(yùn)行之前運(yùn)行的一段程序,它類似于PC機(jī)中的BIOS程序。通過這段程序,可以完成硬件設(shè)備的初始化,并建立內(nèi)存空間的映射關(guān)系,從而將系統(tǒng)的軟硬件環(huán)境帶到一個合適的狀態(tài),為最終加載系統(tǒng)內(nèi)核做好準(zhǔn)備。

通常,Bootloader比較依賴于硬件平臺,特別是在嵌入式系統(tǒng)中,更為如此。因此,在嵌入式世界里建立一個通用的Bootloader是一件比較困難的事情。盡管如此,仍然可以對Bootloader歸納出一些通用的概念來指導(dǎo)面向用戶定制的Bootloader設(shè)計與實現(xiàn)。

(1)Bootloader所支持的CPU嵌入式開發(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è)備的配置。

(2)Bootloader的存儲位置。

系統(tǒng)加電或復(fù)位后,所有的CPU通常都從某個由CPU制造商預(yù)先安排的地址上取指令。而基于CPU構(gòu)建的嵌入式系統(tǒng)通常都有某種類型的固態(tài)存儲設(shè)備(比如ROMEEPROM或Flash等)被映射到這個預(yù)先安排的地址上。因此在系統(tǒng)加電后,CPU將首先執(zhí)行Bootloader程序。

(3)Bootloader的啟動過程分為單階段和多階段兩種。通常多階段的Bootloader能提供更為復(fù)雜的功能,以及更好的可移植性。

(4)Bootloader的操作模式。大多數(shù)Bootloader都包含兩種不同的操作模式:“啟動加載”模式和“下載”模式,這種區(qū)別僅對于開發(fā)人員才有意義。

n 啟動加載模式:這種模式也稱為“自主”模式。也就是Bootloader從目標(biāo)機(jī)上的某個固態(tài)存儲設(shè)備上將操作系統(tǒng)加載到RAM中運(yùn)行,整個過程并沒有用戶的介入。這種模式是嵌入式產(chǎn)品發(fā)布時的通用模式。

n 下載模式:在這種模式下,目標(biāo)機(jī)上的Bootloader將通過串口連接或網(wǎng)絡(luò)連接等通信手段從主機(jī)(Host)下載文件,比如:下載內(nèi)核映像和根文件系統(tǒng)映像等。從主機(jī)下載的文件通常首先被Bootloader保存到目標(biāo)機(jī)的RAM中,然后再被Bootloader寫入到目標(biāo)機(jī)上的Flash類固態(tài)存儲設(shè)備中。Bootloader的這種模式在系統(tǒng)更新時使用。工作于這種模式下的Bootloader通常都會向它的終端用戶提供一個簡單的命令行接口。

(5)Bootloader與主機(jī)之間進(jìn)行文件傳輸所用的通信設(shè)備及協(xié)議,最常見的情況就是,目標(biāo)機(jī)上的Bootloader通過串口與主機(jī)之間進(jìn)行文件傳輸,傳輸協(xié)議通常是xmodem/?ymodem/zmodem等。但是,串口傳輸?shù)乃俣仁怯邢薜?,因此通過以太網(wǎng)連接并借助TFTP等協(xié)議來下載文件是個更好的選擇。

2.Bootloader啟動流程

Bootloader的啟動流程一般分為兩個階段:stage1和stage2,下面分別對這兩個階段進(jìn)行講解。

(1)Bootloader的stage1。

在stage1中Bootloader主要完成以下工作。

n 基本的硬件初始化,包括屏蔽所有的中斷、設(shè)置CPU的速度和時鐘頻率、RAM初始化、初始化外圍設(shè)備、關(guān)閉CPU內(nèi)部指令和數(shù)據(jù)cache等。

n 為加載stage2準(zhǔn)備RAM空間,通常為了獲得更快的執(zhí)行速度,通常把stage2加載到RAM空間中來執(zhí)行,因此必須為加載Bootloader的stage2準(zhǔn)備好一段可用的RAM空間。

n 復(fù)制stage2到RAM中,在這里要確定兩點:①stage2的可執(zhí)行映像在固態(tài)存儲設(shè)備的存放起始地址和終止地址;②RAM空間的起始地址。

n 設(shè)置堆棧指針sp,這是為執(zhí)行stage2的C語言代碼做好準(zhǔn)備。

(2)Bootloader的stage2。

在stage2中Bootloader主要完成以下工作。

n 用匯編語言跳轉(zhuǎn)到main入口函數(shù)。

由于stage2的代碼通常用C語言來實現(xiàn),目的是實現(xiàn)更復(fù)雜的功能和取得更好的代碼可讀性和可移植性。但是與普通C語言應(yīng)用程序不同的是,在編譯和鏈接Bootloader這樣的程序時,不能使用glibc庫中的任何支持函數(shù)。

n 初始化本階段要使用到的硬件設(shè)備,包括初始化串口、初始化計時器等。在初始化這些設(shè)備之前可以輸出一些打印信息。

n 檢測系統(tǒng)的內(nèi)存映射,所謂內(nèi)存映射就是指在整個4GB物理地址空間中指出哪些地址范圍被分配用來尋址系統(tǒng)的內(nèi)存。

n 加載內(nèi)核映像和根文件系統(tǒng)映像,這里包括規(guī)劃內(nèi)存占用的布局和從Flash上復(fù)制數(shù)據(jù)。

n 設(shè)置內(nèi)核的啟動參數(shù)。

5.2.2??U-Boot概述

1.U-Boot簡介

U-Boot(UniversalBootloader)是遵循GPL條款的開放源碼項目。它是從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來。其源碼目錄、編譯形式與Linux內(nèi)核很相似,事實上,不少U-Boot源碼就是相應(yīng)的Linux內(nèi)核源程序的簡化,尤其是一些設(shè)備的驅(qū)動程序,這從U-Boot源碼的注釋中能體現(xià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等諸多常用系列的處理器。這兩個特點正是U-Boot項目的開發(fā)目標(biāo),即支持盡可能多的嵌入式處理器和嵌入式操作系統(tǒng)。就目前為止,U-Boot對PowerPC系列處理器支持最為豐富,對Linux的支持最完善。

2.U-Boot特點

U-Boot的特點如下。

n 開放源碼;

n 支持多種嵌入式操作系統(tǒng)內(nèi)核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;

n 支持多個處理器系列,如PowerPC、ARM、x86、MIPS、XScale;

n 較高的可靠性和穩(wěn)定性;

n 高度靈活的功能設(shè)置,適合U-Boot調(diào)試、操作系統(tǒng)不同引導(dǎo)要求和產(chǎn)品發(fā)布等;

n 豐富的設(shè)備驅(qū)動源碼,如串口、以太網(wǎng)、SDRAM、Flash、LCD、NVRAM、EEPROM、RTC、鍵盤等;

n 較為豐富的開發(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è)置、傳遞多個關(guān)鍵參數(shù)給操作系統(tǒng),適合系統(tǒng)在不同開發(fā)階段的調(diào)試要求與產(chǎn)品發(fā)布,尤其對Linux支持最為強(qiáng)勁;支持目標(biāo)板環(huán)境參數(shù)多種存儲方式,如Flash、NVRAM、EEPROM;CRC32校驗,可校驗Flash中內(nèi)核、RAMDISK映像文件是否完好。

n 設(shè)備驅(qū)動:串口、SDRAM、Flash、以太網(wǎng)、LCD、NVRAM、EEPROM、鍵盤、USB、PCMCIA、PCI、RTC等驅(qū)動支持。

n 上電自檢功能:SDRAM、Flash大小自動檢測;SDRAM故障檢測;CPU型號。

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:和一些已有開發(fā)板有關(guān)的代碼,比如makefile和U-Boot.lds等都和具體開發(fā)板的硬件和地址分配有關(guān)。

n common:與體系結(jié)構(gòu)無關(guān)的代碼,用來實現(xiàn)各種命令的C程序。

n cpu:包含CPU相關(guān)代碼,其中的子目錄都是以U-BOOT所支持的CPU為名,比如有子目錄arm926ejs、mips、mpc8260和nios等,每個特定的子目錄中都包括cpu.c和interrupt.c,start.S等。其中cpu.c初始化CPU、設(shè)置指令Cache和數(shù)據(jù)Cache等;interrupt.c設(shè)置系統(tǒng)的各種中斷和異常,比如快速中斷、開關(guān)中斷、時鐘中斷、軟件中斷、預(yù)取中止和未定義指令等;匯編代碼文件start.S是U-BOOT啟動時執(zhí)行的第一個文件,它主要是設(shè)置系統(tǒng)堆棧和工作方式,為進(jìn)入C程序奠定基礎(chǔ)。

n disk:disk驅(qū)動的分區(qū)相關(guān)代碼。

n doc:文檔。

n drivers:通用設(shè)備驅(qū)動程序,比如各種網(wǎng)卡、支持CFI的Flash、串口和USB總線等。

n fs:支持文件系統(tǒng)的文件,U-BOOT現(xiàn)在支持cramfs、fat、fdos、jffs2和registerfs等。

n include:頭文件,還有對各種硬件平臺支持的匯編文件,系統(tǒng)的配置文件和對文件系統(tǒng)支持的文件。

n net:與網(wǎng)絡(luò)有關(guān)的代碼,BOOTP協(xié)議、TFTP協(xié)議、RARP協(xié)議和NFS文件系統(tǒng)的實現(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的起始位置。在這個文件中設(shè)置了處理器的狀態(tài)、初始化中斷向量和內(nèi)存時序等,從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:?(拷貝過程)

??????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

這個文件是處理中斷的,如打開和關(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啟動模式下,在原則上要禁止中斷處理,所以如果發(fā)生中斷,當(dāng)作出錯處理?*/

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

這個文件是對處理器進(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

這個文件是用于配置開發(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)建立自己的開發(fā)板類型。

閱讀makefile文件,在makefile文件中添加兩行,如下所示:

fs2410_config:?unconfig?

????@./mkconfig?$(@:_config=)?arm?arm920t?fs2410

其中“arm”為表示處理器體系結(jié)構(gòu)的種類,“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”開頭)。

n 完成之后,可以測試配置。

$?make?fs2410_config;make

(2)修改程序鏈接地址。

在board/s3c2410中有一個config.mk文件,它是用于設(shè)置程序鏈接的起始地址,因為會在U-Boot中增加功能,所以留下6MB的空間,修改33F80000為33A00000。

為了以后能用U-Boot的“go”命令執(zhí)行修改過的用loadb或tftp下載的U-Boot,需要在board/?s3c2410的memsetup.S中標(biāo)記符”0:”上加入5句:

mov?r3,?pc

ldr?r4,?=0x3FFF0000

and?r3,?r3,?r4?(以上3句得到實際代碼啟動的內(nèi)存地址)

aad?r0,?r0,?r3?(用go命令調(diào)試u-boot時,啟動地址在RAM)

add?r2,?r2,?r3?(把初始化內(nèi)存信息的地址,加上實際啟動地址)

(3)將中斷禁止的部分應(yīng)該改為如下所示(/cpu/arm920t/start.S):

#?if?defined(CONFIG_S3C2410)

?????ldr????r1,?=0x7ff??

?????ldr????r0,?=INTSUBMSK

?????str????r1,?[r0]

#?endif

(4)因為在fs2410開發(fā)板啟動時是直接從Nand?Flash加載代碼,所以啟動代碼應(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);

相關(guān)推薦

電子產(chǎn)業(yè)圖譜

華清遠(yuǎn)見(www.farsight.com.cn)是國內(nèi)領(lǐng)先嵌入師培訓(xùn)機(jī)構(gòu),2004年注冊于中國北京海淀高科技園區(qū),除北京總部外,上海、深圳、成都、南京、武漢、西安、廣州均有直營分公司。華清遠(yuǎn)見除提供嵌入式相關(guān)的長期就業(yè)培訓(xùn)、短期高端培訓(xùn)、師資培訓(xùn)及企業(yè)員工內(nèi)訓(xùn)等業(yè)務(wù)外,其下屬研發(fā)中心還負(fù)責(zé)嵌入式、Android及物聯(lián)網(wǎng)方向的教學(xué)實驗平臺的研發(fā)及培訓(xùn)教材的出版,截止目前為止已公開出版70余本嵌入式/移動開發(fā)/物聯(lián)網(wǎng)相關(guān)圖書。企業(yè)理念:專業(yè)始于專注 卓識源于遠(yuǎn)見。企業(yè)價值觀:做良心教育、做專業(yè)教育,更要做受人尊敬的職業(yè)教育。