zoukankan      html  css  js  c++  java
  • S3C6410之uboot回炉再造(3)lowlevle_init.S

      这一篇粗略讲一下lowlevel_init.S内部的模块。

      1、_TEXT_BASE

      1 #include <config.h>
      2 #include <version.h>
      3 
      4 #include <asm/arch/s3c6400.h>
      5 
      6 #ifdef CONFIG_SERIAL1
      7 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART0_OFFSET)
      8 #elif defined(CONFIG_SERIAL2)
      9 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART1_OFFSET)
     10 #else
     11 #define ELFIN_UART_CONSOLE_BASE (ELFIN_UART_BASE + ELFIN_UART2_OFFSET)
     12 #endif
     13 
     14 _TEXT_BASE:
     15     .word    TEXT_BASE
     16 

      来看一下最后两句的的反汇编

    00000000 <_TEXT_BASE>:      
       0:    57e00000     .word    0x57e00000

      看到这里的 0x57e00000 有种似曾相识的感觉,但是这段代码的特殊位置决定了这个地址是无效的。

      回想一下上一篇的地址无关性,就能明白了。

      2、点亮LED

     17     .globl lowlevel_init
     18 lowlevel_init:
     19     mov    r12, lr
     20 
     21     /* LED on only #8 */
     22     ldr    r0, =ELFIN_GPIO_BASE
     23     ldr    r1, =0x55540000
     24     str    r1, [r0, #GPNCON_OFFSET]
     25 
     26     ldr    r1, =0x55555555
     27     str    r1, [r0, #GPNPUD_OFFSET]
     28 
     29     ldr    r1, =0xf000
     30     str    r1, [r0, #GPNDAT_OFFSET]
     31 

      3、关闭看门狗

     32     /* Disable Watchdog */
     33     ldr    r0, =0x7e000000        @0x7e004000
     34     orr    r0, r0, #0x4000
     35     mov    r1, #0
     36     str    r1, [r0]
     37 

      从这里看到,在 start.S 中取出的关闭看门狗原来是移动到了这里执行。

      这样做的好处是,让每个单独部分的代码信息显得更紧凑一些。

      4、读一次外部中断,然后清除中断信号 

     38     /* External interrupt pending clear */
     39     ldr    r0, =(ELFIN_GPIO_BASE+EINTPEND_OFFSET)    /*EINTPEND*/
     40     ldr    r1, [r0]
     41     str    r1, [r0]
     42 
     43     ldr    r0, =ELFIN_VIC0_BASE_ADDR    @0x71200000
     44     ldr    r1, =ELFIN_VIC1_BASE_ADDR    @0x71300000
     45 

      5、将所有中断设置为IRQ

     51     /* Set all interrupts as IRQ */
     52     mov    r3, #0x0
     53     str    r3, [r0, #oINTMOD]
     54     str    r3, [r1, #oINTMOD]
     55 

      6、等待中断清除

     56     /* Pending Interrupt Clear */
     57     mov    r3, #0x0
     58     str    r3, [r0, #oVECTADDR]
     59     str    r3, [r1, #oVECTADDR]
     60 

      这里的作用应该等效于禁用中断。

      7、初始化系统时钟

     61     /* init system clock */
     62     bl system_clock_init
     63   //具体实现代码在118行

      8、初始化UART串口和NAND flash

     64 #ifndef CONFIG_NAND_SPL
     65     /* for UART */
     66     bl uart_asm_init
     67 #endif
     68 
     69 #ifdef CONFIG_BOOT_NAND
     70     /* simple init for NAND */
     71     bl nand_asm_init
     72 #endif
     73 

      9、内存控制的初始化

     74     /* Memory subsystem address 0x7e00f120 */
     75     ldr    r0, =ELFIN_MEM_SYS_CFG
     76 
     77     /* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */
     78     mov    r1, #S3C64XX_MEM_SYS_CFG_NAND
     79     str    r1, [r0]
     80 
     81     bl    mem_ctrl_asm_init
     82 

      10、测试将要使用的功能

     83 /* Wakeup support. Don't know if it's going to be used, untested. */
     84     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + RST_STAT_OFFSET)
     85     ldr    r1, [r0]
     86     bic    r1, r1, #0xfffffff7
     87     cmp    r1, #0x8
     88     beq    wakeup_reset
     89 
     90 1:
     91     mov    lr, r12
     92     mov    pc, lr
     93 
     94 wakeup_reset:
     95 
     96     /* Clear wakeup status register */
     97     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + WAKEUP_STAT_OFFSET)
     98     ldr    r1, [r0]
     99     str    r1, [r0]
    100 
    101     /* LED test */
    102     ldr    r0, =ELFIN_GPIO_BASE
    103     ldr    r1, =0x3000
    104     str    r1, [r0, #GPNDAT_OFFSET]
    105 
    106     /* Load return address and jump to kernel */
    107     ldr    r0, =(ELFIN_CLOCK_POWER_BASE + INF_REG0_OFFSET)
    108     /* r1 = physical address of s3c6400_cpu_resume function */
    109     ldr    r1, [r0]
    110     /* Jump to kernel (sleep-s3c6400.S) */
    111     mov    pc, r1
    112     nop
    113     nop

      11、时钟初始化的执行代码

    114 /*
    115  * system_clock_init: Initialize core clock and bus clock.
    116  * void system_clock_init(void)
    117  */
    118 system_clock_init:
    119     ldr    r0, =ELFIN_CLOCK_POWER_BASE    /* 0x7e00f000 */
    120 
    121 #ifdef CONFIG_SYNC_MODE
    122     ldr    r1, [r0, #OTHERS_OFFSET]
    123     mov    r2, #0x40
    124     orr    r1, r1, r2
    125     str    r1, [r0, #OTHERS_OFFSET]
    126 
    127     nop
    128     nop
    129     nop
    130     nop
    131     nop
    132 
    133     ldr    r2, =0x80
    134     orr    r1, r1, r2
    135     str    r1, [r0, #OTHERS_OFFSET]
    136 
    137 check_syncack:
    138     ldr    r1, [r0, #OTHERS_OFFSET]
    139     ldr    r2, =0xf00
    140     and    r1, r1, r2
    141     cmp    r1, #0xf00
    142     bne    check_syncack
    143 #else    /* ASYNC Mode */
    144     nop
    145     nop
    146     nop
    147     nop
    148     nop
    149 
    150     /*
    151      * This was unconditional in original Samsung sources, but it doesn't
    152      * seem to make much sense on S3C6400.
    153      */
    154 #ifndef CONFIG_S3C6400
    155     ldr    r1, [r0, #OTHERS_OFFSET]
    156     bic    r1, r1, #0xC0
    157     orr    r1, r1, #0x40
    158     str    r1, [r0, #OTHERS_OFFSET]
    159 
    160 wait_for_async:
    161     ldr    r1, [r0, #OTHERS_OFFSET]
    162     and    r1, r1, #0xf00
    163     cmp    r1, #0x0
    164     bne    wait_for_async
    165 #endif
    166 
    167     ldr    r1, [r0, #OTHERS_OFFSET]
    168     bic    r1, r1, #0x40
    169     str    r1, [r0, #OTHERS_OFFSET]
    170 #endif
    171 
    172     mov    r1, #0xff00
    173     orr    r1, r1, #0xff
    174     str    r1, [r0, #APLL_LOCK_OFFSET]
    175     str    r1, [r0, #MPLL_LOCK_OFFSET]
    176 
    177     /* Set Clock Divider */
    178     ldr    r1, [r0, #CLK_DIV0_OFFSET]
    179     bic    r1, r1, #0x30000
    180     bic    r1, r1, #0xff00
    181     bic    r1, r1, #0xff
    182     ldr    r2, =CLK_DIV_VAL
    183     orr    r1, r1, r2
    184     str    r1, [r0, #CLK_DIV0_OFFSET]
    185 
    186     ldr    r1, =APLL_VAL
    187     str    r1, [r0, #APLL_CON_OFFSET]
    188     ldr    r1, =MPLL_VAL
    189     str    r1, [r0, #MPLL_CON_OFFSET]
    190 
    191     /* FOUT of EPLL is 96MHz */
    192     ldr    r1, =0x200203
    193     str    r1, [r0, #EPLL_CON0_OFFSET]
    194     ldr    r1, =0x0
    195     str    r1, [r0, #EPLL_CON1_OFFSET]
    196 
    197     /* APLL, MPLL, EPLL select to Fout */
    198     ldr    r1, [r0, #CLK_SRC_OFFSET]
    199     orr    r1, r1, #0x7
    200     str    r1, [r0, #CLK_SRC_OFFSET]
    201 
    202     /* wait at least 200us to stablize all clock */
    203     mov    r1, #0x10000
    204 1:    subs    r1, r1, #1
    205     bne    1b
    206 
    207     /* Synchronization for VIC port */
    208 #if defined(CONFIG_SYNC_MODE)
    209     ldr    r1, [r0, #OTHERS_OFFSET]
    210     orr    r1, r1, #0x20
    211     str    r1, [r0, #OTHERS_OFFSET]
    212 #elif !defined(CONFIG_S3C6400)
    213     /* According to 661558um_S3C6400X_rev10.pdf 0x20 is reserved */
    214     ldr    r1, [r0, #OTHERS_OFFSET]
    215     bic    r1, r1, #0x20
    216     str    r1, [r0, #OTHERS_OFFSET]
    217 #endif
    218     mov    pc, lr
    219 
    220 

      12、串口初始化的执行代码

    221 #ifndef CONFIG_NAND_SPL
    222 /*
    223  * uart_asm_init: Initialize UART's pins
    224  */
    225 uart_asm_init:
    226     /* set GPIO to enable UART */
    227     ldr    r0, =ELFIN_GPIO_BASE
    228     ldr    r1, =0x220022
    229     str    r1, [r0, #GPACON_OFFSET]
    230     mov    pc, lr
    231 #endif
    232 

      13、NAND flash的初始化

      后面有详细分析,这里不重复粘贴了。

      14、MMU的初始化

      同上。

      这篇比较偷懒,但是想把主要精力放在start.S的分析上。

      其实这也是分析方法的一种,看代码的时候先了解模块的代码区,若想深入了解某个模块的实现,则再深入到每一行代码中理解。

     

      总结一下 lowlevl_init 的总体实现内容:

      1、点亮LED;

      2、关闭看门狗;

      3、禁用中断;

      4、初始化时钟;

      5、初始化串口;

      6、初始化NAND FLASH;

      7、初始化MMU(根据宏声明而定)。

      这里补上两段代码的分析:

      NAND flash的初始化 与 MMU 的初始化,因为在 kernel 的启动过程中还会有类似的代码段,现在分析了,到后面分析 kernel 初始化的时候可以做一个对比。

      1、首先是 NAND FLASH 的初始化

    233 #ifdef CONFIG_BOOT_NAND
    234 /*
    235  * NAND Interface init for SMDK6400
    236  */
    237 nand_asm_init:
    238     ldr    r0, =ELFIN_NAND_BASE
    239     ldr    r1, [r0, #NFCONF_OFFSET]
    240     orr    r1, r1, #0x70
    241     orr    r1, r1, #0x7700
    242     str    r1, [r0, #NFCONF_OFFSET]
    243 
    244     ldr    r1, [r0, #NFCONT_OFFSET]
    245     orr    r1, r1, #0x07
    246     str    r1, [r0, #NFCONT_OFFSET]
    247 
    248     mov    pc, lr
    249 #endif
    250 

      1)确认成立条件 CONFIG_BOOT_NAND

      这个条件声明在/include/configs/smdk6400.h中,所以下面的执行代码是有效的。

      接着深入分析

    238     ldr    r0, =ELFIN_NAND_BASE
    //在/include/asm-arm/arch-s3c64xx/s3c6400.h中声明了
    #define  ELFIN_NAND_BASE  0x70200000
    //这里采用的是伪汇编指令,即将其值放入 r0 中

      2)进入s3c6410 UM中检索 ELFIN_NAND_BASE 相关地址信息找到table 2-3 中有相应的地址信息。

    Address              Description
    0x7020_0000 ~ 0x702F_FFFF  NFCON SFR

      接着在UM中检索0x7020_0000 可以跳转到8.11节。

      看了之后发现,这一小篇内容描述的是 NAND FALSH 控制寄存器地图。

      其中 base 就是我们的 0x7020_0000。

      从UM中,我们先看到 0x7020_0000 代表的意思:

      NFCONF (Nand Flash CONFiguration)寄存器功能为 Nand Flash Configuration register。

      复位值为 0xX000_100X

      相对应的位的信息为

    //不同关系的作用位用 ',' 隔开,总体以 4 bit 来分隔, 含同一组作用位的用 '|' 隔开。
    [31, 30, 29 28 | 27 26, 25, 24 | 23, 22 21 20 | 19 18 17 16 ]
    [15, 14 13 12, | 11, 10 9 8, | 7, 6 5 4, | 3, 2, 1, 0]
    //按作用位组来介绍
    //1、 X, 0, 0 0 ---> X
    31 - Reserved, 30 - [0:系统时钟 > 66MHZ; 1:系统时钟 < 66MHZ], 29 28 - Reserved
    //2、 0 0, 0, 0 ---> 0
    27 26 - Reserved, 25 - ECC校验长度 [0:512 byte; 1:24 byte ], 24 - 联合23
    //3、 0, 0 0 0 ---> 0
    24 23 - ECC类型 [00: 1 bit; 10: 4 bit; 01: 8 bit /*注意4 bit 和 8 bit 的类型码*/]
    22 : 15 - Reserved
    //4、 0 0 0 0 ---> 0
    //5、 0, 0 0 1 ---> 1
    14 13 12 - CLE & ALE 持续时间设定 
    //6、 0, 0 0 0 ---> 0
    11 - Reserved, 10 9 8 - TWRPH0 持续时间设定
    //7、 0, 0 0 0 ---> 0
    7 - Reserved, 6 5 4 - TWRPH1 持续时间设定
    //8、 X, 0, X, 0 ---> X
    4 2 1 - Reserved, 3 - Reserved 但必须为1

      3)接着看下面的指令

    239     ldr    r1, [r0, #NFCONF_OFFSET] //先找到 NFCONF_OFFSET 的定义
    //目录为 /include/asm-arm/arch-s3c64xx/s3c6400.h, 则此处 r1 = 0xX000_100X
    //在UM中找到相应项目
    240     orr    r1, r1, #0x70
    //                   r1 = 0xX020_007X
    241     orr    r1, r1, #0x7700
    //                   r1 = 0xX020_777X
    242     str    r1, [r0, #NFCONF_OFFSET]
    //送回NFCONF寄存器
    //对应上面的表可以知道,改变的为 CLE & ALE, TWRPH0/1 的持续时间而已(时间增加了)
    243 

      4)然后是剩下的指令

    244     ldr    r1, [r0, #NFCONT_OFFSET] //这里是NFCONT_OFFSET了,注意区分
    245     orr    r1, r1, #0x07        // r1 = 0x0001_00C6 | 0x07 
                            // r1 = 0x0001_00C7
    //NFCONT 寄存器的最后一位功能为 [0:禁用NAND Flash 1:使用NADN flash]
    //所以这里的功能就很清晰了,就是初始化 NAND flash
    246 str r1, [r0, #NFCONT_OFFSET] //回送 247 248 mov pc, lr //程序返回 249 #endif 250

      2、MMU的初始化代码

    251 #ifdef CONFIG_ENABLE_MMU
    252 /*
    253  * MMU Table for SMDK6400
    254  */
    255 
    256     /* form a first-level section entry */
    257 .macro FL_SECTION_ENTRY base,ap,d,c,b
    258     .word (\base << 20) | (\ap << 10) | \
    259           (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
    260 .endm
    261 
    262 .section .mmudata, "a"
    263     .align 14
    264     /* the following alignment creates the mmu table at address 0x4000. */
    265     .globl mmu_table
    266 mmu_table:
    267     .set __base, 0
    268     /* 1:1 mapping for debugging */
    269     .rept 0xA00
    270     FL_SECTION_ENTRY __base, 3, 0, 0, 0
    271     .set __base, __base + 1
    272     .endr
    273 
    274     /* access is not allowed. */
    275     .rept 0xC00 - 0xA00
    276     .word 0x00000000
    277     .endr
    278 
    279     /* 128MB for SDRAM 0xC0000000 -> 0x50000000 */
    280     .set __base, 0x500
    281     .rept 0xC80 - 0xC00
    282     FL_SECTION_ENTRY __base, 3, 0, 1, 1
    283     .set __base, __base + 1
    284     .endr
    285 
    286     /* access is not allowed. */
    287     .rept 0x1000 - 0xc80
    288     .word 0x00000000
    289     .endr
    290 #endif

      1)确认成立条件

    #if !defined(CONFIG_NAND_SPL) && (TEXT_BASE >= 0xc0000000)
    #define CONFIG_ENABLE_MMU
    #endif

      此处的TEXT_BASE是 0x0000_0000显然是不成立的。

      但是我们还是继续往下分析。

      2).macro

    252 /*
    253  * MMU Table for SMDK6400
    254  */
    255 
    256     /* form a first-level section entry */
    257 .macro FL_SECTION_ENTRY base, ap, d, c, b
    258     .word (\base << 20) | (\ap << 10) | \
    259           (\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
    260 .endm    //结束宏定义
    261 

      先来看看伪指令的格式

    MACRO{$label}    macroname    {$parameter1} {$parameter2} ...
    //label宏展开时可以替换的符号
    //macroname 宏名
    //parameter n 宏指令的参数

      这里宏的名字为 FL_SECTION_ENTRY,其实可以看成C语言的 #define

      3)制作映射表

    262 .section .mmudata, "a"
    263     .align 14    //按照 2^14 = 16384 对齐,即 0x4000
    264     /* the following alignment creates the mmu table at address 0x4000. */
    265     .globl mmu_table
    266 mmu_table:
    267     .set __base, 0  //赋值为 0
    268     /* 1:1 mapping for debugging */
    269     .rept 0xA00    //重复次数 0xA00 = 2560
    270     FL_SECTION_ENTRY __base, 3, 0, 0, 0
        //代入公式得 FL_SECTION_ENTRY(起始) = (0b11 << 10) | (0b1 << 4) | (0b1 << 1)
                            =  0x0000_4000(对齐后)
    271     .set __base, __base + 1
        //每一次 __base + 1 之后, FL_SECTION_ENTRY + 0x0010_0000 ,即 1MB 
        //所以此次制表范围是 2560MB
        //从 0x0000_4000 ~ 0x9FF0_4000
    272     .endr
    273 

      不可访问的区域,全部置为 0

    274     /* access is not allowed. */
    275     .rept 0xC00 - 0xA00  //重复次数 0x200 = 512
    276     .word 0x00000000    //从0x9FF0_4000 ~ 0xBFF0_4000
    277     .endr
    278 

      映射SDRAM

    279     /* 128MB for SDRAM 0xC0000000 -> 0x50000000 */
        //这里为128MB,在实际使用中应该为256MB
    280     .set __base, 0x500
    281     .rept 0xC80 - 0xC00  //重复次数 0x80 = 128
        //为256MB时应更改为 0xD00 - 0xC00 
    282     FL_SECTION_ENTRY __base, 3, 0, 1, 1
        //代入公式得  FL_SECTION_ENTRY(起始) = 0xBFF0_4000
        //此次制表范围 128MB
        //从 0xBFF0_4000 ~ 0xC7F0_4000
    283     .set __base, __base + 1
    284     .endr
    285 

      不可访问区域,置为0

    286     /* access is not allowed. */
    287     .rept 0x1000 - 0xc80  //重复次数 0x380 = 896
    288     .word 0x00000000    //从0xC7F04000 ~ 0xFFF0_4000
    289 .endr   
    290#endif

      分析方法就是这样,虽然计算的地址可能有错,但是大概意思已经讲清楚了。

      今天就写到这里了。

      

      

      

  • 相关阅读:
    CodeForce VKcup A
    CNN卷积神经网络
    神经网络
    我的机器学习之路
    [OPENCV] 第一个程序 识别颜色
    Android 登录界面与首页的设计
    go web的基本原理
    Go语言标准库之http/template
    吞吐量(TPS)、QPS、并发数、响应时间(RT)概念
    数据库恢复技术
  • 原文地址:https://www.cnblogs.com/plinx/p/3045777.html
Copyright © 2011-2022 走看看