S5PV210(TQ210)U-BOOT第一阶段

时间:2022-07-05 09:23:54

地址:http://write.blog.csdn.net/postedit/8960858

#include <config.h>            //#include <configs/TQ210.h>
#include <version.h>
#include <asm/proc/domain.h>
#include <regs.h>
/* 内部96K SRAM,有一信息头,共16字节。前4字节为BL1大小(此处为.word 0x2000,即BL1大小为8K);4到8字节为保留位,
默认为0;8到12字节为checkSum,校验位,此处默认为0;最后4字节为保留字节,默认为0 */
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
 .word 0x2000
 .word 0x0
 .word 0x0
 .word 0x0
#endif

.globl _start
_start: b reset
reset:
 /*
  * set the cpu to SVC32 mode and IRQ & FIQ disable,设置CPU为管理模式,禁止中断及快速中断
  */
 @;mrs r0,cpsr
 @;bic r0,r0,#0x1f
 @;orr r0,r0,#0xd3
 @;msr cpsr,r0
 msr  cpsr_c, #0xd3  @ I & F disable, Mode: 0x13 - SVC

cpu_init_crit:
 bl disable_l2cache
  .global disable_l2cache
  disable_l2cache:
  mrc     p15, 0, r0, c1, c0, 1 @具体参照DDI0344K_cortex_a8_r3p2_trm.pdf文件,Auxiliary Control辅助控制
  bic     r0, r0, #(1<<1) @将bit1清零
  mcr     p15, 0, r0, c1, c0, 1 @L2 cache disabled
  mov pc, lr

 bl set_l2cache_auxctrl_cycle
  .global set_l2cache_auxctrl_cycle
  set_l2cache_auxctrl_cycle:
  mrc  p15, 1, r0, c9, c0, 2  @L2 Cache Auxiliary Control
  bic  r0, r0, #(0x1<<29)     @two cycles, default
  bic  r0, r0, #(0x1<<21)     @disables parity or ECC, default
  bic  r0, r0, #(0x7<<6)      @tag RAM latency =4 cycles
  bic  r0, r0, #(0x7<<0)      @Data RAM latency = 8 cycles
  mcr  p15, 1, r0, c9, c0, 2
  mov     pc,lr
 
 bl enable_l2cache
  .global enable_l2cache
  enable_l2cache:
  mrc     p15, 0, r0, c1, c0, 1
  orr     r0, r0, #(1<<1)
  mcr     p15, 0, r0, c1, c0, 1  @L2 cache enabled
  mov     pc, lr
 
 /*
 * Invalidate L1 I/D
 */
 mov r0, #0                  @ set up for MCR
 mcr p15, 0, r0, c8, c7, 0   @ Invalidate Inst-TLB and Data-TLB,无效指令TLB与数据TLB
 mcr p15, 0, r0, c7, c5, 0   @ Invalidate all instruction caches to PoU. Also flushes branch target cache
                                @无效所有指令缓存,刷新分支目标缓存
 /*
 * disable MMU stuff and caches
 */
 mrc p15, 0, r0, c1, c0, 0   @ Control
 bic r0, r0, #0x00002000     @ clear bits 13 (--V-),正常异常向量选择,复位值,向量基地址寄存器决定地址范围
 bic r0, r0, #0x00000007     @ clear bits 2:0 (-CAM),关闭数据缓存,禁止对其错误检查,关闭MMU
 orr r0, r0, #0x00000002     @ set bit 1 (--A-) Align,打开对其错误检查
 orr r0, r0, #0x00000800     @ set bit 12 (Z---) BTB,无效指令缓存
 mcr  p15, 0, r0, c1, c0, 0

 /* Read booting information */
 ldr r0, =PRO_ID_BASE        @0xE0000000
 ldr r1, [r0,#OMR_OFFSET]    @R0+0x04;引导模式寄存器地址,此条命令为读寄存器状态
 bic r2, r1, #0xffffffc1     @此条命令为读OM引脚配置状态,将OM[0]位清零,选择X-TAL
 
#ifdef CONFIG_TQ210_IIC_PM_CHIP
 /* PS_HOLD(GPJ2_5) set to output high,电源管理芯片PS_HOLD引脚*/
 ldr  r0, =ELFIN_GPIO_BASE@ 0xE02000000
 ldr  r1, =0x00100000
 str  r1, [r0, #GPJ2CON_OFFSET]@ 0xE02000000+0X280;将R1寄存器值存入GPJ2CON,设置为输出.
 
 ldr  r1, =0x0400
 str  r1, [r0, #GPJ2PUD_OFFSET]@ 0xE02000000+0X288;将R1寄存器值存入GPJ2PUD,设置为上拉

 ldr  r1, =0x20
 str  r1, [r0, #GPJ2DAT_OFFSET]@ 0xE02000000+0X284;将R1寄存器值存入GPJ2DAT,设置为1

#endif /* CONFIG_TQ210_IIC_PM_CHIP */

 /* NAND BOOT根据OM引脚配置状态来给R3寄存器赋予代表系统是从何种外部存储器启动的配置值,
 确定从哪个介质中copy U-Boot到RAM ,识别各种启动方式,并将识别到的启动识别码写入R3中 */
 cmp r2, #0x0  @ 512B 4-cycle
 moveq r3, #BOOT_NAND

 cmp r2, #0x2  @ 2KB 5-cycle
 moveq r3, #BOOT_NAND

 cmp r2, #0x4  @ 4KB 5-cycle 8-bit ECC
 moveq r3, #BOOT_NAND

 cmp r2, #0x6  @ 4KB 5-cycle 16-bit ECC
 moveq r3, #BOOT_NAND

 cmp r2, #0x8  @ OneNAND Mux
 moveq r3, #BOOT_ONENAND

 /* SD/MMC BOOT */
 cmp     r2, #0xc
 moveq   r3, #BOOT_MMCSD 

 /* NOR BOOT */
 cmp     r2, #0x14
 moveq   r3, #BOOT_NOR 

 /* Uart BOOTONG failed */
 cmp     r2, #(0x1<<4)
 moveq   r3, #BOOT_SEC_DEV
 
 ldr r0, =INF_REG_BASE
 str r3, [r0, #INF_REG3_OFFSET]@  将R3存入INFORM3(0xE010_F00C)中 

 /*
  * Go setup Memory and board specific bits prior to relocation..重定位前初始化存储器和板特殊位
  */

 ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
 sub sp, sp, #12 /* set stack */
 mov fp, #0

 bl lowlevel_init /* lowlevel_init.S go setup pll,mux,memory,完成关看门狗,电源模块初始化,时钟初始化,
      串口初始化,sdram初始化,NANDFLASH初始化 */
    .globl lowlevel_init
   lowlevel_init:
   push {lr}
   /* check reset status,检查复位状态 */
   ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)@将R0值设为0XE010A000,为复位状态寄存器,反映了各位复位条件的状态。
   ldr r1, [r0]
   bic r1, r1, #0xfff6ffff  @保留bit16及bit19位,其他位清零
   cmp r1, #0x10000         @ARM reset from DEEP-IDLE
   beq wakeup_reset_pre
   cmp r1, #0x80000      @Reset by SLEEP mode wake-up
   beq wakeup_reset_from_didle

   /* IO Retention release,不太明白 */
   ldr r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)@0xE010_E000,OTHERS
   ldr r1, [r0]
   ldr r2, =IO_RET_REL                              @((1 << 31) | (1 << 29) | (1 << 28))
   orr r1, r1, r2
   str r1, [r0]

   /* Disable Watchdog,管看门狗 */
   ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */
   mov r1, #0
   str r1, [r0]    @关闭看门狗,关闭看门狗中断,关闭看门狗复位

   /* SRAM(2MB) init for SMDKC110 */
   /* GPJ1 SROM_ADDR_16to21, 配置sram引脚,16位数据宽度,SROM_ADDR_16to22[ ]为复用引脚,22位地址宽度*/
   ldr r0, =ELFIN_GPIO_BASE
    
   ldr r1, [r0, #GPJ1CON_OFFSET]
   bic r1, r1, #0xFFFFFF
   ldr r2, =0x444444
   orr r1, r1, r2
   str r1, [r0, #GPJ1CON_OFFSET]    @引脚功能SROM_ADDR_16to22[ ]

   ldr r1, [r0, #GPJ1PUD_OFFSET]
   ldr r2, =0x3ff
   bic r1, r1, r2
   str r1, [r0, #GPJ1PUD_OFFSET]    @禁止上拉下拉模式

   /* GPJ4 SROM_ADDR_16to21 */
   ldr r1, [r0, #GPJ4CON_OFFSET]
   bic r1, r1, #(0xf<<16)
   ldr r2, =(0x4<<16)
   orr r1, r1, r2
   str r1, [r0, #GPJ4CON_OFFSET]    @引脚功能SROM_ADDR_16to22[ ]

   ldr r1, [r0, #GPJ4PUD_OFFSET]
   ldr r2, =(0x3<<8)
   bic r1, r1, r2
   str r1, [r0, #GPJ4PUD_OFFSET]    @禁止上拉下拉模式


   /* CS0 - 16bit sram, enable nBE, Byte base address */
   ldr r0, =ELFIN_SROM_BASE /* 0xE8000000 */
   mov r1, #0x1
   str r1, [r0]

   /* PS_HOLD pin(GPH0_0) set to high,不清楚到底什么作用*/
   ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)@0xE010_E81C,PS_HOLD_CONTROL寄存器
   ldr r1, [r0]
   orr r1, r1, #0x300
   orr r1, r1, #0x1 
   str r1, [r0]   @将寄存器bit8,bit9,bit1置1;

   /* when we already run in ram, we don't need to relocate U-Boot.
   * and actually, memory controller must be configured before U-Boot
   * is running in ram.
   */
   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   */
   
   /* init PMIC chip */
   #ifdef CONFIG_TQ210_IIC_PM_CHIP
   bl PMIC_InitIp    @电源管理单元初始化
   #endif

   /* init system clock,system_clock_init: Initialize core clock and bus clock. void system_clock_init(void)
   系统时钟初始化后频率为:ARMCLK=1G; SCLKA2M=200M; HCLK_MSYS=200M; PCLK_MSYS=100M;HCLK_DSYS=166M;
   PCLK_DSYS=83M;HCLK_PSYS=133M;PCLK_PSYS=66.5M
   */
   bl system_clock_init @1)选择时钟源;2)设置锁定时间;3)设置APLL,MPLL,VPLL频率;4)配置各模块分频;5)开ACF;6)耗时等待稳定 
    system_clock_init:
    
     ldr r0, =ELFIN_CLOCK_POWER_BASE @0xe0100000

     /* Set Mux to FIN */
     ldr r1, =0x0
     str r1, [r0, #CLK_SRC0_OFFSET]   @CLK_SRC0,时钟源选择

     ldr r1, =APLL_LOCKTIME_VAL
     str r1, [r0, #APLL_LOCK_OFFSET]  @将APLL_LOCK,APLL锁定时间设置为0x2cf

     /* Disable PLL */
     ldr r1, =0x0
     str r1, [r0, #APLL_CON0_OFFSET]  @APLL_CON0 设置APLL使能锁存,锁定时间使能,APLL频率设置,此处将APLL禁止
     ldr r1, =0x0
     str r1, [r0, #MPLL_CON_OFFSET]   @MPLL_CON0 设置APLL使能锁存,锁定时间使能,APLL频率设置,此处将MPLL禁止

     ldr    r1, [r0, #CLK_DIV0_OFFSET]
     ldr r2, =CLK_DIV0_MASK
     bic r1, r1, r2

     ldr r2, =CLK_DIV0_VAL
     orr r1, r1, r2
     str r1, [r0, #CLK_DIV0_OFFSET]  @时钟分频控制寄存器CLK _DIV0,(0<<APLL_RATIO)|(4<<A2M_RATIO)|
             @(4<<HCLK_MSYS_RATIO)|(1<<PCLK_MSYS_RATIO)|(3<<HCLK_DSYS_RATIO)|
             @(1<<PCLK_DSYS_RATIO)|(4<<HCLK_PSYS_RATIO)|(1<<PCLK_PSYS_RATIO))

     ldr r1, =APLL_VAL
     str r1, [r0, #APLL_CON0_OFFSET]  @APLL_CON0 ,使能APLL,设置APLL频率,即MDIV=7D;PDIV=3;SDIV=1;APLL频率为1G

     ldr r1, =MPLL_VAL
     str r1, [r0, #MPLL_CON_OFFSET]   @MPLL_CON0 ,使能MPLL,设置MPLL频率,即MDIV=29B;PDIV=C;SDIV=1;MPLL频率为667M

     ldr r1, =VPLL_VAL
     str r1, [r0, #VPLL_CON_OFFSET]   @VPLL_CON0 ,使能VPLL,设置VPLL频率,即MDIV=6C;PDIV=6;SDIV=3;MPLL频率为108M
    #if defined(CONFIG_EVT1)
     ldr r1, =AFC_ON
     str r1, [r0, #APLL_CON1_OFFSET]  @APLL_CON1 ,设置为0,开AFC,AFC是干什么用的?
    #endif
     mov r1, #0x10000                  /*耗时等待稳定*/
    1: subs r1, r1, #1
     bne 1b
     
     ldr r1, [r0, #CLK_SRC0_OFFSET]
     ldr r2, =0x10001111
     orr r1, r1, r2
     str r1, [r0, #CLK_SRC0_OFFSET]  @设置MUXVPLL,MUXEPLL,MUXMPLL,MUXAPLL为FOUTxPLL
     
    #if defined(CONFIG_MCP_SINGLE)

     /* CLK_DIV6 */
     ldr r1, [r0, #CLK_DIV6_OFFSET]  @时钟分频寄存器CLK _DIV6,SCLK_ONENAND = MOUTFLASH / (ONENAND_RATIO + 1)
     bic r1, r1, #(0x7<<12) @; ONENAND_RATIO: 0
     str r1, [r0, #CLK_DIV6_OFFSET]

    #endif 

     mov pc, lr
   bl mem_ctrl_asm_init @cpu_init.s SDRAM初始化
  1:
   /* for UART */
   bl uart_asm_init
    uart_asm_init:
     /* set GPIO(GPA) to enable UART */
     @ GPIO setting for UART
     ldr r0, =ELFIN_GPIO_BASE
     ldr r1, =0x22222222
     str    r1, [r0, #GPA0CON_OFFSET]
     ldr     r1, =0x2222
     str     r1, [r0, #GPA1CON_OFFSET]

     ldr r0, =ELFIN_UART_CONSOLE_BASE  @0xEC000000
     mov r1, #0x0
     str r1, [r0, #UFCON_OFFSET]    @USART FIFO控制寄存器,禁止FIFO
     str r1, [r0, #UMCON_OFFSET]    @USART MODEM控制寄存器,禁止MODEM及AFC

     mov r1, #0x3
     str r1, [r0, #ULCON_OFFSET]    @ULCON0,设置为普通模式,无奇偶校验位,1位停止位,8位数据位

     ldr r1, =0x3c5
     str r1, [r0, #UCON_OFFSET]     @时钟源为PCLK,TX,RX中断类型为电平触发,接收错误状态中断使能,
               @接收超时使能,RX与TX模式为中断请求或轮询

     ldr r1, =UART_UBRDIV_VAL
     str r1, [r0, #UBRDIV_OFFSET]    @设置模特率,设置波特率为115200,则UBRDIV=(66.7x10^5/115200/16)-1取整,
             @此处求出的值为35,不太清楚为什么设置为34?

     ldr r1, =UART_UDIVSLOT_VAL
     str r1, [r0, #UDIVSLOT_OFFSET]   @UDIVSLOT=((66.7x10^5/115200/16)-1取余),此处求出为3,不明白为什么设置为0XDDDD?

     ldr r1, =0x4f4f4f4f
     str r1, [r0, #UTXH_OFFSET]  @'O',@发送“0x4f4f4f4f”

     mov pc, lr
   
   bl tzpc_init         @TrustZone Protection Controller,安全模式,取消存储保护区域,无安全区域
   bl nand_asm_init     @nand简单的初始化
   
   /* check reset status  */
 
   ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
   ldr r1, [r0]
   bic r1, r1, #0xfffeffff
   cmp r1, #0x10000
   beq wakeup_reset_pre

   /* ABB disable */
   ldr r0, =0xE010C300
   orr r1, r1, #(0x1<<23)
   str r1, [r0]

   /* Print 'K' */
   ldr r0, =ELFIN_UART_CONSOLE_BASE
   ldr r1, =0x4b4b4b4b
   str r1, [r0, #UTXH_OFFSET]

   pop {pc}
 
 /*不清楚作用,别的文档标注:PS_HOLD输出高电平,PS_HOLD使能。PMIC相关*/
 ldr r0, =0xE010E81C  /* PS_HOLD_CONTROL register */
 ldr r1, =0x00005301  /* PS_HOLD output high */
 str r1, [r0]

 /* get ready to call C functions */
 ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer,0x23E0_0000 */
 sub sp, sp, #12
 mov fp, #0   /* no previous frame, so fp=0 */

 /* when we already run in ram, we don't need to relocate U-Boot.
  * and actually, memory controller must be configured before U-Boot
  * is running in ram.
  */
 ldr r0, =0xff000fff
 bic r1, pc, r0  /* r0 <- current base addr of code */
 ldr r2, _TEXT_BASE  /* _TEXT_BASE:0xC3E0_0000,r1 <- original base addr in ram */
 bic r2, r2, r0  /* r0 <- current base addr of code */
 cmp     r1, r2                  /* compare r0, r1                  */
 beq     after_copy  /* r0 == r1 then skip flash copy   */

#if defined(CONFIG_EVT1)
 /* If BL1 was copied from SD/MMC CH2 */
 ldr r0, =0xD0037488    @V210_SDMMC_BASE,Current boot channel
 ldr r1, [r0]
 ldr r2, =0xEB200000    @SDMA System Address
 cmp r1, r2
 beq     mmcsd_boot
#endif
/*判断启动类型,根据启动方式不同,跳转不同执行*/
 ldr  r0, =INF_REG_BASE
 ldr  r1, [r0, #INF_REG3_OFFSET]
 cmp  r1, #BOOT_NAND  /* 0x0 => boot device is nand */
 beq  nand_boot
 cmp  r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
 beq  onenand_boot
 cmp  r1, #BOOT_MMCSD
 beq  mmcsd_boot
 cmp  r1, #BOOT_NOR
 beq  nor_boot
 cmp  r1, #BOOT_SEC_DEV
 beq  mmcsd_boot   

 nand_boot:      @copy_from_nand
 mov  r0, #0x1000
 bl  copy_from_nand
 b  after_copy

 onenand_boot:    @onenand_bl2_copy
 bl  onenand_bl2_copy
 b  after_copy

 mmcsd_boot:     @movi_bl2_copy
#if DELETE
 ldr  sp, _TEXT_PHY_BASE     
 sub  sp, sp, #12
 mov  fp, #0
#endif
 bl  movi_bl2_copy
 b  after_copy

 nor_boot:    @read_hword
 bl  read_hword
 b  after_copy
 
after_copy:

#if defined(CONFIG_ENABLE_MMU)
enable_mmu:
 /* enable domain access */
 ldr r5, =0x0000ffff
 mcr p15, 0, r5, c3, c0, 0  @load domain access register,定义使能域的访问权限,Manager

 /* Set the TTB register */
 ldr r0, _mmu_table_base    @映射页表地址
  /*定义一个名为 FL_SECTION_ENTRY 的宏,参数为 base,ap,d,c,b,内容为
  (\base << 20) | (\ap << 10) | \ (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1),
  根据控制参数建立一个字大小的描述符,以.endm结束*/
  .macro FL_SECTION_ENTRY base,ap,d,c,b
   .word (\base << 20) | (\ap << 10) | \
      (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
  .endm
  /*将这一部分代码都编译进以.mmudata命名的段中(定义MMU数据段,在lds文件里面用到了,定义了
  mmu_table放置的位置,“a”表示这是一个需要鉴权的段),权限为a,并确保14喂对齐*/ 
  .section .mmudata, "a"
  .align 14
  
 .globl mmu_table
  mmu_table:
  .set __base,0    @__base设置为0,物理地址高12位
  // Access for iRAM
  .rept 0x100      @循环0x100次
  FL_SECTION_ENTRY __base,3,0,0,0    @页表描述符
  .set __base,__base+1
  .endr

  // Not Allowed
  .rept 0x200 - 0x100
  .word 0x00000000
  .endr

  .set __base,0x200
  // should be accessed
  .rept 0x600 - 0x200
  FL_SECTION_ENTRY __base,3,0,1,1
  .set __base,__base+1
  .endr
  
  .rept 0x800 - 0x600
  .word 0x00000000
  .endr


  .set __base,0x800
  // should be accessed
  .rept 0xb00 - 0x800
  FL_SECTION_ENTRY __base,3,0,0,0
  .set __base,__base+1
  .endr

  .set __base,0xB00
  .rept 0xc00 - 0xb00
  FL_SECTION_ENTRY __base,3,0,0,0
  .set __base,__base+1
  .endr
  
  .set __base,0x200
  // 256MB for SDRAM with cacheable
  .rept 0xD00 - 0xC00
  FL_SECTION_ENTRY __base,3,0,1,1
  .set __base,__base+1
  .endr

  .set __base,0xD00
  // 1:1 mapping for debugging with non-cacheable
  .rept 0x1000 - 0xD00
  FL_SECTION_ENTRY __base,3,0,0,0
  .set __base,__base+1
  .endr 
 /*不太明白为什么这么求的*/
 ldr r1, =CFG_PHY_UBOOT_BASE    @0xc3e00000
 ldr r2, =0xfff00000 
 bic r0, r0, r2   
 orr r1, r0, r1
 mcr p15, 0, r1, c2, c0, 0

 /* Enable the MMU,开MMU*/
mmu_on:
 mrc p15, 0, r0, c1, c0, 0
 orr r0, r0, #1
 mcr p15, 0, r0, c1, c0, 0
 nop
 nop
 nop
 nop
#endif

skip_hw_init:
 /* Set up the stack          */
stack_setup:  @建立栈,栈的设置灵活性很大,只要将SP指向一段没有使用的内存即可
#if defined(CONFIG_MEMORY_UPPER_CODE)
 ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#endif

clear_bss:    @清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处继续运行。

_start_armboot:
 .word start_armboot

讨论加QQ:1735613836