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 ###\n");並進入一個死循環;
總結一下:這段代碼是初始化一個全局變量數組,數組中存放一些硬件初始化相關的函數指針,遍歷這些函數,並進行相應硬件的初始化;這些全局變量放在數據段;
 
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 ###\n"); 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            "\0"
#endif #ifdef CONFIG_BOOTCOMMAND "bootcmd="    CONFIG_BOOTCOMMAND        "\0"
#endif
。。。。。。。。。。。。。。。。。。。。。 #ifdef CONFIG_CLOCKS_IN_MHZ "clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
    "pcidelay="    MK_STR(CONFIG_PCI_BOOTDELAY)    "\0"
#endif #ifdef CONFIG_EXTRA_ENV_SETTINGS CONFIG_EXTRA_ENV_SETTINGS #endif
    "\0" };

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

函數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) != '\0'; i=nxt+1) { 6 int val, n; 7 8 for (nxt=i; env_get_char(nxt) != '\0'; ++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++)) != '\0')     //找到對應的環境變量以后,把這個環境變量保存在buf中,並返回賦值的長度 18 ; 19 if (len == n) 20 *buf = '\0'; 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 == '\0' && 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 ("\n\n%s\n\n", version_string);  4     debug ("U-Boot code: %08lX -> %08lX BSS: -> %08lX\n",  5  _armboot_start, _bss_start, _bss_end);  6 #ifdef CONFIG_MEMORY_UPPER_CODE /* by scsuh */
 7     debug("\t\bMalloc and Stack is above the U-Boot Code.\n");  8 #else
 9     debug("\t\bMalloc and Stack is below the U-Boot Code.\n"); 10 #endif
11 #ifdef CONFIG_MODEM_SUPPORT 12     debug ("Modem Support enabled\n"); 13 #endif
14 #ifdef CONFIG_USE_IRQ 15     debug ("IRQ Stack: %08lx\n", IRQ_STACK_START); 16     debug ("FIQ Stack: %08lx\n", 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\n"); 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("\nCPU: S5PV210@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL")); 32 #else
33     printf("\nCPU: S5PC110@%ldMHz(%s)\n", get_ARMCLK()/1000000, ((result_set == 1) ? "OK" : "FAIL")); 34 #endif
35     printf(" APLL = %ldMHz, HclkMsys = %ldMHz, PclkMsys = %ldMHz\n", 36 get_FCLK()/1000000, get_HCLK()/1000000, get_PCLK()/1000000); 37 #if 1 38 printf(" MPLL = %ldMHz, EPLL = %ldMHz\n", 39 get_MPLL_CLK()/1000000, get_PLLCLK(EPLL)/1000000); 40 printf(" HclkDsys = %ldMHz, PclkDsys = %ldMHz\n", 41 get_HCLKD()/1000000, get_PCLKD()/1000000); 42 printf(" HclkPsys = %ldMHz, PclkPsys = %ldMHz\n", 43 get_HCLKP()/1000000, get_PCLKP()/1000000); 44 printf(" SCLKA2M = %ldMHz\n", 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("\nBoard: VOGUESV210\n");  6 #else
 7     printf("\nBoard: X210\n");  8 #endif //CONFIG_VOGUES
 9 #else
10     printf("\nBoard: X210\n"); 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:\n");  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, "\n"); 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, "\n"); 21 #endif
22 
23     return (0); 24 }

輸出內容如下: 

 










 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM