日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

3、u-boot-2016 - board_init_f

發布時間:2023/12/20 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 = 4fff0000 debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,gd->arch.tlb_addr + gd->arch.tlb_size);return 0; }

    PGTABLE_SIZE 定義在 arch/arm/include/asm/system.h, 因為imx6q是32為的arm,所以定義應是如下:

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

    static int reserve_trace(void) { #ifdef CONFIG_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的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

日日干美女 | 国产黄色片免费观看 | 中文字幕a∨在线乱码免费看 | 福利一区二区在线 | 国产精品久久99综合免费观看尤物 | 久久久成人精品 | 99视频一区二区 | 97电影在线看视频 | 狠狠色丁香婷婷综合久小说久 | 国产精品av免费在线观看 | 婷婷综合影院 | 欧美日韩国产色综合一二三四 | av久久在线 | 日韩av一区二区在线 | 成人在线播放免费观看 | 337p西西人体大胆瓣开下部 | 中文在线字幕免费观 | 国产999在线观看 | 在线看毛片网站 | 四虎在线免费观看 | 欧洲一区二区三区精品 | 国产另类av| 91福利在线观看 | 欧美性极品xxxx娇小 | 成 人 黄 色 视频播放1 | 81国产精品久久久久久久久久 | 93久久精品日日躁夜夜躁欧美 | 特级西西444www大胆高清无视频 | 亚洲午夜精 | 精品久久久久久亚洲综合网 | 欧美日韩一区二区三区视频 | 中文字幕一区2区3区 | 国产一区成人 | 亚洲视频,欧洲视频 | 九九日韩| 精品久久久久久久久久岛国gif | 日韩精品欧美一区 | 国产福利在线 | 视频在线播放国产 | 免费h漫在线观看 | 国产伦理久久精品久久久久_ | 日韩a级免费视频 | 国产经典 欧美精品 | 成人久久久久久久久 | 中文字幕成人 | 日日碰狠狠躁久久躁综合网 | 一区二区三区影院 | 福利精品在线 | 欧美狠狠操 | 国产精品久久久久久av | 最新成人在线 | 干狠狠| 精品久久美女 | 亚洲 欧美 另类人妖 | 日韩.com | 天天干夜夜夜 | 国产精品毛片一区二区三区 | 国产黄网在线 | 色综合激情网 | 伊人五月天综合 | www黄色com | 中文字幕在线有码 | 91香蕉视频在线 | 夜色资源网 | 亚洲午夜精品福利 | 成人精品一区二区三区中文字幕 | 国产精品国产三级国产aⅴ入口 | 精品久久久精品 | 久久久久久蜜av免费网站 | 国产成人性色生活片 | 国产精品18久久久久久首页狼 | 国产精品丝袜久久久久久久不卡 | 99视频在线精品免费观看2 | 欧美激情视频在线观看免费 | 91九色最新地址 | 99综合电影在线视频 | 国产欧美精品一区二区三区四区 | 亚洲午夜av| a级片网站 | 国产精品av免费观看 | 免费a级毛片在线看 | av中文在线播放 | 国产精品免费在线观看视频 | 三级在线国产 | 中文字幕av在线不卡 | 懂色av一区二区三区蜜臀 | 日本黄色免费电影网站 | 国产成年免费视频 | 久久亚洲私人国产精品 | 波多野结衣视频在线 | 中文字幕在线不卡国产视频 | 久久精品伊人 | 免费一级黄色 | 欧美日韩亚洲一 | 黄网站色视频免费观看 | 91在线视频免费 | 亚洲精品在线网站 | 日韩视频在线不卡 | 狠狠躁日日躁 | 91在线亚洲| 狠狠色噜噜狠狠狠狠2021天天 | 中文字幕亚洲精品日韩 | 天天操天天干天天爱 | 五月色综合 | 91在线视频免费91 | 免费成人黄色av | 久久国产欧美日韩 | 欧美一级电影 | 黄色毛片视频免费 | 99精品乱码国产在线观看 | 日韩专区在线 | 久久国产精品一区二区 | 91传媒在线看 | 久久伊人精品一区二区三区 | 91自拍视频在线 | 久久久久久久久久久成人 | 国产91精品在线播放 | 国产 日韩 欧美 在线 | 日本动漫做毛片一区二区 | 91av资源在线 | 久久久免费观看完整版 | 激情综合久久 | 国产淫片| 日韩免费电影网站 | 中文字幕亚洲字幕 | 在线免费视频 你懂得 | 高潮久久久久久久久 | 精品在线亚洲视频 | 成人在线播放网站 | 日韩在线资源 | 免费福利视频导航 | 免费能看的黄色片 | 国产色 在线 | 天天综合久久综合 | 人人添人人澡人人澡人人人爽 | 久久蜜桃av | 国产婷婷在线观看 | 97香蕉久久国产在线观看 | 免费在线播放av电影 | 免费精品国产va自在自线 | 狠狠综合久久 | www.91国产| 91免费在线播放 | 在线免费观看麻豆 | 国产不卡在线播放 | 国产最新福利 | 亚洲在线观看av | 81国产精品久久久久久久久久 | 中文字幕丝袜制服 | 这里只有精品视频在线 | 狠狠的操狠狠的干 | 最近的中文字幕大全免费版 | 欧美粗又大 | 成年人免费看片 | 中文字幕在线观看2018 | 久久天天躁狠狠躁亚洲综合公司 | 91大神电影 | 99久久精 | 在线免费av播放 | 欧美一区日韩精品 | 精品久久久久久久久久久久久久久久 | 精品电影一区二区 | 国产视频中文字幕 | 亚洲免费激情 | 成人黄色资源 | 成人av电影网址 | 免费网站观看www在线观看 | 久久91久久久久麻豆精品 | 手机av电影在线观看 | 91福利视频久久久久 | 国产视频1区2区3区 久久夜视频 | 高清av影院 | 天天做天天爱天天爽综合网 | 91色在线观看视频 | avwww在线| 色黄视频免费观看 | 狠狠色丁香婷婷综合 | 成人高清av在线 | 成人免费视频网站在线观看 | 91在线观看视频网站 | 主播av在线 | 日本bbbb摸bbbb | 中文字幕一二三区 | 色综合久久久久久久久五月 | 最近高清中文字幕在线国语5 | 在线视频 区 | 成人亚洲免费 | 午夜精品久久久久久久久久久久 | 国语久久 | 亚洲免费资源 | 伊人狠狠色丁香婷婷综合 | 国产九色视频在线观看 | 欧美一区二区精品在线 | 五月天狠狠操 | 伊人婷婷网 | 精品中文字幕在线观看 | 欧美性粗大hdvideo | 久久久久亚洲精品男人的天堂 | 久久综合婷婷国产二区高清 | 五月婷婷操 | www日韩在线 | 激情校园亚洲 | 在线观看你懂的网站 | 国产精品99久久久久久小说 | 精品久久久久久久久久久久久久久久久久 | 欧美韩国日本在线 | 天天操天天干天天爱 | 韩日电影在线 | 色资源在线 | 免费福利视频网 | 91香蕉视频污在线 | 911精品美国片911久久久 | 特级片免费看 | 国产精品久久99精品毛片三a | 天天操天天色综合 | 久草综合在线 | 久久精品小视频 | 在线视频日韩一区 | 天天操天天操天天干 | 一级片视频免费观看 | 久久精品国产精品亚洲精品 | 97精品久久人人爽人人爽 | 日韩欧美精品一区 | 91精品国产亚洲 | 免费视频久久久久 | 在线精品观看国产 | 国内毛片毛片 | 婷婷激情av | 精品女同一区二区三区在线观看 | 亚洲综合色视频在线观看 | 欧美一区在线看 | 西西44人体做爰大胆视频 | 国产视频精选在线 | 人人澡人人添人人爽一区二区 | 99久久久久久久久久 | 天天爱天天操天天射 | 麻豆国产露脸在线观看 | 成人在线免费视频 | 伊人中文字幕在线 | 国产精品av在线 | 亚洲天堂网在线播放 | 正在播放亚洲精品 | 男女啪啪视屏 | 精品一区二区三区在线播放 | 亚洲国产av精品毛片鲁大师 | 久久久黄视频 | 天天干天天射天天操 | 久久黄视频 | 99国产视频在线 | 黄色av影视| 国产一级精品视频 | 国产免费av一区二区三区 | 亚洲永久av| 欧美热久久 | 亚洲一区二区视频在线 | 99热在线国产 | 婷婷丁香激情五月 | 91视频在线免费下载 | 亚洲区色 | 韩国精品福利一区二区三区 | av一区二区在线观看中文字幕 | 成人黄色电影在线播放 | 在线观看一级视频 | 天天操天天爱天天爽 | 亚洲.www| 日韩电影黄色 | 91资源在线免费观看 | 久久天天躁 | 国产日本在线 | 免费电影一区二区三区 | 在线观看黄色国产 | 一本—道久久a久久精品蜜桃 | 成年人免费看的视频 | 久久毛片高清国产 | 国产精品毛片久久蜜 | 婷婷视频在线 | 中文日韩在线视频 | 国产精品久久久久999 | 精品毛片一区二区免费看 | 日韩一区二区免费视频 | 亚洲天天草 | 热久久免费视频 | 日韩大片在线播放 | 欧美日韩国产伦理 | 99久久999久久久精玫瑰 | 六月丁香综合网 | 色婷婷综合视频在线观看 | 国产淫片免费看 | 91尤物国产尤物福利在线播放 | 国内精品毛片 | 国产成人精品亚洲日本在线观看 | 韩国av一区二区 | 又色又爽又黄高潮的免费视频 | 亚洲国产精品电影在线观看 | 97免费在线观看 | 国产在线综合视频 | 99久久9| 亚洲欧美经典 | 夜夜摸夜夜爽 | 国产区第一页 | 91丨九色丨蝌蚪丨对白 | 日韩欧美视频免费观看 | 国产精品亚洲人在线观看 | 久久一区二 | 中文字幕av全部资源www中文字幕在线观看 | 欧美日韩网站 | 久久tv| 亚洲另类xxxx| 中文字幕色综合网 | 精品国产精品久久一区免费式 | 1024手机基地在线观看 | 久久在线视频精品 | 日韩精品一区在线播放 | 欧美巨乳波霸 | 在线观看日韩精品 | 中文字幕乱码日本亚洲一区二区 | 亚洲专区欧美 | 欧美日韩18 | 国产99一区视频免费 | 国产裸体视频网站 | 中文字幕在线观看一区 | 国产高清视频在线免费观看 | 精品在线观看视频 | 国产一区二区在线免费 | 手机av片| www日日| 国产成人精品999在线观看 | av官网在线 | 日韩网站在线观看 | 久久天堂网站 | 欧美成人91 | www.一区二区三区 | 国产一二区免费视频 | 天天射天天干天天爽 | 日韩av在线不卡 | 色偷偷中文字幕 | 欧日韩在线 | 成年人视频在线 | 欧美日韩在线免费观看 | 成人av地址| 亚洲精品美女在线 | 中文字幕一区二区三区四区 | 日本精品中文字幕 | 九九在线国产视频 | 欧美成人一区二区 | 一区二区激情视频 | 午夜精品一区二区三区在线视频 | www.天天草 | 超碰97人| 亚洲国产成人高清精品 | 一级黄色在线免费观看 | 2000xxx影视| 免费在线一区二区三区 | 日韩一区二区在线免费观看 | 久草在线资源视频 | 91精品啪在线观看国产线免费 | 久久精品久久久久久久 | 草久久久久久久 | 日韩专区一区二区 | 91丨九色丨蝌蚪丨老版 | 综合网在线视频 | 亚洲黄色一级电影 | 亚洲电影院 | 中文高清av | 9999在线观看| 国产精品乱看 | 亚洲综合网 | 97精品国产91久久久久久久 | 99精品视频观看 | 亚洲综合黄色 | 国产高清不卡在线 | 天堂入口网站 | 欧美激情综合五月色丁香小说 | 一区二区亚洲精品 | 国产亚洲精品久久19p | av福利在线播放 | 在线看国产日韩 | 精品一区二区久久久久久久网站 | 粉嫩一区二区三区粉嫩91 | 成人免费视频视频在线观看 免费 | 日本最新高清不卡中文字幕 | 97色婷婷成人综合在线观看 | 成人在线视频论坛 | 亚洲精品在线播放视频 | 在线v片 | av日韩国产 | 中文国产字幕在线观看 | 97在线视频免费观看 | 中文在线免费看视频 | 国产亚洲精品久久久久动 | 国产一区二区久久精品 | 伊人影院av | 日韩欧美在线高清 | 四虎在线免费观看 | 日韩免费电影 | 中文字幕首页 | 国产精品网红直播 | 久久激情精品 | 国产69精品久久99的直播节目 | 国产精品久久久久亚洲影视 | 波多野结衣电影一区二区 | 亚洲免费国产视频 | 成人国产精品久久久 | 婷婷色综合色 | 97超碰人人爱 | 成年人网站免费观看 | 欧美一区二区在线看 | 久久久免费在线观看 | 国产高清精品在线 | 五月天婷亚洲天综合网精品偷 | 91亚·色 | 国产一级片免费观看 | 日韩免费 | 国产视频欧美视频 | 亚洲在线高清 | 麻豆成人精品视频 | 欧美 激情 国产 91 在线 | 亚洲国产福利视频 | 国产高清在线a视频大全 | 三级黄色片在线观看 | 国产91av视频在线观看 | 亚洲精品在线免费看 | 久久久久久电影 | www国产亚洲精品久久麻豆 | 九九热在线免费观看 | 国产精品成人一区二区三区 | 久草视频手机在线 | 99久久er热在这里只有精品66 | 久久字幕精品一区 | 欧美日韩中文另类 | www色,com | 国产精品欧美激情在线观看 | 综合色婷婷 | 亚洲一级片在线观看 | japanese黑人亚洲人4k | 天天操天天色天天 | 久久一区二区三区日韩 | 天天插天天狠天天透 | 美女视频国产 | 国产亚洲精品久久久久久大师 | 成人啪啪18免费游戏链接 | 久久兔费看a级 | 精品视频123区在线观看 | 国产福利91精品张津瑜 | 99r在线视频 | 亚洲理论电影网 | 久久久这里有精品 | 香蕉免费在线 | 人人插人人做 | 91九色最新| 亚洲免费精品一区二区 | 久久99在线视频 | 久久人人97超碰com | 日韩在线观看 | 中文电影网 | 99精品免费久久久久久日本 | 在线观看成人一级片 | 色噜噜日韩精品欧美一区二区 | 国产又粗又猛又色又黄视频 | 免费三级a | 日韩美女黄色片 | 中文字幕一区二区三区四区 | 国内精品中文字幕 | 色综合久久久久网 | 久久丁香网 | 五月天视频网站 | 国内精品一区二区 | 超级碰碰碰视频 | 国产999免费视频 | 91九色视频导航 | 国产精品免费在线播放 | 天堂中文在线视频 | 国产精品色婷婷视频 | 欧洲精品在线视频 | 亚洲最新毛片 | 久久视频 | 国产精品av在线 | 国产在线欧美 | 日本少妇视频 | 涩涩伊人 | 高清精品视频 | 久久99精品久久只有精品 | 亚洲午夜久久久久久久久久久 | 狠狠干电影 | 天天做天天爱天天综合网 | 免费日p视频| 中文字幕在线国产 | 中文字幕国产一区二区 | 免费日韩在线 | 天天操综 | 成年人黄色免费网站 | www.天天成人国产电影 | 成人影音av | 日韩大片在线 | 怡红院久久 | 亚洲一区二区高潮无套美女 | 成人黄色大片在线观看 | 久草电影免费在线观看 | 国产资源免费 | 国产麻豆果冻传媒在线观看 | 国产在线观看污片 | 久久久高清视频 | 久久精选视频 | 亚洲网久久| 午夜精品久久久久久久99婷婷 | 伊色综合久久之综合久久 | 在线免费观看一区二区三区 | 在线va网站 | 天天色影院 | 在线观看国产永久免费视频 | 日韩高清在线不卡 | 国产高清不卡在线 | 欧美极品少妇xxxx | 色综合亚洲精品激情狠狠 | 亚洲视频六区 | 日韩有码网站 | 精品国产人成亚洲区 | 亚洲国产精彩中文乱码av | 黄色成人小视频 | 欧美日韩在线视频一区二区 | 亚洲国产免费 | 免费观看9x视频网站在线观看 | 麻花豆传媒mv在线观看网站 | 黄色一级性片 | 国产成人精品电影久久久 | 欧美日韩成人 | 色婷婷综合久久久 | 天天激情在线 | 国产91精品一区二区麻豆亚洲 | 狠狠亚洲| 麻豆网站免费观看 | www.久久久com | 在线国产精品一区 | 日韩美精品视频 | 国产青草视频在线观看 | 在线观看www视频 | 精品在线播放视频 | 三级av在线 | 国产免费三级在线观看 | 国产高清精品在线 | 一级电影免费在线观看 | 国产黄色理论片 | 国产91免费观看 | 国产精品欧美久久 | 日韩精品亚洲专区在线观看 | 成人免费视频网址 | 久久精品久久国产 | 天天操天天舔天天爽 | 中文字幕免费一区 | 免费a一级 | 91亚洲夫妻 | 亚洲国产经典视频 | 亚洲精品久久久久久中文传媒 | 91福利国产在线观看 | 免费在线观看国产黄 | 欧美日韩国产伦理 | 国产精品日韩久久久久 | 日韩在线三区 | 国产精品男女 | 欧美日韩成人 | 国产一及片 | 亚洲涩涩色 | 亚洲专区视频在线观看 | 在线午夜 | 国产a精品 | 精品一区电影 | 中文字幕在线观看免费高清电影 | 999ZYZ玖玖资源站永久 | 日韩在线观看视频在线 | 国产一区二区三区在线免费观看 | 黄网站色视频 | av在线免费播放网站 | caobi视频| 99视频国产精品免费观看 | 99电影 | 亚洲热久久 | 中文字幕欧美日韩va免费视频 | 日韩有码网站 | 五月宗合网 | 91高清免费观看 | 97在线视频免费看 | 91在线精品视频 | 91精品视频免费观看 | 最新av网址在线 | 波多野结衣理论片 | 在线中文字幕观看 | 中文字幕亚洲欧美日韩2019 | 草久久久久久 | 久久黄色精品视频 | 2020天天干夜夜爽 | 天天爽天天搞 | 91av在线看| 久久九九免费视频 | 亚洲 欧美 日韩 综合 | 六月丁香综合网 | 99re中文字幕| 国产美女黄网站免费 | 色噜噜日韩精品一区二区三区视频 | 最近能播放的中文字幕 | 亚洲精选视频在线 | 亚洲 中文 欧美 日韩vr 在线 | 香蕉视频免费看 | 国产精品九九久久99视频 | 亚洲资源网 | 日韩动漫免费观看高清完整版在线观看 | 国产午夜小视频 | 国产 一区二区三区 在线 | 精品在线播放视频 | 久久精品视频网 | 亚洲少妇久久 | 天天干天天做 | 18国产精品白浆在线观看免费 | 亚洲一区美女视频在线观看免费 | 日韩视频在线观看视频 | 国产精品视频大全 | 亚洲色图27p| 久久久精品日本 | 一区二区三区免费在线观看 | 久久精品79国产精品 | 97av色| 成人黄色小说在线观看 | 在线看成人av | 欧美日韩国产精品一区二区 | 国模一区二区三区四区 | 91精品免费看 | 天天干亚洲 | 国产成人精品电影久久久 | 亚洲欧美成人综合 | 婷婷天天色 | 在线国产精品视频 | 免费观看午夜视频 | 麻豆成人网| 97精品国产91久久久久久 | 黄网站大全 | 99色在线观看 | 91人人揉日日捏人人看 | 亚洲综合色视频在线观看 | 精品国产一区二区三区久久久 | 亚洲黄网站| 最近2019年日本中文免费字幕 | 人人cao| 国产精品破处视频 | 成人午夜电影在线 | 激情av在线资源 | 最近最新中文字幕视频 | 中文字幕亚洲欧美日韩2019 | 韩国av在线播放 | 成年一级片| 国产精品久久影院 | 国产精品久久久久久婷婷天堂 | 欧美日韩精品电影 | 怡春院av| 国际精品久久 | 久久免费视频在线观看30 | 国产老妇av| 久久久精品99 | 免费成人黄色片 | 欧美精品一区二区免费 | 国产亚洲精品久久久久久久久久 | 97视频在线观看网址 | 免费观看av网站 | 国产精品都在这里 | 六月丁香综合网 | 激情视频免费在线观看 | 超碰日韩 | 色欧美成人精品a∨在线观看 | 国产精品 日韩精品 | 人人玩人人添人人澡超碰 | 色综合久久88 | 欧美精品视| 久久刺激视频 | 日韩在线观看小视频 | 国产一区网 | 一区二区成人国产精品 | 中文字幕 在线看 | 国产又粗又硬又爽的视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 日韩欧美精品在线观看视频 | 久久99精品国产麻豆婷婷 | 成人一级片免费看 | 天天射天天搞 | 国产精品福利无圣光在线一区 | 久久久久国产精品视频 | 国内毛片毛片 | 天天射天天操天天 | 亚洲 欧美日韩 国产 中文 | 毛片无卡免费无播放器 | 久久久精品小视频 | 天天天色综合 | www.人人草| 99国产精品久久久久老师 | 天天想夜夜操 | 一级做a爱片性色毛片www | 在线国产一区二区 | 久久综合精品一区 | 综合色久 | 少妇超碰在线 | 久久黄色成人 | 婷婷亚洲综合五月天小说 | 99精品热视频只有精品10 | 成人av免费电影 | 久久综合99| 国产99精品在线观看 | 97日日碰人人模人人澡分享吧 | 精品国产一区二区三区av性色 | 激情久久婷婷 | 在线激情影院一区 | 性色av免费观看 | 亚洲手机av| 国产成人精品一区二区三区 | 黄av免费在线观看 | jizz欧美性9 国产一区高清在线观看 | 探花视频网站 | 黄色大片视频网站 | 日日躁你夜夜躁你av蜜 | 日本aaaa级毛片在线看 | 免费国产在线观看 | 欧美性色综合 | 人人cao| 中文字幕日韩免费视频 | 成人黄色大片在线观看 | 久久精品久久久久 | 一区二区三区免费在线 | 99r在线观看 | 日韩在线免费高清视频 | 亚洲欧美日韩精品一区二区 | 人人搞人人爽 | 午夜精品视频免费在线观看 | 日韩精品中文字幕在线不卡尤物 | 在线草 | 成人福利在线播放 | 天天干天天拍天天操天天拍 | 日韩久久在线 | 欧美一级电影免费观看 | 黄色精品视频 | 午夜视频免费在线观看 | 蜜桃传媒一区二区 | 国产精品久久在线 | 久久亚洲美女 | 国产一区久久久 | 亚洲精品免费在线 | www亚洲视频 | 黄色网址a | 日本高清dvd | 久久视频这里有精品 | 极品嫩模被强到高潮呻吟91 | 麻豆94tv免费版 | 狠狠色丁香久久婷婷综 | 成人免费视频播放 | 夜夜嗨av色一区二区不卡 | 亚洲一区二区三区精品在线观看 | 91精品久久久久久综合乱菊 | 国产精品一区二区三区在线 | 激情av网址| 丁香婷婷综合激情五月色 | 日韩精品在线视频免费观看 | 中文字幕资源网在线观看 | 99久久电影 | 国产成人黄色网址 | 国产精品第52页 | 夜夜夜夜猛噜噜噜噜噜初音未来 | 91av在线免费播放 | 久九视频 | 国产成人免费 | 国产精品久久久久久久免费 | 亚洲国产大片 | 99热亚洲精品 | 亚洲一区二区观看 | 久久午夜电影网 | 日韩网站在线免费观看 | 免费观看版 | 色片网站在线观看 | 91丨九色丨国产在线观看 | 手机看片午夜 | 国产精品久久99精品毛片三a | av中文字幕亚洲 | 亚洲精品国产第一综合99久久 | 亚洲女人av | 久久国产精品99国产 | 狠狠的干 | 91在线视频免费播放 | 中文字幕在线观看网 | 在线国产高清 | 91激情视频在线 | 婷婷在线精品视频 | 欧美精品天堂 | 国产黄色免费观看 | 国产免费观看视频 | 欧美日韩视频在线播放 | 91av电影在线观看 | 国产美女免费看 | 国产一级片免费视频 | 美女网站视频免费都是黄 | 国产精品第二十页 | 在线观看中文字幕一区二区 | 精品一区二区在线看 | 在线观看国产永久免费视频 | 精品久久综合 | 青春草国产视频 | 在线免费观看视频一区 | 亚洲国产免费看 | 三级黄色欧美 | 亚洲午夜精品久久久 | 操操操操网 | 最新国产视频 | 欧美精品中文在线免费观看 | av中文天堂 | 91九色国产 | 精品亚洲国产视频 | 就操操久久 | 午夜精品久久久久久久99 | 久久这里有精品 | 日韩久久午夜一级啪啪 | 国产精品欧美日韩在线观看 | 9999亚洲| 在线视频久 | 玖玖在线资源 | 欧美日韩免费观看一区=区三区 | 国产精品视频不卡 | 美女免费黄网站 | av直接看| 日韩中文在线电影 | 激情五月婷婷综合 | www..com黄色片| 精品字幕在线 | 亚洲 欧洲av| 五月婷婷中文 | 最近中文国产在线视频 | 精品专区一区二区 | 色91在线| 51久久夜色精品国产麻豆 | 亚洲jizzjizz日本少妇 | 99视频精品 | 三级免费黄 | 五月天婷亚洲天综合网精品偷 | 久久久免费| 天天干天天射天天操 | 亚洲天堂首页 | 亚洲国产无 | 日韩一二三区不卡 | 欧美激情亚洲综合 | 久久久久成人精品免费播放动漫 | 婷婷网站天天婷婷网站 | 精品久久久久亚洲 | 欧美性色综合 | 成人一区二区在线 | 国产一区在线视频观看 | 国产一区二区在线播放 | 日韩欧美在线免费 | 欧美性精品| 日韩欧美在线高清 | 日韩剧情| 国产精品av在线免费观看 | 久久人人精 | 东方av免费在线观看 | 91精品秘密在线观看 | 天天天在线综合网 | 在线日本看片免费人成视久网 | 亚洲精品久久视频 | 五月天狠狠操 | 欧美激情另类文学 | 国产成人在线观看免费 | 69视频在线播放 | 中文字幕欧美日韩va免费视频 | 久久精品高清视频 | 久操视频在线播放 | av在线官网 | 手机成人免费视频 | 麻豆精品在线 | 成人小视频在线观看免费 | 一级欧美日韩 | 九九久久影视 | 久久久久久久国产精品视频 | 久久手机视频 | 久久精品亚洲国产 | 精品一区二区久久久久久久网站 | 国产精品12345| av黄色大片 | 少妇bbb搡bbbb搡bbbb | 中文字幕国内精品 | 精品一区二区免费 | 一区二区精品视频 | 99精彩视频在线观看免费 | 成人精品一区二区三区中文字幕 | 国产精品国产三级国产 | 亚洲国产精品久久久 | 久久精品官网 | 久久夜色精品国产欧美乱极品 | 黄色福利视频网站 | 天天爽天天做 | 丁香婷婷综合激情五月色 | 久久开心激情 | 日韩在线三区 | a'aaa级片在线观看 | 亚洲欧美va | 天天操夜夜曰 | av成人在线网站 | h网站免费在线观看 | 黄色一二级片 | 特黄特色特刺激视频免费播放 | 国产精品视频永久免费播放 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 视频一区视频二区在线观看 | 在线观看你懂的网址 | 色综合天天干 | 亚洲国产日韩欧美 | 日韩免费高清在线 | 在线观看亚洲电影 | 天天干国产 | 中文区中文字幕免费看 | 天天射综合网站 | 久久免费视频一区 | 黄色小说视频网站 | av黄色国产| 亚洲最大免费成人网 | 欧美久久久久久久久久久久 | 精品国产一区二区久久 | 91亚洲精品久久久 | 亚洲精品视频在线播放 | 国产成人精品一区二区在线 | 日本一区二区三区免费观看 | a视频免费看 | 色97在线 | 精品国产一区二区三区久久久 | 国产一区免费看 | 五月婷婷久草 | www.777奇米| 久久久性| 91麻豆精品| 国产成人av电影在线观看 | 日韩久久精品一区二区三区 | 丁香婷婷网| av在线免费播放网站 | 亚洲老妇xxxxxx | 黄污网站在线观看 | 91大神一区二区三区 | 国产在线视频资源 | 免费在线观看黄色网 | 中文字幕一区二区三区四区 | 日韩高清久久 | 日韩精品视频在线观看免费 | 成人小视频在线免费观看 | 国内精品久久久久久久久 | 一本到视频在线观看 | 最近最新最好看中文视频 | 国产区免费在线 | 美女视频黄免费 | 日韩欧美在线一区二区 | 免费观看国产视频 | 午夜一级免费电影 | 久久99精品国产一区二区三区 | 免费a视频在线 | 992tv人人网tv亚洲精品 | 日韩欧美xxxx | 日本久久91| 在线免费观看的av | 手机在线视频福利 | 91色亚洲 | 国产不卡免费视频 | a色网站| 久久99热这里只有精品 | 中国黄色一级大片 | 久久香蕉一区 | 一区电影 | 射综合网 | 久久精品国产久精国产 | www久久| 91视频首页 | 国产视频在线免费 | 草久在线播放 | 日本中文字幕在线 | 天天插综合 | 婷婷九月激情 | 97视频在线免费观看 | 欧美性精品 | 九九久久久久99精品 | 成人午夜影视 | 免费福利在线播放 | 天天干,天天插 | 国产精品理论片 | 久草精品在线播放 | 欧美大片mv免费 | 成人毛片在线观看视频 | 国产手机av在线 | 在线观看韩日电影免费 | 亚洲少妇激情 | 精品一二三区 | 深夜激情影院 | 欧美午夜激情网 | 五月婷婷综合在线观看 | 国产精品久久久久永久免费观看 | 在线观看免费福利 | 亚洲爱爱视频 | 狠狠色丁婷婷日日 | 国产在线欧美 | 亚洲精品视频在线播放 | 欧美黑吊大战白妞欧美 | 国产丝袜 |