• I.MX6 recovery mode hacking


    /********************************************************************************
     *                      I.MX6 recovery mode hacking
     * 说明:
     *     看一下i.MX6 Recovery模式是怎么工作的。
     *
     *                                              2017-6-12 深圳 龙华樟坑村 曾剑锋
     *******************************************************************************/
    
    
    一、参考文档:
        1. Booting into recovery from terminal [duplicate]
            https://android.stackexchange.com/questions/50366/booting-into-recovery-from-terminal
        2. Enter recovery mode from command line
            https://android.stackexchange.com/questions/21050/enter-recovery-mode-from-command-line
        3. 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
    ", 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
    ", 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 > 0) {
        # 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") == 1) {
                    printf("  CRC: %08X", crc32(0,
                        (const unsigned char *) CONFIG_SYS_FLASH_BASE,
                        flash_size));
                }
                putc('
    ');
        # else    /* !CONFIG_SYS_FLASH_CHECKSUM */
                print_size(flash_size, "
    ");
        # 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", 16, 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
    ");                                           |
            reset_phy();                                                             |
        #endif                                                                       |
        #endif                                                                       |
                                                                                     |
        #ifdef CONFIG_POST                                                           |
            post_run(NULL, POST_RAM | post_bootmode_get(0));                         |
        #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 = 0;                                                      |
                uchar memsz[32];                                                     |
                                                                                     |
        #ifdef CONFIG_PRAM                                                           |
                pram = getenv_ulong("pram", 10, 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) / 1024;                     |
        #endif                                                                       |
        #endif                                                                       |
                sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - 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[17];
    
            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!
    ");
                setup_recovery_env();
            } else if (check_recovery_cmd_file()) {    --------------+
                puts("Fastboot: Recovery command file found!
    ");    |
                setup_recovery_env();                  --------------*-------------------+
        #ifdef CONFIG_BCB_SUPPORT                                    |                   |
            } else if (recovery_check_and_clean_command()) {         |                   |
                puts("Fastboot: BCB command found
    ");               |                   |
                setup_recovery_env();                                |                   |
        #endif                                                       |                   |
            } else {                                                 |                   |
                puts("Fastboot: Normal
    ");                          |                   |
            }                                                        |                   |
        }                                                            |                   |
                                                                     |                   |
        int check_recovery_cmd_file(void)        <-------------------+                   |
        {                                                                                |
            int button_pressed = 0;                                                      |
            int recovery_mode = 0;                                                       |
                                                                                         |
        #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) == 0) { /* VOL_DN key is low assert */ | |
                button_pressed = 1;                                                    | |
                printf("Recovery key pressed
    ");                                      | |
            }                                                                          | |
                                                                                       | |
            return recovery_mode || button_pressed;                                    | |
        }                                                                              | |
                                                                                       | |
        int recovery_check_and_clean_flag(void)             <--------------------------+ |
        {                                                                                |
            int flag_set = 0;                                                            |
            u32 reg;                                                                     |
            reg = readl(SNVS_BASE_ADDR + SNVS_LPGPR);                                    |
                                                                                         |
            flag_set = !!(reg & ANDROID_RECOVERY_BOOT);                                  |
            printf("check_and_clean: reg %x, flag_set %d
    ", 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
    ",                |
                    bootdev);                                                              |
                return;                                                                    |
            }                                                                              |
                                                                                           |
            printf("setup env for recovery..
    ");                                          |
            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 = (1 << 0);                                              |      |
            /*                                                                      |      |
             * 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 == 2 && (cpu_is_imx6q() || cpu_is_imx6dl() ||     |      |
                    cpu_is_imx6sl())) || cpu_is_imx6sx() || cpu_is_imx7d()          |      |
                    || cpu_is_imx6ul())                                             |      |
                wcr_enable = 0x14;                                                  |      |
            else                                                                    |      |
                wcr_enable = (1 << 2);                                              |      |
                                                                                    |      |
            /* 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(500);                                                            |      |
                                                                                    |      |
            pr_err("%s: Watchdog reset failed to assert reset
    ", __func__);        |      |
                                                                                    |      |
            /* delay to allow the serial port to show the message */                |      |
            mdelay(50);                                                             |      |
                                                                                    |      |
            /* we'll take a jump through zero as a poor second */                   |      |
            soft_restart(0);                                                        |      |
        }                                                                           |      |
                                                                                    |      |
        static void arch_reset_special_mode(char mode, const char *cmd)  <----------+      |
        {                                                                                  |
        #ifdef CONFIG_MXC_REBOOT_ANDROID_CMD                                               |
            if (cmd && strcmp(cmd, "recovery") == 0)                                       |
                do_switch_recovery();                          -----+                      |
            else if (cmd && strcmp(cmd, "bootloader") == 0)         |                      |
                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!
    ");                                     |
                    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!
    ");
                    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);
        }
  • 相关阅读:
    Spring核心思想:IOC(控制反转)、DI(依赖注入)和AOP(面向切面编程)
    synchronized 与 lock锁的异同
    SpringMVC工作流程
    close()和flush()的区别
    MySQL—索引(Index)
    MySQL—事务(ACID)
    MySQL—存储引擎
    周学习笔记(16)——大三下
    周学习笔记(15)——大三下
    周学习笔记(14)——大三下
  • 原文地址:https://www.cnblogs.com/zengjfgit/p/6995030.html
Copyright © 2020-2023  润新知