星期三, 4月 09, 2008

U-boot移植日記(s3c44b0)

摘自: http://bbs.chinalinux.com/blog.php?tid=176&starttime=0&endtime=0

幾經艱辛,終於基本完成了 u-boot 在 s3c44b0 的移植工作,在些記錄一下在移植過程中所碰到的困難和解決方法(一些心得),作為日後參考之用,也希望能夠幫到其它有需要的人 ^_^ 。
1. 來由:
在我搞完 ucos 後 ( 本來我是想學 uclinux 的,不過在對系統一無所知的情況下,還是先學一下 ucos 比較實際 ^_^ ,從中也可以對系統有個清晰的概 念 ) ,我意識到要搞系統的話一個功能強大的 bootloader 是必不可少的,而我的板上自帶的是 armboot (其實我個人覺得應用在 ARM 上的話 armboot 已經足夠了,畢竟 u-boot 也是從 armboot 中發展過來的,純屬個人意見),如果我的板上自帶光盤有已經移植好的 armboot 源代 碼供我參考的話,我想我也不會花這麼多時間去搞 u-boot ,可恨的是我的光盤上只有 armboot.bin 這個二進制文件,而沒有源文件,沒辦法,我下 定主意自己搞一個,考慮了一番後我選擇了 u-boot ,畢竟參考資料相對比較多,再我學完 u-boot 後再回頭看 armboot ,簡直是一個爐裡出的餅, 這是後話。
2. 準備:
說是容易,做起來卻挺難。因為編譯 u-boot 要在 linux 環境下,而不能在我們平時所熟悉的 ads 下那麼直觀。首先要建立好交叉編譯環境,這個交叉編 譯環境可以自己來做,不過完全沒必要,而且難度也挺大,一般是下載人家編譯好的工具。我剛開始在這裡就鬱悶了很久,現在會了以後覺得原來就是這麼簡單,在 些我把方法說清楚,希望不會再有人為這個問題鬱悶了 ^_^ :
1 )在網上下載一個 u-boot 源代碼,我用的是 1.1.2 版本的,最新的應該是 1.1.4 的吧,其實差不多,那就像我那樣下載一個 1.1.2 版本的吧。 把源文件解壓,這個應該不用說了吧,學過 linux 的人應該會,不會的話我想你繼續做下去也困難,那就先裝個 linux 用下吧(我用的是 RedHat 的, 哦對了,編譯程序是需要 gcc 編譯器的,所以安裝方式一定要選擇工作站哦 ^_^ )。好了,解壓後你發現在 u-boot.1.1.2 目錄下有 Makefile 這個文件吧?讓我們看看它裡面的內容,最簡單的方法就是 vi Makefile 了。我們要看的是它選擇的是哪一個交叉編譯器。可以看到這一項:
ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
看到吧,也就是說這裡所用的交叉編譯器是 arm-linux-gcc 了,( u-boot 默認是用這個的,也有用 arm-elf-gcc 的,網上有個工具包 arm-elf-tools-20030314.sh, 我試過用它來編譯,沒有問題,順便提一下, arm-elf-gcc 是用來編譯 uClinux 內核的 工具來的)那你就下載一個 arm-linux- 的交叉編譯器吧,我是在網上下載 cross-2.95.3.tar.bz2 這個文件,然後解壓得到 2.95.3 版本的交叉編譯工具的,具體設置如下(參考網上資料):
2 )在宿主機上建立 arm-linux-gcc 交叉編譯環境
在 RedHat Linux 系統下以 root 用戶登錄,
將 cross-2.95.3.tar.bz2 文件複製到 / 目錄下,
安裝:
# tar jxvf cross-2.95.3.tar.bz2
這個命令會在你的 /usr/local/arm/2.95.3 目錄下安裝 arm-linux-gcc 交叉編譯程序,
然後在 PATH 變量中添加一項: /usr/local/arm/2.95.3/bin.
[root@localhost root]# export ATH=/usr/local/arm/2.95.3/bin:$PATH

把 PATH=/usr/local/arm/2.95.3/bin:$PATH 添加到 /ETC/bash_profile 文件中
或者
在 /etc/bashrc 文件中添加一項 :
export PATH=/usr/local/arm/2.95.3/bin:$PATH
測試:
把終端關閉,重新打開後執行如下命令:
# arm-linux-gcc –v
好了,建立好交叉編譯環境後可以試著編譯 u-boot 了

這裡提幾個注意點:
1. 不可用 winRAR 解壓 u-boot-1.1.2.tar.bz2 或 u-boot-1.1.2.tar.gz 這種文件(就個可能新手會犯,一般熟悉 linux 命令的人應該都不會這樣做吧,在此還是要提一下)
2. 可能下載的文件有一些中間文件會阻礙編譯的運行,所以在編譯前最好來個徹底清除,在 u-boot.1.1.2 目錄下運行命令: make distclean (其實這個命令在 Makefile 文件下就有)我當時為這個問題鬱悶了很久,希望你們不會像我這樣 ^_^ ) ;
3 ,有些人為了方便想在 cygwin 下編譯,但是經常在網上看到在這個虛擬平台下編譯有很多的問題,要配置的東西也多,而且好像我用過那個 vi 沒有 linux 環境下的好用,所以最好還是不要用這個軟件了吧,如果你真的離不開 windows 的話可以像我這樣裝個虛擬機,在虛擬機下再裝 linux 的系 統,具體參考這個網站): http://fedora.linuxsir.org/doc/vmware/
3 )好了,現在開始測試你的交叉編譯器搞好沒有。在 u-boot. 1.1.2 目錄下執行如下命令:
1)Make distclean ( 再次強調 )
2)Make B2_config( 隨便再個現成的試試 ^_^)
3)Make ( 沒錯的話應該會生成 u-boot.bin 文件,發生錯誤的話也不怕,只要細心看一下哪裡錯就行了, gcc 碰到錯誤後會退出編譯,所以可以一個個錯誤來 改,一般的問題都是沒找到編譯器(可能你沒裝或者裝的不對,例如人家用的是 arm-linux- 而你裝的是 arm-elf- ,如果你裝了的話看看你的環境 變量設好了沒有,前面有講,如果不關編譯器的事的話那就再看看,一般是文件的後綴不對,有些文件後綴是大寫的,例如 start.S 但是如果你的是 start.s 小寫的話那當然找不到(解決方法很,把它改成大寫就行了)。細心看吧,不用怕,它都有註明路徑,很容易可以找到的) )
如果以上步驟都無誤的話那麼恭喜你,你的交叉編譯環境可以用來編譯你的 u-boot 源代碼了,可以開始以下階段。

3. 移植:
說時遲那時快,現在開始移植工作 ( 以下是我一步步重新做一遍,力求說得詳細點,感謝我吧 ^_^)
我以 B2 板子的程序做為模板來做 .
#cd u-boot- 1.1.2
#cd board
#cp -R dave myboard ( 這是我取的板子名字,可以換上你的,但是後面的也要跟著來換哦 ^_^)
#cd myboard
#mv B2 myboards 3c 44b0 ( 自己取個板子名 )
#cd myboards 3c 44b0
# mv B2.c myboards 3c 44b0.c
修改 myboards 3c 44b0 裡面的 Makefile, 把 B2 改成 myboards 3c 44b0 ,編譯時如果報的其它類似找不到 B2 的錯誤也是把相應的 B2 改成 myboards 3c 44b0 來處理。

1 )其中的 myboards 3c 44b0.c 文件是板的初始化代碼,看一下就知道,根據你的板上自帶的 44binit.s

來修改吧。 memsetup.S 文件主要是存儲器的初始化設置,其實也是 44binit.s 裡面的一部分。
2 )其實 board 這裡要修改的不多,先跳過 flash 部分吧,我們來看一下 cpu 設置部分吧。
u-boot-1.1.2 裡面已經加入了對 s 3c 44b0 的支持,讓我們來看一下 cpu/s 3c 44b0 裡面的部分吧。
看到 start.S 這個文件了嗎?要修改的其實並不多,按照你的板設置一下中斷跳轉矢量就行了,或者上網查一下吧,應該很容易看明的。其中 cpu.c 這個 文件簡直不用修改,再來看一下 serial.c 這個文件吧,改一下波特率的設置就行,就是你用多少 M 的 CPU 頻率的話對應的波特率參數設置問題,其實 B2 已經做得不錯的了,很多子程序都不用自己寫的了 ^_^ ,在我的板上是這樣設置的 , 參考一下吧 :
#if CONFIG_S 3C 44B0_CLOCK_SPEED==66 ,把所有的這些 66 改成 60 ,原因,我的實驗板上用的頻率是 60 ( 44B0 最高頻率為 64M )。然後其它分頻係數,寄存器初始化設置,可以參考一下 44blib.c ,在這裡我給出我的設置出來吧,可以參考一下。

case 115200:
#if CONFIG_S 3C 44B0_CLOCK_SPEED==60
divisor = 32;

UFCON0 = 0x0;
ULCON0 = 0x03;
UCON0 = 0x245;
UBRDIV0 = divisor;

我在這方面算術不好,所以都是參考人家的。

3 )好,再加上個頭文件:
cd u-boot-1.1.2/include/configs
cp B2.h myboards 3c 44b0.h
這個頭文件其實要改的地方還挺多的,我等下再說怎樣修改。先回到 u-boot.1.1.2 目錄,

4 )在 Makefile 裡面加上這部分,不會的話就模仿 B2 來寫吧 ^_^
在 B2 的這部分文件
B2_config:unconfig
@./mkconfig $(@:_config=) arm s 3c 44b0 B2 dave
後面加上這部分:
myboards 3c 44b0_config:unconfig
@./mkconfig $(@:_config=) arm s 3c 44b0 myboard 3c 44b0 myboard

切記在 @./mkconfig $(@:_config=) arm s 3c 44b0 myboard 3c 44b0 myboard 前面的是 Tab 來的,萬萬不能用空格代替,因為它是靠這個來識別命令的!

5 )好,現在可以在 u-boot-1.1.2 目錄下執行如下命令:
Make distclean (還是用這個吧,比較徹底)
Make myboards 3c 44b0_config
Make
看看有沒有錯,有錯的話按著提示來改,如果沒錯的話應該就能生成 u-boot.bin 這個文件,現在還不能用哦,因為這幾是 B2 的一個仿製品而已(註:在我的機上到這一步可沒有報錯哦,你一步步按著來做的話應該也不會有什麼錯誤吧 ^_^ )。


6 )好,現在繼續修改 u-boot-1.1.2/include/configs/myboards 3c 44b0.h 這個文件。
#define CONFIG_INIT_CRITICAL1 這個在 cpu/s 3c 44b0/start.S 裡面用到,如果你的 u-boot 程序不是在 sdram 中調試而是固化到 flash 中運行的話,這個必不可少。
找到 #define CONFIG_B2 1 把 B2 改成 myboards 3c 44b0 吧(不然就不會編譯你的板了)
找到 #define CONFIG_S 3C 44B0_CLOCK_SPEED 75 你的 44b0x 應該沒有 75M 吧 我的是改成 60 的
找到 Size of malloc() pool 這部分設置,改成這樣吧,反正我是照著人家來做的,你自己研究下吧 ^_^ 。

#define CFG_MONITOR_LEN(256 * 1024)/* Reserve 256 kB for Monitor*/
#define CFG_ENV_SIZE (64*1024)/* 1024 bytes may be used for env vars*/
#define CFG_MALLOC_LEN(CFG_ENV_SIZE + 128*1024 )
#define CFG_GBL_DATA_SIZE128/* size in bytes reserved for initial data */
#define CFG_ENV_IS_IN_FLASH 1 這個必不可少,如果你想把你的參數保存到 flash 的話(有些板是保存到 EEPRAM 中去的,但是 s 3c 44b0 的話還是保存到 flash 吧)
#define CFG_ENV_ADDR(PHYS_FLASH_1+0x40000) 這個就是你的參數保存在 flash 裡的起始地址了
#define CFG_ENV_OFFSET0x40000 這個我後來看它源程序發現如果你上一步沒有設置它的起始地址的話就會用它來作默認地址的了
#define CONFIG_AUTO_COMPLETE

其它地方沒有深究哦,有些好像不要也行,你就試試吧。

找到 Hardware drivers 部分,這應該是網絡芯片設置吧,參考一下這個吧(要看芯片的):
#define CONFIG_DRIVER_RTL8019 這個就要看你的板上用的是什麼網卡了(這個是台灣出的,有 10M )
#define RTL8019_BASE0x06000000 這個是網卡相就寄存器的起始地址
以下部分我試過不要也行,你試下吧
#define RTL8019_BUS320
#define CONFIG_SMC_USE_16_BIT
#undef CONFIG_SHOW_ACTIVITY
#define CONFIG_NET_RETRY_COUNT10 應該是重試的次數吧

#define CONFIG_BAUDRATE115200 設置波特率

#define CONFIG_COMMANDS( CONFIG_CMD_DFL | \
CFG_CMD_DATE | \
CFG_CMD_ELF| \
CFG_CMD_NET | \

CFG_CMD_EEPROM| \
CFG_CMD_I 2C | \
CFG_CMD_FAT | \
CFG_CMD_JFFS2)
把 CFG_CMD_EEPROM 改成 CFG_CMD_FLASH 吧,雖然不改也是可以的,具體沒考究。

以下是板上 env 參數設置,看一下吧,其實我覺得瞭解一下就行的了,只是一些初始設置值,以後可以用命令 setenv saveenv 來修改的。
#define CONFIG_BOOTDELAY3 這個就是運行 bootcmd 之前的等待時間
#define CONFIG_BOOTARGS "devfs=mount root=ramfs console=ttyS0,115200" 引導 uClinux 的時候傳遞的參數,不會就先不用管它也行。
#define CONFIG_ETHADDR00:50:c2:1e:af:fb 網卡的物理地址 MAC
#define CONFIG_NETMASK 255.255.255.0 掩碼地址,設置過 ip 的人都應該知道吧
#define CONFIG_IPADDR 192.168.0.30 這是你板上網卡 8019 的 ip 地址
#define CONFIG_SERVERIP192.168.0.10 這是你宿主機的 ip 地址,以後用 tftp 下載的時候用到,一定要跟你的宿主機一致才行。
#define CONFIG_BOOTFILE"u-boot.bin" 這個就是你要下載文件的默認名字
#define CONFIG_BOOTCOMMAND"bootm 0x50000" 這是 bootdelay 後運行的命令

Miscellaneous configurable options 部分,參考一下吧:
#defineCFG_LONGHELP/* undef to save memory*/
#defineCFG_PROMPT"s 3c 44b0=>" 這是進入命令模式下的提示符,改個帥一點的吧
#defineCFG_CBSIZE256/* Console I/O Buffer Size*/
#defineCFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
#defineCFG_MAXARGS 100/* max number of command args*/
#define CFG_BARGSIZECFG_CBSIZE/* Boot Argument Buffer Size*/

#define CFG_MEMTEST_START 0x 0C 400000/* memtest works on*/
#define CFG_MEMTEST_END0x 0C 800000/* 4 ... 8 MB in DRAM*/
#undef CFG_CLKS_IN_HZ/* everything, incl board info, in Hz */
#defineCFG_LOAD_ADDR0x 0c 008000 默認的下載地址
#defineCFG_HZ1000/* 1 kHz */
#define CFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } 可供選擇的波特率

Physical Memory Map 部分,比較重要,修改你的 sdram 和 flash 的地址和容量。
#define CONFIG_NR_DRAM_BANKS1 我們只佔用了一個 Bank 用來映射 sdram
#define PHYS_SDRAM_10x 0c 000000 sdram 的起始地址
#define PHYS_SDRAM_1_SIZE0x00800000 sdram 的容量( 8M )
#define PHYS_FLASH_10x00000000 flash 的起始地址
#define PHYS_FLASH_SIZEflash 的容量( 2M )
#define CFG_FLASH_BASEPHYS_FLASH_1 定義多個名字而已,其它地方會用到

FLASH organization 部分,看註釋應該知道了吧,參考一下:
#define CFG_FLASH_ERASE_TOUT4120000/* Timeout for Flash Erase (in ms)*/
#define CFG_FLASH_WRITE_TOUT4000/* Timeout for Flash Write (in ms)*/

按著來一步步的做應該不難,這裡提一下 vi 程序的用法,其實在 google 一搜就找到了,不過為了方便大家,還是說一聲吧,
在命令模式下:
按 / xxx 再回車即可搜索到你所需要的內容( xxx ),再按 n 搜索下一個,按 shift+n 搜索上一個
按 :xxx 即可跟到你想要的行
按 :set nu 顯示行號
其它查書都可以找到就不說了。

做到這個時候,你可以再編譯一下,看有沒有錯,這一步我就沒有幫你們做了,不過我覺得應該不會有問題吧,下載到 ram 中運行,看看效果。

7 )終於到了 flash 的設置部分了,這完全是我個人悟出來的,網上資料好像講得不是先清楚。
首先介紹一下 flash 的識別吧,每塊 flash 都有一個 id ,前部分用來說明生產廠家,後部分用來說明它的容量,類型,位數等。它們的定義是在 u-boot-1.1.2/include/flash.h 中,就以我的 ssts9vf1601 為例:
#define SST_MANUFACT0x00BF00BF 這是生產廠家 id
#define SST_ID_xF16010x234B234B 這是它的型號,容量,位數等 id
#define FLASH_SST 160A 0x0046 這個我還說不清楚,有個要注意的問題是像 sst160 是不能用奇地址的,我做的過程中是把 SST 160A 改成 SST1601 的,懶得幫它創一個
好了,相信你已經找到你的板上所用的 flash 對應的 id 號了吧?現在就來談談怎麼改。
先進入 u-boot-1.1.2/board/myboards 3c 44b0/common/flash.c
它裡面已經幫 SST 160A 設置好了,我的做法是把 SST 公司的 160A 都改成 1601 ,是不是很簡單,當然你也可以幫 1601 再寫一分,但是我是個懶人,所以我就樣做了 ^_^

到這裡還有個問題沒提到的,就是如果你重新用 setenv saveenv 設置了參數,但是復位後會發現怎麼沒有保存到的(不信你試試看)。其實我是故意留到這裡講的,應該它不會報錯,可以說是比較隱秘的問題,所以我故意放到這裡來說,以引起你的重視。
解決方法: vi u-boot-1.1.2/board/myboard/common/flash.c
找到這個函數: write_buff
裡面有這句話: #ifdef CONFIG_B2
要把 B2 改了,因為我們的板不叫 B2 ,那叫什麼呢?原來是在這裡定義的: u-boot-1.1.2/include/configs/myboards 3c 44b0.h
裡面有這句話: #define CONFIG_HFRK 你不喜歡 HFRK 這個名字也行,可以改成別的名字,只不過相應地前面的 B2 也要改成這個名字而已。

4. 後記:
本來是想剛做好的時候寫的,但是後來發現有些功能實現不了,所以就停住了筆,等我搞好了以後,又急著去學習 uClinux 的移植,真的很忙,現在終於 抽空把它寫完。雖然有些地方還沒說清楚(畢竟我對它的瞭解還不是很深,但我相信在我以後移植系統的過程中會逐步加深對它的瞭解),我還是希望它能成為最詳 盡的 u-boot 移植新手指導,對 u-boot 移植的初學者起到實質性的作用,這樣就不枉我花了這麼多的心思來寫這個文檔。

參考資料:
http://blog.21ic.com/more.asp?name=sockit&id=8509
我所認為的最有奉獻精神,寫得最詳細的記錄,在此表示我深深的敬意!

沒有留言: