猫史档案馆


【插件实验室专版】深入Android启动---上电自检及uboot 上

用户:顺铂顺铂查看:0 回复:4 评论:0 创建时间:2018-12-15T13:52:15


上次,我们发布了安卓的启动过程,不是很好。希望zhei次能有个全新的开始~

 

话不多说,开始讲解~

《深入android启动》分为以下几个部分:

1、上电自检及uboot---美好的开端

2、Linux内核---风华正茂

3、init进程与init.rc---纠缠不清的关系

4、deamon守护代理进程

5、zytoge---星星之火

6、System Services

7、从activitymanager到homeactivity---使命完成

 

先贴张jpg

 

 

本次先讲解下uboot吧

当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redbootubootqi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。Android引导程序可以在\bootable\bootloader\legacy\usbloader找到。
uboot运行有两个阶段,一个阶段是运行在SRAM中的汇编阶段,另一个是运行在DDR中的C语言阶段。

与大多数BootLoader一样,uboot的启动过程分为BL1和BL2两个阶段。BL1阶段通常是开发板的配置等设备初始化代码,需要依赖依赖于SoC体系结构,通常用汇编语言来实现;BL2阶段主要是对外部设备如网卡、Flash等的初始化以及uboot命令集等的自身实现,通常用C语言来实现。

1、BL1阶段

    uboot的BL1阶段代码通常放在start.s文件中,用汇编语言实现,其主要代码功能如下:

    (1) 指定uboot的入口。在链接脚本uboot.lds中指定uboot的入口为start.S中的_start。

    (2)设置异常向量(exception vector)

    (3)关闭IRQ、FIQ,设置SVC模式

    (4)关闭L1 cache、设置L2 cache、关闭MMU

    (5)根据OM引脚确定启动方式

    (6)在SoC内部SRAM中设置栈

    (7)lowlevel_init(主要初始化系统时钟、SDRAM初始化、串口初始化等)

    (8)设置开发板供电锁存

    (9)设置SDRAM中的栈

    (10)将uboot从SD卡拷贝到SDRAM中

    (11)设置并开启MMU

    (12)通过对SDRAM整体使用规划,在SDRAM中合适的地方设置栈

    (13)清除bss段,远跳转到start_armboot执行,BL1阶段执行完

2、 BL2阶段

    start_armboot函数位于lib_arm/board.c中,是C语言开始的函数,也是BL2阶段代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,BL2阶段的主要功能如下:

        (1)规划uboot的内存使用

        (2)遍历调用函数指针数组init_sequence中的初始化函数

        (3)初始化uboot的堆管理器mem_malloc_init

        (4)初始化SMDKV210开发板的SD/MMC控制器mmc_initialize

        (5)环境变量重定位env_relocate

        (6)、将环境变量中网卡地址赋值给全局变量的开发板变量

        (7)、开发板硬件设备的初始化devices_init

        (8)、跳转表jumptable_init

        (9)、控制台初始化console_init_r

       (10)、网卡芯片初始化eth_initialize

       (11)、uboot进入主循环main_loop

二、uboot程序入口分析 1、 link.lds链接脚本文件分析

u-boot.lds文件是uboot工程的链接脚本文件,位于board\samsung\喵dkc110目录下,对于工程项目编译后期的链接阶段非常重要,决定了uboot程序的组装。

u-boot.lds链接文件中的ENTRY(_start)指定了uboot程序的入口地址为_start。

2、定位uboot程序入口地址

在SourceInsight建立uboot工程,利用索引功能查找_start,在搜索结果中找到与三星喵dkv210开发板相关的代码,最终锁定cpu\s5pc11x\start.S文件,定位到文件中的_start标识符。

 

 

第一阶段;

  1. #include @该文件是第二步中mkconfig文件执行时创建的。include/config.h
    #include
    #include @在include目录下。
    /*
    *************************************************************************
    *
    * Jump vector table as in table 3.1 in [1]
    *
    *************************************************************************
    */
    @这是一个异常跳转表,
    .globl _start
    _start: 
    b start_code  @start_code才是真正的启动代码
    ldr pc, _undefined_instruction
    ldr pc, _software_interrupt
    ldr pc, _prefetch_abort
    ldr pc, _data_abort
    ldr pc, _not_used
    ldr pc, _irq
    ldr pc, _fiq
    
    _undefined_instruction: .word undefined_instruction @在标号_undefined_instruction处存储了一个变量,该变量也是一个标号地址
    _software_interrupt: .word software_interrupt @执行上面的ldr pc, _undefined_instruction;指令会将变量undefined_instruction的值装入PC
    _prefetch_abort: .word prefetch_abort @pc指向一个地址,喵U从该地址中取指执行
    _data_abort: .word data_abort
    _not_used: .word not_used
    _irq: .word irq
    _fiq: .word fiq
    .balignl 16,0xdeadbeef
    
    /*
    *************************************************************************
    *
    * Startup Code (called from the ARM reset exception vector)
    *
    * do important init only if we don't start from memory!
    * relocate armboot to ram
    * setup stack
    * jump to second stage
    *
    *************************************************************************
    */
    _TEXT_BASE:
    .word TEXT_BASE @变量TEXT_BASE由连接脚本指定,
    
    .globl _armboot_start
    
    _armboot_start:
    .word _start @_start是在起始代码处定义的标号,当跳到_armboot_start后还是会跳转到_start
    /*
    * These are defined in the board-specific linker script.
    */
    .globl _bss_start
    
    _bss_start:
    .word __bss_start  @这是board/mini2440/u-boot.lds脚本中的变量,
    
    .globl _bss_end
    _bss_end:
    .word _end  @这也是board/mini2440/u-boot.lds脚本中的变量,
    
    #ifdef CONFIG_USE_IRQ  @这个宏在include/configs/$(board_name).h中定义。可以取消
    /* IRQ stack memory (calculated at run-time) */
    .globl IRQ_STACK_START
    IRQ_STACK_START:
    .word 0x0badc0de
    /* IRQ stack memory (calculated at run-time) */
    .globl FIQ_STACK_START
    FIQ_STACK_START:
    .word 0x0badc0de
    #endif
    
    /*
    * the actual start code
    */
    
    start_code:  @这是真正的启动代码
    /* set the cpu to SVC32 mode*/
    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0
    bl coloured_LED_init @这个函数在status_led.h中被提升了作用域,但是在哪里面实现??status_led.h文件
    bl red_LED_on @同上
    
    @下面这些宏开关也是在include/configs/$(board_name).h中定义??
    #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
    
    /*
    * relocate exception table
    */
    ldr r0, =_start
    ldr r1, =0x0
    mov r2, #16
    
    copyex:
    subs r2, r2, #1
    ldr r3, [r0], #4
    str r3, [r1], #4
    bne copyex
    #endif
    
    @下面这些宏开关是在include/configs/$(board_name).h中定义
    #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)||defined(CONFIG_S3C2440)
    /* turn off the watchdog */
    # if defined(CONFIG_S3C2400)
    # define pWTCON 0x15300000
    # define IN喵SK 0x14400008 /* Interupt-Controller base addresses */
    # define CLKDIVN 0x14800014 /* clock divisor register */
    #else
    # define pWTCON 0x53000000
    # define IN喵SK 0x4A000008 /* Interupt-Controller base addresses */
    # define INTSUBMSK 0x4A00001C
    # define CLKDIVN 0x4C000014 /* clock divisor register */
    # endif
    #define CLK_CTL_BASE 0x4c000000
    #define MDIV_405 0x7f<<12
    #define PSDIV_405 0x21
    #define UPLL_MDIV_48 0x38<<12
    #define UPLL_PSDIV_48 0x22
    #define MDIV_200 0xa1<<12
    #define PSDIV_200 0x31
    ldr r0, =pWTCON
    mov r1, #0x0
    str r1, [r0]
    
    /*
    * mask all IRQs by setting all bits in the IN喵R - default
    */
    mov r1, #0xffffffff
    ldr r0, =IN喵SK
    str r1, [r0]
    # if defined(CONFIG_S3C2410)
    ldr r1, =0x3ff
    ldr r0, =INTSUBMSK
    str r1, [r0]
    # endif
    
    /*add by gray*/
    #if defined(CONFIG_S3C2440)
    ldr r1, =0x7fff
    ldr r0, =INTSUBMSK
    str r1, [r0]
    #endif
    
    /*add by gray,这里是修改后的,其实可以在uboot启动的第二阶段start_armboot()函数里调用board_init()函数时重置喵U钟
    
    对于S3C2440,MPLL(clk)=(2 * m * Fin) / p * 2^s,
    m = MDIV + 8, p = PDIV + 2, s = SDIV.
    这里MDIV =  0x7f, PDIV = 0x2 ,SDIV = 0x1 
    */
    #if defined(CONFIG_S3C2440)
    /*FCLK:HCLK:PCLK=1:2:4*/
    ldr r0, =CLKDIVN
    mov r1, #5
    str r1,[r0]
    
    mrc p15,0,r1,c1,c0,0 /*read ctrl reg*/
    orr r1,r1,#0xc0000000 /*ASYN*/
    mcr p15,0,r1,c1,c0,0 /*write ctrl reg*/
    
    mov r1,#CLK_CTL_BASE
    
    mov r2,#UPLL_MDIV_48
    add r2, r2,#UPLL_PSDIV_48
    str r2,[r1,#0x08] /*write UPLL first,48MHZ*/
    
    mov r2,#MDIV_405
    add r2,r2,#PSDIV_405  /*mpll_405MHZ*/
    str r2,[r1,#0x04]  /*MPLLCON*/
    #else
    /*F:H:P=1:2:4*/
    ldr r0, =CLKDIVN
    mov r1, #3
    str r1,[r0]
    
    mrc p15,0,r1,c1,c0,0  /*read ctrl reg*/
    orr r1,r1,#0xc0000000
    mcr p15,0,r1,c1,c0,0
    
    mov r1,#CLK_CTL_BASE
    mov r2,#MDIV_200
    add r2,r2,#PSDIV_200  /*mpll_200MHZ*/
    str r2,[r1,#0x04]  /*MPLLCON*/
    #endif
    #endif /*CONFIG_S3C2400 || CONFIG_S3C2410 || CONFIG_S3C2440*/
    
    /*
    * we do sys-critical inits only at reboot,
    * not when booting from ram!
    */
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl cpu_init_crit @如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,就进行严格的初始化,调用lowlevel_init函数
    #endif
    
    #ifndef CONFIG_AT91RM9200 @AT91RM9200评估板,基于ARM920T内核
    #ifndef CONFIG_SKIP_RELOCATE_UBOOT
    
    /* relocate U-Boot to RAM */
    relocate: 
    adr r0, _start   /* r0 <- current position of code */
    ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
    cmp r0, r1  /* don't reloc during debug */
    beq stack_setup   /*如果_start与_TEXT_BASE相等,就直接跳去stack_setup进行栈的设置, 否则就要进行代码的拷贝,把代码拷贝到内存中*/
    
    ldr r2, _armboot_start
    ldr r3, _bss_start  @计算代码段大小=_bss_start-_armboot_start
    sub r2, r3, r2  /* r2 <- size of armboot */
    add r2, r0, r2  /* r2 <- source end address */
    @ r2 = _start的地址+代码段大小
    copy_loop:
    ldmia r0!, {r3-r10}  /* copy from source address [r0] */
    stmia r1!, {r3-r10}  /* copy to target address [r1] */
    cmp r0, r2  /* until source end addreee [r2] */
    ble copy_loop
    #endif  /* CONFIG_SKIP_RELOCATE_UBOOT */
    #endif
    
    
    /* Set up the stack,设置栈 */
    stack_setup:
    ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
    sub r0, r0, #CFG_MALLOC_LEN  /* malloc area,这是堆区 */
    sub r0, r0, #CFG_GBL_DATA_SIZE  /* bdinfo */
    
    #ifdef CONFIG_USE_IRQ @如果定义了IRQ,就要为IRQ,FIQ分配中断栈。
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    #endif
    sub sp, r0, #12  /* leave 3 words for abort-stack */
    clear_bss:  @清除bss段,_bss_start 和_bss_end就是u-boot.lds脚本传入的变量
    ldr r0, _bss_start  /* find start of bss segment */
    ldr r1, _bss_end  /* stop here */
    mov r2, #0x00000000  /* clear */
    clbss_l:str r2, [r0]  /* clear loop... */
    add r0, r0, #4
    cmp r0, r1
    ble clbss_l
    
    ldr pc, _start_armboot
    _start_armboot: .word start_armboot @跳到start_armboot()函数执行,进入uboot的第二阶段
    
    /*
    *************************************************************************
    *
    * 喵U_init_critical registers
    *
    * setup important registers
    * setup memory timing
    *
    *************************************************************************
    */
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    cpu_init_crit:  @进行严格的初始化,关闭I/D caches,MMU,
    
    /*
    * flush v4 I/D caches
    */
    mov r0, #0
    mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
    mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */
    
    /*
    * disable MMU stuff and caches
    */
    mrc p15, 0, r0, c1, c0, 0
    bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
    bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
    orr r0, r0, #0x00000002 @ set bit 2 (A) Align
    orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
    mcr p15, 0, r0, c1, c0, 0
    
    /*
    * before relocating, we have to setup RAM timing
    * because memory timing is board-dependend, you will
    * find a lowlevel_init.S in your board directory.
    */
    
    mov ip, lr
    #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF)
    #else
    
    bl lowlevel_init  @这个函数是重点。。在lowlevel_init.S中
    #endif
    
    mov lr, ip
    mov pc, lr
    #endif  /* CONFIG_SKIP_LOWLEVEL_INIT */
    
    lowlevel_init.S的内容:
    _TEXT_BASE:
    .word TEXT_BASE
    .globl lowlevel_init
    
    lowlevel_init:  @很明显,是初始化SDRAM
    /* memory control configuration */
    /* make r0 relative the current location so that it */
    /* reads SMRDATA out of FLASH rather than memory ! */
    ldr r0, =SMRDATA
    ldr r1, _TEXT_BASE
    sub r0, r0, r1
    ldr r1, =BWSCON  /* Bus Width Status Controller */
    add r2, r0, #13*4
    
    0:
    ldr r3, [r0], #4
    str r3, [r1], #4
    cmp r2, r0
    bne 0b
    
    /* everything is fine now */
    mov pc, lr
    .ltorg
  1. 分析下
  2. start.S有四个头文件:

    #include <config.h>

        config.h头文件在配置开发板时由mkconfig脚本创建的头文件,头文件内容即包含开发板的头文件:#include <configs/喵dkv210single.h>

    #include <version.h>

        version.h头文件的内容为包含自动生成的版本头文件,头文件内容为:#include "version_autogenerated.h",version_autogenerated.h头文件定义了版本宏,宏定义为:#define U_BOOT_VERSION "U-Boot 1.3.4"。版本宏的值就是Makefile中定义的版本信息。

    #include <a喵/proc/domain.h>

        domain.h头文件在定义了CONFIG_ENABLE_MMU宏时有效,为链接文件,实际指向的文件为include/a喵-arm/proc-armv/domain.h。

    #include <regs.h>

    regs.h头文件为链接文件,指向s5pc110.h头文件,s5pc110.h文件内部使用宏定义了有关SoC内部寄存器的大量信息。

  3. 2、头校验信息的占位

    #if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)

    .word 0x2000

    .word 0x0

    .word 0x0

    .word 0x0

    #endif

    定义uboot程序开头的16字节校验头信息填充空间,头校验信息块内的值需要在后面写入。

    3、异常向量表的构建

    .globl _start

    _start:

    b reset

    ldrpc, _undefined_instruction

    ldrpc, _software_interrupt

    ldrpc, _prefetch_abort

    ldrpc, _data_abort

    ldrpc, _not_used

    ldrpc, _irq

    ldrpc, _fiq

        uboot程序的入口点实际是定义了异常向量表,异常向量表由SoC硬件实现,因此uboot在开机上电复位时需要跳转到reset执行。

    4、复位reset分析

    SoC上电复位后运行的第一段代码就是reset。主要包括以下几部分:

    A、关闭IRQ、FIQ,并将处理器模式设置为SVC模式

    B、喵U关键寄存器的初始化cpu_init_crit:

        关闭L2 cache

        初始化L2 cache

        开启L2 cache

        关闭L1 cache

        关闭MMU

        读取OM启动引脚信息

        确定从启动设备SD卡启动

        设置SRAM中的栈为调用lowlevel_init做准备(lowlevel_init内部有嵌套调用)

        调用lowlevel_init(主要初始化系统时钟、SDRAM初始化、串口初始化等)

        设置开发板供电锁存

        设置SDRAM中的栈

        判断当前代码是否运行在SDRAM中,如果当前代码运行在SDRAM中,则跳过代码重定位。

        判断启动方式,选择SD卡启动设备,跳转到mmcsd_boot

        SD卡启动的准备工作,从SD卡拷贝uboot到SDRAM:movi_bl2_copy

     

    C、设置MMU,开启MMU

    D、通过对SDRAM整体使用规划,在SDRAM中合适的地方设置栈

    E、清除bss段,远跳转到start_armboot执行,BL1阶段执行完

    5、lowlevel_init分析

    lowlevel_init位于\board\samsung\喵dkc110\lowlevel_init.S中,主要功能如下:

        A、检查复位状态,判断启动的方式

    根据复位状态选择复位启动的方式,处于低功耗状态时复位启动可以跳过后续多个步骤。

        B、IO状态恢复

        C、关闭看门狗

        D、外部SRAM的GPIO初始化、外部SROM初始化

        E、开发板供电锁存设置

        F、判断当前代码是否运行在SDRAM,如果当前代码运行在SDRAM,说明目前从低功耗状态复位,可以跳过系统时钟初始化、串口初始化、SDRAM初始化等

        G、初始化系统时钟:system_clock_init

        H、初始化SDRAM内存:mem_ctrl_a喵_init

        I、初始化串口,打印出’O’:uart_a喵_init

        J、初始化trustzone:tzpc_init

        K、初始化nand或onenand

        L、检查复位状态

        M、关闭ABB

        N、串口打印出‘K’

    说明:”OK”是打印出的调试信息,如果打印出’O’则说明在串口初始化uart_a喵_init前的所有代码是正确的。如果打印出”OK”则说明在开发板板级初始化lowlevel_init前的所有代码是正常工作的。

    system_clock_init、uart_a喵_init、tzpc_init、nand_a喵_init都位于lowlevel_init.S文件内,mem_ctrl_a喵_init位于cpu\s5pc11x\s5pc110\cpu_init.S文件中。

 

 

 

 

  1. 进入uboot启动的第二阶段:start_armboot()
start_armboot()在board.c中,处于lib_arm/下,在进入lib_arm目录下编译LIBS目标时依赖board.o文件

void start_armboot (void)
{
 init_fnc_t **init_fnc_ptr;
 char *s;

#if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
 ulong size;
#endif

#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
 unsigned long addr;
#endif

 //gd是个寄存器变量,ARM平台对应R8寄存器
 /* Pointer is writable since we allocated a register for it
  *_armboot_start是代码的起始地址,链接脚本指定为0x33f80000,CFG_MALLOC_LEN=192k,
  *所以gd的起始地址=0x33F50000
  */

 gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
 /* compiler optimization barrier needed for GCC >= 3.4 */
 __a喵__ __volatile__("": : :"memory");

 memset ((void*)gd, 0, sizeof (gd_t));//清空gd_t结构体

 gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));//bd_t结构体

 memset (gd->bd, 0, sizeof (bd_t)); 
 gd->flags |= GD_FLG_RELOC;

 monitor_flash_len = _bss_start - _armboot_start;//uboot代码的长度

 //对结构体init_fnc_t *init_sequence[]数组中的函数指针挨个调用。
 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   hang ();
  }
 }

 /* 初始化flash*/
 size = flash_init ();

 。。。。。。

 /* 初始化一个堆空间 */
 mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

 nand_init(); /* go init the NAND */

 /* 初始化环境变量,将环境参数读入内存指定位置 */
 env_relocate ();

 /* must do this after the framebuffer is allocated,串口初始化 */
 serial_initialize();

 /* IP Address */
 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
 /* MAC Address,省略 */

 devices_init (); /* get the devices list going. */

 jumptable_init (); /* 跳转表初始化 */

 console_init_r (); /* fully init console as a device */

 /* 使能异常中断 */
 enable_interrupts ();
 /* Perform network card initialisation if necessary */

#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

 /* main_loop() can return to retry autoboot, if so just run it again. */

 for (;;) {
  main_loop ();
 }

 /* NOTREACHED - no way out of command loop except booting */
}

  init_fnc_t *init_sequence[] = {
         cpu_init, /* 基本的处理器相关配置,初始化IRQ/FIQ模式的栈 -- cpu/arm920t/cpu.c */
         board_init, /* 基本的板级相关配置,设置系统时钟等 -- board/喵dk2410/喵dk2410.c */
         interrupt_init, /* 初始化定时器处理 -- cpu/arm920t/s3c24x0/interrupt.c */
         env_init, /* 初始化环境变量,检查Flash上的环境参数是否有效 -- common/env_flash.c */
         init_baudrate, /* 初始化波特率设置 -- lib_arm/board.c */
         serial_init, /* 串口通讯设置 -- cpu/arm920t/s3c24x0/serial.c */
         console_init_f, /* 控制台初始化阶段1 -- common/console.c */
         display_banner, /* 打印u-boot信息 -- lib_arm/board.c */
         dram_init, /* 配置可用的RAM,检测系统内存映射 -- board/喵dk2410/喵dk2410.c */
         display_dram_config, /* 显示RAM的配置大小 -- lib_arm/board.c */
         NULL,
  };

  下面逐个分析初始化函数:
1.int cpu_init (void)
{
 /* setup up stacks if necessary */
#ifdef CONFIG_USE_IRQ
 IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
 FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
 return 0;
}

2.int board_init (void)//设置系统时钟,配置引脚,使能缓存
{
 S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
 S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();

 /* to reduce PLL lock time, adjust the LOCKTIME register */
 clk_power->LOCKTIME = 0xFFFFFF;

 /* configure MPLL */
 clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
 ......
 /* configure UPLL */
 clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
 ......
 /* set up the I/O ports */
 gpio->GPACON = 0x007FFFFF;
 gpio->GPBCON = 0x00044555;
 gpio->GPBUP = 0x000007FF;
 gpio->GPCCON = 0xAAAAAAAA;
 gpio->GPCUP = 0x0000FFFF;
 gpio->GPDCON = 0xAAAAAAAA;
 gpio->GPDUP = 0x0000FFFF;
 gpio->GPECON = 0xAAAAAAAA;
 gpio->GPEUP = 0x0000FFFF;
 gpio->GPFCON = 0x000055AA;
 gpio->GPFUP = 0x000000FF;
 gpio->GPGCON = 0xFF95FFBA;
 gpio->GPGUP = 0x0000FFFF;
 gpio->GPHCON = 0x002AFAAA;
 gpio->GPHUP = 0x000007FF;

 /* arch number of SMDK2410-Board */
 gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

 /* address of boot parameters */
 gd->bd->bi_boot_params = 0x30000100;//为什么是这个地址
 icache_enable();//下面这两个函数都是设置协处理器的相关寄存器,使能缓存
 dcache_enable();
}

3.int interrupt_init (void)	//初始化2410的PWM timer 4,使其能自动装载计数值,
   				//恒定的产生时间中断信号,但是中断被屏蔽了用不上。
{
 S3C24X0_TIMERS * const timers = S3C24X0_GetBase_TIMERS();

 /* use PWM Timer 4 because it has no output */
 /* prescaler for Timer 4 is 16 */
 timers->TCFG0 = 0x0f00;

 if (timer_load_val == 0)
 {
  /*
   * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
   * (default) and prescaler = 16. Should be 10390
   * @33.25MHz and 15625 @ 50 MHz
   */
  timer_load_val = get_PCLK()/(2 * 16 * 100);
 }

 /* load value for 10 ms timeout */
 lastdec = timers->TCNTB4 = timer_load_val;

 /* auto load, manual update of Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x600000;

 /* auto load, start Timer 4 */
 timers->TCON = (timers->TCON & ~0x0700000) | 0x500000;

 timestamp = 0;
 return (0);
}

4.int env_init(void)
{
 int crc1_ok = 0, crc2_ok = 0;
 uchar flag1 = flash_addr->flags;
 uchar flag2 = flash_addr_new->flags;
 ulong addr_default = (ulong)&default_environment[0];
 ulong addr1 = (ulong)&(flash_addr->data);
 ulong addr2 = (ulong)&(flash_addr_new->data);
 crc1_ok = (crc32(0, flash_addr->data, ENV_SIZE) == flash_addr->crc);
 crc2_ok = (crc32(0, flash_addr_new->data, ENV_SIZE) == flash_addr_new->crc);

 if (crc1_ok && ! crc2_ok) {
  gd->env_addr = addr1;
  gd->env_valid = 1;
 } else if (! crc1_ok && crc2_ok) {
  gd->env_addr = addr2;
  gd->env_valid = 1;
 } else if (! crc1_ok && ! crc2_ok) {
  gd->env_addr = addr_default;
  gd->env_valid = 0;
 } else if (flag1 == ACTIVE_FLAG && flag2 == OBSOLETE_FLAG) {
  gd->env_addr = addr1;
  gd->env_valid = 1;
 } else if (flag1 == OBSOLETE_FLAG && flag2 == ACTIVE_FLAG) {
  gd->env_addr = addr2;
  gd->env_valid = 1;
 } else if (flag1 == flag2) {
  gd->env_addr = addr1;
  gd->env_valid = 2;
 } else if (flag1 == 0xFF) {
  gd->env_addr = addr1;
  gd->env_valid = 2;
 } else if (flag2 == 0xFF) {
  gd->env_addr = addr2;
  gd->env_valid = 2;
 }
 return (0);
}

 

未完待续~~~

 

插件实验室新闻工作者 小倩


回复

上一页1 页 / 共 1下一页
十二の十二の

emotion_编程猫_厉害了emotion_编程猫_厉害了emotion_编程猫_厉害了

点赞0


评论


yamolyamol

大佬!

不过我更想知道你是用什么把代码插入的

点赞0


评论


顺铂顺铂

能看懂吗?

点赞0


评论


顺铂顺铂

插入代码教程

center_image

点赞0


评论