嵌入式学习-uboot-lesson7-内存初始化

Posted Stoneshen1211

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了嵌入式学习-uboot-lesson7-内存初始化相关的知识,希望对你有一定的参考价值。

6410所使用的内存为DDR 210使用的是DDR2 2440使用的是SDRAM,关于他们之间的区别,我在以前的文章中ok6410内存及启动流程简单介绍过,有兴趣的可以看看。

1. 地址空间

S3C6410处理器拥32位地址总线,其寻址空间为4GB。其中高2GB为保留区,低2GB区域又可划分为两部分:主存储区和外设区。
这里写图片描述
外设区主要是与6410寄存器相关,在核心初始化—外设基地址初始化中,有说明外设的寄存器的基地址为0x70000000
这里写图片描述
下面则是主存储区的地址分布,在以前的课程中有介绍,现在贴出来加强理解
这里写图片描述
主存储区可以分为

  • Boot镜像区
  • 内部存储区
  • 静态存储区
  • 保留区
  • 动态存储区

这里写图片描述

启动镜像区

这个区域并没有固定的存储介质与之对应,也就是没有实际的映射内存。但是可以把不同的启动介质的地址映射到该区域。比如说选择了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开始的原因。

2. 6410内存芯片连接

这里写图片描述
如上图可以看到,6410的内存是由两块128MB的内存芯片连接而成,除了每个芯片的16位数据位不同,其他均相同。

3.内存初始化编程

这里写图片描述
根据上面的DRAM控制器初始化流程,可以得到以下步骤:

  • 1.配置memc_cmd 使DRAM控制器进入 config 状态
  • 2.写 内存时序 芯片配置 id配置等寄存器
  • 3.等待200微妙,使SDRAM电压和时钟进入稳定状态,但是当cpu工作的时候,已经进入稳定的状态,因此这一步可以不做
  • 4.执行内存初始化
  • 5.配置memc_cmd 使DRAM控制器进入 ready 状态
  • 6.检查 memc_stat 是否为2b01

step1

这里写图片描述

根据上面的图,可知需要设置[2:0]位设置位0b100即可

  ldr r0,=0x7e001004    
  mov r1,#0x4 
  str r1,[r0]

step2

这一步骤的主要流程在6410的手册中并没有找到具体的过程,因此主要参考内存芯片手册和uboot相关步骤写的。

    ldr r0, =0x7e001010  @刷新寄存器地址
    ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) )      @设置刷新时间
    str r1, [r0]

    ldr r0, =0x7e001014  @CAS latency寄存器
    mov r1, #(3 << 1)
    str r1, [r0]

    ldr r0, =0x7e001018  @t_DQSS寄存器
    mov r1, #0x1
    str r1, [r0]

    ldr r0, =0x7e00101c  @T_MRD寄存器
    mov r1, #0x2
    str r1, [r0]

    ldr r0, =0x7e001020   @t_RAS寄存器
    ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001024   @t_RC寄存器
    ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001028   @t_RCD寄存器
    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e00102c   @t_RFC寄存器
    ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001030   @t_RP寄存器
    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001034   @t_rrd寄存器
    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001038   @t_wr寄存器
    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
 @  ldr r2, [r0]
    str r1, [r0]

    ldr r0, =0x7e00103c   @t_wtr寄存器
    mov r1, #0x07
    str r1, [r0]

    ldr r0, =0x7e001040   @t_xp寄存器   
    mov r1, #0x02
    str r1, [r0]

    ldr r0, =0x7e001044   @t_xsr寄存器  
    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001048   @t_esr寄存器
    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e00100c   @内存控制配置寄存器
    ldr r1, =0x00010012   @配置控制器
    str r1, [r0]

    ldr r0, =0x7e00104c   @32位DRAM配置控制寄存器
     ldr r1, =0x0b45
    str r1, [r0]

    ldr r0, =0x7e001200   @片选寄存器
    ldr r1, =0x150f8
    str r1, [r0]

    ldr r0, =0x7e001304   @用户配置寄存器 
    mov r1, #0x0
    str r1, [r0]     

step3

等待200μs 来使SDRAM 电源和时钟稳定。当 CPU 开始工作时,电源和时钟已经被稳定下来因此多余 不做。

step4

下面是step4 内存初始化中的各个步骤
这里写图片描述

step4.1

这里写图片描述
根据上图,使[19:18]位为0b011即可满足要求,因此转化为16进制为0xc0000

    ldr r0,=0x7e001008
    ldr r1,=0xc0000
    str r1,[r0]

step4.2

根据上图,使[19:18]位为0b000即可满足要求

    ldr r0,=0x7e001008
    ldr r1,=0x0
    str r1,[r0]

step4.3 step4.4

4.3 和 4.4 为相同的操作,执行两遍

这里写图片描述
根据上图,使[19:18]位为0b001即可满足要求,因此转化为16进制为0x40000

    ldr r0,=0x7e001008
    ldr r1,=0x40000
    str r1,[r0]

    ldr r0,=0x7e001008
    ldr r1,=0x40000
    str r1,[r0]    

step4.5

参考自uboot源码

    ldr r0,=0x7e001008
    ldr r1,=0xa0000
    str r1,[r0]    

step4.6

参考自uboot源码

    ldr r0,=0x7e001008
    ldr r1,=0x80032
    str r1,[r0]    

step5

这里写图片描述
如上图所示,需要设置[2:0]位0b000即可,

     ldr r0,=0x7e001004
    mov r1,#0x0
    str r1,[r0]

step6

这里写图片描述
根据上图,需要设置其为ready状态,即[1:0]为0b10

check_ready:
ldr r0,=0x7e001000
ldr r1,[r0]
mov r2,#0x3
and r1,r1,r2  @将r1r2进行位与操作
cmp r1,#0x1  @与0x1进行比较
bne check_ready @不相等,跳转到check_ready

step7

在代码设置之前,需要设置DDR的管脚为数据管脚,要设置第二块内存芯片的数据引脚,如下所示
这里写图片描述

这里写图片描述

    ldr r0,=0x7e00f120  @设置为数据引脚
    mov r1,#0x0
    str r1,[r0]    

以下是全部代码片段:

Makefile

all: start.o mem.o
    arm-linux-ld -Tgboot.lds -o gboot.elf $^
    arm-linux-objcopy -O binary gboot.elf gboot.bin

%.o : %.S
    arm-linux-gcc -g -c $^

%.o : %.c
    arm-linux-gcc -g -c $^

.PHONY: clean
clean:
    rm *.o *.elf *.bin

start.S

@****************************
@name: start.S
@by  : stone
@time: 2016.6.26
@function: 
@     异常向量表
@         设置SVC模式
@         关闭看门狗
@         关闭中断
@         关闭MMU
@         外设基地址初始化
@         点亮LED
@         时钟初始化
@         内存初始化
@****************************

.text
.global _start  @将_start声明为全局变量
_start:
        b   reset                       
        ldr pc, _undefined_instruction  
        ldr pc, _software_interrupt     
        ldr pc, _prefetch_abort         
        ldr pc, _data_abort             
        ldr pc, _not_used               
        ldr pc, _irq                    
        ldr pc, _fiq

_undefined_instruction: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:      .word not_used
_irq:           .word irq
_fiq:           .word fiq                   

undefined_instruction:  @处理未定义指令异常
        nop

software_interrupt:     @软中断
        nop

prefetch_abort:         @预取指令异常
        nop

data_abort:             @数据访问异常
        nop

not_used:               @空位
        nop

irq:                    @中断
        nop

fiq:                    @快速中断
        nop

reset:                          @reset
    bl set_svc              @设置为SVC模式
    bl set_peri_port        @外设基地址初始化
    bl disable_watchdog     @关闭看门狗
    bl disable_interrupt    @关闭中断
    bl disable_mmu          @关闭mmu
    bl init_clock           @时钟初始化
    bl mem_init             @内存初始化
    bl light_led            @点亮LED

set_svc:        
    mrs r0, cpsr        @将值取出cpsr寄存器
    bic r0, r0, #0x1f   @将后5位 即M[4:0]清零 
    orr r0, r0, #0xd3   @0b10011 转化为16进制为0x13 同时为了屏蔽irq和fiq,可以将其设置为0b11010011即0xd3  
    msr cpsr, r0        @将值送回cpsr寄存器
    mov pc, lr              @返回

set_peri_port:
    ldr r0, =0x70000000     @基地址
    orr r0, r0, #0x13       @256MB
    mcr p15,0,r0,c15,c2,4   @写入cp15
    mov pc, lr

#define pwTCON 0x7E004000       @WTCON寄存器
disable_watchdog: 
        ldr r0, =pwTCON         @把地址装载到R0
        mov r1, #0x0            @置0,关闭看门狗
        str r1,[r0]     
        mov pc,lr

disable_interrupt:
        mvn r1,#0x0             @0x0 取反,给r1
        ldr r0,=0x71200014      @VIC0
        str r1,[r0]
        ldr r0,=0x71300014      @VIC1
        str r1,[r0]
        mov pc,lr

disable_mmu:
        mcr p15,0,r0,c7,c7,0    @使ICACHE 和DCACHE 无效
    mrc p15,0,r0,c1,c0,0    @read control register
    bic r0,r0,#0x00000007   @mmu 和 dcache置零
    mcr p15,0,r0,c1,c0,0    @write control register
    mov pc,lr

#define CLK_DIV0 0x7e00f020
#define CLK_SRC  0x7e00f01c
#define OTHERS   0x7e00f900
#define MPLL_CON 0X7E00F010
#define APLL_CON 0X7E00F00c
#define PLL_VAL ((1<<31)|(266<<16)|(3<<8)|(1<<0))
#define DIV_VAL ((0X0<<0)|(0X1<<9)|(0X1<<8)|(0X3<<12))
init_clock:
        ldr r0,=CLK_DIV0 @设置分频系数
        ldr r1,=DIV_VAL
        str r1,[r0]

        ldr r0,=OTHERS   @设置异步工作模式 第7位为06位为0(时钟选择器)
        ldr r1,[r0]
        bic r1,r1,#0xc0
        str r1,[r0]

        ldr r0,=APLL_CON @APLL设置为533Mhz
        ldr r1,=PLL_VAL
        str r1,[r0]

        ldr r0,=MPLL_CON @MPLL设置为533Mhz
        ldr r1,=PLL_VAL
        str r1,[r0]

        ldr r0, =CLK_SRC @选择时钟源为APLL MPLL还是外部
        mov r1, #0x3     @APLL MPLL
        str r1, [r0]        
        mov pc,lr

#define GPMCON 0x7F008820       @控制寄存器
#define GPMDAT 0x7F008824   @数据寄存器  
light_led:
        ldr r0,=GPMCON
        ldr r1,=0x1111  @输出模式
        str r1,[r0]

        ldr r0,=GPMDAT
        ldr r1,=0x00    @低电平点亮
        str r1,[r0] 
        mov pc,lr

mem.S

@*************************************
@name : mem.S
@time : 2016/06/26
@function : 内存初始化相关代码
@************************************

.text              @代码段
.global mem_init
mem_init:
    ldr r0,=0x7e00f120  @设置为数据引脚
    mov r1,#0x0
    str r1,[r0] 

    ldr r0,=0x7e001004   @配置寄存器 使DRAM控制器进入 config 状态
    mov r1,#0x4
    str r1,[r0]

    ldr r0, =0x7e001010  @刷新寄存器地址
    ldr r1, =( ( 7800 / ( 1000000000/133000000 ) + 1 ) )      @设置刷新时间
    str r1, [r0]

    ldr r0, =0x7e001014  @CAS latency寄存器
    mov r1, #(3 << 1)
    str r1, [r0]

    ldr r0, =0x7e001018  @t_DQSS寄存器
    mov r1, #0x1
    str r1, [r0]

    ldr r0, =0x7e00101c  @T_MRD寄存器
    mov r1, #0x2
    str r1, [r0]

    ldr r0, =0x7e001020   @t_RAS寄存器
    ldr r1, =( ( 45 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001024   @t_RC寄存器
    ldr r1, =( ( 68 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001028   @t_RCD寄存器
    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e00102c   @t_RFC寄存器
    ldr r1, =( ( 80 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001030   @t_RP寄存器
    ldr r1, =( ( 23 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001034   @t_rrd寄存器
    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001038   @t_wr寄存器
    ldr r1, =( ( 15 / ( 1000000000 / 133000000 ) + 1 ) )
 @  ldr r2, [r0]
    str r1, [r0]

    ldr r0, =0x7e00103c   @t_wtr寄存器
    mov r1, #0x07
    str r1, [r0]

    ldr r0, =0x7e001040   @t_xp寄存器   
    mov r1, #0x02
    str r1, [r0]

    ldr r0, =0x7e001044   @t_xsr寄存器  
    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e001048   @t_esr寄存器
    ldr r1, =( ( 120 / ( 1000000000 / 133000000 ) + 1 ) )
    str r1, [r0]

    ldr r0, =0x7e00100c   @内存控制配置寄存器
    ldr r1, =0x00010012   @配置控制器
    str r1, [r0]

    ldr r0, =0x7e00104c   @32位DRAM配置控制寄存器
     ldr r1, =0x0b45
    str r1, [r0]

    ldr r0, =0x7e001200   @片选寄存器
    ldr r1, =0x150f8
    str r1, [r0]

    ldr r0, =0x7e001304   @用户配置寄存器 
    mov r1, #0x0
    str r1, [r0]        

    ldr r0,=0x7e001008
    ldr r1,=0xc0000
    str r1,[r0]

    ldr r0,=0x7e001008
    ldr r1,=0x0
    str r1,[r0]

    ldr r0,=0x7e001008
    ldr r1,=0x40000
    str r1,[r0]

    ldr r0,=0x7e001008
    ldr r1,=0x40000
    str r1,[r0] 

    ldr r0,=0x7e001008
    ldr r1,=0xa0000
    str r1,[r0] 

    ldr r0,=0x7e001008
    ldr r1,=0x80032
    str r1,[r0] 

    ldr r0,=0x7e001004
    mov r1,#0x0
    str r1,[r0]

check_ready:
    ldr r0,=0x7e001000
    ldr r1,[r0]
    mov r2,#0x3
    and r1,r1,r2    @将r1r2进行位与操作
    cmp r1,#0x1     @与0x1进行比较
    bne check_ready @不相等,跳转到check_ready     
    mov pc,lr

菜鸟一枚,如有错误,多多指教。。。

以上是关于嵌入式学习-uboot-lesson7-内存初始化的主要内容,如果未能解决你的问题,请参考以下文章

UCOS学习之内存管理

嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序

Linux嵌入式驱动学习之路⑤u-boot启动流程分析

嵌入式开发裸机引导操作系统和ARM 内存操作 ( DRAM SRAM 类型 简介 | Logical Bank | 内存地址空间介绍 | 内存芯片连接方式 | 内存初始化 | 汇编代码示例 )(代码片

学习ARM开发(17)

linux进程内存布局