1。第一阶段完成的功能
u-boot-2010.06/arch/arm/cpu/arm920t/start.S
Bootloader第一阶段的功能
<1>硬件初始化。
关WATCHDOG、关中断
设置CPU工作模式为管理模式(svc)
设置时钟频率 FCLK,HCLK,PCLK的比例(即设置CLKDIVN)
RAM初始化 关闭MMU.CACHE
<2>为加载Bootloader的第二阶段代码准备RAM空间。
所谓准备RAM空间就是初始化内存芯片,使其能正常工作。在start.S中调用lowlevel_init 函数来设置存储控制器,使得外接的SDRAM可用。代码在lowlevel_init.S中。
<3>设置好栈。
<4>跳转到第二阶段的C入口点。
在跳转之前,还要清除BSS段(初始值为0、无初始化的全局变量、静态变量都放在BSS段)。如果设置了如下命令(1-bootdelay、2-bootm)则直接跳转,调用lib_arm/board.c中的start_armboot()函数。这是第二阶段的入口点。
start_code:
-
.globl _start // uboot的主入口
-
_start: b start_code //这是跳转向量表 占一个word
-
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 //中断向量
-
-
//.word 伪操作用于分配一word的内存单元
-
//并且用expr初始化 与.long作用相同
-
_undefined_instruction: .word undefined_instruction
-
_software_interrupt: .word software_interrupt
-
_prefetch_abort: .word prefetch_abort
-
_data_abort: .word data_abort
-
_not_used: .word not_used
-
_irq: .word irq
-
_fiq: .word fiq
-
//以上总共占了4*7+4*8=60字节内存
-
// .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign的作用
-
同.align。
-
// .align {alignment} {,fill} {,max}
-
// 其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0
-
填充。max是填充字节数最大值
-
// .align 4 /* 指定对齐方式为字对齐 */
-
.balignl 16,0xdeadbeef
-
//16字节对齐 当指针移到64时填充0xdeadbeef这个值
-
//不能为4,因为pc值在任何时候,都是4的倍数,只要不为0就为4的倍数,呵呵,这个值不行,如果用了这个值,0xdeadbeef永远也插不进去,呵呵。
-
-
// TEXT_BASE在研发板相关的目录中的config.mk文档中定义, 他定义了
-
// 代码在运行时所在的地址, 那么_TEXT_BASE中保存了这个地址
-
-
_TEXT_BASE:
-
.word TEXT_BASE
-
-
//声明为全局变量 _armboot_start并用_start来初始化
-
.globl _armboot_start
-
_armboot_start:
-
.word _start
-
-
.globl _bss_start
-
_bss_start:
-
.word __bss_start
-
-
.globl _bss_end
-
_bss_end:
-
-
.word _end
-
#ifdef CONFIG_USE_IRQ
-
/* IRQ stack memory (calculated at run-time) */
-
.globl IRQ_STACK_START
-
IRQ_STACK_START:
-
.word 0x0badc0de
-
-
/* IRQ stack memory (calculated at run-time) */
-
.globl FIQ_STACK_START
-
FIQ_STACK_START:
-
.word 0x0badc0de
-
#endif
start_code:
设置cpu的模式
-
/* set the cpu to SVC32 mode*/
-
mrs r0, cpsr
-
bic r0, r0, #0x1f
-
orr r0, r0, #0xd3
-
msr cpsr, r0
#ifdef CONFIG_S3C24X0
设置watchdog interupt clock divisor 的base
-
# if defined(CONFIG_S3C2400)
-
# define pWTCON 0x15300000
-
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
-
# define CLKDIVN 0x14800014 /* clock divisor register */
-
#else
-
# define pWTCON 0x53000000 // WatchDog-Controller base addresses
-
# define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
-
# define INTSUBMSK 0x4A00001C
-
# define CLKDIVN 0x4C000014 /* clock divisor register */
-
# endif
关看门狗
-
ldr r0, =pWTCON
-
mov r1, #0x0
-
str r1, [r0]
关闭中断
-
mov r1, #0xffffffff
-
ldr r0, =INTMSK
-
str r1, [r0]
-
-
# if defined(CONFIG_S3C2410)
-
ldr r1, =0x3ff
-
ldr r0, =INTSUBMSK
-
str r1, [r0]
-
# endif
-
# if defined(CONFIG_S3C2440)
-
ldr r1, =0x7fff
-
ldr r0, =INTSUBMSK
-
str r1, [r0]
-
# endif
#if 0
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
时钟设置在clock_init函数中
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
#endif
#endif /* CONFIG_S3C24X0 */
CPU初始化 关闭MMU Cache 并初始化存储控制器的参数
-
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
-
bl cpu_init_crit
-
#endif
-
//跳入cpu_init_crit ,这是一个系统初始化函数,他还会调用board/samsung/lowlevel_init.S中的lowlevel_init函数。主要是对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor Flash、SDRAM才可以被系统使用。下面的代码重定向就依赖它。
-
lowlevel_init.S这个函数中要注意这时的代码、数据都只是保存在Nor Flash上,内存中还没有,所以读取数据时要变化数据。这些都在4kb Stepping Stone中进行。
-
_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 表示这13个寄存器的值存放的开始地址(连接地址),值为0x33F8 XXXX ,处于内存中
-
ldr r1, _TEXT_BASE //代码段地址 0x33F8 0000,定义在board/samsung/smdk2440/config.mk中
-
sub r0, r0, r1 //0x33F8 xxxx 与 0x33F8 0000相减,这就是13个寄存器值在NOR Flash上存放的地址
-
ldr r1, =BWSCON /* Bus Width Status Controller */
-
add r2, r0, #13*4
-
0:
-
ldr r3, [r0], #4
-
str r3, [r1], #4
-
cmp r2, r0
-
bne 0b
-
-
/* everything is fine now */
-
mov pc, lr
-
-
.ltorg
-
/* the literal pools origin */
-
-
SMRDATA://根据SDRAM的datasheet,给13个寄存器赋值
-
.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
将堆栈前移并 初始化 因为clock_init(c code)需要
-
stack_setup:
-
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
-
sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area 代码段下面,留一段内存以实现malloc*/
-
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo *///再留出一段内存,存一些全局参数
-
#ifdef CONFIG_USE_IRQ //IRQ,FIQ模式的栈
-
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
-
#endif
-
sub sp, r0, #12 /* leave 3 words for abort-stack *///最后,留出12字节的内存给abort异常
时钟初始化函数
bl clock_init
-
static inline void delay (unsigned long loops)
-
{
-
__asm__ volatile ("1:\n"
-
"subs %0, %1, #1\n"
-
"bne 1b":"=r" (loops):"0" (loops));
-
}
-
-
/* S3C2440: Mpll = (2*m * Fin) / (p * 2^s), UPLL = (m * Fin) / (p * 2^s)
-
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
-
*/
-
#define S3C2440_MPLL_400MHZ ((0x5c<<12)|(0x01<<4)|(0x01))
-
#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
-
#define S3C2440_MPLL_100MHZ ((0x5c<<12)|(0x01<<4)|(0x03))
-
#define S3C2440_UPLL_96MHZ ((0x38<<12)|(0x02<<4)|(0x01))
-
#define S3C2440_UPLL_48MHZ ((0x38<<12)|(0x02<<4)|(0x02))
-
#define S3C2440_CLKDIV (0x05) // | (1<<3)) /* FCLK:HCLK:PCLK = 1:4:8, UCLK = UPLL/2 */
-
#define S3C2440_CLKDIV188 0x04 /* FCLK:HCLK:PCLK = 1:8:8 */
-
#define S3C2440_CAMDIVN188 ((0<<8)|(1<<9)) /* FCLK:HCLK:PCLK = 1:8:8 */
-
-
/* S3C2410: Mpll,Upll = (m * Fin) / (p * 2^s)
-
* m = M (the value for divider M)+ 8, p = P (the value for divider P) + 2
-
*/
-
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
-
#define S3C2410_UPLL_48MHZ ((0x28<<12)|(0x01<<4)|(0x02))
-
#define S3C2410_CLKDIV 0x03 /* FCLK:HCLK:PCLK = 1:2:4 */
-
void clock_init(void)
-
{
-
struct s3c24x0_clock_power *clk_power = (struct s3c24x0_clock_power *)0x4C000000;
-
-
/* support both of S3C2410 and S3C2440, by www.arm9.net */
-
if ((GSTATUS1 == 0x32410000) || (GSTATUS1 == 0x32410002))
-
{
-
/* FCLK:HCLK:PCLK = 1:2:4 */
-
clk_power->CLKDIVN = S3C2410_CLKDIV;
-
-
/* change to asynchronous bus mod */
-
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
-
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
-
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
-
:::"r1"
-
);
-
-
/* to reduce PLL lock time, adjust the LOCKTIME register */
-
clk_power->LOCKTIME = 0xFFFFFFFF;
-
-
/* configure UPLL */
-
clk_power->UPLLCON = S3C2410_UPLL_48MHZ;
-
-
/* some delay between MPLL and UPLL */
-
delay (4000);
-
-
/* configure MPLL */
-
clk_power->MPLLCON = S3C2410_MPLL_200MHZ;
-
-
/* some delay between MPLL and UPLL */
-
delay (8000);
-
}
-
else
-
{
-
/* FCLK:HCLK:PCLK = 1:4:8 */
-
clk_power->CLKDIVN = S3C2440_CLKDIV;
-
-
/* change to asynchronous bus mod */
-
__asm__( "mrc p15, 0, r1, c1, c0, 0\n" /* read ctrl register */
-
"orr r1, r1, #0xc0000000\n" /* Asynchronous */
-
"mcr p15, 0, r1, c1, c0, 0\n" /* write ctrl register */
-
:::"r1"
-
);
-
-
/* to reduce PLL lock time, adjust the LOCKTIME register */
-
clk_power->LOCKTIME = 0xFFFFFFFF;
-
-
/* configure UPLL */
-
clk_power->UPLLCON = S3C2440_UPLL_48MHZ;
-
-
/* some delay between MPLL and UPLL */
-
delay (4000);
-
-
/* configure MPLL */
-
clk_power->MPLLCON = S3C2440_MPLL_400MHZ;
-
-
/* some delay between MPLL and UPLL */
-
delay (8000);
-
}
-
}
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
支持从nandFlash启动并判断启动方式
-
relocate: /* relocate U-Boot to RAM */
-
adr r0, _start /* r0 <- current position of code */ //R0:当前代码段开始地址
-
ldr r1, _TEXT_BASE /* test if we run from flash or RAM *///R1:代码段的连接地址
-
cmp r0, r1 /* don't reloc during debug */ //测试现在是在Flash中还是在RAM中
-
beq clear_bss //stack_setup 如果是则直接跳转到 stack中
-
-
ldr r2, _armboot_start //
-
ldr r3, _bss_start
-
sub r2, r3, r2 /* r2 <- size of armboot */
-
//主要是将c代码段(bootloader第二段)拷到 r1 即代码段链接地址中去
-
//支持从nandflash启动并判断
-
#if 1
-
bl CopyCode2Ram
-
#endif
-
-
int CopyCode2Ram(unsigned long start_addr, unsigned char *buf, int size)
-
{
-
unsigned int *pdwDest;
-
unsigned int *pdwSrc;
-
int i;
-
-
if (bBootFrmNORFlash())
-
{
-
pdwDest = (unsigned int *)buf;
-
pdwSrc = (unsigned int *)start_addr;
-
/* 从 NOR Flash启动 */
-
for (i = 0; i < size / 4; i++)
-
{
-
pdwDest[i] = pdwSrc[i];
-
}
-
return 0;
-
}
-
else
-
{
-
/* 初始化NAND Flash */
-
nand_init_ll();
-
/* 从 NAND Flash启动 */
-
nand_read_ll(buf, start_addr, (size + NAND_BLOCK_MASK)&~(NAND_BLOCK_MASK));
-
return 0;
-
}
-
}
-
-
int bBootFrmNORFlash(void)
-
{
-
volatile unsigned int *pdw = (volatile unsigned int *)0;
-
unsigned int dwVal;
-
-
/*
-
* 无论是从NOR Flash还是从NAND Flash启动,
-
* 地址0处为指令"b Reset", 机器码为0xEA00000B,
-
* 对于从NAND Flash启动的情况,其开始4KB的代码会复制到CPU内部4K内存中,
-
* 对于从NOR Flash启动的情况,NOR Flash的开始地址即为0。
-
* 对于NOR Flash,必须通过一定的命令序列才能写数据,
-
* 所以可以根据这点差别来分辨是从NAND Flash还是NOR Flash启动:
-
* 向地址0写入一个数据,然后读出来,如果没有改变的话就是NOR Flash
-
*/
-
-
dwVal = *pdw;
-
*pdw = 0x12345678;
-
if (*pdw != 0x12345678)
-
{
-
return 1;
-
}
-
else
-
{
-
*pdw = dwVal;
-
return 0;
-
}
-
}
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
清bss段
-
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
-
-
clear_bss:
-
ldr r0, _bss_start /* find start of bss segment */
-
ldr r1, _bss_end /* stop here */
-
mov r2, #0x00000000 /* clear */
-
-
clbss_l:str r2, [r0] /* clear loop... */
-
add r0, r0, #4
-
cmp r0, r1
-
ble clbss_l
ldr pc, _start_armboot
_start_armboot: .word start_armboot
阅读(1386) | 评论(0) | 转发(0) |