zoukankan      html  css  js  c++  java
  • 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 }

    输出内容如下: 










  • 相关阅读:
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    206. Reverse Linked List
    205. Isomorphic Strings
    204. Count Primes
    203. Remove Linked List Elements
    201. Bitwise AND of Numbers Range
    199. Binary Tree Right Side View
    ArcGIS API for JavaScript 4.2学习笔记[8] 2D与3D视图同步
  • 原文地址:https://www.cnblogs.com/biaohc/p/6371834.html
Copyright © 2011-2022 走看看