u-boot-2016.11移植uboot-spl.bin

一、时钟初始化
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 


你可能感兴趣的:(u-boot)