zoukankan      html  css  js  c++  java
  • AM335X启动(转)

    AM335x启动

     

    参考文件:

    1、TI.Reference_Manual_1.pdf

    http://pan.baidu.com/s/1c1BJNtm

    2、TI_AM335X.pdf

    http://pan.baidu.com/s/1geNOYI3

    芯片到uboot启动流程 :ROM → MLO(SPL)→ uboot.img。

    rom为芯片内部的固化的程序,用户不能修改。内部rom程序流程:

    Booting的方式可以通过引脚SYSBOOT[15...0]来配置。SYSBoot[15...0]=LCD_DATA[15...0]引脚,这些引脚的状态会被上电复位后获取。

    AM335x 中bootloader被分成了 3 个部分:

    第一级 bootloader:引导加载程序,板子上电后会自动执行这些代码,如选择哪种方式启动(NAND,SDcard,UART。。。),然后跳转转到第二级 bootloader。这些代码应该是存放在 176KB 的 ROM 中。

    第二级 bootloader:MLO(SPL),用以硬件初始化:关闭看门狗,关闭中断,设置 CPU 时钟频率、速度等操作。然后会跳转到第三级bootloader。MLO文件应该会被映射到 64 KB的 Internal SRAM 中。

    第三级 bootloader:uboot.img,C代码的入口。

    其中第一级 bootloader 是板子固化的,第二级和第三级是通过编译 uboot 所得的。

    u-boot-SPL编译

    也就是说spl的编译是编译uboot的一部分,和uboot.bin走的是两条编译流程,这个要重点注意。 
    正常来说,会先编译主体uboot,也就是uboot.bin.再编译uboot-spl,也就是uboot-spl.bin,虽然编译命令是一起的,但是编译流程是分开的。

    在uboot的顶层目录Makefile中有:

    spl/u-boot-spl.bin: spl/u-boot-spl
    @:
    spl/u-boot-spl: tools prepare (if(if(CONFIG_OF_SEPARATE),dts/dt.dtb)
    (Q)(Q)(MAKE) obj=spl -f $(srctree)/scripts/Makefile.spl all

    指出编译u-boot-spl.bin的链接是在u-boot的顶层目录下的scripts/make.spl里定义的,且要编译u-boot-spl.bin首先要定义CONFIG_SPL(在u-boot的顶层目录下的configs目录对应的AM335X_evm_defconfig有定义)

    在文件scripts/makedile.spl中:

    spl/u-boot-spl.bin依赖如下

               ||

    spl/u-boot-spl-nodtb.bin

               ||

    spl/u-boot-spl

               ||

    u-boot-spl-init,  u-boot-spl-main, spl/u-boot-spl.ld 最后通过cmd_u-boot-spl来生成spl/u-boot-spl。

    重点定义:

      1、CONFIG_SPL:configs/AM335x_evm_defconfig,用于指定是否需要编译SPL,也就是是否需要编译出uboot-spl.bin文件

      2、CONFIG_SPL_TEXT_BASE   定义在板子的对应的config文件中

      3、CONFIG_SPL_BUILD 

    • 在编译spl过程中,会配置 
      u-boot-2016.03/scripts/Makefile.spl中定义了如下 KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD 也就是说在编译uboot-spl.bin的过程中,CONFIG_SPL_BUILD这个宏是被定义的。                                                                                                                                                                                                                                                                                                                                                                                                                    更加具体参考:

    • http://www.cnblogs.com/leaven/p/6296140.html。

    U-boot-spl代码流程

    通过u-boot-spl编译的脚本(Makefile.spl)知u-boot-spl入口:u-boot-2016.03/arch/arm/cpu/armv7/u-boot-spl.lds

    ENTRY(_start)

    所以uboot-spl的代码入口函数是_start 
    对应于路径project-X/u-boot/arch/arm/lib/vector.S的_start,后续就是从这个函数开始分析。

    uboot-spl需要做的事情

    CPU初始刚上电的状态。需要小心的设置好很多状态,包括cpu状态、中断状态、MMU状态等等。 
    在armv7架构的uboot-spl,主要需要做如下事情

    • 关闭中断,svc模式
    • 禁用MMU、TLB
    • 芯片级、板级的一些初始化操作 
      • IO初始化
      • 时钟
      • 内存
      • 选项,串口初始化
      • 选项,nand flash初始化
      • 其他额外的操作
    • 加载u-boot.img,跳转到u-boot.img.

    上述工作,也就是uboot-spl代码流程的核心。

    代码流程

    1、代码整体流程

    代码整体流程如下,以下列出来的就是spl核心函数。 
    _start———–>reset————–>关闭中断 
    ………………………………| 
    ………………………………———->cpu_init_cp15———–>关闭MMU,TLB 
    ………………………………| 
    ………………………………———->cpu_init_crit————->lowlevel_init————->CPU级初始化 
    ………………………………| 
    ………………………………———->_main————–>board_init_f_alloc_reserve & board_init_f_init_reserve & board_init_f———->board_init_r加载u-boot.img,跳转到u-boot.img. 
    board_init_f,board_init_r执行时已经是C语言环境了。在这里需要结束掉SPL的工作,跳转到u-boot.img中。

    2、_start

    上述已经说明了_start是整个spl的入口,其代码如下: 
    arch/arm/lib/vector.S

    _start:
    #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
        .word   CONFIG_SYS_DV_NOR_BOOT_CFG
    #endif
        b   reset

    会跳转到reset中。 
    注意,spl的流程在reset中就应该被结束,也就是说在reset中,就应该转到到BL2,也就是uboot中了。 
    后面看reset的实现。

    3、reset

    建议先参考[kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断,了解一下为什么要设置SVC、关闭中断以及如何操作。目的:svc模式主要用于软件中断和OS操作系统。若是中断未关闭,CPU在初始化阶段有可能产生中断,但是中断处理函数还未就绪(未对中断进行处理),容易使CPU halt停止工作。

    代码如下: 
    arch/arm/cpu/armv7/start.S

        .globl  reset
        .globl  save_boot_params_ret
    
    reset:
        /* Allow the board to save important registers */
        b   save_boot_params
    save_boot_params_ret:
        /*
         * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
         * except if in HYP mode already
         */
        mrs r0, cpsr
        and r1, r0, #0x1f       @ mask mode bits
        teq r1, #0x1a       @ test for HYP mode
        bicne   r0, r0, #0x1f       @ clear all mode bits
        orrne   r0, r0, #0x13       @ set SVC mode
        orr r0, r0, #0xc0       @ disable FIQ and IRQ
        msr cpsr,r0
    @@ 以上通过设置CPSR寄存器里设置CPU为SVC模式,禁止中断
    @@ 具体操作可以参考《[kernel 启动流程] (第二章)第一阶段之——设置SVC、关闭中断》的分析
    
        /* the mask ROM code should have PLL and others stable */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
        bl  cpu_init_cp15
    @@ 调用cpu_init_cp15,初始化协处理器CP15,从而禁用MMU和TLB。
    @@ 后面会有一小节进行分析
    
        bl  cpu_init_crit
    @@ 调用cpu_init_crit,进行一些关键的初始化动作,也就是平台级和板级的初始化
    @@ 后面会有一小节进行分析
    #endif
    
        bl  _main
    @@ 跳转到主函数,也就是要加载BL2以及跳转到BL2的主体部分

    4、cpu_init_cp15

    建议先参考[kernel 启动流程] (第六章)第一阶段之——打开MMU两篇文章的分析。 
    cpu_init_cp15主要用于对cp15协处理器进行初始化,其主要目的就是关闭其MMU和TLB。 
    代码如下(去掉无关部分的代码): 
    arch/arm/cpu/armv7/start.S

    ENTRY(cpu_init_cp15)
        /*
         * Invalidate L1 I/D
         */
        mov r0, #0          @ set up for MCR
        mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs
        mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
        mcr p15, 0, r0, c7, c5, 6   @ invalidate BP array
        mcr     p15, 0, r0, c7, c10, 4  @ DSB
        mcr     p15, 0, r0, c7, c5, 4   @ ISB
    @@ 这里只需要知道是对CP15处理器的部分寄存器清零即可。
    @@ 将协处理器的c7c8清零等等,各个寄存器的含义请参考《ARM的CP15协处理器的寄存器》
    
        /*
         * disable MMU stuff and caches
         */
        mrc p15, 0, r0, c1, c0, 0
        bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
        bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
        orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
        orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
    #ifdef CONFIG_SYS_ICACHE_OFF
        bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
    #else
        orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
    #endif
        mcr p15, 0, r0, c1, c0, 0
    @@ 通过上述的文章的介绍,我们可以知道cp15的c1寄存器就是MMU控制器
    @@ 上述对MMU的一些位进行清零和置位,达到关闭MMU和cache的目的,具体的话去看一下上述文章吧。
    
    ENDPROC(cpu_init_cp15)

    5、cpu_init_crit

    cpu_init_crit,进行一些关键的初始化动作,也就是平台级和板级的初始化。其代码核心就是lowlevel_init,如下 
    arch/arm/cpu/armv7/start.S

    ENTRY(cpu_init_crit)
        /*
         * Jump to board specific initialization...
         * The Mask ROM will have already initialized
         * basic memory. Go here to bump up clock rate and handle
         * wake up conditions.
         */
        b   lowlevel_init       @ go setup pll,mux,memory
    ENDPROC(cpu_init_crit)

    所以说lowlevel_init就是这个函数的核心。 
    lowlevel_init一般是由板级代码自己实现的。但是对于某些平台来说,也可以使用通用的lowlevel_init,其定义在arch/arm/cpu/armv7/lowlevel_init.S中 
    以Am335x为例,在移植过程中,就需要在lowlevel_init.S里加入一些简单的板级初始化,例如在lowlevle_init.s------->s_init中:

    arch/arm/cpu/armv7/am33xx/board.c

    复制代码
    void s_init(void)
    {
    /*
    * The ROM will only have set up sufficient pinmux to allow for the
    * first 4KiB NOR to be read, we must finish doing what we know of
    * the NOR mux in this space in order to continue.
    */
    #ifdef CONFIG_NOR_BOOT
    enable_norboot_pin_mux();
    #endif
    watchdog_disable();               //arch/arm/cpu/armv7/am33xx/board.c
    
    set_uart_mux_conf();            // xx/board/ti/am335x/board.c
    setup_clocks_for_console();   // arch/arm/cpu/armv7/am335x/Clock_am33xx.c
    uart_soft_reset();                 // arch/arm/cpu/armv7/am33xx/board.c
    #if defined(CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC)  // include/configs/ti_am335x_common.h
    /* Enable RTC32K clock */
    rtc32k_enable();                  // arch/arm/cpu/armv7/am33xx/board.c
    #endif
    }
    复制代码

    (其实只要实现了lowlevel_init了就好,没必要说在哪里是实现,但是通常规范都是创建了lowlevel_init.S来专门实现lowlevel_init函数)。

    6、_main

    spl的main的主要目标是调用board_init_f进行先前的板级初始化动作,板级初始化之后调用board_init_r主要设计为,加载u-boot.img到DDR上并且跳转到u-boot.img中。DDR在板级初始化中完成--board_init_f。 
    由于board_init_f是以C语言的方式实现,所以需要先构造C语言环境。 
    注意:uboot-spl和uboot的代码是通用的,其区别就是通过CONFIG_SPL_BUILD宏来进行区分的。 
    所以以下代码中,我们只列出spl相关的部分,也就是被CONFIG_SPL_BUILD包含的部分。 
    arch/arm/lib/crt0.S

    复制代码
    ENTRY(_main)
    
    /*
    * Set up initial C runtime environment and call board_init_f(0). 因为后面是C语言环境,首先是设置堆栈
    */
    
    #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr    sp, =(CONFIG_SPL_STACK)                                                   //设置堆栈为后边调用board_init_f做准备
    #else
    ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
    #endif
    #if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
    mov    r3, sp
    bic    r3, r3, #7
    mov    sp, r3
    #else
    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
    #endif
    mov    r0, sp
    bl    board_init_f_alloc_reserve                                     //2. 为gd_t结构体保留空间理论上有些函数可以用了,例如:preloader_console_init()初始化串口,common/init/board_init.c
    
    
    mov    sp, r0
    /* set up gd here, outside any C code */
    mov    r9, r0
    bl    board_init_f_init_reserve                      //3. 初始化gd_t(清零)  common/init/board_init.c
    
                        //gd_t的地址存在r9寄存器中,结构体中存放的是全局参数                 
    mov r0, #0
    bl    board_init_f
    
    #if ! defined(CONFIG_SPL_BUILD)
    
    /*
    * Set up intermediate environment (new sp and gd) and call
    * relocate_code(addr_moni). Trick here is that we'll return
    * 'here' but relocated.
    */
    
    ldr    sp, [r9, #GD_START_ADDR_SP]    /* sp = gd->start_addr_sp */
    #if defined(CONFIG_CPU_V7M)    /* v7M forbids using SP as BIC destination */
    mov    r3, sp
    bic    r3, r3, #7
    mov    sp, r3
    #else
    bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
    #endif
    ldr    r9, [r9, #GD_BD]    /* r9 = gd->bd */
    sub    r9, r9, #GD_SIZE    /* new GD is below bd */
    
    adr    lr, here
    ldr    r0, [r9, #GD_RELOC_OFF]    /* r0 = gd->reloc_off */
    add    lr, lr, r0
    #if defined(CONFIG_CPU_V7M)
    orr    lr, #1    /* As required by Thumb-only */
    #endif
    ldr    r0, [r9, #GD_RELOCADDR]    /* r0 = gd->relocaddr */
    b    relocate_code
    here:
    /*
    * now relocate vectors
    */
    
    bl    relocate_vectors
    
    /* Set up final (full) environment */
    
    bl    c_runtime_cpu_setup    /* we still call old routine here */
    #endif
    #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
    # ifdef CONFIG_SPL_BUILD
    /* Use a DRAM stack for the rest of SPL, if requested */
    bl    spl_relocate_stack_gd
    cmp    r0, #0
    movne    sp, r0
    movne    r9, r0
    # endif
    ldr    r0, =__bss_start    /* this is auto-relocated! */
    
    #ifdef CONFIG_USE_ARCH_MEMSET
    ldr    r3, =__bss_end    /* this is auto-relocated! */
    mov    r1, #0x00000000    /* prepare zero to clear BSS */
    
    subs    r2, r3, r0    /* r2 = memset len */
    bl    memset
    #else
    ldr    r1, =__bss_end    /* this is auto-relocated! */
    mov    r2, #0x00000000    /* prepare zero to clear BSS */
    
    clbss_l:cmp    r0, r1    /* while not at end of BSS */
    #if defined(CONFIG_CPU_V7M)
    itt    lo
    #endif
    strlo    r2, [r0]    /* clear 32-bit BSS word */
    addlo    r0, r0, #4    /* move to next */
    blo    clbss_l
    #endif
    
    #if ! defined(CONFIG_SPL_BUILD)
    bl coloured_LED_init
    bl red_led_on
    #endif
    /* call board_init_r(gd_t *id, ulong dest_addr) */
    mov r0, r9 /* gd_t */
    ldr    r1, [r9, #GD_RELOCADDR]    /* dest_addr */
    /* call board_init_r */
    #if defined(CONFIG_SYS_THUMB_BUILD)
    ldr    lr, =board_init_r    /* this is auto-relocated! */
    bx    lr
    #else
    ldr    pc, =board_init_r    /* this is auto-relocated! */
    #endif
    /* we should not return here. */
    #endif
    
    ENDPROC(_main)
    复制代码

    代码拆分如下: 
    (1)因为后面是C语言环境,首先是设置堆栈

        ldr sp, =(CONFIG_SPL_STACK)
    @@ 设置堆栈为CONFIG_SPL_STACK
    
        bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
    @@ 堆栈是8字节对齐,2^7bit=2^3byte=8byte
    
        mov r0, sp
    @@ 把堆栈地址存放到r0寄存器中

    关于CONFIG_SPL_STACK,我们通过前面的文章
    我们已经知道am335x的BL1(spl)是运行在RAM的,并且RAM的地址空间是0x402F0400-0x402FFFFF,RAM前面的部分放的是BL1的代码部分,所以把RAM最后的空间用来当作堆栈。 
    所以CONFIG_SPL_STACK定义如下: 
    include/configs/ti_am335x_common.h

                         --->ti_armv7_common.h

                        ---->ti_armv7_keystone2.h

    #define CONFIG_SPL_STACK    (0x402F0400+32*1024+32*1024+8*1024-4)//自己计算结果可能不正确
    • 1
    • 1

    注意:上述还不是最终的堆栈地址,只是暂时的堆栈地址!!!

    (2)为GD分配空间

        bl  board_init_f_alloc_reserve
    @@ 把堆栈的前面一部分空间分配给GD使用
    
        mov sp, r0
    @@ 重新设置堆栈指针SP
    
        /* set up gd here, outside any C code */
        mov r9, r0
    @@ 保存GD的地址到r9寄存器中

    注意:虽然sp的地址和GD的地址是一样的,但是堆栈是向下增长的,而GD则是占用该地址后面的部分,所以不会有冲突的问题。 
    关于GD,也就是struct global_data,可以简单的理解为uboot的全局变量都放在了这里,比较重要,所以后续有会写篇文章说明一下global_data。这里只需要知道在开始C语言环境的时候需要先为这个结构体分配空间。 
    board_init_f_alloc_reserve实现如下 
    common/init/board_init.c

    ulong board_init_f_alloc_reserve(ulong top)
    {
        /* Reserve early malloc arena */
        /* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
        top = rounddown(top-sizeof(struct global_data), 16);
    // 现将top(也就是r0寄存器,前面说过存放了暂时的指针地址),减去sizeof(struct global_data),也就是预留出一部分空间给sizeof(struct global_data)使用。
    // rounddown表示向下16个字节对其
    
        return top;
    // 到这里,top就存放了GD的地址,也是SP的地址
    //把top返回,注意,返回后,其实还是存放在了r0寄存器中。
    }

    还有一点,其实GD在spl中没什么使用,主要是用在uboot中,但在uboot中的时候还需要另外分配空间,在讲述uboot流程的时候会说明。

    (3)初始化GD空间 
    前面说了,此时r0寄存器存放了GD的地址。

        bl  board_init_f_init_reserve

    board_init_f_init_reserve实现如下 
    common/init/board_init.c 
    编译SPL的时候_USE_MEMCPY宏没有打开,所以我们去掉了_USE_MEMCPY的无关部分。

    void board_init_f_init_reserve(ulong base)
    {
        struct global_data *gd_ptr;
        int *ptr;
        /*
         * clear GD entirely and set it up.
         * Use gd_ptr, as gd may not be properly set yet.
         */
    
        gd_ptr = (struct global_data *)base;
    // 从r0获取GD的地址
        /* zero the area */
        for (ptr = (int *)gd_ptr; ptr < (int *)(gd_ptr + 1); )
            *ptr++ = 0;
    // 对GD的空间进行清零
    }

    (4)跳转到板级前期的初始化函数中 

    u-boot-2016.03/arch/arm/cpu/armv7/Am33xx/board.c
    如下代码

        bl  board_init_f

    board_init_f需要由板级代码自己实现。

    u-boot-2016.03/arch/arm/cpu/armv7/Am33xx/board.c

    1 void board_init_f(ulong dummy)
    2 {
    3 board_early_init_f();
    4 preloader_console_init();  //初始化uart,使用Puts函数
    5 sdram_init();
    6 }

    u-boot-2016.03/arch/arm/cpu/armv7/Am33xx/board.c

    1 int board_early_init_f(void)
    2 {
    3     prcm_init();    //系统外设时钟初始化使能,SPI,I2C,uart,gpio.....
    4     set_mux_conf_regs();  //系统外设引功能配置,spi,I2C,uart,gpio.
    5     return 0;
    6 }

    u-boot-2016.03/arch/arm/cpu/armv7/Am33xx/clock.c

    1 void prcm_init()
    2 {
    3     enable_basic_clocks();
    4     scale_vcores();
    5     setup_dplls();
    6 }

    u-boot-2016.03/board/ti/am335x/board.c

    复制代码
    void set_mux_conf_regs(void)
    {
        
        __maybe_unused struct am335x_baseboard_id header;
    
        if (read_eeprom(&header) < 0)
            puts("Could not get board ID.
    ");
        
        enable_board_pin_mux(&header);
            puts("enable_board_pin.
    ");
    }
    复制代码

    u-boot-2016.03/board/ti/am335x/MUX.c

    复制代码
    void enable_board_pin_mux(struct am335x_baseboard_id *header)
    {
        /* Do board-specific muxes. */
        if (board_is_bone(header)) {
            /* Beaglebone pinmux */
            configure_module_pin_mux(mii1_pin_mux);
            configure_module_pin_mux(mmc0_pin_mux);
    #if defined(CONFIG_NAND)
            configure_module_pin_mux(nand_pin_mux);
    #elif defined(CONFIG_NOR)
            configure_module_pin_mux(bone_norcape_pin_mux);
    #else
            configure_module_pin_mux(mmc1_pin_mux);
    #endif
        } else if (board_is_gp_evm(header)) {
            /* General Purpose EVM */
            unsigned short profile = detect_daughter_board_profile();
            configure_module_pin_mux(rgmii1_pin_mux);
            configure_module_pin_mux(mmc0_pin_mux);
            /* In profile #2 i2c1 and spi0 conflict. */
            if (profile & ~PROFILE_2)
                configure_module_pin_mux(i2c1_pin_mux);
            /* Profiles 2 & 3 don't have NAND */
    #ifdef CONFIG_NAND
            if (profile & ~(PROFILE_2 | PROFILE_3))
                configure_module_pin_mux(nand_pin_mux);
    #endif
            else if (profile == PROFILE_2) {
                configure_module_pin_mux(mmc1_pin_mux);
                configure_module_pin_mux(spi0_pin_mux);
            }
        } else if (board_is_idk(header)) {
            /* Industrial Motor Control (IDK) */
            configure_module_pin_mux(mii1_pin_mux);
            configure_module_pin_mux(mmc0_no_cd_pin_mux);
        } else if (board_is_evm_sk(header)) {
            /* Starter Kit EVM */
            configure_module_pin_mux(i2c1_pin_mux); // 配置I2C1对应的引脚为功能引脚,u-boot-2016.03/board/ti/am335x/mux.c
            configure_module_pin_mux(gpio0_7_pin_mux);
            configure_module_pin_mux(rgmii1_pin_mux);
            configure_module_pin_mux(mmc0_pin_mux_sk_evm);
        } else if (board_is_bone_lt(header)) {
            /* Beaglebone LT pinmux */
            configure_module_pin_mux(mii1_pin_mux);
            configure_module_pin_mux(mmc0_pin_mux);
    #if defined(CONFIG_NAND) && defined(CONFIG_EMMC_BOOT)
            configure_module_pin_mux(nand_pin_mux);
    #elif defined(CONFIG_NOR) && defined(CONFIG_EMMC_BOOT)
            configure_module_pin_mux(bone_norcape_pin_mux);
    #else
            configure_module_pin_mux(mmc1_pin_mux);
    #endif
        } else {
            puts("Unknown board, cannot configure pinmux.");
            hang();
        }
    }
    复制代码

    也就是说

    void board_init_f(ulong dummy)
    {
      1、board_early_init_f------>prmc_init(u-boot-2016.03/arch/arm/cpu/armv7/Am33xx/clock.c)------->enable_basic_clocks(u-boot-                                                                             使能CPU各外设包括gpio时钟                                                 2016.03/arch/arm/cpu/armv7/Am33xx/clock_am3xx.c)

                                        ------>set_mux_conf_regs(u-boot-2016.03/board/ti/am335x/board.c)------>enable_board_pin_mux(&header)配置板级各外设引脚功能(UART,MMC,SPI,)u-boot-2016.03/board/ti/am335x/Mux.c

      2、sdram_init()--------------》(u-boot-2016.03/board/ti/am335x/board.c)

              --------->未完待续
    }

    SDRAM初始化,只有SDRAM初始化完成了,才能为下一步的u-boot运行提供运行环境,这一部分也是要根据板上的SDRAM芯片型号来初始化的。

    u-boot-2016.03/board/ti/am335x/board.c

    复制代码
    void sdram_init(void)
    {
        __maybe_unused struct am335x_baseboard_id header;
    
        if (read_eeprom(&header) < 0)
            puts("Could not get board ID.
    ");
    
        if (board_is_evm_sk(&header)) {
            /*
             * EVM SK 1.2A and later use gpio0_7 to enable DDR3.
             * This is safe enough to do on older revs.
             */
            gpio_request(GPIO_DDR_VTT_EN, "ddr_vtt_en"); //请求GPIO0_7脚是否有效,AM335x共有GPIO=32*4.如果GPIO_DDR_VTT_EN的数值在0~127之间,返回0
            gpio_direction_output(GPIO_DDR_VTT_EN, 1);//使GPIO的第8脚,GPIO0_7输出1,使能SDRAM芯片的电源
        }
    
        if (board_is_evm_sk(&header))
            config_ddr(303, &ioregs_evmsk, &ddr3_data,
                   &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0);
        else if (board_is_bone_lt(&header))
            config_ddr(400, &ioregs_bonelt,
                   &ddr3_beagleblack_data,
                   &ddr3_beagleblack_cmd_ctrl_data,
                   &ddr3_beagleblack_emif_reg_data, 0);
        else if (board_is_evm_15_or_later(&header))
            config_ddr(303, &ioregs_evm15, &ddr3_evm_data,
                   &ddr3_evm_cmd_ctrl_data, &ddr3_evm_emif_reg_data, 0);
        else
            config_ddr(266, &ioregs, &ddr2_data,
                   &ddr2_cmd_ctrl_data, &ddr2_emif_reg_data, 0);
                   debug(">>spl:SDRAM_init()
    ");
                   puts(">>spl:SDRAM_init()
    ");
    
    }
    复制代码

     板级的初级初始化之后board_init_f()会为后续的调用board_init_r()函数提供更多的堆栈的空间(放在了SDRAM中)

    bl spl_relocate_stack_gd

    u-boot-2016.03/common/spl/spl.c

    复制代码
    ulong spl_relocate_stack_gd(void)
    {
    #ifdef CONFIG_SPL_STACK_R
        gd_t *new_gd;
        ulong ptr = CONFIG_SPL_STACK_R_ADDR;
    
    #ifdef CONFIG_SPL_SYS_MALLOC_SIMPLE
        if (CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN) {
            if (!(gd->flags & GD_FLG_SPL_INIT))
                panic_str("spl_init must be called before heap reloc");
    
            ptr -= CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN;
            gd->malloc_base = ptr;
            gd->malloc_limit = CONFIG_SPL_STACK_R_MALLOC_SIMPLE_LEN;
            gd->malloc_ptr = 0;
        }
    #endif
        /* Get stack position: use 8-byte alignment for ABI compliance */
        ptr = CONFIG_SPL_STACK_R_ADDR - roundup(sizeof(gd_t),16);
        new_gd = (gd_t *)ptr;
        memcpy(new_gd, (void *)gd, sizeof(gd_t));
    #if !defined(CONFIG_ARM)
        gd = new_gd;
    #endif
        return ptr;
    #else
        return 0;
    #endif
    }
    复制代码

    堆栈空间分配好之后就可以用board_init_r了。

    u-boot-2016.03/common/spl/spl.c

    复制代码
    board_init_r
    {
         1、经行memory的malloc池的初始化
          2、timer_init() 初始化时钟 arch/arm/cpu/armv7/omap_common
          3、spl_board_init() arch/arm/cpu/armv7/omap_common/boot-common.c
          4、jump_to_image_no_args(&spl_image) // 跳转u-boot入口地址 entry_point,entry_point是由u-boot.img头部信息提供的
    5、SPL结束其生命,将控制权交给u-boot/Linux
    }
    复制代码
    arch/arm/cpu/armv7/omap_common/boot-common.c
    复制代码
    void spl_board_init(void)
    {
        /*
         * Save the boot parameters passed from romcode.
         * We cannot delay the saving further than this,
         * to prevent overwrites.
         */
        save_omap_boot_params(); // 这里讲boot_device的参数传递给spl_boot_list(自己理解),确定以什么方式加载u-boot.img(uart or spi or mmc or nand....)
    
        /* Prepare console output */
       // preloader_console_init();
    
    #if defined(CONFIG_SPL_NAND_SUPPORT) || defined(CONFIG_SPL_ONENAND_SUPPORT)
        gpmc_init();
    #endif
    #ifdef CONFIG_SPL_I2C_SUPPORT
        i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, CONFIG_SYS_OMAP24_I2C_SLAVE);
    #endif
    #if defined(CONFIG_AM33XX) && defined(CONFIG_SPL_MUSB_NEW_SUPPORT)
        arch_misc_init();
    #endif
    #if defined(CONFIG_HW_WATCHDOG)
        hw_watchdog_init();
    #endif
    #ifdef CONFIG_AM33XX
        am33xx_spl_board_init();
    #endif
    }
    复制代码

     更加详细的启动顺序,及相关内存地址分配参考:

    链接: https://pan.baidu.com/s/1hseK4cO 密码: m9ci

  • 相关阅读:
    2015531 网络攻防 Exp1 PC平台逆向破解(5)M
    2017-2018-1 20155331 嵌入式C语言
    20155330 《网络对抗》 Exp9 web安全基础实践
    20155330 《网络对抗》 Exp8 Web基础
    20155330 《网络对抗》 Exp7 网络欺诈防范
    20155330 《网络对抗》 Exp6 信息搜集与漏洞扫描
    20155330 《网络对抗》 Exp5 MSF基础应用
    20155330 《网络攻防》 Exp4 恶意代码分析
    20155330 《网络攻防》 Exp3 免杀原理与实践
    20155330 《网络对抗》 Exp2 后门原理与实践
  • 原文地址:https://www.cnblogs.com/lh03061238/p/10181088.html
Copyright © 2011-2022 走看看