这节我们完成内存的初始化: 我们在 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
到这里。内存初始化代码已经完成。下一节继续。