• uboot————第二阶段start_armboot 函数详解


    1:上一节讲到start.S中进行了一系列的SoC相关硬件初始化以后进行了长跳转到start_armboot 函数中;

    start_armboot进一步初始化board中硬件,并设置了uboot下的命令行、环境变量、基本命令、跳转到kernel

    下面详细介绍start_armboot中的代码:

    ------------------------第一段代码---------------------------------------------

    红色代码为条件编译以后要执行的代码

     1 void start_armboot (void)
     2 {
     3     init_fnc_t **init_fnc_ptr;
     4     char *s;
     5     int mmc_exist = 0;
     6 #if !defined(CFG_NO_FLASH) || defined (CONFIG_VFD) || defined(CONFIG_LCD)
     7     ulong size;
     8 #endif
     9 
    10 #if defined(CONFIG_VFD) || defined(CONFIG_LCD)
    11     unsigned long addr;
    12 #endif
    13 
    14 #if defined(CONFIG_BOOT_MOVINAND)
    15     uint *magic = (uint *) (PHYS_SDRAM_1);
    16 #endif
    17 
    18     /* Pointer is writable since we allocated a register for it */
    19 #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
    20     ulong gd_base;
    21 
    22     gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
    23 #ifdef CONFIG_USE_IRQ
    24     gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
    25 #endif
    26     gd = (gd_t*)gd_base;
    27 #else    //CONFIG_MEMORY_UPPER_CODE
    28     gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
    29 #endif
    30 
    31     if (readl(INF_REG_BASE+INF_REG0_OFFSET)==0xFFAADDEE)
    32     {
    33         extern int gbl_silent;
    34         gbl_silent = 1;
    35     }
    36 
    37     /* compiler optimization barrier needed for GCC >= 3.4 */      //这段是c语言内嵌汇编,为了实现内存墙;
    38     __asm__ __volatile__("": : :"memory");
    39 
    40     memset ((void*)gd, 0, sizeof (gd_t));                
    41     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    42     memset (gd->bd, 0, sizeof (bd_t));
    43 
    44     monitor_flash_len = _bss_start - _armboot_start;
    45 
    46     for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
    47         if ((*init_fnc_ptr)() != 0) {
    48             hang ();
    49         }
    50     }
    -------------------未完待续------------------------

    首先看一下

    init_fnc_t **init_fnc_ptr;这个变量,这是一个init_fnc_t 类型的二重指针;typedef int (init_fnc_t) (void);
    可以看出init_fnc_t类型为 返回值为int 传参为空的函数类型,看一下下面这段代码:对
    init_fnc_ptr 赋值为init_sequence(init_sequence为一个函数指针数组,这个数字为一个全局变量,存放的是硬件初始化有关的
    一些函数这些函数类型都是init_fnc_t类型),因此下面for循环的作用就是遍历init_sequence数组中的所有函数,并执行这些函数;

    如果这些初始化函数的返回值为0的话则执行hang() 挂起函数;hang函数的作用是输出
    puts ("### ERROR ### Please RESET the board ### ");并进入一个死循环;
    总结一下:这段代码是初始化一个全局变量数组,数组中存放一些硬件初始化相关的函数指针,遍历这些函数,并进行相应硬件的初始化;这些全局变量放在数据段;
     
    for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
            if ((*init_fnc_ptr)() != 0) {
                hang ();
            }
        }
     1 init_fnc_t *init_sequence[] = {
     2     cpu_init,        /* basic cpu dependent setup */
     3 #if defined(CONFIG_SKIP_RELOCATE_UBOOT)
     4     reloc_init,        /* Set the relocation done flag, must
     5                    do this AFTER cpu_init(), but as soon
     6                    as possible */
     7 #endif
     8     board_init,        /* basic board dependent setup */
     9     interrupt_init,        /* set up exceptions */
    10     env_init,        /* initialize environment */
    11     init_baudrate,        /* initialze baudrate settings */
    12     serial_init,        /* serial communications setup */
    13     console_init_f,        /* stage 1 init of console */
    14     display_banner,        /* say that we are here */
    15 #if defined(CONFIG_DISPLAY_CPUINFO)
    16     print_cpuinfo,        /* display cpu info (and speed) */
    17 #endif
    18 #if defined(CONFIG_DISPLAY_BOARDINFO)
    19     checkboard,        /* display board info */
    20 #endif
    21 #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
    22     init_func_i2c,
    23 #endif
    24     dram_init,        /* configure available RAM banks */
    25     display_dram_config,
    26     NULL,
    27 };
    1 void hang (void)
    2 {
    3     puts ("### ERROR ### Please RESET the board ###
    ");
    4     for (;;);
    5 }

    下面这段代码是为gd_base、gd_bd、两个全局变量分配内存地址;gd_t类型为结构体其中的内容为:大小为36byte;

    {
      bd_t 类型指针              //4字节
      flag 无符号整形             //4字节
      baudrate 波特率 无符号整形        //4字节
      have_console 无符号整形          //4字节
      reloc_off; /* Relocation Offset */  //4字节
      env_addr                  //4字节
      env_valid                  //4字节
      unsigned long fb_base LCD的内存基地址  //4字节
      void **jt; /* jump table */      //指针4字节         
    }

    bd_t 也为一结构体,大小为42字节
    {
      int 波特率          //4字节
      unsigned int IP地址    //4字节
      unsigned char 网卡地址   //6字节
      环境变量指针          //4字节
      机器码            //4字节
      启动参数          //4字节
      内存配置结构体        //8字节*2
              
    }

    下面这段代码的作用:gd_base 为0x23e00000 + 0x200000 - 912K -512K - 36byte这个地址用来存放这个全局变量

    同样 bd_t 全局变量的地址设置在gd_base往下移动42byte的地址;

    从这段代码我们可以看出uboot是如何进行内存分配的;

    可以看下图:下图为uboot中的内存;

     这段代码作的事情就是为gd_t、bd_t两个结构体分配内存地址,并初始化gd、gd->bd指针分别指向这两个结构体;

    #define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

    gd为一个register volatile结构体指针;asm ("r8")意思是放在r8寄存器中;

    
    20     ulong gd_base;
    21 
    22     gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t);
    23
    26     gd = (gd_t*)gd_base;
    
    31   36 
    37     /* compiler optimization barrier needed for GCC >= 3.4 */      //这段是c语言内嵌汇编,为了实现内存墙;
    38     __asm__ __volatile__("": : :"memory");
    39 
    40     memset ((void*)gd, 0, sizeof (gd_t));                
    41     gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
    42     memset (gd->bd, 0, sizeof (bd_t));
    43 
    44     monitor_flash_len = _bss_start - _armboot_start;
     1 typedef    struct    global_data {
     2     bd_t        *bd;
     3     unsigned long    flags;
     4     unsigned long    baudrate;
     5     unsigned long    have_console;    /* serial_init() was called */
     6     unsigned long    reloc_off;    /* Relocation Offset */
     7     unsigned long    env_addr;    /* Address  of Environment struct */
     8     unsigned long    env_valid;    /* Checksum of Environment valid? */
     9     unsigned long    fb_base;    /* base address of frame buffer */
    10 #ifdef CONFIG_VFD
    11     unsigned char    vfd_type;    /* display type */
    12 #endif
    13 #if 0
    14     unsigned long    cpu_clk;    /* CPU clock in Hz!        */
    15     unsigned long    bus_clk;
    16     phys_size_t    ram_size;    /* RAM size */
    17     unsigned long    reset_status;    /* reset status register at boot */
    18 #endif
    19     void        **jt;        /* jump table */
    20 } gd_t;
     1 typedef struct bd_info {
     2     int            bi_baudrate;    /* serial console baudrate */
     3     unsigned long    bi_ip_addr;    /* IP Address */
     4     unsigned char    bi_enetaddr[6]; /* Ethernet adress */
     5     struct environment_s           *bi_env;
     6     ulong            bi_arch_number;    /* unique id for this board */
     7     ulong            bi_boot_params;    /* where this board expects params */
     8     struct                /* RAM configuration */
     9     {
    10     ulong start;
    11     ulong size;
    12     }            bi_dram[CONFIG_NR_DRAM_BANKS];
    13 #ifdef CONFIG_HAS_ETH1
    14     /* second onboard ethernet port */
    15     unsigned char   bi_enet1addr[6];
    16 #endif
    17 } bd_t;

     下面看一下init_sequence数组中有有哪些函数:

    init_fnc_t *init_sequence[] = {
        cpu_init,        /* basic cpu dependent setup */
    #if defined(CONFIG_SKIP_RELOCATE_UBOOT)
        reloc_init,        /* Set the relocation done flag, must
                       do this AFTER cpu_init(), but as soon
                       as possible */
    #endif
        board_init,        /* basic board dependent setup */
        interrupt_init,        /* set up exceptions */
        env_init,        /* initialize environment */
        init_baudrate,        /* initialze baudrate settings */
        serial_init,        /* serial communications setup */
        console_init_f,        /* stage 1 init of console */
        display_banner,        /* say that we are here */
    #if defined(CONFIG_DISPLAY_CPUINFO)
        print_cpuinfo,        /* display cpu info (and speed) */
    #endif
    #if defined(CONFIG_DISPLAY_BOARDINFO)
        checkboard,        /* display board info */
    #endif
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
        init_func_i2c,
    #endif
        dram_init,        /* configure available RAM banks */
        display_dram_config,
        NULL,
    };

    函数1:cpu_init函数;因为cpu相关的初始化已经在_start函数中做了,所以这里什么也没有做;

     1 int cpu_init (void)
     2 {
     3     /*
     4      * setup up stacks if necessary
     5      */
     6 #ifdef CONFIG_USE_IRQ            //这个未定义
     7     IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
     8     FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
     9 #endif
    10     return 0;
    11 }

    函数2:board_init函数;这个函数中初始化了dm9000网卡,并且对gd->bd中的机器码以及启动参数赋值;

    这里要注意一下:uboot中赋值的机器码要和linux内核中的机器码要一致,否则不能正常启动;

    boot参数为:0x02000000+0x100;

     1 int board_init(void)
     2 {
     3     DECLARE_GLOBAL_DATA_PTR;
     4 
     5 
     6 #ifdef CONFIG_DRIVER_DM9000
     7     dm9000_pre_init();
     8 #endif
     9 
    10     gd->bd->bi_arch_number = MACH_TYPE;
    11     gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
    12 
    13     return 0;
    14 }

    函数3:interrupt_init中的初始化

     1 int interrupt_init(void)
     2 {
     3 
     4     S5PC11X_TIMERS *const timers = S5PC11X_GetBase_TIMERS();
     5 
     6     /* use PWM Timer 4 because it has no output */
     7     /* prescaler for Timer 4 is 16 */
     8     timers->TCFG0 = 0x0f00;              //设置预分频为15 +1 = 16
     9     if (timer_load_val == 0) {
    10         /*
    11          * for 10 ms clock period @ PCLK with 4 bit divider = 1/2
    12          * (default) and prescaler = 16. Should be 10390
    13          * @33.25MHz and  @ 66 MHz
    14          */
    15         timer_load_val = get_PCLK() / (16 * 100);    //设置为10ms
    16     }
    17 
    18     /* load value for 10 ms timeout */
    19     lastdec = timers->TCNTB4 = timer_load_val;
    20     /* auto load, manual update of Timer 4 */
    21     timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;        
    22     /* auto load, start Timer 4 */
    23     timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
    24     timestamp = 0;
    25 
    26 
    27     return (0);
    28 }

    代码解析:

      typedef vu_long S5PC11X_REG32;

    S5PC11X_TIMERS:定义了一个结构体类型,把与时钟有关的所有所有寄存器都存放在这个结构体内
    typedef struct {
        S5PC11X_REG32    TCFG0;
        S5PC11X_REG32    TCFG1;
        S5PC11X_REG32    TCON;
        S5PC11X_TIMER    ch[4];
        S5PC11X_REG32    TCNTB4;
        S5PC11X_REG32    TCNTO4;
    } /*__attribute__((__packed__))*/ S5PC11X_TIMERS;

     这句代码的意思就是把

    S5PC11X_TIMERS *const timers = S5PC11X_GetBase_TIMERS();
    S5PC11X_GetBase_TIMERS函数:的作用就是把timer寄存器的基地址强制类型转换为S5PC11X_TIMERS *  类型然后赋值给 timers变量;timers->TCFG0实际就是代表基地址右移4字节
    之后的地址中的值,直接赋值相当于把0x0f00这个值放到 TCFG0对应的寄存器地址处,但是这个要注意的是,寄存器必须设置为连续的/或者一一对应的,否则会造成赋值的地址错误;
     timers->TCFG0 = 0x0f00;
    static inline S5PC11X_TIMERS * S5PC11X_GetBase_TIMERS(void)
    {
        return (S5PC11X_TIMERS *)ELFIN_TIMER_BASE;
    }

    剩下的代码就和裸机的代码一致了;TCON的timer4的相应控制为清0,设置为自动reload,并且第一次要手动载入,然后时在清0,设置reload,开启timer4

    timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | TCON_4_UPDATE;        
    22     /* auto load, start Timer 4 */
    23     timers->TCON = (timers->TCON & ~0x00700000) | TCON_4_AUTO | COUNT_4_ON;
    ----------------------------------

    函数4:env_init
     1 int env_init(void)
     2 {
     3 #if defined(ENV_IS_EMBEDDED)
     4     ulong total;
     5     int crc1_ok = 0, crc2_ok = 0;
     6     env_t *tmp_env1, *tmp_env2;
     7 
     8     total = CFG_ENV_SIZE;      // tatal = 0x4000 16k的大小,环境变量整个大小为16k
     9 
    10     tmp_env1 = env_ptr;
    11     tmp_env2 = (env_t *)((ulong)env_ptr + CFG_ENV_SIZE);
    12 
    13     crc1_ok = (crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc);
    14     crc2_ok = (crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc);
    15 
    16     if (!crc1_ok && !crc2_ok)
    17         gd->env_valid = 0;
    18     else if(crc1_ok && !crc2_ok)
    19         gd->env_valid = 1;
    20     else if(!crc1_ok && crc2_ok)
    21         gd->env_valid = 2;
    22     else {
    23         /* both ok - check serial */
    24         if(tmp_env1->flags == 255 && tmp_env2->flags == 0)
    25             gd->env_valid = 2;
    26         else if(tmp_env2->flags == 255 && tmp_env1->flags == 0)
    27             gd->env_valid = 1;
    28         else if(tmp_env1->flags > tmp_env2->flags)
    29             gd->env_valid = 1;
    30         else if(tmp_env2->flags > tmp_env1->flags)
    31             gd->env_valid = 2;
    32         else /* flags are equal - almost impossible */
    33             gd->env_valid = 1;
    34     }
    35 
    36     if (gd->env_valid == 1)
    37         env_ptr = tmp_env1;
    38     else if (gd->env_valid == 2)
    39         env_ptr = tmp_env2;
    40 #else /* ENV_IS_EMBEDDED */
    41     gd->env_addr  = (ulong)&default_environment[0];
    42     gd->env_valid = 1;
    43 #endif /* ENV_IS_EMBEDDED */
    44 
    45     return (0);
    46 }
    
    

    执行的是红色的代码:即把common.c中初始化好的default_environment地址赋值到gd->env_addr中,env_valid 赋值为1; 这里对字符串数组的初始化有些疑问???????

    uchar default_environment[] = {
    #endif
    #ifdef    CONFIG_BOOTARGS
        "bootargs="    CONFIG_BOOTARGS            ""
    #endif
    #ifdef    CONFIG_BOOTCOMMAND
        "bootcmd="    CONFIG_BOOTCOMMAND        ""
    #endif
    。。。。。。。。。。。。。。。。。。。。。
    #ifdef  CONFIG_CLOCKS_IN_MHZ
        "clocks_in_mhz=1"
    #endif
    #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
        "pcidelay="    MK_STR(CONFIG_PCI_BOOTDELAY)    ""
    #endif
    #ifdef  CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
    #endif
        ""
    };

    ---------------------------------------------------------

    函数5:init_baudrate初始化波特率:从env中获取波特率 赋值给gd->bd->bi_baudrate  gd->baudrate

    实现是通过以下几个函数来实现的我们逐一来分析:

    /* init_baudrate这个函数的作用就是从环境变量中读取出波特率,从之前的波特率初始化函数看出,
    实际上环境变量中的波特率就是我们在x210_sd.h头文件中配置的波特率config_baudrate,*/
    static
    int init_baudrate (void) { char tmp[64]; /* long enough for environment variables */ int i = getenv_r ("baudrate", tmp, sizeof (tmp)); gd->bd->bi_baudrate = gd->baudrate = (i > 0)   ? (int) simple_strtoul (tmp, NULL, 10)                //simple_strtoul 把字符串tmp中的波特率转成十进制数字; : CONFIG_BAUDRATE; return (0); }
    
    
    /*这个函数的作用是读取环境变量name 到 缓存buf中,读取成功返回n大于0,失败返回0*/ 
    1
    int getenv_r (char *name, char *buf, unsigned len) 2 { 3 int i, nxt; 4 5 for (i=0; env_get_char(i) != ''; i=nxt+1) { 6 int val, n; 7 8 for (nxt=i; env_get_char(nxt) != ''; ++nxt) { 9 if (nxt >= CFG_ENV_SIZE) { 10 return (-1); 11 } 12 } 13 if ((val=envmatch((uchar *)name, i)) < 0) 14 continue; 15 /* found; copy out */ 16 n = 0; 17 while ((len > n++) && (*buf++ = env_get_char(val++)) != '')     //找到对应的环境变量以后,把这个环境变量保存在buf中,并返回赋值的长度 18 ; 19 if (len == n) 20 *buf = ''; 21 return (n); 22 } 23 return (-1); 24 }
    /*这个函数的作用是判断环境变量是从内存还是sd卡中赋值的,然后返回index对应的环境变量中的字符*/
    uchar env_get_char (int index) { uchar c; /* if relocated to RAM */ if (gd->flags & GD_FLG_RELOC) c = env_get_char_memory(index); else c = env_get_char_init(index); return (c); }
     /* envmatch函数的作用是判断*s1,是否和i2对应的字符串相等,如果相等返回i2,*/
    1
    int envmatch (uchar *s1, int i2) 2 { 3 4 while (*s1 == env_get_char(i2++)) 5 if (*s1++ == '=') 6 return(i2); 7 if (*s1 == '' && env_get_char(i2-1) == '=') 8 return(i2); 9 return(-1); 10 }
    /* 从内存中读取环境变量字符,作为返回值返回 */
    1
    uchar env_get_char_memory (int index) 2 { 3 if (gd->env_valid) { 4 return ( *((uchar *)(gd->env_addr + index)) ); 5 } else { 6 return ( default_environment[index] ); 7 } 8 }

    --------------------------------------------------------------------------------------------------

    函数6:串口的初始化serial_init,因为我们在_start函数中已经初始化了串口,并打印了OK

    可以看出这函数中实际是调用了serial_setbrg函数,而这个函数什么也没有做;

    1 int serial_init(void)
    2 {
    3     serial_setbrg();
    4 
    5     return (0);
    6 }
    1 void serial_setbrg(void)
    2 {
    3     DECLARE_GLOBAL_DATA_PTR;
    4 
    5     int i;
    6     for (i = 0; i < 100; i++);
    7 }
     
    --------------------------------------------------------------


    函数7:console_init_f 控制台初始化函数
    实际在这里只把gd中的have_console赋值为1;真正的控制台初始化函数在console_init_r函数中;
     1 int console_init_f (void)
     2 {
     3     gd->have_console = 1;
     4 
     5 #ifdef CONFIG_SILENT_CONSOLE
     6     if (getenv("silent") != NULL)
     7         gd->flags |= GD_FLG_SILENT;
     8 #endif
     9 
    10     return (0);
    11 }

    -------------------------------------------------------------------------

    函数8:display_banner函数

    实际上这个函数的作用是打印version_string字符串,和打开背光

    const char version_string[] =
    U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;

    U_BOOT_VERSION是在makefile中自动生成的,在version_autogenerated.h中#define U_BOOT_VERSION "U-Boot 1.3.4"  

    __DATE__  __TIME__  也应在是在某个脚本中生成的,然后输出到某个头文件包含的一个全局变量;所以或打印出 U-BOOT 1.3.4 日期 时间

     1 static int display_banner (void)
     2 {
     3     printf ("
    
    %s
    
    ", version_string);
     4     debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX
    ",
     5            _armboot_start, _bss_start, _bss_end);
     6 #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
     7     debug("	Malloc and Stack is above the U-Boot Code.
    ");
     8 #else
     9     debug("	Malloc and Stack is below the U-Boot Code.
    ");
    10 #endif
    11 #ifdef CONFIG_MODEM_SUPPORT
    12     debug ("Modem Support enabled
    ");
    13 #endif
    14 #ifdef CONFIG_USE_IRQ
    15     debug ("IRQ Stack: %08lx
    ", IRQ_STACK_START);
    16     debug ("FIQ Stack: %08lx
    ", FIQ_STACK_START);
    17 #endif
    18     open_backlight();//lqm.
    19     //open_gprs();
    20 
    21     return (0);
    22 }

    ----------------------------------------------------------------------

    函数9:printf_cpuinfo 打印cpu信息,红色代码为要执行的代码;

     1 int print_cpuinfo(void)
     2 {
     3     uint set_speed;
     4     uint tmp;
     5     uchar result_set;
     6 
     7 #if defined(CONFIG_CLK_533_133_100_100)
     8     set_speed = 53300;
     9 #elif defined(CONFIG_CLK_667_166_166_133)
    10     set_speed = 66700;
    11 #elif defined(CONFIG_CLK_800_200_166_133)
    12     set_speed = 80000;
    13 #elif defined(CONFIG_CLK_1000_200_166_133)
    14     set_speed = 100000;
    15 #elif defined(CONFIG_CLK_1200_200_166_133)
    16     set_speed = 120000;
    17 #else
    18     set_speed = 100000;
    19     printf("Any CONFIG_CLK_XXX is not enabled
    ");
    20 #endif
    21 
    22     tmp = (set_speed / (get_ARMCLK()/1000000));
    23 
    24     if((tmp < 105) && (tmp > 95)){
    25         result_set = 1;
    26     } else {
    27         result_set = 0;
    28     }
    29 
    30 #ifdef CONFIG_MCP_SINGLE
    31     printf("
    CPU:  S5PV210@%ldMHz(%s)
    ", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
    32 #else
    33     printf("
    CPU:  S5PC110@%ldMHz(%s)
    ", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL"));
    34 #endif
    35     printf("        APLL = %ldMHz, HclkMsys = %ldMHz, PclkMsys = %ldMHz
    ",
    36             get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000);
    37 #if 1
    38     printf("    MPLL = %ldMHz, EPLL = %ldMHz
    ",
    39             get_MPLL_CLK()/1000000, get_PLLCLK(EPLL)/1000000);
    40     printf("               HclkDsys = %ldMHz, PclkDsys = %ldMHz
    ",
    41             get_HCLKD()/1000000, get_PCLKD()/1000000);
    42     printf("               HclkPsys = %ldMHz, PclkPsys = %ldMHz
    ",
    43             get_HCLKP()/1000000, get_PCLKP()/1000000);
    44     printf("               SCLKA2M  = %ldMHz
    ", get_SCLKA2M()/1000000);
    45 #endif
    46     puts("Serial = CLKUART ");
    47 
    48     return 0;
    49 }

    包含了一下几个函数:get_ARMCLK函数、get_PLLCLK函数。

    /*这个函数是查看时钟域24MHz经过APLL倍频以后,在经过分频器以后获得的cpu的频率
    详细代码分析可以看时钟哪个章节*/
    1
    ulong get_ARMCLK(void) 2 { 3 ulong div,apll_ratio; 4 5 div = CLK_DIV0_REG; 6 apll_ratio = ((div>>0) & 0x7); 7 8 return ((get_PLLCLK(APLL)) / (apll_ratio + 1)); 9 10 }
    /*这个函数用来获取PLL倍频以后的时钟频率:APLL、MPLL、 EPLL 
     详细代码分析可以看裸机中时钟那一章节*/

    1
    static ulong get_PLLCLK(int pllreg) 2 { 3 ulong r, m, p, s; 4 5 if (pllreg == APLL) { 6 r = APLL_CON0_REG; 7 m = (r>>16) & 0x3ff; 8 } else if (pllreg == MPLL) { 9 r = MPLL_CON_REG; 10 m = (r>>16) & 0x3ff; 11 } else if (pllreg == EPLL) { 12 r = EPLL_CON_REG; 13 m = (r>>16) & 0x1ff; 14 } else 15 hang(); 16 17 p = (r>>8) & 0x3f; 18 s = r & 0x7; 19 20 if (pllreg == APLL) 21 s= s-1; 22 23 return (m * (CONFIG_SYS_CLK_FREQ / (p * (1 << s)))); 24 }

    同样可以分析其他输出信息:最后的输出信息如下:

    -------------------------------------------------------------------------------

    函数10:checkboard:打印board信息

     1 int checkboard(void)
     2 {
     3 #ifdef CONFIG_MCP_SINGLE
     4 #if defined(CONFIG_VOGUES)
     5     printf("
    Board:   VOGUESV210
    ");
     6 #else
     7     printf("
    Board:   X210
    ");
     8 #endif //CONFIG_VOGUES
     9 #else
    10     printf("
    Board:   X210
    ");
    11 #endif
    12     return (0);
    13 }

    ------------------------------------------------------------------------------

    函数11:dram_init实际执行的一下红色代码:实际真正的初始化函数已经在_start函数中执行了,而这里只是把dram的信息赋值到全局变量gd->bd中;

    把chip1的首地址和大小以及chip2的首地址和大小放入全局变量中;

     1 int dram_init(void)
     2 {
     3     DECLARE_GLOBAL_DATA_PTR;
     4 
     5     gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
     6     gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
     7 
     8 #if defined(PHYS_SDRAM_2)
     9     gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
    10     gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
    11 #endif
    12 
    13 #if defined(PHYS_SDRAM_3)
    14     gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
    15     gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
    16 #endif
    17 
    18     return 0;
    19 }

    ------------------------------------------------------------------------------

    函数12:display_dram_config实际执行的为红色部分代码

     1 static int display_dram_config (void)
     2 {
     3     int i;
     4 
     5 #ifdef DEBUG
     6     puts ("RAM Configuration:
    ");
     7 
     8     for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
     9         printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
    10         print_size (gd->bd->bi_dram[i].size, "
    ");
    11     }
    12 #else
    13     ulong size = 0;
    14 //这段代码的作用就是计算chip1、chip2一共多少内存并输出出来
    15     for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {    
    16         size += gd->bd->bi_dram[i].size;
    17     }
    18 
    19     puts("DRAM:    ");
    20     print_size(size, "
    ");
    21 #endif
    22 
    23     return (0);
    24 }

    输出内容如下: 










  • 相关阅读:
    01-SCOTT-SQL建表语句
    面试小题
    Swagger2使用API
    Elasticsearch单机安装_集群搭建_索引基本操作_Head插件安装与基本操作_ik分词器配置_logstash实现数据同步_教程
    45个非常有用的 Oracle 查询语句小结
    oracle获取定时时间段
    彻底理解webservice SOAP WSDL
    MySQL 1045登录失败
    quartz定时任务时间设置
    map 遍历的四种方式
  • 原文地址:https://www.cnblogs.com/biaohc/p/6371834.html
Copyright © 2020-2023  润新知