2007.8.13
u-boot
1.在網上找了幾個u-boot的移植文檔,之前一直沒有成功,後來,設置好u-boot的程序運行地址後,make clean && make at91rm9200dk_config && make ,生成u-boot.bin文件。
2.在調試好arm9200的仿真器後,選擇File->Load memory from file ,選擇u-boot.bin 文件。
3.文件Load 成功以後,將PC指針設置爲u-boot程序的運行地址。
4.執行程序,即可在串口終端看到u-boot的提示符。
2007.8.14
1.發現在文件Start.S中調用了LowLevelInit函數,初始化SDRAM,終端,DEBUG串口,NAND等,根據需要添加。在u-boot中沒有進行LowLevelInit,所以會出現初始化不正確的時候會有問題。
2.經常會出現IIC不能寫的狀況,原因不明。
3.AXD調試的時候,經常要重啓纔可以。有時候要進行斷電。
4.u-boot的程序啓動地址在board/at91rm9200dk/config.mk中修改TEXT_BASE的值
2007.8.15
1.研究PMC時鐘是怎麼回事,給個時鐘是如何產生的,看數據手冊的方框圖。
設置master clock 的寄存器,選擇使用slow clock ,main clock,plla,pllb中的一個作爲時鐘輸入,通過master clock controller後生成master clock 和process clock.選擇的plla和pllb可以通過設置相應的寄存器來倍頻main clock.
1.u-boot-
文件從flash中讀取到sdram中的內存的位置不是這個地址,也還是可以啓動的。所以,之前的bios9200的代碼完全不用作任何的改變,就可以將u-boot燒寫到nand flash上,並且讀入內存,啓動u-boot。之前雖然也進行過直接燒寫的工作,但是可能是u-boot中的代碼,初始化的串口有問題,造成沒有什麼輸出,顯示的。現在代碼中寫死了。
2.閱讀了一下bios9200的代碼,關鍵的部分在於,不同的板子,要進行不同的LowLevelInit工作的,所以之前的at91rm9200_for_Uboot,不能夠使用,也是因爲LowLevelInit初始化的可能有些問題,在u-boot 啓動的時候,按照網上的修改方法,並沒有進行LowLevelInit,所以出現問題。
3.u-boot的移植配置,參看以下文章
開發板H FLSH: [編輯] [編輯]
[編輯]
[編輯] [編輯] board 目標板相關文件,比如Makefile和u-boot.lds等都和具體的開發板的硬件和地址分配有關; [編輯] 1、增加目標平臺到./board/下(此步驟可選,主要爲了不影響源碼) 因爲我們當前平臺h cd u-boot- 2、進入./include/configs下 以at91rm9200dk.h爲模板,生成h cd u-boot- 3、修改Makefile以及 編輯源碼根目錄下的Makefile,搜索at91rm9200, vi u-boot- 4、根據具體的硬件配置,修改參數 因爲在at91rm9200引導時,廠商提供了前期初始化的boot.bin,它主要作了部分的硬件初始化,替代U-boot的 stage1部分,所以在U-boot中就應該去掉這部分功能,不然會導致重複配置,使U-boot在初始配置時當掉,因此我們要修改. /include/configs/h vi u-boot- 5、下面我們要進行鍼對板子的具體化設置 編輯./board/h 將gd->bd->bi_arch_number = MACH_TYPE_AT91RM9200; 再編輯./include/asm-arm/mach-types.h,跳轉到第740行,添加硬件設備的ID號,我們在這裏使用1888作爲h #define MACH_TYPE_H 這樣我們的開發板就有自己的設備號了,不過kernel是不成認的,如果你想讓全世界人都承認,你還要到www.kernel.com去申請你的設備,這樣一來所有內核源碼中都會有這一段代碼了;上面的做法僅用來測試使用。 (至此一個可以啓動的U-boot就已經完成了) [編輯] a.PC宿主機設置 在windows下,打開超級終端,設置串口爲115200 8N1 無流控 b.JP100設置爲2-3短接,從片內rom啓動,啓動片內ROM中的程序。上電,復位,超級終端下出現”CCCCCCC” c.用Xmodem協議發送loader.bin,發完繼續出現”CCCCCC” d.再用Xmodem協議發送u-boot.bin,發完顯示>U-Boot>提示符 e.擦除FLASH: >protect off all 上述兩步擦除FLASH中所有內容,若只擦除uboot所佔部分,則 >protect off 10000000 1001FFFF 或(待證實) >protect off 1:0-1 f.裝入boot.bin >loadb 20000000 (能過串口線(Kermit mode)來裝載二進制文件) 在超級終端下,用kermit模式發送boot.bin >cp.b 20000000 10000000 5ffff g.裝入u-boot.gz >loadb 20000000 用kermit模式發送u-boot.gz >cp.b 20000000 10010000 ffff h.JP100設置爲1-2短接,從flash啓動,啓動Flash中固化的程序。 [編輯] a.網絡參數設置 >setenv ethaddr 12:34:56:78:99:aa ;MAC地址 b.系統自動運行 注意:這裏設置爲絡服務器啓動模式,用網線從主機上下載內核和文件系統到SDRAM中,每次掉電後都要重新開始。 >setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 initrd指定根文件系統的位置 >setenv bootcmd tftp 21000000 uimage/; tftp 21100000 ramdisk.gz/; bootm 21000000 設定自動啓動腳本,先用tftp下載內核鏡象到21000000 ,然後下載文件系統到21100000,再從內核鏡象地址21000000啓動 注意:必須確保主機上啓動了tftp服務,在根目錄上有tftpboot目錄。可用rpm –q tftp查看是否安裝了tftp,若沒有的話,則需要安裝。在服務配置裏選定tftp服務,開始。設置開機時自動啓動tftp服務。執行ntsysv命 令,然後選擇需要開機自動啓動的服務,nfs,tftp等,以空格選擇。 在linux下的終端執行minicom,則啓動串口終端,可以用minicom –s設置。 |
主要參看了網上的幾篇文章,http://bbs2.chinaunix.net/viewthread.php?tid=855860
http://www.lupaworld.com/23340/viewspace_4343.html
重點內容如下部分:
對於uboot的移植請參考我之前寫的《U-Boot的編譯與移植到QT-S3C44B0X開發板上》http://bbs.chinaunix.net/viewthr ... p;highlight=pywj777
非常感謝dozec的《基於S3C2410的Linux全線移植文檔》http://bbs.chinaunix.net/viewthr ... 的Linux全線移植文檔我的nand flash移植大部分是參考這個文檔移植成功的。
下面對nand flash的初始化代碼nand_init()進行分析:
1.如果定義(CONFIG_COMMANDS & CFG_CMD_NAND)沒定義(CFG_NAND_LEGACY) 則start_armboot()調用driver/nand/nand.c中的nand_init(),否則如果定義(CONFIG_COMMANDS & CFG_CMD_NAND)並且有定義了CFG_NAND_LEGACY,則調用自己定義的nand_init()。在我當前的情景中是使用driver/nand/nand.c中的nand_init()。
2.nand_init()調用本文件中的nand_init_chip()對nand進行初始化。
3.nand_init_chip()首先調用board_nand_init()。
4.board_nand_init()是需要自己添加的函數,這個函數的主要功能是對struct nand_chip結構體的函數指針賦值,讓它們指向自己爲nand驅動編寫的一些函數,對未賦值的指針,uboot會在後面爲其賦上通用nand驅動函數指針。
5.nand_init_chip()接着調用nand_scan().
6.nand_scan()定義在drivers/nand/nand_base.c文件中。它首先對struct nand_chip結構體中在board_nand_init()函數中未賦值的指針賦上通用nand驅動函數指針。
7.通用nand驅動函數nand_select_chip()賦值給struct nand_chip結構體的函數指針用於打開或關閉nand芯片,0爲打開,1爲關閉。在這個函數中會調用nand_chip結構體中的hwcontrol函數指針,這個指針指向的函數是需要自己編寫的。這個函數指針在board_nand_init()函數中被賦值。主要作用是向nand flash發送一些nand flash開啓與關閉命令。
8.nand_scan()剩餘部分初始化nand_chip和mtd_info結構體。
9.nand_scan()最後在返回時調用drivers/nand/nand_bbt.c文件中的nand_default_bbt()。
10.nand_default_bby()選擇一個壞塊描述表,返回時調用本文件中的nand_scan_bbt()。
11.nand_scan_bbt()尋找建立一個壞塊描述表。
12.最後返回到nand_init(),這樣nand驅動的初始化完成了。
下面對命令nand read addr ofs size的執行流程進行分析:
1.nand read addr ofs size命令的作用是從nand flash地址的偏移量ofs處讀取長度爲size字節的數據存儲到內存地址addr處。
2.common/main.c文件中的main_loop()主要執行read_line()讀取命令行。
3.read_line()讀取到命令行後會調用common/main.c文件中的run_command()。
4.run_command()調用common/command.c文件中的find_cmd()在.u_boot_cmd段中尋找該命令的cmd_tbl_t結構,找到後返回該結構。該命令的結構是通過定義在include/command.h中的宏定義U_BOOT_CMD登記進.u_boot_cmd段中的。
5.run_command()找到該命令的cmd_tbl_t結構後則執行該命令對應的函數。對於本情景是nand命令對應的函數do_nand()。
6.do_nand()有兩個版本,一個是定義了CFG_NAND_LEGACY。另一個是未定義CFG_NAND_LEGACY。這兩個版本都定義在common/cmd_nand.c文件中。對於本情景使用未定義CFG_NAND_LEGACY的do_nand()函數。要使用do_nand()還必須定義宏CONFIG_COMMANDS&CFG_CMD_NAND。(若未定義CFG_NAND_LEGACY則在這個情景中的do_nand()函數調用的函數都定義在drivers/nand_legacy/nand_legacy.c文件中)。
7.對於我們的情景do_nand()會調用定義在include/nand.h文件中的nand_read()。
8.nand_read()則調用本nand芯片對應的nand_info_t結構的read指針。而read指針在nand_scan()中被指向了同文件(drivers/nand/nand_base.c)中的nand_read()函數。
9.nand_read()函數最終會調用nand_chip結構中的cmdfunc指針,通過這個指針指向的函數向nand flash芯片發送命令。最終完成整個命令的執行。
爲了讓uboot支持自己QT板子的nand flash而進行修改的部分
1.前面的移植請參考我寫的一篇《U-Boot的編譯與移植到QT-S3C44B0X開發板上》,現在在board/51EDA/QT/目錄下建立nand.c文件。
2.在nand.c中添加自己的board_nand_init()函數。設定nand_chip結構中的hwcontrol和dev_ready指針指向自己的函數QT_hwcontrol和QT_device_ready。並建立自己的QT_hwcontrol和QT_device_ready函數。
3.由於自己板子的nand flash的命令發送方式與uboot提供的通用nand flash命令發送方式不同,所以在nand.c文件中建立自己的命令發送函數QT_nand_command(),並在board_nand_init()函數中將nand_chip結構中的cmdfunc指針指向QT_nand_command()函數,使其使用自己定義的發送命令函數。
4.在include/configs/QT.h中定義CFG_NAND_BASE用於指定自己板子nand flash的I/O地址。
5.在CONFIG_COMMANDS中打開CFG_CMD_NAND選項。
6.在include/configs/QT.h中定義NAND_MAX_CHIPS指定自己板子的nand flash芯片數。
7.在include/configs/QT.h中定義CFG_MAX_NAND_DEVICE指定想要支持的nand flash設備數。
dozec的《基於S3C2410的Linux全線移植文檔》在U-BOOT對Nand Flash的支持中的移植方法是在定義了CFG_NAND_LEGACY情況下移植的。而我的是在未定義CFG_NAND_LEGACY的情況下移植的。
基於以上的分析,仔細閱讀u-boot的代碼主要修改board/at91rm9200dk/at91rm9200dk.c
/*
* Disk On Chip (NAND) Millenium initialization.
* The NAND lives in the CS2* space
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe (ulong physadr);
#define AT91_SMARTMEDIA_BASE 0x40000000 /* physical address to access memory on NCS3 */
void nand_init (void)
{
/* Setup Smart Media, fitst enable the address range of CS3 */
*AT
//CFGR
#define AT
#define AT
AT
//根據不同的flash 對寄存器進行相應的設置
/* AT
AT
SM_TDF | AT
AT
AT
(AT
(AT
AT
/* enable the SMOE line PC0=SMCE, A21=CLE, A22=ALE */
*AT
AT
*AT
AT
//flash CE接PC15 RE接PC14,所以進行以下配置,根據不同的板子來
*AT
//enable PC14 bid output
*AT
*AT
//pull-up 14
AT
AT
//enable pc15 for output
*AT
AT
//進行短暫的延時
int j;
for(j=0;j<50000;j++);
printf ("%4lu MB/n", nand_probe(AT91_SMARTMEDIA_BASE) >> 20);
}
修改配置文件include/configs/at91rm9200dk.h中關於nand flash的宏定義
//增加nand的命令支持
#define CONFIG_COMMANDS /
((CONFIG_CMD_DFL | CFG_CMD_MII |/
CFG_CMD_DHCP | CFG_CMD_NAND ) & /
~(CFG_CMD_BDI | /
CFG_CMD_IMI | /
CFG_CMD_AUTOSCRIPT | /
CFG_CMD_FPGA | /
CFG_CMD_MISC | /
CFG_CMD_LOADS ))
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
//#include <asm/arch/AT91RM9200.h>
#define CFG_NAND_LEGACY 1 //使用board/at91rm9200dk/at91rm9200dk.c中的nand_init()函數和driver/nand_legacy/nand_legacy.c中的函數,如果不定義,使用driver/nand/nand.c中的nand_init()
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
//my ale cle 這個不是很明白,應該根據你的板子上的連接來設置,看你的flash 上的cle和ale分別接的是那一根地址線
#define AT91_SMART_MEDIA_ALE (1 << 21) /* our ALE is AD21 */
#define AT91_SMART_MEDIA_CLE (1 << 22) /* our CLE is AD22 */
//PC15接的是CE,PC14接的是RE
#define NAND_DISABLE_CE(nand) do { *AT
#define NAND_ENABLE_CE(nand) do { *AT
#define NAND_WAIT_READY(nand) while (!(*AT
#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_CLE) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_ALE) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
/* the following are NOP's in our implementation */
//要進行修改,按以下定義
#define NAND_CTL_CLRALE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_ALE))
#define NAND_CTL_SETALE(nandptr) (nandptr|AT91_SMART_MEDIA_ALE)
#define NAND_CTL_CLRCLE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_CLE))
#define NAND_CTL_SETCLE(nandptr) (nandptr|AT91_SMART_MEDIA_CLE)
1.解決環境變量env的存儲問題。
描述:在cmd_nvedit.c中,檢查環境變量存儲在那裏。可選的有 CFG_ENV_IS_IN_NVRAM
CFG_ENV_IS_IN_EEPROM
CFG_ENV_IS_IN_FLASH
CFG_ENV_IS_IN_DATAFLASH
CFG_ENV_IS_IN_NAND
CFG_ENV_IS_NOWHERE
在include/configs/at91rm9200.h中定義其中的一種就可以,因爲還沒有搞好I
#define CFG_ENV_IS_IN_NAND
#define CFG_ENV_OFFSET 0x40000 //環境變量存儲位置偏移
#define CFG_ENV_SIZE 0x20000 //環境變量存儲大小
#define CFG_ENV_ADDR 0x40040000
並且註釋掉其他的ENV的設置。
由於nand的驅動使用了nand_legacy.c中的nand接口函數。所以要修改common/env_nand.c中的saveenv 函數和env_relocate_spec函數。
int saveenv(void)
{
ulong total;
int ret = 0;
puts ("Erasing Nand...");
/*
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
*/
if (nand_legacy_erase(&nand_dev_desc[0], CFG_ENV_OFFSET, CFG_ENV_SIZE,1))
return 1;
puts ("Writing to Nand... ");
total = CFG_ENV_SIZE;
/*
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
*/
ret = nand_legacy_rw(&nand_dev_desc[0] , 0x00 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
puts ("done/n");
return ret;
}
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total;
int ret;
total = CFG_ENV_SIZE;
// ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret = nand_legacy_rw(&nand_dev_desc[0], 0x01 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
內核與文件系統移植成功。其中經歷了不少的問題。主要是這麼幾個方面:
1. 在uboot中的bootargs的設置,init=/linuxrc console=/dev/ttyS0,115200 root=/dev/mtdblock2。
2. 自動啓動內核的時候,bootcmd的設置在內核中要給nand flash 分好區的,在第三個分區燒寫上文件系統。
3. 編譯busybox,寫好rcS文件。
1.明確的幾個問題。
1)在當前的啓動方式下,uboot僅僅相當於提供了方便的方式下載內核,文件系統的任務,如何能夠讓uboot自己完成啓動的全部任務。目前爲eeprom中的bios程序,調用燒寫在nand flash上的uboot,完成啓動。但是bios要是從nand flash上讀出uboot,就必須移植nand flash的驅動纔可以,這樣相當於bios也可以完成燒寫nand flash的任務。那麼是不是有辦法讓uboot燒寫在eeprom中,自己啓動的。
2.出現不能初始化console的錯誤的時候,可能是/dev沒有加載,在編譯內核的時候,要選中自動加載/dev在boot的時候,這個選項。不然程序會因爲找不到/dev/console出錯。
2007.8.13
u-boot
1.在網上找了幾個u-boot的移植文檔,之前一直沒有成功,後來,設置好u-boot的程序運行地址後,make clean && make at91rm9200dk_config && make ,生成u-boot.bin文件。
2.在調試好arm9200的仿真器後,選擇File->Load memory from file ,選擇u-boot.bin 文件。
3.文件Load 成功以後,將PC指針設置爲u-boot程序的運行地址。
4.執行程序,即可在串口終端看到u-boot的提示符。
2007.8.14
1.發現在文件Start.S中調用了LowLevelInit函數,初始化SDRAM,終端,DEBUG串口,NAND等,根據需要添加。在u-boot中沒有進行LowLevelInit,所以會出現初始化不正確的時候會有問題。
2.經常會出現IIC不能寫的狀況,原因不明。
3.AXD調試的時候,經常要重啓纔可以。有時候要進行斷電。
4.u-boot的程序啓動地址在board/at91rm9200dk/config.mk中修改TEXT_BASE的值
2007.8.15
1.研究PMC時鐘是怎麼回事,給個時鐘是如何產生的,看數據手冊的方框圖。
設置master clock 的寄存器,選擇使用slow clock ,main clock,plla,pllb中的一個作爲時鐘輸入,通過master clock controller後生成master clock 和process clock.選擇的plla和pllb可以通過設置相應的寄存器來倍頻main clock.
1.u-boot-
文件從flash中讀取到sdram中的內存的位置不是這個地址,也還是可以啓動的。所以,之前的bios9200的代碼完全不用作任何的改變,就可以將u-boot燒寫到nand flash上,並且讀入內存,啓動u-boot。之前雖然也進行過直接燒寫的工作,但是可能是u-boot中的代碼,初始化的串口有問題,造成沒有什麼輸出,顯示的。現在代碼中寫死了。
2.閱讀了一下bios9200的代碼,關鍵的部分在於,不同的板子,要進行不同的LowLevelInit工作的,所以之前的at91rm9200_for_Uboot,不能夠使用,也是因爲LowLevelInit初始化的可能有些問題,在u-boot 啓動的時候,按照網上的修改方法,並沒有進行LowLevelInit,所以出現問題。
3.u-boot的移植配置,參看以下文章
開發板H FLSH: [編輯] [編輯]
[編輯]
[編輯] [編輯] board 目標板相關文件,比如Makefile和u-boot.lds等都和具體的開發板的硬件和地址分配有關; [編輯] 1、增加目標平臺到./board/下(此步驟可選,主要爲了不影響源碼) 因爲我們當前平臺h cd u-boot- 2、進入./include/configs下 以at91rm9200dk.h爲模板,生成h cd u-boot- 3、修改Makefile以及 編輯源碼根目錄下的Makefile,搜索at91rm9200, vi u-boot- 4、根據具體的硬件配置,修改參數 因爲在at91rm9200引導時,廠商提供了前期初始化的boot.bin,它主要作了部分的硬件初始化,替代U-boot的 stage1部分,所以在U-boot中就應該去掉這部分功能,不然會導致重複配置,使U-boot在初始配置時當掉,因此我們要修改. /include/configs/h vi u-boot- 5、下面我們要進行鍼對板子的具體化設置 編輯./board/h 將gd->bd->bi_arch_number = MACH_TYPE_AT91RM9200; 再編輯./include/asm-arm/mach-types.h,跳轉到第740行,添加硬件設備的ID號,我們在這裏使用1888作爲h #define MACH_TYPE_H 這樣我們的開發板就有自己的設備號了,不過kernel是不成認的,如果你想讓全世界人都承認,你還要到www.kernel.com去申請你的設備,這樣一來所有內核源碼中都會有這一段代碼了;上面的做法僅用來測試使用。 (至此一個可以啓動的U-boot就已經完成了) [編輯] a.PC宿主機設置 在windows下,打開超級終端,設置串口爲115200 8N1 無流控 b.JP100設置爲2-3短接,從片內rom啓動,啓動片內ROM中的程序。上電,復位,超級終端下出現”CCCCCCC” c.用Xmodem協議發送loader.bin,發完繼續出現”CCCCCC” d.再用Xmodem協議發送u-boot.bin,發完顯示>U-Boot>提示符 e.擦除FLASH: >protect off all 上述兩步擦除FLASH中所有內容,若只擦除uboot所佔部分,則 >protect off 10000000 1001FFFF 或(待證實) >protect off 1:0-1 f.裝入boot.bin >loadb 20000000 (能過串口線(Kermit mode)來裝載二進制文件) 在超級終端下,用kermit模式發送boot.bin >cp.b 20000000 10000000 5ffff g.裝入u-boot.gz >loadb 20000000 用kermit模式發送u-boot.gz >cp.b 20000000 10010000 ffff h.JP100設置爲1-2短接,從flash啓動,啓動Flash中固化的程序。 [編輯] a.網絡參數設置 >setenv ethaddr 12:34:56:78:99:aa ;MAC地址 b.系統自動運行 注意:這裏設置爲絡服務器啓動模式,用網線從主機上下載內核和文件系統到SDRAM中,每次掉電後都要重新開始。 >setenv bootargs root=/dev/ram rw initrd=0x21100000,6000000 ramdisk_size=15360 initrd指定根文件系統的位置 >setenv bootcmd tftp 21000000 uimage/; tftp 21100000 ramdisk.gz/; bootm 21000000 設定自動啓動腳本,先用tftp下載內核鏡象到21000000 ,然後下載文件系統到21100000,再從內核鏡象地址21000000啓動 注意:必須確保主機上啓動了tftp服務,在根目錄上有tftpboot目錄。可用rpm –q tftp查看是否安裝了tftp,若沒有的話,則需要安裝。在服務配置裏選定tftp服務,開始。設置開機時自動啓動tftp服務。執行ntsysv命 令,然後選擇需要開機自動啓動的服務,nfs,tftp等,以空格選擇。 在linux下的終端執行minicom,則啓動串口終端,可以用minicom –s設置。 |
主要參看了網上的幾篇文章,http://bbs2.chinaunix.net/viewthread.php?tid=855860
http://www.lupaworld.com/23340/viewspace_4343.html
重點內容如下部分:
對於uboot的移植請參考我之前寫的《U-Boot的編譯與移植到QT-S3C44B0X開發板上》http://bbs.chinaunix.net/viewthr ... p;highlight=pywj777
非常感謝dozec的《基於S3C2410的Linux全線移植文檔》http://bbs.chinaunix.net/viewthr ... 的Linux全線移植文檔我的nand flash移植大部分是參考這個文檔移植成功的。
下面對nand flash的初始化代碼nand_init()進行分析:
1.如果定義(CONFIG_COMMANDS & CFG_CMD_NAND)沒定義(CFG_NAND_LEGACY) 則start_armboot()調用driver/nand/nand.c中的nand_init(),否則如果定義(CONFIG_COMMANDS & CFG_CMD_NAND)並且有定義了CFG_NAND_LEGACY,則調用自己定義的nand_init()。在我當前的情景中是使用driver/nand/nand.c中的nand_init()。
2.nand_init()調用本文件中的nand_init_chip()對nand進行初始化。
3.nand_init_chip()首先調用board_nand_init()。
4.board_nand_init()是需要自己添加的函數,這個函數的主要功能是對struct nand_chip結構體的函數指針賦值,讓它們指向自己爲nand驅動編寫的一些函數,對未賦值的指針,uboot會在後面爲其賦上通用nand驅動函數指針。
5.nand_init_chip()接着調用nand_scan().
6.nand_scan()定義在drivers/nand/nand_base.c文件中。它首先對struct nand_chip結構體中在board_nand_init()函數中未賦值的指針賦上通用nand驅動函數指針。
7.通用nand驅動函數nand_select_chip()賦值給struct nand_chip結構體的函數指針用於打開或關閉nand芯片,0爲打開,1爲關閉。在這個函數中會調用nand_chip結構體中的hwcontrol函數指針,這個指針指向的函數是需要自己編寫的。這個函數指針在board_nand_init()函數中被賦值。主要作用是向nand flash發送一些nand flash開啓與關閉命令。
8.nand_scan()剩餘部分初始化nand_chip和mtd_info結構體。
9.nand_scan()最後在返回時調用drivers/nand/nand_bbt.c文件中的nand_default_bbt()。
10.nand_default_bby()選擇一個壞塊描述表,返回時調用本文件中的nand_scan_bbt()。
11.nand_scan_bbt()尋找建立一個壞塊描述表。
12.最後返回到nand_init(),這樣nand驅動的初始化完成了。
下面對命令nand read addr ofs size的執行流程進行分析:
1.nand read addr ofs size命令的作用是從nand flash地址的偏移量ofs處讀取長度爲size字節的數據存儲到內存地址addr處。
2.common/main.c文件中的main_loop()主要執行read_line()讀取命令行。
3.read_line()讀取到命令行後會調用common/main.c文件中的run_command()。
4.run_command()調用common/command.c文件中的find_cmd()在.u_boot_cmd段中尋找該命令的cmd_tbl_t結構,找到後返回該結構。該命令的結構是通過定義在include/command.h中的宏定義U_BOOT_CMD登記進.u_boot_cmd段中的。
5.run_command()找到該命令的cmd_tbl_t結構後則執行該命令對應的函數。對於本情景是nand命令對應的函數do_nand()。
6.do_nand()有兩個版本,一個是定義了CFG_NAND_LEGACY。另一個是未定義CFG_NAND_LEGACY。這兩個版本都定義在common/cmd_nand.c文件中。對於本情景使用未定義CFG_NAND_LEGACY的do_nand()函數。要使用do_nand()還必須定義宏CONFIG_COMMANDS&CFG_CMD_NAND。(若未定義CFG_NAND_LEGACY則在這個情景中的do_nand()函數調用的函數都定義在drivers/nand_legacy/nand_legacy.c文件中)。
7.對於我們的情景do_nand()會調用定義在include/nand.h文件中的nand_read()。
8.nand_read()則調用本nand芯片對應的nand_info_t結構的read指針。而read指針在nand_scan()中被指向了同文件(drivers/nand/nand_base.c)中的nand_read()函數。
9.nand_read()函數最終會調用nand_chip結構中的cmdfunc指針,通過這個指針指向的函數向nand flash芯片發送命令。最終完成整個命令的執行。
爲了讓uboot支持自己QT板子的nand flash而進行修改的部分
1.前面的移植請參考我寫的一篇《U-Boot的編譯與移植到QT-S3C44B0X開發板上》,現在在board/51EDA/QT/目錄下建立nand.c文件。
2.在nand.c中添加自己的board_nand_init()函數。設定nand_chip結構中的hwcontrol和dev_ready指針指向自己的函數QT_hwcontrol和QT_device_ready。並建立自己的QT_hwcontrol和QT_device_ready函數。
3.由於自己板子的nand flash的命令發送方式與uboot提供的通用nand flash命令發送方式不同,所以在nand.c文件中建立自己的命令發送函數QT_nand_command(),並在board_nand_init()函數中將nand_chip結構中的cmdfunc指針指向QT_nand_command()函數,使其使用自己定義的發送命令函數。
4.在include/configs/QT.h中定義CFG_NAND_BASE用於指定自己板子nand flash的I/O地址。
5.在CONFIG_COMMANDS中打開CFG_CMD_NAND選項。
6.在include/configs/QT.h中定義NAND_MAX_CHIPS指定自己板子的nand flash芯片數。
7.在include/configs/QT.h中定義CFG_MAX_NAND_DEVICE指定想要支持的nand flash設備數。
dozec的《基於S3C2410的Linux全線移植文檔》在U-BOOT對Nand Flash的支持中的移植方法是在定義了CFG_NAND_LEGACY情況下移植的。而我的是在未定義CFG_NAND_LEGACY的情況下移植的。
基於以上的分析,仔細閱讀u-boot的代碼主要修改board/at91rm9200dk/at91rm9200dk.c
/*
* Disk On Chip (NAND) Millenium initialization.
* The NAND lives in the CS2* space
*/
#if (CONFIG_COMMANDS & CFG_CMD_NAND)
extern ulong nand_probe (ulong physadr);
#define AT91_SMARTMEDIA_BASE 0x40000000 /* physical address to access memory on NCS3 */
void nand_init (void)
{
/* Setup Smart Media, fitst enable the address range of CS3 */
*AT
//CFGR
#define AT
#define AT
AT
//根據不同的flash 對寄存器進行相應的設置
/* AT
AT
SM_TDF | AT
AT
AT
(AT
(AT
AT
/* enable the SMOE line PC0=SMCE, A21=CLE, A22=ALE */
*AT
AT
*AT
AT
//flash CE接PC15 RE接PC14,所以進行以下配置,根據不同的板子來
*AT
//enable PC14 bid output
*AT
*AT
//pull-up 14
AT
AT
//enable pc15 for output
*AT
AT
//進行短暫的延時
int j;
for(j=0;j<50000;j++);
printf ("%4lu MB/n", nand_probe(AT91_SMARTMEDIA_BASE) >> 20);
}
修改配置文件include/configs/at91rm9200dk.h中關於nand flash的宏定義
//增加nand的命令支持
#define CONFIG_COMMANDS /
((CONFIG_CMD_DFL | CFG_CMD_MII |/
CFG_CMD_DHCP | CFG_CMD_NAND ) & /
~(CFG_CMD_BDI | /
CFG_CMD_IMI | /
CFG_CMD_AUTOSCRIPT | /
CFG_CMD_FPGA | /
CFG_CMD_MISC | /
CFG_CMD_LOADS ))
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include <cmd_confdefs.h>
//#include <asm/arch/AT91RM9200.h>
#define CFG_NAND_LEGACY 1 //使用board/at91rm9200dk/at91rm9200dk.c中的nand_init()函數和driver/nand_legacy/nand_legacy.c中的函數,如果不定義,使用driver/nand/nand.c中的nand_init()
#define CFG_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define ADDR_COLUMN 1
#define ADDR_PAGE 2
#define ADDR_COLUMN_PAGE 3
#define NAND_ChipID_UNKNOWN 0x00
#define NAND_MAX_FLOORS 1
#define NAND_MAX_CHIPS 1
//my ale cle 這個不是很明白,應該根據你的板子上的連接來設置,看你的flash 上的cle和ale分別接的是那一根地址線
#define AT91_SMART_MEDIA_ALE (1 << 21) /* our ALE is AD21 */
#define AT91_SMART_MEDIA_CLE (1 << 22) /* our CLE is AD22 */
//PC15接的是CE,PC14接的是RE
#define NAND_DISABLE_CE(nand) do { *AT
#define NAND_ENABLE_CE(nand) do { *AT
#define NAND_WAIT_READY(nand) while (!(*AT
#define WRITE_NAND_COMMAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_CLE) = (__u8)(d); } while(0)
#define WRITE_NAND_ADDRESS(d, adr) do{ *(volatile __u8 *)((unsigned long)adr | AT91_SMART_MEDIA_ALE) = (__u8)(d); } while(0)
#define WRITE_NAND(d, adr) do{ *(volatile __u8 *)((unsigned long)adr) = (__u8)d; } while(0)
#define READ_NAND(adr) ((volatile unsigned char)(*(volatile __u8 *)(unsigned long)adr))
/* the following are NOP's in our implementation */
//要進行修改,按以下定義
#define NAND_CTL_CLRALE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_ALE))
#define NAND_CTL_SETALE(nandptr) (nandptr|AT91_SMART_MEDIA_ALE)
#define NAND_CTL_CLRCLE(nandptr) (nandptr & ~(AT91_SMART_MEDIA_CLE))
#define NAND_CTL_SETCLE(nandptr) (nandptr|AT91_SMART_MEDIA_CLE)
1.解決環境變量env的存儲問題。
描述:在cmd_nvedit.c中,檢查環境變量存儲在那裏。可選的有 CFG_ENV_IS_IN_NVRAM
CFG_ENV_IS_IN_EEPROM
CFG_ENV_IS_IN_FLASH
CFG_ENV_IS_IN_DATAFLASH
CFG_ENV_IS_IN_NAND
CFG_ENV_IS_NOWHERE
在include/configs/at91rm9200.h中定義其中的一種就可以,因爲還沒有搞好I
#define CFG_ENV_IS_IN_NAND
#define CFG_ENV_OFFSET 0x40000 //環境變量存儲位置偏移
#define CFG_ENV_SIZE 0x20000 //環境變量存儲大小
#define CFG_ENV_ADDR 0x40040000
並且註釋掉其他的ENV的設置。
由於nand的驅動使用了nand_legacy.c中的nand接口函數。所以要修改common/env_nand.c中的saveenv 函數和env_relocate_spec函數。
int saveenv(void)
{
ulong total;
int ret = 0;
puts ("Erasing Nand...");
/*
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
*/
if (nand_legacy_erase(&nand_dev_desc[0], CFG_ENV_OFFSET, CFG_ENV_SIZE,1))
return 1;
puts ("Writing to Nand... ");
total = CFG_ENV_SIZE;
/*
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
*/
ret = nand_legacy_rw(&nand_dev_desc[0] , 0x00 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
puts ("done/n");
return ret;
}
/*
* The legacy NAND code saved the environment in the first NAND device i.e.,
* nand_dev_desc + 0. This is also the behaviour using the new NAND code.
*/
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
ulong total;
int ret;
total = CFG_ENV_SIZE;
// ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
ret = nand_legacy_rw(&nand_dev_desc[0], 0x01 ,CFG_ENV_OFFSET,CFG_ENV_SIZE, (size_t *)&total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();
#endif /* ! ENV_IS_EMBEDDED */
}
內核與文件系統移植成功。其中經歷了不少的問題。主要是這麼幾個方面:
1. 在uboot中的bootargs的設置,init=/linuxrc console=/dev/ttyS0,115200 root=/dev/mtdblock2。
2. 自動啓動內核的時候,bootcmd的設置在內核中要給nand flash 分好區的,在第三個分區燒寫上文件系統。
3. 編譯busybox,寫好rcS文件。
1.明確的幾個問題。
1)在當前的啓動方式下,uboot僅僅相當於提供了方便的方式下載內核,文件系統的任務,如何能夠讓uboot自己完成啓動的全部任務。目前爲eeprom中的bios程序,調用燒寫在nand flash上的uboot,完成啓動。但是bios要是從nand flash上讀出uboot,就必須移植nand flash的驅動纔可以,這樣相當於bios也可以完成燒寫nand flash的任務。那麼是不是有辦法讓uboot燒寫在eeprom中,自己啓動的。
2.出現不能初始化console的錯誤的時候,可能是/dev沒有加載,在編譯內核的時候,要選中自動加載/dev在boot的時候,這個選項。不然程序會因爲找不到/dev/console出錯。