U-boot原廠版本移植流程
今天開始移植三星原廠的U-boot,做一下筆記,以備日後所需
移植的時候有一點感想,就是最好別注釋掉不對的源碼,定義的地方千萬別動,盡量修改調用的地方,這樣可以極大的避免出錯
1. 先燒錄看現象
先燒到板子裡試試看,看看有什麼現象,再做分析
解壓源碼後,先看看Makefile中的交叉編譯工具鏈有沒有問題。根據 U-boot配置及編譯階段流程宏觀分析可知,交叉編譯工具鏈配置在主Makefile的前端。查看後發現裡面的工具鏈和我裝的一樣,沒有問題
正式開始編譯之前需要配置,那麼Makefile中關於配置的偽目標是什麼呢?根據 U-boot配置及編譯階段流程宏觀分析可知,偽目標在主Makefile的非常後面,而且名字應該是開發板的名字。但是問題來了,三星原廠的評估板叫smdkv210,但是Makefile後面的偽目標有5個名字差不多的,這樣的話,相應的.h文件也有5個…..怎麼辦?
先不管了,選第一個吧,第一個名字看上去最正常,那以後頭文件就要選smdkv210single.h了….然後開始配置階段了,輸入make smdkv210single_config
配置完之後直接make,發現並沒有報錯,編譯一切順利
燒錄前,先看看燒錄腳本有沒有錯,打開sd_fusing目錄下的sd_fusing.sh,重點關注
這兩行,確定BL1和U-boot整體的燒錄扇區無誤,其中,U-boot的燒錄扇區由smdkv210single.h中的宏MOVI_BL2_POS指定。然後保險起見,防止原廠編譯出來的sd_fdisk不能用,先在sd_fusing目錄make clean一下,再make,得到全新的sd_fdisk。最後執行 ./sd_fusing.sh /dev/sdb 燒錄一切順利
插入SD卡,開機,發現
,此外,開發板供電鎖存成功了
根據現象分析可知,我們並不能證明SD卡中U-boot徹底失敗,因為SD卡正常引導的時候也會輸出SD checksum Error,因為x210這塊板開機後inand通道的檢測優先級是大於SD卡所在的通道的所以這句話指的是inand中校驗失敗。此外本應在lowlevel_init中最先打印的”OK“卻沒有正常打印,但是lowlevel_init中的供電鎖存卻成功了
所以得出結論,可能有兩種情況:
1.程序在供電鎖存和打印”OK”之間的某處掛掉了;2.串口進行了錯誤的初始化(可能性不大,因為BL0中初始化過了)2.解決串口的問題
由於串口打印對於調試非常重要,所以重點先要把串口問題解決
根據之前分析,先去lowlevel_init中檢查串口的初始化是否正確,結果發現串口的寄存器設置完全符合我們板子,所以能排除掉串口初始化錯誤的可能性了
如果原廠的選用的串口不是我們板子上的串口,那麼就需要修改了,一般來說,選用哪一個串口還是使用宏定義來決定的,通常沒有硬編碼,以210為例,只需要將smdkv210single.h中 #define CONFIG_SERIAL3 改為需要的串口即可
然後檢查供電鎖存和打印”OK”之間的代碼
發現問題會在 PMIC、時鐘、內存初始化中。由於時鐘是SOC內部的,和板級無關,故不會有問題。同樣,lowlevel_init中的代碼還沒重定位,用不到DDR,故也不會有問題。那麼問題可能出在設置PMIC中。另外此處也可以利用連續點燈定位bootloader的錯誤這個方法定位錯誤
查資料可知, PMIC是一種電源管理芯片,而我們板子上沒用到;再看看PMIC_InitIp這個函數,發現裡面都是I2C的通信代碼….果然是在這裡掛掉了….由於我們沒有用PMIC,I2C的通信便會失敗,一直處在某一個while(1)中
燒錄,嘗試,發現整個U-boot居然啟動起來了,但是裡面的初始化有挺多的錯誤
可知,DRAM、SD、網卡、fastboot之類的全部有問題,接下來開始根據U-boot初始化階段流程的順序來整改
3.檢查供電鎖存、時鐘、內存、串口配置
這幾部分的初始化都在lowlevel_init中
關於供電鎖存,由現象可知並沒有問題
關於時鐘,由U-boot打印信息可知,沒有問題。不過如果要修改的話,直接改smdkv210single.h中的宏即可,無需修改代碼
關於內存,由U-boot打印信息可知,內存大小是有問題的,板子上只有512M(每片256,一片位於0x20000000,一片位於0x40000000),打印出來總共卻有1G。那麼內存本身的初始化(即時序、驅動強度等)有沒有問題呢?輸入md命令查看內存信息
發現內存可以正常工作,則內存本身的初始化(即時序、驅動強度等)是正確的,錯誤是在內存的部署上面。那麼進入smdkv210single.h修改DDR相關的宏
將SDRAM_BANK_SIZE(單片SDRAM大小) 改為0x10000000 ,即256MB。改為再檢查檢查後面幾行,SDRAM1起始物理地址是正確的;單片SDRAM大小也是正確的;但是,SDRAM2的物理地址是有問題的,其值為MEMORY_BASE_ADDRESS + SDRAM_BANK_SIZE,即SDRAM1起始物理地址加上單片SDRAM的大小,這樣算下來就不對了。我們根據板子上的部署,將其改成0x40000000
上電後,發現打印出來的DDR相關的設置都正確了~
關於串口,由現象可知並沒有問題
4.檢查虛擬地址映射
默認的原廠U-boot的虛擬地址映射是不用改的,除非修改了內存從部署和配置
(可選步驟)接下來嘗試修改內存的部署和配置,把內存的部署改為0x30000000~0x4FFFFFFF,目的是為了熟悉並演示修改U-boot的參數的流程。首先,我們假設原廠的代碼寫的都挺好的,不存在硬編碼,那麼只需要修改smdkv210single.h內的宏即可。進入查看和內存有關的宏,首先根據條件編譯確定了我們使用的宏為
分析可知,內存本身的初始化(即時序、驅動強度等)應該不用改,需要改的是DMC0控制器的起始位置,仔細查詢寄存器可知,只需修改DMC0_MEMCONFIG_0 值為 0x30F01323;此外,還需修改MEMORY_BASE_ADDRESS 值為 0x30000000,這個宏被引用了多次,指導了很多代碼的運行。
然後來檢查和內存有關的虛擬地址映射表,進入lowlevel_init
發現0xc0000000被映射到了0x20000000,而我們內存的起始地址為0x30000000,故把第一行改為.set __base,0x300即可
此外,還需要檢查一下smdkv210single.h內有關虛擬地址的宏,發現
看來必須要修改這個虛擬地址轉換為物理地址的函數,定位後發現
這個函數寫的也是無語,居然硬編碼…..我們直接把0x20000000改成0x30000000即可…..
上電,發現修改成功
5.檢查MMC配置
由U-boot打印信息可知,mmc的配置是有問題的
但是由於mmc的初始化利用了linux的驅動,比較龐大,排查起來較為不便。所以,U-boot的打印信息是定位問題的關鍵,我們可以利用編輯器的搜索功能來搜索打印信息中的關鍵字。
我們在源碼中搜索 EXT_CSD,在此我用了slickedit的搜素功能,操作如下
搜索可得結果在mmc.c中
由此定位了錯誤之所在,但是還是不明白發生了什麼……
先觀察這幾句的上下文,發現整個函數是在讀取所謂的“拓展CSD寄存器”,從拓展CSD寄存器讀取到了mmc的版本號信息,但是版本號大於5,就導致了程序錯誤並退出。問題的根節就在於我們用的mmc太新式,而這個U-boot並不認得太新潮的mmc……
解決之道只有兩種,要麼換mmc,要麼強行改代碼。換mmc不現實,至於怎麼改,因為太難,就只能上網查了。上網查了之後發現解決方法倒是很簡單,直接把判斷的數字5改為8,跳過這個錯誤即可。修改,上電,測試,發現確實解決了這個問題
問題解決了,但還有一個問題,此處U-boot初始化的是接在通道0的inand還是接在通道1的SD卡呢?其實還是函數int mmc_initialize(bd_t *bis)初始化的時候 有一句代碼:mmc = find_mmc_device(0); 所指定的,故此處初始化的不是SD而是inand,並且我們可以通過把0改成1來改為初始化SD卡
6.檢查環境變量配置
首先,在U-boot命令行下嘗試環境變量的設置,設置後發現能斷電保存,說明環境變量功能成功,但是我們還是要檢查一下,環境變量存放的扇區是否安全,會不會和其他內容發生沖突
關於環境變量分區的檢查,以及默認環境變量的修改詳見U-boot對啟動介質的空間分配
7.檢查網卡配置
根據U-boot打印信息可知,網卡初始化顯然是失敗的。由於網卡驅動是從linux驅動拿過來的,所以無需修改,只需要確保U-boot中網卡初始化成功即可。
關於這個網卡,其實是通過s5pv210的SROM接口來直接掛載在總線上的,所謂的SROM接口其實是一種對外部開放總線的方式,通過這個接口,網卡芯片內的寄存器可以直接通過總線訪問,對於程序員來說就仿佛在訪問SOC內部的SFR,網卡芯片與SOC直接的通信過程就可以不用關心了。簡而言之,這個網卡芯片就像集成在SOC內部一樣。s5pv210的內存映射表有關SROM的部分:
接下來看看我們板子上網卡的具體接法:
首先,要清楚一點,dm9000的地址接口和數據接口是復用的!CMD接在了ADDR2(一根地址總線),當CMD為1時data0-data15傳輸的是數據,而當CMD為0時傳輸的是地址,也就是說,如果要訪問dm9000的寄存器,data0-data15要先傳輸地址再傳輸數據。由接口data0-data15可知,SROM接口使用了16位寬度。由接口CSn1可知,網卡接了SROM的bank1的片選腳,所以網卡處在SROM的bank1。
關於網卡的初始化,具體是在U-boot初始化第二階段的board_init函數中,裡面有調用網卡初始化函數(和SROM接口有關),我們板子上的網卡是dm9000,所以真正的初始化函數是dm9000_pre_init,我們需要檢查
1.初始化函數
2.smdkv210single.h中網卡相關的宏定義
具體修改需要根據網卡芯片的接法(SROM接口)來定,以x210為例,板載的是dm9000,先來看看原廠代碼的初始化流程
上來先根據宏來配置SROM_BW_REG,查手冊得知SROM_BW寄存器主要負責各個bank的數據總線的寬度設置,不同的位分別設置不同的bank,由於定義了宏DM9000_16BIT_DATA,故此寄存器配置為16位模式,並且配置的是bank5,byteenable位設置成0(不使用UB/LB),waitenable位設成0(禁止等待),addrmode設為0(半字對齊)。我們修改為bank1,此外,原廠的很多設置都是有問題的,必須修改為byteenable位設置成1(使用UB/LB),waitenable位設成1(使能等待),addrmode設為1(字節對齊),至於這些參數到底怎麼選擇,其實都是一些約定俗成的套路,特別是dm9000作為一款歷史悠久的老芯片,很多設置的方法都已經固化了,通過網絡可以很輕松查到。綜上所述,我們把代碼修改為:SROM_BW_REG &= ~(0xf << 4); SROM_BW_REG |= (0<<7) | (0<<6) | (0<<5) | (1<<4);
隨後原廠設置了SROM_BC5_REG,查手冊得知SROM_BC*寄存器負責第*個bank的控制,寄存器的內容本身倒是不用改,只需把SROM_BC5_REG改為SROM_BC1_REG即可。
最後原廠配置了MP01CON_REG這個寄存器,利用了臨時變量tmp先讀後改,這個寄存器其實就是配置了引腳MP01,原廠將其設為復用功能————SROM接口中的bank5片選引腳,而我們應將其改為bank1片選引腳,查詢手冊後,將其改為tmp &=~(0xf<<4); tmp |=(2<<4);
接下來看看smdkv210single.h中相關宏定義:
由s5pv210的內存映射表可知,宏 CONFIG_DM9000_BASE將dm9000地址接口的基地址設置在了bank5(0xA8000000),我們應將其改為bank1,根據內存映射理論上是0x88000000但此處有坑,很玄學,居然有可能不工作,需要改成0x88000300才行,至於原因的話網上眾說紛纭,一種比較合理的說法是:DM9000有不同的版本,其中有的內部自帶0x300的偏移量…故只用bank的基地址是不行的,需要加上0x300。接下來看後面,DM9000_DATA(數據接口)的地址應改為CONFIG_DM9000_BASE+4,這是因為CMD接在了ADDR2(地址總線),當CMD為1時data0-data15傳輸的是數據,而當CMD為0時傳輸的是地址。修改後上電,測試,發現網卡成功運行,可以ping通主機
8.檢查內核引導部分
當前U-boot還無法啟動內核,但是首先需要確定到底是U-boot的問題還是kernel的問題,如果手頭存在著其他確定正確的U-boot或者kernel,那麼就有可能排除掉一種情況。但是一般來說,手頭是沒有這個條件的,那麼就需要多方位的去診斷
首先,在U-boot命令行設置正確的環境變量bootcmd和bootargs,具體詳見 U-boot引導內核流程分析 ,設置完發現無法啟動
接著,試試看使用tftp導入內核鏡像至內存,發現仍然無法啟動
根據 U-boot引導內核流程分析 末尾的論述,我們來做基本的檢測,首先懷疑機器碼不對,此處要對比U-boot和kernel源碼中的機器碼,U-boot的部分在smdkv210single.h中的#define
MACH_TYPE,對比kernel源碼中的機器碼發現相同,說明機器碼沒問題。再來看看和傳參有關的宏是否正確定義,發現好像#define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_CMDLINE_TAG #define CONFIG_INITRD_TAG 這三個宏沒有定義,定義完之後上電發現能夠正常運行
至此,整個移植過程正式結束,總體來說,原廠的U-boot需要修改的地方不是很多