高通 MSM8K bootloader : SBL1 .
一、 MSM8K Boot Flow?
圖1:
?
高通MSM8K平臺bootloader啟動流程基本類似,但具體各平臺,比如MSM8974、MSM8916、MSM8994等,會有微小區(qū)別。
從上圖,可以看出高通8K平臺的boot過程非常不一般啊。相比MTK平臺,或者高通7K平臺,復(fù)雜了非常多。 下圖是高通文檔對啟動流程的說明,
已經(jīng)很清楚了,我這邊就直接貼出來啦。
圖2:
系統(tǒng)上電后從RPM PBL啟動到 APPS PBL 然后SBL1 ,再啟動APPSBL 等等,整個過程看似非常復(fù)雜,但其實(shí)很多代碼OEM廠家是看不到,也修改不了的。
那我們需要我們做什么? 能做點(diǎn)什么呢? 呵呵!不會沒事情做的。 SBL1和appsbl高通是有開放代碼。
本章我重點(diǎn)關(guān)注SBL1,且主要描述我認(rèn)為重點(diǎn)的幾方面:
1、 ? ?CDT : Platform ID和DDR參數(shù)?
2、 debug log :
3、 download : msm8K 新平臺軟件download支持兩種協(xié)議,sahara和firehose
4、 ramdump :死機(jī)異常信息dump
好的,下面將SBL1我比較關(guān)注的點(diǎn)調(diào)用流程總結(jié)成如下圖,后面再針對關(guān)注點(diǎn)展開,逐個分析。
圖3:
二、CDT:Platform ID和DDR參數(shù)?
1、CDT(Configuration Data Table ) 里到底有什么內(nèi)容?
參考下圖,可知CDT包含CDB0: platform info信息和CDB1: DDR配置參數(shù)。圖4:
platform info 包含平臺id,主板的版本號,項(xiàng)目號等信息。
圖5:
CDB0: platform info 如下結(jié)構(gòu)體表現(xiàn):
typedef PACKED struct
{
? uint8 ? ? ? ? ? ? ? ? nVersion;
? uint8 ? ? ? ? ? ? ? ??nPlatform; //這個是平臺id,用于高通不同平臺類型。我們不能去修改。
? uint8 ? ? ? ? ? ? ? ? nHWVersionMajor; ? //硬件版本號暫時沒有使用,默認(rèn)為0
? uint8 ? ? ? ? ? ? ? ? nHWVersionMinor;
? uint8 ? ? ? ? ? ? ? ??nSubtype; // 默認(rèn)為0沒有用。我們可以用它來做項(xiàng)目區(qū)分
? 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
2、CDB0:?platform info信息有什么用處?
上圖3可以看到CDB0:?platform info相關(guān)的代碼調(diào)用有如下二函數(shù):
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");
} ?//該函數(shù)獲取到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);
? ? ??//調(diào)用?PlatformInfo.c?中的PlatformInfo_InitSMem保存platform info 到smem.
? ? ? boot_DAL_DeviceDetach(phPlatform);
? ? }
? }
??
}/* sbl1_hw_platform_smem() */
//好了
static DALResultPlatformInfo_InitSMem
(
? PlatformInfoDrvCtxt *pDrvCtxt
)
{
? ?//申請共享內(nèi)存區(qū):SMEM_HW_SW_BUILD_ID
? pSMem = (DalPlatformInfoSMemType *)
? ? smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(DalPlatformInfoSMemType));
? ?...............
//保存platform info到共享內(nèi)存
??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 根據(jù)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請參考這些函數(shù),后面專門研究lk,再詳細(xì)描述。
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格式及代碼分析,可以看出,如果不同項(xiàng)目cdt的nPlatform和nSubtype項(xiàng)配置成不同的值,?與dts 包含的platform id & subtype id信息進(jìn)行匹配。就可以用來區(qū)分不同的項(xiàng)目。
即:我們在項(xiàng)目開發(fā)過程中,同一個分支代碼要進(jìn)行多項(xiàng)目開發(fā)時,
sbl、lk、kernel可以利用這些信息來區(qū)分不同項(xiàng)目,實(shí)現(xiàn)一套代碼多項(xiàng)目配置目標(biāo)。如下圖:
? ?圖6:
總結(jié):通過修改cdt和dts,sbl、lk、kernel階段使用如下接口,可以將同一個branch代碼中多項(xiàng)目區(qū)分出來!
sbl_board_subtype ? ? ?// sbl高通沒有,自己開發(fā)一個接口
board_hardware_subtype ? // lk接口
of_board_is_xxx ?// kernel 接口
3、CDB1:DDR參數(shù)的配置流程?
cdt中還有一項(xiàng)重要內(nèi)容是CDB1: DDR參數(shù),下面看看如何利用這些參數(shù)進(jìn)行ddr初始化的。
ddr初始化涉及如下重要三函數(shù):
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 參數(shù)到底層
? /* Initialize DDR */
? (boot_procedure_func_type)sbl1_ddr_init, ? ?//初始化ddr
? ?.......
? /* Last entry in the table. */
? NULL?
};
下面重點(diǎn)介紹這三個函數(shù):
? ???圖7:
?cdt數(shù)據(jù)?config_data_table保存到config_data_table_info.cdt_ptr
? ? ??圖8:
sbl1_ddr_set_params調(diào)用ddr_set_params,將ddr參數(shù)保存到ddr_device_table。
獲取num_of_device保存到ddr_device_table_entry_num 。
? ?圖9:
sbl1_ddr_init 通過?HAL_SDRAM_Init調(diào)用到如下函數(shù),
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?實(shí)現(xiàn)一個項(xiàng)目自動支持多種ddr timing的方法。
?
好了,ddr timing就不再多說了,詳細(xì)請閱讀代碼及參考文檔:
80-NJ172-1_A_LPDDR2_CUSTOMIZATION_FOR_MSM8x26_DEVICES.pdf
三、Debug log
坑跌的高通,MSM6K/7K平臺,包括舊的MSM8K平臺bootloader都不支持uart。 需要自己添加uart debug log,否則只能連接jtag接口,使用Trace32調(diào)試。 哎,Trace32那價錢,咱這貧民企,都調(diào)試不起啦。高通也賺了夠多的,總算有良心,在MSM8916平臺默認(rèn)支持uart啦!
好了,不罵高通了,看下面代碼。
void sbl1_main_ctl(boot_pbl_shared_data_type *pbl_shared)
{
? 。。。。。。。。。 //sbl入口足夠早的地方就開始log初始化。再前面就沒法打印log了,就當(dāng)作前面的代碼不出錯吧。
??
? /* Initialize boot logger and start the log timer */
??sbl1_boot_logger_init(&boot_log_data,
? ? ? ? ? ? ? ? ? ? ? ? pbl_shared);
。。。。。。。。。 } sbl1_boot_logger_init調(diào)用boot_log_init進(jìn)行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
四、SW download
待續(xù):《高通 MSM8K bootloader之二: SBL1》
待續(xù):《高通 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
?
總結(jié)
以上是生活随笔為你收集整理的高通 MSM8K bootloader : SBL1 .的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于LCD的分屏与切屏 Tearing
- 下一篇: msm8916 dt选用规则