热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

S5PV210的内存分配研究分析

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

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_xxxxDMC1 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=0xf8DMC0_MEMCONFIG1   chip_base =  0x28      chip_mask=0xf8当你要访问的地址是 0x22xx_xxxx的时候,  (0x22 & 0xf8) ==  0x20,所以使用CS0那要是  0x2exx_xxxx呢?     (0x2e & 0xf8) == 0x28 ,当然使用CS1了。也就是说CS0对应的是 0x2000_0000 ~ 0x27ff_ffff,128MCS1对应的是 0x2800_0000 ~ 0x28ff_ffff,128M同样的每个CS下都是256M呢?DMC0_MEMCONFIG0   chip_base =  0x20      chip_mask=0xf0          // 0x2000_0000 ~ 0x2fff_ffff     256MDMC0_MEMCONFIG1   chip_base =  0x30      chip_mask=0xf0          // 0x3000_0000 ~ 0x3fff_ffff     256MDMC0和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     256MDMC1_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     256MDMC1_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)用户代码需要检验自己运行时的位置,如果运行在内存中则需跳过内存初始化,根据需要决定是否需要代码重定位。


推荐阅读
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件
    本文旨在全面介绍Windows内存管理机制及C++内存分配实例中的内存映射文件。通过对内存映射文件的使用场合和与虚拟内存的区别进行解析,帮助读者更好地理解操作系统的内存管理机制。同时,本文还提供了相关章节的链接,方便读者深入学习Windows内存管理及C++内存分配实例的其他内容。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文介绍了一个适用于PHP应用快速接入TRX和TRC20数字资产的开发包,该开发包支持使用自有Tron区块链节点的应用场景,也支持基于Tron官方公共API服务的轻量级部署场景。提供的功能包括生成地址、验证地址、查询余额、交易转账、查询最新区块和查询交易信息等。详细信息可参考tron-php的Github地址:https://github.com/Fenguoz/tron-php。 ... [详细]
author-avatar
等待的承诺灬_231
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有