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
- UBOOT之board.c分析(一)
- UBOOT之board.c分析(二)
- UBOOT之board.c分析(三)
- UBOOT之board.c分析(四)
- uboot之board.c源码分析
- uboot之board.c
- mini6410 uboot board.c 分析
- mini6410 uboot board.c 分析
- uboot-1.1.6 /lib_arm/board.c分析
- uboot-1.1.6 /lib_arm/board.c分析
- TQ210 —— s5pv210 board.c分析(uboot第二阶段)
- Uboot 启动流程分析:启动阶段2 board.c
- Uboot移植之board.c中函数指针数组
- UBOOT之main.c分析
- s3c2410 board.c分析
- s3c2410 board.c分析
- uboot/board/mini2440/conifg.mk 之TEXT_BASE
- uboot分析之Makefile(一)
- 无法嵌入互操作类型“MSScriptControl.ScriptControlClass”
- js编写ajax
- state 状态模式
- 主成分分析(PCA)学习有感
- 【协议分析】Wireshark 过滤表达式实例
- UBOOT之board.c分析(一)
- 支持向量机
- Why the “MAVEN2_CLASSPATH_CONTAINER will not be exported or published”
- strategy 策略模式
- jquery计算出left和top,让一个div水平垂直居中
- UBOOT之board.c分析(二)
- HTTP页面下载(CInternetSession 和 CHttpFile应用)
- 2013-C++第17周项目参考解答链接集
- UBOOT之board.c分析(三)