UBOOT之board.c分析(一)

来源:互联网 发布:java中九九乘法表 编辑:程序博客网 时间:2024/05/21 01:56
############board.c在文件夹lib_arm中##################

gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
    为全局变量gd_t结构体指定起始地址,变量gd在include/asm-arm/global_data.h中定义:
    #define DECLARE_GLOBAL_DATA_PTR     register volatile  gd_t  *gd  asm ("r8")

memset ((void*)gd, 0, sizeof (gd_t));                          //清空gd_t结构体
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));        //为gd_bd指定起始地址
memset (gd->bd, 0, sizeof (bd_t));                    //清空bd_t结构体

gd->flags |= GD_FLG_RELOC;                        //gd->flags 标记程序已经运行在ram中

monitor_flash_len = _bss_start - _armboot_start;   //计算程序的大小

GD_FLG_RELOC在include/asm-arm/global_data.h中定义:
#define GD_FLG_RELOC 0x00001/* Code was relocated to RAM */

bd_t结构体在include/asm-arm/u-boot.h中定义

/*************初始化操作序列*************/
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}

其中init_sequence是一个存放函数指针的数组,里面存放了一系列进行初始化操作的函数名,然后通过for循环一次调用这些函数。此数组就在就定义在lib_arm/board.c中,定义如下:
init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
arch_cpu_init,/* basic arch cpu dependent setup */
#endif
board_init,/* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
interrupt_init,/* set up exceptions */
#endif
timer_init,/* initialize timer */
#ifdef CONFIG_FSL_ESDHC
get_clocks,
#endif
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 */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
arm_pci_init,
#endif
display_dram_config,
NULL,
};


依次说明各个函数的作用:
/************************    arch_cpu_init    *************************************/
这个函数在cpu/arm_cortexa8/s5pc1xx/clock_info.c中定义
int arch_cpu_init(void)
{
s5pc1xx_cpu_id = readl(S5PC1XX_PRO_ID);             
s5pc1xx_cpu_id = 0xC000 | ((s5pc1xx_cpu_id & 0x00FFF000) >> 12);
        /***以上两句代码获取cpu的id,S5PC1XX_PRO_ID在include/asm_arm/arch_s5pcxx/cpu.h中定义***/

s5pc1xx_clock_init();
       /***用于获取系统时钟,在cpu/arm_cortexa8/s5pc1xx/clock.c中定义**/
return 0;
}


/************************   board_init      *************************************/
这个函数在board/samsung/smdkc100/smdkc100.c定义
int board_init(void)
{
#ifdef CONFIG_DRIVER_DM9000
dm9000aep_pre_init();                //初始化网卡芯片
#endif
gd->bd->bi_arch_number = MACH_TYPE_SMDKV210;    //这个复制在之后启动内核传参时需要使用
gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;    //指定内核启动参数的存放地址

return 0;
}
PHYS_SDRAM_X和PHYS_SDRAM_X_SIZE在 include/configs/smdkc100.h中定义
/***********************    interrupt_init     **************************************/
这个函数在/lib_arm/interrupts.c中定义
int interrupt_init (void)
{
/*
 * setup up stacks if necessary
 */
IRQ_STACK_START = _armboot_start - CONFIG_SYS_MALLOC_LEN - CONFIG_SYS_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
        /********设置IRQ和FIQ的栈起始地址************/
return arch_interrupt_init();                // 初始化中断,配置GPIO为中断引脚,清悬起位等

}

/*************************   timer_init    ************************************/
这个函数在 cpu/arm_cortexa8/s5pc1xx/timer.c中定义
int timer_init(void)
{
struct s5pc1xx_timer *const timer = s5pc1xx_get_base_timer();
u32 val;

/*
 * @ PWM Timer 4
 * Timer Freq(HZ) =
 * PCLK / { (prescaler_value + 1) * (divider_value) }
 */

/* set prescaler : 16 */
/* set divider : 2 */
writel((PRESCALER_1 & 0xff) << 8, &timer->tcfg0);             //设置一级预分频值
writel((MUX_DIV_2 & 0xf) << MUX4_DIV_SHIFT, &timer->tcfg1);    //设置二级预分频值
/**********设置计数值,计数时间约为10ms********************/
if (count_value == 0) {
/* reset initial value */
/* count_value = 2085937.5(HZ) (per 1 sec)*/
count_value = get_pclk() / ((PRESCALER_1 + 1) *                 
(MUX_DIV_2 + 1));

/* count_value / 100 = 20859.375(HZ) (per 10 msec) */
count_value = count_value / 100;
}

/* set count value */
writel(count_value, &timer->tcntb4);
lastdec = count_value;

val = (readl(&timer->tcon) & ~(0x07 << TCON_TIMER4_SHIFT)) |
S5PC1XX_TCON4_AUTO_RELOAD;                        //设置自动装载模式

/* auto reload & manual update */
writel(val | S5PC1XX_TCON4_UPDATE, &timer->tcon);    //手动更新cont寄存器

/* start PWM timer 4 */
writel(val | S5PC1XX_TCON4_START, &timer->tcon);        //开始计时

timestamp = 0;

return 0;
}

/**************************    env_init     ***********************************/
这个函数在common/env_nand.c中
int env_init(void)
{
gd->env_addr  = (ulong)&default_environment[0];    //设置存放环境变量的地址
gd->env_valid = 1;                                                        //设置环境变量的值为有效

return (0);
}
default_environment是一个存放环境变量的数组,在commo/env_common.c中定义

/*************************   init_baudrate   ************************************/
这个函数就在board.c中定义
static int init_baudrate (void)
{
char tmp[64];/* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp));          //获取环境变量baudrate的值,即波特率
gd->bd->bi_baudrate = gd->baudrate = (i > 0)          //如果能够找到baudrate环境变量,则将获取到的波特率字符串转换成int型
? (int) simple_strtoul (tmp, NULL, 10)         //如果找不到baudrate环境变量,则赋值一个已经定义的值
: CONFIG_BAUDRATE;

return (0);
}

getenv_r用于获取一个环境变量的值,并将此值存放在tmp中,如果要获取的环境变量存在,则返回写入tmp缓冲区的字节数,如果不存在,则返回-1。此函数在common/cmd_nvedit.c中定义。
CONFIG_BAUDRATE在include/autoconf.mk中定义

/*************************   serial_init            ************************************/
此函数在common/serial.c定义
int serial_init (void)
{
if (!(gd->flags & GD_FLG_RELOC) || !serial_current) {
struct serial_device *dev = default_serial_console ();

return dev->init ();                     //执行结构体中的函数指针init指向的函数
}

return serial_current->init ();
}

default_serial_console()函数在common/serial.c中定义:
struct serial_device *default_serial_console(void)     __attribute__((weak, alias("__default_serial_console")));
以上这个定义的意思是__default_serial_console函数的别名为default_serial_console,具体含义看__attribute__的用法,所以相当于是__default_serial_console函数,这个函数也在common/serial.c中定义。

struct serial_device *__default_serial_console (void)
{
#if defined(CONFIG_SERIAL0)
return &s5pc1xx_serial0_device;
#elif defined(CONFIG_SERIAL1)
return &s5pc1xx_serial1_device;
#elif defined(CONFIG_SERIAL2)
return &s5pc1xx_serial2_device;
#elif defined(CONFIG_SERIAL3)
return &s5pc1xx_serial3_device;
}
通过以上几个宏确定要使用哪个串口,然后返回一个结构体地址。我们定义了CONFIG_SERIAL0 这个宏,则使用串口0,所以返回s5pc1xx_serial0_device这个结构体的地址,这个结构体在drivers/serial/serial_s5pc1xx.c中定义:
DECLARE_S5P_SERIAL_FUNCTIONS(0);          // 这个宏定义了一系列的串口函数,包括初始化串口,设置波特率等
struct serial_device s5pc1xx_serial0_device =
INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0", "S5PUART0");     //这个宏则将一系列的值赋给s5pc1xx_serial0_device 结构
                                                                                                                           //体,包括上面定义的一系列串口函数的首地址等

/*************************   console_init_f          ************************************/
这个函数定义在common/console.c中
int console_init_f(void)
{
gd->have_console = 1;                //serial_init() was called

#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL)
gd->flags |= GD_FLG_SILENT;
#endif

return 0;
}

/*************************   display_banner          ************************************/
此函数在ib_arm/board.c中
这个函数主要显示启动U-BOOT时的版本信息
static int display_banner (void)
{
printf ("\n\n%s\n\n", version_string);                        //打印U-BOOT的版本信息
/**************调试U-BOOT时才会打印*******************/
debug ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
       _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT
debug ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
debug ("IRQ Stack: %08lx\n", IRQ_STACK_START);
debug ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

return (0);
}
version_string在ib_arm/board.c中定义:
const char version_string[ ] =
U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"CONFIG_IDENT_STRING;
打印出的版本信息如:
U-Boot 2010.03 (Oct 30 2013 - 14:32:07) for Smdkv100

/*************************   print_cpuinfo         ************************************/
这个函数在cpu/arm_cortexa8/s5pc1xx/clock_info.c中定义
int print_cpuinfo(void)
{
char buf[32];

printf("CPU:\tS5P%X@%sMHz\n",
s5pc1xx_cpu_id, strmhz(buf, get_arm_clk()));

return 0;
}
打印cpu信息,如:CPU:    S5PC110@1000MHz
s5pc1xx_cpu_id在cpu/arm_cortexa8/s5pc1xx/clock_info.c中定义:
unsigned int s5pc1xx_cpu_id = 0xC100;
或则由初始化序列中的第一个函数arch_cpu_init定义    

/*************************   checkboard        ************************************/
这个函数在board/samsung/smdkc100/smdkc100.c中
int checkboard(void)
{
printf("Board:\tSMDKC100\n");
return 0;
}
打印板子信息,如:Board:  FS210


/*************************   dram_init           ************************************/
这个函数在board/samsung/smdkc100/smdkc100.c中
int dram_init(void)
{
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;                //指定DMC0的开始地址
gd->bd->bi_dram[0].size = get_ram_size((long *)PHYS_SDRAM_1,    //指定DMC0的size
PHYS_SDRAM_1_SIZE);

#ifdef PHYS_SDRAM_2
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;                  //指定DMC1的开始地址
gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2,
PHYS_SDRAM_2_SIZE);             //指定DMC1的size
#endif    

return 0;
}

PHYS_SDRAM_X和PHYS_SDRAM_X_SIZE在 include/configs/smdkc100.h中定义
get_ram_size函数主要做一个简单的测试,测试外接RAM中真正可用的地址大小

/*************************   display_dram_config         ************************************/
这个函数在ib_arm/board.c中定义
static int display_dram_config (void)
{
int i;
ulong size = 0;

for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
size += gd->bd->bi_dram[i].size;                    //计算外接RAM(DDR2)总的大小
}
puts("DRAM:  ");
print_size(size, "\n");                                            //打印RAM信息

return (0);
}

至此,初始化序列完毕!!!




0 0
原创粉丝点击