移植U-Boot2009-01到阳初S<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />3C2440超值版支持NAND启动,支持YAFFS文件系统
参考了《移植U-Boot-2008.10到友善之臂mini2440》
要知道需要修改那些文件就要分析顶层Makefile【bootloader是什么?分为几个阶段?每阶段分别完成什么任务?】<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
根据README,先要运行make <board_name>_config然后再运行make来生成uboot执行文件,根据makefile的语法这个<board_name>_config必然是makefile中定义的一个target,那么我们就要
①仿照其他的开发板来建立自己开发板的<board_name>_config,与我的开发板最相近的为smdk2410,所以根据smdk2410_config来写自己的gateway_config并加入到顶层makefile中;从顶层makefile中<board_name>_config目标的执行命令可以看出调用了mkconfig脚本,正常执行本脚本后应该会在./include中生成两个文件:config.mk和config.h并且会将输入的参数传递到ARCH、CPU、BOARD、VENDOR、SOC几个变量中,且在生成的config.h文件中将包含configs/$1.h文件,所以我们要
②在configs下建立自己开发板的.h头文件,可以通过拷贝相似开发板的头文件;
③修改子目录下的makefile;
④修改源文件中与2440不符的内容。
一个调试方法就是用板子上已能正常跑起来的bootloader将刚改过编译好的uboot下载到内存中运行,具体操作为:定义CONFIG_SKIP_LOWLEVEL_INIT为“1”,或者注释掉start.s中
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
这三句中间的那句跳转,然后修改当前开发板目录下的config.mk中的text_base为0x33000000,使用vivi命令load ram 0x33000000 0x17ea8 x将u-boot.bin装入内存。再用go 0x33000000命令,即可。
· 1、建立开发板目录,因为开发板跟smdk2440的硬件结构类似,而u-boot中最相近的配置为smdk2410,所以先复制smdk2410开发板目录为新的开发板目录:#cp -r /board/smdk2410 /board/hgateway。
· 2、将开发板目录中的开发板配置文件更名#mv /board/smdk2410/smdk2410.c /board/smdk2410/hgateway.c。
· 3、修改/board/hgateway下的makefile,将COBJS:=smdk2410.o flash.o改为COBJS:=hgateway.o flash.o
· 4、在/include/configs下建立新的开发板配置头文件#cp /include/configs/smdk2410.h /include/configs/hgateway.h。
· 5、修改顶层Makefile文件建立新开发板选项:在smdk2410_config:unconfig下增加:
hgateway_config:unconfig
@$(MCCONFIG)$(@:_config=)arm arm920t gateway NULL s3c24x0
注意还要改一点:__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))
改为:__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS)) 网上说UBOOT1.3.3以后Makefile发生了变化,编译器会将我们添加唉的用于nandboot的子函数放到4k以后。这个可以通过比较查看System.map文件可知。(有时间真要把这个两个编译一下比较看看)
这时执行#make hgateway_config&&make all可以顺利得到u-boot.bin文件了,但是别忘了这是对S3C2410的,并且是针对smdk2410开发板的,如果下到我们自己的开发板上,呵呵因为硬件配置不同,肯定是跑不起来的。下面就要更改源文件,编译出适合我们自己开发板的u-boot了。
· 6、根据芯片Datasheet及板子的硬件配置更改相应的源文件,根据顶层makefile可知,跟移植相关的几个文件夹及文件为:cpu/arm920t/start.S;cpu/arm920t/s3c24x0/;lib_arm/;board/hgateway/。首先是CPU初始化的汇编文件,根据顶层Makefile的可知在/cpu/arm920t下的start.S文件,其次是cpu/soc/下的相关文件,再次是改include/config/<board_name>.h,然后就是更改跟板密切相关的/board/下的开发板子目录中的文件。(我的开发板的LED状况:LED1-GPF6,LED2-GPF7低电平亮)
·Ⅰ、更改/cpu/arm920t/start.S这是bootloader的stage1负责初始化硬件环境并把uboot从flash加载到RAM中,然后跳转到C语言中去。之所以后缀名为大写是因为start.S中有很多预处理,而GNU as是不能做宏处理和文件包含处理的,要处理这些宏只有交给CPP预处理器来做,查看GCC帮助可以看出要用大写的S才能。【来源于天行者博客vivi源码分析】,注意在这个文件中包含了config.h,而config.h是由mkconfig生成的,其中只有一句话"#include <configs/$1.h>",所以注意再更改完start.S及相关的启动文件后还要更改configs/$1.h中有关板子的配置。
第一阶段流程:
· 异常向量表
· 置处理器为管理模式
· 关闭看门狗(加入对S3C2440的支持:defined(CONFIG_S3C2440))
· 关闭所有中断(S3C2440的INTSUBMSK寄存器有15位可用,加入对S3C2440的支持的代码)
· 设置LOCKTIME寄存器
· 设置摄像头时钟分频寄存器
· 设置时钟分频(S3C2440的时钟高达400M,设置分频为1:4:8)
· 设置写处理器P15给快时钟一个缓冲
· 写UPLLCON寄存器,使USB的PLL时钟生效
· 等待USB的PLL时钟生效
· 写MPLLCON寄存器,使主PLL生效,产生FCLK时钟
· CPU初始化
关闭CACHE和MMU
底层硬件初始化(这里跟开发板密切相关,需要更改,主要更改lowlevel_init.S文件)
将UBOOT自己拷贝到RAM中(这里加上从NAND启动,因为S3C2440的NAND的前4K为自启动区,所以只要在4K范围内完成前面的工作及其自身的拷贝就可以了。这里加上的代码为对NAND的初始化,以及将UBOOT从NAND搬移到RAM的功能)
跳到C语言中完成第二阶段
分析start.S可知,在uboot中为了做到通用性,将跟特定SOC或开发板有关的初始化都放到板级目录下的lowlevel_init.S中去了。所以uboot的第一阶段初始化其实涉及到两个文件start.S和板级目录下的lowlevel_init.S
·Ⅱ、更改/board/hgateway/lowlever_init.S,此文件主要完成对储存器的初始化.
· 1、因为S3C2410和S3C2440的内存控制寄存器的地址相同,所以寄存器的地址不用更改。
· 2、因为内存芯片可能不同,需要修改相应BANKCON的值。自己开发板所用的芯片为:HY57V566120FTP-H,RAS to CAS的延时最小要求20ns,若HCLK(就是提供给SDRAM的时钟)为100MHz的话,时钟周期为10ns,那么至少需要2个时钟周期,保险起见,可以多一点。如果要提升速度应该可以改小一点。这里按默认的2个时钟。
·Ⅲ、因为启动第一阶段的两个文件都引用了/config.h而/config.h中,只是包含了/include/configs/hgateway.h,在这个文件里配置了开发板的基本情况,包括晶振,网卡,网络MAC,IP,主机IP,分配内存空间,启动延时等。在其中添加上有关2440的配置,并修改。(这里面的uboot启动参数真是难设置啊)
·Ⅳ、在board/hgateway/中加入NAND读取函数(start.S中需要的nand_read_ll),文件nand_read.c
·Ⅴ、修改board/hgateway/Makefile,将nand_read.c编译进uboot:OBJS := mini2440.o nand_read.o flash.o
·Ⅵ、修改board/hgateway/hgateway.c中关于时钟的宏定义、GPIO的设置、开发板类型设置。
·Ⅶ、【在/common/cmd_nand.c中的do_nand函数中增加对nand write.yaffs命令的支持,让uboot支持烧写yaffs映像文件。在include/linux/mtd/mtd.h的 mtd_info 结构体定义中加入两个变量,在drivers/mtd/nand/nand_util.c的nand_write_skip_bad函数中加两段程序,一段是为了计算正常数据的长度,一段是为了在写入一段数据后,数据指针能正常跳到下一段数据,在/drivers/mtd/nand/nand_base.c的nand_write函数中,加入一段把正常数据与oob数据分离的代码,再加入页写时的模式设置为MTD_OOB_RAW,在页写时,不进行ECC的校验,ECC的校验在yaffs的oob数据中已自带了,不能重写。此模式下,写入正常数据后,会把oob的数据写入nand的oob区。『参考移植uboot2008.10到友善之臂mini2440』】
·Ⅷ、修改/cpu/arm920t/s3c24x0/nand.c,因为2440和2410的NAND控制寄存器不同,所以首先要修改寄存器定义的宏,
·Ⅸ、更改speed.c中的时钟计算公式
·Ⅹ、把其他文件中含有CONFIG_S3C2410的宏增加对CONFIG_S3C2440的定义(cpu/arm920t/s3c24x0/i2c.c,在相应的文件中把包含了CONFIG_SMDK2410的文件,增加CONFIG_GATEWAY2440
·Ⅺ、为了能将环境变量保存到NAND中,还要修改common/env_nand.c文件
·Ⅻ、修改\board\hgateway\u-boot.lds,在cpu/arm920t/start.o(.text)下增加一行board/hgateway/nand_read.o(.text)
·修改DM9000驱动,注释掉/drivers/net/dm9000x.c中与MII接口相关的语句
·编译、下载:#make distclean&&make hgateway_config&&make all,然后通过JFLASH,JSF或者是开发板原有的bootloader下载到NAND FLASH中,【uboot:首先把二进制文件下到ram中:loadb,然后利用nand write命令:nand write 内存地址 nand偏移地址『注意NAND也是从0地址开始的,所以在烧写bootloader的时候要从0地址开始写』 写入大小『要是页大小的整数倍』。还要注意写之前一定要先擦除。对于linux内核镜像,若是uImage可以用bootm来启动,若是zImage格式则可以用go来运行,当然也可以先处理后再用bootm来启动。把阳初的zImage烧到内存0x30008000地址处,然后用go 0x30008000命令来启动内核,结果停在了booting the kernel处。网上查到原因:“是我的mach_type参数在传给内核的时候,参数不匹配才会一直卡在那里”,在内核中mach_type在/arch/arm/tools中的mach_type文件中,在uboot中mach_type有hgateway.c中决定的我定义的为362。那么我们来查找阳初的vivi中开发板的mach_type为多少,在include/platform下有一句:#define MACH_TYPE 193.很明显两个参数不一样,所以修改内核中的参数增加MACH_TYPE_S3C2440 362的定义『/* adress of boot parameters */0x30000100』】
·vivi中传递给内核的启动参数在linux_cmd[] 数组中。
·vivi中的很多设置在smdk.c文件中,GPIO寄存器的配置在SMDK2440.h中
·注意:uboot启动内核的命令是bootm,bootm会将一些内核用的到的参数传递到R0,R1,R2中,但是bootm只能处理由uboot工具mkimage生成的镜像。如果用go来运行ram中的内核可能导致不正常。
【mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n linux-2.6.17.13 -d zImage uImage2.6.17.13
-A arm -------- 架构是arm
-O linux -------- 操作系统是linux
-T kernel -------- 类型是kernel
-C none -------- 压缩类型为无压缩
-a 30008000 ---- image的载入地址(hex)
-e 30008040 ---- 内核的入口地址(hex),因为信息头的大小是0x40
-n linux-2.6.17.13 --- image的名字
-d zImage ---- 无头信息的image文件名
uImage2.6.17.13 ---- 加了头信息之后的image文件名】【自带vivi:Linux command line: noinitrd init="/linuxrc" console="ttyS0" root="/dev/mtdblock/2" ma
c=00:01:5d:68:7a:0f,mach_type362】
1. 修改顶层Makefile,增加一行
hgateway_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t hgateway NULL s3c24x0
hgateway为我的目标板名字。注意第二行前面有一个TAB,这是Makefile的语法规定的命令前面必须有个TAB。5个参数顺序分别为:CPU架构(ARCH);CPU类型(CPU);开发板型号(BOARD);开发者/经销商(VENDER);片上系统(SOC)。
在《移植U-Boot-2008.10到友善之臂mini2440》中提到对于1.3.3版本以上的U-Boot还要修改__LIBS := $(subst $(obj),,$(LIBS)) $(subst $(obj),,$(LIBBOARD))为__LIBS := $(subst $(obj),,$(LIBBOARD)) $(subst $(obj),,$(LIBS))才能保证nand_read_ll放在前4K中,我觉得这里不改,而改链接文件,将nand_read.o放到代码段的前面也是一样的。
2. 修改/cpu/arm920t/start.S
a) 删除关于AR91RM9200的代码
#include <status_led.h>
……
bl coloured_LED_init
bl red_LED_on
……
#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif
b) 修改为对S3C2440的支持
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)改为
#if defined (CONFIG_S3C2440)
c) 删除关于2400的部分
# if defined(CONFIG_S3C2400)
# define pWTCON 0x15300000
# define INTMSK 0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */
#else
d) 增加S3C2440的时钟控制寄存器
# define CAMDIVN 0x4C000018
//CAMDIVN 2440增加了摄像头,CAMDIVN将影响到CLKDIVN
# define MPLLCON 0x4C000004 //MPLLCON register
# define UPLLCON 0x4C000008 //UPLLCON register
e) 去掉宏# if defined(CONFIG_S3C2410)并修改子中断屏蔽控制寄存器的值
ldr r1, =0x7ff
ldr r0, =INTSUBMSK
str r1, [r0]
改为
ldr r1, =0x7fff
ldr r0, =INTSUBMSK
str r1, [r0]
f) 增加PLL的初始化,对于S3C2440来说,只有当PLL初始化以后CPU才能按照设定的时钟进行工作,即使全部用初始值也必须重新写一次PLL。
//初始化时钟,晶振为12MHz,主频为405MHz
//locktime用来在正常运行时更改时钟的时候保护时钟
ldr r0,=LOCKTIME
mov r1,#0xffffff
str r1,[r0]
//清除摄像头分频寄存器值
ldr r0,=CAMDIVN
mov r1,#0
str r1,[r0]
修改时钟分频为1:4:8
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
改为
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
在其后增加对UPLL和MPLL的初始设置
//在2440的手册中写着若HDIVN不为0,则需要下面几句
mrc p15, 0, r1, c1, c0, 0 @ read ctrl register
orr r1, r1, #0xc0000000 @ Asynchronous
mcr p15, 0, r1, c1, c0, 0 @ write ctrl register
//USB时钟48MHz (56<<12)+(2<<4)+(2)
ldr r0, =UPLLCON
ldr r1, =0x00038022
str r1, [r0]
//arm920t为5级流水线,延迟几个周期,使指令生效
nop
nop
nop
nop
nop
nop
nop
nop
//写MPLL使pll生效,405MHz,(127<<12)+(2<<4)+(1)
ldr r0, =MPLLCON
ldr r1, =0x0007f021
str r1, [r0]
# endif
g) 将U-Boot中本是Flash到RAM的重定向代码,改为NAND到RAM的重定向代码
删除
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* 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 r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
#endif
新增NAND初始化及重定向代码
//这段代码即VIVI中的copy_myself,但要注意2440和2410的NAND寄存器不同
@ reset NAND
mov r1, #NAND_CTL_BASE //0x4E000000
ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )
str r2, [r1, #oNFCONF] //根据手册设置NAND
ldr r2, [r1, #oNFCONF]
ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control
str r2, [r1, #oNFCONT] //允许片选,允许NAND Flash控制寄存器
ldr r2, [r1, #oNFCONT]
ldr r2, =(0x6) @ RnB Clear
str r2, [r1, #oNFSTAT] //清除忙标志,Rnb_TransDetect位写“1”即可清楚忙标志
ldr r2, [r1, #oNFSTAT]
mov r2, #0xff @ RESET command //发送复位命令
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
1: add r3, r3, #0x1
cmp r3, #0xa
blt 1b
2: ldr r2, [r1, #oNFSTAT] @ wait ready
//等待前一次操作完成,通过判断Rnb_TransDetect位实现
tst r2, #0x4
beq 2b
ldr r2, [r1, #oNFCONT]
orr r2, r2, #0x2 @ Flash Memory Chip Disable
str r2, [r1, #oNFCONT] // 关闭片选,到这里只是完成了NAND初始化。
@ get read to call C functions (for nand_read()) //为C准备堆栈
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp="0"
@ copy vivi to RAM
//r0,r1,r2为传递给C的参数
ldr r0,=TEXT_BASE //数据存放位置,即要拷贝到哪里
mov r1, #0x0 //拷贝的起始地址
mov r2, #0x30000 //拷贝长度
bl nand_read_ll //跳到C语言中
tst r0, #0x0 //nand_read_ll返回0则读取成功
beq ok_nand_read
bad_nand_read:
1: b 1b @ infinite loop
//为什么读取错误时设一个无限循?这样不是启动不来了么?为什么不重新读取
ok_nand_read:
@ verify
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch //比较前4K的内容是否拷贝正确
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
1: b 1b
#endif // CONFIG_S3C2440_NAND_BOOT
3. 在/board子目录中建立自己的目标板hgateway目录
a) 复制/board/smdk2410为/board/hgateway
b) 更改smdk2410.c为gateway.c
c) 增加NAND Flash读取函数,复制VIVI中的nand_read.c到/board/hgateway中
nand_read.c
#include <config.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGi(x) (*(volatile unsigned int *)(x))
#define NF_BASE 0x4e000000 //定义NAND 控制寄存器
#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 NFSTAT __REGb(NF_BASE + 0x20)
#define NAND_CHIP_ENABLE (NFCONT &= ~(1<<1))
//定义允许片选的宏
#define NAND_CHIP_DISABLE (NFCONT |= (1<<1))
//定义禁止片选的宏
#define NAND_CLEAR_RB (NFSTAT |= (1<<2))
//定义清除忙标志的宏
#define NAND_DETECT_RB { while(! (NFSTAT&(1<<2)) );}
//定义检测忙标志的宏
#define BUSY 4
inline void wait_idle(void) { //等待NAND操作完成
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
#define NAND_SECTOR_SIZE 512 / /页大小
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* low level nand read function */
//底层NAND读取函数
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
//检测是否达到NAND页边缘,若超过边界就返回-1
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) {
return -1; /* invalid alignment */
}
NAND_CHIP_ENABLE; //开片选
for(i=start_addr; i < (start_addr + size);) {
/* READ0 */
NAND_CLEAR_RB; //清除忙标志
NFCMD = 0; //发送读取前半页命令
/* Write Address */ //写入读取地址
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
NAND_DETECT_RB; //检测忙标志,等待操作完成
//读取数据
for(j=0; j < NAND_SECTOR_SIZE; j++, i++) {
*buf = (NFDATA & 0xff);
buf++;
}
}
NAND_CHIP_DISABLE; //关片选,读取函数结束
return 0;
}
d) 修改lowlevel_init.S
BANK3接DM9000A,BANK6接RAM,注意BANK6和BANK7要设置成相同的值
修改SDRAM的刷新时间
#define REFCNT 1259 /* period="7".9us, HCLK="100Mhz", (2048+1-7.9*100) */
7.9us的周期是因为手册上写着68ms/8192clk
e) 修改hgateway.c
根据手册修改时钟
#define FCLK_SPEED 1
//将时钟改为2440的405MHz
#if FCLK_SPEED==0 /* Fout = 532MHz, Fin = 12MHz for Audio */
#define M_MDIV 0x7d
#define M_PDIV 0x1
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 405MHz */
#define M_MDIV 0x7f
#define M_PDIV 0x2
#define M_SDIV 0x1
#endif
#define USB_CLOCK 1
#if USB_CLOCK==0
#define U_M_MDIV 0x38 //96MHz
#define U_M_PDIV 0x2
#define U_M_SDIV 0x1
#elif USB_CLOCK==1 //48MHz
#define U_M_MDIV 0x38
#define U_M_PDIV 0x2
#define U_M_SDIV 0x2
#endif
在board_init()函数中可以加入一些点灯操作。以便调试方便。
f) 修改此目录下的Makefile
COBJS := smdk2410.o flash.o改为:COBJS := hgateway.o nand_read.o flash.o
g) 修改链接脚本u-boot.lds
.text :
{
cpu/arm920t/start.o (.text)
*(.text)
}
改为
.text :
{
cpu/arm920t/start.o (.text)
board/hgateway/lowlevel_init.o(.text)
board/hgateway/nand_read.o(.text)
*(.text)
}
确保把lowlevel_init.S和nand_read.c放到代码的前面。
4. 修改/cpu/arm920t/s3c24x0/nand.c
加入S3C2440的NAND控制寄存器地址
#if defined(CONFIG_S3C2440) //增加对2440的NAND FLASH控制寄存器的定义
#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 __REGb(NF_BASE + 0x24)
#define NFSTAT1 __REGb(NF_BASE + 0x28)
#define NFMECC0 __REGb(NF_BASE + 0x2C)
#define NFMECC1 __REGb(NF_BASE + 0x30)
#define NFSECC __REGb(NF_BASE + 0x34)
#define NFSBLK __REGb(NF_BASE + 0x38)
#define NFEBLK __REGb(NF_BASE + 0x3C)
#define S3C2440_NFCONT_nCE (1<<1)
#define S3C2440_ADDR_NALE 0x0c
#define S3C2440_ADDR_NCLE 0x08
#endif
以下参考《移植U-Boot-2008.10到友善之臂mini2440》
u-boot.2008.10自带的S3C2410的s3c2410_hwcontrol函数有错。在此函数中,把chip->IO_ADDR_W值改写了,导致在写数据时出现错误。解决方法是使用一全局变量代替 chip->IO_ADDR_W。在 s3c2410_hwcontrol 函数上一行定义这个全局变量,然后修改 s3c2410_hwcontrol 函数,让它支持 S3C2440,修改后如下:
#define S3C2410_ADDR_NCLE 8
ulong IO_ADDR_W = NF_BASE;
static void s3c2410_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 defined(CONFIG_S3C2410)
if (ctrl & NAND_CTRL_CHANGE) {
//ulong IO_ADDR_W = NF_BASE;
IO_ADDR_W = NF_BASE;
if (!(ctrl & NAND_CLE))
IO_ADDR_W |= S3C2410_ADDR_NCLE;
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S3C2410_ADDR_NALE;
//chip->IO_ADDR_W = (void *)IO_ADDR_W;
if (ctrl & NAND_NCE)
NFCONF &= ~S3C2410_NFCONF_nFCE;
……
}
if (cmd != NAND_CMD_NONE)
//writeb(cmd, chip->IO_ADDR_W);
writeb(cmd,(void *)IO_ADDR_W);
#endif
#if defined(CONFIG_S3C2440)
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;}
//chip->IO_ADDR_W = (void *)IO_ADDR_W;
if (ctrl & NAND_NCE)
{NFCONT &= ~S3C2440_NFCONT_nCE; //使能nand flash
//DEBUGN("NFCONT is 0x%x ",NFCONT);
//DEBUGN("nand Enable ");
}
else
{NFCONT |= S3C2440_NFCONT_nCE; //禁止nand flash
//DEBUGN("nand disable ");
}
}
if (cmd != NAND_CMD_NONE)
writeb(cmd,(void *)IO_ADDR_W);
//writeb(cmd, chip->IO_ADDR_W);
#endif
}
修改board_nand_init 函数如下:
DEBUGN("board_nand_init()\n");
clk_power->CLKCON |= (1 << 4);
#if defined(CONFIG_S3C2410)
DEBUGN("CONFIG_S3C2410\n");
/* initialize hardware */
twrph0 = 3; twrph1 = 0; tacls = 0;
……
nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#else
#if defined(CONFIG_S3C2440)
DEBUGN("CONFIG_S3C2440\n");
twrph0 = 4; twrph1 = 2; tacls = 0;
cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4);
NFCONF = cfg;
//DEBUGN("cfg is %x\n",cfg);
//DEBUGN("NFCONF is %lx\n",NFCONF);
cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0);
NFCONT = cfg;
//DEBUGN("cfg is %lx\n",cfg);
//DEBUGN("NFCONT is %x\n",NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#endif
#endif
#ifdef CONFIG_S3C2410_NAND_HWECC
5. 修改/cpu/arm920t/s3c24x0/speed.c
这部分代码是配置PLL及内核总线频率的
a) 修改FCLK的计算公式:
#if defined(CONFIG_S3C2440)
if(pllreg == MPLL)
return((CONFIG_SYS_CLK_FREQ * m*2) / (p << s));
else if(pllreg == UPLL)
#endif
return((CONFIG_SYS_CLK_FREQ * m) / (p << s));
b) 修改HCLK的配置
#if defined(CONFIG_S3C2440)
if(clk_power->CLKDIVN & 0x6){
if((clk_power->CLKDIVN & 0x6)==2)
return (get_FCLK()/2);
if((clk_power->CLKDIVN & 0x6)==6)
return ((clk_power->CAMDIVN & 0x100)? get_FCLK()/6 : get_FCLK()/3);
if((clk_power->CLKDIVN & 0x6)==4)
return ((clk_power->CAMDIVN & 0x200)? get_FCLK()/8 : get_FCLK()/4);
return(get_FCLK());
}
else return(get_FCLK());
#else
return((clk_power->CLKDIVN & 0x2) ? get_FCLK()/2 : get_FCLK());
#endif
6. 修改/common/cmd_nand.c中的do_nand函数加入对yaffs写的支持。
a) 在对jffs2操作的下面加入:
else if(s!= NULL && !strcmp(s,".yaffs")){ //支持yaffs文件的写入
if(read){
printf("nand read.yaffs is not provide!");
}
else{
nand->writeoob=1;
ret = nand_write_skip_bad(nand,off,&size,(u_char *)addr);
nand->writeoob=0;
}
b) 在nand命令说明中加入对nand write yaffs的描述:
"nand write.yaffs - addr off|partition size\n"
" write 'size' bytes starting at offset 'off'\n"
" to/from yaffs image in memory address 'addr',skipping bad blocks.\n"
c) 在/include/linux/mtd/mtd.h中的mtd_info结构体定义中加入两个变量:
struct mtd_info {
u_char writeoob;
u_char skipfirstblock;
//上面两个是根据增加yaffs文件支持添加的变量
d) 在/drivers/mtd/nand/nand_util.c的nand_write_skip_bad函数中加入两段程序
//计算正常数据的长度,从yaffs映像中提取要写入的正常数据长度,即去掉oob数据长度
int rval;
size_t left_to_write = *length;
size_t len_incl_bad;
u_char *p_buffer = buffer;
if(nand->writeoob == 1){
size_t oobsize = nand->oobsize;
size_t datasize = nand->writesize;
int datapages = 0;
if(((*length)%(nand->oobsize+nand->writesize))!= 0){
printf("Attemp to write error length data!\n");
return -EINVAL;
}
datapages = *length/(datasize+oobsize);
*length = datapages*datasize;
left_to_write = *length;
nand->skipfirstblock = 1;
}
在while (left_to_write > 0)循环中添加指针移动的代码
left_to_write -= write_size;
//添加的使指针正常移动的代码
printf("%ld%%is complete.",100-(left_to_write/(*length/100)));
offset += write_size;
//p_buffer += write_size;
if(nand->writeoob == 1){
p_buffer += write_size+(write_size/nand->writesize*nand->oobsize);
}
else{
p_buffer += write_size;
}
e) 在/drivers/mtd/nand/nand_base.c的nand_write函数中,加入一段把正常数据与oob数据分离的代码,再加入页写时的模式设置为MTD_OOB_RAW,在页写时,不进行ECC的校验,ECC的校验在yaffs的oob数据中已自带了,不能重写。此模式下,写入正常数据后,会把oob的数据写入nand的oob区。修改后如下:
static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const uint8_t *buf)
{
struct nand_chip *chip = mtd->priv;
int ret;
//printf("0 len is %d ",len);
//此段数据是将要写入的数据中的正常数据移到buf中的前段,把oob数据移到后段。
int oldopsmode = 0;
if(mtd->writeoob==1)
{
size_t oobsize = mtd->oobsize; //定义oobsize的大小
size_t datasize = mtd->writesize;
int i = 0;
uint8_t oobtemp[16];
int datapages = 0;
datapages = len/(datasize); //传进来的len是没有包括oob的数据长度
for(i=0;i<(datapages);i++)
{
memcpy(oobtemp,buf+datasize*(i+1),oobsize);
memmove(buf+datasize*(i+1),buf+datasize*(i+1)+oobsize,(datapages-(i+1))*(datasize)+(datapages-1)*oobsize);
memcpy(buf+(datapages)*(datasize+oobsize)-oobsize,oobtemp,oobsize);
}
}
//printf("1 len is %d ",len);
/* Do not allow reads past end of device */
if ((to + len) > mtd->size)
return -EINVAL;
if (!len)
//return 0;
{printf("Write data length is %d ",len);return 0;}
nand_get_device(chip, mtd, FL_WRITING);
chip->ops.len = len;
chip->ops.datbuf = (uint8_t *)buf;
//chip->ops.oobbuf = NULL;
if(mtd->writeoob!=1)
{
chip->ops.oobbuf = NULL;
}
else
{
chip->ops.oobbuf = (uint8_t *)(buf+len); //将oob缓存的指针指向buf的后段,即oob数据区的起始地址。
chip->ops.ooblen = mtd->oobsize;
oldopsmode = chip->ops.mode;
chip->ops.mode = MTD_OOB_RAW; //将写入模式改为直接书写oob区,即写入数据时,不进行ECC校验的计算和写入。(yaffs映像的oob数据中,本身就带有ECC校验)
}
7. 修改DM9000驱动
修改/drivers/net/dm9000x.c中
注释掉与MII接口相关的语句
#if 0
i = 0;
while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */
udelay(1000);
i++;
if (i == 10000) {
printf("could not establish link\n");
return 0;
}
}
/* see what we've got */
lnk = phy_read(17) >> 12;
printf("operating at ");
。。。。。。
}
printf("mode\n");
#endif
8. 修改/include/configs/hgateway.h头文件
#define CONFIG_S3C2410 1 /* in a SAMSUNG S3C2410 SoC */
#define CONFIG_SMDK2410 1 /* on a SAMSUNG SMDK2410 Board */
改为
#define CONFIG_S3C2440 1
#define CONFIG_GATEWAY2440 1
网卡的配置改为
//DM9000的配置
#define CONFIG_DRIVER_DM9000 1
#define CONFIG_DM9000_USE_16BIT 1
#define CONFIG_DM9000_BASE 0x20000300
#define DM9000_IO 0x20000300 //I/O的默认基址为300
#define DM9000_DATA 0x20000304 //数据端口
添加配置
#define CONFIG_CMD_PING
#define CONFIG_CMD_NFS //支持NFS
#define CONFIG_CMDLINE_TAG 1 //允许给内核传递参数,下面三个必须配置
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
#define CONFIG_CMD_NAND 1
#define CONFIG_CMDLINE_EDITING
//NAND FLASH设置
#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 CONFIG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
//#define NAND_SECTOR_SIZE
//#define NAND_BLOCK_MASK
#define SECTORSIZE 512 //一页的大小
/////在NAND中保存uboot参数(SAVEENV功能)
#define CONFIG_CMD_ENV //支持saveenv命令
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x30000 //参数在NAND中的起始位置
//#define CONFIG_ENV_IS_IN_FLASH 1
#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */
//////NAND Flash启动设置的一些寄存器
#define CONFIG_S3C2440_NAND_BOOT 1
#define STACK_BASE 0x33F00000
#define STACK_SIZE 0x8000
#define NAND_CTL_BASE 0x4e000000
#define bINT_CTL(Nb) __REG(INT_CTL_BASE+(Nb))
#define oNFCONF 0x00
#define oNFCONT 0x04
#define oNFCMD 0x08
#define oNFADDR 0x0C
#define oNFDATA 0x10
#define oNFSTAT 0x20
#define oNFECC 0x2C
#define rNFCONF (*(volatile unsigned int *)0x4e000000)
#define rNFCONT (*(volatile unsigned int *)0x4e000004)
#define rNFCMD (*(volatile unsigned int *)0x4e000008)
#define rNFADDR (*(volatile unsigned int *)0x4e00000C)
#define rNFDATA (*(volatile unsigned int *)0x4e000010)
#define rNFSTAT (*(volatile unsigned int *)0x4e000020)
#define rNFECC (*(volatile unsigned int *)0x4e00002C)
9. 然后在其他所有包含define(CONFIG_S3C2410)的地方改为:
define(CONFIG_S3C2410)|| define(CONFIG_S3C2440)
将CONFIG_SMDK2410改为
define(CONFIG_SMDK2410)|| define(CONFIG_GATEWAY2440)
文章评论(0条评论)
登录后参与讨论