http://blog.csdn.net/viviod/article/details/7351324
花了三个晚上弄清楚整个流程之后,累翻了。我想,写完这份注释以后,大概我再也不想看到这块的启动分析了。
今天到此为止,明天开始做最后一个mem_ctrl_init的解析。两天内结束。
/*
* Memory Setup stuff - taken from blob memsetup.S
*
* Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
* Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
*
* Modified for the Samsung SMDK2410 by
* (C) Copyright 2002
* David Mueller, ELSOFT AG, <D ch="" elsoft="" mueller="">
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <CONFIG h="">
#include <VERSION h="">
#include <S3C6410 h="">
#include "smdk6410_val.h"
_TEXT_BASE:
.word TEXT_BASE
.globl lowlevel_init
lowlevel_init:
mov r12, lr
;保存当前链接寄存器地址,等跳转回start.s时继续执行使用
ldr r0, =ELFIN_GPIO_BASE ;定基地址 0x7f008000
ldr r1, =0x55555555
str r1, [r0, #GPKCON0_OFFSET]; 0x7f008000 + 0x800
;设置引脚GPIO-K[0-7]管脚为cfdata 模式
ldr r1, =0x55555555
str r1, [r0, #GPKCON1_OFFSET];0x7f008000 + 0x804
;设置引脚GPIO-K[8-14]管脚为cfdata 模式
ldr r1, =0x22222666 ;0010 0010 0010 0010 0010 0110 0110 0110
str r1, [r0, #GPLCON0_OFFSET];0x7f008000 + 0x810
;设置引脚GPIO-L
;打开CF卡串口通信的0-2号三根地址线,其余不变,保持默认值
ldr r1, =0x04000000 ;01 00 00 00 00 00 00 00 00 00 00 00 00 00
str r1, [r0, #GPFCON_OFFSET];0x7f008000 + 0xA0
;设置引脚GPIO-F14为输出
;GPIO-F14连接CLKOUT输出
ldr r1, =0x2000; 10000000000000
str r1, [r0, #GPFDAT_OFFSET];0x7f008000 + 0xA4
;通过向GPIO锁存器写1,维持一个高电平信号。
/* LED on only #8 */
ldr r0, =ELFIN_GPIO_BASE ;0x7f008000
ldr r1, =0x00111111 ;0001 0001 0001 0001 0001 0001
str r1, [r0, #GPMCON_OFFSET] ;0x7f008000 + 0x820
;GPIO0-5引脚使能为输出
ldr r1, =0x00000555 ;010101010101
str r1, [r0, #GPMPUD_OFFSET]
;由于刚启动上电信号不稳定,GPIO0-5引脚下拉电阻保证信号毛刺消除?为何要接下拉,下拉一般是输入时用啊
ldr r1, =0x002a; 101010
str r1, [r0, #GPMDAT_OFFSET] ;0x7f008000 + 0x824
;点亮第二个LED和第4个LED
ldr r1, =0 /*0x55555555 phantom*/ ;1010101010101010101010101010101
str r1, [r0, #MEM1DRVCON_OFFSET] ;0x7f008000 + 0x1D4
;内存驱动控制设置为默认值
/* Disable Watchdog */
ldr r0, =0x7e000000 @0x7e004000
orr r0, r0, #0x4000
mov r1, #0
str r1, [r0]
;关看门狗
@ External interrupt pending clear
ldr r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET) /*EINTPEND*/;0x7f008000 + 0x924
ldr r1, [r0]
str r1, [r0]
;外部中断挂起
ldr r0, =ELFIN_VIC0_BASE_ADDR @0x71200000
ldr r1, =ELFIN_VIC1_BASE_ADDR @0x71300000
;中断向量表0和中断向量表1地址
@ Disable all interrupts (VIC0 and VIC1)
mvn r3, #0x0;反转为1
str r3, [r0, #oINTMSK];中断向量表0的中断使能清0
str r3, [r1, #oINTMSK];中断向量表1的中断是能清0
;
@ Set all interrupts as IRQ
mov r3, #0x0
str r3, [r0, #oINTMOD];0x7120000c
str r3, [r1, #oINTMOD];0x7130000c
;中断选择寄存器,设置为0,选择IRQ中断模式
@ Pending Interrupt Clear
mov r3, #0x0
str r3, [r0, #oVECTADDR]
str r3, [r1, #oVECTADDR]
;中断地址寄存器挂起清零。注意,手册上写,这里无论设置任何值都将挂起中断。
;务必在中断服务程序执行完毕之后进行清零
;否则将会导致不可预知的异常
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;运行至此处,做完了下面几件事情
;1,gpio使能并设置为CF卡功能模式
;2,led灯点亮
;3,关闭看门狗
;4,关闭外部中断并挂起
;5,关闭中断并挂起
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* init system clock */
bl system_clock_init
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;运行至此处,做完了下面几件事情
; 运行至此处,时钟分频全部完成,设置为同步模式
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* for UART */
bl uart_asm_init
@至此,uart串口使能完毕。
ldr r0, =ELFIN_UART_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]
#if defined(CONFIG_NAND)
/* simple init for NAND */
bl nand_asm_init
#endif
bl mem_ctrl_asm_init
@跳到cpu_init.s文件中执行。执行完毕,跳转回此处,再跳转回kernel流程
#if 1
ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
ldr r1, [r0]
bic r1, r1, #0xfffffff7
cmp r1, #0x8
beq wakeup_reset
#endif
1:
ldr r0, =ELFIN_UART_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]
mov lr, r12
mov pc, lr
#if 1
wakeup_reset:
/*Clear wakeup status register*/
ldr r0, =(ELFIN_CLOCK_POWER_BASE+WAKEUP_STAT_OFFSET)
ldr r1, [r0]
str r1, [r0]
/*LED test*/
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x3000
str r1, [r0, #GPNDAT_OFFSET]
/*Load return address and jump to kernel*/
ldr r0, =(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)
ldr r1, [r0] /* r1 = physical address of s3c6400_cpu_resume function*/
mov pc, r1 /*Jump to kernel (sleep-s3c6400.S)*/
nop
nop
#endif
/*
* system_clock_init: Initialize core clock and bus clock.
* void system_clock_init(void)
*/
system_clock_init:
ldr r0, =ELFIN_CLOCK_POWER_BASE @0x7e00f000;APLL时钟地址
#ifdef CONFIG_SYNC_MODE
ldr r1, [r0, #OTHERS_OFFSET] ;0x7e00f000 + 0x900
mov r2, #0x40 ;100 0000
orr r1, r1, r2
;设置为异步模式,不修改其他设置
str r1, [r0, #OTHERS_OFFSET]
;开始浮空,等待指令生效
nop
nop
nop
nop
nop
ldr r2, =0x80 ; 1000 0000
;不理解此句,第八位开始是只读选项
orr r1, r1, r2
str r1, [r0, #OTHERS_OFFSET] ;0x7e00f000 + 0x900地址里的内容
check_syncack:
ldr r1, [r0, #OTHERS_OFFSET]
ldr r2, =0xf00 ;1111 0000 0000
and r1, r1, r2
cmp r1, #0xf00
bne check_syncack; bne 非零则跳转
#else /* ASYNC Mode */
#endif
mov r1, #0xff00
orr r1, r1, #0xff
str r1, [r0, #APLL_LOCK_OFFSET]
str r1, [r0, #MPLL_LOCK_OFFSET]
str r1, [r0, #EPLL_LOCK_OFFSET]
;使A,M,E三个时钟使能
/* CLKUART(=66.5Mhz) = CLKUART_input(532/2=266Mhz) / (UART_RATIO(3)+1) */
/* CLKUART(=50Mhz) = CLKUART_input(400/2=200Mhz) / (UART_RATIO(3)+1) */
/* Now, When you use UART CLK SRC by EXT_UCLK1, We support 532MHz & 400MHz value */
#if defined(CONFIG_CLKSRC_CLKUART)
ldr r1, [r0, #CLK_DIV2_OFFSET] ;0x28
;取时钟分频地址
bic r1, r1, #0x70000 ;0111 0000 0000 0000 0000
orr r1, r1, #0x30000 ;0011 0000 0000 0000 0000
str r1, [r0, #CLK_DIV2_OFFSET]
#endif
ldr r1, [r0, #CLK_DIV0_OFFSET] /*Set Clock Divider*/
bic r1, r1, #0x30000
bic r1, r1, #0xff00
bic r1, r1, #0xff
ldr r2, =CLK_DIV_VAL;时钟频率设置,
;#if defined(CONFIG_CLK_800_133_66)
;#define Startup_APLLdiv 0
;#define Startup_HCLKx2div 2
;#elif defined(CONFIG_CLK_400_133_66)
;#define Startup_APLLdiv 1
;#define Startup_HCLKx2div 2
;#else
;#define Startup_APLLdiv 0
;#define Startup_HCLKx2div 1
;#endif
;#define Startup_PCLKdiv 3
;#define Startup_HCLKdiv 1
;#define Startup_MPLLdiv 1
;#define CLK_DIV_VAL ((Startup_PCLKdiv<<12)|(Startup_HCLKx2div<<9)|(Startup_HCLKdiv<<8)|(Startup_MPLLdiv<<4 startup_aplldiv="" orr="" r1="" r1="" r2="" str="" r1="" r0="" clk_div0_offset="" ldr="" r1="" apll_val="" str="" r1="" r0="" apll_con_offset="" ldr="" r1="" mpll_val="" str="" r1="" r0="" mpll_con_offset="" ldr="" r1="" 0x80200203="" fout="" of="" epll="" is="" 96mhz="" str="" r1="" r0="" epll_con0_offset="" ldr="" r1="" 0x0="" str="" r1="" r0="" epll_con1_offset="" ldr="" r1="" r0="" clk_src_offset="" apll="" mpll="" epll="" select="" to="" fout="" if="" defined="" config_clksrc_clkuart="" ldr="" r2="" 0x2007="" else="" ldr="" r2="" 0x7="" endif="" orr="" r1="" r1="" r2="" str="" r1="" r0="" clk_src_offset="" wait="" at="" least="" 200us="" to="" stablize="" all="" clock="" mov="" r1="" 0x10000="" 1:="" subs="" r1="" r1="" 1="" bne="" 1b="" 2000="" ifdef="" config_sync_mode="" synchronization="" for="" vic="" port="" ldr="" r1="" r0="" others_offset="" orr="" r1="" r1="" 0x20="" str="" r1="" r0="" others_offset="" else="" ldr="" r1="" r0="" others_offset="" bic="" r1="" r1="" 0x20="" str="" r1="" r0="" others_offset="" endif="" mov="" pc="" lr="" bl="" uart_asm_init="" uart_asm_init:="" initialize="" uart="" in="" asm="" mode="" 115200bps="" fixed="" void="" uart_asm_init="" void="" uart_asm_init:="" set="" gpio="" to="" enable="" uart="" gpio="" setting="" for="" uart="" ldr="" r0="" elfin_gpio_base="" 0x7f008000="" ldr="" r1="" 0x220022="" 0000="" 0000="" 0010="" 0010="" 0000="" 0000="" 0010="" 0010="" str="" r1="" r0="" gpacon_offset="" 0x00="" uart1="" gpio-a2="" gpio-a3="" uart2="" gpio-a6="" gpio-a7="" ldr="" r1="" 0x2222="" 0000="" 0000="" 0000="" 0000="" 0010="" 0010="" 0010="" 0010="" str="" r1="" r0="" gpbcon_offset="" 0x7f008000="" 0x20="" uart2="" uart3="" gpio-b3="" gpio-b7="" ok="" 4="" 32="" ldr="" r0="" elfin_uart_console_base="" 0x7f005000="" mov="" r1="" 0x0="" str="" r1="" r0="" ufcon_offset="" define="" ufcon_offset="" 0x08="" str="" r1="" r0="" umcon_offset="" define="" umcon_offset="" 0x0c="" mov="" r1="" 0x3="" was="" 0="" str="" r1="" r0="" ulcon_offset="" 8bit="" 1="" if="" defined="" config_clksrc_clkuart="" ldr="" r1="" 0xe45="" uartclk="" src="11"> EXT_UCLK1*/
#else
ldr r1, =0x245 /* UARTCLK SRC = x0 => PCLK */
#endif
str r1, [r0, #UCON_OFFSET] ;0x04 ,按照硬件手册配时钟频率
#if defined(CONFIG_UART_50)
ldr r1, =0x1A
#elif defined(CONFIG_UART_66)
ldr r1, =0x22
#else
ldr r1, =0x1A
#endif
str r1, [r0, #UBRDIV_OFFSET] ;0x28 设置串口波特率
#if defined(CONFIG_UART_50)
ldr r1, =0x3
#elif defined(CONFIG_UART_66)
ldr r1, =0x1FFF
#else
ldr r1, =0x3
#endif
str r1, [r0, #UDIVSLOT_OFFSET] ;波特率
ldr r1, =0x4f4f4f4f
str r1, [r0, #UTXH_OFFSET] @'O' ;0x20
@设置串口缓冲寄存器
mov pc, lr
@跳转回主干继续往下走
/*
* Nand Interface Init for SMDK6400 */
nand_asm_init:
ldr r0, =ELFIN_NAND_BASE ;nand flash 基址#define ELFIN_NAND_BASE0x70200000
ldr r1, [r0, #NFCONF_OFFSET] ;#define NFCONF_OFFSET 0x00;
orr r1, r1, #0x70 ; 0 0000 0 00 000000000 111 0 111 0 111 0000
orr r1, r1, #0x7700
str r1, [r0, #NFCONF_OFFSET];nandflash控制寄存器配置完成
ldr r1, [r0, #NFCONT_OFFSET]
orr r1, r1, #0x03 ;0 0000 0 00 000000000 111 0 111 0 111 0000 AND 11
str r1, [r0, #NFCONT_OFFSET] ;0 0000 0 00 000000000 111 0 111 0 111 0011
mov pc, lr
@至此,nandflash简单的配置了一下,其实我觉得这里可以不用配置,在mm control过程中配置也是可以的。
从链接寄存器取出当前PC指针,跳回主干流程,执行mem_ctrl_asm_init过程。当前ARM芯片工作模式为SVC模式,现在还没回到启动代码kernel中。
</4></S3C6410></VERSION></CONFIG></D>