uboot移植四:DDR初始化与代码重定位

一、DDR初始化

在u-boot-2013.10\board\samsung\goni目录下新建mem_init.S文件,该文件被用来进行DDR的初始化。

1、修改Makefile与u-boot.lds链接脚本

在同目录的Makefile文件中的OTHER_OBJS变量后面添加mem_init.o,将mem_init.S文件加入到编译的目标文件之中,如下所示:

OTHER_OBJS := lowlevel_init.o mem_init.o

修改u-boot.lds文件的代码段,将mem_init.o链接到uboot靠前的位置。

.text :
{
*(.__image_copy_start)
CPUDIR/start.o (.text*)
board/samsung/goni/lowlevel_init.o (.text*)
board/samsung/goni/mem_init.o (.text*)
*(.text*)

}

2、DDR初始化代码

.globl mem_ctrl_asm_init
mem_ctrl_asm_init:

/* 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]



/* DMC1 Drive Strength (Setting 2X) */

ldr r0, =ELFIN_GPIO_BASE

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_0DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_1DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_2DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_3DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_4DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_5DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_6DRV_SR_OFFSET]

ldr r1, =0x0000AAAA
str r1, [r0, #MP2_7DRV_SR_OFFSET]

ldr r1, =0x00002AAA
str r1, [r0, #MP2_8DRV_SR_OFFSET]

/* DMC0 initialization at single Type*/
ldr r0, =APB_DMC_0_BASE

ldr r1, =0x00101000 @PhyControl0 DLL parameter setting, manual 0x00101000
str r1, [r0, #DMC_PHYCONTROL0]

ldr r1, =0x00000086 @PhyControl1 DLL parameter setting, LPDDR/LPDDR2 Case
str r1, [r0, #DMC_PHYCONTROL1]

ldr r1, =0x00101002 @PhyControl0 DLL on
str r1, [r0, #DMC_PHYCONTROL0]

ldr r1, =0x00101003 @PhyControl0 DLL start
str r1, [r0, #DMC_PHYCONTROL0]

find_lock_val:
ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register value
and r2, r1, #0x7
cmp r2, #0x7 @Loop until DLL is locked
bne find_lock_val

and r1, #0x3fc0 
mov r2, r1, LSL #18
orr r2, r2, #0x100000
orr r2 ,r2, #0x1000

orr r1, r2, #0x3 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]

#if 0 /* Memory margin test 10.01.05 */
orr r1, r2, #0x1 @DLL off
str r1, [r0, #DMC_PHYCONTROL0]
#endif
/* setting DDR2 */
ldr r1, =0x0FFF2010 @ConControl auto refresh off
str r1, [r0, #DMC_CONCONTROL]

ldr r1, =0x00212400 @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]

ldr r1, =DMC0_MEMCONFIG_0 @MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
str r1, [r0, #DMC_MEMCONFIG0]

ldr r1, =DMC0_MEMCONFIG_1 @MemConfig1
str r1, [r0, #DMC_MEMCONFIG1]

ldr r1, =0xFF000000 @PrechConfig
str r1, [r0, #DMC_PRECHCONFIG]

ldr r1, =DMC0_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
str r1, [r0, #DMC_TIMINGAREF]

ldr r1, =DMC0_TIMING_ROW @TimingRow for @200MHz
str r1, [r0, #DMC_TIMINGROW]

ldr r1, =DMC0_TIMING_DATA @TimingData CL=3
str r1, [r0, #DMC_TIMINGDATA]

ldr r1, =DMC0_TIMING_PWR @TimingPower
str r1, [r0, #DMC_TIMINGPOWER]

ldr r1, =0x07000000 @DirectCmd chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00020000 @DirectCmd chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00030000 @DirectCmd chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x07100000 @DirectCmd chip1 Deselect
str r1, [r0, #DMC_DIRECTCMD]


ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00120000 @DirectCmd chip1 EMRS2
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00130000 @DirectCmd chip1 EMRS3
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x0FF02030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]

ldr r1, =0xFFFF00FF @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]

ldr r1, =0x00202400 @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]

/* DMC1 initialization */
ldr r0, =APB_DMC_1_BASE

ldr r1, =0x00101000 @Phycontrol0 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL0]

ldr r1, =0x00000086 @Phycontrol1 DLL parameter setting
str r1, [r0, #DMC_PHYCONTROL1]

ldr r1, =0x00101002 @PhyControl0 DLL on
str r1, [r0, #DMC_PHYCONTROL0]

ldr r1, =0x00101003 @PhyControl0 DLL start
str r1, [r0, #DMC_PHYCONTROL0]
find_lock_val1:
ldr r1, [r0, #DMC_PHYSTATUS] @Load Phystatus register value
and r2, r1, #0x7
cmp r2, #0x7 @Loop until DLL is locked
bne find_lock_val1

and r1, #0x3fc0 
mov r2, r1, LSL #18
orr r2, r2, #0x100000
orr r2, r2, #0x1000

orr r1, r2, #0x3 @Force Value locking
str r1, [r0, #DMC_PHYCONTROL0]

#if 0 /* Memory margin test 10.01.05 */
orr r1, r2, #0x1 @DLL off
str r1, [r0, #DMC_PHYCONTROL0]
#endif

/* settinf fot DDR2 */
ldr r0, =APB_DMC_1_BASE

ldr r1, =0x0FFF2010 @auto refresh off
str r1, [r0, #DMC_CONCONTROL]

ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]

ldr r1, =DMC1_MEMCONFIG_0 @MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
str r1, [r0, #DMC_MEMCONFIG0]

ldr r1, =DMC1_MEMCONFIG_1 @MemConfig1
str r1, [r0, #DMC_MEMCONFIG1]

ldr r1, =0xFF000000
str r1, [r0, #DMC_PRECHCONFIG]

ldr r1, =DMC1_TIMINGA_REF @TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
str r1, [r0, #DMC_TIMINGAREF]

ldr r1, =DMC1_TIMING_ROW @TimingRow for @200MHz
str r1, [r0, #DMC_TIMINGROW]

ldr r1, =DMC1_TIMING_DATA @TimingData CL=3
str r1, [r0, #DMC_TIMINGDATA]

ldr r1, =DMC1_TIMING_PWR @TimingPower
str r1, [r0, #DMC_TIMINGPOWER]

ldr r1, =0x07000000 @DirectCmd chip0 Deselect
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00020000 @DirectCmd chip0 EMRS2
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00030000 @DirectCmd chip0 EMRS3
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00000542 @DirectCmd chip0 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01000000 @DirectCmd chip0 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05000000 @DirectCmd chip0 REFA
str r1, [r0, #DMC_DIRECTCMD]


ldr r1, =0x00000442 @DirectCmd chip0 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010780 @DirectCmd chip0 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00010400 @DirectCmd chip0 EMRS1 (OCD exit)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x07100000 @DirectCmd chip1 Deselect
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00120000 @DirectCmd chip1 EMRS2
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00130000 @DirectCmd chip1 EMRS3
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110440 @DirectCmd chip1 EMRS1 (MEM DLL on, DQS# disable)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00100542 @DirectCmd chip1 MRS (MEM DLL reset) CL=4, BL=4
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x01100000 @DirectCmd chip1 PALL
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x05100000 @DirectCmd chip1 REFA
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00100442 @DirectCmd chip1 MRS (MEM DLL unreset)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110780 @DirectCmd chip1 EMRS1 (OCD default)
str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x00110400 @DirectCmd chip1 EMRS1 (OCD exit)

str r1, [r0, #DMC_DIRECTCMD]

ldr r1, =0x0FF02030 @ConControl auto refresh on
str r1, [r0, #DMC_CONCONTROL]

ldr r1, =0xFFFF00FF @PwrdnConfig
str r1, [r0, #DMC_PWRDNCONFIG]

ldr r1, =DMC1_MEMCONTROL @MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
str r1, [r0, #DMC_MEMCONTROL]

mov pc, lr

代码是在三星官方源码的基础上进行修改得到的,主要是针对自己的开发板实际情况进行修改相关的配置。我开发板上的DDR为512M,地址选用0x30000000-0x4FFFFFFF。配置值使用宏来控制,将宏定义在配置头文件include/configs/s5p_goni.h中,如下:

//#define DMC0_MEMCONFIG_0 0x20E01323 // MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_0 0x30F01323 // modified by lwl MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC0_MEMCONFIG_1 0x40F01323 // modified by lwl MemConfig1
#define DMC0_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4E)
#define DMC0_TIMING_ROW 0x28233287 // TimingRow for @200MHz
#define DMC0_TIMING_DATA 0x23240304 // TimingData CL=3
#define DMC0_TIMING_PWR 0x09C80232 // TimingPower

#define DMC1_MEMCONTROL 0x00202400 // MemControl BL=4, 2 chip, DDR2 type, dynamic self refresh, force precharge, dynamic power down off
//#define DMC1_MEMCONFIG_0 0x40C01323 // MemConfig0 512MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_0 0x40F01323 // modified by lwl MemConfig0 256MB config, 8 banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
#define DMC1_MEMCONFIG_1 0x00E01323 // modified by lwl MemConfig1
#define DMC1_TIMINGA_REF 0x00000618 // TimingAref 7.8us*133MHz=1038(0x40E), 100MHz=780(0x30C), 20MHz=156(0x9C), 10MHz=78(0x4
#define DMC1_TIMING_ROW 0x28233289 // TimingRow for @200MHz
#define DMC1_TIMING_DATA 0x23240304 // TimingData CL=3

#define DMC1_TIMING_PWR 0x08280232 // TimingPower

重新编译之后,DDR就可以使用了,接下来就可以进行代码的重定位了,我们将uboot的整体代码复制到DDR的链接地址处,直接跳到第二阶段去执行,第一阶段在内部的iRam中执行,这就是三星CPU的stepstone技术。

二、代码的重定位

重定位代码加在lowlevel_init之后,重定位之前加上串口打印“r”调试信息:

// before relocate; uart print 'r'
ldr r1, =0x72727272
ldr r0, =S5PC110_UART_BASE

str r1, [r0, #0x820] @'r'

重定位之后加上串口打印“e”调试信息:

// after relocate; uart print 'e'
ldr r1, =0x65656565
ldr r0, =S5PC110_UART_BASE

str r1, [r0, #0x820] @'e'

重定位代码在这两个打印信息的中间添加。

1、movi_bl2_copy函数

在board/samsung/goni目录下新建movi.c文件,该文件中写将代码从SD/EMMC中复制到内部DDR中的代码。Makefile修改如下:

# added by lwl; make but not link

OTHER_OBJS := lowlevel_init.o mem_init.o movi.o

u-boot.lds修改如下:

.text :
{
*(.__image_copy_start)
CPUDIR/start.o (.text*)
board/samsung/goni/lowlevel_init.o (.text*)
board/samsung/goni/mem_init.o (.text*)
board/samsung/goni/movi.o (.text*)
*(.text*)

}

函数代码如下:

void movi_bl2_copy(void)
{

ulong ch;
ch = *(volatile u32 *)(0xD0037488);
copy_sd_mmc_to_mem copy_bl2 =
    (copy_sd_mmc_to_mem) (*(u32 *) (0xD0037F98));

u32 ret;
if (ch == 0xEB000000) {
ret = copy_bl2(0, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
}
else if (ch == 0xEB200000) {
ret = copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CFG_PHY_UBOOT_BASE, 0);
}
else
return;

if (ret == 0)
while (1)
;
else
return;

}

该函数中用到的核心函数的入口地址放在0xD0037F98地址处,函数是三星固化在内部iRom中,给我们提供的接口工具,这里直接采用函数指针调用即可。

2、清BSS段

clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */

clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1

ble clbss_l


变量:

.globl _bss_start
_bss_start:
.word __bss_start

.globl _bss_end
_bss_end:
.word __bss_end

主要间接使用u-boot.lds链接脚本中的两个变量__bss_start和__bss_end来定位BSS段,这两个变量在u-boot.lds中定义。

三、结果

重新编译烧录后启动uboot,看到“re”串口打印信息,则表明DDR初始化与代码重定位成功,接下来远跳转到DDR中执行第二阶段的代码:

ldr pc, __main     // 第二阶段

你可能感兴趣的:(uboot移植)