S5PV210的內存分配研究分析


S5PV210內存一般會使用SDRAM和DDR2 (DDR SDRAM),SDRAM的uboot啟動網絡已經有很多資料的,對於DDR2還有有很多疑惑,如果有錯誤的地方,請大家一定指出,醍醐灌頂,不勝感激。

1、S5PV210的memory map(物理地址)

如下圖:左圖是整個芯片的內存空間(物理地址),右圖是iROM部分的內存空間(BL0的地址貌似不是物理地址==)

 
尋址空間是4GB=232
前512是Boot area
接下是512M的DRAM0通道和512M的DRAM1通道,是存儲器的地址,用於DDR2 RAM尋址的,共1GB
后面是6個128M的SROM (Bank0~Bank5),用於總線型設備尋址的
接着256M的Nand和OneNand控制器寄存器和256M的MP3_SRAM輸出緩存
包含64KB IROM (BL0) 和 96KB 片內SRAM (BL1 BL2)做為internal memory,一般是啟動時用到的
后面的128M DMZ ROM還沒搞明白是什么
最后面512M就是SFR了(特殊功能寄存器)
 

2、U-Boot內存分配圖

 

  

 

2.u-boot映像的地址0並非指物理地址0,由不同的啟動方式映射到不同的地址。例如v210是映射到0xD0000000處的irom。

3.TEXT_BASE等指向SDRAM的地址均為虛擬地址。

4.TEXT_BASE為頂層Makefile中定義的,例如三星官方BSP中定義的是0xC3E00000,它是程序實際的鏈接首地址。

5.SDRAM_BASE被MMU映射在0xC0000000。

6._end和__bss_start為鏈接腳本文件中最后定義的bss段,在鏈接時確定,並與u-boot映像編譯在一起。

7.在bl1段運行時,u-boot映像被復制到TEXT_BASE開始的地址處。

8. u-boot分配用戶棧頂的代碼為:
 ldr r0, _TEXT_BASE  /* upper 128 KiB: relocated uboot   */      將0xc3e00000加載到r0
 sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */      r0減去0x4000的malloc域
 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */      r0減去128字節的全局結構體
#if defined(CONFIG_USE_IRQ)
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)   如果用戶有使用IRQ,再減去2*4*1024的中斷棧空間
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */      為取址終止異常預留3個字空間后設置好用戶sp

 
 3、DDR2 內存分配映射
S5PV210有兩個獨立的內存控制器:DMC0和DMC1,每個控制器又有兩個片選:CS0和CS1。它可以支持16bits和32bits的內存。兩個控制器對應的地址空間是
DMC0 0x2000_0000 ~ 0x3FFF_FFFF             512MB
DMC1 0x4000_0000 ~ 0x7FFF_FFFF             512MB
內存控制器的配置寄存器也分為兩塊,
DMC0 0xF000_xxxx
DMC1 0xF140_xxxx
這一塊主要需要設置的寄存器設置是:MEMCONTROL、MEMCONFIG0、MEMCONFIG1
開發板用的是4片1Gbit x16位的內存,兩片兩片按數據線的高16bits和低16bits組成兩組32bits的256M,分別掛載了DMC0的CS0和DMC1的CS1。
 
MEMCONTROL里面有個num_chip,使用了幾個CS信號。兩個DDR控制器只用了一個CS0,對於210來說就是一片,所以設置為 0x0 = 1 chip
然后 MEMCONTROL的mem_width,設為 0x2 = 32-bit 。
MEMCONFIG0和MEMCONFIG1是一樣的,一個設置相應控制器的CS0,一個設置CS1。
 
這兩個寄存器合起來,可以決定DMC0/DMC1 CS0和CS1下掛着的內存對應哪一段內存地址。我理解的是當你要放問地址0x21xx_xxxx的地址的時候,DMC0會將訪問地址的高8bits 0x21和chip_mask求與,要是等於chip_base,他就會使用相應的控制器的相應的片選去讀數據。就像假如
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf8
DMC0_MEMCONFIG1   chip_base =  0x28      chip_mask=0xf8
當你要訪問的地址是 0x22xx_xxxx的時候,  (0x22 & 0xf8) ==  0x20,所以使用CS0
那要是  0x2exx_xxxx呢?     (0x2e & 0xf8) == 0x28 ,當然使用CS1了。
也就是說CS0對應的是 0x2000_0000 ~ 0x27ff_ffff,128M
CS1對應的是 0x2800_0000 ~ 0x28ff_ffff,128M
同樣的每個CS下都是256M呢?
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf0          // 0x2000_0000 ~ 0x2fff_ffff     256M
DMC0_MEMCONFIG1   chip_base =  0x30      chip_mask=0xf0          // 0x3000_0000 ~ 0x3fff_ffff     256M
DMC0和DMC1配置一樣,但是DMC0只能配置為0x2000_0000~0x3fff_ffff的空間,DMC1只能配置為0x4000_0000~0x5fff_ffff的空間。這是DMC的地址空間決定的,我就是在這郁悶了兩天。
我的板子上面DMC0和DMC1上都只使用了CS0,然后我的設置就是
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf0          // 0x2000_0000 ~ 0x2fff_ffff     256M
DMC1_MEMCONFIG0   chip_base =  0x40      chip_mask=0xf0          // 0x4000_0000 ~ 0x4fff_ffff     256M  注意,DMC1只能從0x4000_0000開始。
問題又來了,這樣內存地址空間不就不連續了嘛?
內存的地址空間不從0x2000_0000開始,從0x3000_0000開始,不就正好接上DMC1的了。只是CONFIG_SYS_SDRAM_BASE和CONFIG_SYS_TEXT_BASE相應的改一下:
DMC0_MEMCONFIG0   chip_base =  0x30      chip_mask=0xf0          // 0x3000_0000 ~ 0x3fff_ffff     256M
DMC1_MEMCONFIG0   chip_base =  0x40      chip_mask=0xf0          // 0x4000_0000 ~ 0x4fff_ffff     256M
 
難點:關於地址映射

如果設置chip_base為0x20:

(1)我們掛載的內存為128M,那么這個chip_mask應該設置為0xF8

(2)我們掛載256M內存時,chip_mask應該設置為0xF0

(3)我們掛載512M時,chip_mask應該設置為0xE0

(4)我們掛載1GB內存時,chip_mask就應該設置為0xC0。

以DMC0為例,當DMC0接收到來自AXI的0x2000,0000~0x3fff,ffff內的地址時,會作如下處理:

(1)將AXI地址的高8位與chip_mask相與得到結果,記為X。

(2)將X分別與MEMCONFIG0和MEMCONFIG1的chip_base相比較,如果相等,則打開相應的片選。

假如掛載的內存為128M,且CS0和CS1上分別掛了一片,那么128M=128*1024*1024=0x8000000,則128M內存的偏移范圍應該是0x0000,0000~0x07ff,ffff,高位剩余5位,那么,我們把MEMCONFIG0的chip_base設置為0x20,chip_mask設置為0xF8,為了保持內存連續,則需要將MEMCONFIG1的chip_base設置為0x28,chip_mask設置為0xF8,當AXI發來的地址為0x23xx,xxxx時,0x23&0xF8得到0x20,所以,會打開片選CS0,當AXI發來的地址為0x28xx,xxxx時,0x28&0xF8得到0x28,所以,會打開片選CS1,依此類推。

特別的,當載在的內存芯片為8bank(8bank內存芯片一般為14/15行地址,10列地址,即容量一般為512M或者1G)時,由於CS1為bank2引腳,為了保持CS0時鍾處於片選狀態,對於512M內存來講需要將chip_mask設置為0xE0,這是因為512M=512*1024*1024=0x2000,0000,也就是說,512M內存的偏移應該為0x0000,0000~0x1fff,ffff,所以高位剩余3位,即0xE0,當然了,如果內存為1G=1024*1024*1024=0x4000,0000,即偏移為0x0000,0000~0x3fff,ffff,高位剩余2為,故設置chip_mask為0xC0。這樣,就會計算偏移這兩個值了。

4、 配置流程

內存芯片的配置比較復雜,好在芯片手冊上給出了常用內存類型的初始化序列,TQ210的內存是DDR2的,可以按照如下順序進行初始化: 

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 memo ry 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. 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.
上面就是手冊上給出的DDR2型內存芯片的初始化序列,但是單純的根據上面的步驟配置可能有些困難,這時,我們可以參考u-boot的內存初始化代碼來初始化內存,最后你會發現u-boot的操作順序跟上面是完全一致的。

 

5、代碼的鏈接地址和運行地址等注意事項

配置好內存的代碼燒寫到Nand運行是正常的,但是用USB方式啟動時不正常,目前還沒有找到原因,如果有朋友解決了或者有其他問題請留言相告,在這里先說聲謝謝。

現在找到原因了,原來S5PV210的USB啟動過程跟Nand啟動方式不一樣,S5PV210以USB方式啟動時會先將三星提供的一個固件程序下載到0xd0020010處運行,然后,再將用戶代碼下載0x23e00000處運行,也就是說,固件程序完成了內存的初始化,因為我們的代碼位於0x23e00000處。而我們的代碼中再次配置內存時會重置內存,下載到內存中的代碼也就丟失了,所以程序執行到內存初始化函數就會掛掉。

為了證明上面的假設,我在代碼中加上一段程序,該程序將內存的中代碼拷貝到iram的16K以后的位置上(直接拷貝到0xd0020000處有問題,我是拷貝到了0xd0024000處,現在還不知道什么原因),然后將代碼跳轉到IRAM中,如果代碼可以正常運行就可以證明內存初始化部分正常,實驗結果是肯定的,下面總結下:

S5PV210以USB方式啟動時用戶代碼是下載到內存中的(0x23e00000處),要使代碼以USB方式啟動時正常運行,應該注意以下兩點:

(1)如果是位置相關的代碼,連接地址應該鏈接到0x23e00000,如果是位置無關碼,可以隨便指定連接地址。
(2)用戶代碼需要檢驗自己運行時的位置,如果運行在內存中則需跳過內存初始化,根據需要決定是否需要代碼重定位。

 

參考網址:http://blog.chinaunix.net/uid-122754-id-3144920.html

       http://www.cnblogs.com/Efronc/archive/2012/03/01/2375578.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM