天天看點

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
{
    . = ;

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

    .data : {
        * (.data)
    }

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

    bss_end  = .;   
}
           
S5PV210系列(裸機七)之 SDRAM

原理圖中每個DDR端口都由3類總線構成:位址總線(Xmn_ADDR0~XMnADDR13共14根位址總線) + 控制總線(中間部分,自己看原理圖) + 資料總線(Xmn_DATA0~XMnDATA31共32根資料線)

分析:從資料總線的位數可以看出,我們用的是32位的(實體)記憶體。

S5PV210系列(裸機七)之 SDRAM

原理圖中畫出4片記憶體晶片的一頁,可以看出:X210開發闆共使用了4片記憶體(每片1Gb=128MB,共512MB),每片記憶體的資料總線都是16位的(單晶片是16位記憶體)。如何由16位記憶體得到32位記憶體呢?可以使用并聯方法。在原理圖上橫向的2顆記憶體晶片就是并聯連接配接的。并聯時位址總線接法一樣,但是資料總線要加起來。這樣連接配接相當于在邏輯上可以把這2顆記憶體晶片看成是一個(這一個晶片是32位的,接在Xm1端口上)。

S5PV210系列(裸機七)之 SDRAM

資料手冊中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)記憶體。

S5PV210系列(裸機七)之 SDRAM

彙編初始化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, =
    ldr r1, =
    str r1, [r0, #0x0]

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

    ldr r0, =ELFIN_GPIO_BASE

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

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

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

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

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

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

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

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

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


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

    ldr r0, =ELFIN_GPIO_BASE

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

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

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

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

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

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

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

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

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

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

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

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

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

    ldr r1, =             @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, =             @ConControl auto refresh off
    str r1, [r0, #DMC_CONCONTROL]

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

    ldr r1, =DMC0_MEMCONFIG_0           @MemConfig0 MB config,  banks,Mapping Method[:]:linear, :linterleaved, :Mixed
    str r1, [r0, #DMC_MEMCONFIG0]

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

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

    ldr r1, =DMC0_TIMINGA_REF           @TimingAref us*MHz=(), MHz=(), MHz=(), MHz=()
    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=
    str r1, [r0, #DMC_TIMINGDATA]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ldr r1, =             @MemControl BL=,  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, =             @Phycontrol0 DLL parameter setting
    str r1, [r0, #DMC_PHYCONTROL0]


    ldr r1, =             @Phycontrol1 DLL parameter setting
    str r1, [r0, #DMC_PHYCONTROL1]
    ldr r1, =             @PhyControl0 DLL on
    str r1, [r0, #DMC_PHYCONTROL0]
    ldr r1, =             @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, =             @auto refresh off
    str r1, [r0, #DMC_CONCONTROL]

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

    ldr r1, =DMC1_MEMCONFIG_0           @MemConfig0 MB config,  banks,Mapping Method[:]:linear, :linterleaved, :Mixed
    str r1, [r0, #DMC_MEMCONFIG0]

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

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

    ldr r1, =DMC1_TIMINGA_REF           @TimingAref us*MHz=(), MHz=(), MHz=(), MHz=(
    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=
    str r1, [r0, #DMC_TIMINGDATA]

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ldr r1, =DMC1_MEMCONTROL            @MemControl BL=,  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中完全相同。

繼續閱讀