1. 程式人生 > >【轉】PowerPC DPAA平臺啟動方式

【轉】PowerPC DPAA平臺啟動方式

在Freescale DPAA QorIQ平臺上的啟動和non-DPAA QorIQ平臺的啟動有一些區別:

1.non-DPAA QorIQ平臺在上電時通過取樣配置管腳來決定對CPU的配置(P2020 ( e500核 ) 上電啟動及uboot流程|http://bbs.ednchina.com/BLOG_ARTICLE_1988662.HTM),而DPAA QorIQ平臺採用RCW (Reset ConfigurationWord)來決定對CPU的各種配置。

2. 在從SD Card/SPI flash啟動的時候,non-DPAA平臺是通過on-Chip ROM邏輯將U-Boot image拷貝到L2 SRAM中啟動,而從NAND flash啟動時,是將4K的啟動程式碼拷貝到eLBC FCM的RAM buffer中,該段程式碼負責將U-Boot image搬移到L2 SRAM中啟動;DPAA平臺是通過PBL(Pre-Boot Loader)邏輯將U-Boot image搬移的CPC SRAM中啟動。

大體啟動流程是這樣的:上電PBL會取樣cfg_rcw_src管腳來判斷RCW存放在那種儲存介質中,然後從相應的儲存裝置讀取RCW對CPU進行配置。如果是從NOR flash啟動,則不需要執行PBI command和拷貝U-Boot image到alternate配置空間,直接跳轉到0xFFFFFFFC處執行。如果不是從NOR flash啟動,在配置完畢CPU後會讀取PBI command完成部分初始化工作,然後根據PBI command中對alternate配置空間地址的配置將U-Boot image拷貝到alternate配置空間中開始執行。

1. RCW

RCW是存放在外部儲存裝置中的512bit的配置資訊,用來對CPU進行配置。和non-DPAA平臺中的配置管腳完成的功能是一樣的。當然RCW是存放在哪裡的?這個還是通過配置管腳來完成的。

在上電的時候,PBL首先會取樣cfg_rcw_src管腳來判斷RCW存放在那種儲存介質中,然後從相應的儲存介質讀取RCW來對CPU進行配置。那麼PBL是從哪裡開始讀取呢?下表列出了對不同介質PBL開始讀取的地址:

Interface

Starting Address

eLBC

0x00000000

I2C

0x00000000

eSPI

0x00000000

eSDHC

0x00001000

其中比較特殊的是Hard-coded RCW options. 如果選擇RCW為Hard-coded,那麼PBL不會去外部儲存裝置去讀取RCW而是使用預先定義好的RCW配置來對CPU進行配置。有以下兩個好處:

1. 如果儲存裝置介面有問題從而沒法儲存RCW,可以選擇使用Hard-coded啟動。

2. 如果使用者自己設定的RCW有問題導致系統沒法啟動,可以使用hard-coded RCW來啟動,啟動完成後可以恢復使用者自己設定的RCW。

RCW主要完成對CPU一些資源的配置,比如Core的頻率,serdes lane的使用,管腳複用的配置等等。對啟動來說應該關注以下幾個bit位的配置:

1. 選擇PBI資料來源的存放處,關於PBI的含義可以參考下面的PBL部分

2.Boot location的選擇

3. 從PCIe啟動時配置哪個PCIe controller為Agent模式

4.Secure boot模式

2. PBL

PBL(Pre-Boot Loader)用來輔助從I2C,SD,NAND flash,SPI flash啟動的一個硬體單元。主要功能是在上電之初首先配置以上介面的暫存器來對介面初始化,根據cfg_rcw_src管腳的配置從相應的介面讀取RCW和PBI命令,然後根據RCW來配置CPU,並執行PBI命令完成初始化操作,最後釋放CPU core跳轉到0xFFFFFFFC處執行第一條指令。

在釋放CPU core後,CPU core去哪兒執行第一條指令?這個是很關鍵的一點,會影響到U-Boot image的TEXT_BASE的設定,而且在non-DPAA平臺和DPAA平臺上的實現是不同的。在non-DPAA平臺上,若是從SD/SPI flash啟動,on-chip ROM將U-Boot image拷貝到L2 SRAM後,會跳轉到下面的控制字指定的地址去執行,我們知道CPU執行的第一條指令是存放到512K U-Boot image最後4個位元組的一條跳轉指令(bl start_e500),所以跳轉指令的地址(下面的”Execution Starting Address”)應該指向U-Boot的TEXT_BASE的最後4個位元組的地址。

如果是從NAND flash啟動,on-chip ROM會將4K的啟動程式碼拷貝到eLBC內部的RAM buffer,並將CPU釋放到0xFFFFFFFC出執行指令,所以從NAND啟動時的4K啟動到程式碼的TEXT_BASE是0xfffff000。

而在DPAA平臺上CPU core,只要不是從NOR flash啟動,PBL都會從相應的啟動裝置中拷貝RCW,執行PBI command,拷貝U-Boot image到CPC SRAM中(當然這個是PBI command指定的,下面會有詳細的介紹),並將CPU core釋放到到0xFFFFFFFC處執行第一條指令。

 
和non-DPAA平臺的on-chip ROM一樣,PBL也只能識別固定的資料格式,所以我們需要將RCW,PBI command(可選)封裝為PBL能夠識別的格式。Freescale提供了一套工具QCS來完成封裝的工作。

2.1 RCW的封裝

如果只是從NOR flash啟動,我們只需要RCW即可,下面是RCW的封裝格式:

SYS_ADDR地址是將n位元組的資料寫入的地址。SYS_ADDR是指向CCSRBAR空間或者alternate配置空間(ACS值決定)的地址。CCSRBAR空間比較好理解,那麼alternate配置空間指的是哪裡?該空間的高8位地址是多少?是由暫存器ALTCBARH/ALTCBARL/ALTCAR來決定的。

對於RCW DATA的SYS_ADDR來說就是CCSRBAR空間的device control and pincontrol block中的RCW狀態暫存器(RCWSR[1-16]=64B),即:

fe_000000+ 0x0E_0000 + 0x100

2.2 RCW+PBI的封裝

如果需要PBI command,比如配置CPC cache為SRAM,建立相應的LAW,配置alternate配置空間或者將U-Boot image拷貝到CPC SRAM等,都是通過

PBI command的設定完成的。

3. Boot from SD/NAND flash/SPI flash

3.1 程式碼解析

首先PBI command會做下面的初始化工作:

1. Invalidateand flush CPC cache

2. 將CPC SRAM配置為SRAM,地址為0xfff00000

3. 給CPC SRAM配置一個LAW entry(LAW16)

4. 配置alternate 配置空間,用來指示PBL將U-Boot image拷貝到CPC SRAM的0xfff80000開始的512K

5. 重新配置SPI controller的暫存器提高傳輸速率。PBL本身會配置各個介面的暫存器的,但SPI介面配置的速率比較低,傳輸U-Boot image花費的時間比較長,所有重新配置從而提高傳輸速率

下面是P4080DS的PBI command,從下面的command可以看出,CPC cache配置為SRAM,地址為0xfff0000,大小為1M,PBL將U-Boot iamge拷貝到0xfff80000開始

的地方。

下面是U-Boot image封裝為PBI data的結構。

0x81f8000000的解析:

0x81 = 1000 0001 => ACS=1,CNT=1

F80000 => 指定alternate配置空間的低24位

然後在boards.cfg檔案中新增對Boot from NAND的支援,並設定CONFIG_SYS_TEXT_BASE 為0xfff80000

  1. "boards.cfg"  

  2. P5020DS_NAND                 powerpc     mpc85xx     corenet_ds          freescale      -           P5020DS:RAMBOOT_PBL,NAND,SYS_TEXT_BASE=0xFFF80000  

  3. "include/configs/corenet_ds.h"  

  4. #ifdef CONFIG_RAMBOOT_PBL  

  5. #define CONFIG_RAMBOOT_TEXT_BASE        CONFIG_SYS_TEXT_BASE  

  6. #define CONFIG_RESET_VECTOR_ADDRESS     0xfffffffc  

  7. #endif  

  8. #define CONFIG_SYS_INIT_L3_ADDR         0xfff80000  

  9. #define CONFIG_SYS_INIT_L3_ADDR_PHYS    CONFIG_SYS_INIT_L3_ADDR  

  10. #define CONFIG_SYS_L3_SIZE              (1024 << 10)  

  11. #define CONFIG_SYS_INIT_L3_END (CONFIG_SYS_INIT_L3_ADDR + CONFIG_SYS_L3_SIZE)  

配置CPC SRAM需要的TLB表項

  1. "board/freescale/common/p_corenet/tlb.c"  

  2. struct fsl_e_tlb_entry tlb_table[] = {  

  3. #if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L3_ADDR)  

  4.         SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR,  

  5.                         MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  

  6.                         0, 0, BOOKE_PAGESZ_1M, 1),  

  7. #else  

  8.         SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000,  

  9.                       MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,  

  10.                       0, 0, BOOKE_PAGESZ_4K, 1),  

  11. #endif  

  12. <p>會對齊到1M,即0xfff80000 -> 0xfff00000,目的是在跳轉到AS0時, 還有TLB entry覆蓋對L3 SRAM,因為此時程式碼是在L3中存放的,還沒有relocate到DDR。</p><p></p><p>init_tlbs會執行上面的TLB entry</p><p>_start-> cpu_init_early_f &ndash;> init_tlbs run in AS=1</p>  

在invalidate CPC cache的時候,判斷是否作為SRAM,若為SRAM則不invalidate, 因為程式碼還是在L3 SRAM中,若此時invalidateCPC SRAM,則執行的U-Boot程式碼也會被清掉。

  1. "arch/powerpc/cpu/mpc85xx/cpu_init.c"  

  2. _start_cont -> cpu_init_f -> invalidate_cpc  

  3. void invalidate_cpc(void)  

  4. {  

  5.         int i;  

  6.         cpc_corenet_t *cpc = (cpc_corenet_t *)CONFIG_SYS_FSL_CPC_ADDR;  

  7.         for (i = 0; i < CONFIG_SYS_NUM_CPC; i++, cpc++) {  

  8.                 if (in_be32(&cpc->cpcsrcr0) & CPC_SRCR0_SRAMEN)  

  9.                         continue;  

  10.                 out_be32(&cpc->cpccsr0, CPC_CSR0_FI | CPC_CSR0_LFC);  

  11.                 while (in_be32(&cpc->cpccsr0) & (CPC_CSR0_FI | CPC_CSR0_LFC))  

  12.                         ;  

  13.         }  

  14. }  

在使能CPC cache時,disable PBI command為CPC SRAM配置的LAW16

  1. "arch/powerpc/cpu/mpc85xx/cpu_init.c"  

  2. Relocate to RAM -> board_init_r -> cpu_init_r -> enable_cpc  

  3. static void enable_cpc(void)  

  4. {  

  5.         cpc_corenet_t *cpc = (cpc_corenet_t *)CONFIG_SYS_FSL_CPC_ADDR;  

  6.         for (i = 0; i < CONFIG_SYS_NUM_CPC; i++, cpc++) {  

  7.                 u32 cpccfg0 = in_be32(&cpc->cpccfg0);  

  8.                 size += CPC_CFG0_SZ_K(cpccfg0);  

  9. #ifdef CONFIG_RAMBOOT_PBL  

  10.                 if (in_be32(&cpc->cpcsrcr0) & CPC_SRCR0_SRAMEN) {  

  11.                         struct law_entry law = find_law(CONFIG_SYS_INIT_L3_ADDR);  

  12.                         if (law.index == -1) {  

  13.                                 printf("\nFatal error happened\n");  

  14.                                 return;  

  15.                         }  

  16.                         disable_law(law.index);  

  17.                         clrbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_CDQ_SPEC_DIS);  

  18.                         out_be32(&cpc->cpccsr0, 0);  

  19.                         out_be32(&cpc->cpcsrcr0, 0);  

  20.                 }  

  21. #endif  

  22.                 out_be32(&cpc->cpccsr0, CPC_CSR0_CE | CPC_CSR0_PE);  

  23.                 in_be32(&cpc->cpccsr0);  

  24.         }  

  25. }  


3.2 啟動image的製作

Freescale的SDK release中用相應的步驟,請參見下面的連結,這裡不贅述。

4. Open source上的patch