这节我们完成内存的初始化: 我们在 u-boot-2014.04/board/samsung/tiny210/tiny210.c 中实现它, 由于这个函数只需要在 u-boot-spl.bin 中实现,而 u-boot.bin 不需要,同时 smdkv210.c中的其他函数只需要在 u-boot.bin 中实现,前面分析过,编译 u-boot-spl.bin 时,spl/Makefile 会导出一个宏 CONFIG_SPL_BUILD,我们通过这个宏来控制代码是否被编译,下面列出修改后的框架:
首先在 u-boot-2014.04/arch/arm/include/asm/arch-s5pc1xx/cpu.h 中添加与 S5PV210 相关的寄存器定义,后面会用到
编写u-boot-2014.04/arch/arm/include/asm/arch-s5pc1xx/dmc.h:
/* add by shl */
#ifndef __ASM_ARM_ARCH_DRAM_H_
#define __ASM_ARM_ARCH_DRAM_H_
#ifndef __ASSEMBLY__
struct s5pv210_dmc0 {
unsigned int concontrol;
unsigned int memcontrol;
unsigned int memconfig0;
unsigned int memconfig1;
unsigned int directcmd;
unsigned int prechconfig;
unsigned int phycontrol0;
unsigned int phycontrol1;
unsigned char res1[0x08];
unsigned int pwrdnconfig;
unsigned char res2[0x04];
unsigned int timingaref;
unsigned int timingrow;
unsigned int timingdata;
unsigned int timingpower;
unsigned int phystatus;
unsigned int chip0status;
unsigned int chip1status;
unsigned int arefstatus;
unsigned int mrstatus;
unsigned int phytest0;
unsigned int phytest1;
};
struct s5pv210_dmc1 {
unsigned int concontrol;
unsigned int memcontrol;
unsigned int memconfig0;
unsigned int memconfig1;
unsigned int directcmd;
unsigned int prechconfig;
unsigned int phycontrol0;
unsigned int phycontrol1;
unsigned char res1[0x08];
unsigned int pwrdnconfig;
unsigned char res2[0x04];
unsigned int timingaref;
unsigned int timingrow;
unsigned int timingdata;
unsigned int timingpower;
unsigned int phystatus;
unsigned int chip0status;
unsigned int chip1status;
unsigned int arefstatus;
unsigned int mrstatus;
unsigned int phytest0;
unsigned int phytest1;
};
#endif
#endif
在 u-boot-2014.04/board/samsung/tiny210/tiny210.c 中添加头文件:
同时在 u-boot-2014.04/arch/arm/include/asm/arch-s5pc1xx/cpu.h 中添加宏:
现在就可以在u-boot-2014.04/board/samsung/tiny210/tiny210.c 中 实现 ddr_init 了,具体请看源码:
void ddr_init(void)
{
struct s5pv210_dmc0 *const dmc0 = (struct s5pv210_dmc0 *)samsung_get_base_dmc0();
struct s5pv210_dmc1 *const dmc1 = (struct s5pv210_dmc1 *)samsung_get_base_dmc1();
/* DMC0 */
writel(0x00101000, &dmc0->phycontrol0);
writel(0x00101002, &dmc0->phycontrol0); /* DLL on */
writel(0x00000086, &dmc0->phycontrol1);
writel(0x00101003, &dmc0->phycontrol0); /* DLL start */
while ((readl(&dmc0->phystatus) & 0x7) != 0x7); /* wait DLL locked */
writel(0x0FFF2350, &dmc0->concontrol); /* Auto Refresh Counter should be off */
writel(0x00202430, &dmc0->memcontrol); /* Dynamic power down should be off */
writel(0x20E01323, &dmc0->memconfig0);
writel(0xFF000000, &dmc0->prechconfig);
writel(0xFFFF00FF, &dmc0->pwrdnconfig);
writel(0x00000618, &dmc0->timingaref); /* 7.8us * 200MHz = 1560 = 0x618 */
writel(0x19233309, &dmc0->timingrow);
writel(0x23240204, &dmc0->timingdata);
writel(0x09C80232, &dmc0->timingpower);
writel(0x07000000, &dmc0->directcmd); /* NOP */
writel(0x01000000, &dmc0->directcmd); /* PALL */
writel(0x00020000, &dmc0->directcmd); /* EMRS2 */
writel(0x00030000, &dmc0->directcmd); /* EMRS3 */
writel(0x00010400, &dmc0->directcmd); /* EMRS enable DLL */
writel(0x00000542, &dmc0->directcmd); /* DLL reset */
writel(0x01000000, &dmc0->directcmd); /* PALL */
writel(0x05000000, &dmc0->directcmd); /* auto refresh */
writel(0x05000000, &dmc0->directcmd); /* auto refresh */
writel(0x00000442, &dmc0->directcmd); /* DLL unreset */
writel(0x00010780, &dmc0->directcmd); /* OCD default */
writel(0x00010400, &dmc0->directcmd); /* OCD exit */
writel(0x0FF02030, &dmc0->concontrol); /* auto refresh on */
writel(0xFFFF00FF, &dmc0->pwrdnconfig);
writel(0x00202400, &dmc0->memcontrol);
/* DMC1 */
writel(0x00101000, &dmc1->phycontrol0);
writel(0x00101002, &dmc1->phycontrol0); /* DLL on */
writel(0x00000086, &dmc1->phycontrol1);
writel(0x00101003, &dmc1->phycontrol0); /* DLL start */
while ((readl(&dmc1->phystatus) & 0x7) != 0x7); /* wait DLL locked */
writel(0x0FFF2350, &dmc1->concontrol); /* Auto Refresh Counter should be off */
writel(0x00202430, &dmc1->memcontrol); /* Dynamic power down should be off */
writel(0x40E01323, &dmc1->memconfig0);
writel(0xFF000000, &dmc1->prechconfig);
writel(0xFFFF00FF, &dmc1->pwrdnconfig);
writel(0x00000618, &dmc1->timingaref); /* 7.8us * 200MHz = 1560 = 0x618 */
writel(0x19233309, &dmc1->timingrow);
writel(0x23240204, &dmc1->timingdata);
writel(0x09C80232, &dmc1->timingpower);
writel(0x07000000, &dmc1->directcmd); /* NOP */
writel(0x01000000, &dmc1->directcmd); /* PALL */
writel(0x00020000, &dmc1->directcmd); /* EMRS2 */
writel(0x00030000, &dmc1->directcmd); /* EMRS3 */
writel(0x00010400, &dmc1->directcmd); /* EMRS enable DLL */
writel(0x00000542, &dmc1->directcmd); /* DLL reset */
writel(0x01000000, &dmc1->directcmd); /* PALL */
writel(0x05000000, &dmc1->directcmd); /* auto refresh */
writel(0x05000000, &dmc1->directcmd); /* auto refresh */
writel(0x00000442, &dmc1->directcmd); /* DLL unreset */
writel(0x00010780, &dmc1->directcmd); /* OCD default */
writel(0x00010400, &dmc1->directcmd); /* OCD exit */
writel(0x0FF02030, &dmc1->concontrol); /* auto refresh on */
writel(0xFFFF00FF, &dmc1->pwrdnconfig);
writel(0x00202400, &dmc1->memcontrol);
}
在 ddr_init 函数中使用到了宏 samsung_get_base_dmc0和 samsung_get_base_dmc1:
struct s5pv210_dmc0 *const dmc0 = (struct s5pv210_dmc0 *)samsung_get_base_dmc0();
struct s5pv210_dmc1 *const dmc1 = (struct s5pv210_dmc1 *)samsung_get_base_dmc1();
这个宏在 u-boot-2014.04/arch/arm/include/asm/arch-s5pc1xx/cpu.h 中定义
以SAMSUNG_BASE(dmc0, DMC0_BASE)这个宏展开即为:
SAMSUNG_BASE(dmc0, DMC0_BASE) ----- >>
static inline unsigned int samsung_get_base_dmc0(void) \
{ \
if (cpu_is_s5pc100()) \
return S5PC100_dmc0; \
else if (cpu_is_s5pc110()) \
return S5PC110_dmc0; \
else \
return 0; \
}
这里首先判断 CPU 类型,这里只判断了 S5PC100A 和 S5PC110,这里判断 CPU 类型同样使用的是宏:
这个宏展开即为:
这里判断了一个变量 s5p_cpu_id,这个变量通过 s5p_set_cpu_id 函数读取寄存器 PRO_ID 来设置我们不用那么麻烦,直接修改 SAMSUNG_BASE 这个宏,让它直接返回 S5PV210_##base
到这里。内存初始化代码已经完成。下一节继续。