自己编写bootloader(二):SDRAM初始化

    本节,我们继续编写bootloader,实现SDRAM初始化与代码的重定位。首先从SDRAM初始化开始。

    我们先看到SDRAM的结构图:

对于SDRAM,它有四个Bank。因此,我们访问SDRAM的某个地址,要做以下的操作:

    1.内存控制器发出片选信号(chip selection)信号,选中SDRAM。

    2.接着发出Bank地址,选中某块Bank

    3.分别发出行地址、列地址,定位到某个具体的地址。

我们首先从第一步开始,如何选中SDRAM呢?我们看芯片手册里的这张图:

我们看到,只有BANK6和BANK7才是可以接SDRAM的,对于S3C2440开发版来说,其内置的是两块并联的32MSDRAM,总共大小是64M,所以SDRAM的有效地址应该为0x30000000-0x33ffffff。也就只在BANK6区域,我们发出nGCS6就好了。这一操作是在我们发出的地址属于这个范围时,内存控制器自动的帮我们发出片选信号。接下来我们看第二步,发出Bank地址。怎么去发出Bank地址呢?我们看S3C2440的原理图:

我们看到,对于LADDR2-LADDR14,都是用来进行寻址的(也就是发出行地址和列地址共用的),而LADDR24和LADDR25,则表示BA0和BA1,也就是用来选中某个Bank的(两位恰好有4种情况,所以可以选中4个Bank)。最后一步就是分别发出行地址和列地址了,我们看到LADDR2-LADDR14就是用来寻址的。其实,这些步骤并不需要我们去完成。CPU只需要发出相应的地址(范围:0x30000000-0x33ffffff)内存控制器会根据地址发出相应的片选信号,并选中Block,发出相应的行地址和列地址。我们需要做的,只需设置好相关的寄存器就行了。接下来我们看寄存器的设置:

这个寄存器是位宽还有等待控制寄存器,这里我们只需要设置与Bank6相关的位就好了,也就是ST6、WS6、DW6。我们分别看一下:

    ST6:启动/禁止SRAM的数据掩码引脚。这个是为SRAM准备的,不关我们事,设置成0就好了。

    WS6:启动/进制等待信号。什么是等待信号呢?就是当某款内存芯片的速度比较慢的时候,内存控制器已经发出好相应的指令了,也等待了该等待的时间了,内存芯片还没有准备好数据,就会发出等待信号,请求再宽限一些时间。但我们看SDRAM的原理图里,没有看到与等待信号相关的结构,所以我们也用不到,设置成0就好。

    DW6:设置位宽,这里我们使用的是32位,设置为10

    除此之外,我们一般也把Bank7相关位也设置成与Bank6相同,即使我们用不到。

因此,BWSCON寄存器的值为:0x22000000。

接着我们往下看,看到BANKCON6:

前面的一部分都是给ROM和SRAM准备的,作为SDRAM,我只需要初始化后面的两位:Trcd和SCAN

    Trcd:行地址和列地址的间隔,也就是发出行地址后,多久才发出列地址。对于这个值,我们可以参考一下一些SDRAM的手册。参考过几款SDRAM手册后我们知道,这个值设置为20ns是最合适的,而内存控制器是接AHB总线的,HCLK为100MHz,所以我们应该设置为2 clocks:00。

    SCAN,列地址的位数,这个我们也需要去翻看SDRAM的手册,参考过几款之后,发现这个值都是9,所以这里我们设置为01。

我们看到后面的寄存器:


从名字我们应该可以知道,这是一个管内存刷新的。我们知道SDRAM是动态的(Dynamic),得不断刷新来保存它里面的值。我们看到里面的位:

    REFEN:启动刷新,这个直接填1.

    TREFMD:刷新模式,使用自动刷新,填0

    Trp:设定当行地址信号需要重新寻址时,要隔多久时间才能开始下次的寻址动作,通常被视为RAS的充电时间,理论上是越短越好。这里我们直接看芯片手册它的设置。我们参照几款之后,发现这个值设为20ns比较合理,也就是两个周期。

    Tsrc:这个可以直接根据它所提供的那个公式得到:Tsrc=Trc-Trp,Trc为Row Cycle time,可以在手册中查得到。参考并计算后得出,这个值为5blocks比较合理,也就是设置为01

    Refresh Counter:这个值与刷新周期有关,我们查看手册就可以知道refresh period一般是在7.8us,所以此时可以直接另它为1269。

综上,REFRESH的值设为0x8404F5。我们继续往下看:

    

    BURST_EN:连续访问,这里我们设置为1

    SCKE_EN:0=不使用SCKE信号令SDRAM进入省电模式,1=使用SCKE信号令SDRAM进入省电模式(推荐);这里我们设置为1,

    SCLK_ENL:直接设置为推荐值1

    BK76MAP:设置BANK6的大小。本开发板BANK6外接64MB的SDRAM,令[2:0]=b001(64M/64M),表示BANK6/7的容量都是64MB,虽然BANK7没有使用。

    因此,本开发板中BANKSIZE设为0xB1。我们看到最后一个寄存器:

    

    WBL、TM:只能使用它要求的值

    CL:列地址发出后,要等多久才能取到数据,这里我们设置为010,2blocks

    BT、BL:只能使用固定值。

    这样,我们就设置完所有的寄存器了,也就是初始化SDRAM了。但其实,在真正的bootloader里,每个寄存器的值不一定都是这么设置,但主要都是这些,这里我给出它的初始化的代码:

/* 3. 初始化SDRAM */
	ldr r0, =MEM_CTL_BASE
	adr r1, sdram_config     /* sdram_config的当前地址 */
	add r3, r0, #(13*4)
1:
	ldr r2, [r1], #4
	str r2, [r0], #4
	cmp r0, r3
	bne 1b

sdram_config:
    .long 0x22011110     //BWSCON
    .long 0x00000700     //BANKCON0
    .long 0x00000700     //BANKCON1
    .long 0x00000700     //BANKCON2
    .long 0x00000700     //BANKCON3  
    .long 0x00000700     //BANKCON4
    .long 0x00000700     //BANKCON5
    .long 0x00018005     //BANKCON6
    .long 0x00018005     //BANKCON7
    .long 0x008C04F4     // REFRESH
    .long 0x000000B1     //BANKSIZE
    .long 0x00000030     //MRSRB6
    .long 0x00000030     //MRSRB7

这些寄存器都是连续的,所以就循环分别进行了初始化。

猜你喜欢

转载自blog.csdn.net/xiaokangdream/article/details/79651133