MT6739 preloaer流程分析

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 初始化。

猜你喜欢

转载自blog.csdn.net/yuewen2008/article/details/80535180