preloader阶段初始化流程图
代码流程图
\vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\init\init.S
nit.s 主要干的事情是切换系统到管理模式(svc)(如果平台有实现el3,那么pre-loader运行在el3,否则运行在el1),禁止irq/fiq,设置stack等, 然后jump到c代码main函数入口。
\vendor\mediatek\proprietary\bootable\bootloader\preloader\platform\mt6739\src\core\main.c
void main(u32 *arg)
{
struct bldr_command_handler handler;
u32 jump_addr, jump_arg;
/* get the bldr argument */
p_bldr_param = &bldr_param;
memcpy((void *)p_bldr_param, (void *)*arg, sizeof(bl_param_t));
#ifdef MTK_SECURITY_SW_SUPPORT
/* note that if you use cmm file, these parameters are empty. */
seclib_set_pl_load_addr(p_bldr_param->bl_loadinfo[0].bl_load_addr);
seclib_set_cc_status(p_bldr_param->cc_lcs, p_bldr_param->cc_flags);
seclib_set_sctrl_info(p_bldr_param->sctrl_cert_file_addr, p_bldr_param->sctrl_cert_file_len);
seclib_set_tool_auth_info(p_bldr_param->tool_auth_file_addr, p_bldr_param->tool_auth_file_len);
seclib_set_me_id(p_bldr_param->meid, ME_IDENTITY_LEN);
seclib_set_soc_id(p_bldr_param->socid, SOC_ID_LEN);
seclib_set_prov_key(p_bldr_param->prov_key, PROVISIONING_KEY_LEN);
#endif
#if CFG_CANCEL_BWDT_TIMEOUT
/* Cancel BWDT timeout, otherwise it would reset in 2 second. */
DRV_WriteReg32(0x100070A4, DRV_Reg32(0x100070A4) | 0x66000001);
#endif
//初始化串口
mtk_uart_init(UART_SRC_CLK_FRQ, CFG_LOG_BAUDRATE);
//该函数做了很多事情,包括了各种的平台硬件操作(timer、pll、pmic、gpio、wdt、iic……)
bldr_pre_process();
#ifdef HW_INIT_ONLY
#if !CFG_FPGA_PLATFORM
/*
* The following is requested by MD: Ying Hsu and Jim Chou
* Set VCORE and VMODEM as 1.19375V respectively.
* Read the settings back and print the results.
*/
pmic_config_interface(0x152A, 0x6C, 0x7F,0);
pmic_config_interface(0x15AA, 0x6F, 0x7F,0);
unsigned int val = 0;
pmic_read_interface(0x152A, &val, 0x7F,0);
print("VCORE: %d\n", val);
pmic_read_interface(0x15AA, &val, 0x7F,0);
print("VMODEM: %d\n", val);
#endif
bldr_wait_forever();
#endif
handler.priv = NULL;
handler.attr = 0;
handler.cb = bldr_cmd_handler;
BOOTING_TIME_PROFILING_LOG("before bldr_handshake");
//该函数式获得启动模式等信息保存到g_boot_mode和g_boot_mode全局变量中
bldr_handshake(&handler);
BOOTING_TIME_PROFILING_LOG("bldr_handshake");
#if !CFG_FPGA_PLATFORM
/* security check */
device_APC_dom_setup();
#endif
BOOTING_TIME_PROFILING_LOG("sec_boot_check");
#if CFG_ATF_SUPPORT
trustzone_pre_init();
#endif
#if defined(MTK_AB_OTA_UPDATER)
/* This is for MT6739 only.
* Since preloader needs to load loader_ext_dram, the time of executing
* ab_ota_boot_check() is earlier than other platform. Once g_boot_mode
* is assigned as RECOVERY_BOOT in ab_ota_boot_check(), it would be
* overwritten as NORMAL_BOOT in bldr_pre_process(). Therefore we back up
* g_boot_mode and resume it later if it is RECOVERY_BOOT.
*/
if (ab_boot_mode == RECOVERY_BOOT) {
print("ab_boot_mode: %d\n", ab_boot_mode);
g_boot_mode = RECOVERY_BOOT;
}
#endif
BOOTING_TIME_PROFILING_LOG("before load image");
#if !(CFG_BYPASS_LOAD_IMG_FORCE_ATF)
/* Do not load ATF, lk, load by JTAG */
//bldr_load_images
此函数要做的事情就是把lk从ROM中指定位置load到DRAM中,开机log中可以看到具体信息:
[PART] load "lk" from 0x0000000001CC0200 (dev) to 0x81E00000 (mem) [SUCCESS]这里准备好了jump到DRAM的具体地址
if (0 != bldr_load_images(&jump_addr)) {
print("%s Second Bootloader Load Failed\n", MOD);
goto error;
}
#else
jump_addr = CFG_UBOOT_MEMADDR;
#endif
BOOTING_TIME_PROFILING_LOG("load image");
// bldr_post_process()该函数的具体实现是platform_post_init();该函数通过hw_check_battery检测电池是否存在,如果电池不存在就一直死循环,因此第一次不接电池有可能开不了机就可能是这里导致的
bldr_post_process();
#ifdef SLT
mt_usb_phy_recover();
//mu3d_hal_rst_dev();
#endif
#if CFG_ATF_SUPPORT
trustzone_post_init();
#endif
#if CFG_LOAD_SLT_AARCH64_KERNEL
if (0 == aarch64_slt_done())
{
*(unsigned int*) AARCH64_SLT_DONE_ADDRESS = AARCH64_SLT_DONE_MAGIC;
jump_addr = CFG_BOOTA64_MEMADDR;
//set up slave cpu reset address
*(unsigned int*) 0x10200040 = CFG_BOOTA64_MEMADDR; //cpu1
*(unsigned int*) 0x10200048 = CFG_BOOTA64_MEMADDR; //cpu2
*(unsigned int*) 0x10200050 = CFG_BOOTA64_MEMADDR; //cpu3
*(unsigned int*) 0x10200238 = CFG_BOOTA64_MEMADDR; //cpu4
*(unsigned int*) 0x10200240 = CFG_BOOTA64_MEMADDR; //cpu5
*(unsigned int*) 0x10200248 = CFG_BOOTA64_MEMADDR; //cpu6
*(unsigned int*) 0x10200250 = CFG_BOOTA64_MEMADDR; //cpu7
print("%s Aarch64 Kernel SLT , jump to 64 bit kernel, address: 0x%x\n", MOD,jump_addr);
bldr_jump64(jump_addr, (u32)&bootarg, sizeof(boot_arg_t));
}
#endif
//jump_arg 跳转传入lk的参数,包括boot time、mode、reason等
#if CFG_BOOT_ARGUMENT_BY_ATAG
jump_arg = (u32)&(g_dram_buf->boottag);
#else
jump_arg = (u32)&bootarg;
#endif
/* 64S3,32S1,32S1 (MTK_ATF_BOOT_OPTION = 0)
* re-loader jump to LK directly and then LK jump to kernel directly */
#if CFG_ATF_SUPPORT
print("%s Others, jump to ATF\n", MOD);
bldr_jump64(jump_addr, jump_arg, sizeof(boot_arg_t));
#else
// bldr_jump该函数通过执行jump系统调用从preloader跳转到lk继续执行。
bldr_jump(jump_addr, jump_arg, sizeof(boot_arg_t));
#endif
error:
platform_error_handler();
}
以上简单分析了preloader的main函数的基本流程,
main 函数小结:
(1)各种硬件初始化(uart、pmic、wdt、timer、mem..);
(2)获取系统启动模式等,保存在全局变量中;
(3)Security check,跟secro.img相关;
(4)如果系统已经实现el3,则进入tz初始化;
(5)获取lk加载到DRAM的地址(固定值),然后从ROM中找到lk分区的地址, 如果没找到jump_addr,则 goto error;
(6)battery check,如果没有电池就会陷入while(1);
(7)jump到lk(如果有实现el3,则会先jump到el3,然后再回到lk
下面重点来看跟电池 pmic相关的函数bldr_post_process()流程。
static void bldr_post_process(void)
{
platform_post_init();
}
//重点看platform_post_init这个函数
void platform_post_init(void)
{
#ifdef MTK_SECURITY_SW_SUPPORT
/*Anti rollback update*/
#ifdef MTK_SECURITY_ANTI_ROLLBACK
u32 g_pl_otp_status = 0x0;
g_pl_otp_status = sec_otp_ver_update();
if (g_pl_otp_status)
print("update fail 0x%x\n", g_pl_otp_status);
#endif
#endif
#if CFG_FUNCTION_PICACHU_SUPPORT
start_picachu();
etc_entry();
#endif
#if CFG_BATTERY_DETECT //是否进行电池检测
/* normal boot to check battery exists or not */
if (g_boot_mode == NORMAL_BOOT && !hw_check_battery() && usb_accessory_in()) {//正常开机模式下如果USB插入且电池不在位就一直死循环,等待电池接入
print("%s Wait for battery inserted...\n", MOD);
/* disable pmic pre-charging led */
//remove empty function to save space pl_close_pre_chr_led();
/* enable force charging mode */
//remove empty function to save space pl_charging(1);
do {
mdelay(300);
/* check battery exists or not */
if (hw_check_battery())
break;//电池在位,退出死循环
/* kick all watchdogs */
platform_wdt_all_kick();//看门狗喂狗
} while(1);
/* disable force charging mode */
//remove empty function to save space pl_charging(0);
}
#endif
#if !CFG_FPGA_PLATFORM
pl_battery_init(true);//preloader阶段电池初始化相关的操作
#endif
BOOTING_TIME_PROFILING_LOG("Battery detect");
#if CFG_MDJTAG_SWITCH
unsigned int md_pwr_con;
/* md0 default power on and clock on */
/* md1 default power on and clock off */
/* ungate md1 */
/* rst_b = 0 */
md_pwr_con = DRV_Reg32(0x10006280);
md_pwr_con &= ~0x1;
DRV_WriteReg32(0x10006280, md_pwr_con);
/* enable clksq2 for md1 */
DRV_WriteReg32(0x10209000, 0x00001137);
udelay(200);
DRV_WriteReg32(0x10209000, 0x0000113f);
/* rst_b = 1 */
md_pwr_con = DRV_Reg32(0x10006280);
md_pwr_con |= 0x1;
DRV_WriteReg32(0x10006280, md_pwr_con);
/* switch to MD legacy JTAG */
/* this step is not essentially required */
#endif
BOOTING_TIME_PROFILING_LOG("MTJTAG switch");
#if CFG_MDMETA_DETECT
if (g_boot_mode == META_BOOT || g_boot_mode == ADVMETA_BOOT) {
/* trigger md0 to enter meta mode */
DRV_WriteReg32(0x20000010, 0x1);
/* trigger md1 to enter meta mode */
DRV_WriteReg32(0x30000010, 0x1);
} else {
/* md0 does not enter meta mode */
DRV_WriteReg32(0x20000010, 0x0);
/* md1 does not enter meta mode */
DRV_WriteReg32(0x30000010, 0x0);
}
#endif
BOOTING_TIME_PROFILING_LOG("MTMETA Detect");
platform_set_boot_args();
BOOTING_TIME_PROFILING_LOG("Boot Argu");
}
如何检测电池是否存在?
int hw_check_battery(void)
{
#ifdef MTK_DISABLE_POWER_ON_OFF_VOLTAGE_LIMITATION
print("ignore bat check\n");
return 1;
#else
#if CFG_EVB_PLATFORM //这里EVB的板子跳过电池检测,需要关注该宏在哪里定义?
print("ignore bat check\n");
return 1;
#else
U32 val = 0;
U32 ret_val;
ret_val = pmic_config_interface(PMIC_RG_LDO_TREF_EN_ADDR, 1,
PMIC_RG_LDO_TREF_EN_MASK,
PMIC_RG_LDO_TREF_EN_SHIFT);
pmic_upmu_set_rg_baton_en(1);
val = pmic_upmu_get_rgs_baton_undet();//读取寄存器标志位。
if(val == 0) {
print("battery exists\n");
return 1;
} else {
print("battery doesn't exist\n");
return 0;
}
#endif /* !CFG_EVB_PLATFORM */
#endif /* !MTK_DISABLE_POWER_ON_OFF_VOLTAGE_LIMITATION */
}
检测电池是否存在的寄存器判断标志位:
下面再来看pl_battery_init(true)电池初始化都做了哪些事情?
void pl_battery_init(bool force_init)
{
if (force_init == true)
return;
#if !CFG_EVB_PLATFORM && !CFG_FPGA_PLATFORM
fuel_gauge_init();
#endif
}
void fuel_gauge_init(void)
{
int m = 0, ret;
int b_moniter_pl_charg_bit;
int plcharg_status = 0;
U32 gain_cal;
boot_vbat = get_bat_sense_volt(1);//电池电压
pmic_read_interface(PMIC_RG_FGADC_GAINERROR_CAL_ADDR, &gain_cal, PMIC_RG_FGADC_GAINERROR_CAL_MASK, PMIC_RG_FGADC_GAINERROR_CAL_SHIFT);
pmic_config_interface(PMIC_FG_GAIN_ADDR, gain_cal, PMIC_FG_GAIN_MASK, PMIC_FG_GAIN_SHIFT);
/*reset HW FG */
pmic_config_interface(PMIC_FG_CHARGE_RST_ADDR, 1, PMIC_FG_CHARGE_RST_MASK, PMIC_FG_CHARGE_RST_SHIFT);
pmic_config_interface(PMIC_FG_TIME_RST_ADDR, 1, PMIC_FG_TIME_RST_MASK, PMIC_FG_TIME_RST_SHIFT);
pmic_config_interface(PMIC_FG_OFFSET_RST_ADDR, 1, PMIC_FG_OFFSET_RST_MASK, PMIC_FG_OFFSET_RST_SHIFT);
pmic_config_interface(PMIC_FG_SW_CR_ADDR, 1, PMIC_FG_SW_CR_MASK, PMIC_FG_SW_CR_SHIFT);
udelay(100);
pmic_config_interface(PMIC_FG_CHARGE_RST_ADDR, 0, PMIC_FG_CHARGE_RST_MASK, PMIC_FG_CHARGE_RST_SHIFT);
pmic_config_interface(PMIC_FG_TIME_RST_ADDR, 0, PMIC_FG_TIME_RST_MASK, PMIC_FG_TIME_RST_SHIFT);
pmic_config_interface(PMIC_FG_OFFSET_RST_ADDR, 0, PMIC_FG_OFFSET_RST_MASK, PMIC_FG_OFFSET_RST_SHIFT);
pmic_config_interface(PMIC_FG_SW_CR_ADDR, 0, PMIC_FG_SW_CR_MASK, PMIC_FG_SW_CR_SHIFT);
pmic_config_interface(PMIC_FG_SW_READ_PRE_ADDR, 1, PMIC_FG_SW_READ_PRE_MASK, PMIC_FG_SW_READ_PRE_SHIFT);
m = 0;
while (fg_get_data_ready_status() == 0) {
udelay(100);
m++;
if (m > 5) {
print("1.PMIC_FG_LATCHDATA_ST_SHIFT = 0\r\n");
break;
}
}
pmic_config_interface(PMIC_FG_SW_CLEAR_ADDR, 1, PMIC_FG_SW_CLEAR_MASK, PMIC_FG_SW_CLEAR_SHIFT);
pmic_config_interface(PMIC_FG_SW_READ_PRE_ADDR, 0, PMIC_FG_SW_READ_PRE_MASK, PMIC_FG_SW_READ_PRE_SHIFT);
m = 0;
while (fg_get_data_ready_status() != 0) {
udelay(100);
m++;
if (m > 5) {
print("2.PMIC_FG_LATCHDATA_ST_SHIFT != 0\r\n");
break;
}
}
pmic_config_interface(PMIC_FG_SW_CLEAR_ADDR, 0, PMIC_FG_SW_CLEAR_MASK, PMIC_FG_SW_CLEAR_SHIFT);
/* if WDT reset from PL to KERNEL, b_moniter_pl_charg_bit will keep 1*/
/* record PL charging status in bit1, mointer bit in bit2 */
pmic_read_interface(PMIC_RG_SYSTEM_INFO_CON0_ADDR, &b_moniter_pl_charg_bit, 0x0001, 0x2);
if (b_moniter_pl_charg_bit == 0) {
plcharg_status = upmu_is_chr_det();
ret = pmic_config_interface(PMIC_RG_SYSTEM_INFO_CON0_ADDR, 0x1, 0x0001, 0x2);
ret = pmic_config_interface(PMIC_RG_SYSTEM_INFO_CON0_ADDR, plcharg_status, 0x0001, 0x1);
}
ret = pmic_read_interface(PMIC_RG_SYSTEM_INFO_CON0_ADDR, &b_moniter_pl_charg_bit, 0x0001, 0x2);
ret = pmic_read_interface(PMIC_RG_SYSTEM_INFO_CON0_ADDR, &plcharg_status, 0x0001, 0x1);
print("pl chr:%d monitor:%d plchr:%d gain:%d\r\n",upmu_is_chr_det() b_moniter_pl_charg_bit,plcharg_status,gain_cal);
if (hw_check_battery() == 1) {
pl_check_bat_protect_status();
}
}
//fuel gauge初始化完了之后开始电池保护相关的操作,类似于lk中的预充电流程,电池电压低于开机电压时就先预充电。
void pl_check_bat_protect_status(void)
{
int bat_val = 0;
int current, chr_volt, cnt=0, i;
#if SWCHR_POWER_PATH
bat_val = get_i_sense_volt(1);
#else
bat_val = get_bat_sense_volt(1);
#endif
chr_volt = get_charger_volt(1);
print("[%s]: check VBAT=%dmV with %dmV, VCHR=%dmV ,VCHR_HV=%dmv, start charging\n",
__func__, bat_val, BATTERY_LOWVOL_THRESOLD, chr_volt, V_CHARGER_MAX);
while (bat_val < BATTERY_LOWVOL_THRESOLD) {
mtk_wdt_restart();
if (upmu_is_chr_det() == KAL_FALSE) {
print("No Charger\n");
break;
}
chr_volt = get_charger_volt(1);
if (chr_volt > V_CHARGER_MAX) {
print("Vchr is too high :%dmv, threshold is %dmv\n",
chr_volt, V_CHARGER_MAX);
break;
}
pchr_turn_on_charging(KAL_TRUE);//开始充电
cnt = 0;
for (i = 0; i < 10; i++) {
current = get_charging_current();
chr_volt = get_charger_volt(1);
if (current < 100 && chr_volt < 4400) {
cnt++;
print("ichg=%dmA, Vchr=%d\n", current, chr_volt);
} else {
print("ichg=%dmA, Vchr=%d\n", current, chr_volt);
cnt = 0;
}
}
if (cnt >= 8) {
print("ichg and Vchr is too low: %d\n", cnt);
pchr_turn_on_charging(KAL_FALSE);
break;
}
mdelay(2000);
#if SWCHR_POWER_PATH
bat_val = get_i_sense_volt(1);
#else
bat_val = get_bat_sense_volt(1);
#endif
print("[%s]: check VBAT=%dmV, Vchr=%dmV, I=%dmA\n", __func__, bat_val, chr_volt, current);
}
print("[%s]: check VBAT=%dmV with %dmV, stop charging\n", __func__,
bat_val, BATTERY_LOWVOL_THRESOLD);
}
综上bldr_post_process函数中跟电池相关的操作,一是检测电池是否在位,二是fuel gauge 初始化。