u-boot2010.03 分析篇(二)-----lowlevel.init.S

分析篇(二)-----lowlevel.init.S
-----------------------------
使用环境
PC:     ubuntu 11.04
kernel: 2.6.32-28-generic
corss:  arm-linux-gcc 4.3.2
arm:    s3c6410
-----------------------------
作者: LvApp
联系方式: 97164811@qq.com

一切版权均有作者所有,欢迎转载,请指明出处,如何修改请与本人联系,谢谢

今天主要分析上次说的lowlevel_init.S 这个文件board/samsung/smdk6400/lowlevel_init.S
这个文件内的lowlevel_init 就是系统初始化的时候被调用的,在这里面完成很多事情,主要为:
1:led设置
2:禁止看门狗
3:禁止所有的中断
4:设置系统时钟
5:设置nand相关的寄存器
6:设置内存blank相关寄存器


下面直接看代码:
lowlevel_init:
mov	r12, lr
/* 对LED的设置,这里可以根据自己的板子外接的led进行配置,或者直接无视也行 */
/* LED on only #8 */
ldr	r0, =ELFIN_GPIO_BASE
ldr	r1, =0x55540000
str	r1, [r0, #GPNCON_OFFSET]

ldr	r1, =0x55555555
str	r1, [r0, #GPNPUD_OFFSET]

ldr	r1, =0xf000
str	r1, [r0, #GPNDAT_OFFSET]

/* Disable Watchdog */
ldr	r0, =0x7e000000	 @0x7e004000
orr	r0, r0, #0x4000
mov	r1, #0
str	r1, [r0]
/* 此处可见,将0x7E004000 地址处写入了0x00这个值 */
参看 WTCON(0x7E004000) 寄存器可知,第五位是启动和禁止看门狗的位, 0是禁止。这里干脆直接往这个寄存器写 0,这样就肯定可以禁止看门狗了
有图可知,该位默认是为1的。也就是说,看门狗默认是启动的,如果不禁止,那么有可能导致系统不停的复位,以至于无法启动,所以在 uboot启动阶段,
禁止看门狗,而且看门狗需要放到相对比较靠前的位置,可以让系统复位之后,可以保证能够执行到该指定去关闭看门狗,否则在关闭之前系统就复位了。

这里开始就是跟中断相关了
/* External interrupt pending clear */
ldr	r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET)	/*EINTPEND*/
ldr	r1, [r0]
str	r1, [r0]

ldr	r0, =ELFIN_VIC0_BASE_ADDR	@0x71200000
ldr	r1, =ELFIN_VIC1_BASE_ADDR	@0x71300000

/* Disable all interrupts (VIC0 and VIC1) */
mvn	r3, #0x0
str	r3, [r0, #oINTMSK]
str	r3, [r1, #oINTMSK]

/* Set all interrupts as IRQ */
mov	r3, #0x0
str	r3, [r0, #oINTMOD]
str	r3, [r1, #oINTMOD]

/* Pending Interrupt Clear */
mov	r3, #0x0
str	r3, [r0, #oVECTADDR]
str	r3, [r1, #oVECTADDR]

/* init system clock */
/* 
* 系统时钟的配置相对比较重要,s3c6410可以跑到500Mhz+ 呢。所以必须得设置好了
* 设置过程有点长,一会在下面进行分析
*/
bl system_clock_init

#ifndef CONFIG_NAND_SPL
/* for UART */
bl uart_asm_init
#endif

#ifdef CONFIG_BOOT_NAND
/* simple init for NAND */
/* 
* 如果是从nand启动的uboot,那就离不开nand_copy代码了,要使用nand 那就需要对nand进行初始化。
* 也是在下面讲解
*/
bl nand_asm_init
#endif
/*
* 内存初始化
*/
/* Memory subsystem address 0x7e00f120 */
ldr	r0, =ELFIN_MEM_SYS_CFG

/* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */
mov	r1, #S3C64XX_MEM_SYS_CFG_NAND
str	r1, [r0]
/* 进入内存配置 cpu_init.S */
bl	mem_ctrl_asm_init

/* Wakeup support. Don't know if it's going to be used, untested. */
ldr	r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET)
ldr	r1, [r0]
bic	r1, r1, #0xfffffff7
cmp	r1, #0x8
beq	wakeup_reset

1:
mov	lr, r12
mov	pc, lr
至此,整个初始化就完成了。可以看到,这个函数内,完成的任务非常艰巨,可谓是功不可没呀~~下面我们仔细分析下,都具体完成了些什么内容。


system_clock_init:
对于s3c6410时钟频率如何计算,其寄存器的介绍,总线的介绍,请先参阅下面这个链接
S3C6410 系统时钟介绍 http://blog.csdn.net/yyttiao/article/details/7933646
有了上面这个帖子的介绍之后,我们开始分析代码...这里会发现特别简单...
摘取了关键部分代码
/* 设置系统时钟的来源,此处为MPLL 默认也是该值 */
ldr	r1, [r0, #OTHERS_OFFSET]
bic	r1, r1, #0x40	 /* syncmux = 0 moutmpll */
/* sync mux 的时钟来自mpll 倍频器,为1 就是来自 内核频率(典型值533mhz) */
str	r1, [r0, #OTHERS_OFFSET]
#endif
/* 设置PLL锁住时间,默认为最长时间,该值表示在改变频率期间,CPU终止脉冲输出的时间 */
mov	r1, #0xff00
orr	r1, r1, #0xff
str	r1, [r0, #APLL_LOCK_OFFSET]
str	r1, [r0, #MPLL_LOCK_OFFSET]

/* Set Clock Divider */
/* 设置分频比 */
ldr	r1, [r0, #CLK_DIV0_OFFSET]
bic	r1, r1, #0x30000
bic	r1, r1, #0xff00
bic	r1, r1, #0xff

/* CLK_DIV_VAL 这是一个宏,进入该宏,会得到设置好的值.直接写入PLL就好了 */
ldr	r2, =CLK_DIV_VAL	 /* 设置时钟分频比,根据configs/smdk6410.h设置,改变include/arch-s3c64xx/s3c6410.h内对分频比的设置 */

orr	r1, r1, r2
str	r1, [r0, #CLK_DIV0_OFFSET]

/* 设置APLL的分频比以及使能APLL */
/* 公式FOUT = M x Fin / ( P x 2 x s ) */
ldr	r1, =APLL_VAL
str	r1, [r0, #APLL_CON_OFFSET]

/* 设置MPLL的分频比以及使能MPLL */
ldr	r1, =MPLL_VAL
str	r1, [r0, #MPLL_CON_OFFSET]

/* FOUT of EPLL is 96MHz */
/* Fout = (M + K / 2^16) * Fin / (P x 2^s) */
ldr	r1, =0x200203
str	r1, [r0, #EPLL_CON0_OFFSET]
ldr	r1, =0x0
str	r1, [r0, #EPLL_CON1_OFFSET]

/* APLL, MPLL, EPLL select to Fout */
/* 选择时钟源,是经过PLL倍频还是直接外部引脚 */
ldr	r1, [r0, #CLK_SRC_OFFSET]
orr	r1, r1, #0x7
str	r1, [r0, #CLK_SRC_OFFSET]

/* wait at least 200us to stablize all clock */
mov	r1, #0x10000
1:	subs	r1, r1, #1
bne	1b
关于系统时钟频率,到这就介绍完了...还有不明白了,请留言...我会及时回复的.....


nand_asm_init:
我们经常会将uboot放到nand中,因为nor比较贵..所以常用的就是nand了.在使用nand搬移uboot的时候,就得设置nand了..
对于nand只要操作寄存器就好了.因为芯片给我们做好了硬件控制器.而nand访问其实是有时间的,不同的nand芯片,所需要的
总线访问时间是不同的,但是现在我们还不知道外围的设备是什么型号,所以,比较麻烦,当然我们自己用,肯定知道芯片的时间了
但是为了更好的支持,一般在第一阶段,会把nand的总线访问时间,设置为最大时间,这样就比较通用了.在第二阶段的时候,再
去判断芯片的类型,设置比较合理的总线访问时间...这样会比较好...
代码比较简单...先看个图...这里不详细介绍nand的硬件框架图..以后会补上.跟上面介绍时钟一样...
在NAND中有一个寄存器叫做 NCONF 下面是该寄存器中,对时序设置的几个配置,第一阶段都将这些值设置为最高.

/*
 * NAND Interface init for SMDK6400
 */
nand_asm_init:
ldr	r0, =ELFIN_NAND_BASE
/* 此处由于是第一次获取,读取到的应该是复位值 0x0000100X
 * 此处设置了nand时序线上的延时时间,采用最大值 TACLS TWRPH0 TWRPH1 均为7
 * 
 * TACLS = HCLK * TACLS 
 * TWRPH0 = HCLK * (TWRPH0 + 1)
 * TWRPH1 = HCLK * (TWRPH1 + 1)
 */
ldr	r1, [r0, #NFCONF_OFFSET]
orr	r1, r1, #0x70
orr	r1, r1, #0x7700
str	r1, [r0, #NFCONF_OFFSET]

/* 开始nand控制器,禁止2个NAND芯片,未使能 */
ldr	r1, [r0, #NFCONT_OFFSET]
orr	r1, r1, #0x07
str	r1, [r0, #NFCONT_OFFSET]

mov	pc, lr
/*
* NAND Interface init for SMDK6400
*/
nand_asm_init:
ldr	r0, =ELFIN_NAND_BASE
/* 此处由于是第一次获取,读取到的应该是复位值 0x0000100X
 * 此处设置了nand时序线上的延时时间,采用最大值 TACLS TWRPH0 TWRPH1 均为7
 * 
 * TACLS = HCLK * TACLS 
 * TWRPH0 = HCLK * (TWRPH0 + 1)
 * TWRPH1 = HCLK * (TWRPH1 + 1)
 */
ldr	r1, [r0, #NFCONF_OFFSET]
orr	r1, r1, #0x70
orr	r1, r1, #0x7700
str	r1, [r0, #NFCONF_OFFSET]

/* 开始nand控制器,禁止2个NAND芯片,未使能 */
ldr	r1, [r0, #NFCONT_OFFSET]
orr	r1, r1, #0x07
str	r1, [r0, #NFCONT_OFFSET]

mov	pc, lr

对于nand的详细介绍,会在移植帖中讲解..这里只需要简单的知道下就好了..第一阶段对nand的操作,只有copy了...

我们把复杂的处理,都放到第二阶段,到时候会跟大家讲解mtd管理的流程...


Finish!
Thanks a lot;

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值