一、初始化时钟
s5pv210内部的irom中有对时钟的初始化,但是其时钟配置不是三星官方的推荐的配置,它的配置是arm主频400MHz,在这里我们在lowlevel_init函数中重新初始化时钟,将主频初始化到1GHz。
初始化后时钟频率如下图所示:
时钟的初始化主要是向相关寄存器中写值,比较模式化,代码部分移植自三星官方,我主要在配置头文件include/configs/s5p_goni.h中添加相应的宏控制就行了, 这些宏主要控制时钟的MUX开关与DIV分频系数。
//clk
//#define CONFIG_CLK_667_166_166_133
//#define CONFIG_CLK_533_133_100_100
//#define CONFIG_CLK_800_200_166_133
//#define CONFIG_CLK_800_100_166_133
#define CONFIG_CLK_1000_200_166_133
//#define CONFIG_CLK_400_200_166_133
//#define CONFIG_CLK_400_100_166_133
#if defined(CONFIG_CLK_667_166_166_133)
#define APLL_MDIV 0xfa
#define APLL_PDIV 0x6
#define APLL_SDIV 0x1
#elif defined(CONFIG_CLK_533_133_100_100)
#define APLL_MDIV 0x215
#define APLL_PDIV 0x18
#define APLL_SDIV 0x1
#elif defined(CONFIG_CLK_800_200_166_133) || \
defined(CONFIG_CLK_800_100_166_133) || \
defined(CONFIG_CLK_400_200_166_133) || \
defined(CONFIG_CLK_400_100_166_133)
#define APLL_MDIV 0x64
#define APLL_PDIV 0x3
#define APLL_SDIV 0x1
#elif defined(CONFIG_CLK_1000_200_166_133)
#define APLL_MDIV 0x7d
#define APLL_PDIV 0x3
#define APLL_SDIV 0x1
#endif
#define APLL_LOCKTIME_VAL 0x2cf
#if defined(CONFIG_EVT1)
/* Set AFC value */
#define AFC_ON 0x00000000
#define AFC_OFF 0x10000010
#endif
#if defined(CONFIG_CLK_533_133_100_100)
#define MPLL_MDIV 0x190
#define MPLL_PDIV 0x6
#define MPLL_SDIV 0x2
#else
#define MPLL_MDIV 0x29b
#define MPLL_PDIV 0xc
#define MPLL_SDIV 0x1
#endif
#define EPLL_MDIV 0x60
#define EPLL_PDIV 0x6
#define EPLL_SDIV 0x2
#define VPLL_MDIV 0x6c
#define VPLL_PDIV 0x6
#define VPLL_SDIV 0x3
/* CLK_DIV0 */
#define APLL_RATIO 0
#define A2M_RATIO 4
#define HCLK_MSYS_RATIO 8
#define PCLK_MSYS_RATIO 12
#define HCLK_DSYS_RATIO 16
#define PCLK_DSYS_RATIO 20
#define HCLK_PSYS_RATIO 24
#define PCLK_PSYS_RATIO 28
#define CLK_DIV0_MASK 0x7fffffff
#define set_pll(mdiv, pdiv, sdiv) (1<<31 | mdiv<<16 | pdiv<<8 | sdiv)
#define APLL_VAL set_pll(APLL_MDIV,APLL_PDIV,APLL_SDIV)
#define MPLL_VAL set_pll(MPLL_MDIV,MPLL_PDIV,MPLL_SDIV)
#define EPLL_VAL set_pll(EPLL_MDIV,EPLL_PDIV,EPLL_SDIV)
#define VPLL_VAL set_pll(VPLL_MDIV,VPLL_PDIV,VPLL_SDIV)
#if defined(CONFIG_CLK_667_166_166_133)
#define CLK_DIV0_VAL ((0<
#define CLK_DIV0_VAL ((0<
#define CLK_DIV0_VAL ((0<
#define CLK_DIV0_VAL ((0<
#define CLK_DIV0_VAL ((1<
#define CLK_DIV0_VAL ((1<
#elif defined(CONFIG_CLK_1000_200_166_133)
#define CLK_DIV0_VAL ((0<
#define CLK_DIV1_VAL ((1<<16)|(1<<12)|(1<<8)|(1<<4))
#define CLK_DIV2_VAL (1<<0)
这些宏适配了7种不同的时钟配置,需要哪一种就打开对应的宏就行了,我们在这里打开了#define CONFIG_CLK_1000_200_166_133也就是说最终配置的时钟和上图中一致。
二、修改banner打印信息
banner打印信息由三部分组成
#define U_BOOT_VERSION_STRING U_BOOT_VERSION " (" U_BOOT_DATE " - " \
U_BOOT_TIME ")" CONFIG_IDENT_STRING
整体上由U_BOOT_VERSION_STRING 这个宏控制。
第一部分:U_BOOT_VERSION,这个在主Makefile中有定义,最终生成的include/generated/version_autogenerated.h头文件中包含了对这个宏的定义。
第二部分:" (" U_BOOT_DATE " - " U_BOOT_TIME ")"代表日期和时间,也是在makefile中生成然后宏定义在include/generated/timestamp_autogenerated.h 头文件中。
第三部分:uboot中将其定义为空
#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif
我们只需要在配置头文件include/configs/s5p_goni.h中定义这个宏为我们想要的字符串就可以了;我的定义如下:
#define CONFIG_IDENT_STRING " for LWL210"
三、打印cpu的时钟信息
修改print_cpuinfo函数代码如下:
char buf[10][32];
#if 0 // added by lwl
printf("CPU:\t%s%X@%sMHz\n",
s5p_get_cpu_name(), s5p_cpu_id,
strmhz(buf, get_arm_clk()));
#endif // #if 0
/* added by lwl; uart print clk info */
printf("\nCPU: S5PV210@%sMHz\n", strmhz(buf[0], get_arm_clk()));
printf(" APLL = %sMHz, HclkMsys = %sMHz, PclkMsys = %sMHz\n",
strmhz(buf[1], get_pll_clk(APLL)), strmhz(buf[2], get_hclk_sys(0)), strmhz(buf[3], get_pclk_sys(0)));
printf(" MPLL = %sMHz, EPLL = %sMHz\n",
strmhz(buf[4], get_pll_clk(MPLL)), strmhz(buf[5], get_pll_clk(EPLL)));
printf(" HclkDsys = %sMHz, PclkDsys = %sMHz\n",
strmhz(buf[6], get_hclk_sys(1)), strmhz(buf[7], get_pclk_sys(1)));
printf(" HclkPsys = %sMHz, PclkPsys = %sMHz\n",
strmhz(buf[8], get_hclk_sys(2)), strmhz(buf[9], get_pclk_sys(2)));
/* end added */
return 0;
上面就是格式化打印时钟信息的函数,其中用到的工具函数均在arch/arm/cpu/armv7/s5pc1xx/clock.c文件中有定义。其中用到的两个函数get_hclk_sys、get_pclk_sys在文件中定义为static,由于我们要在别的文件中引用他们,所以去掉它们的static属性,并在头文件arch/arm/include/asm/arch-s5pc1xx/clk.h中添加对他们的申明:
/* added by lwl */
unsigned long get_hclk_sys(int dom);
unsigned long get_pclk_sys(int dom);
/* end added */
这样在包含了该头文件的c文件中就能调用上面这两个函数。
四、修改开发板名称打印信息
在checkboard函数中添加puts("Board:\tLWL210\n"); // modified by lwl
串口打印开发板名称:LWL210
五、修改ddr软初始化
我们的开发板上使用了两块ddr,有两个bank,为bank0与bank1,所以dram_init函数去掉bank2,修改如下:
/*gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE +
PHYS_SDRAM_3_SIZE; */
gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE; // modified by lwl
return 0;
dram_init_banksize函数也去掉bank2
gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
// modified by lwl
//gd->bd->bi_dram[2].start = PHYS_SDRAM_3;
//gd->bd->bi_dram[2].size = PHYS_SDRAM_3_SIZE;
在配置头文件中修改ddr的信息:
#define CONFIG_NR_DRAM_BANKS 2 // modified by lwl; 2 banks
#define PHYS_SDRAM_1 CONFIG_SYS_SDRAM_BASE /* OneDRAM Bank #0 */
//#define PHYS_SDRAM_1_SIZE (80 << 20) /* 80 MB in Bank #0 */
#define PHYS_SDRAM_1_SIZE (256 << 20) /* modified by lwl; 256 MB in Bank #0 */
#define PHYS_SDRAM_2 0x40000000 /* mDDR DMC1 Bank #1 */
#define PHYS_SDRAM_2_SIZE (256 << 20) /* 256 MB in Bank #1 */
//#define PHYS_SDRAM_3 0x50000000 /* mDDR DMC2 Bank #2 */
//#define PHYS_SDRAM_3_SIZE (128 << 20) /* 128 MB in Bank #2 */
去掉bank2的信息;bank0改成256MB。
六、修改机器码
由于我们的uboot将来去启动smdkv210的内核,在这里将机器码与其内核的机器码设置成一样的,修改board_init函数
gd->bd->bi_arch_number = MACH_TYPE_SMDKV210; // modified by lwl
所有开发板的机器码信息全部在arch/arm/include/asm/mach-types,h中有定义
七、去掉onenand的初始化,添加MMC的初始化
由于我们的开发板上没有onenand,只有iNand,所以我们应该屏蔽掉队onenand的初始化,添加队mmc的初始化。代码中用宏进行控制。
去掉//#define CONFIG_CMD_ONENAND // modified by lwl
由于去掉了这个宏,其他依赖于这个宏的文件预处理时会报错,所以直接将uboot中关于onenand的文件不加入编译之中。
修改board/samsung/goni/Makefile,去掉对onenand.c的编译。
我们的环境变量将来保存在iNand中,随意去掉环境变量与onenand有关的宏
#if 0
/* FLASH and environment organization */
#define CONFIG_ENV_IS_IN_ONENAND 1
#define CONFIG_ENV_SIZE (256 << 10) /* 256 KiB, 0x40000 */
#define CONFIG_ENV_ADDR (1 << 20) /* 1 MB, 0x100000 */
#define CONFIG_USE_ONENAND_BOARD_INIT
#define CONFIG_SAMSUNG_ONENAND 1
#define CONFIG_SYS_ONENAND_BASE 0xB0000000
#endif
添加环境变量与iNand有关的宏,CONFIG_SYS_MMC_ENV_DEV 表示设备0,指的是内部的iNand,将环境变量保存在iNand中而不是SD卡中。
// env
#define CONFIG_ENV_IS_IN_MMC 1
#define CONFIG_ENV_SIZE CFG_ENV_SIZE
#define CONFIG_SYS_MMC_ENV_DEV 0
这样对于common文件夹下有关环境变量的文件Makefile就会选择env_mmc.c,将其添加到编译之中,这种条件编译主要靠宏控制,如下:
COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o
COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o
XCOBJS-$(CONFIG_ENV_IS_EMBEDDED) += env_embedded.o
COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_embedded.o
XCOBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_embedded.o
COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_embedded.o
COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o
COBJS-$(CONFIG_ENV_IS_IN_FAT) += env_fat.o
COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o
COBJS-$(CONFIG_ENV_IS_IN_NVRAM) += env_nvram.o
COBJS-$(CONFIG_ENV_IS_IN_ONENAND) += env_onenand.o
COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
COBJS-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o
COBJS-$(CONFIG_ENV_IS_IN_UBI) += env_ubi.o
COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
八、运行结果
重新编译uboot,运行结果如下:
可以看到已经进入了uboot的命令行,但是MMC设备读取失败,主要是MMC设备的驱动部分没有修改,接下来要做的就是对MMC驱动的移植。