TI OMAP平台BSP学习笔记之 - UBOOT(2)

TI OMAP 专栏收录该内容
7 篇文章 1 订阅

1. 代码流程分析

  1.     前面已经知道由于UBOOT同时编译两个镜像,代码有一部分重叠复用,需要关注CONFIG_SPL_BUILD宏控;
  2.     嵌入式中代码的逻辑通常是board->machine -> ARCH -> CPU,在UBOOT中的接口使用类似于重载的概念,使用WEAK修饰;比如在CPU定义一个API并用WEAK修饰,在board中可以重新定义该API并且覆盖前述API,而不会报错;
  3.     重点关注几个惯例API,如lowlevel_init, board_init_f, board_init_r等等;

    以编译am57xx_evm_config为例分析。首先看arch/arm/lib/Makefile

ifdef CONFIG_CPU_V7M
obj-y	+= vectors_m.o crt0.o
else ifdef CONFIG_ARM64
obj-y	+= crt0_64.o
else
obj-y	+= vectors.o crt0.o
endif

   我们并没有定义CONFIG_CPU_V7M,所以vectors.S和crt0.S被编译进我们的镜像;其中还会有ifndef CONFIG_SPL_BUILD的定义,即在UBOOT中才会被编译的镜像比如relocate等。而在ectors.S中会定义中断向量表,略过异常处理的中断处理暂不考虑,由于CONFIG_ARCH_K3没有定义,正常重启的处理是reset。

        .macro ARM_VECTORS
#ifdef CONFIG_ARCH_K3
	ldr     pc, _reset
#else
	b	reset
#endif
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
	.endm

    找到reset的定义,该代码入口位于 arch/arm/cpu/armv7/start.S,同样是查看其中的makefile

reset:
	/* Allow the board to save important registers */
	b	save_boot_params
save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE
/*
 * check for Hypervisor support
 */
	mrc	p15, 0, r0, c0, c1, 1		@ read ID_PFR1
	and	r0, r0, #CPUID_ARM_VIRT_MASK	@ mask virtualization bits
	cmp	r0, #(1 << CPUID_ARM_VIRT_SHIFT)
	beq	switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
	/*
	 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
	 * except if in HYP mode already
	 */
	mrs	r0, cpsr
	and	r1, r0, #0x1f		@ mask mode bits
	teq	r1, #0x1a		@ test for HYP mode
	bicne	r0, r0, #0x1f		@ clear all mode bits
	orrne	r0, r0, #0x13		@ set SVC mode
	orr	r0, r0, #0xc0		@ disable FIQ and IRQ
	msr	cpsr,r0

/*
 * Setup vector:
 * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
 * Continue to use ROM code vector only in OMAP4 spl)
 */
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
	/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
	mrc	p15, 0, r0, c1, c0, 0	@ Read CP15 SCTLR Register
	bic	r0, #CR_V		@ V = 0
	mcr	p15, 0, r0, c1, c0, 0	@ Write CP15 SCTLR Register

#ifdef CONFIG_HAS_VBAR
	/* Set vector address in CP15 VBAR register */
	ldr	r0, =_start
	mcr	p15, 0, r0, c12, c0, 0	@Set VBAR
#endif
#endif

	/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
#ifdef CONFIG_CPU_V7A
	bl	cpu_init_cp15
#endif
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
	bl	cpu_init_crit
#endif
#endif

	bl	_main
  1.   save_boot_params,保存ROM code中的parameters(有开机原因等);
  2.   switch_to_hypervisor, 切到hypervisor模式
  3.   cp15协处理器初始化,之后就可以使能MMU等功能;cpu_init_crit 初始化;这两个会调用到板级的定义中。在其中会调用lowlevel_init; lowlevel init设置临时stack,gdata 等;CONFIG_CPU_V7A被定义
  4.   bl _main

    前面的过程暂不具体学习,直接到_main函数,这时又回到crt0.S中; _main是一个通用函数,其中通过CONFIG_SPL_BUILD宏控区分SPL和UBOOT。

    头文件定义include/config.h

/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/ti/am57xx
#include <config_defaults.h>
#include <config_uncmd_spl.h>
#include <configs/am57xx_evm.h>
#include <asm/config.h>
#include <linux/kconfig.h>
#include <config_fallbacks.h>

    _main最开始的部分:

    调用 board_init_f_alloc_reserve 和 board_init_f_init_reserve 分配并初始化GD; 设置堆栈等C环境,并最终从汇编世界切到C的世界。关于GD,global data,在系统启动的最开始阶段,有些机器是从FLASH启动的,只能执行而不写数据,所以一般需要再SRAM上分配一个全局的地址来保存全局数据比如重定向的信息等等,这些信息在以后程序在DRAM中运行时需要用到所以需要处理好这段数据。

TODO: header files generation and specifications of asm code

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
	ldr	r0, =(CONFIG_SPL_STACK)
#else
	ldr	r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
	bic	r0, r0, #7	/* 8-byte alignment for ABI compliance */
	mov	sp, r0
	bl	board_init_f_alloc_reserve
	mov	sp, r0
	/* set up gd here, outside any C code */
	mov	r9, r0
	bl	board_init_f_init_reserve

	mov	r0, #0
	bl	board_init_f

    然后跳转到board_init_f执行;到board_init_f为止,SPL和UBOOT运行的代码差不多是相同的。但是后面的代码则通过CONFIG_SPL_BUILD宏控控制,SPL和UBOOT的代码会有差异。同时,对于同一个函数比如board_init_f和board_init_r来说,SPL和UBOOT也不是同样的函数。 查看common/Makefile;SPL的board_init_f实现在arch/arm/mach-omap2/hwinit-common.c中; 查看Makefile文件, uboot的board_init_f实现在common/board_f.c中。

   只看SPL,hwinit-common.c被编译入镜像。

obj-$(CONFIG_OMAP54XX) += omap5/
...
ifneq ($(CONFIG_OMAP44XX)$(CONFIG_OMAP54XX),)
obj-y	+= hwinit-common.o
obj-y	+= clocks-common.o
obj-y	+= emif-common.o
obj-y	+= vc.o
obj-y	+= abb.o
endif
...
obj-y	+= boot-common.o
obj-y	+= lowlevel_init.o

    对应的代码如下, 出后初始化SDRAM,就退出了;

#ifdef CONFIG_SPL_BUILD
void board_init_f(ulong dummy)
{
	early_system_init();
#ifdef CONFIG_BOARD_EARLY_INIT_F
	board_early_init_f();
#endif
	/* For regular u-boot sdram_init() is called from dram_init() */
	sdram_init();
	gd->ram_size = omap_sdram_size();
}
#endif

    在early_system_init中通过init_omap_revision读取ID寄存器,确定IC的版本,后面的初识话将用到这个版本信息;初始化watchdog、mux相关寄存器、GPIO、时钟等,保存boot_parameters,board_detect等。

void early_system_init(void)
{
	init_omap_revision();
	hw_data_init();
	init_package_revision();

#ifdef CONFIG_SPL_BUILD
	if (warm_reset())
		force_emif_self_refresh();
#endif
	watchdog_init();
	set_mux_conf_regs();
#ifdef CONFIG_SPL_BUILD
	srcomp_enable();
	do_io_settings();
#endif
	setup_early_clocks();
#ifdef CONFIG_SPL_BUILD
	/*
	 * Save the boot parameters passed from romcode.
	 * We cannot delay the saving further than this,
	 * to prevent overwrites.
	 */
	save_omap_boot_params();
#endif
	do_board_detect();
#ifdef CONFIG_SPL_BUILD
	spl_early_init();
#endif
	vcores_init();
#ifdef CONFIG_DEBUG_UART_OMAP
	debug_uart_init();
#endif
	prcm_init();
}

    回到crt0.S中,由于我们定义了 CONFIG_SPL_FRAMEWORK,所以 ldr    pc, =board_init_r    /* this is auto-relocated! */会被执行,于是:

libs-$(CONFIG_SPL_FRAMEWORK) += common/spl/
libs-y += common/init/

    其中的spl.c里面board_init_r最终加载镜像,跳转到镜像运行;通常来说这里的镜像就是UBOOT。UBOOT的流程和SPL类似,只是两个函数的实现不同。

2. Board detect

    以上过程有需要时再深入学习,这里直接看board detect代码。在TI开发板有很多系列,我们通过IC的版本信息和Board的版本信息能知道当前运行的硬件信息,这样多个硬件可以共用同一个代码基线。Board的信息保存在eeprom中,生产时写入信息,在SPL启动时通过I2C读取这些信息。读取函数在board/ti/am57xx/board.c当中,具体实现在board_detect.c中。无论是SPL还是UBOOT调用相同的ti_i2c_eeprom_am_get函数(这个函数是对AMxx系列开发板的读取接口,其它系列接口不同)

#ifdef CONFIG_SPL_BUILD
/* No env to setup for SPL */
static inline void setup_board_eeprom_env(void) { }

/* Override function to read eeprom information */
void do_board_detect(void)
{
	int rc;

	rc = ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
				  CONFIG_EEPROM_CHIP_ADDRESS);
	if (rc)
		printf("ti_i2c_eeprom_init failed %d\n", rc);
}

#else	/* CONFIG_SPL_BUILD */

/* Override function to read eeprom information: actual i2c read done by SPL*/
void do_board_detect(void)
{
	char *bname = NULL;
	int rc;

	rc = ti_i2c_eeprom_am_get(CONFIG_EEPROM_BUS_ADDRESS,
				  CONFIG_EEPROM_CHIP_ADDRESS);
	if (rc)
		printf("ti_i2c_eeprom_init failed %d\n", rc);

	if (board_is_x15())
		bname = "BeagleBoard X15";
	else if (board_is_am572x_evm())
		bname = "AM572x EVM";
	else if (board_is_am574x_idk())
		bname = "AM574x IDK";
	else if (board_is_am572x_idk())
		bname = "AM572x IDK";
	else if (board_is_am571x_idk())
		bname = "AM571x IDK";

	if (bname)
		snprintf(sysinfo.board_string, SYSINFO_BOARD_NAME_MAX_LEN,
			 "Board: %s REV %s\n", bname, board_ti_get_rev());
}

E2PROM中的数据格式为ti_am_eeprom

struct ti_am_eeprom {
	unsigned int header;
	char name[TI_EEPROM_HDR_NAME_LEN];
	char version[TI_EEPROM_HDR_REV_LEN];
	char serial[TI_EEPROM_HDR_SERIAL_LEN];
	char config[TI_EEPROM_HDR_CONFIG_LEN];
	char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
} __attribute__ ((__packed__));

    但无论哪个系列,从E2PROM读取的数据,最终要转换为这个通用的结构体;以便于后面的使用。

struct ti_common_eeprom {
	u32 header;
	char name[TI_EEPROM_HDR_NAME_LEN + 1];
	char version[TI_EEPROM_HDR_REV_LEN + 1];
	char serial[TI_EEPROM_HDR_SERIAL_LEN + 1];
	char config[TI_EEPROM_HDR_CONFIG_LEN + 1];
	char mac_addr[TI_EEPROM_HDR_NO_OF_MAC_ADDR][TI_EEPROM_HDR_ETH_ALEN];
	u64 emif1_size;
	u64 emif2_size;
};

    当这些信息被设置之后(在TI_EEPROM_DATA当中),其它模块如果需要获取这些信息,可以通过提供的接口,如get和is_xx等。

bool __maybe_unused board_ti_is(char *name_tag);
bool __maybe_unused board_ti_rev_is(char *rev_tag, int cmp_len);
char * __maybe_unused board_ti_get_rev(void);
char * __maybe_unused board_ti_get_config(void);
char * __maybe_unused board_ti_get_name(void);
void __maybe_unused
board_ti_get_eth_mac_addr(int index,
			  u8 mac_addr[TI_EEPROM_HDR_ETH_ALEN]);
u64 __maybe_unused board_ti_get_emif1_size(void);
u64 __maybe_unused board_ti_get_emif2_size(void);
void __maybe_unused set_board_info_env(char *name);
void board_ti_set_ethaddr(int index);
bool __maybe_unused board_ti_was_eeprom_read(void);

    board的信息主要是控制代码流程,使得同一套代码可以支持多个board,下一节学习uboot时会看到一个例子。

3. UBOOT

    第一节中知道无论是SPL还是UBOOT最后都会执行board_init_f这个函数。这一节中简单学习UBOOT中的大概流程,首先找到该函数的调用,如下,即顺序执行init_sequence_f中定义的函数列表,如果出错则hang住(下面两个hang注意第二个被宏控控制,在ARM平台上不会有第二个hang)。

void board_init_f(ulong boot_flags)
{
	gd->flags = boot_flags;
	gd->have_console = 0;

	if (initcall_run_list(init_sequence_f))
		hang();

#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!defined(CONFIG_EFI_APP) && !CONFIG_IS_ENABLED(X86_64)
	/* NOTREACHED - jump_to_copy() does not return */
	hang();
#endif
}

    这些函数列表如下。最后一个函数为static int jump_to_copy(void),但实际上被宏控控制,ARM平台上并没有执行,最终会执行前述的board_init_r。

static const init_fnc_t init_sequence_f[] = {
	setup_mon_len,
#ifdef CONFIG_OF_CONTROL
	fdtdec_setup,
#endif
#ifdef CONFIG_TRACE
	trace_early_init,
#endif
	initf_malloc,
	log_init,
	initf_bootstage,	/* uses its own timer, so does not need DM */
	initf_console_record,
#if defined(CONFIG_HAVE_FSP)
	arch_fsp_init,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	mach_cpu_init,		/* SoC/machine dependent CPU setup */
	initf_dm,
	arch_cpu_init_dm,
#if defined(CONFIG_BOARD_EARLY_INIT_F)
	board_early_init_f,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
	/* get CPU and bus clocks according to the environment variable */
	get_clocks,		/* get CPU and bus clocks (etc.) */
#endif
#if !defined(CONFIG_M68K)
	timer_init,		/* initialize timer */
#endif
#if defined(CONFIG_BOARD_POSTCLK_INIT)
	board_postclk_init,
#endif
	env_init,		/* initialize environment */
	init_baud_rate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_options,	/* say that we are here */
	display_text_info,	/* show debugging info if required */
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SH) || \
		defined(CONFIG_X86)
	checkcpu,
#endif
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DTB_RESELECT)
	embedded_dtb_select,
#endif
#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_SYS_I2C)
	init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)
	init_func_spi,
#endif
	announce_dram_init,
	dram_init,		/* configure available RAM banks */
#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,
#ifdef CONFIG_PRAM
	reserve_pram,
#endif
	reserve_round_4k,
#ifdef CONFIG_ARM
	reserve_mmu,
#endif
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,
	show_dram_config,
#if defined(CONFIG_M68K) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
	defined(CONFIG_SH)
	setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
	INIT_FUNC_WATCHDOG_RESET
	setup_board_part2,
#endif
	display_new_sp,
#ifdef CONFIG_OF_BOARD_FIXUP
	fix_fdt,
#endif
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	reloc_bootstage,
	setup_reloc,
#if defined(CONFIG_X86) || defined(CONFIG_ARC)
	copy_uboot_to_ram,
	do_elf_reloc_fixups,
	clear_bss,
#endif
#if defined(CONFIG_XTENSA)
	clear_bss,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX) && \
		!CONFIG_IS_ENABLED(X86_64)
	jump_to_copy,
#endif
	NULL,
};

    board_init_r的过程和f类似,也是处理函数列表。它位于common/board_r.c文件中。

	if (initcall_run_list(init_sequence_r))
		hang();

    rear的函数列表如下,最终运行main_loop,会超时几秒钟等到用户按键,如果没有按键则转入到HLOS如linux中运行。

static init_fnc_t init_sequence_r[] = {
	initr_trace,
	initr_reloc,
	/* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
	initr_caches,
	/* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
	 *	 A temporary mapping of IFC high region is since removed,
	 *	 so environmental variables in NOR flash is not availble
	 *	 until board_init() is called below to remap IFC to high
	 *	 region.
	 */
#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,
	log_init,
	initr_bootstage,	/* Needs malloc() but has its own timer */
	initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
	initr_noncached,
#endif
	bootstage_relocate,
#ifdef CONFIG_OF_LIVE
	initr_of_live,
#endif
#ifdef CONFIG_DM
	initr_dm,
#endif
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
	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
#ifdef CONFIG_EFI_LOADER
	efi_memory_init,
#endif
	stdio_init_tables,
	initr_serial,
	initr_announce,
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOC
	initr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
	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_POST
	initr_post_backlog,
#endif
	INIT_FUNC_WATCHDOG_RESET
#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_ARCH_EARLY_INIT_R
	arch_early_init_r,
#endif
	power_init_board,
#ifdef CONFIG_MTD_NOR_FLASH
	initr_flash,
#endif
	INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86)
	/* initialize higher level parts of CPU like time base and timers */
	cpu_init_r,
#endif
#ifdef CONFIG_PPC
	initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
	initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
	initr_onenand,
#endif
#ifdef CONFIG_MMC
	initr_mmc,
#endif
	initr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LEN
	initr_malloc_bootparams,
#endif
	INIT_FUNC_WATCHDOG_RESET
	initr_secondary_cpu,
#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
	console_announce_r,
	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
	INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
	initr_kgdb,
#endif
	interrupt_init,
#ifdef CONFIG_ARM
	initr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_M68K)
	timer_init,		/* initialize timer */
#endif
#if defined(CONFIG_LED_STATUS)
	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
#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI)
	INIT_FUNC_WATCHDOG_RESET
	initr_scsi,
#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_IDE)
	initr_pcmcia,
#endif
#if defined(CONFIG_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)
	initr_mem,
#endif
#ifdef CONFIG_PS2KBD
	initr_kbd,
#endif
	run_main_loop,
};

3.1 常见bootargs

 

3.2 TI平台如何解析uEnv.txt

 

3.3 常见的command

 

 

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论
请先登录 后发表评论~
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页

打赏作者

佛系代码阅读家

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值