嵌入式Linux学习笔记(基于S5PV210 TQ210)之裸机编程ddr

2019-07-13 06:54发布

在初学时,对于DDR初始化即便是按照S5PV210芯片手册列出的DDR初始化步骤,也感觉很多参数无法设置。在按照S5P芯片手册中列出的DDR初始化步骤时要参考如下文档:S5P210芯片手册,DDR2操作时序规范(三星)和K4T1G084QF芯片的资料(此3个)。由于查看网上众多资料,几乎没看到哪一位能把它的配置讲清楚的,有些寄存器的参数不知由来。下面是我对网上相关资料的总结与加工。
S5PV210芯片手册列出的DDR初始化步骤:

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_pointand PhyControl0.ctrl_incbit-fields to correct value according to clock  
  frequency. Set the PhyControl0.ctrl_dll_onbit-field to ‘1’ to turn on the PHY DLL.
3.  DQS Cleaning: Set the PhyControl1.ctrl_shiftcand PhyControl1.ctrl_offsetcbit-fields to correct value  
  according to clock frequency and memory tAC parameters. 
4. Set the PhyControl0.ctrl_startbit-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 MemConfig0register. If there are two external memory chips, set the MemConfig1 register.
8. Set the PrechConfigand PwrdnConfigregisters. 
9. Set the TimingAref, TimingRow, TimingDataand TimingPowerregisters according to memory AC  
  parameters. 
10. If QoS scheme is required, set the QosControl0~15and QosConfig0~15registers. 
11. Wait for the PhyStatus0.ctrl_lockedbit-fields to change to ‘1’. Check whether PHY DLL is locked.
12. PHY DLL compensates the changes of delay amountcaused 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_forcebit-field to correct value  
  according to the PhyStatus0.ctrl_lock_value[9:2]bit-field to fix delay amount. Clear the  
PhyControl0.ctrl_dll_onbit-field to turn off PHY DLL. 
13. Confirm whether stable clock is issued minimum 200us after power on 
14. Issue a NOPcommand using the DirectCmdregister to assert and to hold CKE to a logic high level.15. Wait for minimum 400ns.
16. Issue a PALLcommand using the DirectCmdregister. 
17. Issue an EMRS2command using the DirectCmdregister to program the operating parameters.
18. Issue an EMRS3command using the DirectCmdregister to program the operating parameters.
19. Issue an EMRScommand using the DirectCmdregister to enable the memory DLLs. 
20. Issue a MRScommand using the DirectCmdregister to reset the memory DLL. 
21. Issue a PALLcommand using the DirectCmdregister. 
22. Issue two Auto Refreshcommands using the DirectCmdregister. 
23. Issue a MRScommand using the DirectCmdregister to program the operating parameters without resetting  
the memory DLL. 
24. Wait for minimum 200 clock cycles. 
25. Issue an EMRScommand using the DirectCmdregister to program the operating parameters. If OCD  
  calibration is not used, issue an EMRScommand 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 ConControlto turn on an auto refresh counter. 28. If power down modes is required, set the  
MemControlregisters. 
15. Wait for minimum 400ns. 
16. Issue a PALLcommand using the DirectCmdregister. 
17. Issue an EMRS2command using the DirectCmdregister to program the operating parameters.
18. Issue an EMRS3command using the DirectCmdregister to program the operating parameters.
19. Issue an EMRScommand using the DirectCmdregister to enable the memory DLLs. 
20. Issue a MRScommand using the DirectCmdregister to reset the memory DLL. 
21. Issue a PALLcommand using the DirectCmdregister. 
22. Issue two Auto Refreshcommands using the DirectCmdregister. 
23. Issue a MRScommand using the DirectCmdregister to program the operating parameters without resetting  
the memory DLL. 
24. Wait for minimum 200 clock cycles. 
25. Issue an EMRScommand using the DirectCmdregister to program the operating parameters. If OCD  
  calibration is not used, issue an EMRScommand 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 ConControlto turn on an auto refresh counter. 28. If power down modes is required, set the  
MemControlregisters. 





首先贴出TQ210的内存接线图:

S5PV210有2个独立的DRAM控制器和端口(引脚):DMC0和DMC1。DMC0最大支持512MByte,DMC1最大支持1GByte,两个控制器必须使用相同类型的内存。

TQ210开发板板载8片K4T1G084QQ,每片128MByte,共计1GByte内存。

其中4片挂接在DMC0,使用相同的地址线xm1ADDR[13:0],串联使用数据线xm1DATA[31:0],数据位宽32位;

另外4片挂接在DMC1,使用相同的地址线xm2ADDR[13:0],串联使用数据线xm2DATA[31:0],数据位宽32位;


下面贴出S5PV210给出的芯片接线配置方案


从K4T1G084QQ芯片手册得知该芯片具有8个BANK,需要3根BANK选择线,具有14根地址线(其中14根行地址和10根列地址复用),见下图中的128Mbx8那列

所以使用的是S5PV210中给出的方案3,其中使用一根片选Xm1(2)CSn[0]

关键寄存器配置说明(DMC0和DMC1的配置完全一样,除了AXI Base Address):

MEMCONTROL


num_chip[19:16]:从上面的配置方案3得出这里配置为0x0 = 1 chip,因为只使用了一个片选信号。

mem_width[15:12]:数据位宽0x2 = 32-bit




MEMCONFIG0

chip_base[31:24]:S5PV210可以自定义内存基地址,这里使用默认的0x20,

从S5PV210芯片手册的2.1  MEMORY ADDRESS MAP 一节可以得知DRAM0的地址范围为0x2000_0000~0x3FFF_FFFF,DRAM1的地址范围为0x4000_0000~0x7FFF_FFFF。


chip_mask[23:16]:DMC将AXI发来的地址的高8位与chip_mask按位与,如果与chip_base相等,则打开相应的片选。


例如:

DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xF8

DMC0_MEMCONFIG1   chip_base =  0x28      chip_mask=0xF8
当AXI发来0x2000_0000~0x27FF_FFFF(128MByte)时,高8位按位与0xF8=0x20,则打开DMC0的片选CS0,
当AXI发来0x2800_0000~0x27FF_FFFF(128MByte)时,高8位按位与0xF8=0x28,则打开DMC0的片选CS1,

TQ210开发板只有一个片选CS0,DMC0的地址范围0x2000_0000~0x3FFF_FFFF(512MByte),DMC1的地址范围0x4000_0000~0x5FFF_FFFF(512MByte),


DMC0_MEMCONFIG0  chip_base =  0x20     chip_mask=0xE0


DMC1_MEMCONFIG0  chip_base =  0x40     chip_mask=0xE0

当AXI发来0x2000_0000~0x3FFF_FFFF时,高8位按位与0xE0=0x20,则打开DMC0的片选CS0,
当AXI发来0x4000_0000~0x5FFF_FFFF时,高8位按位与0xE0=0x40,则打开DMC1的片选CS0,
下面只提供DDR相关初始化代码: define MP1_0DRV (*(volatile unsigned long*)0xE02003CC)
#define MP1_1DRV (*(volatile unsigned long*)0xE02003EC)
#define MP1_2DRV (*(volatile unsigned long*)0xE020040C)
#define MP1_3DRV (*(volatile unsigned long*)0xE020042C)
#define MP1_4DRV (*(volatile unsigned long*)0xE020044C)
#define MP1_5DRV (*(volatile unsigned long*)0xE020046C)
#define MP1_6DRV (*(volatile unsigned long*)0xE020048C)
#define MP1_7DRV (*(volatile unsigned long*)0xE02004AC)
#define MP1_8DRV (*(volatile unsigned long*)0xE02004CC)


#define DMC0_BASE 0xF0000000
#define DMC1_BASE 0xF1400000


#define DMC0_CONCONTROL *((volatile unsigned int *)(DMC0_BASE + 0x00))
#define DMC0_MEMCONTROL *((volatile unsigned int *)(DMC0_BASE + 0x04))
#define DMC0_MEMCONFIG0 *((volatile unsigned int *)(DMC0_BASE + 0x08))
#define DMC0_MEMCONFIG1 *((volatile unsigned int *)(DMC0_BASE + 0x0C))
#define DMC0_DIRECTCMD *((volatile unsigned int *)(DMC0_BASE + 0x10))
#define DMC0_PRECHCONFIG *((volatile unsigned int *)(DMC0_BASE + 0x14))
#define DMC0_PHYCONTROL0 *((volatile unsigned int *)(DMC0_BASE + 0x18))
#define DMC0_PHYCONTROL1 *((volatile unsigned int *)(DMC0_BASE + 0x1C))
#define DMC0_PWRDNCONFIG *((volatile unsigned int *)(DMC0_BASE + 0x28))
#define DMC0_TIMINGAREF         *((volatile unsigned int *)(DMC0_BASE + 0x30))
#define DMC0_TIMINGROW *((volatile unsigned int *)(DMC0_BASE + 0x34))
#define DMC0_TIMINGDATA         *((volatile unsigned int *)(DMC0_BASE + 0x38))
#define DMC0_TIMINGPOWER *((volatile unsigned int *)(DMC0_BASE + 0x3C))
#define DMC0_PHYSTATUS *((volatile unsigned int *)(DMC0_BASE + 0x40))
#define DMC0_CHIP0STATUS   *((volatile unsigned int *)(DMC0_BASE + 0x48))
#define DMC0_CHIP1STATUS   *((volatile unsigned int *)(DMC0_BASE + 0x4C))
#define DMC0_AREFSTATUS   *((volatile unsigned int *)(DMC0_BASE + 0x50))
#define DMC0_MRSTATUS *((volatile unsigned int *)(DMC0_BASE + 0x54))


#define DMC1_CONCONTROL *((volatile unsigned int *)(DMC1_BASE + 0x00))
#define DMC1_MEMCONTROL *((volatile unsigned int *)(DMC1_BASE + 0x04))
#define DMC1_MEMCONFIG0 *((volatile unsigned int *)(DMC1_BASE + 0x08))
#define DMC1_MEMCONFIG1 *((volatile unsigned int *)(DMC1_BASE + 0x0C))
#define DMC1_DIRECTCMD *((volatile unsigned int *)(DMC1_BASE + 0x10))
#define DMC1_PRECHCONFIG *((volatile unsigned int *)(DMC1_BASE + 0x14))
#define DMC1_PHYCONTROL0 *((volatile unsigned int *)(DMC1_BASE + 0x18))
#define DMC1_PHYCONTROL1 *((volatile unsigned int *)(DMC1_BASE + 0x1C))
#define DMC1_PWRDNCONFIG *((volatile unsigned int *)(DMC1_BASE + 0x28))
#define DMC1_TIMINGAREF         *((volatile unsigned int *)(DMC1_BASE + 0x30))
#define DMC1_TIMINGROW *((volatile unsigned int *)(DMC1_BASE + 0x34))
#define DMC1_TIMINGDATA         *((volatile unsigned int *)(DMC1_BASE + 0x38))
#define DMC1_TIMINGPOWER *((volatile unsigned int *)(DMC1_BASE + 0x3C))
#define DMC1_PHYSTATUS *((volatile unsigned int *)(DMC1_BASE + 0x40))
#define DMC1_CHIP0STATUS    *((volatile unsigned int *)(DMC1_BASE + 0x48))
#define DMC1_CHIP1STATUS   *((volatile unsigned int *)(DMC1_BASE + 0x4C))
#define DMC1_AREFSTATUS   *((volatile unsigned int *)(DMC1_BASE + 0x50))
#define DMC1_MRSTATUS *((volatile unsigned int *)(DMC1_BASE + 0x54))




void ddr_init()
{
/* DMC0 */
DMC0_PHYCONTROL0 = 0x00101000;
DMC0_PHYCONTROL0 = 0x00101002;/* DLL on */
DMC0_PHYCONTROL1 = 0x00000086;               /*reference to the u-boot源码的cup_init.S*/
DMC0_PHYCONTROL0 = 0x00101003;/* DLL start */


while ((DMC0_PHYSTATUS & 0x7) != 0x7);     /* wait DLL locked */


DMC0_CONCONTROL = 0x0FFF2350;/* Auto Refresh Counter should be off */
DMC0_MEMCONTROL = 0x00202430;/* Dynamic power down should be off */
DMC0_MEMCONFIG0 = 0x20E01323;     


DMC0_PRECHCONFIG = 0xFF000000;
DMC0_PWRDNCONFIG = 0xFFFF00FF;
        /*tCK为时钟周期mlck=5ns,下面的四个寄存器配置参考S5P210芯片手册和K4T1G084QQ芯片的资料*/
DMC0_TIMINGAREF = 0x00000618; /* 7.8us * 200MHz = 1560 = 0x618  */
DMC0_TIMINGROW = 0x19233309;                        /*00011010,0010,0011,0011,001100,001001*/
DMC0_TIMINGDATA = 0x23240204;  /*0010,0011,0010,0100,0000,0010,0000,0100 */
DMC0_TIMINGPOWER = 0x09C80232;  /*00,001001(00),11001000,00000010,0011,0010 */

         /*下面DMC0_DIRECTCMD配置见DDR2操作时序规范.pdf和S5P210芯片手册*/
DMC0_DIRECTCMD = 0x07000000;/* NOP */
DMC0_DIRECTCMD = 0x01000000;/* PALL */
DMC0_DIRECTCMD = 0x00020000;/* EMRS2 */
DMC0_DIRECTCMD = 0x00030000;/* EMRS3 */
DMC0_DIRECTCMD = 0x00010400;/* EMRS enable DLL */
DMC0_DIRECTCMD = 0x00000542;/* DLL reset */
DMC0_DIRECTCMD = 0x01000000; /* PALL */
DMC0_DIRECTCMD = 0x05000000;/* auto refresh */
DMC0_DIRECTCMD = 0x05000000;/* auto refresh */
DMC0_DIRECTCMD = 0x00000442;/* DLL unreset */
DMC0_DIRECTCMD = 0x00010780;/* OCD default */
DMC0_DIRECTCMD = 0x00010400;/* OCD exit */


DMC0_CONCONTROL = 0x0FF02030;/* auto refresh on */
DMC0_PWRDNCONFIG = 0xFFFF00FF;
DMC0_MEMCONTROL = 0x00202400;


/* DMC1 */
DMC1_PHYCONTROL0 = 0x00101000;
DMC1_PHYCONTROL0 = 0x00101002;
DMC1_PHYCONTROL1 = 0x86;
DMC1_PHYCONTROL0 = 0x00101003;


while((DMC0_PHYSTATUS&0x7) != 0x7);


DMC1_CONCONTROL = 0x0FFF2350;/* Auto Refresh Counter should be off */
DMC1_MEMCONTROL = 0x00202430;/* Dynamic power down should be off */
DMC1_MEMCONFIG0 = 0x40E01323;    


DMC1_PRECHCONFIG = 0xFF000000;
DMC1_PWRDNCONFIG = 0xFFFF00FF;


DMC1_TIMINGAREF = 0x00000618;/* 7.8us * 200MHz = 1560 = 0x618  */
DMC1_TIMINGROW = 0x19233309;
DMC1_TIMINGDATA = 0x23240204;
DMC1_TIMINGPOWER = 0x09C80232;


DMC1_DIRECTCMD = 0x07000000;
DMC1_DIRECTCMD = 0x01000000;
DMC1_DIRECTCMD = 0x00020000;
DMC1_DIRECTCMD = 0x00030000;
DMC1_DIRECTCMD = 0x00010400;
DMC1_DIRECTCMD = 0x00000542;
DMC1_DIRECTCMD = 0x01000000;
DMC1_DIRECTCMD = 0x05000000;
DMC1_DIRECTCMD = 0x05000000;
DMC1_DIRECTCMD = 0x00000442;
DMC1_DIRECTCMD = 0x00010780;
DMC1_DIRECTCMD = 0x00010400;


DMC1_CONCONTROL = 0x0FF02030;
DMC1_PWRDNCONFIG = 0xFFFF00FF;
DMC1_MEMCONTROL = 0x00202400;
}

参考博客:点击打开链接
相关代码及资料为:DDR初始化代码及相关资料.zip网址为:http://pan.baidu.com/s/1o6sN11o