S5PV210内存一般会使用SDRAM和DDR2 (DDR SDRAM),SDRAM的uboot启动网络已经有很多资料的,对于DDR2还有有很多疑惑,如果有错误的地方,请大家一定指出,醍醐灌顶,不胜感激。

1、S5PV210的memory map(物理地址)

如下图:左图是整个芯片的内存空间(物理地址),右图是iROM部分的内存空间(BL0的地址貌似不是物理地址==)

 
寻址空间是4GB=232
前512是Boot area
接下是512M的DRAM0通道和512M的DRAM1通道,是存储器的地址,用于DDR2 RAM寻址的,共1GB
后面是6个128M的SROM (Bank0~Bank5),用于总线型设备寻址的
接着256M的Nand和OneNand控制器寄存器和256M的MP3_SRAM输出缓存
包含64KB IROM (BL0) 和 96KB 片内SRAM (BL1 BL2)做为internal memory,一般是启动时用到的
后面的128M DMZ ROM还没搞明白是什么
最后面512M就是SFR了(特殊功能寄存器)
 

2、U-Boot内存分配图

2.u-boot映像的地址0并非指物理地址0,由不同的启动方式映射到不同的地址。例如v210是映射到0xD0000000处的irom。

3.TEXT_BASE等指向SDRAM的地址均为虚拟地址。

4.TEXT_BASE为顶层Makefile中定义的,例如三星官方BSP中定义的是0xC3E00000,它是程序实际的链接首地址。

5.SDRAM_BASE被MMU映射在0xC0000000。

6._end和__bss_start为链接脚本文件中最后定义的bss段,在链接时确定,并与u-boot映像编译在一起。

7.在bl1段运行时,u-boot映像被复制到TEXT_BASE开始的地址处。

8. u-boot分配用户栈顶的代码为:
 ldr r0, _TEXT_BASE  /* upper 128 KiB: relocated uboot   */      将0xc3e00000加载到r0
 sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */      r0减去0x4000的malloc域
 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */      r0减去128字节的全局结构体
#if defined(CONFIG_USE_IRQ)
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)   如果用户有使用IRQ,再减去2*4*1024的中断栈空间
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */      为取址终止异常预留3个字空间后设置好用户sp

 
 3、DDR2 内存分配映射
S5PV210有两个独立的内存控制器:DMC0和DMC1,每个控制器又有两个片选:CS0和CS1。它可以支持16bits和32bits的内存。两个控制器对应的地址空间是
DMC0 0x2000_0000 ~ 0x3FFF_FFFF             512MB
DMC1 0x4000_0000 ~ 0x7FFF_FFFF             512MB
内存控制器的配置寄存器也分为两块,
DMC0 0xF000_xxxx
DMC1 0xF140_xxxx
这一块主要需要设置的寄存器设置是:MEMCONTROL、MEMCONFIG0、MEMCONFIG1
开发板用的是4片1Gbit x16位的内存,两片两片按数据线的高16bits和低16bits组成两组32bits的256M,分别挂载了DMC0的CS0和DMC1的CS1。
 
MEMCONTROL里面有个num_chip,使用了几个CS信号。两个DDR控制器只用了一个CS0,对于210来说就是一片,所以设置为 0x0 = 1 chip
然后 MEMCONTROL的mem_width,设为 0x2 = 32-bit 。
MEMCONFIG0和MEMCONFIG1是一样的,一个设置相应控制器的CS0,一个设置CS1。
 
这两个寄存器合起来,可以决定DMC0/DMC1 CS0和CS1下挂着的内存对应哪一段内存地址。我理解的是当你要放问地址0x21xx_xxxx的地址的时候,DMC0会将访问地址的高8bits 0x21和chip_mask求与,要是等于chip_base,他就会使用相应的控制器的相应的片选去读数据。就像假如
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf8
DMC0_MEMCONFIG1   chip_base =  0x28      chip_mask=0xf8
当你要访问的地址是 0x22xx_xxxx的时候,  (0x22 & 0xf8) ==  0x20,所以使用CS0
那要是  0x2exx_xxxx呢?     (0x2e & 0xf8) == 0x28 ,当然使用CS1了。
也就是说CS0对应的是 0x2000_0000 ~ 0x27ff_ffff,128M
CS1对应的是 0x2800_0000 ~ 0x28ff_ffff,128M
同样的每个CS下都是256M呢?
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf0          // 0x2000_0000 ~ 0x2fff_ffff     256M
DMC0_MEMCONFIG1   chip_base =  0x30      chip_mask=0xf0          // 0x3000_0000 ~ 0x3fff_ffff     256M
DMC0和DMC1配置一样,但是DMC0只能配置为0x2000_0000~0x3fff_ffff的空间,DMC1只能配置为0x4000_0000~0x5fff_ffff的空间。这是DMC的地址空间决定的,我就是在这郁闷了两天。
我的板子上面DMC0和DMC1上都只使用了CS0,然后我的设置就是
DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf0          // 0x2000_0000 ~ 0x2fff_ffff     256M
DMC1_MEMCONFIG0   chip_base =  0x40      chip_mask=0xf0          // 0x4000_0000 ~ 0x4fff_ffff     256M  注意,DMC1只能从0x4000_0000开始。
问题又来了,这样内存地址空间不就不连续了嘛?
内存的地址空间不从0x2000_0000开始,从0x3000_0000开始,不就正好接上DMC1的了。只是CONFIG_SYS_SDRAM_BASE和CONFIG_SYS_TEXT_BASE相应的改一下:
DMC0_MEMCONFIG0   chip_base =  0x30      chip_mask=0xf0          // 0x3000_0000 ~ 0x3fff_ffff     256M
DMC1_MEMCONFIG0   chip_base =  0x40      chip_mask=0xf0          // 0x4000_0000 ~ 0x4fff_ffff     256M
 
难点:关于地址映射

如果设置chip_base为0x20:

(1)我们挂载的内存为128M,那么这个chip_mask应该设置为0xF8

(2)我们挂载256M内存时,chip_mask应该设置为0xF0

(3)我们挂载512M时,chip_mask应该设置为0xE0

(4)我们挂载1GB内存时,chip_mask就应该设置为0xC0。

以DMC0为例,当DMC0接收到来自AXI的0x2000,0000~0x3fff,ffff内的地址时,会作如下处理:

(1)将AXI地址的高8位与chip_mask相与得到结果,记为X。

(2)将X分别与MEMCONFIG0和MEMCONFIG1的chip_base相比较,如果相等,则打开相应的片选。

假如挂载的内存为128M,且CS0和CS1上分别挂了一片,那么128M=128*1024*1024=0x8000000,则128M内存的偏移范围应该是0x0000,0000~0x07ff,ffff,高位剩余5位,那么,我们把MEMCONFIG0的chip_base设置为0x20,chip_mask设置为0xF8,为了保持内存连续,则需要将MEMCONFIG1的chip_base设置为0x28,chip_mask设置为0xF8,当AXI发来的地址为0x23xx,xxxx时,0x23&0xF8得到0x20,所以,会打开片选CS0,当AXI发来的地址为0x28xx,xxxx时,0x28&0xF8得到0x28,所以,会打开片选CS1,依此类推。

特别的,当载在的内存芯片为8bank(8bank内存芯片一般为14/15行地址,10列地址,即容量一般为512M或者1G)时,由于CS1为bank2引脚,为了保持CS0时钟处于片选状态,对于512M内存来讲需要将chip_mask设置为0xE0,这是因为512M=512*1024*1024=0x2000,0000,也就是说,512M内存的偏移应该为0x0000,0000~0x1fff,ffff,所以高位剩余3位,即0xE0,当然了,如果内存为1G=1024*1024*1024=0x4000,0000,即偏移为0x0000,0000~0x3fff,ffff,高位剩余2为,故设置chip_mask为0xC0。这样,就会计算偏移这两个值了。

4、 配置流程

内存芯片的配置比较复杂,好在芯片手册上给出了常用内存类型的初始化序列,TQ210的内存是DDR2的,可以按照如下顺序进行初始化:

1. To provide stable power for controller and memory device, the controller must assert and hold CKE to a logic low level. Then apply stable clock. Note: XDDR2SEL should be High level to hold CKE to low.
2. Set the PhyControl0.ctrl_start_point and PhyControl0.ctrl_inc bit-fields to correct value according to clock frequency. Set the PhyControl0.ctrl_dll_on bit-field to ‘1’ to turn on the PHY DLL.
3. DQS Cleaning: Set the PhyControl1.ctrl_shiftc and PhyControl1.ctrl_offsetc bit-fields to correct value according to clock frequency and memory tAC parameters.
4. Set the PhyControl0.ctrl_start bit-field to ‘1’.
5. Set the ConControl. At this moment, an auto refresh counter should be off.
6. Set the MemControl. At this moment, all power down modes should be off.
7. Set the MemConfig0 register. If there are two external memo ry chips, set the MemConfig1 register.
8. Set the PrechConfig and PwrdnConfig registers.
9. Set the TimingAref, TimingRow, TimingData and TimingPower registers according to memory AC parameters.
10. If QoS scheme is required, set the QosControl0~15 and QosConfig0~15 registers.
11. Wait for the PhyStatus0.ctrl_locked bit-fields to change to ‘1’. Check whether PHY DLL is locked.
12. PHY DLL compensates the changes of delay amount caused by Process, Voltage and Temperature (PVT) variation during memory operation. Therefore, PHY DLL should not be off for reliable operation. It can be off except runs at low frequency. If off mode is used, set the PhyControl0.ctrl_force bit-field to correct value according to the PhyStatus0.ctrl_lock_value[9:2] bit-field to fix delay amount. Clear the PhyControl0.ctrl_dll_on bit-field to turn off PHY DLL.
13. Confirm whether stable clock is issued minimum 200us after power on
14. Issue a NOP command using the DirectCmd register to assert and to hold CKE to a logic high level
15. Wait for minimum 400ns.
16. Issue a PALL command using the DirectCmd register.
17. Issue an EMRS2 command using the DirectCmd register to program the operating parameters.
18. Issue an EMRS3 command using the DirectCmd register to program the operating parameters.
19. Issue an EMRS command using the DirectCmd register to enable the memory DLLs.
20. Issue a MRS command using the DirectCmd register to reset the memory DLL.
21. Issue a PALL command using the DirectCmd register.
22. Issue two Auto Refresh commands using the DirectCmd register.
23. Issue a MRS command using the DirectCmd register to program the operating parameters without resetting the memory DLL.
24. Wait for minimum 200 clock cycles.
25. Issue an EMRS command using the DirectCmd register to program the operating parameters. If OCD calibration is not used, issue an EMRS command to set OCD Calibration Default. After that, issue an EMRS command to exit OCD Calibration Mode and to program the operating parameters.
26. If there are two external memory chips, perform steps 14~25 for chip1 memory device.
27. Set the ConControl to turn on an auto refresh counter. 28. If power down modes is required, set the MemControl registers.

上面就是手册上给出的DDR2型内存芯片的初始化序列,但是单纯的根据上面的步骤配置可能有些困难,这时,我们可以参考u-boot的内存初始化代码来初始化内存,最后你会发现u-boot的操作顺序跟上面是完全一致的。

5、代码的链接地址和运行地址等注意事项

配置好内存的代码烧写到Nand运行是正常的,但是用USB方式启动时不正常,目前还没有找到原因,如果有朋友解决了或者有其他问题请留言相告,在这里先说声谢谢。

现在找到原因了,原来S5PV210的USB启动过程跟Nand启动方式不一样,S5PV210以USB方式启动时会先将三星提供的一个固件程序下载到0xd0020010处运行,然后,再将用户代码下载0x23e00000处运行,也就是说,固件程序完成了内存的初始化,因为我们的代码位于0x23e00000处。而我们的代码中再次配置内存时会重置内存,下载到内存中的代码也就丢失了,所以程序执行到内存初始化函数就会挂掉。

为了证明上面的假设,我在代码中加上一段程序,该程序将内存的中代码拷贝到iram的16K以后的位置上(直接拷贝到0xd0020000处有问题,我是拷贝到了0xd0024000处,现在还不知道什么原因),然后将代码跳转到IRAM中,如果代码可以正常运行就可以证明内存初始化部分正常,实验结果是肯定的,下面总结下:

S5PV210以USB方式启动时用户代码是下载到内存中的(0x23e00000处),要使代码以USB方式启动时正常运行,应该注意以下两点:

(1)如果是位置相关的代码,连接地址应该链接到0x23e00000,如果是位置无关码,可以随便指定连接地址。
(2)用户代码需要检验自己运行时的位置,如果运行在内存中则需跳过内存初始化,根据需要决定是否需要代码重定位。

参考网址:http://blog.chinaunix.net/uid-122754-id-3144920.html

       http://www.cnblogs.com/Efronc/archive/2012/03/01/2375578.html

S5PV210的内存分配研究分析的更多相关文章

  1. map的内存分配机制分析

    该程序演示了map在形成的时候对内存的操作和分配. 因为自己对平衡二叉树的创建细节理解不够,还不太明白程序所显示的日志.等我明白了,再来修改这个文档. /* 功能说明: map的内存分配机制分析. 代 ...

  2. list的内存分配机制分析

    该程序演示了list在内存分配时候的问题.里面的备注信息是我的想法. /* 功能说明: list的内存分配机制分析. 代码说明: list所管理的内存地址可以是不连续的.程序在不断的push_back ...

  3. vector的内存分配机制分析

    该程序初步演示了我对vector在分配内存的时候的理解.可能有误差,随着理解的改变,改代码可以被修改. /* 功能说明: vector的内存分配机制分析. 代码说明: vector所管理的内存地址是连 ...

  4. java 字符串内存分配的分析与总结

    经常在网上各大版块都能看到对于java字符串运行时内存分配的探讨,形如:String a = "123",String b = new String("123" ...

  5. mimalloc内存分配代码分析

    这篇文章中我们会介绍一下mimalloc的实现,其中可能涉及上一篇文章提到的内容,如果不了解的可以先看下这篇mimalloc剖析.首先我们需要了解的是其整体结构,mimalloc的结构如下图所示   ...

  6. Java 内存分配全面浅析

    本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java.这类文章网上有很多,但大多比较零碎.本文从认知过程角度出发,将带给读者一个系统的介绍. 进入正题前首先要知道的是Java程 ...

  7. Java内存分配全面浅析

    本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java.这类文章网上有很多,但大多比较零碎.本文从认知过程角度出发,将带给读者一个系统的介绍. 进入正题前首先要知道的是Java程 ...

  8. Java内存分配全面浅析(转)

           原文引自CSDN:        本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java.这类文章网上有很多,但大多比较零碎.本文从认知过程角度出发,将带给读者一个 ...

  9. Java 内存分配全面浅析(转)

    本文将由浅入深详细介绍Java内存分配的原理,以帮助新手更轻松的学习Java.这类文章网上有很多,但大多比较零碎.本文从认知过程角度出发,将带给读者一个系统的介绍. 进入正题前首先要知道的是Java程 ...

随机推荐

  1. java中newInstance()和new()

    在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法.通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为了动态 ...

  2. 8种效果实例-jQuery anoSlide 焦点图轮播

    anoslide是一款可调节效果至任意宽度大小,支持图文混合内容显示的图片轮播插件. 在线实例 单个 多个 动画延迟 自动播放 显示分页 显示标题 延迟加载 自适应高度 使用方法 <div cl ...

  3. Java2_J2EE体系架构

    J2EE是Java2平台企业版(Java 2 Platform,Enterprise Edition),它的核心是一组技术规范与指南,提供基于组件的方式来设计.开发.组装和部署企业应用.J2EE使用多 ...

  4. 性能更好的js动画实现方式——requestAnimationFrame

    用js来实现动画,我们一般是借助setTimeout或setInterval这两个函数,css3动画出来后,我们又可以使用css3来实现动画了,而且性能和流畅度也得到了很大的提升.但是css3动画还是 ...

  5. 杭电acm2029-Palindromes _easy version

    Problem Description “回文串”是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串.请写一个程序判断读入的字符串是否是“回文”.   Input 输入包 ...

  6. Sharepoint学习笔记—习题系列--70-576习题解析 -(Q6-Q8)

    Question 6  You are designing a SharePoint 2010 solution that allows users to enter address informat ...

  7. 操作系统开发系列—12.b.从Loader跳入保护模式

    现在,内核已经被我们加载进内存了,该是跳入保护模式的时候了. 首先是GDT以及对应的选择子,我们只定义三个描述符,分别是一个0~4GB的可执行段.一个0~4GB的可读写段和一个指向显存开始地址的段: ...

  8. 两个Service之间相互监视的实现

    在实际开发中可能需要用到两个Service相互监视的情况,本示例就是实现此功能以作参考. 服务A: public class ServiceA extends Service { private st ...

  9. iOS数据缓存及YYCache的实现分析

    1. 什么是cache cache就是缓存的意思. 计算机上的cache就是高速缓存,计算机组成课程里的定义是,存在于主存和CPU之间,主要用于解决CPU处理数据的速度远远大于读取主存数据的速度. 手 ...

  10. Android 采用get方式提交数据到服务器

    首先搭建模拟web 服务器,新建动态web项目,servlet代码如下: package com.wuyudong.web; import java.io.IOException; import ja ...