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();
#endifgd->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_APPreloc_ofs = (unsigned long)image_base;
#endifdebug("initcall: %p", (char *)*init_fnc_ptr - reloc_ofs);if (gd->flags & GD_FLG_RELOC)debug(" (relocated to %p)\n", (char *)*init_fnc_ptr);elsedebug("\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_SANDBOXsetup_ram_buf,
#endifsetup_mon_len,
#ifdef CONFIG_OF_CONTROLfdtdec_setup,
#endif
#ifdef CONFIG_TRACEtrace_early_init,
#endifinitf_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,
#endifarch_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,
#endifenv_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,
#endifinit_baud_rate, /* initialze baudrate settings */serial_init, /* serial communications setup */console_init_f, /* stage 1 init of console */
#ifdef CONFIG_SANDBOXsandbox_early_getopt_check,
#endif
#ifdef CONFIG_OF_CONTROLfdtdec_prepare_fdt,
#endifdisplay_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,
#endifprint_cpuinfo, /* display cpu info (and speed) */
#if defined(CONFIG_MPC5xxx)prt_mpc5xxx_clks,
#endif /* CONFIG_MPC5xxx */
#if defined(CONFIG_DISPLAY_BOARDINFO)show_board_info,
#endifINIT_FUNC_WATCHDOG_INIT
#if defined(CONFIG_MISC_INIT_F)misc_init_f,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)init_func_i2c,
#endif
#if defined(CONFIG_HARD_SPI)init_func_spi,
#endifannounce_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_POSTpost_init_f,
#endifINIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_SYS_DRAM_TEST)testdram,
#endif /* CONFIG_SYS_DRAM_TEST */INIT_FUNC_WATCHDOG_RESET#ifdef CONFIG_POSTinit_post,
#endifINIT_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_PRAMreserve_pram,
#endifreserve_round_4k,
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF)) &&\defined(CONFIG_ARM)reserve_mmu,
#endif
#ifdef CONFIG_DM_VIDEOreserve_video,
#else
# ifdef CONFIG_LCDreserve_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_BUILDreserve_malloc,reserve_board,
#endifsetup_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_RESETsetup_board_part2,
#endifdisplay_new_sp,
#ifdef CONFIG_SYS_EXTBDINFOsetup_board_extra,
#endifINIT_FUNC_WATCHDOG_RESETreloc_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,
#endifNULL,
};
针对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; #endifreturn 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_LENassert(gd->malloc_base); /* Set up by crt0.S */gd->malloc_limit = CONFIG_SYS_MALLOC_F_LEN;gd->malloc_ptr = 0; #endifreturn 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(); #elsereturn 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(); #endifif (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(); #endifinit_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);elsereg &= ~(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_MX6if (check_module_fused(MX6_MODULE_APBHDMA)) {printf("NAND APBH-DMA@0x%x is fused, disable it\n",MXS_APBH_BASE);return;} #endifmxs_reset_block(&apbh_regs->hw_apbh_ctrl0_reg);#ifdef CONFIG_APBH_DMA_BURST8writel(APBH_CTRL0_AHB_BURST8_EN,&apbh_regs->hw_apbh_ctrl0_set); #elsewritel(APBH_CTRL0_AHB_BURST8_EN,&apbh_regs->hw_apbh_ctrl0_clr); #endif#ifdef CONFIG_APBH_DMA_BURSTwritel(APBH_CTRL0_APB_BURST_EN,&apbh_regs->hw_apbh_ctrl0_set); #elsewritel(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_EARLYret = dm_timer_init();if (ret)return ret; #endifreturn 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(); #endifreturn 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_HCLKif (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_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC3_BASE_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); #elif CONFIG_SYS_FSL_ESDHC_ADDR == USDHC4_BASE_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK); #elsegd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); #endif #else #if CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC2_BASE_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC3_BASE_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC3_CLK); #elif CONFIG_SYS_FSL_ESDHC_ADDR == MMC_SDHC4_BASE_ADDRgd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC4_CLK); #elsegd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC_CLK); #endif #endif #endifreturn 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();elsedev = serial_current;/* We must have a console device */if (!dev) { #ifdef CONFIG_SPL_BUILDputs("Cannot find console\n");hang(); #elsepanic("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_CONSOLEif (getenv("silent") != NULL)gd->flags |= GD_FLG_SILENT; #endifprint_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); #elseprintf ("\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_BASEtext_base = CONFIG_SYS_TEXT_BASE; #elsetext_base = CONFIG_SYS_MONITOR_BASE; #endifdebug("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",text_base, bss_start, bss_end); #endif#ifdef CONFIG_USE_IRQdebug("IRQ Stack: %08lx\n", IRQ_STACK_START);debug("FIQ Stack: %08lx\n", FIQ_STACK_START); #endifreturn 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; #endifcpurev = 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);} #elseprintf("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);elsedebug(" - 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)); #endifprintf("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); #endifreturn 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_I2Ci2c_init_all(); #elsei2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); #endifputs("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_BASEgd->ram_top = CONFIG_SYS_SDRAM_BASE; #endifgd->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);} #endifreturn 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_HIDEreturn ram_size - CONFIG_SYS_MEM_TOP_HIDE; #elsereturn 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_ARMreturn gd->ram_size; #elsereturn ((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; #endifreturn 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 = 0x50000000return 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) = 0x4fff0000gd->arch.tlb_addr = gd->relocaddr;// 把对齐后的mmu table 基地址赋值给 gd->arch.tlb_addr, 这里relocaddr = 4fff0000debug("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_TRACEgd->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); #endifreturn 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); #endifdebug("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_TYPEgd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */ #endifreturn 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_spdebug("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);} #endifreturn 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_BANKSint 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 DEBUGprint_size(gd->bd->bi_dram[i].size, "\n"); #endif}debug("\nDRAM: "); #elsesize = gd->ram_size; #endifprint_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_EMBEDif (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;} #endifreturn 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_BASEgd->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 #endifmemcpy(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结构体,为后面代码重定位做准备。
3、u-boot-2016 - board_init_f相关推荐
- 解题报告(一)D、(CROC 2016 - Final Round C)Binary Table(矩阵 + 状态压缩 + FWT)(3.5)
繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...
- 快来领60 本书!涵盖 Linux、Spring Boot、Python、MongoDB、Hadoop等!免费包邮!
「清华大学出版社」联系了包括K8S中文社区在内的 6 家技术公众号,送出 60 本技术书.内容涉及 Linux .Spring Boot.大数据.Python.MongoDB.数据挖掘.Hadoop等 ...
- springboot web项目_Vue、Spring Boot开发小而完整的Web前后端分离项目实战12
第12讲 tabs选项卡制作讲解 1.1.tabs选项卡组件: 1. tabs 组件 2.常用属性: value :选中选项卡的name type :选项卡风格 可选择 card / border-c ...
- boot spring test 文档_Spring、Spring Boot 和 TestNG 测试指南 ( 3 )
原标题:Spring.Spring Boot 和 TestNG 测试指南 ( 3 ) 来源:chanjarster, github.com/chanjarster/spring-test-exampl ...
- spring Boot 学习(七、Spring Boot与开发热部署)
一.热部署 在开发中我们修改一个Java文件后想看到效果不得不重启应用,这导致大量时间 花费,我们希望不重启应用的情况下,程序可以自动部署(热部署).有以下四 种情况,如何能实现热部署. •1.模板引 ...
- 厦门信息计算机专业录取分数,厦门大学计算机类(含计算机科学与技术、智能科学与技术、网络专业2016年在福建理科高考录取最低分数线...
类似问题答案 厦门大学计算机类(含计算机科学与技术.智能科学与技术.网络专业2016年在北京理科... 学校 地 区 专业 年份 批次 类型 分数 厦门大学 北京 计算机类(含计算机科学与技术.智能科 ...
- SpringMVC框架、Spring boot框架、SSM區別
參考: 构建微服务:Spring boot 入门篇 https://www.cnblogs.com/ityouknow/p/5662753.html Spring Cloud与Docker ...
- 第七章、Spring Boot MyBatis升级篇
课时二十七.Spring Boot MyBatis升级篇-注解 缘起:在一节视频中,有这么一段留言:"会不会推出SpringBoot整合Mybaits配置文件sqlMapConfig.xml ...
- BIOS 启动类型:Legacy+UEFI、UEFI BOOT、Legacy BOOT
目录 一.常见启动方式 1.Legacy+UEFI(或者标成Auto/Both) 2.UEFI BOOT(仅UEFI) 3.Legacy BOOT(仅Legacy) 二.UEFI boot和Legac ...
- 1.Spring、Spring Boot 和 Spring Cloud 有什么关系?
1.什么是SpringBoot? Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程,该框架使用了特定的方式来进行配置, ...
最新文章
- matlab直方图绘制
- 【采用】解读消金业务风控模型的6个层级
- 华为机试题【9】-整数分割为2的幂次
- 00截断上传绕过_小谈截断上传漏洞
- struts2中Action名称的搜索顺序
- Computed property “value1“ was assigned to but it has no setter.
- python输出所有素数_Python程序打印一个区间内所有质数
- mysql数控不小心被删_mysql 数据库信息不小心被删除了, 请问能恢复么
- 如何自定义Struts2表单验证后的错误信息显示格式
- 1 ELK安装部署并监控nginx
- 在Python中从头开始迭代本地搜索
- Java参数传递对象引用传递失效
- 台湾“比基尼登山客”遗体运出 山友接其“回家”
- android 动态获取权限
- js监听移动端横屏和竖屏状态
- mysql 关闭远程_禁止MySQL root远程访问
- win10删除账户文件夹(C:\Users\***)后,无法登录账户的解决方法
- Java九阳神功--BP神经网络JAVA代码解析
- 后序线索化二叉树及遍历(图解)
- Signal Processing投稿经历
热门文章
- 词霸天下---词根234【-zo(o)- 动 物】
- sdif matlab,sdif.dat是什么文件
- 《Linux就该这么学》读书笔记
- 亚德诺半导体收购竞争对手美信;凯西与拜耳将在华共同推广宝丽亚和启尔畅 | 美通企业日报...
- 在线求助ing~ 急!!
- java中关键字_java中的关键字是什么?
- 都说C++难,那么它到底难在了哪里?
- 解决安卓手机点击有效,苹果手机点击事件无效的问题
- nodejs 获取系统环境变量_Node.js中环境变量process.env的一些事详解
- WPF编程,使用系统自带的Wingdings字体。