Rockchip - uboot启动流程

前言:

我们在项目工作中对Uboot启动流程熟悉后,会非常有帮助,例如:工作中再做一些关于secure boot、loader模式下做一些操作、启动阶段拉高电平操作外设等。

一、u-boot基本介绍

1.1 u-boot起源

   u-boot(Universal Boot Loader),是Wolfgang Denk (德国人)在sourceforge.net的发起的开源项目用于嵌入式soc开发,支持ARM,MIPS,PowerPC,x86等处理器架构,

同时支持linux,VxWorks,NetBSD,QNX等操作系统,逐渐被众多厂商采用成为BootLoader标准之一。

1.2 RK使用的u-boot

         u-boot  一共有两个版本v2014旧版本和v2017新版本:

                - 基于开源的 UBoot v2014.10 正式版中切出来:

                     支持芯片:rk3288、rk3036、rk312x、rk3368、rk322x、rk3366、rk3399 等;

                  rk3399: # strings uboot.img |grep 2023 

                                             U-Boot 2014.10-RK3399-06 (Sep 20 2023 - 09:31:37)

                - 基于开源的  U-Boot v2017.09 正式版中切出来:

                   支持目前RK所有主流在售芯片:

                   rk3588: # strings uboot.img |grep 2023 

                                         U-Boot 2017.09 (Jun 02 2023 - 19:43:33 +0800)

1.2  v2017.09 支持的功能主要有

  • 支持 RK Android 固件启动;

  • 支持 Android AOSP 固件启动;

  • 支持 Linux Distro 固件启动;

  • 支持 Rockchip miniloader 和 SPL/TPL 两种 Pre-loader 引导;

  • 支持 LVDS、EDP、MIPI、HDMI、CVBS、RGB 等显示设备;

  • 支持 eMMC、Nand Flash、SPI Nand flash、SPI NOR flash、SD 卡、 U 盘等存储设备启动;

  • 支持 FAT、EXT2、EXT4 文件系统;

  • 支持 GPT、RK parameter 分区表;

  • 支持开机 LOGO、充电动画、低电管理、电源管理;

  • 支持 I2C、PMIC、CHARGE、FUEL GUAGE、USB、GPIO、PWM、GMAC、eMMC、NAND、Interrupt 等;

  • 支持 Vendor storage 保存用户的数据和配置;

  • 支持 RockUSB 和 Google Fastboot 两种 USB gadget 烧写 eMMC;

  • 支持 Mass storage、ethernet、HID 等 USB 设备;

  • 支持通过硬件状态动态选择 kernel DTB.

1.3  u-boot的代码结构

以卫士通rk3399的uboot-v2014为例:


├── api                            #存放uboot提供的syscall 的api函数例如:system (reset, platform info), devices (enumerate all, open, close, read, write)等

├── arch                          #存放SOC相关的代码平台文件 包括重要的 start.S load armboot to ram、设置栈等
├── board                       #存放板级的代码,例如rk的fastboot、loader模式检测等
├── common                  #通用函数的实现 ,包含进入uboot命令行模式后的实现run_command();比如我们常用的tftp 、nand/memory测试等命令,还有board_f 、board_r 初始化的board_init_f和board_init_r
├── disk                          #磁盘分区相关代码
├── drivers                     #设备驱动的代码storage、spi nor/nand、emmc、pcie、网卡等
├── dts                           #存放设备树(与kernel共用,这个里面基本上没有用)
├── fs                             #文件系统格式的支持 ext2、ext4、fat的代码
├── include                    #头文件和平台宏控的默认文件.h 例如:串口的波特率、默认打印的串口NUM等
├── net                          #网络协议的代码,例如arp、tftp、ping等
├── post                        #上电自检代码检测,例如:CPU cache、memory、watchdog、uart等
├── scripts                     #脚本存放位置 例如:cleanpatch等工具
├── tools                       #用于编译和检查uboot目标文件mkimage工具

二、u-boot启动流程

2.1 RK启动方式

        RK平台根据前级Loader代码是否开源,目前有两套启动方式:

// 前级loader闭源
BOOTROM => ddr bin => Miniloader => TRUST => U-BOOT => KERNEL
// 前级loader开源
BOOTROM => TPL(Tiny Program Loader) => SPL (Secondary Program Loade)Miniloader => TRUST => U-BOOT => KERNEL

     TPL(Tiny Program Loader)和 SPL(Secondary Program Loader)是比 U-Boot 更早阶段的 Loader:
                 TPL:运行在 sram 中,负责完成 ddr 初始化;
                 SPL:运行在 ddr 中,负责完成系统的 lowlevel 初始化、后级固件加载(trust.img 和 uboot.img);
                 U-Boot proper:运行在ddr中,即我们通常所说的"U-Boot",它负责引导kernel;

2.1.1 BootRom与SRAM在RK3399数据手册的规格:

2.1.2 BootRom引导过程流程

      例如 RK3399支持从内部bootrom启动,重映射由 SGRF_PMU_CON0[15] 控制。当 remap 设置为 0 时,0xFFFF0000 地址被映射到 bootrom。当 remapis 设置为 1 时,0xFFFF0000 地址被映射到 INTMEM0。

其中cortex-A53的core0作为第一个启动的核心,执行0xffff0000处的Bootrom loader程序。

引导过程流程流程图:

·

2.1.3 u-boot 启动过程

  1. 链接脚本文件u-boot.lds uboot的入口函数
    uboot编译完成后会在根目录生成这个文件
     

    OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
    OUTPUT_ARCH(aarch64)
    ENTRY(_start)
    SECTIONS
    {
     . = 0x00000000;
     . = ALIGN(8);
     .text :
     {
      *(.__image_copy_start)
      arch/arm/cpu/armv8/start.o (.text*)
      *(.text*)
     }

  2. arch/arm/cpu/armv8/start.S
     _start:
        .globl _start
         _start:
        nop
        b reset

    3. reset:
       

reset:

#ifdef CONFIG_ROCKCHIP
	/*
	 * check loader tag
	 */
	ldr	x0, =__loader_tag
	ldr	w1, [x0]
	ldr	x0, =LoaderTagCheck
	ldr	w2, [x0]
	cmp	w1, w2
	b.eq	checkok

	ret	/* return to maskrom or miniloader */

checkok:
#endif

	/*
	 * Could be EL3/EL2/EL1, Initial State:
	 * Little Endian, MMU Disabled, i/dCache Disabled
	 */
	adr	x0, vectors
	switch_el x1, 3f, 2f, 1f
3:	msr	vbar_el3, x0
	mrs	x0, scr_el3
	orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */
	msr	scr_el3, x0
	msr	cptr_el3, xzr			/* Enable FP/SIMD */
	ldr	x0, =COUNTER_FREQUENCY
	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */
#ifdef CONFIG_ROCKCHIP
	msr	cntvoff_el2, xzr		/* clear cntvoff_el2 for kernel */
#endif
	b	0f
2:	msr	vbar_el2, x0
	mov	x0, #0x33ff
	msr	cptr_el2, x0			/* Enable FP/SIMD */
	b	0f
1:	msr	vbar_el1, x0
	mov	x0, #3 << 20
	msr	cpacr_el1, x0			/* Enable FP/SIMD */
0:

	bl	lowlevel_init

     

4. lowlevel_init: u-boot/arch/arm/cpu/armv8/fsl-lsch3/lowlevel.S 
 
ENTRY(lowlevel_init)
	mov	x29, lr			/* Save LR */

	ldr	x0, =secondary_boot_func

	bl secondary_switch_to_el2
#ifdef CONFIG_ARMV8_SWITCH_TO_EL1
	bl secondary_switch_to_el1
#endif

     在ARMv8架构中改用执行等级(Execution Level,EL)EL0~EL3来定义ARM核的运行等级,其中EL0~EL2等级分为安全态和非安全态。ARMv8架构与ARMv7架构中ARM核运行权限的对应关系如下图:

EL3 负责负责安全监测和安全模式切换通过设定SCR寄存器中的安全状态位(NS bit)来实现的,通过触发安全监控模式调用(smc)切换到Monitor模式或EL3,
    并通过共享内存的方式将数据发送给安全世界状态来进行处理;

root@linux :/data/develop/root/android/rk/00_wst/u-boot# strings tools/rk_tools/bin/rk33/rk3399_bl31_v1.31.elf |grep arm_smc
arm_smccc_res

     参考函数reset: 

     switch_el x1, 3f, 2f, 1f

EL2 主要提供虚拟化支持;
EL1 能够执行一些特权指令,用于运行各类操作系统,在安全模式则是Trusted OS;
EL0 (Normal World) 用户的APP进程等;

5. _main: arch/arm/lib/crt0_64.S

ENTRY(_main)

/*
 * Set up initial C runtime environment and call board_init_f(0).
 */
	ldr	x0, =(CONFIG_SYS_INIT_SP_ADDR)
	sub	x0, x0, #GD_SIZE	/* allocate one GD above SP */
	bic	sp, x0, #0xf	/* 16-byte alignment for ABI compliance */
	mov	x18, sp			/* GD is above SP */
	mov	x0, #0
	bl	board_init_f 
    ..................
	/* call board_init_r(gd_t *id, ulong dest_addr) */
	mov	x0, x18				/* gd_t */
	ldr	x1, [x18, #GD_RELOCADDR]	/* dest_addr */
	b	board_init_r 

2.1.4  board_init_f 

   

   u-boot/lib/hang.c

 void hang(void)
 {
     bootstage_error(BOOTSTAGE_ID_NEED_RESET);
     for (;;)
         ;
 } 

 u-boot/lib/initcall.c

int initcall_run_list(const init_fnc_t init_sequence[])
{
	const init_fnc_t *init_fnc_ptr;

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		unsigned long reloc_ofs = 0;
		int ret;

		if (gd->flags & GD_FLG_RELOC)
			reloc_ofs = gd->reloc_off;
		debug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);
		if (gd->flags & GD_FLG_RELOC)
			debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);
		else
			debug("\n");
		ret = (*init_fnc_ptr)();
		if (ret) {
			printf("initcall sequence %p failed at call %p (err=%d)\n",
			       init_sequence,
			       (char *)*init_fnc_ptr - reloc_ofs, ret);
			return -1;
		}
	}
	return 0;
}

u-boot/common/board_f.c

void board_init_f(ulong boot_flags)
{
	gd->flags = boot_flags;
	gd->have_console = 0;
 
	if (initcall_run_list(init_sequence_f)) 
		hang(); 
}


/* 通过 hung() for 循环调用init_sequence_f 的函数指针 */
static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
	setup_ram_buf,
#endif
	setup_mon_len, /* 设置 monitor 长度 */
	setup_fdt,
#ifdef CONFIG_TRACE
	trace_early_init,
#endif
	initf_malloc,
	arch_cpu_init,		/* basic arch cpu dependent setup */
#endif
	mark_bootstage,
#ifdef CONFIG_OF_CONTROL
	fdtdec_check_fdt,
#endif
	initf_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
	/* TODO: can any of this go into arch_cpu_init()? */
#if defined(CONFIG_PPC) && !defined(CONFIG_8xx_CPUCLK_DEFAULT)
	get_clocks,		/* get CPU and bus clocks (etc.) */
#if defined(CONFIG_TQM8xxL) && !defined(CONFIG_TQM866M) \
		&& !defined(CONFIG_TQM885D)
	adjust_sdram_tbs_8xx,
#endif
	/* TODO: can we rename this to timer_init()? */
	init_timebase,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_BLACKFIN)
	timer_init,		/* initialize timer */
#endif
#ifdef CONFIG_SYS_ALLOC_DPRAM
#if !defined(CONFIG_CPM2)
	dpram_init,
#endif
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif
#ifdef CONFIG_FSL_ESDHC
	get_clocks,
#endif
	env_init,		/* initialize environment */
#if defined(CONFIG_8xx_CPUCLK_DEFAULT)
	/* get CPU and bus clocks according to the environment variable */
	get_clocks_866,
	/* adjust sdram refresh rate according to the new clock */
	sdram_adjust_866,
	init_timebase,
#endif
	init_baud_rate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
#ifdef CONFIG_SANDBOX
	sandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROL
	fdtdec_prepare_fdt,
#endif
	display_options,	/* say that we are here */
	display_text_info,	/* show debugging info if required */
#if defined(CONFIG_MPC8260)
	prt_8260_rsr,
	prt_8260_clks,
#endif /* CONFIG_MPC8260 */
#if defined(CONFIG_MPC83xx)
	prt_83xx_rsr,
#endif
#ifdef CONFIG_PPC
	checkcpu,
#endif
	print_cpuinfo,		/* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)
	prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)
	show_board_info,
#endif
	INIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)
	misc_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
	init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
	init_func_spi,
#endif
#ifdef CONFIG_X86
	dram_init_f,		/* configure available RAM banks */
	calculate_relocation_address,
#endif
	announce_dram_init,
	/* TODO: unify all these dram functions? */
#ifdef CONFIG_ARM
	dram_init,		/* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC)
	init_func_ram,
#endif
#ifdef CONFIG_POST
	post_init_f,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)
	testdram,
#endif /* CONFIG_SYS_DRAM_TEST */
	INIT_FUNC_WATCHDOG_RESET

#ifdef CONFIG_POST
	init_post,
#endif
	INIT_FUNC_WATCHDOG_RESET
	/*
	 * Now that we have DRAM mapped and working, we can
	 * relocate the code and continue running from DRAM.
	 *
	 * Reserve memory at end of RAM for (top down in that order):
	 *  - area that won't get touched by U-Boot and Linux (optional)
	 *  - kernel log buffer
	 *  - protected RAM
	 *  - LCD framebuffer
	 *  - monitor code
	 *  - board info struct
	 */
	setup_dest_addr,
#if defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2)
	/* Blackfin u-boot monitor should be on top of the ram */
	reserve_uboot,
#endif
#if defined(CONFIG_LOGBUFFER) && !defined(CONFIG_ALT_LB_ADDR)
	reserve_logbuffer,
#endif
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) && \
		defined(CONFIG_ARM)
	reserve_mmu,
#endif
#if defined(CONFIG_LCD) || defined(CONFIG_ROCKCHIP_DISPLAY)
	reserve_lcd,
#endif
#ifdef CONFIG_ROCKCHIP
	reserve_global_buffers,
#endif
	reserve_trace,
	/* TODO: Why the dependency on CONFIG_8xx? */
#if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) && \
		!defined(CONFIG_ARM) && !defined(CONFIG_X86) && \
		!defined(CONFIG_BLACKFIN)
	reserve_video,
#endif
#if !defined(CONFIG_BLACKFIN) && !defined(CONFIG_NIOS2)
	reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
	reserve_malloc,
	reserve_board,
#endif
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_stacks,
	setup_dram_config,
	show_dram_config,
#ifdef CONFIG_PPC
	setup_board_part1,
	INIT_FUNC_WATCHDOG_RESET
	setup_board_part2,
#endif
	display_new_sp,
#ifdef CONFIG_SYS_EXTBDINFO
	setup_board_extra,
#endif
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	setup_reloc,
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
	jump_to_copy,
#endif
	NULL,
};

2.1.5  board_init_r

u-boot/common/board_r.c

void board_init_r(gd_t *new_gd, ulong dest_addr)
{
	if (initcall_run_list(init_sequence_r))
		hang();

} 

init_fnc_t init_sequence_r[] = {
	initr_trace,
	initr_reloc,
	/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
	initr_caches,
#endif
	initr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
	initr_unlock_ram_in_cache,
#endif
	initr_barrier,
	initr_malloc,
	bootstage_relocate,
#ifdef CONFIG_DM
	initr_dm,
#endif
#ifdef CONFIG_ARM
	board_init,	/* Setup chipselects */
#endif
	/*
	 * 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
	stdio_init_tables,
	initr_serial,
	initr_announce,
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_PPC
	initr_trap,
#endif
#ifdef CONFIG_ADDR_MAP
	initr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)
	board_early_init_r,
#endif
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_LOGBUFFER
	initr_logbuffer,
#endif
#ifdef CONFIG_POST
	initr_post_backlog,
#endif
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_SYS_DELAYED_ICACHE
	initr_icache_enable,
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
	/*
	 * Do early PCI configuration _before_ the flash gets initialised,
	 * because PCU ressources are crucial for flash access on some boards.
	 */
	initr_pci,
#endif
#ifdef CONFIG_PPC
	initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
	initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
	initr_onenand,
#endif
#ifdef CONFIG_GENERIC_MMC
	initr_mmc,
#endif
#ifdef CONFIG_HAS_DATAFLASH
	initr_dataflash,
#endif
#ifdef CONFIG_ROCKCHIP
	initr_rk_storage,
#endif
	initr_env,
	INIT_FUNC_WATCHDOG_RESET
	initr_secondary_cpu,
#ifdef	CONFIG_HERMES
	initr_hermes,
#endif
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
	mac_read_from_eeprom,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
	/*
	 * Do pci configuration
	 */
	initr_pci,
#endif
	stdio_add_devices,
	initr_jumptable,
#ifdef CONFIG_API
	initr_api,
#endif
	console_init_r,		/* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
	show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
	arch_misc_init,		/* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_R
	misc_init_r,		/* miscellaneous platform-dependent init */
#endif
#ifdef CONFIG_HERMES
	initr_hermes_start,
#endif
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
	initr_kgdb,
#endif
#ifdef CONFIG_X86
	board_early_init_r,
#endif
	interrupt_init,
#if defined(CONFIG_ARM) || defined(CONFIG_x86)
	initr_enable_interrupts,
#endif
#ifdef CONFIG_X86
	timer_init,		/* initialize timer */
#endif
#if defined(CONFIG_STATUS_LED) && defined(STATUS_LED_BOOT)
	initr_status_led,
#endif
	/* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NET
	initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
	board_late_init,
#endif
#ifdef CONFIG_CMD_SCSI
	INIT_FUNC_WATCHDOG_RESET
	initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
	INIT_FUNC_WATCHDOG_RESET
	initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
	initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET
	INIT_FUNC_WATCHDOG_RESET
	initr_net,
#endif
#ifdef CONFIG_POST
	initr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
	initr_pcmcia,
#endif
#if defined(CONFIG_CMD_IDE)
	initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INIT
	INIT_FUNC_WATCHDOG_RESET
	/*
	 * Some parts can be only initialized if all others (like
	 * Interrupts) are up and running (i.e. the PC-style ISA
	 * keyboard).
	 */
	last_stage_init,
#endif
#ifdef CONFIG_CMD_BEDBUG
	INIT_FUNC_WATCHDOG_RESET
	initr_bedbug,
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
	initr_mem,
#endif
#ifdef CONFIG_ROCKCHIP
	rk_initr_serial,	/* YQ Add for serial-MM Boot */
#endif
#ifdef CONFIG_PS2KBD
	initr_kbd,
#endif
	run_main_loop,
};

root@chroot:~/android/rk/00_wst/u-boot# grep -rn rk_initr_serial
匹配到二进制文件 u-boot
System.map:495:0000000000216878 t rk_initr_serial

串口抓的启动log:

2.1.6  main_loop

static int run_main_loop(void)
{
	/* main_loop() can return to retry autoboot, if so just run it again */
	for (;;)
		main_loop();
	return 0;
}


void main_loop(void)
{
	const char *s;

	bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

#ifndef CONFIG_SYS_GENERIC_BOARD
	puts("Warning: Your board does not use generic board. Please read\n");
	puts("doc/README.generic-board and take action. Boards not\n");
	puts("upgraded by the late 2014 may break or be removed.\n");
#endif

	modem_init();
#ifdef CONFIG_VERSION_VARIABLE
	setenv("ver", version_string);  /* set version variable */
#endif /* CONFIG_VERSION_VARIABLE */

	cli_init();

	run_preboot_environment_command();

#if defined(CONFIG_UPDATE_TFTP)
	update_tftp(0UL);
#endif /* CONFIG_UPDATE_TFTP */

	s = bootdelay_process();
	if (cli_process_fdt(&s))
		cli_secure_boot_cmd(s);

	autoboot_command(s);

	cli_loop();
}

U_BOOT_CMD:

U_BOOT_CMD(
tftpboot, 3, 1, do_tftpb,
"boot image via network using TFTP protocol",
"[loadAddress] [[hostIPaddr:]bootfilename]"
);

2.1.7  reboot loader

kernel :

arch/arm64/boot/dts/rockchip/rk3399.dtsi

最后更新到寄存器中

uboot: board/rockchip/common/rkboot/fastboot.c

board_late_init()

   board_fbt_preboot()

       board_fbt_get_reboot_type()

enum fbt_reboot_type board_fbt_get_reboot_type(void)
{
	enum fbt_reboot_type frt = FASTBOOT_REBOOT_UNKNOWN;

	uint32_t loader_flag = IReadLoaderFlag();
	int reboot_mode = loader_flag ? (loader_flag & 0xFF) : BOOT_NORMAL;

	/* Feedback reboot mode to the kernel. */
	ISetLoaderFlag(SYS_KERNRL_REBOOT_FLAG | reboot_mode);


	if (SYS_LOADER_ERR_FLAG == loader_flag) {
		loader_flag = SYS_LOADER_REBOOT_FLAG | BOOT_LOADER;
		reboot_mode = BOOT_LOADER;
	}

	if ((loader_flag & 0xFFFFFF00) == SYS_LOADER_REBOOT_FLAG) {
		switch (reboot_mode) {
		case BOOT_NORMAL:
			printf("reboot normal.\n");
			frt = FASTBOOT_REBOOT_NORMAL;
			break;
		case BOOT_LOADER:
#ifdef CONFIG_CMD_ROCKUSB
			printf("reboot rockusb.\n");
			do_rockusb(NULL, 0, 0, NULL);
#endif
			break;
#ifdef CONFIG_CMD_FASTBOOT
		case BOOT_FASTBOOT:
			printf("reboot fastboot.\n");
			frt = FASTBOOT_REBOOT_FASTBOOT;
			break;
#endif
		case BOOT_NORECOVER:
			printf("reboot no recover.\n");
			frt = FASTBOOT_REBOOT_NORECOVER;
			break;
		case BOOT_RECOVER:
			printf("reboot recover.\n");
			frt = FASTBOOT_REBOOT_RECOVERY;
			break;
		case BOOT_WIPEDATA:
		case BOOT_WIPEALL:
			printf("reboot wipe data.\n");
			frt = FASTBOOT_REBOOT_RECOVERY_WIPE_DATA;
			break;
		case BOOT_CHARGING:
			printf("reboot charge.\n");
			frt = FASTBOOT_REBOOT_CHARGE;
			break;
		default:
			printf("unsupport reboot type %d\n", reboot_mode);
			break;
		}
	} else {
		printf("normal boot.\n");
	}

	/* Normal boot mode */
	if (reboot_mode == BOOT_NORMAL) {
#ifdef CONFIG_RK_SDCARD_BOOT_EN
		if (StorageSDCardUpdateMode()) {
			/* detect sd card update, audo entern recovery */
			frt = FASTBOOT_REBOOT_RECOVERY;
		}
#endif
#ifdef CONFIG_RK_UMS_BOOT_EN
		if (StorageUMSUpdateMode()) {
			/* detect ums update, audo entern recovery */
			frt = FASTBOOT_REBOOT_RECOVERY;
		}
#endif
	}

	return frt;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月上柳青

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值