U-boot1.3.4移植流程
標籤: ARM Linux Uboot 移植 DM9000 YAFFS 抵岸科技
U-boot簡介
一般來說,引導加載程序是系統加電後運行的第一段代碼(at91sam芯片除外,其加電第一段程序是BOOTROM,其次是Bootstrap)。大家熟悉的PC中的引導程序一般由BIOS和位於MBR的操作系統BootLoader(例如LILO或者GRUB)一起組成。然而在嵌入式系統中通常沒有像BIOS那樣的固件程序,因此整個系統的加載啓動任務就完全由BootLoader來完成。在嵌入式Linux中,引導加載程序即等效爲BootLoader。簡單地說,BootLoader就是在操作系統內核運行前執行的一段小程序。通過這段小程序,我們可以初始化必要的硬件設備,創建內核需要的一些信息並將這些信息通過相關機制傳遞給內核,從而將系統的軟硬件環境帶到一個合適的狀態,最終調用操作系統內核,真正起到引導和加載內核的作用。
BootLoader是依賴於硬件實現的,特別是在嵌入式系統中。不同體系結構需求的BootLoader是不同的,除了體系結構,BootLoader還依賴於具體的嵌入式板級設備的配置。也就是說,對於兩塊不同的嵌入式板而言,即使它們基於相同的CPU構建,運行在其中一塊電路板上的BootLoader,未必能夠運行在另一塊電路開發板上。
Bootloader的啓動過程可以是單階段的,也可以是多階段的。大多數單階段的BootLoader應用於簡單的系統,比如沒有操作系統的系統。通常多階段的BootLoader能提供更爲複雜的功能以及更好的可移植性。從固態存儲設備上啓動的BootLoader大多數是兩階段的啓動過程,也就是啓動過程可以分爲stage 1和stage 2兩部分。依賴於CPU體系結構的代碼,比如設備初始化代碼 等,通常都放在stage1中,而且通常都用彙編語言來實現,以達到短小精悍的目的。而stage2則通常用C語言來實現,這樣可以實現更復雜的功能,而且代碼會具有更好的可讀性和可移植性。
大多數BootLoader都包含兩種不同的操作模式:啓動加載(Boot loading)模式和下載(Down loading)模式,這種區別僅對於開發人員纔有意義。但從最終用戶的角度看,BootLoader的作用就是用來加載操作系統,而並不存在所謂的啓動加載模式與下載工作模式的區別。
(1)啓動加載模式:這種模式也稱爲自主(Autonomous)模式,即BootLoader從目標機上的某個固態存儲設備上將操作系統加載到RAM中運行,整個過程沒有用戶的介入。這種模式是BootLoader的正常工作模式。因此在嵌入式產品發佈的時候,BootLoader顯然必須工作在這種模式下。
(2)下載模式:在這種模式下,目標機上的BootLoader將通過串口連接或網絡連接等通信手段從主機上下載文件,比如下載應用程序、數據文件、內核映像等。從主機下載的文件通常首先被BootLoader保存到目標機的RAM中然後再被BootLoader寫到目標機上的固態存儲設備中,BootLoader的這種模式通常在系統更新時使用。工作於這種模式下的BootLoader通常都會向它的終端用戶提供一個簡單的命令行接口,比如U-Boot、Blob、VIVI等。
U-Boot是德國DENX小組開發的用於多種嵌入式CPU的BootLoader程序,它可以運行在基於PowerPC、ARM、MIPS等多種嵌入式開發板上。從http://u-boot.sourceforge.net/ 或ftp://ftp.denx.de/pub/u-boot/ 站點都可以下載U-Boot的源代碼,U-Boot源代碼的主要目錄解釋如下。
· board 目標板相關文件,主要包含SDRAM、Flash驅動;
· common 獨立於處理器體系結構的通用代碼,如內存大小探測與故障檢測;
· cpu 與處理器相關的文件,如mpc8xx子目錄下含串口、網口、LCD驅動及中斷初始化等文件;
· driver 通用設備驅動,如CFI Flash驅動(目前對Intel Flash支持較好);
· doc U-Boot的說明文檔;
· examples 可在U-Boot下運行的示例程序,如hello_world.c、timer.c;
· include U-Boot頭文件,尤其是configs子目錄下與目標板相關的配置頭文件是移植過程中經常要修改的文件;
· lib_xxx 處理器體系相關的文件,如lib_ppc、lib_arm目錄分別包含與PowerPC、ARM體系結構相關的文件;
· net 與網絡功能相關的文件目錄,如bootp、nfs、tftp;
· post 上電自檢文件目錄,尚有待於進一步完善;
· rtc RTC(Real Time Clock,實時時鐘)驅動程序;
· tools 用於創建U-Boot S-RECORD和BIN鏡像文件的工具。
開發環境
? Linux環境:Ubuntu 10.4。
? Windows環境:Windows XP SP3。
? U-boot版本:v1.3.4。
? 交叉編譯工具:arm-linux-gcc 4.3.2。
下載U-boot源代碼及ATMEL補丁
U-boot-1.3.4源代碼下載地址:
ftp://ftp.denx.de/pub/u-boot/u-boot-1.3.4.tar.bz2
AT91 U-boot 功能補丁下載地址:
ftp://www.at91.com/pub/uboot/u-boot-1.3.4-exp.5/u-boot-1.3.4-exp.5.diff
安裝補丁及修改編譯U-boot
1. 解壓U-boot-1.3.4
將u-boot-1.3.4.tar.bz2壓縮包拷貝到/opt/目錄,在提示符下輸入:
/opt# tar jxf u-boot-1.3.4.tar.bz2
將壓縮包解壓在當前目錄。如圖1所示:
圖 1
2. 安裝補丁文件
將補丁文件u-boot-1.3.4-exp.diff和u-boot-1.3.4-exp.5.diff複製到U-boot的根目錄下。
/opt/u-boot-1.3.4# cat u-boot-1.3.4-exp.5.diff | patch -p1
3. 修改U-boot源代碼
增加對DM9000的支持:
修改board/atmel/at91sam9g20ek/at91sam9g20ek.c文件,在其中添加 DM9000的硬件初始化:
#ifdef CONFIG_DRIVER_DM9000
static void at91sam9263ek_dm9000_hw_init(void)
{
/* Configure SMC CS2 for DM9000 */
at91_sys_write(AT91_SMC_SETUP(2),
AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(0) |
AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(0));
at91_sys_write(AT91_SMC_PULSE(2),
AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(8) |
AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(8));
at91_sys_write(AT91_SMC_CYCLE(2),
AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
at91_sys_write(AT91_SMC_MODE(2),
AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
AT91_SMC_EXNWMODE_DISABLE |
AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16 |
AT91_SMC_TDF_(1));
/* Configure Reset signal as output */
at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS2*/
/* Configure Interrupt pin as input, no pull-up */
at91_set_gpio_input(AT91_PIN_PB25, 0);
}
#endif
229行添加:
#ifdef CONFIG_DRIVER_DM9000
at91sam9263ek_dm9000_hw_init();
#endif
250行修改:
#if defined(CONFIG_MACB) || defined(CONFIG_DRIVER_DM9000)
增加燒寫YAFFS的功能:
修改common/cmd_nand.c文件,在其349行添加:
#if defined(ENABLE_CMD_NAND_YAFFS)
} else if ( s != NULL &&
(!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))){
if (read) {
/* read */
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
opts.readoob = 1;
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts);
} else {
/* write */
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
//opts.noecc = 1;
opts.pad = 0;
opts.writeoob = 1;
opts.blockalign = 1;
opts.quiet = quiet;
opts.autoplace = 1;
if (s[6] == '1')
opts.forceyaffs = 1;
#if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)
opts.skipfirstblk = 1;
#endif
ret = nand_write_opts(nand, &opts);
}
#endif
在504行添加如下紅色代碼:
U_BOOT_CMD(nand, 5, 1, do_nand,
"nand - NAND sub-system/n",
"info - show available NAND devices/n"
"nand device [dev] - show or set current device/n"
"nand read[.jffs2] - addr off|partition size/n"
"nand write[.jffs2] - addr off|partition size - read/write `size' bytes starting/n"
" at offset `off' to/from memory address `addr'/n"
#if defined(ENABLE_CMD_NAND_YAFFS)
"nand write[.yaffs[1]] - addr off|partition size - write `size' byte yaffs image/n"
" starting at offset `off' from memory address `addr' (.yaffs1 for 512+16 NAND)/n"
#endif
"nand erase [clean] [off size] - erase `size' bytes from/n"
" offset `off' (entire device if not specified)/n"
"nand bad - show bad blocks/n"
修改drivers/mtd/nand/nand_util.c文件,在356行添加如下紅色代碼:
/* force OOB layout for jffs2 or yaffs? */
if (opts->forcejffs2 || opts->forceyaffs) {
struct nand_oobinfo *oobsel =
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
#if definde(CFG_NAND_YAFFS1_NEW_OOB_LAYOUT)
/* jffs2_oobinfo matches 2.6.18+ MTD nand_oob_16 ecclayout */
oobsel = &jffs2_oobinfo;
#endif
if (meminfo->oobsize == 8) {
if (opts->forceyaffs) {
printf("YAFSS cannot operate on "
"256 Byte page size/n");
goto restoreoob;
在456行添加如下紅色代碼:
/* read OOB data from input memory block, exit
* on failure */
memcpy(oob_buf, buffer, meminfo->oobsize);
buffer += meminfo->oobsize;
if (opts->forceyaffs) {
#if define(CFG_NAND_YAFFS1_NEW_OOB_LAYOUT)
/* translate OOB for yaffs1 on Linux 2.6.18+ */
oob_buf[15] = oob_buf[12];
oob_buf[14] = oob_buf[11];
oob_buf[13] = (oob_buf[7] & 0x3f)
| (oob_buf[5] == 'Y' ? 0 : 0x80)
| (oob_buf[4] == 0 ? 0 : 0x40);
oob_buf[12] = oob_buf[6];
oob_buf[11] = oob_buf[3];
oob_buf[10] = oob_buf[2];
oob_buf[9] = oob_buf[1];
oob_buf[8] = oob_buf[0];
memset(oob_buf, 0xff, 8);
#else
/* set the ECC bytes to 0xff so MTD will
calculate it */
int i;
for (i = 0; i < meminfo->oobinfo.eccbytes; i++)
oob_buf[meminfo->oobinfo.eccpos[i]] = 0xff;
#endif
}
/* write OOB data first, as ecc will be placed
* in there*/
result = meminfo->write_oob(meminfo,
mtdoffset,
修改include/command.h文件,添加:
define ENABLE_CMD_NAND_YAFFS 1
define ENABLE_CMD_NAND_YAFFS_SKIPFB 1
define CFG_NAND_YAFFS1_NEW_OOB_LAYOUT 0
解決目標板的一個BUG:
將board/atmel/at91sam9g20ek/at91sam9g20ek.c文件的159行屏蔽:
//at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_EXTRST);
4. 編譯U-boot生成BIN文件
在提示符下輸入以下命令:
/opt/u-boot-1.3.4# make distclean
/opt/u-boot-1.3.4# make ARCH=arm at91sam9g20ek_nandflash_config
/opt/u-boot-1.3.4# make ARCH=arm CROSS_COMPILE=arm-linux-
如圖2所示:
圖 2
在U-boot的根目錄下,可以看到剛剛出生的u-boot.bin文件。
下載U-boot到目標板
打開SAM-BA程序,按照圖3所示的步驟,將u-boot.bin文件燒寫到NANDFLASH當中。
圖 3
文件歷史記錄
版本 編制 日期 更改內容
-----------------------------------------------------------------------------------
V1.0 抵岸科技 2010-7-5 首發