高通 MSM8K bootloader之一: SBL1

MSM8K Boot Flow 

                              圖1:html

 

高通MSM8K平臺bootloader啓動流程基本相似,但具體各平臺,好比MSM897四、MSM891六、MSM8994等,會有微小區別。app

 

從上圖,能夠看出高通8K平臺的boot過程很是不通常啊。相比MTK平臺,或者高通7K平臺,複雜了很是多。 下圖是高通文檔對啓動流程的說明,函數

已經很清楚了,我這邊就直接貼出來啦。ui

                                   圖2:.net

系統上電後從RPM PBL啓動到 APPS PBL 而後SBL1 ,再啓動APPSBL 等等,整個過程看似很是複雜,但其實不少代碼OEM廠家是看不到,也修改不了的。debug

那咱們須要咱們作什麼? 能作點什麼呢? 呵呵!不會沒事情作的。 SBL1和appsbl高通是有開放代碼。調試

 

本章我重點關注SBL1,且主要描述我認爲重點的幾方面:code

1、    CDT : Platform ID和DDR參數 orm

2、 debug log :xml

3、 download : msm8K 新平臺軟件download支持兩種協議,sahara和firehose

4、 ramdump :死機異常信息dump

 

好的,下面將SBL1我比較關注的點調用流程總結成以下圖,後面再針對關注點展開,逐個分析。

 

                           圖3:

 

2、CDT:Platform ID和DDR參數 

一、CDT(Configuration Data Table ) 裏到底有什麼內容?

   參考下圖,可知CDT包含CDB0: platform info信息和CDB1: DDR配置參數。
 
                 圖4:
 
   platform info 包含 平臺id,主板的版本號,項目號等信息
          圖5:
 
CDB0: platform info 以下結構體表現:
typedef PACKED struct
{
  uint8                 nVersion;
  uint8                 nPlatform;      //這個是平臺id,用於高通不一樣平臺類型。咱們不能去修改。
  uint8                 nHWVersionMajor;   //硬件版本號暫時沒有使用,默認爲0
  uint8                 nHWVersionMinor;
  uint8                 nSubtype;    // 默認爲0沒有用。咱們能夠用它來作項目區分   
  uint8                 nNumKVPS;
  PlatformInfoKVPSCDTType  aKVPS[];
} PlatformInfoCDTType;
 

參考以下文檔和code:
80-N3411-1_B_EEPROM_SW_CDT.pdf
boot_images/core/boot/secboot3/hw/msm8916/boot_cdt_array.c

boot_images/core/systemdrivers/platforminfo/src/PlatformInfo.c

boot_images/core/boot/secboot3/scripts/cdt_generator.py

boot_images/core/boot/secboot3/scripts/jedec_lpddr3_single_channel.xml

 

二、CDB0: platform info信息有什麼用處?

 

 上圖3能夠看到CDB0: platform info相關的代碼調用有以下二函數:

voidboot_config_data_table_init(bl_shared_data_type* bl_shared_data)
{
  boot_log_message("boot_config_data_table_init, Start");
  boot_log_start_timer();
  
  /*populate configuration data table's info*/
  config_data_table_info.size = config_data_table_size;
  config_data_table_info.cdt_ptr = config_data_table;
   //get default config_data_table array from boot_cdt_array.c

  boot_update_config_data_table(&config_data_table_info);
  //read the cdt from eMMC and update the default config_data_table array


  /*put a pointer to the table info into sbl shared data so next sbl can access it*/
  bl_shared_data->sbl_shared_data->config_data_table_info = &config_data_table_info;
  
  boot_log_stop_timer("boot_config_data_table_init, Delta");
}  //該函數獲取到cdt,並存放在config_data_table_info


void sbl1_hw_platform_smem(bl_shared_data_type* bl_shared_data)
{
    .......

    if (eResult == DAL_SUCCESS) 
    {
      /*call the following API to store the platform id to DAL and SMEM*/
      boot_DalPlatformInfo_CDTConfigPostDDR(phPlatform, platform_id_cdb_ptr);

      //調用 PlatformInfo.c 中的PlatformInfo_InitSMem保存platform info 到smem.
      boot_DAL_DeviceDetach(phPlatform);
    }
  }
  
}/* sbl1_hw_platform_smem() */

//好了

static DALResultPlatformInfo_InitSMem
(
  PlatformInfoDrvCtxt *pDrvCtxt
)
{
   //申請共享內存區:SMEM_HW_SW_BUILD_ID
  pSMem = (DalPlatformInfoSMemType *)
    smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(DalPlatformInfoSMemType));
   ...............

 //保存platform info到共享內存
  pSMem->ePlatformType = pDrvCtxt->PlatformInfo.platform;
  pSMem->nPlatformVersion = pDrvCtxt->PlatformInfo.version;
  pSMem->nPlatformSubtype = pDrvCtxt->PlatformInfo.subtype;
  pSMem->bFusion = pDrvCtxt->PlatformInfo.fusion;
   .................

  return DAL_SUCCESS;

} /* END PlatformInfo_InitSMem */

 

花了這麼多精力談如何存platform info,得用啊?這些platform info在lk和kernel有何用呢?

 

lk 根據platform id及subtype id匹配正確的dts,這樣後面kernel也能夠利用dts裏的

platform info。

注:msm8916-mtp.dts 包含以下platform id & subtype id信息。

{
model = "Qualcomm Technologies, Inc. MSM 8916 MTP xxx";
compatible = "qcom,msm8916-mtp", "qcom,msm8916", "qcom,mtp", "qcom,xxxx";
qcom,board-id = <8 0x21>;   //platform id & subtype id
};

 

lk請參考這些函數,後面專門研究lk,再詳細描述。

platform_detect   //board.c , smem.h : enum platform_subtype 

board_hardware_subtype //board.c , smem.h : enum platform_subtype 

board_hardware_id   //board.c , smem.h : enum platform_subtype 

dev_tree_get_entry_info  //dev_tree.c

kernel請參考setup.c

 

從上面CDT格式及代碼分析,能夠看出,若是不一樣項目cdt的nPlatform和nSubtype項配置成不一樣的值, 與dts 包含的platform id & subtype id信息進行匹配。就能夠用來區分不一樣的項目。

即:咱們在項目開發過程當中,同一個分支代碼要進行多項目開發時,

sbl、lk、kernel能夠利用這些信息來區分不一樣項目,實現一套代碼多項目配置目標。以下圖:

 

   圖6:

 

總結:經過修改cdt和dts,sbl、lk、kernel階段使用以下接口,能夠將同一個branch代碼中多項目區分出來!

sbl_board_subtype      // sbl高通沒有,本身開發一個接口

board_hardware_subtype   // lk接口

of_board_is_xxx     // kernel 接口

 

三、CDB1:DDR參數的配置流程?

 

cdt中還有一項重要內容是CDB1: DDR參數,下面看看如何利用這些參數進行ddr初始化的。

ddr初始化涉及以下重要三函數:

boot_procedure_func_type load_qsee_pre_procs[] = 
{
  .......
  /* Copy the configure data table from eeprom */
  boot_config_data_table_init
  .......
  /* Configure ddr parameters based on eeprom CDT table data. */
  sbl1_ddr_set_params,   //  保存cdt ddr 參數到底層
  /* Initialize DDR */
  (boot_procedure_func_type)sbl1_ddr_init,    //初始化ddr
   .......

  /* Last entry in the table. */
  NULL 
};

 

下面重點介紹這三個函數:

     圖7:

 cdt數據 config_data_table保存到config_data_table_info.cdt_ptr

      圖8:

sbl1_ddr_set_params調用ddr_set_params,將ddr參數保存到ddr_device_table。

獲取num_of_device保存到ddr_device_table_entry_num 。

 

   圖9:

 

sbl1_ddr_init 經過 HAL_SDRAM_Init調用到以下函數,

HAL_SDRAM_Ram_Rank_Detection,========》cs auto detect 

HAL_SDRAM_Ram_Size_Detection, =========> ram size auto detect by :row、col、bank、width , manufacture_id

ddr_params_detection , ========》 two DDR chips auto detect 

HAL_SDRAM_DPE_Update_AC_Paramenters  =========> update ddr timing with new DDR timing

 

 上圖說明,經過ddr_params_detection 實現一個項目自動支持多種ddr timing的方法。

 

好了,ddr timing就再也不多說了,詳細請閱讀代碼及參考文檔:

80-NJ172-1_A_LPDDR2_CUSTOMIZATION_FOR_MSM8x26_DEVICES.pdf

 

3、Debug log

坑跌的高通,MSM6K/7K平臺,包括舊的MSM8K平臺bootloader都不支持uart。
須要本身添加uart debug log,不然只能鏈接jtag接口,使用Trace32調試。
哎,Trace32那價錢,咱這貧民企,都調試不起啦。
 
高通也賺了夠多的,總算有良心,在MSM8916平臺默認支持uart啦!
 
好了,不罵高通了,看下面代碼。
 
void sbl1_main_ctl(boot_pbl_shared_data_type *pbl_shared)
{
 
 。。。。。。。。。
 //sbl入口足夠早的地方就開始log初始化。再前面就無法打印log了,就看成前面的代碼不出錯吧。
  
  /* Initialize boot logger and start the log timer */
  sbl1_boot_logger_init(&boot_log_data,
                        pbl_shared);
 
  。。。。。。。。。
}
sbl1_boot_logger_init調用boot_log_init進行ram log , timer ,uart 初始化。
void boot_log_init(boot_log_init_data *init_data)
{
  /*we must first set meta info becasue boot_log_init_ram and
   * boot_log_init_timer will use the meta info structure*/
  boot_log_set_meta_info(init_data->meta_info_start);
  boot_log_init_ram(init_data);  //初始化ram log
  boot_init_timer(init_data);        //初始化timer ,可用於打印sbl各階段的啓動時間
  boot_log_init_uart();                //初始化uart
}
/* boot_log_init */
 
作完初始化的工做後,就可直接使用boot_log_message將log打印到ram和uart啦!
使用方法參考:
  static char error_message[BOOT_ERROR_MSG_LEN];
  //本身將打印的信息格式化到自定義的buffer:error_message
      snprintf(error_message, BOOT_ERROR_MSG_LEN, 
             "Error code %lx at %s Line %lu", err_code, filename_ptr, line);
      //打印log       
      boot_log_message(error_message);
 
參考代碼:
boot_logger.c
boot_logger_uart.c
boot_logger_ram.c
boot_logger_timer.c


4、SW download

 待續:《高通 MSM8K bootloader之二: SBL1》

 

5、Crash ramdump

 待續:《高通 MSM8K bootloader之二: SBL1》

 

參考資料:

80_NA157_7_C_MSM8974_Boot_Architecture_Overview.pdf

80-NL239-1_A_MSM8916_Boot_Architecture_Overview.pdf

80-N3411-1_B_EEPROM_SW_CDT.pdf

80-NJ172-1_A_LPDDR2_CUSTOMIZATION_FOR_MSM8x26_DEVICES.pdf

相關文章
相關標籤/搜索