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_recordstatic 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_tracestatic 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_fdtstatic 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_fdtstatic 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结构体,为后面代码重定位做准备。