Mini440之uboot移植之源码分析(四)


board_init_r和board_init_f差不多,都是执行一个循环。这里是循环执行init_sequence_r[]里的函数指针。

一、board_init_r(common/board_r.c)

void board_init_r(gd_t *new_gd, ulong dest_addr)
{
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    int i;
#endif

#ifdef CONFIG_AVR32
    mmu_init_r(dest_addr);
#endif

#if !defined(CONFIG_X86) && !defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
    gd = new_gd;
#endif

#ifdef CONFIG_NEEDS_MANUAL_RELOC
    for (i = 0; i < ARRAY_SIZE(init_sequence_r); i++)
        init_sequence_r[i] += gd->reloc_off;
#endif

    if (initcall_run_list(init_sequence_r))
        hang();

    /* NOTREACHED - run_main_loop() does not return */
    hang();
}

在上一篇博客中我们已经介绍了该函数调用表时会传入两个参数:

  • new_gd:为u-boot重定位后的新地址的gd结构;
  • dest_addr:u-boot重定位后的地址;

然后循环遍历init_sequence_r中的每一个函数,并执行。

二、init_sequence_r

/*
 * Over time we hope to remove these functions with code fragments and
 * stub funtcions, and instead call the relevant function directly.
 *
 * We also hope to remove most of the driver-related init and do it if/when
 * the driver is later used.
 *
 * TODO: perhaps reset the watchdog in the initcall function after each call?
 */
init_fnc_t init_sequence_r[] = {
    initr_trace,
    initr_reloc,
    /* TODO: could x86/PPC have this also perhaps? */
#ifdef CONFIG_ARM
    initr_caches,
    /* Note: For Freescale LS2 SoCs, new MMU table is created in DDR.
     *     A temporary mapping of IFC high region is since removed,
     *     so environmental variables in NOR flash is not availble
     *     until board_init() is called below to remap IFC to high
     *     region.
     */
#endif
    initr_reloc_global_data,
#if defined(CONFIG_SYS_INIT_RAM_LOCK) && defined(CONFIG_E500)
    initr_unlock_ram_in_cache,
#endif
    initr_barrier,
    initr_malloc,
    initr_console_record,
#ifdef CONFIG_SYS_NONCACHED_MEMORY
    initr_noncached,
#endif
    bootstage_relocate,
#ifdef CONFIG_DM
    initr_dm,
#endif
    initr_bootstage,
#if defined(CONFIG_ARM) || defined(CONFIG_NDS32)
    board_init,    /* Setup chipselects */
#endif
    /*
     * TODO: printing of the clock inforamtion of the board is now
     * implemented as part of bdinfo command. Currently only support for
     * davinci SOC's is added. Remove this check once all the board
     * implement this.
     */
#ifdef CONFIG_CLOCKS
    set_cpu_clk_info, /* Setup clock information */
#endif
#ifdef CONFIG_EFI_LOADER
    efi_memory_init,
#endif
    stdio_init_tables,
    initr_serial,
    initr_announce,
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_NEEDS_MANUAL_RELOC
    initr_manual_reloc_cmdtable,
#endif
#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
    initr_trap,
#endif
#ifdef CONFIG_ADDR_MAP
    initr_addr_map,
#endif
#if defined(CONFIG_BOARD_EARLY_INIT_R)
    board_early_init_r,
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_LOGBUFFER
    initr_logbuffer,
#endif
#ifdef CONFIG_POST
    initr_post_backlog,
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_SYS_DELAYED_ICACHE
    initr_icache_enable,
#endif
#if defined(CONFIG_PCI) && defined(CONFIG_SYS_EARLY_PCI_INIT)
    /*
     * Do early PCI configuration _before_ the flash gets initialised,
     * because PCU ressources are crucial for flash access on some boards.
     */
    initr_pci,
#endif
#ifdef CONFIG_WINBOND_83C553
    initr_w83c553f,
#endif
#ifdef CONFIG_ARCH_EARLY_INIT_R
    arch_early_init_r,
#endif
    power_init_board,
#ifndef CONFIG_SYS_NO_FLASH
    initr_flash,
#endif
    INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_X86) || \
    defined(CONFIG_SPARC)
    /* initialize higher level parts of CPU like time base and timers */
    cpu_init_r,
#endif
#ifdef CONFIG_PPC
    initr_spi,
#endif
#ifdef CONFIG_CMD_NAND
    initr_nand,
#endif
#ifdef CONFIG_CMD_ONENAND
    initr_onenand,
#endif
#ifdef CONFIG_GENERIC_MMC
    initr_mmc,
#endif
#ifdef CONFIG_HAS_DATAFLASH
    initr_dataflash,
#endif
    initr_env,
#ifdef CONFIG_SYS_BOOTPARAMS_LEN
    initr_malloc_bootparams,
#endif
    INIT_FUNC_WATCHDOG_RESET
    initr_secondary_cpu,
#if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET)
    mac_read_from_eeprom,
#endif
    INIT_FUNC_WATCHDOG_RESET
#if defined(CONFIG_PCI) && !defined(CONFIG_SYS_EARLY_PCI_INIT)
    /*
     * Do pci configuration
     */
    initr_pci,
#endif
    stdio_add_devices,
    initr_jumptable,
#ifdef CONFIG_API
    initr_api,
#endif
    console_init_r,        /* fully init console as a device */
#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
    show_board_info,
#endif
#ifdef CONFIG_ARCH_MISC_INIT
    arch_misc_init,        /* miscellaneous arch-dependent init */
#endif
#ifdef CONFIG_MISC_INIT_R
    misc_init_r,        /* miscellaneous platform-dependent init */
#endif
    INIT_FUNC_WATCHDOG_RESET
#ifdef CONFIG_CMD_KGDB
    initr_kgdb,
#endif
    interrupt_init,
#if defined(CONFIG_ARM) || defined(CONFIG_AVR32)
    initr_enable_interrupts,
#endif
#if defined(CONFIG_MICROBLAZE) || defined(CONFIG_AVR32) || defined(CONFIG_M68K)
    timer_init,        /* initialize timer */
#endif
#if defined(CONFIG_STATUS_LED)
    initr_status_led,
#endif
    /* PPC has a udelay(20) here dating from 2002. Why? */
#ifdef CONFIG_CMD_NET
    initr_ethaddr,
#endif
#ifdef CONFIG_BOARD_LATE_INIT
    board_late_init,
#endif
#if defined(CONFIG_CMD_AMBAPP)
    ambapp_init_reloc,
#if defined(CONFIG_SYS_AMBAPP_PRINT_ON_STARTUP)
    initr_ambapp_print,
#endif
#endif
#ifdef CONFIG_CMD_SCSI
    INIT_FUNC_WATCHDOG_RESET
    initr_scsi,
#endif
#ifdef CONFIG_CMD_DOC
    INIT_FUNC_WATCHDOG_RESET
    initr_doc,
#endif
#ifdef CONFIG_BITBANGMII
    initr_bbmii,
#endif
#ifdef CONFIG_CMD_NET
    INIT_FUNC_WATCHDOG_RESET
    initr_net,
#endif
#ifdef CONFIG_POST
    initr_post,
#endif
#if defined(CONFIG_CMD_PCMCIA) && !defined(CONFIG_CMD_IDE)
    initr_pcmcia,
#endif
#if defined(CONFIG_CMD_IDE)
    initr_ide,
#endif
#ifdef CONFIG_LAST_STAGE_INIT
    INIT_FUNC_WATCHDOG_RESET
    /*
     * Some parts can be only initialized if all others (like
     * Interrupts) are up and running (i.e. the PC-style ISA
     * keyboard).
     */
    last_stage_init,
#endif
#ifdef CONFIG_CMD_BEDBUG
    INIT_FUNC_WATCHDOG_RESET
    initr_bedbug,
#endif
#if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
    initr_mem,
#endif
#ifdef CONFIG_PS2KBD
    initr_kbd,
#endif
#if defined(CONFIG_SPARC)
    prom_init,
#endif
    run_main_loop,
};

通过反汇编代码我们可以确定实际定义了哪些函数:

0007220c :
   7220c:    0000eab0     .word    0x0000eab0     initr_trace
   72210:    0000eab8     .word    0x0000eab8     initr_reloc
   72214:    0000ec88     .word    0x0000ec88     initr_caches
   72218:    0000ead0     .word    0x0000ead0     initr_reloc_global_data
   7221c:    0000eaf8     .word    0x0000eaf8     initr_barrier
   72220:    0000ec6c     .word    0x0000ec6c     initr_malloc
   72224:    0000eb00     .word    0x0000eb00     initr_console_record
   72228:    0000ea8c     .word    0x0000ea8c     bootstage_relocate
   7222c:    0000ec58     .word    0x0000ec58     initr_bootstage
   72230:    0000111c     .word    0x0000111c     board_init
   72234:    000163c8     .word    0x000163c8     stdio_init_tables
   72238:    0000ec48     .word    0x0000ec48     initr_serial
   7223c:    0000eb10     .word    0x0000eb10     initr_announce
   72240:    0000eb08     .word    0x0000eb08     power_init_board
   72244:    0000ebcc     .word    0x0000ebcc     initr_flash
   72248:    0000ebb0     .word    0x0000ebb0     initr_nand
   7224c:    0000eb80     .word    0x0000eb80     initr_env
   72250:    0000eaa0     .word    0x0000eaa0     initr_secondary_cpu
   72254:    00016488     .word    0x00016488     stdio_add_devices
   72258:    0000eb70     .word    0x0000eb70     initr_jumptable
   7225c:    000146e0     .word    0x000146e0     console_init_r
   72260:    00000ae0     .word    0x00000ae0     interrupt_init
   72264:    0000eb60     .word    0x0000eb60     initr_enable_interrupts
   72268:    0000eb40     .word    0x0000eb40     initr_ethaddr
   7226c:    0000eb24     .word    0x0000eb24     initr_net
   72270:    0000eb18     .word    0x0000eb18     run_main_loop

三、各个函数指针

3.1 initr_trace(common/board_r.c)

static int initr_trace(void)
{
#ifdef CONFIG_TRACE
    trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE);
#endif

    return 0;
}

3.2 initr_reloc(common/board_r.c)

static int initr_reloc(void)
{
    /* tell others: relocation done */
    gd->flags |= GD_FLG_RELOC | GD_FLG_FULL_MALLOC_INIT;

    return 0;
}

常量GD_FLG_RELOC 和GD_FLG_FULL_MALLOC_INIT定义如下:

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

设置gd->flags标志位第1位、第10位为1。

3.3 initr_caches(common/board_r.c)

static int initr_caches(void)
{
    /* Enable caches */
    enable_caches();
    return 0;
}

enable_caches()使能缓存,定义在arch/arm/lib/cache.c:

/*
 * Default implementation of enable_caches()
 * Real implementation should be in platform code
 */
__weak void enable_caches(void)
{
    puts("WARNING: Caches not enabled\n");
}

3.4 initr_reloc_global_data(common/board_r.c)

static int initr_reloc_global_data(void)
{
#ifdef __ARM__
    monitor_flash_len = _end - __image_copy_start;
#elif defined(CONFIG_NDS32)
    monitor_flash_len = (ulong)&_end - (ulong)&_start;
#elif !defined(CONFIG_SANDBOX) && !defined(CONFIG_NIOS2)
    monitor_flash_len = (ulong)&__init_end - gd->relocaddr;
#endif
#if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)
    /*
     * The gd->cpu pointer is set to an address in flash before relocation.
     * We need to update it to point to the same CPU entry in RAM.
     * TODO: why not just add gd->reloc_ofs?
     */
    gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;

    /*
     * If we didn't know the cpu mask & # cores, we can save them of
     * now rather than 'computing' them constantly
     */
    fixup_cpu();
#endif
#ifdef CONFIG_SYS_EXTRA_ENV_RELOC
    /*
     * Some systems need to relocate the env_addr pointer early because the
     * location it points to will get invalidated before env_relocate is
     * called.  One example is on systems that might use a L2 or L3 cache
     * in SRAM mode and initialize that cache from SRAM mode back to being
     * a cache in cpu_init_r.
     */
    gd->env_addr += gd->relocaddr - CONFIG_SYS_MONITOR_BASE;
#endif
#ifdef CONFIG_OF_EMBED
    /*
    * The fdt_blob needs to be moved to new relocation address
    * incase of FDT blob is embedded with in image
    */
    gd->fdt_blob += gd->reloc_off;
#endif
#ifdef CONFIG_EFI_LOADER
    efi_runtime_relocate(gd->relocaddr, NULL);
#endif

    return 0;
}

全局变量monitor_flash_len定义:

ulong monitor_flash_len;

3.5 initr_barrier(common/board_r.c)

static int initr_barrier(void)
{
#ifdef CONFIG_PPC
    /* TODO: Can we not use dmb() macros for this? */
    asm("sync ; isync");
#endif
    return 0;
}

3.6 initr_malloc(common/board_r.c)

static int initr_malloc(void)
{
    ulong malloc_start;

#ifdef CONFIG_SYS_MALLOC_F_LEN
    debug("Pre-reloc malloc() used %#lx bytes (%ld KB)\n", gd->malloc_ptr,
          gd->malloc_ptr / 1024);
#endif
    /* The malloc area is immediately below the monitor copy in DRAM */
    malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN;
    mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN),
            TOTAL_MALLOC_LEN);
    return 0;
}

从board_init_f画出的内存图可知,u-boot重定位地址的下面就是预留的堆区。

设置malloc的起始地址,malloc_start设置为u-boot重定位后的地址-TOTAL_MALLOC_LEN,TOTAL_MALLOC_LEN之前有介绍4MB。

然后填充了三个全局变量并将堆区全部清零。

3.7 initr_console_record(common/board_r.c)

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

3.8 bootstage_relocate(common/bootstage.c)

int bootstage_relocate(void)
{
    int i;

    /*
     * Duplicate all strings.  They may point to an old location in the
     * program .text section that can eventually get trashed.
     */
    for (i = 0; i < BOOTSTAGE_ID_COUNT; i++)
        if (record[i].name)
            record[i].name = strdup(record[i].name);

    return 0;
}

3.9 initr_bootstage(common/board_r.c)

static int initr_bootstage(void)
{
    /* We cannot do this before initr_dm() */
    bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

    return 0;
}

3.10 board_init(board/samaung/smdk2410.c)

int board_init(void)
{
    /* arch number of SMDK2410-Board */
    gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

    /* adress of boot parameters */
    gd->bd->bi_boot_params = 0x30000100;

    icache_enable();
    dcache_enable();

    return 0;
}

gd->bd->bi_arch_number修改成SMDK2410的机器码,启动linux需要的,但实际测试,这个就算不设置也能够启动,但我们还是将其添加上(可在arch/arm/include/asm/mach-types.h中找到。

#define MACH_TYPE_SMDK2410             193

然后设置gd->bd->bi_boot_params,从0x30000100地址开始存放启动参数,内核启动时会从这里取出参数。

3.11 stdio_init_tables(common/sdtio.c)

int stdio_init_tables(void)
{
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
    /* already relocated for current ARM implementation */
    ulong relocation_offset = gd->reloc_off;
    int i;

    /* relocate device name pointers */
    for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
        stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
                        relocation_offset);
    }
#endif /* CONFIG_NEEDS_MANUAL_RELOC */

    /* Initialize the list */
    INIT_LIST_HEAD(&(devs.list));

    return 0;
}

初始化了一个双向循环链表:

static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

3.12 initr_serial(common/board_r.c)

static int initr_serial(void)
{
    serial_initialize();
    return 0;
}

串口初始化,serial_initialize定义在drivers/serial/serial.c文件:

/**
 * serial_initialize() - Register all compiled-in serial port drivers
 *
 * This function registers all serial port drivers that are compiled
 * into the U-Boot binary with the serial core, thus making them
 * available to U-Boot to use. Lastly, this function assigns a default
 * serial port to the serial core. That serial port is then used as a
 * default output.
 */
void serial_initialize(void)
{
    amirix_serial_initialize();
    arc_serial_initialize();
    arm_dcc_initialize();
    asc_serial_initialize();
    atmel_serial_initialize();
    au1x00_serial_initialize();
    bfin_jtag_initialize();
    bfin_serial_initialize();
    bmw_serial_initialize();
    clps7111_serial_initialize();
    cogent_serial_initialize();
    cpci750_serial_initialize();
    evb64260_serial_initialize();
    imx_serial_initialize();
    iop480_serial_initialize();
    jz_serial_initialize();
    leon2_serial_initialize();
    leon3_serial_initialize();
    lh7a40x_serial_initialize();
    lpc32xx_serial_initialize();
    marvell_serial_initialize();
    max3100_serial_initialize();
    mcf_serial_initialize();
    ml2_serial_initialize();
    mpc512x_serial_initialize();
    mpc5xx_serial_initialize();
    mpc8260_scc_serial_initialize();
    mpc8260_smc_serial_initialize();
    mpc85xx_serial_initialize();
    mpc8xx_serial_initialize();
    mxc_serial_initialize();
    mxs_auart_initialize();
    ns16550_serial_initialize();
    oc_serial_initialize();
    p3mx_serial_initialize();
    pl01x_serial_initialize();
    pxa_serial_initialize();
    s3c24xx_serial_initialize();
    s5p_serial_initialize();
    sa1100_serial_initialize();
    sandbox_serial_initialize();
    sconsole_serial_initialize();
    sh_serial_initialize();
    stm32_serial_initialize();
    uartlite_serial_initialize();
    zynq_serial_initialize();

    serial_assign(default_serial_console()->name);
}

3.13 initr_announce(common/board_r.c)

static int initr_announce(void)
{
    debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr);
    return 0;
}

3.14 power_init_board(common/board_r.c)

__weak int power_init_board(void)
{
    return 0;
}

3.15 initr_flash(common/board_r.c)

static int initr_flash(void)
{
    ulong flash_size = 0;
    bd_t *bd = gd->bd;

    puts("Flash: ");

    if (board_flash_wp_on())
        printf("Uninitialized - Write Protect On\n");
    else
        flash_size = flash_init();

    print_size(flash_size, "");
#ifdef CONFIG_SYS_FLASH_CHECKSUM
    /*
    * Compute and print flash CRC if flashchecksum is set to 'y'
    *
    * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
    */
    if (getenv_yesno("flashchecksum") == 1) {
        printf("  CRC: %08X", crc32(0,
            (const unsigned char *) CONFIG_SYS_FLASH_BASE,
            flash_size));
    }
#endif /* CONFIG_SYS_FLASH_CHECKSUM */
    putc('\n');

    /* update start of FLASH memory    */
#ifdef CONFIG_SYS_FLASH_BASE
    bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
#endif
    /* size of FLASH memory (final value) */
    bd->bi_flashsize = flash_size;

#if defined(CONFIG_SYS_UPDATE_FLASH_SIZE)
    /* Make a update of the Memctrl. */
    update_flash_size(flash_size);
#endif


#if defined(CONFIG_OXC) || defined(CONFIG_RMU)
    /* flash mapped at end of memory map */
    bd->bi_flashoffset = CONFIG_SYS_TEXT_BASE + flash_size;
#elif CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
    bd->bi_flashoffset = monitor_flash_len;    /* reserved area for monitor */
#endif
    return 0;
}

3.16 initr_nand(common/board_r.c)

static int initr_nand(void)
{
    puts("NAND:  ");
    nand_init();
    return 0;
}

初始化nand flash。

3.17 initr_env(common/board_r.c)

static int initr_env(void)
{
    /* initialize environment */
    if (should_load_env())
        env_relocate();
    else
        set_default_env(NULL);
#ifdef CONFIG_OF_CONTROL
    setenv_addr("fdtcontroladdr", gd->fdt_blob);
#endif

    /* Initialize from environment */
    load_addr = getenv_ulong("loadaddr", 16, load_addr);
#if defined(CONFIG_SYS_EXTBDINFO)
#if defined(CONFIG_405GP) || defined(CONFIG_405EP)
#if defined(CONFIG_I2CFAST)
    /*
     * set bi_iic_fast for linux taking environment variable
     * "i2cfast" into account
     */
    {
        char *s = getenv("i2cfast");

        if (s && ((*s == 'y') || (*s == 'Y'))) {
            gd->bd->bi_iic_fast[0] = 1;
            gd->bd->bi_iic_fast[1] = 1;
        }
    }
#endif /* CONFIG_I2CFAST */
#endif /* CONFIG_405GP, CONFIG_405EP */
#endif /* CONFIG_SYS_EXTBDINFO */
    return 0;
}

3.18 initr_secondary_cpu(common/board_r.c)

static int initr_secondary_cpu(void)
{
    /*
     * after non-volatile devices & environment is setup and cpu code have
     * another round to deal with any initialization that might require
     * full access to the environment or loading of some image (firmware)
     * from a non-volatile device
     */
    /* TODO: maybe define this for all archs? */
    cpu_secondary_init_r();

    return 0;
}

3.19 stdio_add_devices(common/sdtio.c)

int stdio_add_devices(void)
{
#ifdef CONFIG_DM_KEYBOARD
    struct udevice *dev;
    struct uclass *uc;
    int ret;

    /*
     * For now we probe all the devices here. At some point this should be
     * done only when the devices are required - e.g. we have a list of
     * input devices to start up in the stdin environment variable. That
     * work probably makes more sense when stdio itself is converted to
     * driver model.
     *
     * TODO(sjg@chromium.org): Convert changing uclass_first_device() etc.
     * to return the device even on error. Then we could use that here.
     */
    ret = uclass_get(UCLASS_KEYBOARD, &uc);
    if (ret)
        return ret;

    /* Don't report errors to the caller - assume that they are non-fatal */
    uclass_foreach_dev(dev, uc) {
        ret = device_probe(dev);
        if (ret)
            printf("Failed to probe keyboard '%s'\n", dev->name);
    }
#endif
#ifdef CONFIG_SYS_I2C
    i2c_init_all();
#else
#if defined(CONFIG_HARD_I2C)
    i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
#endif
#endif
#ifdef CONFIG_DM_VIDEO
    struct udevice *vdev;
# ifndef CONFIG_DM_KEYBOARD
    int ret;
# endif

    for (ret = uclass_first_device(UCLASS_VIDEO, &vdev);
         vdev;
         ret = uclass_next_device(&vdev))
        ;
    if (ret)
        printf("%s: Video device failed (ret=%d)\n", __func__, ret);
#else
# if defined(CONFIG_LCD)
    drv_lcd_init ();
# endif
# if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
    drv_video_init ();
# endif
#endif /* CONFIG_DM_VIDEO */
#if defined(CONFIG_KEYBOARD) && !defined(CONFIG_DM_KEYBOARD)
    drv_keyboard_init ();
#endif
#ifdef CONFIG_LOGBUFFER
    drv_logbuff_init ();
#endif
    drv_system_init ();
    serial_stdio_init ();
#ifdef CONFIG_USB_TTY
    drv_usbtty_init ();
#endif
#ifdef CONFIG_NETCONSOLE
    drv_nc_init ();
#endif
#ifdef CONFIG_JTAG_CONSOLE
    drv_jtag_console_init ();
#endif
#ifdef CONFIG_CBMEM_CONSOLE
    cbmemc_init();
#endif

    return 0;
}

3.20 initr_jumptable(common/board_r.c)

static int initr_jumptable(void)
{
    jumptable_init();
    return 0;
}

3.21 console_init_r(common/sonsole.c)

int console_init_r(void)
{
    struct stdio_dev *inputdev = NULL, *outputdev = NULL;
    int i;
    struct list_head *list = stdio_get_list();
    struct list_head *pos;
    struct stdio_dev *dev;

#ifdef CONFIG_SPLASH_SCREEN
    /*
     * suppress all output if splash screen is enabled and we have
     * a bmp to display. We redirect the output from frame buffer
     * console to serial console in this case or suppress it if
     * "silent" mode was requested.
     */
    if (getenv("splashimage") != NULL) {
        if (!(gd->flags & GD_FLG_SILENT))
            outputdev = search_device (DEV_FLAGS_OUTPUT, "serial");
    }
#endif

    /* Scan devices looking for input and output devices */
    list_for_each(pos, list) {
        dev = list_entry(pos, struct stdio_dev, list);

        if ((dev->flags & DEV_FLAGS_INPUT) && (inputdev == NULL)) {
            inputdev = dev;
        }
        if ((dev->flags & DEV_FLAGS_OUTPUT) && (outputdev == NULL)) {
            outputdev = dev;
        }
        if(inputdev && outputdev)
            break;
    }

    /* Initializes output console first */
    if (outputdev != NULL) {
        console_setfile(stdout, outputdev);
        console_setfile(stderr, outputdev);
#ifdef CONFIG_CONSOLE_MUX
        console_devices[stdout][0] = outputdev;
        console_devices[stderr][0] = outputdev;
#endif
    }

    /* Initializes input console */
    if (inputdev != NULL) {
        console_setfile(stdin, inputdev);
#ifdef CONFIG_CONSOLE_MUX
        console_devices[stdin][0] = inputdev;
#endif
    }

#ifndef CONFIG_SYS_CONSOLE_INFO_QUIET
    stdio_print_current_devices();
#endif /* CONFIG_SYS_CONSOLE_INFO_QUIET */

    /* Setting environment variables */
    for (i = 0; i < 3; i++) {
        setenv(stdio_names[i], stdio_devices[i]->name);
    }

    gd->flags |= GD_FLG_DEVINIT;    /* device initialization completed */

#if 0
    /* If nothing usable installed, use only the initial console */
    if ((stdio_devices[stdin] == NULL) && (stdio_devices[stdout] == NULL))
        return 0;
#endif
    print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT2_EVERYTHING_BUT_SERIAL);
    return 0;
}

3.22 interrupt_init(arch/arm/lib/interrupts.c)

int interrupt_init(void)
{
    return 0;
}

3.23 initr_enable_interrupts(common/board_r.c)

static int initr_enable_interrupts(void)
{
    enable_interrupts();
    return 0;
}

3.24 initr_ethaddr(common/board_r.c)

static int initr_ethaddr(void)
{
    bd_t *bd = gd->bd;

    /* kept around for legacy kernels only ... ignore the next section */
    eth_getenv_enetaddr("ethaddr", bd->bi_enetaddr);
#ifdef CONFIG_HAS_ETH1
    eth_getenv_enetaddr("eth1addr", bd->bi_enet1addr);
#endif
#ifdef CONFIG_HAS_ETH2
    eth_getenv_enetaddr("eth2addr", bd->bi_enet2addr);
#endif
#ifdef CONFIG_HAS_ETH3
    eth_getenv_enetaddr("eth3addr", bd->bi_enet3addr);
#endif
#ifdef CONFIG_HAS_ETH4
    eth_getenv_enetaddr("eth4addr", bd->bi_enet4addr);
#endif
#ifdef CONFIG_HAS_ETH5
    eth_getenv_enetaddr("eth5addr", bd->bi_enet5addr);
#endif
    return 0;
}

3.25 initr_net(common/board_r.c)

static int initr_net(void)
{
    puts("Net:   ");
    eth_initialize();
#if defined(CONFIG_RESET_PHY_R)
    debug("Reset Ethernet PHY\n");
    reset_phy();
#endif
    return 0;
}

3.26 run_main_loop

到此,board_init_r也就分析完了,最后就是进入u-boot的大循环run_main_loop了,这个里面就是启动内核或者处理用户输入的命令,这部分后面再详细分析一下。

参考文章:

[1]u-boot2020.04移植(6、board_init_r)

[2]