/********************************************************************************
* I.MX6 recovery mode hacking
* 说明:
* 看一下i.MX6 Recovery模式是怎么工作的。
*
* 2017-6-12 深圳 龙华樟坑村 曾剑锋
*******************************************************************************/ 一、参考文档:
. Booting into recovery from terminal [duplicate]
https://android.stackexchange.com/questions/50366/booting-into-recovery-from-terminal
. Enter recovery mode from command line
https://android.stackexchange.com/questions/21050/enter-recovery-mode-from-command-line
. How to Support Recovery Mode for POR Reboot Based on i.MX6 Android R13.4.1
https://community.nxp.com/docs/DOC-93964 二、U-Boot Hacking /************************************************************************
*
* This is the next part if the initialization sequence: we are now
* running from RAM and have a "normal" C environment, i. e. global
* data can be written, BSS has been cleared, the stack size in not
* that critical any more, etc.
*
************************************************************************
*/ void board_init_r(gd_t *id, ulong dest_addr)
{
ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
ulong flash_size;
#endif gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */
bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r"); monitor_flash_len = (ulong)&__rel_dyn_end - (ulong)_start; /* Enable caches */
enable_caches(); debug("monitor flash len: %08lX\n", monitor_flash_len);
board_init(); /* Setup chipselects */
/*
* TODO: printing of the clock inforamtion of the board is now
* implemented as part of bdinfo command. Currently only support for
* davinci SOC's is added. Remove this check once all the board
* implement this.
*/
#ifdef CONFIG_CLOCKS
set_cpu_clk_info(); /* Setup clock information */
#endif
serial_initialize(); debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); #ifdef CONFIG_LOGBUFFER
logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST
post_output_backlog();
#endif /* The Malloc area is immediately below the monitor copy in DRAM */
malloc_start = dest_addr - TOTAL_MALLOC_LEN;
mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN); #ifdef CONFIG_ARCH_EARLY_INIT_R
arch_early_init_r();
#endif
power_init_board(); #if !defined(CONFIG_SYS_NO_FLASH)
puts("Flash: "); flash_size = flash_init();
if (flash_size > ) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
print_size(flash_size, "");
/*
* Compute and print flash CRC if flashchecksum is set to 'y'
*
* NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
*/
if (getenv_yesno("flashchecksum") == ) {
printf(" CRC: %08X", crc32(,
(const unsigned char *) CONFIG_SYS_FLASH_BASE,
flash_size));
}
putc('\n');
# else /* !CONFIG_SYS_FLASH_CHECKSUM */
print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts(failed);
hang();
}
#endif #if defined(CONFIG_CMD_NAND)
puts("NAND: ");
nand_init(); /* go init the NAND */
#endif #if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif #ifdef CONFIG_GENERIC_MMC
puts("MMC: ");
mmc_initialize(gd->bd);
#endif #ifdef CONFIG_CMD_SCSI
puts("SCSI: ");
scsi_init();
#endif #ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif /* initialize environment */
if (should_load_env())
env_relocate();
else
set_default_env(NULL); #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
arm_pci_init();
#endif stdio_init(); /* get the devices list going. */ jumptable_init(); #if defined(CONFIG_API)
/* Initialize API */
api_init();
#endif console_init_r(); /* fully init console as a device */ #ifdef CONFIG_DISPLAY_BOARDINFO_LATE
# ifdef CONFIG_OF_CONTROL
/* Put this here so it appears on the LCD, now it is ready */
display_fdt_model(gd->fdt_blob);
# else
checkboard();
# endif
#endif #if defined(CONFIG_ARCH_MISC_INIT)
/* miscellaneous arch dependent initialisations */
arch_misc_init();
#endif
#if defined(CONFIG_MISC_INIT_R)
/* miscellaneous platform dependent initialisations */
misc_init_r();
#endif /* set up exceptions */
interrupt_init();
/* enable exceptions */
enable_interrupts(); /* Initialize from environment */
load_addr = getenv_ulong("loadaddr", , load_addr); #ifdef CONFIG_BOARD_LATE_INIT
board_late_init();
#endif #ifdef CONFIG_FSL_FASTBOOT
fastboot_setup(); ----------------------------------------------+
#endif |
|
#ifdef CONFIG_BITBANGMII |
bb_miiphy_init(); |
#endif |
#if defined(CONFIG_CMD_NET) |
puts("Net: "); |
eth_initialize(gd->bd); |
#if defined(CONFIG_RESET_PHY_R) |
debug("Reset Ethernet PHY\n"); |
reset_phy(); |
#endif |
#endif |
|
#ifdef CONFIG_POST |
post_run(NULL, POST_RAM | post_bootmode_get()); |
#endif |
|
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER) |
/* |
* Export available size of memory for Linux, |
* taking into account the protected RAM at top of memory |
*/ |
{ |
ulong pram = ; |
uchar memsz[]; |
|
#ifdef CONFIG_PRAM |
pram = getenv_ulong("pram", , CONFIG_PRAM); |
#endif |
#ifdef CONFIG_LOGBUFFER |
#ifndef CONFIG_ALT_LB_ADDR |
/* Also take the logbuffer into account (pram is in kB) */ |
pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / ; |
#endif |
#endif |
sprintf((char *)memsz, "%ldk", (gd->ram_size / ) - pram); |
setenv("mem", (char *)memsz); |
} |
#endif |
|
#ifdef CONFIG_FSL_FASTBOOT |
check_fastboot(); |
#endif |
|
/* main_loop() can return to retry autoboot, if so just run it again. */ |
for (;;) { |
main_loop(); |
} |
|
/* NOTREACHED - no way out of command loop except booting */ |
} |
|
void fastboot_setup(void) <------------------------------------+
{
struct tag_serialnr serialnr;
char serial[]; get_board_serial(&serialnr);
sprintf(serial, "%u%u", serialnr.high, serialnr.low);
g_dnl_set_serialnumber(serial); /*execute board relevant initilizations for preparing fastboot */
board_fastboot_setup(); /*get the fastboot dev*/
_fastboot_setup_dev(); /*check if we need to setup recovery*/
#ifdef CONFIG_ANDROID_RECOVERY
check_recovery_mode(); -----------------------+
#endif |
|
/*load partitions information for the fastboot dev*/ |
_fastboot_load_partitions(); |
|
parameters_setup(); |
} |
|
/* export to lib_arm/board.c */ |
void check_recovery_mode(void) <-------------------+
{
if (check_key_pressing()) {
puts("Fastboot: Recovery key pressing got!\n");
setup_recovery_env();
} else if (check_recovery_cmd_file()) { --------------+
puts("Fastboot: Recovery command file found!\n"); |
setup_recovery_env(); --------------*-------------------+
#ifdef CONFIG_BCB_SUPPORT | |
} else if (recovery_check_and_clean_command()) { | |
puts("Fastboot: BCB command found\n"); | |
setup_recovery_env(); | |
#endif | |
} else { | |
puts("Fastboot: Normal\n"); | |
} | |
} | |
| |
int check_recovery_cmd_file(void) <-------------------+ |
{ |
int button_pressed = ; |
int recovery_mode = ; |
|
#ifdef CONFIG_SBC7112 |
return recovery_mode || button_pressed; |
#endif |
recovery_mode = recovery_check_and_clean_flag(); -----------------------+ |
| |
/* Check Recovery Combo Button press or not. */ | |
imx_iomux_v3_setup_multiple_pads(recovery_key_pads, | |
ARRAY_SIZE(recovery_key_pads)); | |
| |
gpio_direction_input(GPIO_VOL_DN_KEY); | |
| |
if (gpio_get_value(GPIO_VOL_DN_KEY) == ) { /* VOL_DN key is low assert */ | |
button_pressed = ; | |
printf("Recovery key pressed\n"); | |
} | |
| |
return recovery_mode || button_pressed; | |
} | |
| |
int recovery_check_and_clean_flag(void) <--------------------------+ |
{ |
int flag_set = ; |
u32 reg; |
reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR); |
|
flag_set = !!(reg & ANDROID_RECOVERY_BOOT); |
printf("check_and_clean: reg %x, flag_set %d\n", reg, flag_set); |
/* clean it in case looping infinite here.... */ |
if (flag_set) { |
reg &= ~ANDROID_RECOVERY_BOOT; |
writel(reg, SNVS_BASE_ADDR + SNVS_LPGPR); --------------------*-+
} | |
| |
return flag_set; | |
} | |
| |
void setup_recovery_env(void) <-----------------------------------+ |
{ |
board_recovery_setup(); --------+ |
} | |
| |
void board_recovery_setup(void) <------+ |
{ |
int bootdev = get_boot_device(); |
|
switch (bootdev) { |
#if defined(CONFIG_FASTBOOT_STORAGE_SATA) |
case SATA_BOOT: |
if (!getenv("bootcmd_android_recovery")) |
setenv("bootcmd_android_recovery", |
"boota sata recovery"); |
break; |
#endif /*CONFIG_FASTBOOT_STORAGE_SATA*/ |
#if defined(CONFIG_FASTBOOT_STORAGE_MMC) |
case SD2_BOOT: |
case MMC2_BOOT: |
if (!getenv("bootcmd_android_recovery")) |
setenv("bootcmd_android_recovery", |
"boota mmc0 recovery"); |
break; |
case SD3_BOOT: |
case MMC3_BOOT: |
if (!getenv("bootcmd_android_recovery")) |
setenv("bootcmd_android_recovery", |
"boota mmc1 recovery"); |
break; |
case MMC4_BOOT: |
if (!getenv("bootcmd_android_recovery")) |
setenv("bootcmd_android_recovery", |
"boota mmc2 recovery"); |
break; |
#endif /*CONFIG_FASTBOOT_STORAGE_MMC*/ |
default: |
printf("Unsupported bootup device for recovery: dev: %d\n", |
bootdev); |
return; |
} |
|
printf("setup env for recovery..\n"); |
setenv("bootcmd", "run bootcmd_android_recovery"); |
} |
|
三、Linux Kernel Hacking |
|
DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)") |
/* |
* i.MX6Q/DL maps system memory at 0x10000000 (offset 256MiB), and |
* GPU has a limit on physical address that it accesses, which must |
* be below 2GiB. |
*/ |
.dma_zone_size = (SZ_2G - SZ_256M), |
.smp = smp_ops(imx_smp_ops), |
.map_io = imx6q_map_io, |
.init_irq = imx6q_init_irq, |
.init_machine = imx6q_init_machine, |
.init_late = imx6q_init_late, |
.dt_compat = imx6q_dt_compat, |
.reserve = imx6q_reserve, |
.restart = mxc_restart, ------------------+ |
MACHINE_END | |
| |
/* | |
* Reset the system. It is called by machine_restart(). | |
*/ | |
void mxc_restart(enum reboot_mode mode, const char *cmd) <-----+ |
{ |
unsigned int wcr_enable; |
|
arch_reset_special_mode(mode, cmd); -------------------------+ |
| |
if (wdog_clk) | |
clk_enable(wdog_clk); | |
| |
if (cpu_is_mx1()) | |
wcr_enable = ( << ); | |
/* | |
* Some i.MX6 boards use WDOG2 to reset external pmic in bypass mode, | |
* so do WDOG2 reset here. Do not set SRS, since we will | |
* trigger external POR later. Use WDOG1 to reset in ldo-enable | |
* mode. You can set it by "fsl,wdog-reset" in dts. | |
* For i.MX6SX we have to trigger wdog-reset to reset QSPI-NOR flash to | |
* workaround qspi-nor reboot issue whatever ldo-bypass or not. | |
*/ | |
else if ((wdog_source == && (cpu_is_imx6q() || cpu_is_imx6dl() || | |
cpu_is_imx6sl())) || cpu_is_imx6sx() || cpu_is_imx7d() | |
|| cpu_is_imx6ul()) | |
wcr_enable = 0x14; | |
else | |
wcr_enable = ( << ); | |
| |
/* Assert SRS signal */ | |
__raw_writew(wcr_enable, wdog_base); | |
/* | |
* Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be | |
* written twice), we add another two writes to ensure there must be at | |
* least two writes happen in the same one 32kHz clock period. We save | |
* the target check here, since the writes shouldn't be a huge burden | |
* for other platforms. | |
*/ | |
__raw_writew(wcr_enable, wdog_base); | |
__raw_writew(wcr_enable, wdog_base); | |
| |
/* wait for reset to assert... */ | |
mdelay(); | |
| |
pr_err("%s: Watchdog reset failed to assert reset\n", __func__); | |
| |
/* delay to allow the serial port to show the message */ | |
mdelay(); | |
| |
/* we'll take a jump through zero as a poor second */ | |
soft_restart(); | |
} | |
| |
static void arch_reset_special_mode(char mode, const char *cmd) <----------+ |
{ |
#ifdef CONFIG_MXC_REBOOT_ANDROID_CMD |
if (cmd && strcmp(cmd, "recovery") == ) |
do_switch_recovery(); -----+ |
else if (cmd && strcmp(cmd, "bootloader") == ) | |
do_switch_fastboot(); | |
#endif | |
} | |
| |
void do_switch_recovery(void) <-------------------+ |
{ |
u32 reg; |
void *addr; |
struct clk *snvs_root; |
if(cpu_is_imx6()){ |
addr = ioremap(MX6_SNVS_BASE_ADDR, MX6_SNVS_SIZE); |
if (!addr) { |
pr_warn("SNVS ioremap failed!\n"); |
return; |
} |
reg = __raw_readl(addr + MX6_SNVS_LPGPR); <----------------------+
reg |= ANDROID_RECOVERY_BOOT;
__raw_writel(reg, (addr + MX6_SNVS_LPGPR));
}else{
snvs_root = clk_get_sys("imx-snvs.0", "snvs");
addr = ioremap(MX7_SNVS_BASE_ADDR, MX7_SNVS_SIZE);
if (!addr) {
pr_warn("SNVS ioremap failed!\n");
return;
}
clk_enable(snvs_root);
reg = __raw_readl(addr + MX7_SNVS_LPGPR);
reg |= ANDROID_RECOVERY_BOOT;
__raw_writel(reg, (addr + MX7_SNVS_LPGPR));
clk_disable(snvs_root);
}
iounmap(addr);
}

最新文章

  1. JavaScript 快速排序(Quicksort)
  2. c#.net 生成清晰缩略图
  3. Yii2中的入口文件环境配置
  4. hdu2665 &amp;&amp; poj2104划分树
  5. discuzX3后台管理插件开发入门
  6. ANGULAR 开发用户选择器指令
  7. sql学习资料
  8. 自然语言处理1——语言处理与Python(内含纠错)
  9. STM32F4_TIM基本延时(计数原理)
  10. [codevs2152]滑雪
  11. Android 原生listview item伸展收缩效果
  12. linux升级openssh7.4sp1
  13. Matlab:如何查找给定目录下的文件
  14. 通过js获取外部css样式
  15. petapoco 实体中字段去掉关联(类似于EF中的NotMap)
  16. sqoop导数据
  17. Bugku-CTF之输入密码查看flag
  18. set集合深浅拷贝以及知识补充
  19. Codeforces Round #272 (Div. 2) B. Dreamoon and WiFi dp
  20. Mac安装mtr与brow安装

热门文章

  1. maven Eclipse实战材料整理
  2. 【leetcode刷题笔记】Convert Sorted Array to Binary Search Tree
  3. MySQL Binlog解析(2)
  4. python中定制类
  5. 王译潇20162314 实验报告三plus结对编程四则运算第一阶段
  6. 广度优先搜索 BFS算法
  7. React-Navigation与Redux整合详解
  8. [mongodb] MMAP 和wiredTiger 的比较
  9. Codeforces Round #447 (Div. 2) C 构造
  10. 机器学习三剑客之Pandas