DDR初始化
一、DDR的容量
我们在DDR芯片资料上的开头都会标明DDR的容量:如我们的手上的OK6410A的DDR(K4X1G163PC),它的芯片资料上写的是32M x16 Mobile-DDR SDRAM。但是厂家跟说ok6410a有128M的容量。看到这里不禁就个疑问了。芯片上明明写是32M为什么,FL说是128M呢。在这里就能给你答案,板子上有两片DDR。那它的容量是32Mx16位x2=32Mx32位。它这里32M指的32位数据,而我们通常所讲的容量是以字节为单位,而不是字为单位。32M的32位就等于32Mx4的8位。这样就根FL给出的数据一样了。所以我们以后在看内存容量时一定要注意到这一点。
二、DDR信号
--------------------------------------------------------------------------------
信号名 作用
-----------------------------------------------------------------------------------
CK,nCK 差分时钟
nCS 片选信号 低电平有效
CKE 时钟使能 高电平有效
A0~A12 地址线 行列地址线复用,行地址:A0~A12 列地址:A0~A9
BA0~BA1 BANK选择 00 01 10 11。第个BAND为4M
nRAS 行地址锁存 低电平有效
nCAS 列地址锁存 低电平有效
nWE 读写使能 低电平有效
L(U)DM 数据屏蔽
L(U)DQS 数据选通
DQ0~DQ15 数据线
VDD/VSS 电源与地
VDDQ/VSSQ 数据输出电源与地
-----------------------------------------------------------------------------------------------------------------------------------------------
三、S3C6410的DRAM控制器初始化
DRAM控制器初始化流程:
(1)以‘3’b100’执行memc_cmd,使得DRAM 控制器输入‘配置’状态。
(2)写存储器时间参数,芯片配置和ID 配置寄存器。
(3)等待200μs 来使SDRAM 电源和时钟稳定。当CPU 开始工作时,电源和时钟已经被稳定下来。
(4)执行存储器初始化顺序。
(5)以‘3’b000’执行memc_cmd,使得DRAM 控制器输入‘准备’状态。
(6)在memc_stat 中检查存储器状态域,直到存储器状态变为‘2’b01’,即‘准备’。
DDR 初始化流程:
(1)在direct_cmd,以‘2’b10’执行mem_cmd,使得DRAM 控制器产生‘NOP’存储器命令。
(2)在direct_cmd,以‘2’b00’执行mem_cmd,使得DRAM 控制器产生‘Prechargeall’存储器命令。
(3)在direct_cmd,以‘2’b11’执行mem_cmd,使得DRAM 控制器产生‘Autorefresh’存储器命令。
(4)在direct_cmd,以‘2’b10’执行mem_cmd,使得DRAM 控制器产生‘MRS’存储器命令。
EMRS 块地址必须被设置。
(5)在direct_cmd,以‘2’b10’执行mem_cmd,使得DRAM 控制器产生‘MRS’存储器命令。
MRS 块地址必须被设置。
(6)在direct_cmd,以‘2’b11’执行mem_cmd,使得DRAM 控制器产生‘Autorefresh’存储器命令。
(7)在direct_cmd,以‘2’b11’执行mem_cmd,使得DRAM 控制器产生‘Autorefresh’存储器命令。
(8)在direct_cmd,以‘2’b11’执行mem_cmd,使得DRAM 控制器产生‘Prechargeall’存储器命令。
如下图所示:
五、DDR初始化程序
在初始化DDR控制器,要结合DDR的芯片手册。通常需要从DDR芯片手册中获取如下参数:
1、地址线的分布(列地址行地址分别各为多少条)。
2、DDR的刷新周期(通常为7.8US)
3、位宽二片DDR,即为32位
4、DDR的访问时序参数
程序如下
头文件:
#ifndef __COMMON_H
#define __COMMON_H
#define vi *( volatile unsigned int * )
#define set_zero( addr, bit ) ( (vi addr) &= ( ~ ( 1 << (bit) ) ) )
#define set_one( addr, bit ) ( (vi addr) |= ( 1 << ( bit ) ) )
#define set_bit( addr, bit, val ) ( (vi addr) = (( vi addr)&=(~(1<<(bit))) ) | ( (val)<<(bit) ) )
#define set_2bit( addr, bit, val ) ( (vi addr) = (( vi addr)&(~(3<<(bit))) ) | ( (val)<<(bit) ) )
#define set_nbit( addr, bit, len, val ) \
( (vi addr) = ((( vi addr)&(~(( ((1<<(len))-1) )<<(bit)))) | ( (val)<<(bit) ) ))
#define get_bit( addr, bit ) ( (( vi addr ) & ( 1 << (bit) )) > 0 )
#define get_val( addr, val ) ( (val) = vi addr )
#define read_val( addr ) ( vi ( addr ) )
#define set_val( addr, val ) ( (vi addr) = (val) )
#define or_val( addr, val ) ( (vi addr) |= (val) )
///
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
// function declare
int delay( int );
#endif /* __COMMON_H */
DDR 初始化程序
#include "common.h"
#define MEMCCMD 0x7e001004
#define P1REFRESH 0x7e001010
#define P1CASLAT 0x7e001014
#define MEM_SYS_CFG 0x7e00f120
#define P1MEMCFG 0x7e00100c
#define P1T_DQSS 0x7e001018
#define P1T_MRD 0x7e00101c
#define P1T_RAS 0x7e001020
#define P1T_RC 0x7e001024
#define P1T_RCD 0x7e001028
#define P1T_RFC 0x7e00102c
#define P1T_RP 0x7e001030
#define P1T_RRD 0x7e001034
#define P1T_WR 0x7e001038
#define P1T_WTR 0x7e00103c
#define P1T_XP 0x7e001040
#define P1T_XSR 0x7e001044
#define P1T_ESR 0x7e001048
#define P1MEMCFG2 0X7e00104c
#define P1_chip_0_cfg 0x7e001200
#define P1MEMSTAT 0x7e001000
#define P1MEMCCMD 0x7e001004
#define P1DIRECTCMD 0x7e001008
#define HCLK 133000000
#define nstoclk(ns) (ns/( 1000000000/HCLK)+1)
int sdram_init( void )
{
// 设置DRAM控制器状态为配置模式
set_val( MEMCCMD, 0x4 );
// 设置DDR刷新周期为7.8US
set_val( P1REFRESH, nstoclk(7800) );
// 设置DDR时序参数
set_val( P1CASLAT, ( 3 << 1 ) );
set_val( P1T_DQSS, 0x1 ); // 0.75 - 1.25时钟周期
set_val( P1T_MRD, 0x2 ); //min=2个时钟周期
set_val( P1T_RAS, nstoclk(45) );//45us
set_val( P1T_RC, nstoclk(68) );//68us
u32 trcd = nstoclk( 23 );
set_val( P1T_RCD, trcd | (( trcd - 3 ) << 3 ) );//22.5us
u32 trfc = nstoclk( 80 );
set_val( P1T_RFC, trfc | ( ( trfc-3 ) << 5 ) );
u32 trp = nstoclk( 23 );
set_val( P1T_RP, trp | ( ( trp - 3 ) << 3 ) );
set_val( P1T_RRD, nstoclk(15) );
set_val( P1T_WR, nstoclk(15) );
set_val( P1T_WTR, 0x7 );
set_val( P1T_XP, 0x2 );
set_val( P1T_XSR, nstoclk(120) );
set_val( P1T_ESR, nstoclk(120) );
// set mem cfg
set_nbit( P1MEMCFG, 0, 3, 0x2 ); /* 配置成10位 列地址 */
/* set_nbit: 把从第bit位开始的一共len位消零,然后把这几位设为val */
//把第0位开始的后三位清零,然后把这三位设置为ox2
set_nbit( P1MEMCFG, 3, 3, 0x2 ); /* 配置成13 行地址 */
set_zero( P1MEMCFG, 6 ); /* 地址位10设为预充电位的编码位置*/
set_nbit( P1MEMCFG, 15, 3, 0x2 ); /* 脉冲 4 */
set_nbit( P1MEMCFG2, 0, 4, 0x5 ); /* 将AXI与内存时钟相同 */
set_2bit( P1MEMCFG2, 6, 0x1 ); /* 32 bit */
set_nbit( P1MEMCFG2, 8, 3, 0x3 ); /* 设置DDR样式Mobile DDR SDRAM */
set_2bit( P1MEMCFG2, 11, 0x1 ); //读延迟1 周期
set_one( P1_chip_0_cfg, 16 ); /* Bank-Row-Column organization */
// DDR 初始化
set_val( P1DIRECTCMD, 0xc0000 ); // NOP
set_val( P1DIRECTCMD, 0x000 ); // precharge
set_val( P1DIRECTCMD, 0x40000 );// auto refresh
set_val( P1DIRECTCMD, 0x40000 );// auto refresh
set_val( P1DIRECTCMD, 0xa0000 ); // EMRS
set_val( P1DIRECTCMD, 0x80032 ); // MRS
set_val( MEM_SYS_CFG, 0x0 );
// 使得DRAM 控制器输入‘准备’状态
set_val( P1MEMCCMD, 0x000 );
// 直到存储器状态变为‘2’b01’,即‘准备
while( !(( read_val( P1MEMSTAT ) & 0x3 ) == 0x1));
}