基于OK-2440III的u-boot移植(一)
u-boot的工作过程与硬件关系密切,所以在移植时必须对S3C2440等芯片手册和开发板的硬件有一定的了解。其工作流程主要分为两个部分涉及两个主要的文件:cpu/arm920t/start.S和lib_arm/board.c,先从前面的汇编程序中执行,再跳到后面的C程序中。
移植思路参考网上友友分为六个步骤:
(1)建立好开发板相关的文件,并利用交叉编译器编译生成bin文件用于下载到开发板中运行;
(2)修改相关硬件配置,让uboot能在sdram中运行调试;
(3)修改norflash相关配置,让uboot在norflash中启动运行;
(4)修改nandflash相关配置,让uboot在nandflash中启动运行;
(5)增加uboot的功能,如网络、USB等;(6)引导Linux系统启动。
一.移植环境
目标板:飞凌的ok-2440III开发板(ARM9)
芯片型号:三星的S3C2440
Uboot版本:u-boot-2009.08
宿主机:RedHat Linux AS5
交叉编译器:arm-linux-gcc-4.3.2
二.编译
1.建立板级文件夹:
(1)在board/samsung目录下新建文件夹ok2440,找到相似的板级文件夹smdk2410,并把该文件夹中的所有文件拷贝到ok2440下;
(2)到ok2440目录下,把文件smdk2410.c重命名为ok2440.c;修改该目录下Makefile中的目标(COBJS),把smdk2410.o改为ok2440.o;
2.建立芯片级文件夹:
直接用cpu/arm920t芯片文件夹,不做修改;
3.建立配置文件:
到include/configs目录下,找到相似的配置文件smdk2410.h,将其拷贝并重命名为ok2440.h;
4.建立编译规则:
在根目录下的Makefile中找到ARM体系架构中smdk2410的编译规则
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0
在此处添加ok2440的编译规则
ok2440_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t ok2440 samsung s3c24x0
(注意Makefile中命令行要以tab键开头)
5.在宿主机linux环境下编译:
在终端进入uboot的根目录下执行两条命令:
# make ok2440_config
# make
(注:执行make命令时,前提是在linux下arm-linux-gcc-4.3.2的安装目录设为PATH环境变量,即交叉工具arm-linux-命令的版本是4.3.2
或者执行:#make CROSS_COMPILE=(arm-linux-的安装目录))
(6.由上面编译生成在根目录下的u-boot.bin就可以下载到开发板中,不过还需修改配置才能运行)
基于OK-2440III的u-boot移植(二)
三、在SDRAM中调试运行
(在 基于OK-2440III的u-boot移植(一) 编译通过后修改一下内容)
(注:此移植过程中没有新添加S3C2440的编译条件,都是用原来S3C2410的编译条件)
1.下载到内存中调试时不进行底层初始化、不进行uboot代码拷贝,所以在配置文件include/configs/ok2440.h中加入两句:
# define CONFIG_SKIP_LOWLEVEL_INIT 1
# define CONFIG_SKIP_RELOCATE_UBOOT 1
2.修改cpu/arm920t/start.S相关部分:
(1).在定义S3C2410的寄存器地址处添加以下寄存器的定义:
# define LOCKTIME 0x4C000000
# define MPLLCON 0x4C000004
# define UPLLCON 0x4C000008
# define CAMDIVN 0x4C000018
(2).修改屏蔽中断的位数,如下:
# if defined(CONFIG_S3C2410)
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif
(3).在中断屏蔽完成后添加下面两个寄存器的配置:
ldr r0,=LOCKTIME
mov r1,#0xffffff
str r1,[r0]
ldr r0,=CAMDIVN
mov r1,#0
str r1,[r0]
(4).修改时钟分配比初始化:
/* FCLK:HCLK:PCLK = 1:4:8 */
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
//以下部分是新添加的
//在2440的手册中指出若HDIVN不为0,则需要添加下面三句:
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
//USB时钟48MHz
ldr r0, =UPLLCON
ldr r1, =0x00038022
str r1, [r0]
//arm920t为5级流水线,延迟几个周期,使指令生效
nop
nop
nop
nop
nop
nop
nop
nop
//写MPLL使pll生效,405MHz
ldr r0, =MPLLCON
ldr r1, =0x0007f021
str r1, [r0]
3.修改board/samsung/ok2440/ok2440.c文件中的时钟部分,如下所示:
#elif FCLK_SPEED==1 /* Fout = 405MHz, FCLK:HCLK:PCLK = 1:4:8 */
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
4.修改cpu/arm920t/s3c24x0/speed.c相关部分:
(1).修改FCLK的计算公式:
把下面的部分:
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
替换为:
m = ((r & 0xFF000) >> 12) + 8;
p = ((r & 0x003F0) >> 4) + 2;
s = r & 0x3;
if(pllreg == MPLL)
return((CONFIG_SYS_CLK_FREQ * m * 2) / (p << s));
else
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
(2).修改get_HCLK函数:
/* return HCLK frequency */
ulong get_HCLK(void)
{ S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
//return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
return (get_FCLK()/4); //这里修改的只能用于 s3c2440 ,1:4:8 !!!
}
5.在linux环境下再次编译,下载到内存中就可以运行,终端串口输出信息!
基于OK-2440III的u-boot移植(三)
四.在Nor Flash中调试运行
(在 基于OK-2440III的u-boot移植(二) 在内存中运行通过后修改一下内容)
注:ok2440III开发板的norflash是Intel的JS28F320(4MB)(1device=32blocks,1block=128MB)
1.修改norflash的配置,在include/configs/ok2440.h中关于flash的配置部分都删掉,换成下面的配置:
/*-----------------------------------------------------------------------
* Physical Memory Map
*/
#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */
#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
#define CONFIG_SYS_MONITOR_BASE TEXT_BASE
#define FLASH_BASE0_PRELIM PHYS_FLASH_1
/*------------------------------------------------------------
* FLASH and environment organization
*/
#define CONFIG_SYS_FLASH_PROTECTION 1
#define CONFIG_SYS_MAX_FLASH_BANKS 1 /*max number of memory banks*/
#define CONFIG_SYS_FLASH_SIZE 0x00400000 /*4 MB*/
#define CONFIG_SYS_MAX_FLASH_SECT 32 /*max number of sectors on one chip*/
/*timeout values are in ticks*/
#define CONFIG_SYS_FLASH_ERASE_TOUT (2*CONFIG_SYS_HZ)
/*Timeout for Flash Erase*/
#define CONFIG_SYS_FLASH_WRITE_TOUT (2*CONFIG_SYS_HZ)
/*Timeout for Flash Write*/
#define CONFIG_ENV_IS_IN_FLASH 1
#define CONFIG_ENV_SIZE 0x20000 /*128KB*/
#define CONFIG_ENV_OFFSET 0x40000
2.下载到norflash中运行时需要进行底层初始化,所以要删除之前在配置文件include/configs/ok2440.h中加入的两句:
//#define CONFIG_SKIP_LOWLEVEL_INIT 1
//#define CONFIG_SKIP_RELOCATE_UBOOT 1
3.修改board/samsung/ok2440/lowlevel_init.S文件中SDARM刷新参数为:
#define REFCNT 1258 /* period=7.8125us, HCLK=405/4 Mhz, (2048+1-7.8125*405/4) */
4.修改flash型号相关文件:
(1).用board/cmi/flash.c文件替换board/samsung/ok2440/flash.c文件,使uboot支持Intel的JS28F320型号nor;
(2).修改board/samsung/ok2440/flash.c中函数申明:
static ulong flash_get_size (vu_short *addr, flash_info_t *info);
//static int write_short (flash_info_t *info, ulong dest, ushort data);
static int write_word (flash_info_t *info, ulong dest, ushort data);
static void flash_get_offsets (ulong base, flash_info_t *info);
(3).删除board/samsung/ok2440/flash.c中write_buff和write_short两个函数,用下面两个函数代替:
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
{
ulong cp, wp;
ushort data;
int l;
int i, rc;
wp = (addr & ~1); /* get lower word aligned address */
/*
* handle unaligned start bytes
*/
if ((l = addr - wp) != 0)
{
data = 0;
for (i=0, cp=wp; i<l; ++i, ++cp) {
data = (data >> 8) | (*(uchar *)cp << 8);
}
for (; i<2 && cnt>0; ++i) {
data = (data >> 8) | (*src++ << 8);
--cnt;
++cp;
}
for (; cnt==0 && i<2; ++i, ++cp) {
data = (data >> 8) | (*(uchar *)cp << 8);
}
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
wp += 2;
}
/*
* handle word aligned part
*/
while (cnt >= 2) {
data = *((vu_short*)src);
if ((rc = write_word(info, wp, data)) != 0) {
return (rc);
}
src += 2;
wp += 2;
cnt -= 2;
}
if (cnt == 0) {
return ERR_OK;
}
/*
* handle unaligned tail bytes
*/
data = 0;
for (i=0, cp=wp; i<2 && cnt>0; ++i, ++cp) {
data = (data >> 8) | (*src++ << 8);
--cnt;
}
for (; i<2; ++i, ++cp) {
data = (data >> 8) | (*(uchar *)cp << 8);
}
return write_word(info, wp, data);
}
static int write_word (flash_info_t *info, ulong dest, ushort data)
{
vu_short *addr = (vu_short *)dest, val;
int rc = ERR_OK;
int flag;
/* Check if Flash is (sufficiently) erased , fix by kavin*/
if ((*addr & data) != data)
return ERR_NOT_ERASED;
flag = disable_interrupts();
*addr = 0x50;
*addr = 0x40;
*addr = data;
reset_timer_masked();
while(((val = *addr) & 0x80) != 0x80)
{
if (get_timer_masked() > CONFIG_SYS_FLASH_WRITE_TOUT) {
rc = ERR_TIMOUT;
*addr = 0xB0;
goto outahere;
}
}
if(val & 0x1A) { /* check for error */
printf("\nFlash write error %02x at address %08lx\n",
(int)val, (unsigned long)dest);
if(val & (1<<3)) {
printf("Voltage range error.\n");
rc = ERR_PROG_ERROR;
goto outahere;
}
if(val & (1<<1)) {
printf("Device protect error.\n");
rc = ERR_PROTECTED;
goto outahere;
}
if(val & (1<<4)) {
printf("Programming error.\n");
rc = ERR_PROG_ERROR;
goto outahere;
}
rc = ERR_PROG_ERROR;
goto outahere;
}
outahere:
*addr = 0xFF;
if (flag)
enable_interrupts();
return rc;
}
基于OK-2440III的u-boot移植(四)
五.在Nand Flash中调试运行
(在 基于OK-2440III的u-boot移植(三) 在norflash中运行通过后修改一下内容)
注:ok2440III开发板的nandflash是三星的K9F1G08(128M)
注:K9F2G08(256M)的nandflash同样可以,不需要更改代码
1.修改nandflash的配置,在include/configs/ok2440.h中添加下面配置:
#define CONFIG_CMD_NAND
#define CONFIG_CMDLINE_EDITING
#ifdef CONFIG_CMDLINE_EDITING
#undef CONFIG_AUTO_COMPLETE
#else
#define CONFIG_AUTO_COMPLETE
#endif
/* NAND flash settings */
#if defined(CONFIG_CMD_NAND)
#define CONFIG_SYS_NAND_BASE 0x4E000000
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#define NAND_SAMSUNG_LP_OPTIONS 1 /*注意是大块nand!! */
#undef CONFIG_ENV_IS_IN_FLASH
#define CONFIG_ENV_IS_IN_NAND 1 /* 环境变量的保存位置 */
#define CONFIG_ENV_SIZE 0x20000
#define CONFIG_ENV_OFFSET 0x40000
#endif
2.增加uboot对该型号nand的支持,在目录drivers/mtd/nand/下新建C文件并命名为s3c2440_nand.c,然后修改目录drivers/mtd/nand/下的Makefile文件:在相应位置加入:
COBJS-y += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o
3.添加drivers/mtd/nand/s3c2440_nand.c文件的内容如下:
#include <common.h>
#if 0
#define DEBUGN printf
#else
#define DEBUGN(x, args ...) {}
#endif
#include <nand.h>
#include <s3c2410.h>
#include <asm/io.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000
#define NFCONF __REGi(NF_BASE + 0x0)
#define NFCONT __REGi(NF_BASE + 0x4)
#define NFCMD __REGb(NF_BASE + 0x8)
#define NFADDR __REGb(NF_BASE + 0xc)
#define NFDATA __REGb(NF_BASE + 0x10)
#define NFMECCD0 __REGi(NF_BASE + 0x14)
#define NFMECCD1 __REGi(NF_BASE + 0x18)
#define NFSECCD __REGi(NF_BASE + 0x1C)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT0 __REGi(NF_BASE + 0x24)
#define NFSTAT1 __REGi(NF_BASE + 0x28)
#define NFMECC0 __REGi(NF_BASE + 0x2C)
#define NFMECC1 __REGi(NF_BASE + 0x30)
#define NFSECC __REGi(NF_BASE + 0x34)
#define NFSBLK __REGi(NF_BASE + 0x38)
#define NFEBLK __REGi(NF_BASE + 0x3c)
#define S3C2440_NFCONT_nCE (1<<1)
#define S3C2440_ADDR_NALE 0x0c
#define S3C2440_ADDR_NCLE 0x08
ulong IO_ADDR_W = NF_BASE;
static void s3c2440_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
DEBUGN("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
if (ctrl & NAND_CTRL_CHANGE) {
IO_ADDR_W = NF_BASE;
if (!(ctrl & NAND_CLE)) //要写的是地址
IO_ADDR_W |= S3C2440_ADDR_NALE;
if (!(ctrl & NAND_ALE)) //要写的是命令
IO_ADDR_W |= S3C2440_ADDR_NCLE;
if (ctrl & NAND_NCE)
NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash
else
NFCONT |= S3C2440_NFCONT_nCE; //禁止nand flash
}
if (cmd != NAND_CMD_NONE)
writeb(cmd,(void *)IO_ADDR_W);
}
static int s3c2440_dev_ready(struct mtd_info *mtd)
{
DEBUGN("dev_ready\n");
return (NFSTAT & 0x01);
}
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
DEBUGN("board_nand_init()\n");
clk_power->CLKCON |= (1 << 4);
twrph0 = 4; twrph1 = 2; tacls = 0;
cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);
NFCONF = cfg;
cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);
NFCONT = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2440_hwcontrol;
nand->dev_ready = s3c2440_dev_ready;
return 0;
}
4.修改cpu/arm920t/u-boot.lds文件,使lowlevel_init.o在前4K范围(因为uboot在nandflash中只能运行前4KB的内容,所以要保证底层初始化在前4KB之内):
.text :
{
cpu/arm920t/start.o (.text)
board/samsung/ok2440v3/lowlevel_init.o (.text)
*(.text)
}
5.修改cpu/arm920t/start.S中uboot代码的搬移部分(因为uboot在nandflash中只能运行前4KB的内容,所以要把uboot搬移到内存中去才能完整的运行):
(1).删除或注释掉该文件中原来的relocate 部分,改成下面:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
#define NFCONF 0x4E000000
relocate_nand: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r5, =NFCONF
//set timing value
ldr r0, =(7<<12)|(7<<8)|(7<<4)
str r0, [r5]
//enable control
ldr r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)
str r0, [r5, #4]
bl ReadNandID
mov r6, #0
ldr r0, =0xecF1
cmp r5, r0
beq 1f
ldr r0, =0xec76 //似乎多余
cmp r5, r0
beq 1f
mov r6, #1
1:
bl ReadNandStatus
mov r8, #0
ldr r9, =_start
mov r10, #128 /*u-boot 256k,128页 --这里原来是32!! */
2:
ands r0, r8, #0x3f /*如果是第一页,则检测坏块 */
bne 3f
mov r0, r8
bl CheckBadBlk
cmp r0, #0
addne r8, r8, #64 /*每块的页数 */
addne r10,r10,#64 /* +081010 feiling */
bne 4f
3:
mov r0, r8
mov r1, r9
bl ReadNandPage
add r9, r9, #2048 /*每页的字节数*/
add r8, r8, #1 /* 页数+1 */
4:
cmp r8, r10 /*要拷贝的页数 081010 pht:#32->r10 */
bcc 2b
ldr r5, =NFCONF /*DsNandFlash */
ldr r0, [r5, #4]
bic r0, r0, #1
str r0, [r5, #4]
#endif
(2).在(cpu/arm920t/start.S)文件最后添加下面子函数:
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
ReadNandID:
ldr r7,=NFCONF
ldr r0,[r7,#4]
bic r0,r0,#2
str r0,[r7,#4]
mov r0,#0x90
strb r0,[r7,#8]
mov r4,#0
strb r4,[r7,#0xc]
1:
ldr r0,[r7,#0x20]
tst r0,#1
beq 1b
ldrb r0,[r7,#0x10]
mov r0,r0,lsl #8
ldrb r1,[r7,#0x10]
orr r5,r1,r0
ldr r0,[r7,#4]
orr r0,r0,#2
str r0,[r7,#4]
mov pc,lr
ReadNandStatus:
ldr r7,=NFCONF
ldr r0,[r7,#4]
bic r0,r0,#2
str r0,[r7,#4]
mov r0,#0x70
strb r0,[r7,#8]
ldrb r1,[r7,#0x10]
ldr r0,[r7,#4]
orr r0,r0,#2
str r0,[r7,#4]
mov pc,lr
WaitNandBusy:
mov r0,#0x70
ldr r1,=NFCONF
strb r0,[r1,#8]
1:
ldrb r0,[r1,#0x10]
tst r0,#0x40
beq 1b
mov r0,#0
strb r0,[r1,#8]
mov pc,lr
CheckBadBlk:
mov r7, lr
ldr r5, =NFCONF
bic r0,r0,#0x3f
ldr r1,[r5,#4]
bic r1,r1,#2
str r1,[r5,#4]
mov r1,#0x00
strb r1,[r5,#8]
mov r1, #0
strb r1,[r5,#0xc]
mov r1, #8
strb r1,[r5,#0xc]
strb r0,[r5,#0xc]
mov r1,r0,lsr #8
strb r1,[r5,#0xc]
/****************nand为256M时,需要加以下代码***************/
cmp r6,#0 ;if(NandAddr)
movne r1,r0,lsr #16 ;WrNFAddr(addr>>16)
strb
/****************nand为256M时,需要加以上代码***************/
mov r1,#0x30
strb r1,[r5,#8]
mov r0, #100
1:
subs r0, r0, #1
bne 1b
2:
ldr r0, [r5, #0x20]
tst r0, #1
beq 2b
ldrb r0, [r5,#0x10]
sub r0, r0, #0xff
ldr r1,[r5,#4]
orr r1,r1,#2
str r1,[r5,#4]
mov pc, r7
ReadNandPage:
mov r7,lr
mov r4,r1
ldr r5,=NFCONF
ldr r1,[r5,#4]
bic r1,r1,#2
str r1,[r5,#4]
mov r1,#0
strb r1,[r5,#8]
strb r1,[r5,#0xc]
strb r1,[r5,#0xc]
strb r0,[r5,#0xc]
mov r1,r0,lsr #8
strb r1,[r5,#0xc]
/****************nand为256M时,需要加以下代码***************/
cmp r6,#0 ;if(NandAddr)
movne r1,r0,lsr #16 ;WrNFAddr(addr>>16)
strb
/****************nand为256M时,需要加以上代码***************/
mov r1,#0x30
strb r1,[r5,#8]
ldr r0,[r5,#4]
orr r0,r0,#0x10
str r0,[r5,#4]
bl WaitNandBusy
mov r0,#0
1:
ldrb r1,[r5,#0x10]
strb r1,[r4,r0]
add r0,r0,#1
bic r0,r0,#0x10000
cmp r0,#0x800
bcc 1b
ldr r0,[r5,#4]
orr r0,r0,#2
str r0,[r5,#4]
mov pc,r7
#endif