mstar 平台升级流程主要是在mboot 开机过程中进行,检测不通的触发条件从而进入升级流程。我们首先熟悉一个mboot的 启动流程。
启动流程
汇编部分不通方案也大致相同,我们主要以C部分启动流程为主,分析升级流程
- start.S 调转执行board_init_f
- 板级初始化 board_init_r (@\MBoot\u-boot-2011.06\arch\arm\lib\board.c)
- mstar 系统初始化MstarSysInit;
- board初始化board_init;
- nand,serial,eth,interrupt初始化;
- mstar 驱动初始化MstarDrvInit
- main_loop (MstarProcess ,MstarToKernel)初始化;
- MstarProcess ,MstarToKernel注册mboot 常用的功能(命令行指令);
上面只是自动的大概枝干,抽出了该平台特殊的部分,其中
vendor\mstar\mboot\MBoot\MstarApp\src\MsStart.c
BOOLEAN MstarProcess(void)
{
#if CONFIG_MINIUBOOT
run_command("updatemiureg", 0);
run_command("bootargs_set", 0);
#else
......
Customer_Register_Process(); // MsCustomerRegister.c 中完成具体注册
Customer_Register_ToKernel(); // MsCustomerRegister.c 中完成具体注册
pCmd=getFirstCmd();
if(pCmd==NULL)
{
UBOOT_DEBUG("There are no any cmds in table\n");
return TRUE;
}
// 从comand 中循环获取指令执行
while(1)
{
if(pCmd->stage == STAGE_PROCESS)
{
UBOOT_BOOTTIME("[AT][MB][%s][%lu]_start\n",pCmd->cmd, MsSystemGetBootTime());
run_command(pCmd->cmd, pCmd->flag);
UBOOT_BOOTTIME("[AT][MB][%s][%lu]_end\n",pCmd->cmd, MsSystemGetBootTime());
}
pCmd=getNextCmd(pCmd);
if(pCmd==NULL)
{
UBOOT_DEBUG("It's the last cmd\n");
break;
}
}
UBOOT_TRACE("OK\n");
#endif
return TRUE;
}
MstarToKernel是在MstarProcess 注册的基础上,执行命令完成对应功能。
BOOLEAN MstarToKernel(void)
{
#if CONFIG_MINIUBOOT
run_command("bootcheck", 0); // 启动检测
#if (CONFIG_PANEL_INIT)
run_command("panel_pre_init", 0); // 屏的预初始化
#endif
#if (ENABLE_HDMI_TX == 1)
run_command("hdmi init", 0); // hdmi 初始化
#endif
#ifdef CONFIG_DISPLAY_LOGO
run_command("bootlogo", 0); // 开机logo初始化
#endif
#else
......
pCmd=getFirstCmd();
if(pCmd==NULL)
{
UBOOT_DEBUG("There are no any cmds in table\n");
return TRUE;
}
while(1)
{
if(pCmd->stage == STAGE_TOKERNEL)
{
UBOOT_BOOTTIME("[AT][MB][%s][%lu]_start\n",pCmd->cmd, MsSystemGetBootTime());
run_command(pCmd->cmd, pCmd->flag);
UBOOT_BOOTTIME("[AT][MB][%s][%lu]_end\n",pCmd->cmd, MsSystemGetBootTime());
}
pCmd=getNextCmd(pCmd);
if(pCmd==NULL)
{
UBOOT_DEBUG("It's the last cmd\n");
break;
}
}
UBOOT_TRACE("OK\n");
#endif
return TRUE;
}
run_command 执行的指令就是在MsCustomerRegister.c文件中
通过Add_Command_Table注册的指令。
例如:
注册:Add_Command_Table (“bootcheck” , 0, STAGE_TOKERNEL);
执行:run_command(“bootcheck”, 0);
声明:
U_BOOT_CMD(
bootcheck, CONFIG_SYS_MAXARGS, 1, do_bootcheck,
"bootcheck - Do boot check\n",
NULL
);
实现:
vendor\mstar\mboot\MBoot\MstarApp\src\MsBoot.c
int do_bootcheck (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
......
}
上面介绍了大致的初始化流程。接着看一下升级检测。
升级检测
int do_bootcheck (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
#if (ENABLE_MODULE_BOOT_IR == 1)
if(BootFlag == 0)
{
BootMode =get_boot_mode_from_ir();
if(BootMode!=EN_BOOT_MODE_UNKNOWN)
{
//bootmode via IR
BootFlag=1;
}
}
#endif
#if (ENABLE_MODULE_BOOT_KEYPAD == 1)
if(BootFlag == 0)
{
BootMode =get_boot_mode_from_keypad();
if(BootMode!=EN_BOOT_MODE_UNKNOWN)
{
//BootMode via KEYPAD
BootFlag=1;
}
}
#endif
#if (ENABLE_MODULE_ANDROID_BOOT == 1)
// NOTE: read BCB in mtd0 (misc) to decide what boot mode to go
if(BootFlag == 0)
{
BootMode=get_boot_mode_from_mtd0();
if(BootMode!=EN_BOOT_MODE_UNKNOWN)
{
//BootMode via MTD
BootFlag=1;
}
}
#endif
#if (ENABLE_MODULE_ENV_BOOT == 1)
if(BootFlag == 0)
{
BootMode=get_boot_mode_from_env();
if(BootMode!=EN_BOOT_MODE_UNKNOWN)
BootFlag = 1;
}
if(BootFlag == 0)
{
char* force_upgrade = getenv(ENV_FORCE_UPGRADE);
if(force_upgrade)
{
int force_flag = simple_strtoul(force_upgrade,NULL,16);
if((force_flag <= 0x0F)&&(force_flag > 0x00))
{
//last time force upgrade not finish,so continue upgrading
BootMode = EN_BOOT_MODE_USB_UPGRADE;
}
}
}
#endif
......
}
do_bootcheck会从IR, KEYPAD,MTD0,ENV 获取信息,标记当前的BootMode ,下一步就是甄别BootMode 决定进入升级,还是进入recovery等其他场景
int do_bootcheck (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
......
switch(BootMode)
{
#if CONFIG_RESCUE_ENV && CONFIG_RESCUE_ENV_IR_TRIGGER
case EN_BOOT_MODE_BRICK_TERMINATOR:
brick_terminator_recover_mode = 1;
break;
#endif
#if (ENABLE_MODULE_ANDROID_BOOT == 1 )
case EN_BOOT_MODE_RECOVERY:
boot_mode_recovery();
break;
case EN_BOOT_MODE_RECOVRY_WIPE_DATA:
run_command("recovery_wipe_partition data",0);
boot_mode_recovery();
break;
case EN_BOOT_MODE_RECOVRY_WIPE_CACHE:
run_command("recovery_wipe_partition cache",0);
boot_mode_recovery();
break;
#if (ENABLE_MODULE_SYSTEM_RESTORE == 1)
case EN_BOOT_MODE_SYSTEM_RESTORE:
ret = run_command("SystemRestore",0);
if (ret != -1)
{
boot_mode_recovery();
}
break;
#endif
#endif
#if (ENABLE_MODULE_USB == 1)
case EN_BOOT_MODE_USB_UPGRADE:
ret = run_command("custar",0);//usb upgrade
break;
#if (ENABLE_MODULE_BOOT_IR == 1)
case EN_BOOT_MODE_OTA_UPGRADE:
ret = run_command("ota_zip_check",0);//ota upgrade
if (ret != -1)
{
boot_mode_recovery();
}
break;
case EN_BOOT_MODE_USB_RECOVRY_UPGRADE:
ret = run_command("usb_bin_check",0);//usb upgrade
if(ret == 0)
{
break;
}
ret = run_command("ota_zip_check",0);//ota upgrade
if (ret != -1)
{
boot_mode_recovery();
}
break;
#endif
#endif
#if (ENABLE_MODULE_OAD == 1)
case EN_BOOT_MODE_OAD_UPGRADE:
ret = run_command("costar",0);//oad upgrade
break;
#endif
#if (ENABLE_MODULE_ENV_UPGRADE_FROM_BANK == 1)
case EN_BOOT_MODE_ENV_UPGRADE:
ret = run_command("rstar",0);
#endif
#if (ENABLE_MODULE_NETUPDATE == 1)
case EN_BOOT_MODE_NET_UPGRADE:
_do_NetUpgrade_mode();
break;
#endif
case EN_BOOT_MODE_UART_DEBUG:
ret = run_command("setenv UARTOnOff on", 0);
ret = run_command("saveenv", 0);
printf("Opening UART now\n");
break;
case EN_BOOT_MODE_NORMAL:
break;
#if defined(CONFIG_AN_FASTBOOT_ENABLE)
case EN_BOOT_MODE_FASTBOOT:
ret = run_command("usb start 0",0);
ret = run_command("fastboot", 0);
break;
#endif
case EN_BOOT_MODE_UPDATE_BOOTLOGO:
ret = run_command("setenv BootlogoFile /cache/boot0.jpg",0);
ret = run_command("saveenv", 0);
ret = run_command("dbtable_init 1", 0);
ret = run_command("mmc erase.p misc", 0);
break;
default:
//normal booting according bootcmd in main.c
UBOOT_DEBUG("non available case\n");
break;
}
......
UBOOT_TRACE("OK\n");
return ret;
}
从上面可以看出BooMode 为EN_BOOT_MODE_RECOVERY,EN_BOOT_MODE_RECOVRY_WIPE_DATA,EN_BOOT_MODE_RECOVRY_WIPE_CACHE,EN_BOOT_MODE_SYSTEM_RESTORE,EN_BOOT_MODE_OTA_UPGRADE,EN_BOOT_MODE_USB_RECOVRY_UPGRADE,都是进入recovery进行OTA升级,为EN_BOOT_MODE_USB_UPGRADE 时,在进入U盘的升级流程。对于按键板而言只需要将按键和BootMode(EN_BOOT_MODE_USB_UPGRADE) 关联起来,即可进入升级流程。
按键检测流程
按键捕获
EN_BOOT_MODE get_boot_mode_from_keypad(void)
{
U8 u8KeyPad_KeyVal=0xFF;
U8 u8KeyPad_RepFlag = 0;
EN_BOOT_MODE mode = EN_BOOT_MODE_UNKNOWN;
UBOOT_TRACE("IN\n");
msKeypad_GetKey(&u8KeyPad_KeyVal,&u8KeyPad_RepFlag);
printf("fore uup u8KeyPad_KeyVal [0x%x]\n",u8KeyPad_KeyVal);
switch(u8KeyPad_KeyVal) // NOTE: read IR Key to decide what boot mode to go
{
#if defined(CONFIG_AN_FASTBOOT_ENABLE)
case KEYPAD_FASTBOOT_KEY:
mode = EN_BOOT_MODE_FASTBOOT;
break;
#endif
case KEYPAD_RECOVERY_KEY:
mode = EN_BOOT_MODE_RECOVERY;
break;
case KEYPAD_FORCEUGRADE_KEY: // 强制升级键值
// mode = check_usb_upgrade();
mode = EN_BOOT_MODE_USB_UPGRADE;
break;
case KEYPAD_UART_DEBUG_KEY:
mode = EN_BOOT_MODE_UART_DEBUG;
break;
#if (ENABLE_MODULE_SYSTEM_RESTORE == 1)
case KEYPAD_SYSTEM_RESTORE_KEY:
mode = EN_BOOT_MODE_SYSTEM_RESTORE;
break;
#endif
default:
mode = EN_BOOT_MODE_UNKNOWN;
break;
}
UBOOT_TRACE("OK\n");
return mode;
}
msKeypad_GetKey 获取按键板按键值,可以将u8KeyPad_KeyVal 的值分别对应上KEYPAD_FASTBOOT_KEY,KEYPAD_RECOVERY_KEY,KEYPAD_FORCEUGRADE_KEY,KEYPAD_UART_DEBUG_KEY,KEYPAD_SYSTEM_RESTORE_KEY。 此处USB升级使用的是power键那么对应的KEY是KEYPAD_FORCEUGRADE_KEY应该为多少?
按键映射
msKeypad_GetKey 虽然获取到的是具体的键值,但是主控检测到时按键板连接到sar口的adc 值,所以要找到sar 和 adc 值的映射关系。
BOOLEAN msKeypad_GetKey(U8 *pkey, U8 *pflag)
{
U8 Channel;
for (Channel=0; Channel<MAXKEYPADCH; Channel++)
{
if (msKeypad_CH_GetKey(Channel, pkey, pflag))
{
return MSRET_OK;
}
}
return MSRET_ERROR;
}
static BOOLEAN msKeypad_CH_GetKey(U8 Channel, U8 *pkey, U8* pflag)
{
U8 i, j, Key_Value;
U8 u8ChIdx = msKeypad_GetChanIndex(Channel);
if(u8ChIdx == 0xFF)
return MSRET_ERROR;
U8 u8KeyLevelNum = m_KpdConfig[u8ChIdx].u8KeyLevelNum;
U8 KEY_LV[u8KeyLevelNum];
memset(KEY_LV, 0x0, u8KeyLevelNum);
*pkey = 0xFF;
*pflag = 0;
for ( i = 0; i < KEYPAD_STABLE_NUM; i++ )
{
Key_Value = MDrv_SAR_Adc_GetValue(m_KpdConfig[u8ChIdx].u8SARChID);
for (j=0;j<u8KeyLevelNum;j++)
{
if (Key_Value < m_KpdConfig[u8ChIdx].u8KeyThreshold[j])
{
if((m_KpdConfig[u8ChIdx].u8KeyThreshold[j] - Key_Value) <= ADC_KEY_LEVEL_TOLERANCE)
{
KEY_LV[j]++;
break;
}
}
}
}
for(i=0; i<u8KeyLevelNum; i++)
{
if(KEY_LV[i] > KEYPAD_STABLE_NUM_MIN)
{
*pkey = m_KpdConfig[u8ChIdx].u8KeyCode[i];
return MSRET_OK;
}
}
return MSRET_ERROR;
}
获取的adc 结合结构体m_KpdConfig 的映射关系得到keycode
static SAR_KpdRegCfg_t m_KpdConfig[MAXKEYPADCH] = {
#include "keypad.h"
};
keypad 的映射关系如下:
//**********************************************************************
//** BOARD KEY PAD SAR SETTING
//**********************************************************************
//bEnable, u8SARChID, u8UpBnd, u8LoBnd, u8KeyLevelNum, u8KeyThreshold[8], u8KeyCode[8]
{0x00, 0x00, {0xFF, 0xF0}, 0x00, {0x10, 0x2F, 0x4D, 0x71, 0x92, 0xAB, 0xC3, 0xE7}, {0x46, 0xA1, 0xA2, 0xA4, 0xA3, 0xA6, 0xA8, 0xA5} },
{0x01, 0x01, {0xFF, 0x70}, 0x08, {0x13, 0x32, 0x52, 0x73, 0x92, 0xAE, 0xC6, 0xE8}, {0x82, 0x25, 0x26, 0x24, 0x32, 0x31, 0x23, 0x30} },
{0x00, 0x02, {0xFF, 0x80}, 0x00, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
{0x00, 0x03, {0xFF, 0xF0}, 0x08, {0x10, 0x2F, 0x4D, 0x71, 0x92, 0xAB, 0xC3, 0xE7}, {0x46, 0xA8, 0xA4, 0xA2, 0x00, 0x00, 0x00, 0x00} },
结合按键的power 的adc 值 为0x00,0x01 在区间,在u8KeyThreshold的
0x00 ~ 0x13 这个区间,对应的key 值应该是0x82 ,也即上面KEYPAD_FORCEUGRADE_KEY 的值。