一、DRAM初始化步骤
第一步、设置 DRAM Driver Strength( 内存访问信号的强度)
第二步、初始化 PHY DLL
第三步、初始化 DMC0
第四步、初始化 DDR2 DRAM
二、相关代码
1、dram_init.S
#include "s5pv210.h"
// MemControl BL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off
#define DMC0_MEMCONTROL 0x00202400
// MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_0 0x20F00313
// MemConfig1
#define DMC0_MEMCONFIG_1 0x00F00313
// TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMINGA_REF 0x00000618
// TimingRow for @200MHz
#define DMC0_TIMING_ROW 0x2B34438A
// TimingData CL=3
#define DMC0_TIMING_DATA 0x24240000
// TimingPower
#define DMC0_TIMING_PWR 0x0BDC0343
.globl dram_init
dram_init:
// 1. 设置DMC0 Drive Strength (Setting 2X)
ldr r0, =ELFIN_GPIO_BASE
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_0DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_1DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_2DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_3DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_4DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_5DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_6DRV_SR_OFFSET]
ldr r1, =0x0000AAAA
str r1, [r0, #MP1_7DRV_SR_OFFSET]
ldr r1, =0x00002AAA
str r1, [r0, #MP1_8DRV_SR_OFFSET]
// 2. 初始化PHY DLL
ldr r0, =APB_DMC_0_BASE
//step 3: PhyControl0 DLL parameter setting, manual 0x00101000
ldr r1, =0x00101000
str r1, [r0, #DMC_PHYCONTROL0]
//PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case
ldr r1, =0x00000086
str r1, [r0, #DMC_PHYCONTROL1]
//step 2: PhyControl0 DLL on
ldr r1, =0x00101002
str r1, [r0, #DMC_PHYCONTROL0]
//step 4: PhyControl0 DLL start
ldr r1, =0x00101003
str r1, [r0, #DMC_PHYCONTROL0]
find_lock_val:
//Loop until DLL is locked
ldr r1, [r0, #DMC_PHYSTATUS]
and r2, r1, #0x7
cmp r2, #0x7
bne find_lock_val
//Force Value locking
and r1, #0x3fc0
mov r2, r1, LSL #18
orr r2, r2, #0x100000
orr r2 ,r2, #0x1000
orr r1, r2, #0x3
str r1, [r0, #DMC_PHYCONTROL0]
// 3. 初始化DMC0
//step 5: ConControl auto refresh off
ldr r1, =0x0FFF2010
str r1, [r0, #DMC_CONCONTROL]
//step 6: MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
ldr r1, =DMC0_MEMCONTROL
str r1, [r0, #DMC_MEMCONTROL]
//step 7: MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
ldr r1, =DMC0_MEMCONFIG_0
str r1, [r0, #DMC_MEMCONFIG0]
//MemConfig1
ldr r1, =DMC0_MEMCONFIG_1
str r1, [r0, #DMC_MEMCONFIG1]
//step 8:PrechConfig
ldr r1, =0xFF000000
str r1, [r0, #DMC_PRECHCONFIG]
//step 9:TimingAref 7.8us//133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
ldr r1, =DMC0_TIMINGA_REF
str r1, [r0, #DMC_TIMINGAREF]
//TimingRow for //200MHz
ldr r1, =DMC0_TIMING_ROW
str r1, [r0, #DMC_TIMINGROW]
//TimingData CL=4
ldr r1, =DMC0_TIMING_DATA
str r1, [r0, #DMC_TIMINGDATA]
//TimingPower
ldr r1, =DMC0_TIMING_PWR
str r1, [r0, #DMC_TIMINGPOWER]
// 4. 初始化DDR2 DRAM
//DirectCmd chip0 Deselect
ldr r1, =0x07000000
str r1, [r0, #DMC_DIRECTCMD]
//step 16:DirectCmd chip0 PALL
ldr r1, =0x01000000
str r1, [r0, #DMC_DIRECTCMD]
//step 17:DirectCmd chip0 EMRS2
ldr r1, =0x00020000
str r1, [r0, #DMC_DIRECTCMD]
//step 18:DirectCmd chip0 EMRS3
ldr r1, =0x00030000
str r1, [r0, #DMC_DIRECTCMD]
//step 19:DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
ldr r1, =0x00010400
str r1, [r0, #DMC_DIRECTCMD]
//step 20:DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
ldr r1, =0x00000542
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 PALL
ldr r1, =0x01000000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 REFA
ldr r1, =0x05000000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 REFA
ldr r1, =0x05000000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 MRS (MEM DLL unreset)
ldr r1, =0x00000442
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 EMRS1 (OCD default)
ldr r1, =0x00010780
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip0 EMRS1 (OCD exit)
ldr r1, =0x00010400
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 Deselect
ldr r1, =0x07100000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 PALL
ldr r1, =0x01100000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 EMRS2
ldr r1, =0x00120000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 EMRS3
ldr r1, =0x00130000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)
ldr r1, =0x00110400
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4
ldr r1, =0x00100542
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 PALL
ldr r1, =0x01100000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 REFA
ldr r1, =0x05100000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 REFA
ldr r1, =0x05100000
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 MRS (MEM DLL unreset)
ldr r1, =0x00100442
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 EMRS1 (OCD default)
ldr r1, =0x00110780
str r1, [r0, #DMC_DIRECTCMD]
//DirectCmd chip1 EMRS1 (OCD exit)
ldr r1, =0x00110400
str r1, [r0, #DMC_DIRECTCMD]
//ConControl auto refresh on
ldr r1, =0x0FF02030
str r1, [r0, #DMC_CONCONTROL]
//PwrdnConfig
ldr r1, =0xFFFF00FF
str r1, [r0, #DMC_PWRDNCONFIG]
//MemControl BL=4, 1 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
ldr r1, =0x00202400
str r1, [r0, #DMC_MEMCONTROL]
mov pc, lr
该代码来自友善之臂官方用户手册。
2、s5pv210.h
这里面都是一些和寄存器有关的宏定义,内容太多就不贴出来了。
3、start.s
/*
* 代码:初始化DRAM并且重定位代码到DRAM0x30000000
* 日期:2020.7.12
* 作者:glass love
*
*/
//要开icache就将 CONFIG_SYS_ICACHE_OFF写为1,关则写为0
#define CONFIG_SYS_ICACHE 1
.globl _start
_start:
/**********************关看门狗*******************************/
//通过查阅数据手册知道控制看门狗开关的寄存器是:
//Watchdog Timer Control Register (WTCON, R/W, Address =0xE2700000 )
//WTCON寄存器的bit[0]位是启用或禁用复位信号的看门狗定时器输出位
//1为启用,0为禁止
//因此只需要往WTCON中写入0x0即可
ldr r0, =0x00000000
ldr r1, =0xE2700000
str r0, [r1]
/**********************开icache*********************************/
//打开icache可以提高运行速度
//读出协处理器cp15的c1的值到r0中
mrc p15, 0, r0, c1, c0, 0
#if CONFIG_SYS_ICACHE
//将cp15协处理器的bit[12]置一(开icache)
orr r0, r0, #0x00001000
#else
//将cp15协处理器的bit[12]清零(关icache)
bic r0, r0, #0x00001000
#endif
//将r0中的值写入到cp15协处理器的c1中
mcr p15, 0, r0, c1, c0, 0
/***********************设置栈****************************/
//IROM 里的固定代码设置的 sp 就等于 0xD003_7D80,
//所以我们设置栈一般就指向0xD003_7D80,以调用c函数
ldr sp, =0xD0037D80
/**********************初始化DRAM**************************/
bl dram_init
/*************************重定位***************************/
//adr短加载,加载_start的地址,即_start的当前地址
adr r0, _start
//ldr长加载,加载_start的链接地址
ldr r1, =_start
//加载bss_start的链接地址
ldr r2, =bss_start
//比较r0和r1是否相同
cmp r0, r1
beq clear_bss
//复制代码到链接地址
copy_loop:
ldr r3, [r0], #4 //源代码
str r3, [r1], #4 //目标代码
cmp r1, r2 //只用复制到bss_start处就可以了
bne copy_loop
//清bss段
clear_bss:
ldr r0, =bss_start
ldr r1, =bss_end
cmp r0, r1
beq run_dram
ldr r2, =0x0
clear_loop:
str r2, [r0], #4
cmp r0, r1
bne clear_loop
//跳转到链接地址中的led函数处
run_dram:
ldr pc, =led_blink
//汇编死循环
b .
4、dram.lds
SECTIONS
{
. = 0x30000000; /*指定链接地址为DRAM0的0x30000000地址*/
.text : {
start.o /*表示start.o排在代码段的最开始*/
* (.text) /*(.text)表示后面的顺序随意*/
}
.data : {
* (.data)
}
bss_start = .; /*将bss段的起始地址赋给bss_start,以方便外部使用该地址*/
.bss : {
* (.bss)
}
bss_end = .; /*bss_end同上*/
}
5、Makefile
led_link_dram.bin: start.o led.o dram_init.o
arm-linux-ld -Tdram.lds -o led_link_dram.elf $^
arm-linux-objcopy -O binary led_link_dram.elf led_link_dram.bin
arm-linux-objdump -D led_link_dram.elf > led_link_dram_elf.dis
gcc mkv210_image.c -o mk210
./mk210 led_link_dram.bin 210.bin
%.o : %.S
arm-linux-gcc -o $@ $< -c -nostdlib
%.o : %.c
arm-linux-gcc -o $@ $< -c -nostdlib
clear:
rm *.o *.elf *.bin *.dis mk210 -f
其余几个代码较上一节均为变化。