一、时钟初始化
1、修改clock.h
cd arch/arm/mach-s5pv210/include/mach/
vim clock.h
/* add by Sourcelink */
struct s5pv210_clock {
unsigned int apll_lock;
unsigned char res1[0x04];
unsigned int mpll_lock;
unsigned char res2[0x04];
unsigned int epll_lock;
unsigned char res3[0x0c];
unsigned int vpll_lock;
unsigned char res4[0xdc];
unsigned int apll_con0;
unsigned int apll_con1;
unsigned int mpll_con;
unsigned char res5[0x04];
unsigned int epll_con0;
unsigned int epll_con1;
unsigned char res6[0x08];
unsigned int vpll_con;
unsigned char res7[0xdc];
unsigned int clk_src0;
unsigned int clk_src1;
unsigned int clk_src2;
unsigned int clk_src3;
unsigned int clk_src4;
unsigned int clk_src5;
unsigned int clk_src6;
unsigned char res8[0x64];
unsigned int clk_src_mask0;
unsigned int clk_src_mask1;
unsigned char res9[0x78];
unsigned int clk_div0;
unsigned int clk_div1;
unsigned int clk_div2;
unsigned int clk_div3;
unsigned int clk_div4;
unsigned int clk_div5;
unsigned int clk_div6;
unsigned int clk_div7;
unsigned char res10[0x24];
unsigned int clk_gate_sclk;
unsigned char res11[0x18];
unsigned int clk_gate_ip0;
unsigned int clk_gate_ip1;
unsigned int clk_gate_ip2;
unsigned int clk_gate_ip3;
unsigned int clk_gate_ip4;
unsigned char res12[0x0c];
unsigned int clk_gate_block;
unsigned int clk_gate_ip5;
};
2、增加clock初始化函数
cd board/samsung/smdkv210/
vim smdkv210.c
void clock_init(void)
{
u32 val = 0;
struct s5pv210_clock *const clock = (struct s5pv210_clock *)samsung_get_base_clock();
/* 1.设置PLL锁定值 */
writel(0xFFFF, &clock->apll_lock);
writel(0xFFFF, &clock->mpll_lock);
writel(0xFFFF, &clock->epll_lock);
writel(0xFFFF, &clock->vpll_lock);
/* 2.设置PLL的PMS值(使用芯片手册推荐的值),并使能PLL */
/* P M S EN */
writel((3 << 8) | (125 << 16) | (1 << 0) | (1 << 31), &clock->apll_con0); /* FOUT_APLL = 1000MHz */
writel((12 << 8) | (667 << 16) | (1 << 0) | (1 << 31), &clock->mpll_con); /* FOUT_MPLL = 667MHz */
writel((3 << 8) | (48 << 16) | (2 << 0) | (1 << 31), &clock->epll_con0); /* FOUT_EPLL = 96MHz */
writel((6 << 8) | (108 << 16) | (3 << 0) | (1 << 31), &clock->vpll_con); /* FOUT_VPLL = 54MHz */
/* 3.等待PLL锁定 */
while (!(readl(&clock->apll_con0) & (1 << 29)));
while (!(readl(&clock->mpll_con) & (1 << 29)));
while (!(readl(&clock->apll_con0) & (1 << 29)));
while (!(readl(&clock->epll_con0) & (1 << 29)));
while (!(readl(&clock->vpll_con) & (1 << 29)));
/*
** 4.设置系统时钟源,选择PLL为时钟输出 */
/* MOUT_MSYS = SCLKAPLL = FOUT_APLL = 1000MHz
** MOUT_DSYS = SCLKMPLL = FOUT_MPLL = 667MHz
** MOUT_PSYS = SCLKMPLL = FOUT_MPLL = 667MHz
** ONENAND = HCLK_PSYS
*/
writel((1 << 0) | (1 << 4) | (1 << 8) | (1 << 12), &clock->clk_src0);
/* 4.设置其他模块的时钟源 */
/* 6.设置系统时钟分频值 */
val = (0 << 0) | /* APLL_RATIO = 0, freq(ARMCLK) = MOUT_MSYS / (APLL_RATIO + 1) = 1000MHz */
(4 << 4) | /* A2M_RATIO = 4, freq(A2M) = SCLKAPLL / (A2M_RATIO + 1) = 200MHz */
(4 << 8) | /* HCLK_MSYS_RATIO = 4, freq(HCLK_MSYS) = ARMCLK / (HCLK_MSYS_RATIO + 1) = 200MHz */
(1 << 12) | /* PCLK_MSYS_RATIO = 1, freq(PCLK_MSYS) = HCLK_MSYS / (PCLK_MSYS_RATIO + 1) = 100MHz */
(3 << 16) | /* HCLK_DSYS_RATIO = 3, freq(HCLK_DSYS) = MOUT_DSYS / (HCLK_DSYS_RATIO + 1) = 166MHz */
(1 << 20) | /* PCLK_DSYS_RATIO = 1, freq(PCLK_DSYS) = HCLK_DSYS / (PCLK_DSYS_RATIO + 1) = 83MHz */
(4 << 24) | /* HCLK_PSYS_RATIO = 4, freq(HCLK_PSYS) = MOUT_PSYS / (HCLK_PSYS_RATIO + 1) = 133MHz */
(1 << 28); /* PCLK_PSYS_RATIO = 1, freq(PCLK_PSYS) = HCLK_PSYS / (PCLK_PSYS_RATIO + 1) = 66MHz */
writel(val, &clock->clk_div0);
/* 7.设置其他模块的时钟分频值 */
}
二、ddr初始化
1、增加dmc寄存器
cd arch/arm/mach-s5pv210/include/mach/
vim dmc.h
/* add by Sourcelink */
#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
2、增加ddr初始化函数
cd board/samsung/smdkv210/
vim smdkv210.c
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);
}
三、初始化sd卡copy函数
void copy_bl2_to_ram(void)
{
/*
** ch: 通道
** sb: 起始块
** bs: 块大小
** dst: 目的地
** i: 是否初始化
*/
#iefine CopySDMMCtoMem(ch, sb, bs, dst, i) \
(((unsigned char(*)(int, unsigned int, unsigned short, unsigned int*, unsigned char))\
(*((unsigned int *)0xD0037F98)))(ch, sb, bs, dst, i))
unsigned int V210_SDMMC_BASE = *(volatile unsigned int *)(0xD0037488); // V210_SDMMC_BASE
unsigned char ch = 0;
/* 参考S5PV210手册7.9.1 SD/MMC REGISTER MAP */
if (V210_SDMMC_BASE == 0xEB000000) // 通道0
ch = 0;
else if (V210_SDMMC_BASE == 0xEB200000) // 通道2
ch = 2;
CopySDMMCtoMem(ch, 32, 10, (unsigned int *)CONFIG_SYS_SDRAM_BASE, 0);
}
四、更改base地址
在进行clock初始化和ddr初始化时用到了.h中的寄存器地址
struct s5pv210_clock *const clock = (struct s5pv210_clock *)samsung_get_base_clock();
定义了这个结构体变量 需要修改cpu.h
cd arch/arm/mach-s5pv210/include/mach/
vim cpu.h
/* add by Sourcelink */
IS_SAMSUNG_TYPE(s5pv210, 0x56210)
/* modif by Sourcelink */
#define SAMSUNG_BASE(device, base) \
static inline unsigned int samsung_get_base_##device(void) \
{ \
if(cpu_is_s5pv210()) \
return S5PV210_##base; \
else if(cpu_is_s5pc100()) \
return S5PC100_##base; \
}
一开始这么写发现执行都是S5PC100的寄存器基地址,现在还没有发现原因。s5pv210的id函数在上一节有贴出来。希望知道的朋友告知。最后改成了如下:
/* modif by Sourcelink */
#define SAMSUNG_BASE(device, base) \
static inline unsigned int samsung_get_base_##device(void) \
{ \
return S5PV210_##base; \
}
/* add by Sourcelink */
SAMSUNG_BASE(dmc0,DMC0_BASE)
SAMSUNG_BASE(dmc1,DMC1_BASE)
五、添加宏CONFIG_SPL
编译 u-boot-spl.bin 时,spl/Makefile 会导出一个宏 CONFIG_SPL_BUILD,我们通过这个宏来控制代码是否被编译,下面列出修改后的框架
#ifdef CONFIG_SPL_BUILD
六、硬件初始化
cd board/samsung/smdkv210/
vim lowlevel_init.S
/* modif by Sourcelink */
.globl lowlevel_init
lowlevel_init:
mov r9, lr
#ifdef CONFIG_SPL_BUILD
bl clock_init /* 时钟初始化 */
bl ddr_init /* DDR初始化 */
#endif
mov pc, r9 /* 返回 */
七、修改_main函数
cd arch/arm/lib
vim crt0.S
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
/* modied by Sourcelink */
#if !defined(CONFIG_SPL_BUILD)
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
sub sp, sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
mov r9, sp /* GD is above SP */
mov r0, #0
#endif
/* modied by Sourcelink */
#ifdef CONFIG_SPL_BUILD
bl copy_bl2_to_ram /* 拷贝BL2到DDR */
ldr pc, =CONFIG_SYS_SDRAM_BASE /* 跳转到DDR的起始地址执行BL2 */
#else
bl board_init_f
#endif
八、修改ddr基地址
vim include/configs/smdkv210.h
/* DRAM Base */
#define CONFIG_SYS_SDRAM_BASE 0x20000000 /* modif by Sourcelink */
/* Text Base */
#define CONFIG_SYS_TEXT_BASE 0x20000000
九、增加宏
vim configs/smdkv210_defconfig
# add by Sourcelink
CONFIG_SPL=y
十、添加增加头信息的可执行文件
在做完前面九步后进行编译会提示mkexynosspl:Command not find 这是个可执行文件是在make时自动增加头信息用的
分析scripts/Makefile.spl
vim scripts/Makefile.spl
# modif by Sourcelink
$(obj)/$(BOARD)-spl.bin: $(obj)/u-boot-spl.bin
$(if $(wildcard $(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl),\
$(objtree)/spl/board/samsung/$(BOARD)/tools/mk$(BOARD)spl,\
$(objtree)/tools/mksource210spl) $(VAR_SIZE_PARAM) $< $@
endif
把自己编译好的可执行文件Source210 更改成mksource210spl 放到tools目录下
十一、编译和烧写
make smdkv210_defconfig
make spl/u-boot-spl.bin
编译完成后把spl目录下的smdkv210-spl.bin 烧写到sd卡扇区1,再烧写一个其他可运行bin文件到sd卡扇区32