此文章参考天祥电子uboot移植文档和网上各位大侠优秀移植文章,在此感谢他们。
一、 环境
硬件信息 | 软件环境 |
开发板:TX2440A | 操作系统:ubuntu 12.04 |
CPU: S3C2440 | Uboot版本:2010.06 |
Nand flash:K9F2G08U0B (256M+8M)x8bit | 交叉编译器:arm-linux-gcc 4.4.1 |
Nor flash: EN29LV160AB (2M) x8bit | USB下载工具:DNW.exe |
SDRAM: H57V2562GTR-75C x 2 (32M) x 2 | TFTP下载工具:TFTPD32.exe |
网卡: DM9000E |
二、 移植前准备
2.1获取uboot-2010.06源码
通过http://www.denx.de/wiki/U-Boot/SourceCode 获取源码,解压源码 tar zxvf u-boot-2010.06.tar.gz。
2.2交叉编译器安装
1)解压交叉工具 arm920t-eabi-4.1.2.tar.gz,生成opt/toolchains/arm920t-eab文件夹
#tar -jxvf arm920t-eabi-4.1.2.tar.gz
2)在根目录下/usr/local/下面创建目录 arm/(注意,最好是放到这个目录,不然在以后的编译过程中可能出现一些错误)。
3)将opt/toolchains/文件夹下将arm920t-eabi 移动到 /usr/local/ arm/下面。
# cd opt/toolchains/
#cp -rf /usr/local/arm
现在交叉编译程序集都在/usr/local/arm/arm920t-eabi/bin下面了
4) 设置环境变量,把交叉编译器的路径加入到PATH。(有三种方法,强烈推荐使用方法一)
方法一:修改/etc/bash.bashrc文件已经验证是可行的。
#gedit~/.bashrc
在最后加上:export PATH=/usr/local/arm/arm920t-eabi/bin:$PATH
(如果不能编辑,先修改相关文件的权限使用chmod命令。)
方法二:修改/etc/profile文件:验证后:不可行
# vim /etc/profile
增加路径设置,在末尾添加如下,保存/etc/profile文件:
export PATH=$PATH:/usr/local/arm/arm920t-eabi/bin
5)立即使新的环境变量生效,不用重启电脑:
对应方法一:#source /root/.bashrc 已经验证是可行的。
对应方法二:# source /etc/profile
6)检查是否将路径加入到PATH:
# echo $PATH
显示的内容中有/usr/local/arm/bin,说明已经将交叉编译器的路径加入PATH。至此,交叉编译环境安装完成。
7)测试是否安装成功
# arm-linux-gcc -v 上面的命令会显示arm-linux-gcc信息和版本
Using built-in specs.
Target: arm-angstrom-linux-gnueabi
……………………………………………………………………………………………………………………………………….
Thread model: posix
gcc version 4.1.2
2.3建立自己开发板项目
首先在源码寻找同开发板匹配的配置,从该源码中arch、board文件夹可知:只有smdk2410比较接近开发板tx2440。
1、具体修改那些地方呢??通过查找源码中与“smdk2410”匹配的文件和文件夹,来确定修改地方。
修改源码: 1、uboot-2010.06/board/Samsung/smdk2410文件夹
2、uboot-2010.06/board/Samsung/smdk2410/smdk2410.c
3、uboot-2010.06/include/configs/smdk2410.h
将上述中smdk2410全部替换为tx2440,其中对应Makefile也需要修改。
具体操作:
1、cp -rf board/Samsung/smdk2410 board/Samsung/tx2440
2、cp -rf board/Samsung/smdk2410/smdk2410.c board/Samsung/smdk2410/tx2440.c
3、cp–rf include/configs/smdk2410.h include/configs/tx2440.h
4、修改board/Samsung/tx2440中Makefile 第28行:
COBJS := TX2440.oflash.o<—将smdk2410.o改名为tx2440.o
2、除了上述修改,还需要增加开发板配置文件。即根目录下Makefile中增加 tx2440_config配置文件和指定交叉编译器。
操作:1、指定交叉编译器 CROSS_COMPILE ?=arm-linux-
2、增加配置文件
tx2440_config: unconfig
@$(MKCONFIG)$(@:_config=) arm arm920t TX2440 samsung s3c24x0
说明:
arm:CPU的架构(ARCH)
arm920t:CPU的类型
tx2440 :对应在board目录下建立新的开发板项目的目录
samsung:新开发板项目的上级目录,如直接在board下建立新的开发板项目,则这里应为NULL
s3c24x0:CPU型号
注意:编译选项格式的第二行要用Tab键开始,否则编译会出错。
3、测试编译新建的TX2440开发板项目:#maketx2440_config
如果出现Configuring for TX2440 board...则表示设置正确
#make -j4
编译后在根目录下会出现u-boot.bin文件,则u-boot移植的第一步就算完成了。其中j4可以理解成:启用4个cpu去编译。提高编译速度。
三、移植
3.1设置时钟、中断配置、存储控制器初始化
#if defined(CONFIG_S3C2400)
#define pWTCON 0x15300000
#define INTMSK 0x14400008 /* Interupt-Controller base addresses */
#define CLKDIVN 0x14800014 /* clock divisor register */
/* 1、增加s3c2440寄存器配置 */
#else if defined(CONFIG_S3C2440)
#define pWTCON 0x53000000 /*watch dog */
#define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
#define INTSUBMSK 0x4A00001C
/* clock register */
#define MPLLCON 0x4C000004
#define UPLLCON 0x4C000008
#define CLKDIVN 0x4C000014
#define CAMDIVN 0x4C000018
#define MDIV_400M (0x5c<<12)
#define PDIV_400M (0x01<<4)
#define SDIV_400M 0x01
/* 通过GPF0-3的IO控制led1-4,来确认程序执行情况*/
#define GPFCON 0x56000050
#define GPFDAT 0x56000054
#define GPFUP 0x56000058
#endif
/*disable watch dog*/
ldr r0, =pWTCON
mov r1, #0x0
str r1, [r0]
/* mask all IRQs by setting all bits in the INTMR - default*/
mov r1, #0xffffffff
ldr r0, =INTMSK
str r1, [r0]
#if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
#endif
/*2、设置S3C2440的中断屏蔽寄存器*/
#if defined(CONFIG_S3C2440)
ldr r1, =0x7fff /*s3c2440的INTSUBMSK有效位bit[14:0]*/
ldr r0, =INTSUBMSK
str r1, [r0]
#endif
#if defined(CONFIG_S3C2440)
/* 3、set clock,
FLCK=400MHz,FCLK:HCLK:PCLK = 1:4:8
设置分频系数相关寄存器CLKDIVN和CAMDIVN,
其中CAMDIVN使用默认值即可。
*/
ldr r0, =CLKDIVN
mov r1, #5
str r1, [r0]
/*当CLKDIVN[2:1]设置值非0时,CPU总线模式为快总线模式,即CPU工作频率是HCLK。
可以通过下面三句程序使CPU工作FCLK的异步总线模式*/
/*MMU_SetAsync BusMode*/
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
ldr r1, =MPLLCON
mov r2, #MDIV_400M
add r2,r2,#PDIV_400M
add r2,r2,#SDIV_400M
str r2, [r1]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN
mov r1, #3
str r1, [r0]
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #0xc0000000
mcr p15, 0, r1, c1, c0, 0
#endif
#define FCLK_SPEED 1 /*设置FLCK速度模式*/
#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */
#define M_MDIV 0xC3
#define M_PDIV 0x4
#define M_SDIV 0x1
#elif FCLK_SPEED==1 /* Fout = 400MHz */
#define M_MDIV 0x5c
#define M_PDIV 0x01
#define M_SDIV 0x01
#endif
具体时钟设置由clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);
2)修改board_init (void)函数架构编码
gd->bd->bi_arch_number = MACH_TYPE_S3C2440;
else if (pllreg == UPLL) {return (CONFIG_SYS_CLK_FREQ * m) / (p << s);}
return (readl(&clk_power->CLKDIVN) & 4) ? get_FCLK() / 4 : get_FCLK(); //计算HCLK=FCLK/4=100MHz
#endif
3.2 启动方式识别(Nor flash和nand flash)
bBootFrmNORFlash:
.word 0
/*4、判断uboot映像位置:是否复制到SDRAM */
/* 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
/*LED1 ON */
ldr r0, =GPFDAT
mov r1, #0x00FE
str r1, [r0]
/*5、设置堆栈,为下面的nand flash的C操作函数提供环境*/
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
/* 6、判断启动方式 */
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /* address of Internal SRAM 0x4000003C*/
mov r0, #0 /* r0 = 0 */
str r0, [r1]
mov r1, #0x3c /* address of 0x0000003C*/
ldr r0, [r1]
cmp r0, #0 /*判断0x0000003C所指向的4个字节是否被清0*/
bne norflash /*没有被清0,就是在Nor Flash中启动,则跳到Nor Flash的重定向代码处relocate*/
/*LED 2 ON*/
ldr r0, =GPFDAT
mov r1, #0x00FD
str r1, [r0]
/* recovery */
ldr r0, =(0xdeadbeef) /*被清0,就是在Nand Flash中启动*/
ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) /*恢复0x4000003C指向的4字节的数据0xdeadbeef*/
str r0, [r1]
/*7、nand flash 初始化*/
bl nandflash_init
/*LED4 ON */
ldr r0, =GPFDAT
mov r1, #0x00F7
str r1, [r0]
/*8、nand flash 代码复制SDRAM,
其中r0-r3提供nand_copy函数的3个参数*/
#define LENGTH_UBOOT 0x100000
ldr r0, =TEXT_BASE
mov r1, #0x0
mov r2, #LENGTH_UBOOT
bl nand_copy
tst r0, #0x0 /*nand_copy返回值传递给r0,若返回0,表示uboot映像成功复制*/
beq ok_nand_read
bad_nand_read:
loop2:
/*LED1 2 3 ON*/
ldr r0, =GPFDAT
mov r1, #0x00F8
str r1, [r0]
b loop2
/*检测Boot Internal SRAM即和SDRAM中的前4K数据是否相等,以保证数据无错。*/
/* 因为nand flash 启动时,自动将steping的4K内容映射到Boot Internal SRAM中。*/
/* 而之前将uboot.bin搬运SDRAM。前4K内容比较重要,主要实现硬件初始化、代码搬运
。为第二阶段做准备。*/
/* 所以前4K内容需要校验 是否正确。如果不正确,执行notmatch。*/
ok_nand_read:
/*LED1 2 ON*/
ldr r0, =GPFDAT
mov r1, #0x00FC
str r1, [r0]
mov r0, #0
ldr r1, =TEXT_BASE
mov r2, #0x1000 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch: /* Boot Internal SRAM即和SDRAM中的前4K数据,不相等*/
loop3:
/*LED3 4 ON*/
ldr r0, =GPFDAT
mov r1, #0x00F3
str r1, [r0]
b loop3 @ infinite loop
/*9、Nor flash启动*/
norflash:
/*LED3 ON*/
ldr r0, =GPFDAT
mov r1, #0x00FB
str r1, [r0]
/*检测norflash中0x0000003C地址中:是否是0xdeadbeef魔数*/
mov r1, #0x3c /* address of 0x0000003C*/
ldr r0, [r1]
ldr r1, =(0xdeadbeef)
cmp r0, r1
bne loop3 /* 如果不是魔数值,表示异常,进入死循环 */
/* uboot映像由norflash复制到SDRAM中 */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
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
SetBootFlag:
ldr r0, =bBootFrmNORFlash
mov r1, #1 /*从Nor启动,将标志设置为1*/
str r1, [r0]
#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
#endif
#define CONFIG_AMD_LV160 1 /* uncomment this if you have a LV160 flash */
#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */
#ifdef CONFIG_AMD_LV800
#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */
#define CONFIG_SYS_MAX_FLASH_SECT (19) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV400
#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */
#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */
#endif
#ifdef CONFIG_AMD_LV160
#define PHYS_FLASH_SIZE 0x00200000 /* 2Mbyte */
#define CONFIG_SYS_MAX_FLASH_SECT (35) /* max number of sectors on one chip */
#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x100000 ) /* addr of environment */
#endif
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV800B & FLASH_TYPEMASK);
#elif defined(CONFIG_AMD_LV160)
(AMD_MANUFACT & FLASH_VENDMASK) |
(AMD_ID_LV160B & FLASH_TYPEMASK);
printf ("1x Amd29LV800BB (8Mbit)\n");
break;
case (AMD_ID_LV160B & FLASH_TYPEMASK):
printf ("1x Amd29LV160B (2M)\n");
break;
3.4支持Nand flash
uboot支持nand flash需要修改 arch架构、board板级、driver驱动级、配置文件tx2440.h、链接脚本uboot.lds五个方面。
1、Arch架构:
1)start.S(路径:arch/arm/arm920t/ )
增加支持nand flash启动和识别代码。其中:启动代码在board板级提供。
2)增加 s3c2440对应nand flash控制器的寄存器,
(路径:arch/arm/include/s3c24x0/s3c24x0.h,该头文件用来定义是s3c24x0系列的SOC上所有寄存器资源)。
为什么不能使用 2410的nand flash定义??因为2440的nand flash的控制寄存器比2410多。
struct s3c2440_nand {
u32 NFCONF;
u32 NFCONT;
u32 NFCMD;
u32 NFADDR;
u32 NFDATA;
u32 NFMECCD0;
u32 NFMECCD1;
u32 NFSECCD;
u32 NFSTAT;
u32 NFESTAT0;
u32 NFESTAT1;
u32 NFMECC0;
u32 NFMECC1;
u32 NFSECC;
u32 NFSBLK;
u32 NFEBLK;
};
3)增加上面寄存器 地址定义和地址接口函数
(路径:arch/arm/include/s3c24x0/s3c2410.h,该头文件用来定义寄存器地址和地址接口函数)
#define S3C2440_NAND_BASE 0x4E000000
static inline struct s3c2410_nand *s3c2440_get_base_nand(void)
{ return (struct s3c2410_nand *)S3C2440_NAND_BASE;
}
2、board板级:
增加nand_read.c文件作用:供start.S中nand flash代码搬运。并修改对应Makefile。(路径:board/Samsung/tx2440/)
nand_read.c源码
#include <common.h>
#include <linux/mtd/nand.h>
#define __REGb(x) (*(volatile unsigned char *)(x))
#define __REGw(x) (*(volatile unsigned short *)(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 NFDATA16 __REGw(NF_BASE + 0x10)
#define NFSTAT __REGb(NF_BASE + 0x20)
#define NFSTAT_BUSY 1
#define nand_select() (NFCONT &= ~(1 << 1))
#define nand_deselect() (NFCONT |= (1 << 1))
#define nand_clear_RnB() (NFSTAT |= (1 << 2))
#define TACLS 0x07
#define TWRPH0 0x07
#define TWRPH1 0x07
void nandflash_init(void)
{
char i;
// for S3C2440
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0);
NFCONT = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0);
for(i=0;i<50;i++);
}
static inline void nand_wait(void)
{
int i;
while (!(NFSTAT & NFSTAT_BUSY))
for (i=0; i<10; i++);
}
struct boot_nand_t {
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};
static int is_bad_block(struct boot_nand_t * nand, unsigned long i)
{
unsigned char data;
unsigned long page_num;
nand_clear_RnB();
if (nand->page_size == 512) {
NFCMD = NAND_CMD_READOOB; /* 0x50 */
NFADDR = nand->bad_block_offset & 0xf;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
} else if (nand->page_size == 2048) {
page_num = i >> 11; /* addr / 2048 */
NFCMD = NAND_CMD_READ0;
NFADDR = nand->bad_block_offset & 0xff;
NFADDR = (nand->bad_block_offset >> 8) & 0xff;
NFADDR = page_num & 0xff;
NFADDR = (page_num >> 8) & 0xff;
NFADDR = (page_num >> 16) & 0xff;
NFCMD = NAND_CMD_READSTART;
} else {
return -1;
}
nand_wait();
data = (NFDATA & 0xff);
if (data != 0xff)
return 1;
return 0;
}
/*struct boot_nand_t {
int page_size;
int block_size;
int bad_block_offset;
// unsigned long size;
};
/*************************************************************************
** 参数: 1、*nand 结构体;
2、buf U-Boot在RAM的开始地址;
3、addr U-Boot在NAND Flash中的开始地址
** 返回值:成功页读取,返回页容量;失败返回-1。
*/
static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr)
{
unsigned short *ptr16 = (unsigned short *)buf;
unsigned int i, page_num;
nand_clear_RnB();
/*#define NAND_CMD_READ0 0 定义在u-boot-2010.06\include\linux\mtd\nand.h中 */
NFCMD = NAND_CMD_READ0; //读命令
//Samsung K9F2G08U0B的page_size=2048
if (nand->page_size == 512) {
/* Write Address */
NFADDR = addr & 0xff;
NFADDR = (addr >> 9) & 0xff;
NFADDR = (addr >> 17) & 0xff;
NFADDR = (addr >> 25) & 0xff;
} else if (nand->page_size == 2048) {
/*NandFlash是以页(Page)为最小单位进行读写的,所以读取时,只需提供页地址和块数即可(不需要考虑页容量内地址)。
nand flash 物理地址=块大小×块号+页大小×页号+页内地址,在该读程序中页内地址不考虑即page_num = addr >> 11
K9F2G08U0B的操作用5个周期来实现,具体参照K9F2G08U0B手册
*/
page_num = addr >> 11; /* addr / 2048 */
/* Write Address */
NFADDR = 0; //A[7:0]
NFADDR = 0; //A[11:8]
NFADDR = page_num & 0xff; //A[19:12]其中A[17:12]表示页数,A[28:18]表示block块数即2^11=2048块
NFADDR = (page_num >> 8) & 0xff; //A[27:20]
NFADDR = (page_num >> 16) & 0xff; //A28
NFCMD = NAND_CMD_READSTART; /*#define NAND_CMD_READSTART 0x30*/
} else {
return -1;
}
nand_wait();
/*此处不明白为什么(nand->page_size>>1)而不是nand->page_size??
因为每次读取到SDRAM数据是16位(相对于K9F2G08U0B由2440的nand flash控制器控制读取两次8bit数据,组成一个16位数据),
所以读取次数减少一半(原来读取2048次,现在1024次即可).
通过裸机的nand程序验证:read nandflash数据时,支持以16位形式读取即data=NF_RDDATA16()。
最多支持32位读取。,一般采用8位读取。
*/
for (i = 0; i < (nand->page_size>>1); i++) {
/*#define __REGw(x) (*(volatile unsigned short *)(x))
#define NFDATA16 __REGw(NF_BASE + 0x10) 即NFDATA16对应数据寄存器NFDATA 8位宽nand flash以B半字(16bit)形式访问
(具体实现通过2440的nand flash实现K9F2G08U0B的8位宽转换16位宽。因为K9F2G08U0B的默认操作是8位宽)。为什么这么设置呢?
原因我们将nand flash中代码搬运到SDRAM中,而SDRAM的设置成16位宽。所以此处需要将nand flash修改与之匹配。
*/
*ptr16 = NFDATA16; //
ptr16++;
}
return nand->page_size;
}
static unsigned short nand_read_id()
{
unsigned short res = 0;
/*#define NAND_CMD_READID 0x90 定义在u-boot-2010.06\include\linux\mtd\nand.h中86行 */
/*读取nand flash 的ID号 ,nand flash的ID号存放在u-boot-2010.06\include\linux\mtd\nand.h中433行*/
NFCMD = NAND_CMD_READID; //读ID命令0x90
NFADDR = 0; //写0x00地址
res = NFDATA; //读取厂商ID:0xEC
res = (res << 8) | NFDATA; //读取设备ID0:xDA,并与厂商ID组成一字信息 即0xECDA
return res;
}
extern unsigned int dynpart_size[];
/* low level nand read function */
/* 参数:
1、*buf:U-Boot在RAM的开始地址即r0 ,由start.S调用处可知:r0=TEXT_BASE
2、start_addr:U-Boot在NAND Flash中的开始地址 即r1,由start.S调用处可知:r1=0x00
3、size:复制的大小 即r2。由start.S调用处可知:r2=#LENGTH_UOOT=0x100000 (size=1Mbyte)
返回值:成功返回0,失败返回-1或挂起
*/
int nand_copy(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
unsigned short nand_id;
struct boot_nand_t nand;
/* chip Enable */
/*#define nand_select() (NFCONT &= ~(1 << 1)) 发出片选信号*/
/*#define nand_clear_RnB() (NFSTAT |= (1 << 2)) 清除RnB位*/
nand_select();
nand_clear_RnB();
for (i = 0; i < 10; i++)
;
nand_id = nand_read_id(); //返回的ID:0xECDA
if (0) { /* dirty little hack to detect if nand id is misread */
unsigned short * nid = (unsigned short *)0x31fffff0;
*nid = nand_id;
}
if (nand_id == 0xec76 || /* Samsung K91208 */
nand_id == 0xad76 ) { /*Hynix HY27US08121A*/
nand.page_size = 512;
nand.block_size = 16 * 1024;
nand.bad_block_offset = 5;
// nand.size = 0x4000000;
} else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */
nand_id == 0xecda || /* Samsung K9F2G08U0B */
nand_id == 0xecd3 ) { /* Samsung K9K8G08 */
nand.page_size = 2048; //页容量2Kbyte
nand.block_size = 128 * 1024; //1 block=128KByte=128*1024Byte(这里是mian区size,不包括spare区)
nand.bad_block_offset = nand.page_size;
// nand.size = 0x8000000;
} else {
return -1; // hang
}
if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1))))
return -1; /* invalid alignment 地址或容量不对齐*/
for (i=start_addr; i < (start_addr + size);)
{
/*未定义CONFIG_S3C2410_NAND_SKIP_BAD */
#ifdef CONFIG_S3C2410_NAND_SKIP_BAD
if (i & (nand.block_size-1)== 0)
{
if (is_bad_block(&nand, i) || is_bad_block(&nand, i + nand.page_size))
{
/* Bad block */
i += nand.block_size;
size += nand.block_size;
continue;
}
}
#endif
/*nand_read_page_ll()返回值是2048的页容量。
&nand 结构体;buf-- U-Boot在RAM的开始地址;i--U-Boot在NAND Flash中的开始地址,
*/
j = nand_read_page_ll(&nand, buf, i); //读取每页中内容到初始地址TEXT_BASE = 0x33F80000的SDRAM中
i += j; //修改页地址
buf += j; //修改SDRAM中指针地址
}
/* chip Disable */
nand_deselect(); //#define nand_deselect() (NFCONT |= (1 << 1))
return 0;
}
3、驱动级
增加基于S3C2440的nand flash驱动:S3C2440_nand.c(路径:driver/mtd/nand/),并修改对应Makefile。
Makefile修改如下:
COBJS-y += s3c2440_nand.o
COBJS-$(CONFIG_NAND_S3C2410) += s3c2440_nand.o
4、配置文件
修改tx2440.h中nand flash配置文件(路径:include/configs/tx2440.h)
#define CONFIG_CMD_NAND
/* NAND flash settings */
#if defined(CONFIG_CMD_NAND) //支持nand flash command命令?
#define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_MTD_NAND_VERIFY_WRITE 1
#endif
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x100000
#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
5、修改启动链接脚本u-boot.lds
在arch/arm/cpu/arm920t/u-boot.lds,该文件决定uboot运行的入口地址、各个字段的存储位置,链接定位的作用。添加下面两行代码的主要目的是防止编译器把我们自己添加的用于nand启动函数放到4K之后,否则是无法启动的。
.text :
{
arch/arm/cpu/arm920t/start.o (.text)
board/samsung/tx2440/lowlevel_init.o (.text)
board/samsung/tx2440/nand_read.o (.text)
*(.text)
}
编译
# make distclean
#make tx2440_config
#make -j4
将编译后uboot.bin下载到nand flash运行。运行界面如下: