lowlevel_init.S

文件:u-boot/board/samsung/mini6410/lowlevel_init.S
#include <config.h>
#include <version.h>

#include <s3c6410.h>
#include "mini6410_val.h"

_TEXT_BASE:
     .word     TEXT_BASE                   @每个lds里面的模块,都可以定义一个TEXT_BASE。

     .globl lowlevel_init
lowlevel_init:
     mov     r12, lr                                @保存PC值到r12

     /* LED on only #8 */
     ldr     r0, =ELFIN_GPIO_BASE         @GPIO的基地址=0x7f008000
     ldr     r1, =0x55540000
     str     r1, [r0, #GPNCON_OFFSET]  @设置GPN15到GPN9(GPN15-GPN13为boot中断?,GPN12为IR红外接口,GPN11/GPN9为外部GPIO口,GPN10为SDIO口使用)为输出管脚;
                                                        @GPN8到GPN0(GPN0-GPN5为mini6410的K1到K6的6个按键,GPN7为DM9000网络芯片的INT中断引脚,GPN6为外部GPIO口,GPN8为USB OTG中断接口)为输入管脚。

     ldr     r1, =0x55555555
     str     r1, [r0, #GPNPUD_OFFSET]  @全部下拉使能

     ldr     r1, =0xf000
     str     r1, [r0, #GPNDAT_OFFSET]  @设置GPN15-GPN12为1,GPN11-GPN9为1,GPN8-GPN0为输入管脚,设置无效,外部是什么信号,数据就是什么。

     ldr     r0, =ELFIN_GPIO_BASE
     ldr     r1, =0x1
     str     r1, [r0, #GPECON_OFFSET]  @设置GPE4-GPE1(mini6410保留给GPIO)为输入,GPE0(mini6410为LCD的夜晚背光on或off)为输出。
     ldr     r1, =0x0
     str     r1, [r0, #GPEDAT_OFFSET]  @设置GPE0输出0。

     ldr     r0, =ELFIN_GPIO_BASE
     ldr     r1, =0x2A5AAAAA
     str     r1, [r0, #GPPCON_OFFSET]  @设置GPP14(mini6410为GPIO)为输入,GPP13-GPP11(GPP13,GPP12在mini6410为GPIO,GPP11为WiFi_PD),GPP8-GPP0(mini6410为GPIO,GPP7-GPP2为Flash,GPP1和GPP0为mem0暂时未用)为MEM0_XXX,GPP10-GPP9(mini6410下GPP9为GPIO,GPP10为WiFi_IO)为输出。
     ldr     r1, =0x0
     str     r1, [r0, #GPPDAT_OFFSET]  @设置所有输出为0。
    

     ldr     r1, =0x55555555
     str     r1, [r0, #MEM1DRVCON_OFFSET]  @设置存储器端口1(mini6410为RAM)芯片管脚的电平为7毫安或10mA。

     /* 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*/
     ldr     r1, [r0]
     str     r1, [r0]                     @读一次外部中断引脚,读完之后中断信号就都被清除,上面已经禁止了中断,所以读完之后就不会再产生中断了。

     ldr     r0, =ELFIN_VIC0_BASE_ADDR      @0x71200000 中断控制器0
     ldr     r1, =ELFIN_VIC1_BASE_ADDR      @0x71300000 中断控制器1

     @ Disable all interrupts (VIC0 and VIC1)
     mvn     r3, #0x0               @0取反,为全1
     str     r3, [r0, #oINTMSK]  @中断使能清除寄存器全部设置1,清除所有中断使能
     str     r3, [r1, #oINTMSK]

     @ Set all interrupts as IRQ
     mov     r3, #0x0
     str     r3, [r0, #oINTMOD]  @所有中断设置为IRQ中断。
     str     r3, [r1, #oINTMOD]

     @ Pending Interrupt Clear
     mov     r3, #0x0
     str     r3, [r0, #oVECTADDR]  @设置矢量地址寄存器(当前中断的矢量地址)为全0。
     str     r3, [r1, #oVECTADDR]

     /* init system clock */
     bl system_clock_init              @初始化系统时钟。

     /* for UART */
     bl uart_asm_init                   @初始化UART串口。

#if defined(CONFIG_NAND)
     /* simple init for NAND */
     bl nand_asm_init                 @NAND FLASH初始化。
#endif

#if 0
     ldr     r0, =0xff000fff
     bic     r1, pc, r0          /* r0 <- current base addr of code */
     ldr     r2, _TEXT_BASE          /* r1 <- original base addr in ram */
     bic     r2, r2, r0          /* r0 <- current base addr of code */
     cmp      r1, r2               /* compare r0, r1                  */
     beq     1f               /* r0 == r1 then skip sdram init   */
#endif

     bl     mem_ctrl_asm_init      @内存控制初始化(参考cpu_init.S)。

#if 1
        ldr     r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET) @RESET状态,0x7E00F904
        ldr     r1, [r0]
        bic     r1, r1, #0xfffffff7
        cmp     r1, #0x8
        beq     wakeup_reset                     @SLEEP模式唤醒导致的reset。

#endif

1:
     ldr     r0, =ELFIN_UART_BASE
     ldr     r1, =0x4b4b4b4b
     str     r1, [r0, #UTXH_OFFSET]  @UART发送缓冲区设置为'K'。

     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]          @写一次唤醒状态寄存器,可以清除掉这些状态。应该写1,这里为什么只写了一下呢?

        /*LED test*/
        ldr     r0, =ELFIN_GPIO_BASE
        ldr     r1, =0x3000
        str     r1, [r0, #GPNDAT_OFFSET] @设置GPN14和GPN13的值为1,跟mini6410实际不一致,mini6410的LED在GPK4,5,6,7。

     /*Load return address and jump to kernel*/
     ldr     r0, =(ELFIN_CLOCK_POWER_BASE+INF_REG0_OFFSET)                       @0x7E00FA00
     ldr     r1, [r0]     /* r1 = physical address of s3c6400_cpu_resume function*/ @s3c6400_cpu_resume函数的物理地址保存在这里。
     mov     pc, r1          /*Jump to kernel (sleep-s3c6400.S)*/                            @跳到s3c6400_cpu_resume函数执行。s3c6400_cpu_resume找不到?
     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

#ifdef     CONFIG_SYNC_MODE              @同步模式选择,内核和总线不同步时,需用异步模式。
     ldr     r1, [r0, #OTHERS_OFFSET]
     mov     r2, #0x40
     orr     r1, r1, r2
     str     r1, [r0, #OTHERS_OFFSET]   @设置SYNCMUX的选择为1,就是DOUTAPLL,就是跟ARM内核用同一个锁相环。

     nop     @等待系统稳定。
     nop
     nop
     nop
     nop

     ldr     r2, =0x80  
     orr     r1, r1, r2
     str     r1, [r0, #OTHERS_OFFSET]  @设置同步模式位7为1,变成同步模式。

check_syncack:
     ldr     r1, [r0, #OTHERS_OFFSET]
     ldr     r2, =0xf00
     and     r1, r1, r2              
     cmp     r1, #0xf00                        @比较0xf00和(OTHERS的同步确认位11,10,9,8的值和0x0f00相与)的值,不等则循环等待。四位全1表示同步完成。
     bne     check_syncack
#else     /* ASYNC Mode */
     nop
     nop
     nop
     nop
     nop

     ldr     r1, [r0, #OTHERS_OFFSET]
     bic     r1, r1, #0xC0
     orr     r1, r1, #0x40
     str     r1, [r0, #OTHERS_OFFSET] @设置为异步模式,SYNCMUX的选择为1,就是DOUTAPLL,下面又设置成0,为什么要这样做呢?

wait_for_async:
     ldr     r1, [r0, #OTHERS_OFFSET]
     and     r1, r1, #0xf00
     cmp     r1, #0x0
     bne     wait_for_async                   @同步确认四位为全0,表示异步模式稳定下来。

     ldr     r1, [r0, #OTHERS_OFFSET]
     bic     r1, r1, #0x40
     str     r1, [r0, #OTHERS_OFFSET]  @设置SYNCMUX的选择为0,就是MOUTPLL。
#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]  @设置时钟输出稳定时间为最大
/* 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]
     bic     r1, r1, #0x70000
     orr     r1, r1, #0x30000
     str     r1, [r0, #CLK_DIV2_OFFSET]  @设置UART_RATIO为3,即四分频。
#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
     orr     r1, r1, r2
     str     r1, [r0, #CLK_DIV0_OFFSET]   @设置时钟分频,PCLK_RATIO,HCLK2_RATIO,HCLK_RATIO,MPLL_RATIO,APLL_RATIO。

     ldr     r1, =APLL_VAL
     str     r1, [r0, #APLL_CON_OFFSET]  @设置APLL_MDIV,APLL_PDIV,APLL_SDIV。
     ldr     r1, =MPLL_VAL
     str     r1, [r0, #MPLL_CON_OFFSET]  @设置MPLL_MDIV,MPLL_PDIV,MPLL_SDIV。

     ldr     r1, =0x80200203               /* FOUT of EPLL is 96MHz */
     str     r1, [r0, #EPLL_CON0_OFFSET]
     ldr     r1, =0x0
     str     r1, [r0, #EPLL_CON1_OFFSET]  @设置EPLL_MDIV,EPLL_PDIV,EPLL_SDIV,EPLL_KDIV。

     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]  @设置APLL,MPLL,EPLL时钟源为FOUT,UART为DOUT(同步模式设置为DOUT,异步模式设置为MOUT)。

     /* wait at least 200us to stablize all clock */
     mov     r1, #0x10000
1:     subs     r1, r1, #1
     bne     1b                               @等待所有时钟稳定。
#if 0
     mrc     p15, 0, r0, c1, c0, 0
     orr     r0, r0, #0xc0000000     /* clock setting in MMU */
     mcr     p15, 0, r0, c1, c0, 0
#endif

#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


/*
* 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
     ldr     r1, =0x22222222
     str        r1, [r0, #GPACON_OFFSET]  @设置GPA0-GPA7口为UART用
     ldr     r1, =0x2222
     str        r1, [r0, #GPBCON_OFFSET]  @设置GPB0-GPB3为UART用

     ldr     r0, =ELFIN_UART_CONSOLE_BASE          @0x7F005000
     mov     r1, #0x0
     str     r1, [r0, #UFCON_OFFSET]        @正常模式,无校验,1bit停止位,5bit数据位。
     str     r1, [r0, #UMCON_OFFSET]       @FIFO为63字节,没有流量控制,没有中断,RTS不使能。

     mov     r1, #0x3                     @was 0.
     str     r1, [r0, #ULCON_OFFSET]        @设置为8bit数据位

#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]  @设置接收超时中断不使能,使能接收错误中断,非环回模式,正常传输,中断方式发送,中断方式接收。电平方式的接收、发送中断,时钟为UCLK1或PCLK。

#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]  @设置波特率整数部分:(66000000/(115200X16))-1=34.81, 34的16进制为0x22。

#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]  @设置波特率小数部分:(UDIVSLOT中1的个数)/16=0.81,则UDIVSLOT中1的个数=12.92,取整为13个,而0x1fff正好有13个二进制1和3个二进制0。

     ldr     r1, =0x4f4f4f4f
     str     r1, [r0, #UTXH_OFFSET]          @'O',发送缓冲寄存器里面填入'O'字符。

     mov     pc, lr

/*
* Nand Interface Init for SMDK6400 */
nand_asm_init:
     ldr     r0, =ELFIN_NAND_BASE          @0x70200000
     ldr     r1, [r0, #NFCONF_OFFSET]
     orr     r1, r1, #0x70
     orr     r1, r1, #0x7700
     str     r1, [r0, #NFCONF_OFFSET]   @设置TACLS(信号清除),TWRPH0(读写阶段0),TWRPH1(读写阶段1)(NAND时序图上有)的持续时间。

     ldr     r1, [r0, #NFCONT_OFFSET]
     orr     r1, r1, #0x03
     str     r1, [r0, #NFCONT_OFFSET]   @为了老芯片兼容,s3c6410x低四位为保留。

     mov     pc, lr

#ifdef CONFIG_ENABLE_MMU

/*
* MMU Table for SMDK6400
*/

     /* form a first-level section entry */
.macro FL_SECTION_ENTRY base,ap,d,c,b                                                  @定义一个可以生成描述符的宏,按照section方式映射,每个section必须是1M,占20位地址,这里共256M物理内存,映射到整个地址空间4G,所以共有4096(0x1000)个描述符。虚拟地址的高12位(4096)作为描述符位置,低20位作为section里面的地址。从下面映射表看出来,虚拟地址0x00000000-0xa0000000跟对应的物理地址是一致的,虚拟地址0xa0000000-0xc0000000和0xc8000000-0xffffffff没有物理地址对应,虚拟地址0xc0000000-0xc8000000跟物理地址0x50000000-0x58000000相对应,所以TEXT_BASE基地址没有MMU时就是物理地址0x57e00000,有MMU时对应的虚拟地址就是0xc7e00000。
     .word (\base << 20) | (\ap << 10) | \
           (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)                        @描述符的最低两位00为无效,01为二级页表方式(由高地址12位的一级页表(TTB的高18位指定的虚拟基地址)位置取出对应二级页表(coarse page table)的基地址,由中间地址8位的二级页表取出对应4KB页表(small page)的基地址,最后由低12为地址的页表取出最终的内存值),10为一级页表方式(如果bit18为0,则为section,bit18为1,则为supersection),11保留。
.endm
.section .mmudata, "a"                                                                              @定义MMU数据段,在lds文件里面用到了,“a”表示这是一个需要鉴权的段
     .align 14
     // the following alignment creates the mmu table at address 0x4000.        @对齐到0x4000(16KB)的整数倍位置,因为TTB寄存器只保存MMU表的高18位地址(16KB对齐位置),所以必须14位对齐。
     .globl mmu_table                                                                                  @在start.S中使能MMU的时候用到了。
mmu_table:
     .set __base,0                                                                                       @前0xa00(2560)个描述符定义,ap为3表示读写允许。c,b比特为00表示共享,互斥读写。d为0表示这些描述符都属于domain0(domain用来做权限控制)。
     // 1:1 mapping for debugging
     .rept 0xA00
     FL_SECTION_ENTRY __base,3,0,0,0
     .set __base,__base+1
     .endr

     // access is not allowed.
     .rept 0xC00 - 0xA00                                                                             @从0xa00-0xc00共512个描述符,ap为0表示不允许访问。
     .word 0x00000000
     .endr

     // 128MB for SDRAM 0xC0000000 -> 0x50000000
     .set __base, 0x500                                                                              @从0xc00-0xc80共128个描述符(因为每个描述符代表1M,就是128MB)定义,cb比特为11表示内存输入输出都为回写模式。
     .rept 0xC80 - 0xC00
     FL_SECTION_ENTRY __base,3,0,1,1
     .set __base,__base+1
     .endr

     // access is not allowed.
     .rept 0x1000 - 0xc80                                                                           @从0xc80-0x1000共896个描述符,不允许访问。
     .word 0x00000000
     .endr

#endif
 

你可能感兴趣的:(lowlevel_init.S)