2008年11月10日

BF532芯片SDRAM连接方式和初始化

今天在网上看到一片介绍SDRAM工作原理和时序的好文章,可以不知道如何放到我的博客上,只给一个链接吧:《SDRAM的原理和时序.pdf》

BF532芯片SDRAM连接框图:
SDRAM Controller (SDC)特点:
1。支持64Mbit~512Mbit x4、x8、x16芯片。
2。支持SDRAM pagesize of 512bytes, 1Kbyte, 2Kbyte, 4Kbyte
3。SA10使能SDC对SDRAM预充电
4。只支持Burst Length = 1
5。CAS Latency (CL)可以设置为2 or 3
6。将EBIU_SDGCTL寄存器PSSE位置1将触发SDC设置SDRAM的Mode register
7。16bit SDRAM banks: page size = 2^(CAW+1), CAW是SDRAM列地址的宽度
我们使用的是Micron芯片MT48LC16M16A2P-75,它的主要性能指标是:
下面我们来看看bf532是如何初始化SDRAM,代码是uboot/cpu/bf533/init_sdram.S。

#define ASSEMBLY

#include
#include
#include
#include
.global init_sdram;

。。。。。。

init_sdram: =>init_sdram函数,先保存一些函数中会使用到的寄存器的值
[--SP] = ASTAT;
[--SP] = RETS;
[--SP] = (R7:0);
[--SP] = (P5:0);

。。。。。。

/*
* PLL_LOCKCNT - how many SCLK Cycles to delay while PLL becomes stable
*/
=>#define PLL_LOCKCNT 0xFFC00010 /* PLL Lock Count register (16-bit) */
=>将PLL Lock Count register地址赋给地址寄存器p0
p0.h = hi(PLL_LOCKCNT);
p0.l = lo(PLL_LOCKCNT);
=>Z的意思是将立即数高位用0扩充 =>W (16-bit word) designator is used to preface the load or store.
=> 0x300=768个时钟周期的延时 => ssync是使配置真正写到寄存器中
r0 = 0x300(Z);
w[p0] = r0.l;
ssync;

/*
* Put SDRAM in self-refresh, incase anything is running
*/
P2.H = hi(EBIU_SDGCTL);
P2.L = lo(EBIU_SDGCTL);
=> EBUIU_SDGCTL寄存器第24bit为1时Enable self-refresh during inactivity,等于0 - Disable self-refresh,默认是0 =>下面的操作是先读出再置bit24=1然后写回去
R0 = [P2];
BITSET (R0, 24);
[P2] = R0;
SSYNC;

=>下面这段是设置时钟频率
=>
=> If (!MSEL) VCO = CLKIN / (DF+1) * MSEL
=> Else VCO = CLKIN / (DF+1)
=> CCLK = VCO / (2^CSEL)
=> SCLK = VCO / SSEL

/*

* Set PLL_CTL with the value that we calculate in R0
* - [14:09] = MSEL[5:0] : CLKIN / VCO multiplication factors
* - [8] = BYPASS : BYPASS the PLL, run CLKIN into CCLK/SCLK
* - [7] = output delay (add 200ps of delay to mem signals)
* - [6] = input delay (add 200ps of input delay to mem signals)
* - [5] = PDWN : 1=All Clocks off
* - [3] = STOPCK : 1=Core Clock off
* - [1] = PLL_OFF : 1=Disable Power to PLL
* - [0] = DF : 1=Pass CLKIN/2 to PLL / 0=Pass CLKIN to PLL
* all other bits set to zero
*/
=>我的设置是CONFIG_VCO_MULTI=40,CLKIN=10M,所以VCO=400M
=>CONFIG_CLKIN_HALF=0

r0 = CONFIG_VCO_MULT & 63; /* Load the VCO multiplier */
r0 = r0 << 9; /* Shift it over, */
r1 = CONFIG_CLKIN_HALF; /* Do we need to divide CLKIN by 2?*/
r0 = r1 | r0;
r1 = CONFIG_PLL_BYPASS; /* Bypass the PLL? */
r1 = r1 << 8; /* Shift it over */
r0 = r1 | r0; /* add them all together */

p0.h = hi(PLL_CTL);
p0.l = lo(PLL_CTL); /* Load the address */
cli r2; /* Disable interrupts */
ssync;
w[p0] = r0.l; /* Set the value */
idle; /* Wait for the PLL to stablize */
sti r2; /* Enable interrupts */
=>PLL_STAT寄存器bit5=1表示PLL LOCKED
check_again:
p0.h = hi(PLL_STAT);
p0.l = lo(PLL_STAT);
R0 = W[P0](Z);
CC = BITTST(R0,5);
if ! CC jump check_again;

=>我们设置CONFIG_SCLK_DIV=3,即系统时钟频率是133M
/* Configure SCLK & CCLK Dividers */
r0 = (CONFIG_CCLK_ACT_DIV | CONFIG_SCLK_DIV);
p0.h = hi(PLL_DIV);
p0.l = lo(PLL_DIV);
w[p0] = r0.l;
ssync;

。。。。。。

/*
* Now, Initialize the SDRAM,
* start with the SDRAM Refresh Rate Control Register
*/
=>#define mem_SDRRC ((( CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - (SDRAM_tRAS_num + SDRAM_tRP_num)
=>上面定义使用的公式是:RDIV = ((fSCLK × tREF) / NRA) – (tRAS + tRP)
=> Where:
=> • fSCLK = SDRAM clock frequency (system clock frequency),也就是133MHz
=> • tREF = SDRAM refresh period
=> • NRA = Number of row addresses in SDRAM (refresh cycles to refresh whole SDRAM)
=> • tRAS = Active to Precharge time (TRAS in the SDRAM Memory Global Control register) in number of clock cycles
=> • tRP = RAS to Precharge time (TRP in the SDRAM Memory Global Control register) in number of clock cycles
=> 对于我们这颗芯片:
=> /*SDRAM INFORMATION: */
=> #define SDRAM_Tref 64 /* Refresh period in milliseconds */
=> #define SDRAM_NRA 8192 /* Number of row addresses in SDRAM */
=> #define SDRAM_CL CL_3
=> #define SDRAM_tRP TRP_2
=> #define SDRAM_tRAS TRAS_7
=> #define SDRAM_tRCD TRCD_2
=> #define SDRAM_tWR TWR_2

p0.l = lo(EBIU_SDRRC);
p0.h = hi(EBIU_SDRRC);
r0 = mem_SDRRC;
w[p0] = r0.l;
ssync;

/*
* SDRAM Memory Bank Control Register - bank specific parameters
*/
=>#define mem_SDBCTL SDRAM_WIDTH | SDRAM_SIZE | EBE
=>对于MT48LC16M16A2P-75,SDRAM_WIDTH=0x00000010 (9bit)
=>SDRAM_SIZE=0x00000002 (32MB)
=>EBE = 0x00000001 /* Enable SDRAM external bank */

p0.l = (EBIU_SDBCTL & 0xFFFF);
p0.h = (EBIU_SDBCTL >> 16);
r0 = mem_SDBCTL;
w[p0] = r0.l;
ssync;

/*
* SDRAM Global Control Register - global programmable parameters
* Disable self-refresh
*/
P2.H = hi(EBIU_SDGCTL);
P2.L = lo(EBIU_SDGCTL);
R0 = [P2];
BITCLR (R0, 24); => disable self-refresh

/*
* Check if SDRAM is already powered up, if it is, enable self-refresh
*/
p0.h = hi(EBIU_SDSTAT);
p0.l = lo(EBIU_SDSTAT);
r2.l = w[p0];
cc = bittst(r2,3);
if !cc jump skip; => 如果是0表示SDRAM already powered up,跳转到skip,这时是不是要disable self-refresh呢?
NOP;
BITSET (R0, 23); => 1: Enable SDRAM powerup sequence on next SDRAM access
skip:
[P2] = R0; => 如果不是跳转到这里倒是对的,????
SSYNC;

/* Write in the new value in the register */
=> #define SCTLE 0x00000001 /* Enable SCLK[0], /SRAS, /SCAS, /SWE, SDQM[3:0] */
=> #define PSS 0x00800000 /* enable SDRAM power-up sequence on next SDRAM access */
=> #define mem_SDGCTL ( SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR | PSS )

R0.L = lo(mem_SDGCTL);
R0.H = hi(mem_SDGCTL);
[P2] = R0;
SSYNC;
nop;

=>恢复前面的保存值
(P5:0) = [SP++];
(R7:0) = [SP++];
RETS = [SP++];
ASTAT = [SP++];
RTS;

没有评论: