• Mini440之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/smdk2410/smdk2410.c)

    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(common/board_f.c)

    int env_init(void)
    {
        /* 默认环境变量初始化 */
        gd->env_addr    = (ulong)&default_environment[0];
        gd->env_valid    = 0;
     
        return 0;
    }

    设置环境变量的地址,default_environment ,这里面定义了默认的参数:

    #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/cpuinfo.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和时钟频率。

    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)

  • 相关阅读:
    LeetCode-Longest Substring Without Repeating Characters
    LeetCode-Add Two Numbers
    LeetCode-Two Sum
    品格的塑造
    闰年的来历
    float在内存中的存取方法
    矩阵顺时针旋转90度
    研究生毕业论文查重
    PAT1009
    PAT1008
  • 原文地址:https://www.cnblogs.com/zyly/p/15544221.html
Copyright © 2020-2023  润新知