u-boot启动流程
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
先看board/smsk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm",
"elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000; /*指定可执行image文件的全局入口点,通常这个地址都放在ROM(flash)0x0位置。必须使编译器知道这个地址,通常都是修改此处来完成*/
. = ALIGN(4);
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
.got : { *(.got) }
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) }
_end = .;
}
第一个要链接的是cpu/arm920t/start.o,那么U-Boot的入口指令一
定位于这个程序中。下面详细分析一下程序跳转和函数的调用关系以及函数
实现。
1.Stage1:cpu/arm920t/start.S
这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。
U-Boot启动代码流程图 _start: b reset //复位向量 ;;设置异常向量表
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq //中断向量
ldr pc, _fiq //中断向量
…
/* the actual reset code */
reset: //复位启动子程序
/* 设置CPU为SVC32模式 */
mrs r0,cpsr
bic r0,r0,#0x1f ;;位清除,将某些位的值置0:r0 = r0 AND ( !0x1f)
orr r0,r0,#0xd3 ;;逻辑戒,将r0不立即数进行逻辑戒,放在r0中(第一个)
msr cpsr,r0
/* 关闭看门狗 */
/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base
addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */ #elif defined(CONFIG_S3C2410)
# define pWTCON 0x53000000
# define INTMSK 0x4A000008 /* Interupt-Controller base
addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */ #endif
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/* 禁止所有中断和设置CPU频率 */
/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */ ;;FCLK用于CPU,HCLK用于AHB,
PCLK用于APB
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN ;;根据硬件手册来设置CLKDIVN寄存器
mov r1, #3 ;;用户手册的推荐值
str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */
/* 这些初始化代码在系统重起的时候执行,运行时热复位从RAM中启动不执行 */
/*
* we do sys-critical inits only at reboot,
* not when booting from
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit ;;跳转去初始化CPU
#endif
;;#ifdef CONFIG_INIT_CRITICAL 原文中的,估计是1.1.16版本的 ;; bl cpu_init_crit
;;#endif
/* CPU和RAM两个关键的初始化子程序 */
/* 初始化CPU */
cpu_init_crit:
/*
* flush v4 I/D caches 设置CP15
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ ;;使I/D cache失效:将寄存器r0的数据传送到协处理器p15的c7中。C7寄存器位对应cp15中的cache控制寄存器
mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ ;;使TLB操作寄存器失效:将r0数据送到cp15的c8、c7中。C8对应TLB操作寄存器
/*
* disable MMU stuff and caches 禁止MMU和caches
*/
mrc p15, 0, r0, c1, c0, 0 ;;先把c1和c0寄存器的各位置0(r0 = 0)
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) ;;这里我本来有个疑问:为什么要分开设置。因为arm汇编要求的立即数格式所决
定的
orr r0, r0, #0x00000002 @ set bit 2(??) (A) Align ;;上一条已经设置bit1为0,这一条又设置为1??
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0 ;;用上面(见下面)设定的r0的值设置c1??(cache类型寄存器)和c0(control字寄存器),以下为c0的位定义 ;;bit8: 0 = Disable System protection
;;bit9: 0 = Disable ROM protection
;;bit0: 0 = MMU disabled
;;bit1: 0 = Fault checking disabled 禁止纠错
;;bit2: 0 = Data cache disabled
;;bit7: 0 = Little-endian operation
;;bit12: 1 = Instruction cache enabled
/* 配置内存区控制寄存器 ??有待分析,是1.1.4版本的
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init ;;位于board/smdk2410/lowlevel_init.S:用于完成芯片存储器的初始化,执行完成后返回
mov lr, ip
mov pc, lr
relocate: /* 把U-Boot重新定位到RAM */
adr r0, _start /* r0是代码的当前位置 */ ;;adr伪指令,汇编器自动
通过当前PC的值算出 如果执行到_start时PC的值,放到r0中: 当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为
0x33F80000,即u-boot在把代码拷贝到RAM中去执行的代码段的开
始)
ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */ ;;此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的
(ads中设置,戒-D设置编译器参数)
cmp r0, r1 /* 比较r0和r1,调试的时候不要执行重定位 */
beq stack_setup /* 如果r0等于r1,跳过重定位代码 */
/* 准备重新定位代码 */ ;;以上确定了复位启动代码是在flash中执行的(是系统重启,而不是软复位),就需要把代码拷贝到RAM中去执行,以下为计算即将拷贝的代码的长度
ldr r2, _armboot_start ;;前面定义了,就是_start
ldr r3, _bss_start ;;所谓bss段,就是未被初始化的静态变量存放的
地方,这个地址是如何的出来的?根据board/smsk2410/u-boot.lds内容?
sub r2, r3, r2 /* r2 得到armboot的大小 */
add r2, r0, r2 /* r2 得到要复制代码的末尾地址 */ copy_loop: /* 重新定位代码 */ ;;开始循环拷贝启动的代码到RAM中
ldmia {r3-r10} /*从源地址[r0]复制 */ ;;r0指向_start(=0)
stmia {r3-r10} /* 复制到目的地址[r1] */ ;;r1指向
_TEXT_BASE(=0x33F80000)
cmp r0, r2 /* 复制数据块直到源数据末尾地址[r2] */
ble copy_loop
;;这里附上u-boot各存储区域的映射图,从网上找的,这下对于这几个
地址的位置就一目了然了,对于我这种菜鸟真的是好图啊!
/* 初始化堆栈等 */
stack_setup:
ldr r0, _TEXT_BASE /* 上面是128 KiB重定位的u-boot */
sub r0, r0, #CFG_MALLOC_LEN /* 向下是内存分配空间 */
sub r0, r0, #CFG_GBL_DATA_SIZE /* 然后是bdinfo结构体地址空间 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif ;;这些宏定义在/include/configs/smdk2410.h中: #define CFG_MALLOC_LEN (CFG_ENV_SIZE +
128*1024) ;;64K+128K=0xC0
#define CFG_ENV_SIZE 0x10000 /* Total Size of Environment
Sector 64k*/
#define CONFIG_STACKSIZE (128*1024) /* regular stack 128k */
#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for
initial data */
用0x33F8000 – 0xC0 – 0x80得到_TEXT_BASE向下(低地址)的堆栈指针sp的起点地址
sub sp, r0, #12 /* 为abort-stack预留3个字 */ ;;得到最终sp指
针初始值
clear_bss:
ldr r0, _bss_start /* 找到bss段起始地址 */
ldr r1, _bss_end /* bss段末尾地址 */
mov r2, #0x00000000 /* 清零 */
clbss_l:str r2, [r0] /* bss段地址空间清零循环... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/* 跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */
ldr pc, _start_armboot
_start_armboot: .word start_armboot ;;start_armboot函数在lib_arm/board.c中实现
2.Stage2:lib_arm/board.c
此文件是u-boot Stage2部分,入口为Stage1最后调用的
start_armboot函数。注意上面最后ldr到pc的是_start_armboot这个地址,而非start_armboot变量。
start_armboot是U-Boot执行的第一个C诧言函数,完成系统初始化
工作,进入主循环,处理用户输入的命令。
void start_armboot (void)
{
DECLARE_GLOBAL_DATA_PTR;
//此宏定义了一个gd_t类型的指针 *gd,并指名用r8寄存器来存储:
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("r8")
ulong size;
init_fnc_t **init_fnc_ptr;
char *s;
/* Pointer is writable since we allocated a register for it 上面那个宏的作用*/
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
//此C诧句引用的是start.S中的地址标号_armboot_start,但是得到的却是其中所指的变量_start的值(在RAM中,_start =
0x33F80000)。 Ps: _armboot_start: .word _start
//gd是全局变量,位置在堆栈区以下(低地址):
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long reloc_off; /* Relocation Offset */ //此变量有什么用?
unsigned long env_addr; /* Address of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
unsigned long fb_base; /* base address of frame buffer */ #ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
unsigned long ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */ #endif
void **jt; /* jump table */
} gd_t;
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t)); //得到bd的起点
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
/* 顺序执行init_sequence数组中的初始化函数 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/*配置可用的Flash */
size = flash_init (); //初始化Nor flash的函数,函数实现在下
面
display_flash_config (size); //打印到控制台:Flash: 512 kB
/* _armboot_start 在u-boot.lds链接脚本中定义 */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN); //将CFG_MALLOC_LEN区域用memset函数清零(直接往目的地址写0)
/* 配置环境变量,重新定位 */
env_relocate (); //刚才的初始化函数中有一个是env_init(),根
据CRC校验来初始化gd->env_addr变量(自己设定的还是初始值),
此函数是作用是将环境变量值从某个flash和RAM之间的拷贝。下图描述了ENV的初始化过程:
/* 从环境变量中获取IP地址,放到全局变量gd中 */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/* 以太网接口MAC 地址,放到全局变量gd中,实现过程有待研究*/
{
int i;
ulong reg;
char *s, *e;
uchar tmp[64];
i = getenv_r ("ethaddr", tmp, sizeof (tmp));
s = (i > 0) ? tmp : NULL;
for (reg = 0; reg < 6; ++reg) {
gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) :
0;
if (s)
s = (*e) ? e + 1 : e;
}
}
devices_init (); /* 获取列表中的设备 */
jumptable_init ();
console_init_r (); /* 完整地初始化控制台设备 */
enable_interrupts (); /* 使能例外处理 */
/* 通过环境变量初始化 */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
//以上几个初始化函数有待研究
/* main_loop()总是试图自动启动,循环不断执行 */
for (;;) {
main_loop (); /* 主循环函数处理执行用户命令 -- common/main.c */
}
/* NOTREACHED - no way out of command loop except
booting */
}
以上总体的浏览了u-boot的启动过程,搞的比较乱,以后有空再修改
整理一下,有几个地方还有待弄清,还有Stage2中的多个初始化函数,待续。。。
前面大致分析了u-boot启动的两个阶段的大致流程,今天再更详细的分析
一下启动过程中涉及的几个用于初始化的子函数。分析不当的地方,希望能
得到指正。
1、lowlevel_init(start.S中用于配置内存区控制寄存器,位于
board/smdk2410/lowlevel_init.S)
start.S中跳转代码:
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr
bl lowlevel_init
/* 位于board/smdk2410/lowlevel_init.S:用于完成芯片存储器的初始
化,执行完成后返回*/
mov lr, ip
mov pc, lr
Lowlevel_init文件代码不是很多,精简一下贴在这里:
#define BWSCON 0x48000000
/* BWSCON */
#define DW8 (0x0)
#define DW16 (0x1)
#define DW32 (0x2)
#define WAIT (0x1<<2)
#define UBLB (0x1<<3)
#define B1_BWSCON (DW32) /* 定义每个bank的数
据总线宽度 */
#define B2_BWSCON (DW16) #define B3_BWSCON (DW16 + WAIT + UBLB)
#define B4_BWSCON (DW16) #define B5_BWSCON (DW16) #define B6_BWSCON (DW32) #define B7_BWSCON (DW32)
/* BANK0CON */
#define B0_Tacs 0x0 /* 0clk */
#define B0_Tcos 0x0 /* 0clk */ #define B0_Tacc 0x7 /* 14clk */ #define B0_Tcoh 0x0 /* 0clk */ #define B0_Tah 0x0 /* 0clk */ #define B0_Tacp 0x0
#define B0_PMC 0x0 /* normal */
/* BANK1CON */
/* 之间省略了多个bank区的配置,类似上面的BANK0CON。具体配置
参数见源文件 */
/* BANK7CON */
/* REFRESH parameter */
#define REFEN 0x1 /* Refresh enable */ #define TREFMD 0x0 /* CBR(CAS before RAS)/Auto
refresh */
#define Trp 0x0 /* 2clk */ #define Trc 0x3 /* 7clk */ #define Tchr 0x2 /* 3clk */ #define REFCNT 1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
/* memory control configuration */
/* make r0 relative the current location so that it */
/* reads SMRDATA out of FLASH rather than memory ! */
ldr r0, =SMRDATA /* SMRDATA见下面,BWSCON寄存器的后面紧接着就是0-7个bank的控制寄存器的地址,这里整个数据是8个bank的配置参数和另外4个寄存器的配置参数,具体按照s3c2410的datasheet进行配置 */
ldr r1, _TEXT_BASE
sub r0, r0, r1
ldr r1, =BWSCON /* Bus Width Status Controller 从BWSCON寄存器的地址开始写13*4这么长的数据,也就是从SMRDATA标号开始的那些配置好的数据,一并写入 */
add r2, r0, #13*4
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
/* everything is fine now 上面都配置好了,返回start.S */
mov pc, lr
.ltorg
/* the literal pools origin */
/* 下面共有13个word,设置了一系列连续的寄存器的值,给上面循环
赋值用*/
SMRDATA:
.word
(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word
((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
.word
((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
.word
((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
.word
((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
.word
((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
.word
((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
.word
((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x32
.word 0x30
.word 0x30
2、分析init_sequence里的初始化函数
(1) cpu_init()
为IRQ和FIQ设置中断的开始地址。具体可查看u-boot存储映射图。 int cpu_init (void)
{
/*
* setup up stacks if necessary
*/
#ifdef CONFIG_USE_IRQ
DECLARE_GLOBAL_DATA_PTR;
IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
FIQ_STACK_START = IRQ_STACK_START -
CONFIG_STACKSIZE_IRQ;
#endif
return 0;
}
(2)board_init()
此函数首先按照datasheet初始化了CPU和各个GPIO,然后将CPU体系结构编号和内核启动的参数赋给全局变量gd。
int board_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
//此全局变量指定用r8寄存器存储其地址,所以在任意子函数里面声明一
下,就可以使用同一个全局变量的了
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); /* 以上使clk_power指向0x4C000000这个PLL lock time count
register,后面为一系列配置CPU的寄存器,具体都用
S3C24X0_CLOCK_POWER这个结构体封装起来了,内部变量的顺序正好
和datasheet中定义的一致;gpio指向0x56000000这个GPACON,后
面为一系列GPIO寄存器,用S3C24X0_GPIO封装了,同上。如: typedef struct {
S3C24X0_REG32 LOCKTIME;
S3C24X0_REG32 MPLLCON;
S3C24X0_REG32 UPLLCON;
S3C24X0_REG32 CLKCON;
S3C24X0_REG32 CLKSLOW;
S3C24X0_REG32 CLKDIVN;
} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER; */
/* 下面都是根据datasheet来设置CPU和GPIO的 */
/* to reduce PLL lock time, adjust the LOCKTIME register */
clk_power->LOCKTIME = 0xFFFFFF;
/* configure MPLL */
clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);
/* some delay between MPLL and UPLL */
delay (4000);
/* configure UPLL */
clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4)
+ U_M_SDIV);
/* some delay between MPLL and UPLL */
delay (8000);
/* set up the I/O ports */
gpio->GPACON = 0x007FFFFF;
gpio->GPBCON = 0x00044555;
gpio->GPBUP = 0x000007FF;
gpio->GPCCON = 0xAAAAAAAA;
gpio->GPCUP = 0x0000FFFF;
gpio->GPDCON = 0xAAAAAAAA;
gpio->GPDUP = 0x0000FFFF;
gpio->GPECON = 0xAAAAAAAA;
gpio->GPEUP = 0x0000FFFF;
gpio->GPFCON = 0x000055AA;
gpio->GPFUP = 0x000000FF;
gpio->GPGCON = 0xFF95FFBA;
gpio->GPGUP = 0x0000FFFF;
gpio->GPHCON = 0x002AFAAA;
gpio->GPHUP = 0x000007FF;
/* arch number of SMDK2410-Board */
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; //CPU体
系结构编号
/* adress of boot parameters */
gd->bd->bi_boot_params = 0x30000100; //存放内核启动引导的参数,此变量在后面可传递给go函数的第三个参数
icache_enable();
dcache_enable();
return 0;
}
(3)env_init
初始化环境变量。全局定义的env_t *env_ptr = (env_t
*)CFG_ENV_ADDR,先CRC校验是否正确,若正确就设置gd->env_valid = 1,否之调用默认环境变量,并设置gd->env_valid = 0。冷复位时,env_ptr->data无数据,CRC肯定错误,所以开机后会提示bad CRC... int env_init(void)
{
DECLARE_GLOBAL_DATA_PTR;
if (crc32(0, env_ptr->data, ENV_SIZE) == env_ptr->crc) {
gd->env_addr = (ulong)&(env_ptr->data);
gd->env_valid = 1;
return(0);
}
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 0;
return (0);
}
(4)init_baudrate
获取环境变量,把其中的波特率值给全局gd,若获取为空值,则赋默认的115200。
static int init_baudrate (void)
{
DECLARE_GLOBAL_DATA_PTR;
uchar tmp[64]; /* long enough for environment variables */
int i = getenv_r ("baudrate", tmp, sizeof (tmp)); //将环境变量获取到tmp中,i为得到的环境变量的长度
gd->bd->bi_baudrate = gd->baudrate = (i > 0) //如果确实获取到了env,则给gd,否则把宏定义的115200给gd
? (int) simple_strtoul (tmp, NULL, 10) //此函数把字符串转换成ulong整型
: CONFIG_BAUDRATE; //此宏为115200
return (0);
}
(5)serial_init
此函数调用serial_setbrg ()函数,主函数返回0。serial_setbrg()函数
初始化串口,具体的配置参数根据datasheet设置。 void serial_setbrg (void)
{
DECLARE_GLOBAL_DATA_PTR;
S3C24X0_UART * const uart =
S3C24X0_GetBase_UART(UART_NR);
int i;
unsigned int reg = 0;
/* value is calculated so : (int)(PCLK/16./baudrate) -1 */
reg = get_PCLK() / (16 * gd->baudrate) - 1;
/* FIFO enable, Tx/Rx FIFO clear */
uart->UFCON = 0x07;
uart->UMCON = 0x0;
/* Normal,No parity,1 stop,8 bit */
uart->ULCON = 0x3;
/*
* tx=level,rx=edge,disable timeout int.,enable rx error int.,
* normal,interrupt or polling
*/
uart->UCON = 0x245;
uart->UBRDIV = reg;
#ifdef CONFIG_HWFLOW
uart->UMCON = 0x1; /* RTS up */
#endif
for (i = 0; i < 100; i++);
}
(6)dram_init(),display_dram_config ()
填充全局gd里面有关RAM的地址和大小,即.start和.size两个变量,之后一个函数把内容打印到终端。
int dram_init (void)
{
DECLARE_GLOBAL_DATA_PTR;
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; //smdk2410.h中定义:
// #define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ // #define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
return 0;
}
3、flash_init ()(此函数紧接着上面那一串初始化函数,用于初始化Nor flash的函数,初始化了每个扇区的首地址)
ulong flash_init (void)
{
int i, j;
ulong size = 0;
for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { //我的板子有1块Nor flash
ulong flashbase = 0;
/* 上面定义了全局变量:flash_info_t
flash_info[CFG_MAX_FLASH_BANKS]。此类型定义了NorFlash的基本信息,具体结构如下:
* FLASH Info: contains chip specific data, per FLASH bank
typedef struct {
ulong size; /* total bank size in bytes */
ushort sector_count; /* number of erase units */
ulong flash_id; /* combined device & manufacturer
code */
ulong start[CFG_MAX_FLASH_SECT]; /* physical sector start
addresses */
uchar protect[CFG_MAX_FLASH_SECT]; /* sector protection
status */
#ifdef CFG_FLASH_CFI
uchar portwidth; /* the width of the port */
uchar chipwidth; /* the width of the chip */
ushort buffer_size; /* # of bytes in write buffer */
ulong erase_blk_tout; /* maximum block erase
timeout */
ulong write_tout; /* maximum write timeout */
ulong buffer_write_tout; /* maximum buffer write
timeout */
ushort vendor; /* the primary vendor id */
ushort cmd_reset; /* Vendor specific reset command */
ushort interface; /* used for x8/x16 adjustments */ #endif
} flash_info_t;
下面就是对这个结构的填充 */
flash_info[i].flash_id = //我这块sbc2410的NorFlash型号是29LV160DB
#if defined(CONFIG_AMD_LV400)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV400B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV800)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV800B & FLASH_TYPEMASK);
#else
#error "Unknown flash configured"
//以上没有这个型号,若默认编译,叧能认出是512K的,实际是2M的,若要移植到sbc2410上,这里要修改才能得到正确的容量
#endif
flash_info[i].size = FLASH_BANK_SIZE;
//在/include/configs/smdk2410.h文件中定义了此块NorFlash的PHY_FLASH_SIZE,我这个应该是2M
flash_info[i].sector_count = CFG_MAX_FLASH_SECT; //擦除的单元总数,在smdk2410.h中定义为19(1M容量的NorFlash,我这块应该是多少个?),即flash中的扇区总数目
memset (flash_info[i].protect, 0, CFG_MAX_FLASH_SECT);//取消扇区的写保护?
if (i == 0)
flashbase = PHYS_FLASH_1;
else
panic ("configured too many flash banks!\n"); //叧有一块Norflash,如果i > 0了表示不止一块
for (j = 0; j < flash_info[i].sector_count; j++) {
//初始化每个扇区的首地址。其中,前4个扇区的大小和后面不同,需要分开设置。??
if (j <= 3) {
/* 1st one is 16 KB */
if (j == 0) {
flash_info[i].start[j] =
flashbase + 0;
}
/* 2nd and 3rd are both 8 KB */
if ((j == 1) || (j == 2)) {
flash_info[i].start[j] =
flashbase + 0x4000 + (j -
1) *
0x2000;
}
/* 4th 32 KB */
if (j == 3) {
flash_info[i].start[j] =
flashbase + 0x8000;
}
} else {
flash_info[i].start[j] =
flashbase + (j - 3) * MAIN_SECT_SIZE; //后面的扇区都是0x10000,即64KB
}
}
size += flash_info[i].size; //计算此块flash的总size,供最后
return
}
flash_protect (FLAG_PROTECT_SET,
CFG_FLASH_BASE,
CFG_FLASH_BASE + monitor_flash_len - 1,
&flash_info[0]);
//此函数有待研究
flash_protect (FLAG_PROTECT_SET,
CFG_ENV_ADDR,
CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0]);
return size;
}