? ? ? IMX6Q的内存初始化程序放在uboot的board/freescale/mx6q_sabresd/flash_header.S文件中,E9提供的源码中没有这个文件,只有一个编译结果flash_header.module,可以通过反汇编指令:arm-linux-objdump -S -EB flash_header.module,获取该模块中的内容并自己写一个flash_header.S文件。
? ? ? flash_header.S文件起始部分配置CPU内存引脚电气特性,如IO驱动电阻的值。驱动电阻值的大小需要根据PCB板中相应引脚走线阻抗设置。有些引脚引出来之后在TOP层或BOTTOM层走线,表层走线为微带线,微带线的阻抗一般是75ohm,对于这些引脚其驱动电阻值应设置在80ohm;有些引脚通过过孔直接引导内部走线层,带状线的阻抗一般为50ohm,这些引脚的驱动电阻值应设置在48ohm。IO驱动电阻的值必须仔细认真设置,特别是数据信号线和时钟信号线,因为它俩的频率最高。设置好IO驱动电阻值使信号在CPU端具有良好的阻抗特性,保证信号有良好的电气特性和质量,这是后期一切配置的基础条件,即时时序在匹配信号完整性受到干扰,内存仍然不能稳定运行。
? ? ? IMX6Q的DDR控制和时序寄存器主要是0x021b0000~0x021b0040(0x021b4000~0x021b4040)。控制寄存器如MMDC1_MDCTL(0x021b0000)比较直观,设置起来不难,这里主要讲时序配置方法和一些重要时序参数。由于处理器端时钟频率(528MHz)和DDR3运行时钟频率(667MHz)不同,处理器时序配置不能简单按照528MHz或667MHz的标准配置,也就是不能照抄DDR的数据手册进行配置。外频与内频不一致时,通常以频率主动方为设置单位,根据被动方的时钟要求设置主动方周期数。内存时序参数时以IMX6Q内存时钟周期1.894ns为基本单位,如667MHz的DDR3要求列地址选通脉冲时延CL=13.125ns,则MMDC0_MDCFG0(0x021b000c)寄存器的tCL设置为13.125ns/1.894ns=7cycles(MMDC0_MDCFG0[3:0]=4),这里如果简单粗暴直接使用DDR3时序参数CL=9cycles是不正确的。其他时序参数也要用类似方法计算获得。时序配置方面IMX6Q提供了时序计算工具I.MX6DQSDL DDR3 Script Aid V0.10,在该excel表格的Register Configuration项填好相应参数,会自动生成IMX6Q寄存器的配置,简化时序计算的过程。
? ? ? 虽然飞思卡尔提供了时序配置计算工具,但有几个重要的时序参数需要注意。在处理器端配置处理器寄存器中tCL=tRCD=tRP=7cycles,那么通过0x021b001c寄存器去配置内存芯片寄存器的时候,要求内存tCL=7cycles与处理器参数相同,即MR0[6:4,2]=6。处理器时序参数与内存时序参数不一致的时候,处理器将无法启动。Write Leveling、DQS Gating和数据读写校准这几个参数会影响系统稳定性,不合适的参数使系统启动的时候就出现内存错误,飞思卡尔提供DDR_Stress_Tester工具用于获取这些校准参数,但个人经验觉得这个工具得到的结果并不理想,沿用原本的参数会更稳定一些。
? ? ? 配置代码如下:
#include <config.h>
#include <asm/arch/mx6.h>
#ifdef CONFIG_FLASH_HEADER
#ifndef CONFIG_FLASH_HEADER_OFFSET
# error "Must define the offset of flash header"
#endif
#define CPU_2_BE_32(l)
((((l) & 0x000000FF) << 24) |
(((l) & 0x0000FF00) << 8) |
(((l) & 0x00FF0000) >> 8) |
(((l) & 0xFF000000) >> 24))
#define MXC_DCD_ITEM(i,addr,val)
dcd_node_##i:
.word CPU_2_BE_32(addr) ;
.word CPU_2_BE_32(val) ;
.section ".text.flasheader","x"
b _start
.org CONFIG_FLASH_HEADER_OFFSET
ivt_header: .word 0x402000D1 /* Tag=0xD1,Len=0x0020,Ver=0x40 */
app_code_jump_v: .word _start
reserv1: .word 0x0
dcd_ptr: .word dcd_hdr
boot_data_ptr: .word boot_data
self_ptr: .word ivt_header
app_code_csf: .word 0x0
reserv2: .word 0x0
boot_data: .word TEXT_BASE
image_len: .word _end_of_copy - TEXT_BASE + CONFIG_FLASH_HEADER_OFFSET
plugin: .word 0x0
dcd_hdr: .word 0x40a002D2 /* Tag=0xD2,Len=83*8 + 4 + 4,Ver=0x40 */
write_dcd_cmd: .word 0x049c02CC /* Tag=0xCC,Len=83*8 + 4,Param=0x04 */
/* DCD */
//corrected to 2GB MT41K256M16HA-125:E based on Sabre AI
MXC_DCD_ITEM(1,IOMUXC_BASE_ADDR + 0x798,0x000C0000)
MXC_DCD_ITEM(2,IOMUXC_BASE_ADDR + 0x758,0x00000000)
MXC_DCD_ITEM(3,IOMUXC_BASE_ADDR + 0x588,0x00000030) //CLK_0
MXC_DCD_ITEM(4,IOMUXC_BASE_ADDR + 0x594,0x00000030) //CLK_1
MXC_DCD_ITEM(5,IOMUXC_BASE_ADDR + 0x56c,0x00000030) //ADDR_OHM
MXC_DCD_ITEM(6,IOMUXC_BASE_ADDR + 0x578,0x00000030) //ADDR_OHM
MXC_DCD_ITEM(7,IOMUXC_BASE_ADDR + 0x74c,0x00000030) //ADDR_OHM
MXC_DCD_ITEM(8,IOMUXC_BASE_ADDR + 0x57c,0x00000030) //XIA CMOS_RSET
MXC_DCD_ITEM(9,IOMUXC_BASE_ADDR + 0x58c,0x00000000)
MXC_DCD_ITEM(10,IOMUXC_BASE_ADDR + 0x59c,0x00000030)
MXC_DCD_ITEM(11,IOMUXC_BASE_ADDR + 0x5a0,0x00000030)
MXC_DCD_ITEM(12,IOMUXC_BASE_ADDR + 0x78c,0x00000030)
MXC_DCD_ITEM(13,IOMUXC_BASE_ADDR + 0x750,0x00020000) //XIA DQS_DIFF
MXC_DCD_ITEM(14,IOMUXC_BASE_ADDR + 0x5a8,0x00000018) //120ohm效果变差,60ohm效果更差
MXC_DCD_ITEM(15,IOMUXC_BASE_ADDR + 0x5b0,0x00000018) //DQS
MXC_DCD_ITEM(16,IOMUXC_BASE_ADDR + 0x524,0x00000018) //DQS
MXC_DCD_ITEM(17,IOMUXC_BASE_ADDR + 0x51c,0x00000018) //DQS
MXC_DCD_ITEM(18,IOMUXC_BASE_ADDR + 0x518,0x00000018) //DQS
MXC_DCD_ITEM(19,IOMUXC_BASE_ADDR + 0x50c,0x00000018) //DQS
MXC_DCD_ITEM(20,IOMUXC_BASE_ADDR + 0x5b8,0x00000018) //DQS
MXC_DCD_ITEM(21,IOMUXC_BASE_ADDR + 0x5c0,0x00000018) //DQS
MXC_DCD_ITEM(22,IOMUXC_BASE_ADDR + 0x774,0x00020000) //DP_DIFF
MXC_DCD_ITEM(23,IOMUXC_BASE_ADDR + 0x784,0x00000018) //DP
MXC_DCD_ITEM(24,IOMUXC_BASE_ADDR + 0x788,0x00000018) //DP
MXC_DCD_ITEM(25,IOMUXC_BASE_ADDR + 0x794,0x00000018) //DP
MXC_DCD_ITEM(26,IOMUXC_BASE_ADDR + 0x79c,0x00000018) //DP
MXC_DCD_ITEM(27,IOMUXC_BASE_ADDR + 0x7a0,0x00000018) //DP
MXC_DCD_ITEM(28,IOMUXC_BASE_ADDR + 0x7a4,0x00000018) //DP
MXC_DCD_ITEM(29,IOMUXC_BASE_ADDR + 0x7a8,0x00000018) //DP
MXC_DCD_ITEM(30,IOMUXC_BASE_ADDR + 0x748,0x00000018) //DP
MXC_DCD_ITEM(31,IOMUXC_BASE_ADDR + 0x5ac,0x00000018) //DQM
MXC_DCD_ITEM(32,IOMUXC_BASE_ADDR + 0x5b4,0x00000018) //DQM
MXC_DCD_ITEM(33,IOMUXC_BASE_ADDR + 0x528,0x00000018) //DQM
MXC_DCD_ITEM(34,IOMUXC_BASE_ADDR + 0x520,0x00000018) //DQM
MXC_DCD_ITEM(35,IOMUXC_BASE_ADDR + 0x514,0x00000018) //DQM
MXC_DCD_ITEM(36,IOMUXC_BASE_ADDR + 0x510,0x00000018) //DQM
MXC_DCD_ITEM(37,IOMUXC_BASE_ADDR + 0x5bc,0x00000018) //DQM
MXC_DCD_ITEM(38,IOMUXC_BASE_ADDR + 0x5c4,0x00000018) //DQM
MXC_DCD_ITEM(39,MMDC_P0_BASE_ADDR + 0x800,0xA1390003)
# write leveling
MXC_DCD_ITEM(40,MMDC_P0_BASE_ADDR + 0x80c,0x001F001F) //Bety1-0
MXC_DCD_ITEM(41,MMDC_P0_BASE_ADDR + 0x810,0x001F001F) //Bety3-2
MXC_DCD_ITEM(42,MMDC_P1_BASE_ADDR + 0x80c,0x001F001F) //Bety5-4
MXC_DCD_ITEM(43,MMDC_P1_BASE_ADDR + 0x810,0x001F001F) //Bety7-6
# DQS gating,read delay,write delay calibration values
MXC_DCD_ITEM(44,MMDC_P0_BASE_ADDR + 0x83c,0x4333033f)
MXC_DCD_ITEM(45,MMDC_P0_BASE_ADDR + 0x840,0x032c031d)
MXC_DCD_ITEM(46,MMDC_P1_BASE_ADDR + 0x83C,0x43200332)
MXC_DCD_ITEM(47,MMDC_P1_BASE_ADDR + 0x840,0x031a026a)
MXC_DCD_ITEM(48,MMDC_P0_BASE_ADDR + 0x848,0x4d464746)
MXC_DCD_ITEM(49,MMDC_P1_BASE_ADDR + 0x848,0x47453f4d)
MXC_DCD_ITEM(50,MMDC_P0_BASE_ADDR + 0x850,0x3e434440)
MXC_DCD_ITEM(51,MMDC_P1_BASE_ADDR + 0x850,0x47384839)
MXC_DCD_ITEM(52,MMDC_P0_BASE_ADDR + 0x81c,0x33333333)
MXC_DCD_ITEM(53,MMDC_P0_BASE_ADDR + 0x820,0x33333333)
MXC_DCD_ITEM(54,MMDC_P0_BASE_ADDR + 0x824,0x33333333)
MXC_DCD_ITEM(55,MMDC_P0_BASE_ADDR + 0x828,0x33333333)
MXC_DCD_ITEM(56,MMDC_P1_BASE_ADDR + 0x81c,0x33333333)
MXC_DCD_ITEM(57,MMDC_P1_BASE_ADDR + 0x820,0x33333333)
MXC_DCD_ITEM(58,MMDC_P1_BASE_ADDR + 0x824,0x33333333)
MXC_DCD_ITEM(59,MMDC_P1_BASE_ADDR + 0x828,0x33333333)
MXC_DCD_ITEM(60,MMDC_P0_BASE_ADDR + 0x8b8,0x00000800)
MXC_DCD_ITEM(61,MMDC_P1_BASE_ADDR + 0x8b8,0x00000800)
MXC_DCD_ITEM(62,MMDC_P0_BASE_ADDR + 0x004,0x00020036)
MXC_DCD_ITEM(63,MMDC_P0_BASE_ADDR + 0x008,0x09444040)
MXC_DCD_ITEM(64,MMDC_P0_BASE_ADDR + 0x00c,0x54597974)
MXC_DCD_ITEM(65,MMDC_P0_BASE_ADDR + 0x010,0xDB338F64)
MXC_DCD_ITEM(66,MMDC_P0_BASE_ADDR + 0x014,0x01FF00DB)
MXC_DCD_ITEM(67,MMDC_P0_BASE_ADDR + 0x018,0x00001740)
MXC_DCD_ITEM(68,MMDC_P0_BASE_ADDR + 0x01c,0x00008000)
MXC_DCD_ITEM(69,MMDC_P0_BASE_ADDR + 0x02c,0x000026D2)
MXC_DCD_ITEM(70,MMDC_P0_BASE_ADDR + 0x030,0x00591023)
MXC_DCD_ITEM(71,MMDC_P0_BASE_ADDR + 0x040,0x00000027)
MXC_DCD_ITEM(72,MMDC_P0_BASE_ADDR + 0x000,0x831A0000) //col=10,row=14 128M x 16b = 256MB
MXC_DCD_ITEM(73,0x04088032) //Rtt_WR=120ohm
MXC_DCD_ITEM(74,0x00008033)
MXC_DCD_ITEM(75,0x00048031) //Rtt_NOM=60ohm
MXC_DCD_ITEM(76,0x09308030) //内存芯片的CAS Latency要和处理器相同
MXC_DCD_ITEM(77,0x04008040)
MXC_DCD_ITEM(78,MMDC_P0_BASE_ADDR + 0x020,0x00007800) //刷新频率
MXC_DCD_ITEM(79,MMDC_P0_BASE_ADDR + 0x818,0x00011117) //Rtt_NOM=120ohm稳定些
MXC_DCD_ITEM(80,MMDC_P1_BASE_ADDR + 0x818,0x00011117)
MXC_DCD_ITEM(81,0x00025576)
MXC_DCD_ITEM(82,MMDC_P0_BASE_ADDR + 0x404,0x00011006)
MXC_DCD_ITEM(83,0x00000000)
#endif