程序项目代做,有需求私信(vue、React、Java、爬虫、电路板设计、嵌入式linux等)

Mini2440之uboot移植之源码分析board_init_f(二)

一、board_init_f(common/board_f.c)

该函数位于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;  #0x00
    gd->have_console = 0;    #0x00  

    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
}

填充了flags和have_console字段后就执行一个初始化列表循环,这个循环里面有很多的函数,只要其中一个出错,u-boot启动就会停止。

initcall_run_list位于lib/initcall.c文件中:

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

这里我们记录gd_t这个数据结构:

typedef struct global_data {
    bd_t *bd;
    unsigned long flags;
    unsigned int baudrate;
    unsigned long cpu_clk;    /* CPU clock in Hz!        */
    unsigned long bus_clk;
    /* We cannot bracket this with CONFIG_PCI due to mpc5xxx */
    unsigned long pci_clk;
    unsigned long mem_clk;
#if defined(CONFIG_LCD) || defined(CONFIG_VIDEO)
    unsigned long fb_base;    /* Base address of framebuffer mem */
#endif
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
    unsigned long post_log_word;  /* Record POST activities */
    unsigned long post_log_res; /* success of POST test */
    unsigned long post_init_f_time;  /* When post_init_f started */
#endif
#ifdef CONFIG_BOARD_TYPES
    unsigned long board_type;
#endif
    unsigned long have_console;    /* serial_init() was called */
#ifdef CONFIG_PRE_CONSOLE_BUFFER
    unsigned long precon_buf_idx;    /* Pre-Console buffer index */
#endif
    unsigned long env_addr;    /* Address  of Environment struct */
    unsigned long env_valid;    /* Checksum of Environment valid? */

    unsigned long ram_top;    /* Top address of RAM used by U-Boot */

    unsigned long relocaddr;    /* Start address of U-Boot in RAM */
    phys_size_t ram_size;    /* RAM size */
#ifdef CONFIG_SYS_MEM_RESERVE_SECURE
#define MEM_RESERVE_SECURE_SECURED    0x1
#define MEM_RESERVE_SECURE_MAINTAINED    0x2
#define MEM_RESERVE_SECURE_ADDR_MASK    (~0x3)
    /*
     * Secure memory addr
     * This variable needs maintenance if the RAM base is not zero,
     * or if RAM splits into non-consecutive banks. It also has a
     * flag indicating the secure memory is marked as secure by MMU.
     * Flags used: 0x1 secured
     *             0x2 maintained
     */
    phys_addr_t secure_ram;
#endif
    unsigned long mon_len;    /* monitor len */
    unsigned long irq_sp;        /* irq stack pointer */
    unsigned long start_addr_sp;    /* start_addr_stackpointer */
    unsigned long reloc_off;
    struct global_data *new_gd;    /* relocated global data */

#ifdef CONFIG_DM
    struct udevice    *dm_root;    /* Root instance for Driver Model */
    struct udevice    *dm_root_f;    /* Pre-relocation root instance */
    struct list_head uclass_root;    /* Head of core tree */
#endif
#ifdef CONFIG_TIMER
    struct udevice    *timer;    /* Timer instance for Driver Model */
#endif

    const void *fdt_blob;    /* Our device tree, NULL if none */
    void *new_fdt;        /* Relocated FDT */
    unsigned long fdt_size;    /* Space reserved for relocated FDT */
    struct jt_funcs *jt;        /* jump table */
    char env_buf[32];    /* buffer for getenv() before reloc. */
#ifdef CONFIG_TRACE
    void        *trace_buff;    /* The trace buffer */
#endif
#if defined(CONFIG_SYS_I2C)
    int        cur_i2c_bus;    /* current used i2c bus */
#endif
#ifdef CONFIG_SYS_I2C_MXC
    void *srdata[10];
#endif
    unsigned long timebase_h;
    unsigned long timebase_l;
#ifdef CONFIG_SYS_MALLOC_F_LEN
    unsigned long malloc_base;    /* base address of early malloc() */
    unsigned long malloc_limit;    /* limit address */
    unsigned long malloc_ptr;    /* current address */
#endif
#ifdef CONFIG_PCI
    struct pci_controller *hose;    /* PCI hose for early use */
    phys_addr_t pci_ram_top;    /* top of region accessible to PCI */
#endif
#ifdef CONFIG_PCI_BOOTDELAY
    int pcidelay_done;
#endif
    struct udevice *cur_serial_dev;    /* current serial device */
    struct arch_global_data arch;    /* architecture-specific data */
#ifdef CONFIG_CONSOLE_RECORD
    struct membuff console_out;    /* console output */
    struct membuff console_in;    /* console input */
#endif
#ifdef CONFIG_DM_VIDEO
    ulong video_top;        /* Top of video frame buffer area */
    ulong video_bottom;        /* Bottom of video frame buffer area */
#endif
} gd_t;
#endif

/*
 * Global Data Flags - the top 16 bits are reserved for arch-specific flags
 */
#define GD_FLG_RELOC        0x00001    /* Code was relocated to RAM       */
#define GD_FLG_DEVINIT        0x00002    /* Devices have been initialized   */
#define GD_FLG_SILENT        0x00004    /* Silent mode               */
#define GD_FLG_POSTFAIL        0x00008    /* Critical POST test failed       */
#define GD_FLG_POSTSTOP        0x00010    /* POST seqeunce aborted       */
#define GD_FLG_LOGINIT        0x00020    /* Log Buffer has been initialized */
#define GD_FLG_DISABLE_CONSOLE    0x00040    /* Disable console (in & out)       */
#define GD_FLG_ENV_READY    0x00080    /* Env. imported into hash table   */
#define GD_FLG_SERIAL_READY    0x00100    /* Pre-reloc serial console ready  */
#define GD_FLG_FULL_MALLOC_INIT    0x00200    /* Full malloc() is ready       */
#define GD_FLG_SPL_INIT        0x00400    /* spl_init() has been called       */
#define GD_FLG_SKIP_RELOC    0x00800    /* Don't relocate */
#define GD_FLG_RECORD        0x01000    /* Record console */

#endif /* __ASM_GENERIC_GBL_DATA_H */

二、 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,
};
View Code

函数指针类型:

typedef int (*init_fnc_t)(void);

由于这个数组太长了,下面列出定义函数(如何知道哪些函数被定义了呢,查看反汇编代码u-boot.map和u-boot.dis)

然后我们打开u-boot.dis文件,找到init_sequence_f定义:

0007217c <init_sequence_f>:
   7217c:    0000e70c     .word    0x0000e70c
   72180:    00014964     .word    0x00014964
   72184:    0000e894     .word    0x0000e894
   72188:    0000e72c     .word    0x0000e72c
   7218c:    0000e89c     .word    0x0000e89c
   72190:    0000e8ac     .word    0x0000e8ac
   72194:    0000ea78     .word    0x0000ea78
   72198:    00000fd8     .word    0x00000fd8
   7219c:    00000634     .word    0x00000634
   721a0:    00010610     .word    0x00010610
   721a4:    0000ea4c     .word    0x0000ea4c
   721a8:    0002ea38     .word    0x0002ea38
   721ac:    000144d0     .word    0x000144d0
   721b0:    0005a428     .word    0x0005a428
   721b4:    0000e704     .word    0x0000e704
   721b8:    000003b0     .word    0x000003b0
   721bc:    0000ea34     .word    0x0000ea34
   721c0:    000010e4     .word    0x000010e4
   721c4:    0000e9b4     .word    0x0000e9b4
   721c8:    0000e750     .word    0x0000e750
   721cc:    0000e768     .word    0x0000e768
   721d0:    0000e7a0     .word    0x0000e7a0
   721d4:    0000e7a8     .word    0x0000e7a8
   721d8:    0000e7d8     .word    0x0000e7d8
   721dc:    0000e97c     .word    0x0000e97c
   721e0:    0000e7ec     .word    0x0000e7ec
   721e4:    0000e7f4     .word    0x0000e7f4
   721e8:    0000e810     .word    0x0000e810
   721ec:    0000e8a4     .word    0x0000e8a4
   721f0:    0000e870     .word    0x0000e870
   721f4:    0000ea24     .word    0x0000ea24
   721f8:    0000e944     .word    0x0000e944
   721fc:    0000e88c     .word    0x0000e88c
   72200:    0000e908     .word    0x0000e908
   72204:    0000e8dc     .word    0x0000e8dc
   72208:    00000000     .word    0x00000000

然后我们找到每个函数指针地址,就可以看到对应的函数,最终得到如下函数:

/*虽然未定义的都删除了,但是还是有这么多*/
static const 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,    board_early_init_f,
    timer_init,        /* initialize timer */
    env_init,        /* initialize environment */
    init_baud_rate,        /* initialze baudrate settings */
    serial_init,        /* serial communications setup */
    console_init_f,     
    display_options,   
    display_text_info,   
    print_cpuinfo,      
    announce_dram_init,
    dram_init,        /* configure available RAM banks *//*
     * 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,
    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,
};

三、各个函数指针

3.1 setup_mon_len(common/board_f.c)

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;
}
  • _start为我们的.text的首地址;
  • _bss_end为我们uboot包含所有段的结束地址;

设置gd->mon_len为uboot的大小;

3.2 initf_malloc(common/dlmalloc.c)

CONFIG_SYS_MALLOC_F_LEN没有在顶层.config文件定义:

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

3.3 initf_console_record(common/board_f.c)

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

3.4 arch_cpu_init(common/board_f.c)

__weak int arch_cpu_init(void)
{
    return 0;
}

3.5 initf_dm(common/board_f.c)

动模型相关的初始化,新版的u-boot引入的。

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

3.6 arch_cpu_init_dm(common/board_f.c)

__weak int arch_cpu_init_dm(void)
{
    return 0;
}

3.7 mark_bootstage(common/board_f.c)

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

3.8 board_early_init_f(board/samsung/smdk2440/smdk2440.c)系统时钟初始化FCLK = 400MHz,HCLK = 100MHz, PCLK = 50MHz, UPLL=48MHz

int board_early_init_f(void)
{
    struct s3c24x0_clock_power * const clk_power =
                    s3c24x0_get_base_clock_power();
    struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();

    /* to reduce PLL lock time, adjust the LOCKTIME register */
    writel(0xFFFFFF, &clk_power->locktime);

    /* configure MPLL */
    writel((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV,
           &clk_power->mpllcon);

    /* some delay between MPLL and UPLL */
    pll_delay(4000);

    /* configure UPLL */
    writel((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV,
           &clk_power->upllcon);

    /* some delay between MPLL and UPLL */
    pll_delay(8000);

    /* set up the I/O ports */
    writel(0x007FFFFF, &gpio->gpacon);
    writel(0x00044555, &gpio->gpbcon);
    writel(0x000007FF, &gpio->gpbup);
    writel(0xAAAAAAAA, &gpio->gpccon);
    writel(0x0000FFFF, &gpio->gpcup);
    writel(0xAAAAAAAA, &gpio->gpdcon);
    writel(0x0000FFFF, &gpio->gpdup);
    writel(0xAAAAAAAA, &gpio->gpecon);
    writel(0x0000FFFF, &gpio->gpeup);
    writel(0x000055AA, &gpio->gpfcon);
    writel(0x000000FF, &gpio->gpfup);
    writel(0xFF95FFBA, &gpio->gpgcon);
    writel(0x0000FFFF, &gpio->gpgup);
    writel(0x002AFAAA, &gpio->gphcon);
    writel(0x000007FF, &gpio->gphup);

    return 0;
}

这块代码主要是用来初始化系统时钟和各种IO。

3.9 timer_init(arch/arm/cpu/arm920t/s3c24x0/time.c)

int timer_init(void)
{
    struct s3c24x0_timers *timers = s3c24x0_get_base_timers();
    ulong tmr;

    /* use PWM Timer 4 because it has no output */
    /* prescaler for Timer 4 is 16 */
    writel(0x0f00, &timers->tcfg0);
    if (gd->arch.tbu == 0) {
        /*
         * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
         * (default) and prescaler = 13. Should be 10390
         * @33.25MHz and 15625 @ 50 MHz
         */
        gd->arch.tbu = get_PCLK() / (2 * 16 * 100);
        gd->arch.timer_rate_hz = get_PCLK() / (2 * 16);
    }
    /* load value for 10 ms timeout */
    writel(gd->arch.tbu, &timers->tcntb4);
    /* auto load, manual update of timer 4 */
    tmr = (readl(&timers->tcon) & ~0x0700000) | 0x0600000;
    writel(tmr, &timers->tcon);
    /* auto load, start timer 4 */
    tmr = (tmr & ~0x0700000) | 0x0500000;
    writel(tmr, &timers->tcon);
    gd->arch.lastinc = 0;
    gd->arch.tbl = 0;

    return 0;
}

3.10 env_init设置环境变量存储地址

env_init函数在多个文件中定义,比如使用mmc、nand、nor初始化环境变量:

具体编译时使用哪个文件,我么可以查看common/Makefile文件中的定义:

 可以看到具体编译哪个文件,取决于宏的定义,查找smdk2440.h中配置的宏配置:

发现默认使用NOR FLASH去初始化环境变量,定位到common/env_flash文件:

int env_init(void)
{
    if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
        gd->env_addr    = (ulong)&(env_ptr->data);
        gd->env_valid    = 1;
        return 0;
    }

    gd->env_addr    = (ulong)&default_environment[0];
    gd->env_valid    = 0;
    return 0;
}

这里首先进行crc32校验,如果校验成功,设置gd->env_valid=1,否者设置gd->env_valid=0,也就是使用默认环境变量初始化。

env_ptr由crc校验值和环境变量字符串组成,如果没有向NOR FLASH地址CONFIG_ENV_ADDR处写入环境变量信息,这里是不可能校验成功的。这里是不可能校验成功的。

那crc32什么时候会校验成功呢,只有我们向env_ptr指向的地址(CONFIG_ENV_ADDR)写入正确的环境变量信息,才能进行crc32校验才会成功。

typedef struct environment_s {
    uint32_t    crc;        /* CRC32 over data bytes    */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
    unsigned char    flags;        /* active/obsolete flags    */
#endif
    unsigned char    data[ENV_SIZE]; /* Environment data        */
} env_t

default_environment 是一个全局字符数组,这里使用字符串常量来初始化字符数组,各个环境变量之间使用\0分隔:

#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
env_t environment __PPCENV__ = {
    ENV_CRC,    /* CRC Sum */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
    1,        /* Flags: valid */
#endif
    {
#elif defined(DEFAULT_ENV_INSTANCE_STATIC)
static char default_environment[] = {
#else
const uchar default_environment[] = {
#endif
#ifdef    CONFIG_ENV_CALLBACK_LIST_DEFAULT
    ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
#endif
#ifdef    CONFIG_ENV_FLAGS_LIST_DEFAULT
    ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
#endif
#ifdef    CONFIG_BOOTARGS
    "bootargs="    CONFIG_BOOTARGS            "\0"
#endif
#ifdef    CONFIG_BOOTCOMMAND
    "bootcmd="    CONFIG_BOOTCOMMAND        "\0"
#endif
#ifdef    CONFIG_RAMBOOTCOMMAND
    "ramboot="    CONFIG_RAMBOOTCOMMAND        "\0"
#endif
#ifdef    CONFIG_NFSBOOTCOMMAND
    "nfsboot="    CONFIG_NFSBOOTCOMMAND        "\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    "bootdelay="    __stringify(CONFIG_BOOTDELAY)    "\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
    "baudrate="    __stringify(CONFIG_BAUDRATE)    "\0"
#endif
#ifdef    CONFIG_LOADS_ECHO
    "loads_echo="    __stringify(CONFIG_LOADS_ECHO)    "\0"
#endif
#ifdef    CONFIG_ETHPRIME
    "ethprime="    CONFIG_ETHPRIME            "\0"
#endif
#ifdef    CONFIG_IPADDR
    "ipaddr="    __stringify(CONFIG_IPADDR)    "\0"
#endif
#ifdef    CONFIG_SERVERIP
"serverip="    __stringify(CONFIG_SERVERIP)    "\0"
#endif
#ifdef    CONFIG_SYS_AUTOLOAD
    "autoload="    CONFIG_SYS_AUTOLOAD        "\0"
#endif
#ifdef    CONFIG_PREBOOT
    "preboot="    CONFIG_PREBOOT            "\0"
#endif
#ifdef    CONFIG_ROOTPATH
    "rootpath="    CONFIG_ROOTPATH            "\0"
#endif
#ifdef    CONFIG_GATEWAYIP
    "gatewayip="    __stringify(CONFIG_GATEWAYIP)    "\0"
#endif
#ifdef    CONFIG_NETMASK
    "netmask="    __stringify(CONFIG_NETMASK)    "\0"
#endif
#ifdef    CONFIG_HOSTNAME
    "hostname="    __stringify(CONFIG_HOSTNAME)    "\0"
#endif
#ifdef    CONFIG_BOOTFILE
    "bootfile="    CONFIG_BOOTFILE            "\0"
#endif
#ifdef    CONFIG_LOADADDR
    "loadaddr="    __stringify(CONFIG_LOADADDR)    "\0"
#endif
#ifdef    CONFIG_CLOCKS_IN_MHZ
    "clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
    "pcidelay="    __stringify(CONFIG_PCI_BOOTDELAY)"\0"
#endif
#ifdef    CONFIG_ENV_VARS_UBOOT_CONFIG
    "arch="        CONFIG_SYS_ARCH            "\0"
    "cpu="        CONFIG_SYS_CPU            "\0"
    "board="    CONFIG_SYS_BOARD        "\0"
    "board_name="    CONFIG_SYS_BOARD        "\0"
#ifdef CONFIG_SYS_VENDOR
    "vendor="    CONFIG_SYS_VENDOR        "\0"
#endif
#ifdef CONFIG_SYS_SOC
    "soc="        CONFIG_SYS_SOC            "\0"
#endif
#endif
#ifdef    CONFIG_EXTRA_ENV_SETTINGS
    CONFIG_EXTRA_ENV_SETTINGS
#endif
    "\0"
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
    }
#endif
};

3.11 init_baud_rate(common/board_f.c)

static int init_baud_rate(void)
{
    gd->baudrate = getenv_ulong("baudrate", 10, CONFIG_BAUDRATE);
    return 0;
}

设置波特率值为CONFIG_BAUDRATE=115200.

3.12 serial_init(drivers/serial/serial.c)初始化串口

int serial_init(void)
{
    gd->flags |= GD_FLG_SERIAL_READY;
    return get_current()->start();
}

设置串口准备就绪标志位。然后初始化串口0:

/**
 * get_current() - Return pointer to currently selected serial port
 *
 * This function returns a pointer to currently selected serial port.
 * The currently selected serial port is altered by serial_assign()
 * function.
 *
 * In case this function is called before relocation or before any serial
 * port is configured, this function calls default_serial_console() to
 * determine the serial port. Otherwise, the configured serial port is
 * returned.
 *
 * Returns pointer to the currently selected serial port on success,
 * NULL on error.
 */
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;
}

在drivers/serial/serial_s3c24x0.h文件中定义default_serial_console:

__weak struct serial_device *default_serial_console(void)
{
#if defined(CONFIG_SERIAL1)
    return &s3c24xx_serial0_device;
#elif defined(CONFIG_SERIAL2)
    return &s3c24xx_serial1_device;
#elif defined(CONFIG_SERIAL3)
    return &s3c24xx_serial2_device;
#else
#error "CONFIG_SERIAL? missing."
#endif
}

宏CONFIG_SERIAL1在include/configs/smdk2410.h文件中有定义。

struct serial_device s3c24xx_serial0_device =
INIT_S3C_SERIAL_STRUCTURE(0, "s3ser0");
#define INIT_S3C_SERIAL_STRUCTURE(port, __name) {    \
    .name    = __name,                \
    .start    = s3serial##port##_init,        \
    .stop    = NULL,                    \
    .setbrg    = s3serial##port##_setbrg,        \
    .getc    = s3serial##port##_getc,        \
    .tstc    = s3serial##port##_tstc,        \
    .putc    = s3serial##port##_putc,        \
    .puts    = s3serial##port##_puts,        \
}

然后执行start()方法,即运行s3serial##0##_init():

/* Multi serial device functions */
#define DECLARE_S3C_SERIAL_FUNCTIONS(port) \
    int s3serial##port##_init(void) \
    { \
        return serial_init_dev(port); \
    } \
    void s3serial##port##_setbrg(void) \
    { \
        serial_setbrg_dev(port); \
    } \
    int s3serial##port##_getc(void) \
    { \
        return serial_getc_dev(port); \
    } \
    int s3serial##port##_tstc(void) \
    { \
        return serial_tstc_dev(port); \
    } \
    void s3serial##port##_putc(const char c) \
    { \
        serial_putc_dev(port, c); \
    } \
    void s3serial##port##_puts(const char *s) \
    { \
        serial_puts_dev(port, s); \
    }
/* Initialise the serial port. The settings are always 8 data bits, no parity,
 * 1 stop bit, no start bits.
 */
static int serial_init_dev(const int dev_index)
{
    struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);

    /* FIFO enable, Tx/Rx FIFO clear */
    writel(0x07, &uart->ufcon);
    writel(0x0, &uart->umcon);

    /* Normal,No parity,1 stop,8 bit */
    writel(0x3, &uart->ulcon);
    /*
     * tx=level,rx=edge,disable timeout int.,enable rx error int.,
     * normal,interrupt or polling
     */
    writel(0x245, &uart->ucon);

    _serial_setbrg(dev_index);

    return (0);
}

这里首先获取串口寄存器基地址,然后配置串口相关寄存器:

  • UFCON:FIFO寄存器;
  • UMCON:MODEM控制寄存器;
  • UCON:控制寄存器;

然后通过_serial_setbrg设置波特率:

static void _serial_setbrg(const int dev_index)
{
    struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
    unsigned int reg = 0;
    int i;

    /* value is calculated so : (int)(PCLK/16./baudrate) -1 */
    reg = get_PCLK() / (16 * gd->baudrate) - 1;

    writel(reg, &uart->ubrdiv);
    for (i = 0; i < 100; i++)
        /* Delay */ ;
}

这里通过公式动态计算UBRDIV寄存器的值。其中get_PCLK(arch/arm/cpu/arm920t/s3c24x0/speed.c)通过读取系统时钟相关寄存器的值获取PCLK频率:

/*
 * (C) Copyright 2001-2004
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * (C) Copyright 2002
 * David Mueller, ELSOFT AG, d.mueller@elsoft.ch
 *
 * SPDX-License-Identifier:    GPL-2.0+
 */

/* This code should work for both the S3C2400 and the S3C2410
 * as they seem to have the same PLL and clock machinery inside.
 * The different address mapping is handled by the s3c24xx.h files below.
 */

#include <common.h>
#ifdef CONFIG_S3C24X0

#include <asm/io.h>
#include <asm/arch/s3c24x0_cpu.h>

#define MPLL 0
#define UPLL 1

/* ------------------------------------------------------------------------- */
/* NOTE: This describes the proper use of this file.
 *
 * CONFIG_SYS_CLK_FREQ should be defined as the input frequency of the PLL.
 *
 * get_FCLK(), get_HCLK(), get_PCLK() and get_UCLK() return the clock of
 * the specified bus in HZ.
 */
/* ------------------------------------------------------------------------- */

static ulong get_PLLCLK(int pllreg)
{
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
    ulong r, m, p, s;

    if (pllreg == MPLL)
        r = readl(&clk_power->mpllcon);
    else if (pllreg == UPLL)
        r = readl(&clk_power->upllcon);
    else
        hang();

    m = ((r & 0xFF000) >> 12) + 8;
    p = ((r & 0x003F0) >> 4) + 2;
    s = r & 0x3;

#if defined(CONFIG_S3C2440)
    if (pllreg == MPLL)
        return 2 * m * (CONFIG_SYS_CLK_FREQ / (p << s));
#endif
    return (CONFIG_SYS_CLK_FREQ * m) / (p << s);

}

/* return FCLK frequency */
ulong get_FCLK(void)
{
    return get_PLLCLK(MPLL);
}

/* return HCLK frequency */
ulong get_HCLK(void)
{
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
#ifdef CONFIG_S3C2440
    switch (readl(&clk_power->clkdivn) & 0x6) {
    default:
    case 0:
        return get_FCLK();
    case 2:
        return get_FCLK() / 2;
    case 4:
        return (readl(&clk_power->camdivn) & (1 << 9)) ?
            get_FCLK() / 8 : get_FCLK() / 4;
    case 6:
        return (readl(&clk_power->camdivn) & (1 << 8)) ?
            get_FCLK() / 6 : get_FCLK() / 3;
    }
#else
    return (readl(&clk_power->clkdivn) & 2) ? get_FCLK() / 2 : get_FCLK();
#endif
}

/* return PCLK frequency */
ulong get_PCLK(void)
{
    struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();

    return (readl(&clk_power->clkdivn) & 1) ? get_HCLK() / 2 : get_HCLK();
}

/* return UCLK frequency */
ulong get_UCLK(void)
{
    return get_PLLCLK(UPLL);
}

#endif /* CONFIG_S3C24X0 */

3.13 console_init_f(common/console.c)

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

3.14 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
    return 0;
}

打印版本信息,你可以修改include/version.h中的CONFIG_IDENT_STRING选项, * 加入你的身份信息

3.15 display_text_info(common/board_f.c)

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

如果定义了#define DEBUG,打印bss段信息及text_base。

3.16 print_cpuinfo(arch/arm/cpu/arm920t/s3c24x0/cpu_info.c)

int print_cpuinfo(void)
{
    int i;
    char buf[32];
/* the S3C2400 seems to be lacking a CHIP ID register */
#ifndef CONFIG_S3C2400
    ulong cpuid;
    struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio();

    cpuid = readl(&gpio->gstatus1);
    printf("CPUID: %8lX\n", cpuid);
#endif
    for (i = 0; i < ARRAY_SIZE(freq_f); i++)
        printf("%cCLK: %8s MHz\n", freq_c[i], strmhz(buf, freq_f[i]()));

    return 0;
}

打印CPUID和时钟频率。默认只打印FCLK、HCLK、PCLK,如果想打印UCLK,修改全局变量freq_f、freq_c为:

static const getfreq freq_f[] = {
        get_FCLK,
        get_HCLK,
        get_PCLK,
        get_UCLK,
};

static const char freq_c[] = { 'F', 'H', 'P','U' };

3.17 announce_dram_init(common/board_f.c)

static int announce_dram_init(void)
{
    puts("DRAM:  ");
    return 0;
}

输出"DRAM: " 然后在下面进行SDRAM参数设置。

3.18 dram_init(board/samsung/smdk2410/smdk2410.c)

int dram_init(void)
{
    /* dram_init must store complete ramsize in gd->ram_size */
    gd->ram_size = PHYS_SDRAM_1_SIZE;
    return 0;
}

设置SDRAM大小,PHYS_SDRAM_1_SIZE =64MB。

3.19 setup_dest_addr(common/board_f.c)

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);  //ram_size=64MB

#ifdef CONFIG_SYS_SDRAM_BASE
    gd->ram_top = CONFIG_SYS_SDRAM_BASE;       //在smdk2410.h定义的0x30000000
#endif
    gd->ram_top += get_effective_memsize();     // gd->ram_top+gd->ram_size
    gd->ram_top = board_get_usable_ram_top(gd->mon_len);  //return gd->ram_top
    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;
}

将gd->relocaddr、gd->ram_top指向SDRAM最顶端0x30000000+64MB。

3.20 reserve_round_4k(common/board_f.c)

/* Round memory pointer down to next 4 kB limit */
static int reserve_round_4k(void)
{
    gd->relocaddr &= ~(4096 - 1);
    return 0;
}

gd->relocaddr 4k向下对齐。

3.21 reserve_mmu(common/board_f.c)

static int reserve_mmu(void)
{
    /* reserve TLB table */
    gd->arch.tlb_size = PGTABLE_SIZE;
    gd->relocaddr -= gd->arch.tlb_size;

    /* round down to next 64 kB limit */
    gd->relocaddr &= ~(0x10000 - 1);  //64k向下对齐

    gd->arch.tlb_addr = gd->relocaddr;
    debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
          gd->arch.tlb_addr + gd->arch.tlb_size);
    return 0;
}

预留MMU空间,PGTABLE_SIZE大小为16kb。这里又64kb向下对齐。

#define PGTABLE_SIZE        (4096 * 4)

3.22 reserve_trace(common/board_f.c)

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

    return 0;
}

3.23 reserve_uboot(common/board_f.c)

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;   // 减去u-boot总长度
    gd->relocaddr &= ~(4096 - 1);    //4k对齐  
#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;

    return 0;
}

预留u-boot空间,并设置relocaddr向下k对齐。

3.24 reserve_malloc(common/board_f.c)

/* reserve memory for malloc() area */
static int reserve_malloc(void)
{
    gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN;
    debug("Reserving %dk for malloc() at: %08lx\n",
            TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp);
    return 0;
}

预留一段malloc的空间,大小为4MB。在./include/common.h和./include/configs/smdk2410.h中定义有:

#define    TOTAL_MALLOC_LEN    CONFIG_SYS_MALLOC_LEN
/*
 * Size of malloc() pool
 * BZIP2 / LZO / LZMA need a lot of RAM
 */
#define CONFIG_SYS_MALLOC_LEN    (4 * 1024 * 1024)

3.25 reserve_board(common/board_f.c)

/* (permanently) allocate a Board Info struct */
static int reserve_board(void)
{
    if (!gd->bd) {
        gd->start_addr_sp -= sizeof(bd_t);
        gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t));
        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;
}

保留gd->bd的空间,大小为bd_t结构体大小。

3.26 setup_machine(common/board_f.c)

static int setup_machine(void)
{
#ifdef CONFIG_MACH_TYPE
    gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
#endif
    return 0;
}

3.27 reserve_global_data(common/board_f.c)

static int reserve_global_data(void)
{
    gd->start_addr_sp -= sizeof(gd_t);
    gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t));
    debug("Reserving %zu Bytes for Global Data at: %08lx\n",
            sizeof(gd_t), gd->start_addr_sp);
    return 0;
}

3.28 reserve_fdt(common/board_f.c)

static int reserve_fdt(void)
{
#ifndef CONFIG_OF_EMBED
    /*
     * If the device tree is sitting immediately above our image then we
     * must relocate it. If it is embedded in the data section, then it
     * will be relocated with other data.
     */
    if (gd->fdt_blob) {
        gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);

        gd->start_addr_sp -= gd->fdt_size;
        gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size);
        debug("Reserving %lu Bytes for FDT at: %08lx\n",
              gd->fdt_size, gd->start_addr_sp);
    }
#endif

    return 0;
}

3.29 reserve_arch(common/board_f.c)

__weak int reserve_arch(void)
{
    return 0;
}

3.30 reserve_stacks(common/board_f.c)

static int reserve_stacks(void)
{
    /* make stack pointer 16-byte aligned */
    gd->start_addr_sp -= 16;
    gd->start_addr_sp &= ~0xf;

    /*
     * let the architecture-specific code tailor gd->start_addr_sp and
     * gd->irq_sp
     */
    return arch_reserve_stacks();
}

预留栈空间。

3.31 setup_dram_config(common/board_f.c)

static int setup_dram_config(void)
{
    /* Ram is board specific, so move it to board code ... */
    dram_init_banksize();

    return 0;
}

设置sdram地址和大小。gd->bd->bi_dram[i].start = addr,gd->bd->bi_dram[i].size = size。

3.32 show_dram_config(common/board_f.c)

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

打印SDRAM大小,与上面的announce_dram_init相对应。

3.33 display_new_sp(common/board_f.c)

static int display_new_sp(void)
{
    debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp);

    return 0;
}

若 #define DEBUG 则打印新的栈地址。

3.34 reloc_fdt(common/board_f.c)

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

    return 0;
}

GD_FLG_SKIP_RELOC 定义为0x00800。gd->flags & GD_FLG_SKIP_RELOC=0x100&0x800=0。gd->new_fdt未初始化,为0。

3.35 setup_reloc(common/board_f.c)

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;  /* 得到新旧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 */

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

将gd数据从旧地址拷贝到新地址。

以上所有初始化函数执行完毕,内存空间分布如下:

 其中gd成员变量如下:

bd

开发板数据指针

CONFIG_SYS_SDRAM_BASE+PHYS_SDRAM_1_SIZE-uboot-64kb-malloc-sizeof(bd_t)

0x30000000 + 64MB-uboot-64kb-malloc-sizeof(bd_t)

flags

指示标志,如设备已经初始化啦

GD_FLG_SERIAL_READY

0x00100    

baudrate

串口波特率

115200

cpu_clk

CPU clock in Hz

 

bus_clk

 

 

pci_clk

 

 

mem_clk

 

 

have_console

serial_init() was called

1

env_addr

环境变量的起始地址

 

env_valid

校验环境变量是否有效

0

ram_top

Top address of RAM used by U-Boot

CONFIG_SYS_SDRAM_BASE+PHYS_SDRAM_1_SIZE

0x30000000 + 64MB

relocaddr

Start address of U-Boot in RAM

CONFIG_SYS_SDRAM_BASE+PHYS_SDRAM_1_SIZE-uboot-64kb

0x30000000 + 64MB-uboot-64KB

ram_size

RAM size

PHYS_SDRAM_1_SIZE    64MB

mon_len

u-boot总长度

(ulong)&__bss_end - (ulong)_start;

irq_sp

irq stack pointer

 

start_addr_sp

start_addr_stackpointer

CONFIG_SYS_SDRAM_BASE+PHYS_SDRAM_1_SIZE-uboot-64kb-malloc-sizeof(bd_t)-sizeof(gd_t)-16

0x30000000 + 64MB-uboot-64kb-malloc-sizeof(bd_t)-sizeof(gd_t)-16

然后 向下16字节对齐

reloc_off

 

gd->relocaddr - CONFIG_SYS_TEXT_BASE

其中CONFIG_SYS_TEXT_BASE=0

new_gd

relocated global data

CONFIG_SYS_SDRAM_BASE+PHYS_SDRAM_1_SIZE-uboot-64kb-malloc-sizeof(bd_t)-sizeof(gd_t)

0x30000000 + 64MB-uboot-64kb-malloc-sizeof(bd_t)-sizeof(gd_t)

fdt_blob

Our device tree, NULL if none

 

new_fdt

Relocated FDT

 

fdt_size

Space reserved for relocated FDT

 

jt

jump table

 

env_buf

buffer for getenv() before reloc

 

timebase_h

 

 

timebase_l

 

 

cur_serial_dev

 

 

arch

 

 

四、总结

看完这部分代码,你会发现这部分代码并不复杂,大部分工作主要是对u-boot之后重定位进行内存的规划,也就是初始化gd成员变量。除了这些以外,当然还做了以下事情:

  • 初始化系统时钟和基本IO;
  • 初始化定时器;
  • 初始化环境变量,指定环境变量存放地址(指向一个字符数组);
  • 初始化串口0,作为控制台输出;
  • 打印版本信息;
  • 打印bss段信息及text_base;
  • 打印CPUID和系统时钟信息;
  • 打印DRAM信息;
  • 打印新的栈地址;

参考文章:

[1]从零开始之uboot、移植uboot2017.01(五、board_init_f分析)

[2]u-boot2020.04移植(4、board_init_f)

posted @ 2021-11-12 22:34  大奥特曼打小怪兽  阅读(758)  评论(2编辑  收藏  举报
如果有任何技术小问题,欢迎大家交流沟通,共同进步