S5PV210系列(裸机七)之 SDRAM

SDRAM引入

SDRAM:Synchronized Dynamic Ramdam Access Memory,同步动态随机存储器

DDR:DDR就是DDR,SDRAM,是SDRAM的升级版。(DDR:double rate,双倍速度的SDRAM)

DDR有好多代:DDR1 DDR2 DDR3 DDR4 LPDDR

SDRAM的特性(容量大、价格低、掉电易失性、随机读写、总线式访问)
SDRAM/DDR都属于动态内存(相对于静态内存SRAM),都需要先运行一段初始化代码来初始化才能使用,不像SRAM开机上电后就可以直接运行。类似于SDRAM和SRAM的区别的,还有NorFlash和NandFlash(硬盘)这两个。
正是因为硬件本身特性有限制,所以才导致启动代码比较怪异、比较复杂。而我们研究裸机是为了研究uboot,在uboot中就充分利用了硬件的各种特性,处理了硬件复杂性。

SDRAM数据手册带读
SDRAM在系统中属于SoC外接设备(外部外设。以前说过随着半导体技术发展,很多东西都逐渐集成到SoC内部去了。现在还长期在外部的一般有:Flash、SDRAM/DDR、网卡芯片如DM9000、音频Codec。现在有一些高集成度的芯片也试图把这几个集成进去,做成真正的单芯片解决方案。)
SDRAM通过地址总线和数据总线接口(总线接口)与SoC通信。

开发板原理图上使用的是K4T1G164QQ,但是实际开发板上贴的不是这个,是另一款。但是这两款是完全兼容的,进行软件编程分析的时候完全可以参考K4T1G164QQ的文档。

全球做SDRAM的厂商不多,二线厂家做的产品参数都是向一线厂家(三星、KingSton)看齐,目的是兼容一线厂家的设计,然后让在意成本的厂商选择它的内存芯片替代一线厂家的内存芯片。SDRAM的这个市场特征就导致这个东西比较标准化,大部分时候细节参数官方(芯片原厂家)都会给你一个参考值。

K4T1G164QE:
K表示三星产品,4表示是DRAM,T表示产品号码,1G表示容量(1Gb,等于128MB,我们开发板X210上一共用了4片相同的内存,所以总容量是128×4=512MB)16表示单芯片是16位宽的,4表示是4bank,

三星官方的数据手册上其实没有芯片相关的参数设置信心,都是芯片选型与外观封装方面的信息,选型是给产品经理来看的,封装和电压等信息是给硬件工程师看的。软件工程师最关注的是工作参数信息,但是数据手册没有。

SDRAM初始化

原理图中SDRAM相关部分

S5PV210 共有2个内存端口(就好象有2个内存插槽)。再结合查阅数据手册中内存映射部分,可知:两个内存端口分别叫 DRAM0 和 DRAM1 :
DRAM0:内存地址范围:0x20000000〜0x3FFFFFFF(512MB),对应引脚是Xm1xxxx
DRAM1: 内存地址范围:0x40000000〜0x7FFFFFFF(1024MB),对应引脚是Xm2xxxx
结论:
(1)整个210最多支持内存为1.5GB,如果给210更多的内存CPU就无法识别。
(2)210最多支持1.5GB内存,但是实际开发板不一定要这么多,譬如我们X210开发板就只有512MB内存,连接方法是在DRAM0端口分布256MB,在DRAM1端口分布了256MB。
(3)由2可知,X210开发板上内存合法地址是:0x20000000〜0x2FFFFFFF(256MB) + 0x40000000〜0x4FFFFFFF(256MB)。当板子上DDR初始化完成之后,这些地址都是可以使用的;如果使用了其他地址譬如0x30004000就是死路一条。

链接脚本:

SECTIONS
{
    . = 0x20000000;

    .text : {
        start.o
        sdram_init.o
        * (.text)
    }

    .data : {
        * (.data)
    }

    bss_start = .; 
    .bss : {
        * (.bss)
    }

    bss_end  = .;   
}

这里写图片描述

原理图中每个DDR端口都由3类总线构成:地址总线(Xmn_ADDR0~XMnADDR13共14根地址总线) + 控制总线(中间部分,自己看原理图) + 数据总线(Xmn_DATA0~XMnDATA31共32根数据线)
分析:从数据总线的位数可以看出,我们用的是32位的(物理)内存。

这里写图片描述

原理图中画出4片内存芯片的一页,可以看出:X210开发板共使用了4片内存(每片1Gb=128MB,共512MB),每片内存的数据总线都是16位的(单芯片是16位内存)。如何由16位内存得到32位内存呢?可以使用并联方法。在原理图上横向的2颗内存芯片就是并联连接的。并联时地址总线接法一样,但是数据总线要加起来。这样连接相当于在逻辑上可以把这2颗内存芯片看成是一个(这一个芯片是32位的,接在Xm1端口上)。

这里写图片描述

数据手册中SDRAM相关部分
看数据手册《NT5TU64M16GG-DDR2-1G-G-R18-Consumer》第10页的block diagram。这个框图是128Bb×8结构的,这里的8指的是8bank,每bank128Mbit。
210的DDR端口信号中有BA0〜BA2,接在内存芯片的BA0〜BA2上,这些引脚就是用来选择bank的。
每个bank内部有128Mb,通过row address(14位) + column address(10位)的方式来综合寻址。
一共能寻址的范围是:2的14次方+2的10次方 = 2的24次方。对应16MB(128Mbit)内存。

这里写图片描述

汇编初始化SDRAM详解1
初始化代码框架介绍(函数调用和返回、步骤等)
SDRAM初始化使用一个函数sdram_asm_init,函数在sdram_init.S文件中实现,是一个汇编函数。
强调:汇编实现的函数在返回时需要明确使用返回指令(mov pc, lr)

#include "s5pv210.h"

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

#define DMC0_MEMCONFIG_0    0x20F01323  // 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, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

#define DMC1_MEMCONFIG_0    0x40F01323  // MemConfig0   512MB 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

#endif

#if 0

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

#define DMC0_MEMCONFIG_0    0x20E01323  // MemConfig0   512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1    0x40F01323  // 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, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off

#define DMC1_MEMCONFIG_0    0x40C01323  // MemConfig0   512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1    0x00E01323  // 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


#endif







.global 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=4, 1 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=4, 2 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=4, 2 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=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
    str r1, [r0, #DMC_MEMCONTROL]
    // 函数返回
    mov pc, lr

27步初始化DDR2

(1)首先,DDR初始化和SoC(准确说是和SoC中的DDR控制器)有关,也和开发板使用的DDR芯片有关,和开发板设计时DDR的连接方式也有关。

(2)S5PV210的DDR初始化步骤在SoC数据手册:1.2.1.3 DDR2这个章节。可知初始化DDR共需27个步骤。

(3)之前分析过X210的内存连接方式是:在DRAM0上连接256MB,在DRAM1上连接了256MB。所以初始化DRAM时分为2部分,第一部分初始化DRAM0,第二部分初始化DRAM1.

(4)我们的代码不是自己写的,这个代码来自于:第一,九鼎官方的uboot中;第二,参考了九鼎的裸机教程中对DDR的初始化;第三,有些参数是我根据自己理解修改过的。

阅读数据手册:

1.2.1.3 DDR2
Initialization sequence for DDR2 memory type:
1. To provide stable power for controller and memory device, the controller must assert and hold CKE to a logic
low level. Then apply stable clock. Note: XDDR2SEL should be High level to hold CKE to low.
2. Set the PhyControl0.ctrl_start_point and PhyControl0.ctrl_inc bit-fields to correct value according to clock
frequency. Set the PhyControl0.ctrl_dll_on bit-field to ‘1’ to turn on the PHY DLL.
3. DQS Cleaning: Set the PhyControl1.ctrl_shiftc and PhyControl1.ctrl_offsetc bit-fields to correct value
according to clock frequency and memory tAC parameters.
4. Set the PhyControl0.ctrl_start bit-field to ‘1’.
5. Set the ConControl. At this moment, an auto refresh counter should be off.
6. Set the MemControl. At this moment, all power down modes should be off.
7. Set the MemConfig0 register. If there are two external memory chips, set the MemConfig1 register.
8. Set the PrechConfig and PwrdnConfig registers.
9. Set the TimingAref, TimingRow, TimingData and TimingPower registers according to memory AC parameters.
10. If QoS scheme is required, set the QosControl0~15 and QosConfig0~15 registers.
11. Wait for the PhyStatus0.ctrl_locked bit-fields to change to ‘1’. Check whether PHY DLL is locked.
12. PHY DLL compensates the changes of delay amount caused by Process, Voltage and Temperature (PVT) variation during memory operation. Therefore, PHY DLL should not be off for reliable operation. It can be off except runs at low frequency. If off mode is used, set the PhyControl0.ctrl_force bit-field to correct value according to the PhyStatus0.ctrl_lock_value[9:2] bit-field to fix delay amount. Clear the PhyControl0.ctrl_dll_on bit-field to turn off PHY DLL.
13. Confirm whether stable clock is issued minimum 200us after power on
14. Issue a NOP command using the DirectCmd register to assert and to hold CKE to a logic high level.
15. 15. Wait for minimum 400ns.
16. Issue a PALL command using the DirectCmd register.
17. Issue an EMRS2 command using the DirectCmd register to program the operating parameters.
18. Issue an EMRS3 command using the DirectCmd register to program the operating parameters.
19. Issue an EMRS command using the DirectCmd register to enable the memory DLLs.
20. Issue a MRS command using the DirectCmd register to reset the memory DLL.
21. Issue a PALL command using the DirectCmd register.
22. Issue two Auto Refresh commands using the DirectCmd register.
23. Issue a MRS command using the DirectCmd register to program the operating parameters without resetting the memory DLL.
24. Wait for minimum 200 clock cycles.
25. Issue an EMRS command using the DirectCmd register to program the operating parameters. If OCD calibration is not used, issue an EMRS command to set OCD Calibration Default. After that, issue an EMRS command to exit OCD Calibration Mode and to program the operating parameters.
26. If there are two external memory chips, perform steps 14~25 for chip1 memory device.
27. Set the ConControl to turn on an auto refresh counter. 28. If power down modes is required, set the
MemControl registers.

主要步骤:

设置 IO 端口驱动强度:
因为 DDR 芯片和 S5PV210 之间是通过很多总线连接的,总线的物理表现就是很多个引脚,也就是说 DDR 芯片和 S5PV210 芯片是通过一些引脚连接的。DDR 芯片工作时需要一定的驱动信号,这个驱动信号需要一定的电平水平才能抗干扰,所以需要设置这些引脚的驱动能力,使 DDR 正常工作。
DRAM 控制器对应的引脚设置为驱动强度 2X(我也不知道为什么是2X,什么时候设置成 3X 4X?,这东西只能问 DDR 芯片厂商或者 SoC 厂商,我们一般是参考原厂给的代码)

DRAM port 时钟设置
从代码第 128 行到 154 行。主要是开启 DLL(dram pll)然后等待锁存。
这段代码对应 27 步中的第 2 到第 4 步。

DMC0_MEMCONTROL
burst length = 4,1chip,······ 对应值是 0x00202400

DMC0_MEMCONFIG_0
DRAM0 通道中memory chip0的参数设置寄存器

DMC0_MEMCONFIG_1
DRAM0 通道中 memory chip1 的参数设置寄存器
总结:我猜测(推论):三星设置 DRAM0 通道,允许我们接 2 片 256MB 的内存,分别叫 memory chip0 和 memory chip1,分别用这两个寄存器来设置它的参数。按照三星的设计,chip0 的地址应该是 0x20000000 到 0x2FFFFFFF,然后chip1 的地址应该是 0x30000000~0x3FFFFFFF. 各自 256MB。
但是我们 X210 开发板实际在 DRAM0 端口只接了 256MB 的内存,所以只用了chip0,没有使用 chip1.(我们虽然是 2 片芯片,然后这两片是并联形成 32 位内存的,逻辑上只能算 1 片)。按照这个推论,DMC0_MEMCONFIG_0 有用,而DMC0_MEMCONFIG_1 无用,所以我直接给他了默认值。

DMC_DIRECTCMD
这个寄存器是个命令寄存器,我们 210 通过向这个寄存器写值来向 DDR 芯片发送命令(通过命令总线),这些命令应该都是用来配置 DDR 芯片工作参数。
总结:DDR 配置过程比较复杂,基本上是按照 DDR 控制器的时序要求来做的,其中很多参数要结合 DDR 芯片本身的参数来定,还有些参数是时序参数,要去详细计算。所以 DDR 配置非常繁琐、细致、专业。所以我们对 DDR 初始化的态度就是:学会这种思路和方法,结合文档和代码能看懂,会算一些常见的参数即可。

重定位代码到SDRAM中
DRAM初始化之后,实际上重定位代码过程和之前重定位到SRAM中完全相同。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值