7.内存初始化:bl mem_init
内存由于具备访问速度快,访问方式简单等优点,成为了PC或者是嵌入式硬件平台上不可或缺的元件。在开始学习如何使用内存之前,非常有必要先了解一下内存的分类: 1.DRAM:它的基本原件是小电容,电容可以在两个极板上保留电荷,但是需要定期的充电(刷新),否则数据会丢失。缺点:由于要定期刷新存储介质,存取速度较慢。 2.SRAM:它是一种具有静止存取功能的内存,不需要定期刷新电路就能保存它内部存储的数据。其优点:存取速度快; 但是缺点是:功耗大,成本高。常用作存储容量不高,但存取速度快的场合,比如steppingstone。 在嵌入式硬件体系中,除了CPU内部的”垫脚石”采用SRAM外,板载内存一般会采用DRAM,而DRAM又可以分为SDRAM,DDR,DDR2等。 SDRAM(Synchronous Dynamic Random AccessMemory):同步动态随机存储器.
同步: 内存工作需要有同步时钟,内部的命令的发送与数据的传输都以该时钟为基准。
动态:存储阵列需要不断的刷新来保证数据不丢失。
随机:是指数据不是线性依次存储,而是自由指定地址进行数据读写。 DDR (Double Data Rate SDRAM),即“双倍速率同步动态随机存储器”。与早期的SDRAM相比,DDR 除了可以在时钟脉冲的上升沿传输数据,还可以在下降沿传输信号,这意味着在相同的工作频率下,DDR 的理论传输速率为SDRAM的两倍。DDR2 则在DDR 的基础上再次进行了改进,使得数据传输速率在DDR 的基础上再次翻倍。6410开发板通常采用DDR内存 。 内存的内部如同表格,数据就存放在每个单元格中。数据读写时,先指定行号(行地址),再指定列号(列地址) ,我们就可以准确地找到所需要的单元格。而这张表格的称为ogical Bank(L-Bank)。 如下图:
由于技术、成本等原因,一块内存不可能把所有的单元格都做到一个L-Bank,现在内存内部基本都会分割成4
个L-Bank。 S3C6410处理器拥32位地址总线,其寻址空间为4GB。其中高2GB为保留区,低2GB区域又可划分
为两部分:主存储区和外设区。如下左图:
主存储去又可以分为:Boot镜像区、内部存储区、静态存储区、保留区、动态存储区,如上右图 。
Boot镜像区:这个区域的作用正如它的名字所述,是用来启动ARM系统的。但是这个区域并没有固定的存储介质与之对应。而是通过修改启动选项,把不同的启动介质映射到该区域。比如说选择了IROM 启动方式后,就把IROM映射到该区域。 内部存储区:这个区域对应着内部的内存地址,iROM和SRAM都是分布在这个区间。0x08000000~0x0bffffff对应着内部ROM,但是IROM实际只有32KB,选择从IROM启动的时候,首先运行就是这里面的程序BL0,这部分代码由三星固化。0x0c000000~0x0fffffff对应内部SRAM,实际就是8KB的Steppingstone。
静态存储区:这个区域用于访问挂在外部总线上的设备,比如说NOR flash、oneNand等。这个区域被分割为6个bank,每个bank为128MB,数据宽度最大支持16bit,每个bank由片选Xm0CS[0]~Xm0CS[5] 选中。
动态存储区:该区域从0x50000000~0x6fffffff,又分为2个区间,分别占256MB,可以片选Xm1CS[0]~Xm1CS[1]来进行着2个区间的选择。我们6410开发板上256MB的DDR内存就安排在这个区域,这也就是为什么6410的内存地址是从0x50000000开始的原因。
OK6410内存芯片硬件连接如下:
从上图可以知道,它是通过两片内存芯片组合成32位数据的,分别使用s3c6410的前16位和后16位数据线。 查看s3c6410手册DRAM Controller 章节,可以发现有关于内存初始化操作步骤的说明,如下:
所以就可以参考上面的操作步骤来实现内存的初始化。 第1步:配置DRAM CONTROLLER COMMAND REGISTER为2b011及为0x4,让其进入配置模式,寄存器说明如下:
第2步:配置内存时序寄存器、片选配置寄存器、用户配置寄存器;内存时序寄存器比较多,这里不再一一列举,大家可以查看s3c6410手册,片选配置寄存器说明如下:
用户配置寄存器说明如下:
第3步:等待200us,让SDRAM电源和时钟稳定,但是,当cpu启动时电源和时钟已经稳定。呵呵,就是不需要了呗,绕这么大一圈,可能是三星公司有病吧; 第4步:执行内存初始化,说了半天才内存初始化,之前干啥啦?不要吵吵,之前是sdram的初始化,因为OK6410使用的是mobile DDR sdram,所以参考5.4.2的ddr/mobile DDR sdram初始化步骤,根据说明,其实就是重复设置P1DIRECTCMD寄存器(直接命令寄存器)的Memory command位,即[19:18]位。分别设置为2b11 2b00 2b01 2b01 2b10 2b10使其运行中nop、Prechargeall 、Autorefresh 、MRS、EMRS。直接命令寄存器说明如下:
第5步:设置P1MEMCCMD寄存器(内存控制命令寄存器)的Memc_cmd位位3b000,让DRAM控制器进入准备好模式,内存控制命令寄存器说明如下:
第6步:检测DRAM控制器是否进入准备模式,详见代码,如下: .text.global mem_initmem_init: ldr r0, =0x7e00f120 @配置内存系统子程序寄存器地址 mov r1, #0x8 @将0x8存入r1寄存器 str r1, [r0] @将r1寄存器里的数据写入配置内存系统子程序寄存器中 ldr r0, =0x7e001004 @内存控制命令寄存器 mov r1, #0x4 @根据手册得知需要先进入配置模式 str r1, [r0] @将寄存器r1内容写入内存控制命令寄存器中 ldr r0, =0x7e001010 @刷新寄存器地址 ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) ) @设置刷新时间 str r1, [r0] @将寄存器r1内容写入刷新寄存器寄存器中 ldr r0, =0x7e001014 @CAS latency寄存器 mov r1, #(3 << 1) @r1=0x6 str r1, [r0] @将寄存器r1内容(0x06)写入CAS latency寄存器中 ldr r0, =0x7e001018 @t_DQSS寄存器 mov r1, #0x1 @r1=0x1 str r1, [r0] @将寄存器r1内容(0x01)写入t_DQSS寄存器中 ldr r0, =0x7e00101c @T_MRD寄存器 mov r1, #0x2 @r1=0x2 str r1, [r0] @将寄存器r1内容(0x02)写入T_MRD寄存器中 ldr r0, =0x7e001020 @t_RAS寄存器 ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=6.95 str r1, [r0] @将寄存器r1内容(6.95)写入t_RAS寄存器中 ldr r0, =0x7e001024 @t_RC寄存器 ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=10.044 str r1, [r0] @将寄存器r1内容(10.044)写入t_RC寄存器中 ldr r0, =0x7e001028 @t_RCD寄存器 ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=3.99 str r1, [r0] @将寄存器r1内容(3.99)写入t_RCD寄存器中 ldr r0, =0x7e00102c @t_RFC寄存器 ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=11.64 str r1, [r0] @将寄存器r1内容(11.64)写入t_RFC寄存器中 ldr r0, =0x7e001030 @t_RP寄存器 ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=3.99 str r1, [r0] @将寄存器r1内容(3.99)写入t_RP寄存器中 ldr r0, =0x7e001034 @t_rrd寄存器 ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=2.995 str r1, [r0] @将寄存器r1内容(2.995)写入t_rrd寄存器中 ldr r0, =0x7e001038 @t_wr寄存器 ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=2.995 @ ldr r2, [r0] str r1, [r0] @将寄存器r1内容(2.995)写入T_MRD寄存器中 ldr r0, =0x7e00103c @t_wtr寄存器 mov r1, #0x07 @r1=0x07 str r1, [r0] @将寄存器r1内容(0x07)写入T_MRD寄存器中 ldr r0, =0x7e001040 @t_xp寄存器 mov r1, #0x02 @r1=0x02 str r1, [r0] @将寄存器r1内容(0x02)写入t_xp寄存器中 ldr r0, =0x7e001044 @t_xsr寄存器 ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=16.69 str r1, [r0] @将寄存器r1内容(16.69)写入t_xsr寄存器中 ldr r0, =0x7e001048 @t_esr寄存器 ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) ) @r1=16.69 str r1, [r0] @将寄存器r1内容(16.69)写入t_esr寄存器中 ldr r0, =0x7e00100c @内存控制配置寄存器 P1MEMCFC ldr r1, =0x00010012 @配置控制器 r1=2b0000_0000_0000_0001_0000_0000_0001_0010 str r1, [r0] @将寄存器r1内容(0x10012)写入P1MEMCFC寄存器中 ldr r0, =0x7e00104c @32位DRAM配置控制寄存器 ldr r1, =0x0b45 @r1=2b0000_0000_0000_0000_0000_1011_0100_0101 选择Mobile DDR SDRAM str r1, [r0] @将寄存器r1内容(0x0b45)写入T寄存器中 ldr r0, =0x7e001200 @片选寄存器 ldr r1, =0x150f8 @r1=0x150f8 r1=2b0000_0000_0000_0001_0101_0000_1111_1000 Bank-Row-Column organization str r1, [r0] @将寄存器r1内容(0x02)写入T_MRD寄存器中 ldr r0, =0x7e001304 @用户配置寄存器 mov r1, #0x0 @r1=0x0 str r1, [r0] @将寄存器r1内容(0x00)写入用户配置寄存器中 ldr r0, =0x7e001008 @直接命令寄存器 ldr r1, =0x000c0000 @r1=2b0000_0000_0000_1100_0000_0000_0000_0000 makes DRAM Controller issue ‘NOP’ memory str r1, [r0] @将寄存器r1内容(0xc0000)写入直接命令寄存器中 ldr r1, =0x00000000 @r1=0 makes DRAM Controller issue‘PrechargeAll’ memory command. str r1, [r0] @将寄存器r1内容(0x0)写入直接命令寄存器中 ldr r1, =0x00040000 @r1=2b0000_0000_0000_0100_0000_0000_0000_0000 makes DRAM Controller issue ‘Autorefresh’ memory command. str r1, [r0] @将寄存器r1内容(0x40000)写入直接命令寄存器中 ldr r1, =0x000a0000 @r1=2b0000_0000_0000_1010_0000_0000_0000_0000 makes DRAM Controller issue ‘MRS’ memory command. str r1, [r0] @将寄存器r1内容(0xa0000)写入直接命令寄存器中 ldr r1, =0x00080032 @r1=2b0000_0000_0000_1000_0000_0000_0011_0010 str r1, [r0] @将寄存器r1内容(0x80032)写入直接命令寄存器中 makes DRAM Controller issue ‘EMRS’ memory command. ldr r0, =0x7e001004 @内存控制命令寄存器 mov r1, #0x0 @根据手册得知需要进入ready模式 str r1, [r0] @将寄存器r1内容写入内存控制命令寄存器中@检查内存初始化是否准备好check_dmc1_ready: ldr r0, =0x7e001000 @DRAM控制状态寄存器 ldr r1, [r0] @将DRAM控制状态寄存器中内容写入寄存器r1中 mov r2, #0x3 @将0x03写入寄存器r2中 and r1, r1, r2 @将r1和r2与运算后存在r1中,即只保持读出的值的[1:0]位 cmp r1, #0x1 @将读出的值与0x01比较 bne check_dmc1_ready @若不相等,跳转到标号check_dmc1_ready处继续执行,检查内存状态 nop mov pc, lr @返回调用处继续往下执行8.拷贝bl到内存中:bl copy_to_arm 要想拷贝bl到内存中,我们首先的看一下s3c6410的启动流程图,如下:
解释如下:
整个流程如下:首先是执行芯片固化在iROM中的bl0代码,该段代码将Booting Device中的bl1搬移到Stepping stone中,但是Stepping stone只有8k,一个完整的代码代码量会超过8K,那样就没法运行了,所以bl1这段代码其中就有一个功能将大部分代码搬移到内存中去执行,这里要实现的就是这个功能,只不过是将从Booting device中bl1开始的的4K代码移过去。代码如下: @ 代码搬移,拷贝bl到内存中copy_to_ram: ldr r0, =0x0c000000 @ Stepping Stone (Boot Loader)基地址,即要搬移的源地址存入r0 起点 ldr r1, =0x50008000 @ 内存地址,要搬移的目标地址存入r1 终点 add r3, r0, #1024*4 @ 将r0处的地址加4k大小存入r3,要搬移的内存Size 4k, 大小copy_loop: @ 等待搬移完成 ldr r2, [r0], #4 @ 将地址0x0c000000增加4后(0x0c000004)地址数据存入r2 str r2, [r1], #4 @ 将r2的数据传送到r1+4地址处(0x500080004) cmp r0, r3 @ 比较r0和r3处地址 bne copy_loop @ 若不相等,跳到标号copy_loop处继续执行 mov pc, lr @ 返回调用处继续往下执行
|