1. 程式人生 > >DDR(六)DDR2初始化原始碼分析

DDR(六)DDR2初始化原始碼分析

1.u-boot關於DDR的原始碼分析在mem_setup.S中,一點一點來,先看第一段

   /* DMC0 Drive Strength (Setting 2X) */
    ldr    r0, =ELFIN_GPIO_BASE
 
    ldr    r1, =0x0000AAAA
    str    r1, [r0, #MP1_0DRV_SR_OFFSET]
 
    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]

首先在初始化DDR之前,引入一個關於DRAM Drive Strength的概念----DRAM Drive Strength(也被稱為:driving strength),表示“DRAM驅動強度”。這個引數用來控制記憶體資料匯流排的訊號強度,數值越高代表訊號強度越高,增加訊號強度可以提高超頻的穩定性。但是並非訊號強度高就一定好。
所以,這裡我們需要配置這個Drive Striegth,DDR2記憶體的所有線都需要配置,這裡我們從地址線開始看,我們的記憶體是掛載在Memory Port1(以下簡稱MP1)上,所以,先在S5PV210的晶片手冊搜尋Xm1ADDR。

在P63頁,找到MP1的各個pin腳的描述,繼續向下搜尋。


在P107頁,Pin腳複用的描述表裡找到他的GPIO口定義

Xm1ADDR[0]~[7]的GPIO的MP1_0[0]~7是複用的,OK,搜尋MP1_0。

在P122頁最終找到MP1_0DRV,在這個暫存器的描述中,顯示這個暫存器就是用來配置我們的記憶體的Drive Strength的暫存器,搜尋MP1_0DRV。

找到MP1_0DRV的暫存器的配置表,這裡給出的初始值是AAAA,我總共是0-7,8根線,每根線我配的值都是10,也就是2x,符合我們上面介紹DRAM Driver Strength的描述,OK,到這裡我們的MP1_0暫存器----Xm1ADDR[0]~[7]的Driver Strength配置完畢。剩下的就按照上面的方法,再把剩下的線全部配好,初始均按晶片手冊的參考值配為2x,也就是10。現在再回過頭來看上面的初始化程式碼,清楚多了,整個這麼一長串程式碼,其實只做了一件事,就是給MP1上接的記憶體的每一根線都配置Driver Strength的值為2x,這裡有一個地方,需要注意一下,最後一個MP1_8他的參考配置為0x2AAA。照樣的,再配置DM1,把Memory Port2也配置完畢,這裡我們沒有用到MP2,不配置,應該也沒有關係。繼續看下一段程式碼:

/* 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]

根據晶片手冊給出的參考步驟,第2步如下:

2.依照時鐘頻率正確配置PhyControl0.ctrl_start_point和PhyControl0.ctrl_inc bit-fields的值。配置的PhyControl0.ctrl_dll_on值為'1'以開啟PHY DLL。

那開始配置PhyControl0的相關位,P614頁找到DRAM的暫存器配置表,找到有關PhyControl0的暫存器為PHYCONTROL0

OK,我們需要正確配置PhyControl0暫存器的ctrl_start_point和ctrl_inc這兩個位的值,OK,檢視暫存器的描述

ctrl_start_point和ctrl_inc這兩位晶片手冊上給的參考值為0x10,先配這兩位,則為:

ctrl_start_point: 0x10 ---- 10000(二進位制)

ctrl_inc: 0x10 ---- 10000(二進位制)

其餘的位全部配成0,最終為10000 00010000 00000000 ---- 0x00101000,程式碼如下:

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

第2步配置完成,接著往下看第3步--3.DQS Cleaning:依照時鐘頻率和記憶體的tAC引數正確設定PhyControl1.ctrl_shiftc and PhyControl1.ctrl_offsetc bit-fields位的值。

檢視PhyControl1的ctrl_shiftc和ctrl_offsetc這兩位的描述

我們的記憶體是DDR2-800,所以ctrl_shiftc配置為0x6 ---- 110,ctrl_offsetc的配置暫時參考三星的裸板引數配置為0,ctrl_ref配置為1000,整理程式碼如下:

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

按照第2步的要求,開啟PLL,將PhyControl0.ctrl_dll_on配置為1

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

繼續第4步--4.配置PhyControl0.ctrl_start位的值為'1'

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

後面的步驟,全部是按照三星的晶片手冊上的那28步來一步一步的在操作暫存器,沒有一步有漏掉,所以,對比著晶片手冊上的那28步一行一行的檢視程式碼就OK了。有一點,在配置完16-25步後,到第26步時--配置第26步--26.如果有兩組DDR晶片,重複14-25步配置chip1的記憶體,剛剛配置的是chip0,也就是第一組記憶體晶片。這裡就把第16-25步重新再做一次,初始化chip1就OK了。程式碼太多,這裡就不詳細重複了,我這裡參考的是三星的裸板的DDR原始碼。至此,DDR的原始碼也分析完成,下面,應該可以開始將這些移植進一個新的u-boot中去了。