Qc片子的啟動是比較九曲十八灣的,從QCPBL,到QCSBL,再到OEMSBL,最後到啟動android的USBloader。在這裡我的版本是Android1.6 donut,Google在後面的版本中加入了LK,不過對於在bootloader中加入Splashscreen道理都是一樣的。開始沒有在OEMbootloader添加主要是因為OEMbootloader不方便打log,不好調試,所以先在USBloader中實現以後再移植到QCSBL中去。
從道理上來說,要想實現開機畫面在邏輯上是比較簡單的,把MDP和LCDC跑起來,然後把panel初始化,最後往buffer上扔上你需要顯示的資料就行了。不過在實現上還是需要下一番功夫的,主要是要對硬體功能需要一定瞭解,整理一下達到這個目標需要完成的工作:
1)首先是要在bootlaoder中添加,所以對bootloader是需要一定瞭解的,在bootloader跑到哪部分的時候點屏是比較合適的。這裡要考慮的時bootloader跑到哪了我們需要的一些API都可以使用了,說穿了就是那些東西初始化可以使用了我們就可以點屏了。
2)然後就MDP和LCDC要跑起來,要瞭解讓這兩個晶片工作起來必須做什麼操作。這個一般需要參考QC的代碼,因為畢竟我們不是很瞭解晶片,除了時鐘之外,那麼一大堆寄存器哪些是需要初始化的,哪些是不需要的我們並不清楚。
3)最然後就是panel的初始化。這裡主要的區別是使用的非同步屏還是同步屏的問題,這裡我們使用的是SPI-RGB的同步屏,SPI的初始化我們使用GPIO類比,這裡一個最重要的問題就是我們如何在bootloader中操縱GPIO。
4)最後就是我們需要顯示的資料了,一般有兩種方法,一個就是將需要顯示的圖片位元據寫入數組,另外就是將要顯示的圖片放入nand分區裡面。
瞭解了需要完成的工作之後下面就是各個擊破~~首先說說bootloader,主晶片上電以後,reset之後供上時鐘,然後就會跳到rom上一段特定的地址開始執行代碼,這裡就是QCPBL了,QCSBL會掉用CONFIG_DATA的資料來初始化RAM和NAND,然後將QCSBL載入ram中執行,QCSBL會將OEMSBL當成動態連結程式庫載入,然後OEMSBL會將USBloader載入記憶體,並reset ARM11,這樣ARM11就開始執行USBLoader。再然後ARM9會將AMSS載入記憶體,載入以後會通知ARM11載入linux kernel,最後兩個核上的系統就都跑起來了。
我們來重點關注一下USBloader,基本上bootloader都是一個形式,首先一段init.s或者start.s之類的彙編用來設定ARM的一些寄存器,比如設定堆棧指標R13,PC指標R14,並使用R1-R3儲存一些參數。彙編執行完以後會blx到bootloader的main或者start之類的函數開始執行。其實bootloader的代碼還是比較好看的,畢竟是單線程一路跑下來,比起camera那動不動開3個線程互動的東西好看多了。main裡面一般都是初始化RAM,NAND,設定一些時鐘,並初始化一些必要的驅動,然後將kernel從NAND中讀出來放入RAM,最後將控制權交給kernel。因為USBloader不需要進行RAM的初始化,主要是進行時鐘,NAND分區表的一些設定,這裡很簡答的,我們的Splash screen就可以放在時鐘設定以及板級初始化的後面。
瞭解完啟動過程之後我們再來看MDP和LCDC,要讓這兩個東西跑起來,一般就是power和時鐘的enable,然後就是相關寄存器的初始化。在這裡我參考了QC的MDP和LCDC driver的代碼,但對於寄存器的設定還是必須要QC支援的,我們不瞭解晶片,不可能對每個寄存器都設一遍值。在這裡稍微描述一下需要賦值的寄存器,影像處理器一般是相通的,一般瞭解以後對以後其他的晶片也有參考作用。
比較重要的有DMA buffer的地址,buffer的RGB資料類型,buffer的大小,對齊等等和FB相關的寄存器,然後就是關於LCDC訊號極性的一些寄存器,再然後就是LCDC HSYNC VSYNC之類的一些寄存器,比如start,end之類的,還有一個重要的就是PCLK的rate。基本上enable MDP和LCDC的時鐘以後,設定好這些寄存器,晶片就能正確發送資料了,如果有問題,那。。。那再慢慢DEBUG吧~~我開始的時候就是PCLK的rate沒設,導致映像怎麼都不對啊~~
最後就是我們的PANEL的初始化了。panel的初始化最重要的一點就是GPIO的使用,因為我們現在使用的是雙核,而對GPIO的設定實際上在ARM9上,要在ARM11上設定GPIO具體許可權問題。在這裡,USBloader通過寫GPIO的shadow寄存器來控制GPIO,這裡有一個特別注意的是必須將GPIO的許可權賦給ARM11,不然寫shadow寄存器是不管用的。知道怎麼操作GPIO那麼初始化的過程就簡單了。
在這裡有個同步屏和非同步屏的區別,同步屏本身內部不具備產生時序的電路,所有的時序都必須由MPU來提供,而且它不具備LCDC控制器,所以屏的data必須保證在一個重新整理頻率。而非同步屏具有自己的LCDC控制器,不需要主晶片的LCDC,要讓它顯示圖片只需要一個更新就可以了,不需要不停地提供訊號。
那麼現在屏就開始正常工作了,我們最後看一看如何要顯示我們的圖片。要顯示圖片,只要將RGB資料放入buffer中,DMA就會將資料送給panel顯示了。所以data的資料類型必須和寄存器的設定相匹配。在這裡我是使用數組的方法來儲存要顯示的資料,當然也可以讀取分區表裡面的類容。一般來說Splash screen都是raw data資料經過遊程編碼產生的*。rle檔案,下面介紹下如何獲得我們需要的像素數組:
首先使用imagemagic提供的covert命令將PNG圖片轉成rawdata,命令是:convert *.png -depth 8 rgb:*.raw 然後使用android提供的RGB2565命令將資料轉成rle格式,rgb2565 -rle <*.raw> *.rle 最後使用xxd -i *.rle > initlogo.h將rle檔案轉化成數組。這裡有一個要特別注意的是使用xxd獲得的數組是unsigned char型,而rle檔案都是short格式儲存的,這樣就需要將兩個char合成一個short,因為x86上的linux是使用litte-edian來儲存資料,所以合并的時候要注意高位實際上是在後的。這裡要特別注意,我開始就因為沒注意,結果映像出來總不對。
基本上就是這些了~~ 以後再想到啥再補充~~