3、u-boot-2016 - board_init_f

i.MX6Q - u-boot_2016

飞凌嵌入式开发板 OKMX6Q_C 1G-DDR, 8G-EMMC版本。

board_init_f

原型:void board_init_f(ulong boot_flags)
路径:common/board_f.c
void board_init_f(ulong boot_flags)
{
#ifdef CONFIG_SYS_GENERIC_GLOBAL_DATA
	/*
	 * For some archtectures, global data is initialized and used before
	 * calling this function. The data should be preserved. For others,
	 * CONFIG_SYS_GENERIC_GLOBAL_DATA should be defined and use the stack
	 * here to host global data until relocation.
	 */
	gd_t data;

	gd = &data;

	/*
	 * Clear global data before it is accessed at debug print
	 * in initcall_run_list. Otherwise the debug print probably
	 * get the wrong vaule of gd->have_console.
	 */
	zero_global_data();
#endif

	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)
	/* NOTREACHED - jump_to_copy() does not return */
	hang();
#endif
}

这里未定义宏CONFIG_SYS_GENERIC_GLOBAL_DATA,所以 board_init_f 函数可以简化为如下:

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

	if (initcall_run_list(init_sequence_f))
		hang();
}

在调用board_init_f函数前,执行了mov r0, #0。所以 boot_flags 为0。
所以,board_init_f 函数的作用:

  • 1、对global_data 结构体的flags 和have_console 赋值,且都是0。
    flags的含义暂不祥,have_console == 0说明此时还没有控制台可用来打印输出。
  • 2、init_sequence_f 是一个函数指针数组,initcall_run_list 的作用就是执行这些函数指针。

一、initcall_run_list

// lib/initcall.c
DECLARE_GLOBAL_DATA_PTR;

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;
#ifdef CONFIG_EFI_APP
		reloc_ofs = (unsigned long)image_base;
#endif
		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;
}
先不看debug信息,函数可简化为:
// lib/initcall.c
DECLARE_GLOBAL_DATA_PTR;

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;

		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;
}

可以看出 initcall_run_list 内部就是用一个for循环执行函数指针数组。

二、init_sequence_f

函数数组init_sequence_f,定义如下:

static init_fnc_t init_sequence_f[] = {
#ifdef CONFIG_SANDBOX
	setup_ram_buf,
#endif
	setup_mon_len,
#ifdef CONFIG_OF_CONTROL
	fdtdec_setup,
#endif
#ifdef CONFIG_TRACE
	trace_early_init,
#endif
	initf_malloc,
	initf_console_record,
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
	/* TODO: can this go into arch_cpu_init()? */
	probecpu,
#endif
#if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP)
	x86_fsp_init,
#endif
	arch_cpu_init,		/* basic arch cpu dependent setup */
	initf_dm,
	arch_cpu_init_dm,
	mark_bootstage,		/* need timer, go after init 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) || defined(CONFIG_NDS32) || \
		defined(CONFIG_SPARC)
	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
#if defined(CONFIG_SYS_FSL_CLK) || defined(CONFIG_M68K)
	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
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
	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
	announce_dram_init,
	/* TODO: unify all these dram functions? */
#if defined(CONFIG_ARM) || defined(CONFIG_X86) || defined(CONFIG_NDS32) || \
		defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32)
	dram_init,		/* configure available RAM banks */
#endif
#if defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_M68K)
	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)
	/* Blackfin u-boot monitor should be on top of the ram */
	reserve_uboot,
#endif
#if defined(CONFIG_SPARC)
	reserve_prom,
#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
#ifdef CONFIG_DM_VIDEO
	reserve_video,
#else
# ifdef CONFIG_LCD
	reserve_lcd,
# endif
	/* 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) && !defined(CONFIG_M68K)
	reserve_legacy_video,
# endif
#endif /* CONFIG_DM_VIDEO */
	reserve_trace,
#if !defined(CONFIG_BLACKFIN)
	reserve_uboot,
#endif
#ifndef CONFIG_SPL_BUILD
	reserve_malloc,
	reserve_board,
#endif
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_arch,
	reserve_stacks,
	setup_dram_config,
	show_dram_config,
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
	setup_board_part1,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
	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_X86) || defined(CONFIG_ARC)
	copy_uboot_to_ram,
	clear_bss,
	do_elf_reloc_fixups,
#endif
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)
	jump_to_copy,
#endif
	NULL,
};
针对imx6q平台对数组预处理:
static init_fnc_t init_sequence_f[] = {
	setup_mon_len,
	initf_malloc,
	initf_console_record,
	arch_cpu_init,		/* basic arch cpu dependent setup */
	initf_dm,
	arch_cpu_init_dm,
	mark_bootstage,		/* need timer, go after init dm */
	board_early_init_f,
	timer_init,		/* initialize timer */
	board_postclk_init,
	get_clocks,
	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 */
	print_cpuinfo,		/* display cpu info (and speed) */
	show_board_info,
	init_func_i2c,
	announce_dram_init,
	dram_init,		/* configure available RAM banks */
	setup_dest_addr,
	reserve_round_4k,
	reserve_mmu,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	setup_machine,
	reserve_global_data,
	reserve_fdt,
	reserve_arch,
	reserve_stacks,
	setup_dram_config,
	show_dram_config,
	display_new_sp,
	reloc_fdt,
	setup_reloc,
	NULL,
};
  • 1、setup_mon_len

    static int setup_mon_len(void)
    {
    #if defined(__ARM__) || defined(__MICROBLAZE__)
    	gd->mon_len = (ulong)&__bss_end - (ulong)_start;
    #elif defined(CONFIG_SANDBOX) || defined(CONFIG_EFI_APP)
    	gd->mon_len = (ulong)&_end - (ulong)_init;
    #elif defined(CONFIG_BLACKFIN) || defined(CONFIG_NIOS2)
    	gd->mon_len = CONFIG_SYS_MONITOR_LEN;
    #elif defined(CONFIG_NDS32)
    	gd->mon_len = (ulong)(&__bss_end) - (ulong)(&_start);
    #else
    	/* TODO: use (ulong)&__bss_end - (ulong)&__text_start; ? */
    	gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
    #endif
    	return 0;
    }
    

    预处理后代码如下:

    static int setup_mon_len(void)
    {
    	gd->mon_len = (ulong)&__bss_end - (ulong)_start;
    	return 0;
    }
    

    初始化了全局变量gd的mon_len值,结构体定义的注释 /* monitor len */,个人理解就是整个程序空间的大小。

  • 2、initf_malloc

    // common/dlmalloc.c
    int initf_malloc(void)
    {
    #ifdef CONFIG_SYS_MALLOC_F_LEN
    	assert(gd->malloc_base);	/* Set up by crt0.S */
    	gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;
    	gd->malloc_ptr = 0;
    #endif
    	return 0;
    }
    

    初始化了全局变量gd的malloc_limit(limit address)就是堆的长度 和malloc_ptr(current address)。

  • 3、initf_console_record

    static int initf_console_record(void)
    {
    #if defined(CONFIG_CONSOLE_RECORD) && defined(CONFIG_SYS_MALLOC_F_LEN)
    	return console_record_init();
    #else
    	return 0;
    #endif
    }
    

    CONFIG_CONSOLE_RECORD 未定义,所以函数initf_console_record为空。

  • 4、arch_cpu_init

    // arch/arm/cpu/armv7/mx6/soc.c
    int arch_cpu_init(void)
    {
    	if (!is_cpu_type(MXC_CPU_MX6SL) && !is_cpu_type(MXC_CPU_MX6SX)
    		&& !is_cpu_type(MXC_CPU_MX6UL) && !is_cpu_type(MXC_CPU_MX6ULL)
    		&& !is_cpu_type(MXC_CPU_MX6SLL)) {
    		/*
    		* imx6sl doesn't have pcie at all.
    		* this bit is not used by imx6sx anymore
    		*/
    		u32 val;
    
    		/*
    		* There are about 0.02% percentage, random pcie link down
    		* when warm-reset is used.
    		* clear the ref_ssp_en bit16 of gpr1 to workaround it.
    		* then warm-reset imx6q/dl/solo again.
    		*/
    		val = readl(IOMUXC_BASE_ADDR + 0x4);
    		if (val & (0x1 << 16)) {
    			val &= ~(0x1 << 16);
    			writel(val, IOMUXC_BASE_ADDR + 0x4);
    			reset_cpu(0);
    		}
    	}
    
    	init_aips();
    
    	/* Need to clear MMDC_CHx_MASK to make warm reset work. */
    	clear_mmdc_ch_mask();
    
    	/*
    	* Disable self-bias circuit in the analog bandap.
    	* The self-bias circuit is used by the bandgap during startup.
    	* This bit should be set after the bandgap has initialized.
    	*/
    	init_bandgap();
    
    	if (!is_cpu_type(MXC_CPU_MX6UL) && !is_cpu_type(MXC_CPU_MX6ULL)) {
    		/*
    		* When low freq boot is enabled, ROM will not set AHB
    		* freq, so we need to ensure AHB freq is 132MHz in such
    		* scenario.
    		*/
    		if (mxc_get_clock(MXC_ARM_CLK) == 396000000)
    			set_ahb_rate(132000000);
    	}
    
    	if (is_cpu_type(MXC_CPU_MX6UL)) {
    		if (is_soc_rev(CHIP_REV_1_0)) {
    			/*
    			* According to the design team's requirement on i.MX6UL,
    			* the PMIC_STBY_REQ PAD should be configured as open
    			* drain 100K (0x0000b8a0).
    			*/
    			writel(0x0000b8a0, IOMUXC_BASE_ADDR + 0x29c);
    		} else {
    			/*
    			* From TO1.1, SNVS adds internal pull up control for POR_B,
    			* the register filed is GPBIT[1:0], after system boot up,
    			* it can be set to 2b'01 to disable internal pull up.
    			* It can save about 30uA power in SNVS mode.
    			*/
    			writel((readl(MX6UL_SNVS_LP_BASE_ADDR + 0x10) & (~0x1400)) | 0x400,
    				MX6UL_SNVS_LP_BASE_ADDR + 0x10);
    		}
    	}
    
    	if (is_cpu_type(MXC_CPU_MX6ULL)) {
    		/*
    		* GPBIT[1:0] is suggested to set to 2'b11:
    		* 2'b00 : always PUP100K
    		* 2'b01 : PUP100K when PMIC_ON_REQ or SOC_NOT_FAIL
    		* 2'b10 : always disable PUP100K
    		* 2'b11 : PDN100K when SOC_FAIL, PUP100K when SOC_NOT_FAIL
    		* register offset is different from i.MX6UL, since
    		* i.MX6UL is fixed by ECO.
    		*/
    		writel(readl(MX6UL_SNVS_LP_BASE_ADDR) |
    			0x3, MX6UL_SNVS_LP_BASE_ADDR);
    	}
    
    		/* Set perclk to source from OSC 24MHz */
    #if defined(CONFIG_MX6SL)
    	set_preclk_from_osc();
    #endif
    
    	if (is_cpu_type(MXC_CPU_MX6SX))
    		set_uart_from_osc();
    
    	imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */
    
    	if (!is_cpu_type(MXC_CPU_MX6SL) && !is_cpu_type(MXC_CPU_MX6UL) &&
    		!is_cpu_type(MXC_CPU_MX6ULL) && !is_cpu_type(MXC_CPU_MX6SLL))
    		imx_set_pcie_phy_power_down();
    
    	if (!is_mx6dqp() && !is_cpu_type(MXC_CPU_MX6UL) &&
    		!is_cpu_type(MXC_CPU_MX6ULL) && !is_cpu_type(MXC_CPU_MX6SLL))
    		imx_set_vddpu_power_down();
    
    #ifdef CONFIG_APBH_DMA
    	/* Start APBH DMA */
    	mxs_dma_init();
    #endif
    
    	init_src();
    
    	if (is_mx6dqp())
    		writel(0x80000201, 0xbb0608);
    
    	return 0;
    }
    

    arch_cpu_init是跟CPU架构严格相关的函数,一般是由芯片官方提供。 不同的芯片,这块内容不一样。
    这里只是记录过程,不去追究细节。

    • 4.1、init_aips

      void init_aips(void)
      {
      	struct aipstz_regs *aips1, *aips2, *aips3;
      
      	aips1 = (struct aipstz_regs *)AIPS1_BASE_ADDR;
      	aips2 = (struct aipstz_regs *)AIPS2_BASE_ADDR;
      	aips3 = (struct aipstz_regs *)AIPS3_BASE_ADDR;
      
      	/*
      	 * Set all MPROTx to be non-bufferable, trusted for R/W,
      	 * not forced to user-mode.
      	 */
      	writel(0x77777777, &aips1->mprot0);
      	writel(0x77777777, &aips1->mprot1);
      	writel(0x77777777, &aips2->mprot0);
      	writel(0x77777777, &aips2->mprot1);
      
      	/*
      	 * Set all OPACRx to be non-bufferable, not require
      	 * supervisor privilege level for access,allow for
      	 * write access and untrusted master access.
      	 */
      	writel(0x00000000, &aips1->opacr0);
      	writel(0x00000000, &aips1->opacr1);
      	writel(0x00000000, &aips1->opacr2);
      	writel(0x00000000, &aips1->opacr3);
      	writel(0x00000000, &aips1->opacr4);
      	writel(0x00000000, &aips2->opacr0);
      	writel(0x00000000, &aips2->opacr1);
      	writel(0x00000000, &aips2->opacr2);
      	writel(0x00000000, &aips2->opacr3);
      	writel(0x00000000, &aips2->opacr4);
      
      	if (is_cpu_type(MXC_CPU_MX6ULL) || is_cpu_type(MXC_CPU_MX6SX) ||
      	    is_soc_type(MXC_SOC_MX7)) {
      		/*
      		 * Set all MPROTx to be non-bufferable, trusted for R/W,
      		 * not forced to user-mode.
      		 */
      		writel(0x77777777, &aips3->mprot0);
      		writel(0x77777777, &aips3->mprot1);
      
      		/*
      		 * Set all OPACRx to be non-bufferable, not require
      		 * supervisor privilege level for access,allow for
      		 * write access and untrusted master access.
      		 */
      		writel(0x00000000, &aips3->opacr0);
      		writel(0x00000000, &aips3->opacr1);
      		writel(0x00000000, &aips3->opacr2);
      		writel(0x00000000, &aips3->opacr3);
      		writel(0x00000000, &aips3->opacr4);
      	}
      }
      
    • 4.2、clear_mmdc_ch_mask

      static void clear_mmdc_ch_mask(void)
      {
      	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
      	u32 reg;
      	reg = readl(&mxc_ccm->ccdr);
      
      	/* Clear MMDC channel mask */
      	if (is_cpu_type(MXC_CPU_MX6SX) || is_cpu_type(MXC_CPU_MX6UL) ||
      	    is_cpu_type(MXC_CPU_MX6SL) || is_cpu_type(MXC_CPU_MX6ULL) ||
      	    is_cpu_type(MXC_CPU_MX6SLL))
      		reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK);
      	else
      		reg &= ~(MXC_CCM_CCDR_MMDC_CH1_HS_MASK | MXC_CCM_CCDR_MMDC_CH0_HS_MASK);
      	writel(reg, &mxc_ccm->ccdr);
      }
      
    • 4.3、init_bandgap

      static void init_bandgap(void)
      {
      	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
      	struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
      	struct fuse_bank *bank = &ocotp->bank[1];
      	struct fuse_bank1_regs *fuse =
      		(struct fuse_bank1_regs *)bank->fuse_regs;
      	uint32_t val;
      
      	/*
      	 * Ensure the bandgap has stabilized.
      	 */
      	while (!(readl(&anatop->ana_misc0) & 0x80))
      		;
      	/*
      	 * For best noise performance of the analog blocks using the
      	 * outputs of the bandgap, the reftop_selfbiasoff bit should
      	 * be set.
      	 */
      	writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
      	/*
      	 * On i.MX6ULL,we need to set VBGADJ bits according to the
      	 * REFTOP_TRIM[3:0] in fuse table
      	 *	000 - set REFTOP_VBGADJ[2:0] to 3b'110,
      	 *	110 - set REFTOP_VBGADJ[2:0] to 3b'000,
      	 *	001 - set REFTOP_VBGADJ[2:0] to 3b'001,
      	 *	010 - set REFTOP_VBGADJ[2:0] to 3b'010,
      	 *	011 - set REFTOP_VBGADJ[2:0] to 3b'011,
      	 *	100 - set REFTOP_VBGADJ[2:0] to 3b'100,
      	 *	101 - set REFTOP_VBGADJ[2:0] to 3b'101,
      	 *	111 - set REFTOP_VBGADJ[2:0] to 3b'111,
      	 */
      	if (is_cpu_type(MXC_CPU_MX6ULL)) {
      		val = readl(&fuse->mem0);
      		val >>= OCOTP_MEM0_REFTOP_TRIM_SHIFT;
      		val &= 0x7;
      
      		writel(val << BM_ANADIG_ANA_MISC0_REFTOP_VBGADJ_SHIFT,
      		       &anatop->ana_misc0_set);
      	}
      }
      
    • 4.4、mxs_dma_init

      void mxs_dma_init(void)
      {
      	struct mxs_apbh_regs *apbh_regs =
      		(struct mxs_apbh_regs *)MXS_APBH_BASE;
      
      #ifdef CONFIG_MX6
      	if (check_module_fused(MX6_MODULE_APBHDMA)) {
      		printf("NAND APBH-DMA@0x%x is fused, disable it\n",
      			MXS_APBH_BASE);
      		return;
      	}
      #endif
      
      	mxs_reset_block(&apbh_regs->hw_apbh_ctrl0_reg);
      
      #ifdef CONFIG_APBH_DMA_BURST8
      	writel(APBH_CTRL0_AHB_BURST8_EN,
      		&apbh_regs->hw_apbh_ctrl0_set);
      #else
      	writel(APBH_CTRL0_AHB_BURST8_EN,
      		&apbh_regs->hw_apbh_ctrl0_clr);
      #endif
      
      #ifdef CONFIG_APBH_DMA_BURST
      	writel(APBH_CTRL0_APB_BURST_EN,
      		&apbh_regs->hw_apbh_ctrl0_set);
      #else
      	writel(APBH_CTRL0_APB_BURST_EN,
      		&apbh_regs->hw_apbh_ctrl0_clr);
      #endif
      }
      
    • 4.5、init_src

      void init_src(void)
      {
      	struct src *src_regs = (struct src *)SRC_BASE_ADDR;
      	u32 val;
      
      	/*
      	 * force warm reset sources to generate cold reset
      	 * for a more reliable restart
      	 */
      	val = readl(&src_regs->scr);
      	val &= ~(1 << SRC_SCR_WARM_RESET_ENABLE);
      	writel(val, &src_regs->scr);
      }
      
  • 5、initf_dm

    static int initf_dm(void)
    {
    #if defined(CONFIG_DM) && defined(CONFIG_SYS_MALLOC_F_LEN)
    	int ret;
    
    	ret = dm_init_and_scan(true);
    	if (ret)
    		return ret;
    #endif
    #ifdef CONFIG_TIMER_EARLY
    	ret = dm_timer_init();
    	if (ret)
    		return ret;
    #endif
    
    	return 0;
    }
    

    这里定义了CONFIG_DM和CONFIG_SYS_MALLOC_F_LEN,未定义CONFIG_TIMER_EARLY。

    • dm_init_and_scan
  • 6、arch_cpu_init_dm

    __weak int arch_cpu_init_dm(void)
    {
    	return 0;
    }
    

    该函数为空。

  • 7、mark_bootstage

    /* Record the board_init_f() bootstage (after arch_cpu_init()) */
    static int mark_bootstage(void)
    {
    	bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
    	return 0;
    }
    

    该函数记录了启动阶段。

  • 8、board_early_init_f

    // board/freescale/mx6sabresd/mx6sabresd.c
    int board_early_init_f(void)
    {
    		setup_iomux_uart();
    #if defined(CONFIG_VIDEO_IPUV3)
    		setup_display();
    #endif
    		return 0;
    }
    
  • 9、timer_init

    // arch/arm/imx-common/timer.c
    int timer_init(void)
    {
    	int i;
    
    	/* setup GP Timer 1 */
    	__raw_writel(GPTCR_SWR, &cur_gpt->control);
    
    	/* We have no udelay by now */
    	for (i = 0; i < 100; i++)
    		__raw_writel(0, &cur_gpt->control);
    
    	i = __raw_readl(&cur_gpt->control);
    	i &= ~GPTCR_CLKSOURCE_MASK;
    
    #ifdef CONFIG_MXC_GPT_HCLK
    	if (gpt_has_clk_source_osc()) {
    		i |= GPTCR_CLKSOURCE_OSC | GPTCR_TEN;
    
    		/* For DL/S, SX, UL, ULL set 24Mhz OSC Enable bit and prescaler */
    		if (is_cpu_type(MXC_CPU_MX6DL) ||
    			is_cpu_type(MXC_CPU_MX6SOLO) ||
    			is_cpu_type(MXC_CPU_MX6SX) ||
    			is_cpu_type(MXC_CPU_MX7D) ||
    			is_cpu_type(MXC_CPU_MX6UL) ||
    			is_cpu_type(MXC_CPU_MX6ULL) ||
    			is_cpu_type(MXC_CPU_MX6SLL)) {
    			i |= GPTCR_24MEN;
    
    			/* Produce 3Mhz clock */
    			__raw_writel((7 << GPTPR_PRESCALER24M_SHIFT),
    					&cur_gpt->prescaler);
    		}
    	} else {
    		i |= GPTCR_CLKSOURCE_PRE | GPTCR_TEN;
    	}
    #else
    	__raw_writel(0, &cur_gpt->prescaler); /* 32Khz */
    	i |= GPTCR_CLKSOURCE_32 | GPTCR_TEN;
    #endif
    	__raw_writel(i, &cur_gpt->control);
    
    	gd->arch.tbl = __raw_readl(&cur_gpt->counter);
    	gd->arch.tbu = 0;
    
    	return 0;
    }
    
  • 10、board_postclk_init

    // arch/arm/cpu/armv7/mx6/soc.c
    int board_postclk_init(void)
    {
    	/* NO LDO SOC on i.MX6SLL */
    	if (is_cpu_type(MXC_CPU_MX6SLL))
    		return 0;
    
    	set_ldo_voltage(LDO_SOC, 1175);	/* Set VDDSOC to 1.175V */
    
    	return 0;
    }
    
  • 11、get_clocks

    // arch/arm/imx-common/speed.c
    int get_clocks(void)
    {
    #ifdef CONFIG_FSL_ESDHC
    #ifdef CONFIG_FSL_USDHC
    #if CONFIG_SYS_FSL_ESDHC_ADDR == USDHC2_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC3_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC4_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
    #else
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
    #endif
    #else
    #if CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC2_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC3_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK);
    #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC4_BASE_ADDR
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK);
    #else
    	gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK);
    #endif
    #endif
    #endif
    	return 0;
    }
    

    获取 sdhc 时钟,eMMC/SD 接口的控制器。

  • 12、env_init

    // 因为配置emmc启动,所以在common/env_mmc.c
    int env_init(void)
    {
    	/* use default */
    	gd->env_addr 	= (ulong)&default_enviornment[0];
    	gd->env_valid 	= 1;
    
    	return 0;
    }
    

    default_enviornment 是默认的环境变量,其实就是一个字符串数组, 存储着基本的一些变量。
    定义在 include/env_default.h 中。

  • 13、init_baud_rate

    static int init_baud_rate(void)
    {
    	gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
    	return 0;
    }
    
    /**
     * Decode the integer value of an environment variable and return it.
     *
     * @param name		Name of environemnt variable
     * @param base		Number base to use (normally 10, or 16 for hex)
     * @param default_val	Default value to return if the variable is not
     *			found
     * @return the decoded value, or default_val if not found
     */
    ulong getenv_ulong(const char *name, int base, ulong default_val)
    {
    	/*
    	 * We can use getenv() here, even before relocation, since the
    	 * environment variable value is an integer and thus short.
    	 */
    	const char *str = getenv(name);
    
    	return str ? simple_strtoul(str, NULL, base) : default_val;
    }
    
  • 14、serial_init

    // drivers/serial/serial.c
    int serial_init(void)
    {
    		gd->flags |= GD_FLG_SERIAL_READY;
    		return get_current()->start();
    }
    
    static struct serial_device *get_current(void)
    {
    	struct serial_device *dev;
    
    	if (!(gd->flags & GD_FLG_RELOC))
    		dev = default_serial_console();
    	else if (!serial_current)
    		dev = default_serial_console();
    	else
    		dev = serial_current;
    
    	/* We must have a console device */
    	if (!dev) {
    #ifdef CONFIG_SPL_BUILD
    		puts("Cannot find console\n");
    		hang();
    #else
    		panic("Cannot find console\n");
    #endif
    	}
    
    	return dev;
    }
    

    default_serial_console 定义在 drivers/serial/serial_mxc.c

    static struct serial_device mxc_serial_drv = {
    	.name	= "mxc_serial",
    	.start	= mxc_serial_init,
    	.stop	= NULL,
    	.setbrg	= mxc_serial_setbrg,
    	.putc	= mxc_serial_putc,
    	.puts	= default_serial_puts,
    	.getc	= mxc_serial_getc,
    	.tstc	= mxc_serial_tstc,
    };
    
    __weak struct serial_device *default_serial_console(void)
    {
    	return &mxc_serial_drv;
    }
    
  • 15、console_init_f

    // common/console.c
    /* Called before relocation - use serial functions */
    int console_init_f(void)
    {
    	gd->have_console = 1;
    #ifdef CONFIG_SILENT_CONSOLE
    	if (getenv("silent") != NULL)
    		gd->flags |= GD_FLG_SILENT;
    #endif
    
    	print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
    
    	return 0;
    }
    

这里gd->have_console 赋值为1,从这里开始串口就可以输出数据了。

  • 16、display_options

    // lib/display_options.c
    int display_options (void)
    {
    #if defined(BUILD_TAG)
    	printf ("\n\n%s, Build: %s\n\n", version_string, BUILD_TAG);
    #else
    	printf ("\n\n%s\n\n", version_string);
    #endif
    }
    
  • 17、display_text_info

    static int display_text_info(void)
    {
    #if !defined(CONFIG_SANDBOX) && !defined(CONFIG_EFI_APP)
    	ulong bss_start, bss_end, text_base;
    
    	bss_start = (ulong)&__bss_start;
    	bss_end = (ulong)&__bss_end;
    
    #ifdef CONFIG_SYS_TEXT_BASE
    	text_base = CONFIG_SYS_TEXT_BASE;
    #else
    	text_base = CONFIG_SYS_MONITOR_BASE;
    #endif
    
    	debug("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
    		text_base, bss_start, bss_end);
    #endif
    
    #ifdef CONFIG_USE_IRQ
    	debug("IRQ Stack: %08lx\n", IRQ_STACK_START);
    	debug("FIQ Stack: %08lx\n", FIQ_STACK_START);
    #endif
    
    	return 0;
    }
    
  • 18、print_cpuinfo

    // arch/arm/imx-common/cpu.c
    int print_cpuinfo(void)
    {
    	u32 cpurev;
    	__maybe_unused u32 max_freq;
    #if defined(CONFIG_DBG_MONITOR)
    	struct dbg_monitor_regs *dbg =
    		(struct dbg_monitor_regs *)DEBUG_MONITOR_BASE_ADDR;
    #endif
    
    	cpurev = get_cpu_rev();
    
    #if defined(CONFIG_IMX_THERMAL)
    	struct udevice *thermal_dev;
    	int cpu_tmp, minc, maxc, ret;
    
    	printf("CPU:   Freescale i.MX%s rev%d.%d",
    		get_imx_type((cpurev & 0xFF000) >> 12),
    		(cpurev & 0x000F0) >> 4,
    		(cpurev & 0x0000F) >> 0);
    	max_freq = get_cpu_speed_grade_hz();
    	if (!max_freq || max_freq == mxc_get_clock(MXC_ARM_CLK)) {
    		printf(" at %dMHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
    	} else {
    		printf(" %d MHz (running at %d MHz)\n", max_freq / 1000000,
    			mxc_get_clock(MXC_ARM_CLK) / 1000000);
    	}
    #else
    	printf("CPU:   Freescale i.MX%s rev%d.%d at %d MHz\n",
    		get_imx_type((cpurev & 0xFF000) >> 12),
    		(cpurev & 0x000F0) >> 4,
    		(cpurev & 0x0000F) >> 0,
    		mxc_get_clock(MXC_ARM_CLK) / 1000000);
    #endif
    
    #if defined(CONFIG_IMX_THERMAL)
    	puts("CPU:   ");
    	switch (get_cpu_temp_grade(&minc, &maxc)) {
    	case TEMP_AUTOMOTIVE:
    		puts("Automotive temperature grade ");
    		break;
    	case TEMP_INDUSTRIAL:
    		puts("Industrial temperature grade ");
    		break;
    	case TEMP_EXTCOMMERCIAL:
    		puts("Extended Commercial temperature grade ");
    		break;
    	default:
    		puts("Commercial temperature grade ");
    		break;
    	}
    	printf("(%dC to %dC)", minc, maxc);
    	ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev);
    	if (!ret) {
    		ret = thermal_get_temp(thermal_dev, &cpu_tmp);
    
    		if (!ret)
    			printf(" at %dC\n", cpu_tmp);
    		else
    			debug(" - invalid sensor data\n");
    	} else {
    		debug(" - invalid sensor device\n");
    	}
    #endif
    
    #if defined(CONFIG_DBG_MONITOR)
    	if (readl(&dbg->snvs_addr))
    		printf("DBG snvs regs addr 0x%x, data 0x%x, info 0x%x\n",
    			readl(&dbg->snvs_addr),
    			readl(&dbg->snvs_data),
    			readl(&dbg->snvs_info));
    #endif
    
    	printf("Reset cause: %s\n", get_reset_cause());
    	return 0;
    }
    #endif 
    
  • 19、show_board_info

    // common/board_info.c
    /*
    * If the root node of the DTB has a "model" property, show it.
    * Then call checkboard().
    */
    int show_board_info(void)
    {
    #if defined(CONFIG_OF_CONTROL) && !defined(CONFIG_CUSTOM_BOARDINFO)
    	DECLARE_GLOBAL_DATA_PTR;
    	const char *model;
    
    	model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
    
    	if (model)
    		printf("Model: %s\n", model);
    #endif
    
    	return checkboard();
    }
    // CONFIG_OF_CONTROL 未定义
    // board/freescale/mx6sabresd/mx6sabresd.c
    int checkboard()
    {
    	puts("Board: MX6-SabreSD\n");
    	return 0;
    }
    
  • 20、init_func_i2c

    static int init_func_i2c(void)
    {
    		puts("I2C:   ");
    #ifdef CONFIG_SYS_I2C
    		i2c_init_all();
    #else
    		i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
    #endif
    		puts("ready\n");
    }
    
  • 21、announce_dram_init

    static int announce_dram_init(void)
    {
    	puts("DRAM:   ");
    	return 0;
    }
    
  • 22、dram_init, /* configure available RAM banks */

    // board/freescale/mx6sabresd/mx6sabresd.c
    int dram_init(void)
    {
    		gd_ram_size  =  imx_ddr_size();
    		return 0;
    }
    
    • imx_ddr_size
    /*
     * imx_ddr_size - return size in bytes of DRAM according MMDC config
     * The MMDC MDCTL register holds the number of bits for row, col, and data
     * width and the MMDC MDMISC register holds the number of banks. Combine
     * all these bits to determine the meme size the MMDC has been configured for
     */
    unsigned imx_ddr_size(void)
    {
    	struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;
    	unsigned ctl = readl(&mem->ctl);
    	unsigned misc = readl(&mem->misc);
    	int bits = 11 + 0 + 0 + 1;      /* row + col + bank + width */
    
    	bits += ESD_MMDC_CTL_GET_ROW(ctl);
    	bits += col_lookup[ESD_MMDC_CTL_GET_COLUMN(ctl)];
    	bits += bank_lookup[ESD_MMDC_MISC_GET_BANK(misc)];
    	bits += ESD_MMDC_CTL_GET_WIDTH(ctl);
    	bits += ESD_MMDC_CTL_GET_CS1(ctl);
    
    	/* The MX6 can do only 3840 MiB of DRAM */
    	if (bits == 32)
    		return 0xf0000000;
    
    	return 1 << bits;
    }
    

    这里通过读取寄存器的值来计算出ddr的大小,单位字节。

  • 23、setup_dest_addr

    static int setup_dest_addr(void)
    {
    	debug("Monitor len: %08lX\n", gd->mon_len);
    	/*
    	* Ram is setup, size stored in gd !!
    	*/
    	debug("Ram size: %08lX\n", (ulong)gd->ram_size);
    #ifdef CONFIG_SYS_MEM_RESERVE_SECURE
    	/* Reserve memory for secure MMU tables, and/or security monitor */
    	gd->ram_size -= CONFIG_SYS_MEM_RESERVE_SECURE;
    	/*
    	* Record secure memory location. Need recalcuate if memory splits
    	* into banks, or the ram base is not zero.
    	*/
    	gd->secure_ram = gd->ram_size;
    #endif
    	/*
    	* Subtract specified amount of memory to hide so that it won't
    	* get "touched" at all by U-Boot. By fixing up gd->ram_size
    	* the Linux kernel should now get passed the now "corrected"
    	* memory size and won't touch it either. This has been used
    	* by arch/powerpc exclusively. Now ARMv8 takes advantage of
    	* thie mechanism. If memory is split into banks, addresses
    	* need to be calculated.
    	*/
    	gd->ram_size = board_reserve_ram_top(gd->ram_size);
    
    #ifdef CONFIG_SYS_SDRAM_BASE
    	gd->ram_top = CONFIG_SYS_SDRAM_BASE;
    #endif
    	gd->ram_top += get_effective_memsize();
    	gd->ram_top = board_get_usable_ram_top(gd->mon_len);
    	gd->relocaddr = gd->ram_top;
    	debug("Ram top: %08lX\n", (ulong)gd->ram_top);
    #if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500))
    	/*
    	* We need to make sure the location we intend to put secondary core
    	* boot code is reserved and not used by any part of u-boot
    	*/
    	if (gd->relocaddr > determine_mp_bootpg(NULL)) {
    		gd->relocaddr = determine_mp_bootpg(NULL);
    		debug("Reserving MP boot page to %08lx\n", gd->relocaddr);
    	}
    #endif
    	return 0;
    }
    
    • 23.1、board_reserve_ram_top
    __weak phys_size_t board_reserve_ram_top(phys_size_t ram_size)
    {
    #ifdef CONFIG_SYS_MEM_TOP_HIDE
    		return ram_size - CONFIG_SYS_MEM_TOP_HIDE;
    #else
    		return ram_size;
    #fi
    }
    

    这里未定义CONFIG_SYS_MEM_TOP_HIDE。

    • 23.2、CONFIG_SYS_SDRAM_BASE 定义在 include/configs/mx6sabre_common.h
    #define PHYS_SDRM 		MMDC0_ARB_BASE_ADDR
    #define  CONFIG_SYS_SDRAM_BASE  PHYS_SDRAM
    

    MMDC0_ARB_BASE_ADDR 定义在 arch/arm/include/asm/arch-mx6/imx-regs.h

    #define MMDC0_ARB_BASE_ADDR   0x10000000
    
    • 23.3、get_effective_memsize
    phys_size_t __weak get_effective_memsize(void)
    {
    #ifndef CONFIG_VERY_BIG_ARM
    		return gd->ram_size;
    #else
    		return ((gd->ram_size > CONFIG_MAX_MEM_MAPPED) ?
    				CONFIG_MAX_MEM_MAPPED : gd->ram_size);
    #endif
    }
    
    • 23.4、board_get_usable_ram_top
    /* Get the top of usable RAM */
    __weak ulong board_get_usable_ram_top(ulong total_size)
    {
    #ifdef CONFIG_SYS_SDRAM_BASE
    	/*
    	 * Detect whether we have so much RAM that it goes past the end of our
    	 * 32-bit address space. If so, clip the usable RAM so it doesn't.
    	 */
    	if (gd->ram_top < CONFIG_SYS_SDRAM_BASE)
    		/*
    		 * Will wrap back to top of 32-bit space when reservations
    		 * are made.
    		 */
    		return 0;
    #endif
    	return gd->ram_top;
    }
    

    这里设置重定位相关数据:

    • gd->ram_size = 0x40000000 = 1G
    • gd->relocaddr = gd->ram_top = 0x50000000
  • 24、reserve_round_4k

    /* Round memory pointer down to next 4 kB limit */
    static int reserve_round_4k(void)
    {
    	gd->relocaddr &= ~(4096 - 1);
    	// 对 gd->relocaddr 做4K对齐。
    	// 这里 relocaddr = 0x50000000
    	return 0;
    }
    
  • 25、reserve_mmu

    static int reserve_mmu(void)
    {
    	/* reserve TLB table */
    	gd->arch.tlb_size = PGTABLE_SIZE;
    	// 这里回 gd->arch.tlb_size 赋值,PGTABLE_SIZE = 16KB,这段作为MMU table用。
    	gd->relocaddr -= gd->arch.tlb_size;
    	// relocaddr 减掉 mmu table的长度。这里relocaddr = 0x50000000 - 0x4000 = 0x4fffc000
    	/* round down to next 64 kB limit */
    	gd->relocaddr &= ~(0x10000 - 1);
    	// 这里的relocaddr 是 mmu table 的基地址,这个操作的是对 mmu table 基地址做64kB对齐。
    	// 这时 relocaddr = 0x4fffc000 & (~0xffff) = 0x4fff0000
    	gd->arch.tlb_addr = gd->relocaddr;
    	// 把对齐后的mmu table 基地址赋值给 gd->arch.tlb_addr, 这里relocaddr = 4fff0000 
    	debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
    		gd->arch.tlb_addr + gd->arch.tlb_size);
    	return 0;
    }
    

    PGTABLE_SIZE 定义在 arch/arm/include/asm/system.h, 因为imx6q是32为的arm,所以定义应是如下:

    #ifndef PGTABLE_SIZE
    #define PGTABLE_SIZE   (4096 * 4)
    #endif
    
  • 26、reserve_trace

    static int reserve_trace(void)
    {
    #ifdef CONFIG_TRACE
    	gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE;
    	gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE);
    	debug("Reserving %dk for trace data at: %08lx\n",
    		CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr);
    #endif
    
    	return 0;
    }
    

    未定义 CONFIG_TRACE,所以这里是空函数。

  • 27、reserve_uboot

    static int reserve_uboot(void)
    {
    	/*
    	* reserve memory for U-Boot code, data & bss
    	* round down to next 4 kB limit
    	*/
    	gd->relocaddr -= gd->mon_len;
    	// mon_len 的长度在setup_mon_len 里已设置好,这里放u-boot的代码。
    	gd->relocaddr &= ~(4096 - 1);
    	// 对 relocaddr 再次做 4kB 对齐
    #ifdef CONFIG_E500
    	/* round down to next 64 kB limit so that IVPR stays aligned */
    	gd->relocaddr &= ~(65536 - 1);
    #endif
    
    	debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10,
    		gd->relocaddr);
    
    	gd->start_addr_sp = gd->relocaddr;
    	// 4kB 对齐后的 relocaddr 作为新的栈指针。
    	return 0;
    }
    

    这里保留的内存是为了后面代码重定位做准备,就是把u-boot代码拷贝到这里。

  • 28、reserve_malloc

    static int reserve_malloc(void)
    {
    	gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
    	// 新的栈指针减去 TOTAL_MALLOC_LEN,
    	// 这个内存区域作为堆使用
    	debug("Reserving %dk for malloc() at: %08lx\n",
    			TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
    	return 0;
    }
    

    这里保留的内存是堆的位置。
    TOTAL_MALLOC_LEN 定义在 include/common.h 中。

    #if defined(CONFIG_ENV_IS_EMBEDDED)
    #define TOTAL_MALLOC_LEN	CONFIG_SYS_MALLOC_LEN
    #elif ( ((CONFIG_ENV_ADDR+CONFIG_ENV_SIZE) < CONFIG_SYS_MONITOR_BASE) || \
    	(CONFIG_ENV_ADDR >= (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN)) ) || \
          defined(CONFIG_ENV_IS_IN_NVRAM)
    #define	TOTAL_MALLOC_LEN	(CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE)
    #else
    #define	TOTAL_MALLOC_LEN	CONFIG_SYS_MALLOC_LEN
    #endif
    
    // include/configs/mx6sabre_common.h
    #define CONFIG_SYS_MALLOC_LEN			(16 * SZ_1M)
    #define CONFIG_ENV_SIZE 				(8 * 1024)
    

    根据debug打印,TOTAL_MALLOC_LEN 为 16392kB,所以这里 TOTAL_MALLOC_LEN = (CONFIG_SYS_MALLOC_LEN + CONFIG_ENV_SIZE)

  • 29、reserve_board

    /* (permanently) allocate a Board Info struct */
    static int reserve_board(void)
    {
    	if (!gd->bd) {
    		gd->start_addr_sp -= sizeof(bd_t);
    		//  堆的及地址减去 bd_t 结构体的大小,这个区域存放 bd_t 结构体。
    		gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
    		// map_sysmem 返回的还是 start_addr_sp,
    		memset(gd->bd, '\0', sizeof(bd_t));
    		debug("Reserving %zu Bytes for Board Info at: %08lx\n",
    			sizeof(bd_t), gd->start_addr_sp);
    	}
    	return 0;
    }
    

    这里保留了一个 bd_t 结构体的长度,存放板级信息的结构体,u-boot里面两个重要的全局变量一个是 global_data, 一个就是这个 bd_t 。

    • map_sysmem
    #ifdef CONFIG_ARCH_MAP_SYSMEM
    #include <asm/io.h>
    #else
    static inline void *map_sysmem(phys_addr_t paddr, unsigned long len)
    {
    		return (void *)(uintptr_t)paddr;
    }
    #endif
    

    这里未定义 CONFIG_ARCH_MAP_SYSMEM。

  • 30、setup_machine

    static int setup_machine(void)
    {
    #ifdef CONFIG_MACH_TYPE
    	gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
    #endif
    	return 0;
    }
    // CONFIG_MACH_TYPE 定义在 include/configs/mx6sabresd.h 中,
    // #define CONFIG_MACH_TYPE  3980
    
  • 31、reserve_global_data

    static int reserve_global_data(void)
    {
    	gd->start_addr_sp -= sizeof(gd_t);
    	// 这里在bd_t的基地址在减去 gd_t 的大小。
    	// 这里的区域存放新的 gd_t 结构体。 
    	gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
    	// 这里 map_sysmem 和上面的一样,返回 start_addr_sp
    	debug("Reserving %zu Bytes for Global Data at: %08lx\n",
    			sizeof(gd_t), gd->start_addr_sp);
    	return 0;
    }
    

    这里为新的global_data结构体保留了内存,之前的global_data结构体是存放在 OCRAM上的,这里是DDRAM上。

  • 32、reserve_fdt

    static int reserve_fdt(void)
    {
    #ifndef CONFIG_OF_EMBED
    	/*
    	* If the device tree is sitting immediately above our image then we
    	* must relocate it. If it is embedded in the data section, then it
    	* will be relocated with other data.
    	*/
    	if (gd->fdt_blob) {
    		gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
    
    		gd->start_addr_sp -= gd->fdt_size;
    		gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
    		debug("Reserving %lu Bytes for FDT at: %08lx\n",
    			gd->fdt_size, gd->start_addr_sp);
    	}
    #endif
    
    	return 0;
    }
    

    这里未定义 CONFIG_OF_EMBED,所以这里为空函数。

  • 33、reserve_arch

    /* Architecture-specific memory reservation */
    __weak int reserve_arch(void)
    {
    	return 0;
    }
    
  • 34、reserve_stacks

    static int reserve_stacks(void)
    {
    	/* make stack pointer 16-byte aligned */
    	gd->start_addr_sp -= 16;
    	// 在新的 gd_t 的基地址在减去16字节。
    	gd->start_addr_sp &= ~0xf;
    	// 对新的start_addr_sp 做16字节对齐
    
    	/*
    	* let the architecture-specific code tailor gd->start_addr_sp and
    	* gd->irq_sp
    	*/
    	return arch_reserve_stacks();
    }
    int arch_reserve_stacks(void)
    {
    	return 0;
    }
    
  • 35、setup_dram_config

    static int setup_dram_config(void)
    {
    	/* Ram is board specific, so move it to board code ... */
    	dram_init_banksize();
    
    	return 0;
    }
    
    __weak void dram_init_banksize(void)
    {
    #if defined(CONFIG_NR_DRAM_BANKS) && defined(CONFIG_SYS_SDRAM_BASE)
    	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
    	gd->bd->bi_dram[0].size = get_effective_memsize(); 
    #endif
    }
    
    // include/configs/mx6sabre_common.h
    #define CONFIG_NR_DRAM_BANKS   	1
    #define PHYS_SDRAM				MMDC0_ARB_BASE_ADDR
    #define CONFIG_SYS_SDRAM_BASE 	PHYS_SDRAM
    
    //  arch/arm/include/asm/arch-mx6/imx-regs.h
    #define MMDC0_ARB_BASE_ADDR   0x10000000
    

    这里是填充bd_t结构体,关于dram信息的域。

  • 36、show_dram_config

    static int show_dram_config(void)
    {
    	unsigned long long size;
    
    #ifdef CONFIG_NR_DRAM_BANKS
    	int i;
    
    	debug("\nRAM Configuration:\n");
    	for (i = size = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
    		size += gd->bd->bi_dram[i].size;
    		debug("Bank #%d: %llx ", i,
    			(unsigned long long)(gd->bd->bi_dram[i].start));
    #ifdef DEBUG
    		print_size(gd->bd->bi_dram[i].size, "\n");
    #endif
    	}
    	debug("\nDRAM:  ");
    #else
    	size = gd->ram_size;
    #endif
    
    	print_size(size, "");
    	board_add_ram_info(0);
    	putc('\n');
    
    	return 0;
    }
    
  • 37、display_new_sp

    static int display_new_sp(void)
    {
    	debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);
    	return 0;
    }
    
  • 38、reloc_fdt

    static int reloc_fdt(void)
    {
    #ifndef CONFIG_OF_EMBED
    	if (gd->flags & GD_FLG_SKIP_RELOC)
    		return 0;
    	if (gd->new_fdt) {
    		memcpy(gd->new_fdt, gd->fdt_blob, gd->fdt_size);
    		gd->fdt_blob = gd->new_fdt;
    	}
    #endif
    	return 0;
    }
    

    这里未定义 CONFIG_OF_EMBED,所以这里为空函数。

  • 39、setup_reloc

    static int setup_reloc(void)
    {
    	if (gd->flags & GD_FLG_SKIP_RELOC) {
    		debug("Skipping relocation due to flag\n");
    		return 0;
    	}
    
    #ifdef CONFIG_SYS_TEXT_BASE
    	gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
    	// 对 reloc_off 赋值,reloc_off 是重定位后地址到源地址的偏移量
    	// relocaddr 存放的是重定位后的u-boot代码的起始地址
    	// CONFIG_SYS_TEXT_BASE 是最开始 u-boot代码的起始地址
    #ifdef CONFIG_M68K
    	/*
    	* On all ColdFire arch cpu, monitor code starts always
    	* just after the default vector table location, so at 0x400
    	*/
    	gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
    #endif
    #endif
    	memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
    	// 把现在的 gd_t 结构体内容拷贝到新的 gd_t 结构体中。
    	debug("Relocation Offset is: %08lx\n", gd->reloc_off);
    	debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
    		gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
    		gd->start_addr_sp);
    
    	return 0;
    }
    

    这里未定义 CONFIG_M68K 。
    到这里重定位的准备都做好了,下一步就是重定位 u-boot 代码。

总结:
board_init_f 函数在这里主要功能是硬件上初始化了芯片的时钟,定时器等。 外设主要初始化了UART(串口debug), I2C(PMIC相关)。这里没有初始化ddr的代码,是因为这里ddr是由Bootrom初始化的。另外就是软件上主要设置了全局变量 global_data结构体,为后面代码重定位做准备。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值