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相关推荐

  1. 解题报告(一)D、(CROC 2016 - Final Round C)Binary Table(矩阵 + 状态压缩 + FWT)(3.5)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  2. 快来领60 本书!涵盖 Linux、Spring Boot、Python、MongoDB、Hadoop等!免费包邮!

    「清华大学出版社」联系了包括K8S中文社区在内的 6 家技术公众号,送出 60 本技术书.内容涉及 Linux .Spring Boot.大数据.Python.MongoDB.数据挖掘.Hadoop等 ...

  3. springboot web项目_Vue、Spring Boot开发小而完整的Web前后端分离项目实战12

    第12讲 tabs选项卡制作讲解 1.1.tabs选项卡组件: 1. tabs 组件 2.常用属性: value :选中选项卡的name type :选项卡风格 可选择 card / border-c ...

  4. boot spring test 文档_Spring、Spring Boot 和 TestNG 测试指南 ( 3 )

    原标题:Spring.Spring Boot 和 TestNG 测试指南 ( 3 ) 来源:chanjarster, github.com/chanjarster/spring-test-exampl ...

  5. spring Boot 学习(七、Spring Boot与开发热部署)

    一.热部署 在开发中我们修改一个Java文件后想看到效果不得不重启应用,这导致大量时间 花费,我们希望不重启应用的情况下,程序可以自动部署(热部署).有以下四 种情况,如何能实现热部署. •1.模板引 ...

  6. 厦门信息计算机专业录取分数,厦门大学计算机类(含计算机科学与技术、智能科学与技术、网络专业2016年在福建理科高考录取最低分数线...

    类似问题答案 厦门大学计算机类(含计算机科学与技术.智能科学与技术.网络专业2016年在北京理科... 学校 地 区 专业 年份 批次 类型 分数 厦门大学 北京 计算机类(含计算机科学与技术.智能科 ...

  7. SpringMVC框架、Spring boot框架、SSM區別

    參考: 构建微服务:Spring boot 入门篇       https://www.cnblogs.com/ityouknow/p/5662753.html Spring Cloud与Docker ...

  8. 第七章、Spring Boot MyBatis升级篇

    课时二十七.Spring Boot MyBatis升级篇-注解 缘起:在一节视频中,有这么一段留言:"会不会推出SpringBoot整合Mybaits配置文件sqlMapConfig.xml ...

  9. BIOS 启动类型:Legacy+UEFI、UEFI BOOT、Legacy BOOT

    目录 一.常见启动方式 1.Legacy+UEFI(或者标成Auto/Both) 2.UEFI BOOT(仅UEFI) 3.Legacy BOOT(仅Legacy) 二.UEFI boot和Legac ...

  10. 1.Spring、Spring Boot 和 Spring Cloud 有什么关系?

    1.什么是SpringBoot? Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程,该框架使用了特定的方式来进行配置, ...

最新文章

  1. matlab直方图绘制
  2. 【采用】解读消金业务风控模型的6个层级
  3. 华为机试题【9】-整数分割为2的幂次
  4. 00截断上传绕过_小谈截断上传漏洞
  5. struts2中Action名称的搜索顺序
  6. Computed property “value1“ was assigned to but it has no setter.
  7. python输出所有素数_Python程序打印一个区间内所有质数
  8. mysql数控不小心被删_mysql 数据库信息不小心被删除了, 请问能恢复么
  9. 如何自定义Struts2表单验证后的错误信息显示格式
  10. 1 ELK安装部署并监控nginx
  11. 在Python中从头开始迭代本地搜索
  12. Java参数传递对象引用传递失效
  13. 台湾“比基尼登山客”遗体运出 山友接其“回家”
  14. android 动态获取权限
  15. js监听移动端横屏和竖屏状态
  16. mysql 关闭远程_禁止MySQL root远程访问
  17. win10删除账户文件夹(C:\Users\***)后,无法登录账户的解决方法
  18. Java九阳神功--BP神经网络JAVA代码解析
  19. 后序线索化二叉树及遍历(图解)
  20. Signal Processing投稿经历

热门文章

  1. 词霸天下---词根234【-zo(o)- 动 物】
  2. sdif matlab,sdif.dat是什么文件
  3. 《Linux就该这么学》读书笔记
  4. 亚德诺半导体收购竞争对手美信;凯西与拜耳将在华共同推广宝丽亚和启尔畅 | 美通企业日报...
  5. 在线求助ing~ 急!!
  6. java中关键字_java中的关键字是什么?
  7. 都说C++难,那么它到底难在了哪里?
  8. 解决安卓手机点击有效,苹果手机点击事件无效的问题
  9. nodejs 获取系统环境变量_Node.js中环境变量process.env的一些事详解
  10. WPF编程,使用系统自带的Wingdings字体。