虫虫首页| 资源下载| 资源专辑| 精品软件
登录| 注册

您现在的位置是:首页 > 技术阅读 >  u-boot2020.04移植(3、lowlevel_init.S)

u-boot2020.04移植(3、lowlevel_init.S)

时间:2024-05-31

点击下方阅读原文可访问文中超链接

现在开始就进入板级相关的初始化了,跳转到board/samsung/goni/lowlevel_init.S文件,注意这里lowlevel_init搜索出来在arch/arm/cpu/armv7/lowlevel_init.S文件里面也有,而且这个文件还被编译了,但仔细看一下就会发现,这个文件里面的lowlevel_init被声明成了弱属性,所以真正调用的是board/samsung/goni/lowlevel_init.S文件。

ENTRY(cpu_init_crit)
    /*
     * Jump to board specific initialization...
     * The Mask ROM will have already initialized
     * basic memory. Go here to bump up clock rate and handle
     * wake up conditions.
     */

    b   lowlevel_init       @ go setup pll,mux,memory
ENDPROC(cpu_init_crit)

其实在lowlevel_init里面也不需要干多少事,但DDR是必须要初始化好的,我们都知道s5pv210的整个IRAM也就96K,而u-boot的大小远远超过了96K,所以比较好的办法就是在BL1阶段就初始化好DDR,并且将u-boot搬运到DDR运行,但是BL1的大小最大只有16K,所以得尽早将DDR初始化好,然后到DDR中运行,这一步本来也是必须的,因为现在u-boot运行在IRAM内,其运行地址与链接地址是不一样的,只能运行位置无关代码。

下面看下lowlevel_init得源码:

board/samsung/goni/lowlevel_init.S

.globl lowlevel_init
lowlevel_init:
    /*这里将lr得值保存到r11中,以便之后返回,因为后面也有跳转得过程,防止lr跳转后丢失*/
    mov r11, lr

    /* r5 has always zero */
    mov r5, #0

    ldr r7, =S5PC100_GPIO_BASE
    ldr r8, =S5PC100_GPIO_BASE
    /* Read CPU ID */
    ldr r2, =S5PC110_PRO_ID
    ldr r0, [r2]
    mov r1, #0x00010000
    and r0, r0, r1
    /*根据手册可以得出,这里是不等的*/
    cmp r0, r5
    beq 100f
    /*这里将r8重新赋值成了C110的GPIO基地址*/
    ldr r8, =S5PC110_GPIO_BASE
100:
    /* Turn on KEY_LED_ON [GPJ4(1)] XMSMWEN */
    /*比较结果不相等,这里比较后,Z位的值是一直保持的*/
    cmp r7, r8
    /*不相等,不执行*/
    beq skip_check_didle            @ Support C110 only

    /*读取复位状态*/
    ldr r0, =S5PC110_RST_STAT
    ldr r1, [r0]
    and r1, r1, #0x000D0000
    cmp r1, #(0x1 << 19)            @ DEEPIDLE_WAKEUP
    /*如果是从DEEPIDLE模式唤醒的就直接跳到didle_wakeup过程*/
    beq didle_wakeup
    cmp r7, r8

skip_check_didle:
    /*下面这一堆代码就是点亮了一颗led灯,我们改成自己板子上对应的灯GPJ0_3*/
    addeq   r0, r8, #0x280              @ S5PC100_GPIO_J4
    addne   r0, r8, #0x240              @ S5PC110_GPIO_J0
    ldr r1, [r0, #0x0]              @ GPIO_CON_OFFSET
    bic r1, r1, #(0xf << 12)            @ 3 * 4-bit
    orr r1, r1, #(0x1 << 12)
    str r1, [r0, #0x0]              @ GPIO_CON_OFFSET

    ldr r1, [r0, #0x4]              @ GPIO_DAT_OFFSET
    bic r1, r1, #(1 << 3)
    str r1, [r0, #0x4]              @ GPIO_DAT_OFFSET

    /*执行到这里,上面点的那颗led灯,如果亮了的话那就说明前面暂时没什么问题了*/
    /* Don't setup at s5pc100 */
    beq 100f

    /*下面这堆都是写的默认值,不知道具体的作用*/
    /*
     省略
    */


    /*
     * Diable ABB block to reduce sleep current at low temperature
     * Note that it's hidden register setup don't modify it
     */

     /*这里操作的是隐藏寄存器,不要动*/
    ldr r0, =0xE010C300
    ldr r1, =0x00800000
    str r1, [r0]

100:
    /* IO retension release */
    /*这一堆好像与低功耗有关*/
    ldreq   r0, =S5PC100_OTHERS         @ 0xE0108200
    ldrne   r0, =S5PC110_OTHERS         @ 0xE010E000
    ldr r1, [r0]
    ldreq   r2, =(1 << 31)              @ IO_RET_REL
    ldrne   r2, =((1 << 31) | (1 << 30) | (1 << 29) | (1 << 28))
    orr r1, r1, r2
    /* Do not release retention here for S5PC110 */
    streq   r1, [r0]

    /* Disable Watchdog */
    ldreq   r0, =S5PC100_WATCHDOG_BASE      @ 0xEA200000
    ldrne   r0, =S5PC110_WATCHDOG_BASE      @ 0xE2700000
    str r5, [r0]

    /* setting SRAM */
    ldreq   r0, =S5PC100_SROMC_BASE
    ldrne   r0, =S5PC110_SROMC_BASE
    ldr r1, =0x9
    str r1, [r0]

    /* S5PC100 has 3 groups of interrupt sources */
    /*s5pv210有四组中断源,这里只失能了三组,再添加一组*/
    ldreq   r0, =S5PC100_VIC0_BASE          @ 0xE4000000
    ldrne   r0, =S5PC110_VIC0_BASE          @ 0xF2000000
    add r1, r0, #0x00100000
    add r2, r0, #0x00200000
    /*r4还没被用过,使用r4*/
    add r4, r0, #0x00300000

    /* Disable all interrupts (VIC0, VIC1 and VIC2, VIC3) */
    mvn r3, #0x0
    str r3, [r0, #0x14]             @ INTENCLEAR
    str r3, [r1, #0x14]             @ INTENCLEAR
    str r3, [r2, #0x14]             @ INTENCLEAR
    /*增加VIC3*/
    str r3, [r4, #0x14]             @ INTENCLEAR

    /* Set all interrupts as IRQ */
    str r5, [r0, #0xc]              @ INTSELECT
    str r5, [r1, #0xc]              @ INTSELECT
    str r5, [r2, #0xc]              @ INTSELECT
    /*增加VIC3*/
    str r5, [r4, #0xc]              @ INTSELECT

    /* Pending Interrupt Clear */
    str r5, [r0, #0xf00]            @ INTADDRESS
    str r5, [r1, #0xf00]            @ INTADDRESS
    str r5, [r2, #0xf00]            @ INTADDRESS
    /*增加VIC3*/
    str r5, [r4, #0xf00]            @ INTADDRESS

    /* for UART */
    /*由于IROM代码已经初始化了串口2,而在u-boot里面我也使用的串口2作为调试串口,
    所以可以选择不初始化,但是后面重新配置了时钟,IROM中的配置在新的时钟下工作不正常,没有输出,
    主要应该就是波特率相关寄存器的设置没法用了,所以再重新配置一下(参考后面的修改)*/

    bl  uart_asm_init

    bl  internal_ram_init

    cmp r7, r8
    /* Clear wakeup status register */
    ldreq   r0, =S5PC100_WAKEUP_STAT
    ldrne   r0, =S5PC110_WAKEUP_STAT
    /*这里是不是感觉什么都没做,但实际上手册说的是写1清除该位,默认状态为0,
    那猜测有效状态应该是1,将读出来的值1又写回去就清除了该位*/

    ldr r1, [r0]
    str r1, [r0]

    /* IO retension release */
    /*是不是很熟悉,前面也有一段一模一样的代码,不知道意欲何为*/
    /*
    省略
    */


    /*向下找标号1*/
    b   1f

/*如果前面检测出是DEEPIDLE模式唤醒的,那么直接就到这儿了*/
didle_wakeup:
    /* Wait when APLL is locked */
    ldr r0, =0xE0100100         @ S5PC110_APLL_CON
lockloop:
    /*等待APLL时钟稳定*/
    ldr r1, [r0]
    and r1, r1, #(1 << 29)
    cmp r1, #(1 << 29)
    bne lockloop

    /*S5PC110_INFORM0是一个用户自定义寄存器*/
    ldr r0, =S5PC110_INFORM0
    ldr r1, [r0]
    /*这里将r1的值放到pc指针里面了,猜测是某个地方进入DEEPIDLE的时候,
    将lr的值保存到了S5PC110_INFORM0里面,这里直接读出来后返回之前执行的地方*/

    mov pc, r1
    nop
    nop
    nop
    nop
    nop

1:
    /*到了这里就直接返回了*/
    mov lr, r11
    mov pc, lr

从源码可以看出,目前lowlevel_init主要做的事:

检测唤醒条件
点了一颗灯显示当前运行到哪儿了
Initialize Async Register
IO retension release相关的
关看门狗
设置SRAM
关中断(这里中断和之前arm内核部分的中断不一样,这些中断是三星公司设计的)
初始化了四个串口的引脚
初始化内部RAM
清除唤醒状态
IO retension release相关的

目前CPU好像是运行在400MHz下的,在本文件lowlevel_init.S的末尾有一个时钟初始化的过程,但是没有被调用,将其添加上:

   /*添加到这句后面*/
bl    internal_ram_init

    /*初始化时钟*/
    bl system_clock_init

由于重新配置了时钟,而串口2的初始化使用的PCLK时钟没有使用串口专有的时钟,所以也跟着发生了变化,串口2在IROM中的配置已经不能用了,不能输出信息,重新配置一下:

/*
 * uart_asm_init: Initialize UART's pins
 */

uart_asm_init:
    /* set GPIO to enable UART0-UART4 */
    mov r0, r8
    ldr r1, =0x22222222
    str r1, [r0, #0x0]          @ S5PC100_GPIO_A0_OFFSET
    ldr r1, =0x00002222
    str r1, [r0, #0x20]         @ S5PC100_GPIO_A1_OFFSET

    /* Check S5PC100 */
    cmp r7, r8
    bne 110f

    /* UART_SEL GPK0[5] at S5PC100 */
    /*
    省略
    */


    b   200f
110:
    /*
     * Note that the following address
     * 0xE020'0360 is reserved address at S5PC100
     */

    /* UART_SEL MP0_5[7] at S5PC110 */
    /*下面这堆代码是在设置MP05_7这个脚,但在我的开发板上悬空的,可以删除,也可以不管*/
    /*
    省略
    */


    /*配置串口2*/
    ldr r0, =S5PC110_UART_BASE
    /*ULCON 8n1*/
    ldr r1, =0x3
    str r1, [r0, #0x800]
    /*UCON*/
    ldr r1, =0x5
    str r1, [r0, #0x804]
    /*UFCON*/
    ldr r1, =0x217
    str r1, [r0, #0x808]
    /*UMCON*/
    ldr r1, =0x0
    str r1, [r0, #0x80C]
    /*UBRDIV*/
    ldr r1, =34
    str r1, [r0, #0x828]
    /*UDIVSLOT*/
    ldr r1, =0xDFDD
    str r1, [r0, #0x82C]
200:
    mov pc, lr

接着是初始化DDR,我这个开发板的配置是4片128M,每两片并联组成32bit的数据线访问,总容量512M,从手册上面可以得知此芯片有两个DDR控制器,总共能扩展的DDR内存最大1.5G:


图1 内存映射图
硬件上前256M在DRAM0区域,后256M在DRAM1区域,为了让两片地址连续起来,前256M的起始地址设置为0x30000000,后256M的起始地址设为0x40000000,这样刚好地址连续,DDR的初始化程序参考三星提供的,下面只对配置部分参数进行说明,关于时间参数不进行讲解,配置流程参见手册DRAM CONTROLLER篇(完整初始化代码见本文末尾):


/*chip相当于rank,就好像电脑的内存插槽是有正反两面的,我们只有一面,也就是一个rank*/
#define DMC0_MEMCONTROL        0x00202400  // MemControl   BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off

/*30代表起始地址是0x30000000,F0有点像大小的意思代表0xfffffff,1有点像扫描方式,3列的位数是10,2行的位数是14,3bank数是8*/
#define DMC0_MEMCONFIG_0    0x30F01323  // MemConfig0   256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
/*前面说了我们只用了一面,另一面没用*/
#define DMC0_MEMCONFIG_1    0x30F00312  // MemConfig1       默认值

#define DMC0_TIMINGA_REF    0x00000618  // TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW        0x28233287  // TimingRow    for @200MHz
#define DMC0_TIMING_DATA    0x23240304  // TimingData   CL=3
#define    DMC0_TIMING_PWR     0x09C80232  // TimingPower

#define    DMC1_MEMCONTROL     0x00202400  // MemControl   BL=4, 1chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

/*除了起始地址,其它描述和DMC0都一样*/
#define DMC1_MEMCONFIG_0    0x40F01323  // MemConfig0   256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
/*这个也是只用了一面*/
#define DMC1_MEMCONFIG_1    0x60E00312  // MemConfig1       默认值

#define DMC1_TIMINGA_REF    0x00000618  // TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW        0x28233289  // TimingRow    for @200MHz
#define DMC1_TIMING_DATA    0x23240304  // TimingData   CL=3
#define    DMC1_TIMING_PWR     0x08280232  // TimingPower

将DDR初始化程序,ddr_init.S文件放到board/samsung/goni/目录,然后修改该目录下的Makefile,添加ddr_init.S的编译:

obj-y    := goni.o onenand.o
obj-y    += lowlevel_init.o
/*增加ddr_init*/
obj-y    += ddr_init.o

然后在时钟初始化的后面添加上DDR的初始化:

/*...*/
bl    internal_ram_init

    /*初始化时钟*/
    bl system_clock_init

    /*初始化DDR*/
    bl sdram_asm_init

DDR怎么验证有没有初始化成功呢,可以添加一段测试程序,先向DDR的某个地址(注意这个地址一定要四字节对齐,因为前面开启了对齐检查,否则访问非对齐地址时会出错,而且这个错误的唯一现象就是你看不到任何输出,这时你可能会怀疑你的DDR初始化没有成功,导致写DDR时出错,但实际上是因为访问了非对齐地址)写入几个值,然后再读出来,我这里写了OK两个字符,通过串口打印查看就可以了:

/*写入字符'O'*/
    ldr r0, =0x40000000
    ldr r1, =0x4f
    str r1, [r0]
    /*写入字符'K'*/
    ldr r0, =0x40000004
    ldr r1, =0x4b
    str r1, [r0]
    /*读出然后通过串口输出*/
    ldr r0, =0xE2900820
    ldr r1, =0x40000000
    ldr r2, [r1]
    str r2, [r0]
    /*读出然后通过串口输出*/
    ldr r0, =0xE2900820
    ldr r1, =0x40000004
    ldr r2, [r1]
    str r2, [r0]

由于硬件设计的原因,开发板上电后还需要进行电源置锁,不然的话开机按钮如果松手的话就掉电了,这里将电源置锁加上:

/*这个只是简单的拉了一个IO的电平,不作介绍,添加函数体的实现到lowlevel_init.S文件的末尾,然后在时钟初始化的前面调用*/
board_power_hold:
    ldr r0, =0xE010E81C
    ldr r1, [r0]
    ldr r2, =((0x1 << 0) | (0x1 << 8) | (0x1 << 9))
    orr r1, r1, r2
    str r1, [r0]
    mov pc, lr

在时钟初始化前调用:

/*...*/
bl    internal_ram_init

    /*电源置锁*/
    bl board_power_hold

    /*初始化时钟*/
    bl system_clock_init

    /*初始化DDR*/
    bl sdram_asm_init

到了这里,DDR已经初始化好了,下一步就是将u-boot拷贝到DDR去执行了,我们u-boot是烧写到sd卡的,三星在IROM代码中已经提供了将SD卡的内容拷贝到内存的函数实现,我们只需要调用就可以了,这里参考手册(S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf):


图2



图3
上面图2表示这个地址存储了当前的启动通道地址,图3就是拷贝函数,三星提供了好几个这样的拷贝函数,用于从不同启动介质中拷贝内容到内存中,这里只截取了SD/MMC和eMMC的拷贝函数,从上面的图可以看出CopySDMMCtoMem这个函数的函数体就放在0xD0037F98这个地址,所以我们只需要通过函数指针的方式,访问这个地址的内容就相当于调用这个函数了,在board/samsung/goni/目录添加一个copy_image_to_mem.c文件,写入以下代码:


#include <configs/s5p_goni.h>

/*
参数1:通道号
参数2:从SD卡的哪个扇区开始拷贝
参数3:拷贝多少个扇区
参数4:拷贝到内存的哪里
参数5:不知道具体用途
*/

typedef bool (*CopySDMMCtoMemTypeDef)(intunsigned intunsigned shortunsigned int*, bool);

void CopySDMMCtoMem(void)
{
    CopySDMMCtoMemTypeDef pFuncCopySDMMCtoMem;

    pFuncCopySDMMCtoMem = (CopySDMMCtoMemTypeDef)(*((volatile unsigned int *)0xD0037F98));
    unsigned int ch = *((volatile unsigned int*)(0xd0037488));

    if(ch == 0xeb000000)
    {
        /*通道0,iNand*/
    }
    else if(ch == 0xeb200000)
    {
        /*通道2,SD卡*/
        pFuncCopySDMMCtoMem(2451000,(unsigned int*)CONFIG_SYS_TEXT_BASE, 0); 
    }
}

有个需要注意的地方就是拷贝到内存的地址,这是个C函数,函数的调用需要使用栈,前面start.S里面设置过一次栈,这里的内存地址最好不要和当时设置的栈空间冲突(注意栈的生长方向是向下的);然后就是SD卡的起始扇区,这个是和你烧写u-boot的起始扇区一样的,因为我是烧写到45扇区开始的位置(这个位置不是固定的,只要没有覆盖掉BL1就行了),所以这里设置45,拷贝大小(这里设置的参数值是扇区数,乘以扇区大小512才是真正的大小,我这里拷贝1000*512=500K)只要大于等于u-boot的大小就行了,然后内存地址我设置的是链接地址。

顺便贴下我的烧写脚本:

#! /bin/bash

UBOOT=2020.04

#mkv210_image是制作BL1的,因为BL1前16个字节需要填写头信息
./mkv210_image ~/Desktop/s5pv210/u-boot-${UBOOT}/u-boot.bin u-boot-sd.bin
sudo dd iflag=dsync oflag=dsync if=u-boot-sd.bin of=/dev/sdb seek=1
sudo dd iflag=dsync oflag=dsync if=~/Desktop/s5pv210/u-boot-${UBOOT}/u-boot.bin of=/dev/sdb seek=45

在board/samsung/goni/Makefile中添加,让其编译进u-boot,就可以调用这个函数进行拷贝了:

obj-y    := goni.o onenand.o
obj-y    += lowlevel_init.o
obj-y    += ddr_init.o
/*添加编译*/
obj-y    += copy_image_to_mem.o



/*...*/
bl    internal_ram_init

    /*电源置锁*/
    bl board_power_hold

    /*初始化时钟*/
    bl system_clock_init

    /*初始化DDR*/
    bl sdram_asm_init

    /*拷贝u-boot到DDR*/
    bl CopySDMMCtoMem

其实还有很重要的一步,我前面没有提到,就是我们调用的这个函数是不是都在BL1里面,也就是是不是在u-boot的前16K,我们可以通过查看System.map文件,这个文件是u-boot编译后生成的,位于u-boot根目录:


图4
起始地址可以看到是0x34800000,前16K的内容就截止与0x34804000这个地址,所以我们只需要看我们调用的内容有没有在这个地址内就行了,或者可以反汇编u-boot文件也可以知道,相对来说反汇编u-boot文件要详细点。

好的,u-boot已经拷贝到DDR里面了,所以紧接着我们进入DDR的u-boot中去执行,修改arch/arm/cpu/armv7/start.S文件:


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
#ifdef CONFIG_CPU_V7A
    bl  cpu_init_cp15
#endif
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
    bl  cpu_init_crit
#endif
#endif

    /*注释掉*/
    @ bl    _main
    /*修改这里,跳转到DDR中去执行*/
    ldr pc, =_main

这部分内容结束,就进入board_init_f了(也就是大家说的u-boot的第一阶段),所以编译看一下效果:


图5
可以看到已经出来很多信息了,说明我们成功跳转到DDR去执行了,不过卡在了OneNAND初始化的后面。

完整DDR初始化代码:


#include <config.h>

#define ELFIN_GPIO_BASE   S5PC110_GPIO_BASE

#define MP1_0DRV_SR_OFFSET         0x3CC
#define MP1_1DRV_SR_OFFSET         0x3EC
#define MP1_2DRV_SR_OFFSET         0x40C
#define MP1_3DRV_SR_OFFSET         0x42C
#define MP1_4DRV_SR_OFFSET         0x44C
#define MP1_5DRV_SR_OFFSET         0x46C
#define MP1_6DRV_SR_OFFSET         0x48C
#define MP1_7DRV_SR_OFFSET         0x4AC
#define MP1_8DRV_SR_OFFSET         0x4CC

#define MP2_0DRV_SR_OFFSET         0x4EC
#define MP2_1DRV_SR_OFFSET         0x50C
#define MP2_2DRV_SR_OFFSET         0x52C
#define MP2_3DRV_SR_OFFSET         0x54C
#define MP2_4DRV_SR_OFFSET         0x56C
#define MP2_5DRV_SR_OFFSET         0x58C
#define MP2_6DRV_SR_OFFSET         0x5AC
#define MP2_7DRV_SR_OFFSET         0x5CC
#define MP2_8DRV_SR_OFFSET         0x5EC

/*
 * SDRAM Controller
 */

#define APB_DMC_0_BASE            0xF0000000
#define APB_DMC_1_BASE            0xF1400000
#define ASYNC_MSYS_DMC0_BASE    0xF1E00000

#define DMC_CONCONTROL             0x00
#define DMC_MEMCONTROL             0x04
#define DMC_MEMCONFIG0             0x08
#define DMC_MEMCONFIG1             0x0C
#define DMC_DIRECTCMD             0x10
#define DMC_PRECHCONFIG         0x14
#define DMC_PHYCONTROL0         0x18
#define DMC_PHYCONTROL1         0x1C
#define DMC_RESERVED             0x20
#define DMC_PWRDNCONFIG         0x28
#define DMC_TIMINGAREF             0x30
#define DMC_TIMINGROW             0x34
#define DMC_TIMINGDATA             0x38
#define DMC_TIMINGPOWER         0x3C
#define DMC_PHYSTATUS             0x40
#define DMC_CHIP0STATUS         0x48
#define DMC_CHIP1STATUS         0x4C
#define DMC_AREFSTATUS             0x50
#define DMC_MRSTATUS             0x54
#define DMC_PHYTEST0             0x58
#define DMC_PHYTEST1             0x5C
#define DMC_QOSCONTROL0         0x60
#define DMC_QOSCONFIG0             0x64
#define DMC_QOSCONTROL1         0x68
#define DMC_QOSCONFIG1             0x6C
#define DMC_QOSCONTROL2         0x70
#define DMC_QOSCONFIG2             0x74
#define DMC_QOSCONTROL3         0x78
#define DMC_QOSCONFIG3             0x7C
#define DMC_QOSCONTROL4         0x80
#define DMC_QOSCONFIG4             0x84
#define DMC_QOSCONTROL5         0x88
#define DMC_QOSCONFIG5             0x8C
#define DMC_QOSCONTROL6         0x90
#define DMC_QOSCONFIG6             0x94
#define DMC_QOSCONTROL7         0x98
#define DMC_QOSCONFIG7             0x9C
#define DMC_QOSCONTROL8         0xA0
#define DMC_QOSCONFIG8             0xA4
#define DMC_QOSCONTROL9         0xA8
#define DMC_QOSCONFIG9             0xAC
#define DMC_QOSCONTROL10         0xB0
#define DMC_QOSCONFIG10         0xB4
#define DMC_QOSCONTROL11         0xB8
#define DMC_QOSCONFIG11         0xBC
#define DMC_QOSCONTROL12         0xC0
#define DMC_QOSCONFIG12         0xC4
#define DMC_QOSCONTROL13         0xC8
#define DMC_QOSCONFIG13         0xCC
#define DMC_QOSCONTROL14         0xD0
#define DMC_QOSCONFIG14         0xD4
#define DMC_QOSCONTROL15         0xD8
#define DMC_QOSCONFIG15         0xDC

#define DMC0_MEMCONTROL        0x00202400  // MemControl   BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off

#define DMC0_MEMCONFIG_0    0x30F01323  // MemConfig0   256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1    0x30F00312  // MemConfig1       默认值

#define DMC0_TIMINGA_REF    0x00000618  // TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW        0x28233287  // TimingRow    for @200MHz
#define DMC0_TIMING_DATA    0x23240304  // TimingData   CL=3
#define    DMC0_TIMING_PWR     0x09C80232  // TimingPower

#define    DMC1_MEMCONTROL     0x00202400  // MemControl   BL=4, 1chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

#define DMC1_MEMCONFIG_0    0x40F01323  // MemConfig0   256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1    0x60E00312  // MemConfig1       默认值

#define DMC1_TIMINGA_REF    0x00000618  // TimingAref   7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW        0x28233289  // TimingRow    for @200MHz
#define DMC1_TIMING_DATA    0x23240304  // TimingData   CL=3
#define    DMC1_TIMING_PWR     0x08280232  // TimingPower

.globl sdram_asm_init
sdram_asm_init:    
    ldr r0, =0xf1e00000
    ldr r1, =0x0
    str r1, [r0, #0x0]

    /* DMC0 Drive Strength (Setting 2X) */

    ldr r0, =ELFIN_GPIO_BASE

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_0DRV_SR_OFFSET]       // 寄存器中对应0b10,就是2X

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_1DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_2DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_3DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_4DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_5DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_6DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP1_7DRV_SR_OFFSET]

    ldr r1, =0x00002AAA
    str r1, [r0, #MP1_8DRV_SR_OFFSET]


    /* DMC1 Drive Strength (Setting 2X) */

    ldr r0, =ELFIN_GPIO_BASE

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_0DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_1DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_2DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_3DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_4DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_5DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_6DRV_SR_OFFSET]

    ldr r1, =0x0000AAAA
    str r1, [r0, #MP2_7DRV_SR_OFFSET]

    ldr r1, =0x00002AAA
    str r1, [r0, #MP2_8DRV_SR_OFFSET]

    /* DMC0 initialization at single Type*/
    ldr r0, =APB_DMC_0_BASE

    ldr r1, =0x00101000             @PhyControl0 DLL parameter setting, manual 0x00101000
    str r1, [r0, #DMC_PHYCONTROL0]

    ldr r1, =0x00000086             @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case
    str r1, [r0, #DMC_PHYCONTROL1]

    ldr r1, =0x00101002             @PhyControl0 DLL on
    str r1, [r0, #DMC_PHYCONTROL0]

    ldr r1, =0x00101003             @PhyControl0 DLL start
    str r1, [r0, #DMC_PHYCONTROL0]

find_lock_val:
    ldr r1, [r0, #DMC_PHYSTATUS]        @Load Phystatus register value
    and r2, r1, #0x7
    cmp r2, #0x7                @Loop until DLL is locked
    bne find_lock_val

    and r1, #0x3fc0 
    mov r2, r1, LSL #18
    orr r2, r2, #0x100000
    orr r2 ,r2, #0x1000 

    orr r1, r2, #0x3                @Force Value locking
    str r1, [r0, #DMC_PHYCONTROL0]

#if 0    /* Memory margin test 10.01.05 */
    orr r1, r2, #0x1                @DLL off
    str r1, [r0, #DMC_PHYCONTROL0]
#endif
    /* setting DDR2 */
    ldr r1, =0x0FFF2010             @ConControl auto refresh off
    str r1, [r0, #DMC_CONCONTROL]

    ldr r1, =DMC0_MEMCONTROL            @MemControl BL=41 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
    str r1, [r0, #DMC_MEMCONTROL]

    ldr r1, =DMC0_MEMCONFIG_0           @MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
    str r1, [r0, #DMC_MEMCONFIG0]

    ldr r1, =DMC0_MEMCONFIG_1           @MemConfig1
    str r1, [r0, #DMC_MEMCONFIG1]

    ldr r1, =0xFF000000             @PrechConfig
    str r1, [r0, #DMC_PRECHCONFIG]

    ldr r1, =DMC0_TIMINGA_REF           @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
    str r1, [r0, #DMC_TIMINGAREF]

    ldr r1, =DMC0_TIMING_ROW            @TimingRow  for @200MHz
    str r1, [r0, #DMC_TIMINGROW]

    ldr r1, =DMC0_TIMING_DATA           @TimingData CL=3
    str r1, [r0, #DMC_TIMINGDATA]

    ldr r1, =DMC0_TIMING_PWR            @TimingPower
    str r1, [r0, #DMC_TIMINGPOWER]

    ldr r1, =0x07000000             @DirectCmd  chip0 Deselect
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01000000             @DirectCmd  chip0 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00020000             @DirectCmd  chip0 EMRS2
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00030000             @DirectCmd  chip0 EMRS3
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010400             @DirectCmd  chip0 EMRS1 (MEM DLL on, DQS# disable)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00000542             @DirectCmd  chip0 MRS (MEM DLL reset) CL=4, BL=4
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01000000             @DirectCmd  chip0 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05000000             @DirectCmd  chip0 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05000000             @DirectCmd  chip0 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00000442             @DirectCmd  chip0 MRS (MEM DLL unreset)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010780             @DirectCmd  chip0 EMRS1 (OCD default)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010400             @DirectCmd  chip0 EMRS1 (OCD exit)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x07100000             @DirectCmd  chip1 Deselect
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01100000             @DirectCmd  chip1 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00120000             @DirectCmd  chip1 EMRS2
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00130000             @DirectCmd  chip1 EMRS3
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110400             @DirectCmd  chip1 EMRS1 (MEM DLL on, DQS# disable)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00100542             @DirectCmd  chip1 MRS (MEM DLL reset) CL=4, BL=4
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01100000             @DirectCmd  chip1 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05100000             @DirectCmd  chip1 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05100000             @DirectCmd  chip1 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00100442             @DirectCmd  chip1 MRS (MEM DLL unreset)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110780             @DirectCmd  chip1 EMRS1 (OCD default)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110400             @DirectCmd  chip1 EMRS1 (OCD exit)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x0FF02030             @ConControl auto refresh on
    str r1, [r0, #DMC_CONCONTROL]

    ldr r1, =0xFFFF00FF             @PwrdnConfig
    str r1, [r0, #DMC_PWRDNCONFIG]

    ldr r1, =0x00202400             @MemControl BL=42 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
    str r1, [r0, #DMC_MEMCONTROL]

// 上面是DRAM0初始化步骤
/*******************************************************************************************/    
// 下面是DRAM1初始化步骤,两者没有联系,是并列的。

    /* DMC1 initialization */
    ldr r0, =APB_DMC_1_BASE
    ldr r1, =0x00101000             @Phycontrol0 DLL parameter setting
    str r1, [r0, #DMC_PHYCONTROL0]


    ldr r1, =0x00000086             @Phycontrol1 DLL parameter setting
    str r1, [r0, #DMC_PHYCONTROL1]
    ldr r1, =0x00101002             @PhyControl0 DLL on
    str r1, [r0, #DMC_PHYCONTROL0]
    ldr r1, =0x00101003             @PhyControl0 DLL start
    str r1, [r0, #DMC_PHYCONTROL0]



find_lock_val1:
    ldr r1, [r0, #DMC_PHYSTATUS]        @Load Phystatus register value
    and r2, r1, #0x7
    cmp r2, #0x7                @Loop until DLL is locked
    bne find_lock_val1

    and r1, #0x3fc0 
    mov r2, r1, LSL #18
    orr r2, r2, #0x100000
    orr r2, r2, #0x1000

    orr r1, r2, #0x3                @Force Value locking
    str r1, [r0, #DMC_PHYCONTROL0]

#if 0    /* Memory margin test 10.01.05 */
    orr r1, r2, #0x1                @DLL off
    str r1, [r0, #DMC_PHYCONTROL0]
#endif

    /* settinf fot DDR2 */
    ldr r0, =APB_DMC_1_BASE

    ldr r1, =0x0FFF2010             @auto refresh off
    str r1, [r0, #DMC_CONCONTROL]

    ldr r1, =DMC1_MEMCONTROL            @MemControl BL=42 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
    str r1, [r0, #DMC_MEMCONTROL]

    ldr r1, =DMC1_MEMCONFIG_0           @MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
    str r1, [r0, #DMC_MEMCONFIG0]

    ldr r1, =DMC1_MEMCONFIG_1           @MemConfig1
    str r1, [r0, #DMC_MEMCONFIG1]

    ldr r1, =0xFF000000
    str r1, [r0, #DMC_PRECHCONFIG]

    ldr r1, =DMC1_TIMINGA_REF           @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
    str r1, [r0, #DMC_TIMINGAREF]

    ldr r1, =DMC1_TIMING_ROW            @TimingRow  for @200MHz
    str r1, [r0, #DMC_TIMINGROW]

    ldr r1, =DMC1_TIMING_DATA           @TimingData CL=3
    str r1, [r0, #DMC_TIMINGDATA]

    ldr r1, =DMC1_TIMING_PWR            @TimingPower
    str r1, [r0, #DMC_TIMINGPOWER]


    ldr r1, =0x07000000             @DirectCmd  chip0 Deselect
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01000000             @DirectCmd  chip0 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00020000             @DirectCmd  chip0 EMRS2
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00030000             @DirectCmd  chip0 EMRS3
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010400             @DirectCmd  chip0 EMRS1 (MEM DLL on, DQS# disable)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00000542             @DirectCmd  chip0 MRS (MEM DLL reset) CL=4, BL=4
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01000000             @DirectCmd  chip0 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05000000             @DirectCmd  chip0 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05000000             @DirectCmd  chip0 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00000442             @DirectCmd  chip0 MRS (MEM DLL unreset)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010780             @DirectCmd  chip0 EMRS1 (OCD default)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00010400             @DirectCmd  chip0 EMRS1 (OCD exit)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x07100000             @DirectCmd  chip1 Deselect
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01100000             @DirectCmd  chip1 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00120000             @DirectCmd  chip1 EMRS2
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00130000             @DirectCmd  chip1 EMRS3
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110440             @DirectCmd  chip1 EMRS1 (MEM DLL on, DQS# disable)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00100542             @DirectCmd  chip1 MRS (MEM DLL reset) CL=4, BL=4
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x01100000             @DirectCmd  chip1 PALL
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05100000             @DirectCmd  chip1 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x05100000             @DirectCmd  chip1 REFA
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00100442             @DirectCmd  chip1 MRS (MEM DLL unreset)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110780             @DirectCmd  chip1 EMRS1 (OCD default)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x00110400             @DirectCmd  chip1 EMRS1 (OCD exit)
    str r1, [r0, #DMC_DIRECTCMD]

    ldr r1, =0x0FF02030             @ConControl auto refresh on
    str r1, [r0, #DMC_CONCONTROL]

    ldr r1, =0xFFFF00FF             @PwrdnConfig    
    str r1, [r0, #DMC_PWRDNCONFIG]

    ldr r1, =DMC1_MEMCONTROL            @MemControl BL=42 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
    str r1, [r0, #DMC_MEMCONTROL]
    // 函数返回
    mov pc, lr

欢迎扫码关注我的微信公众号

漫长当下