分类: 嵌入式
2011-01-10 20:31:52
Nand flash芯片:K9F1G08U0B,128M
在前面移植nor文档的基础上,我们来移植nand flash上的uboot,这样过程就简单许多了,为什么要针对两种flash做移植呢?
原因:我认为一个原因是有些板上是没有nor 芯片的,相对于nand价格贵了点吧(^_^),所以需要针对nand移植,而且现在的uboot也是不直接支持nand启动的。
详细移植步骤 NO11.主要还是需要修改start.S文件,主要在修改在代码拷贝处,从nand拷贝时,不能向操作nor那样通过总线访问硬件,必须通过相应的控制器来访问,所以拷贝uboot代码到sdram的操作需要用一个函数nand_read_II()来实现,这个函数放在board/mini2440/nand_read.c中这个文件中。
/********************************************************************************/
start.S:
删除以前的nor的重定向代码,替换为
#ifdef CONFIG_S3C2440_NAND_BOOT
@ reset NAND
mov r1, #NAND_CTL_BASE //0x4E000000
ldr r2, =( (7<<12) | (7<<8) | (7<<4) | (3<<2)) | (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
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
//等待前一次操作完成,通过判断Rnb_TransDetect位实现
tst r2, #0x4
beq nand2
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 uboot to sdRAM
//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:
loop3:
b loop3
#endif // CONFIG_S3C2440_NAND_BOOT
/********************************************************************************/
在/board/mini2440中添加nand_read.c文件,并且修改makefile
/********************************************************************************/
nand_read.c:
#include
#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 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)
{
while(!(NFSTAT & BUSY));
NFSTAT |= BUSY;
}
#define NAND_SECTOR_SIZE 2048
#define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1)
/* low level nand read function */
int
nand_read_ll(unsigned char *buf, unsigned long start_addr, int size)
{
int i, j;
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 */
/* start comment
NFADDR = i & 0xff;
NFADDR = (i >> 9) & 0xff;
NFADDR = (i >> 17) & 0xff;
NFADDR = (i >> 25) & 0xff;
*/
/*page 2k,so [10..0]=00000000000 ,this must pay attention*/
NFADDR = 0x0;
NFADDR = 0x0;
NFADDR = (i >> 11) & 0xff;
NFADDR = (i >> 19) & 0xff;
NFCMD = 0x30;
NAND_DETECT_RB;
for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
{
*buf = (NFDATA & 0xff);
buf++;
}
}
NAND_CHIP_DISABLE;
return 0;
}
/***************************************************************************/
2.第二个需要修改的文件呢?当然是include/configs/mini2440.h文件咯,大家看看怎么修改?
① 首先,不需要nor flash了,注释掉前面文章中涉及到的nor的宏,自己改吧..
② 添加CMD相关命令,以及nand flash param和nand flash setting
//nand Flash param
#define CONFIG_CMDLINE_EDITING
#ifdef CONFIG_CMDLINE_EDITING
#undef CONFIG_AUTO_COMPLETE
#else
#define CONFIG_AUTO_COMPLETE
#endif
//#define CONFIG_NAND_LEGACY
#define CONFIG_CMD_NAND
/*
* NAND flash settings
*/
#if defined(CONFIG_CMD_NAND)
#define CONFIG_S3C2440_NAND_BOOT 1
#define CFG_NAND_BASE 0x4E000000
/* NandFlash控制器在SFR区起始寄存器地址 */
#define CFG_MAX_NAND_DEVICE 1
/* Max number of NAND devices */
#define CONFIG_MTD_NAND_VERIFY_WRITE 1 //使能flash写校验
/* #undef CONFIG_MTD_NAND_VERIFY_WRITE */
#define CONFIG_SYS_NAND_BASE 0x4E000000
#define CONFIG_SYS_MAX_NAND_DEVICE 1
#define CONFIG_MAX_NAND_DEVICE 1
#define NAND_MAX_CHIPS 1
#endif /* CONFIG_CMD_NAND */
/* NAND Flash Controller */
#define NAND_CTL_BASE 0x4E000000
#define bINT_CTL(Nb) __REG(INT_CTL_BASE + (Nb))
③ 相关nand控制器的地址以及偏移
/* Offset */
#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 char *)0x4e000008)
#define rNFADDR (*(volatile unsigned char *)0x4e00000c)
#define rNFDATA (*(volatile unsigned char *)0x4e000010)
#define rNFSTAT (*(volatile unsigned int *)0x4e000020)
#define rNFECC (*(volatile unsigned int *)0x4e00002c)
④ ENV设置
#define CFG_NO_FLASH 1
#define CONFIG_ENV_IS_IN_NAND 1
#define CONFIG_ENV_OFFSET 0x40000
#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment
Sector */
3.这里我们不使用nand_legacy方式,所以还需要修改nand.c
添加:
#if defined(CONFIG_S3C2440)
#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
#endif
#define S3C2410_NFCONF_EN (1<<15)
#define S3C2410_NFCONF_512BYTE (1<<14)
#define S3C2410_NFCONF_4STEP (1<<13)
#define S3C2410_NFCONF_INITECC (1<<12)
#define S3C2410_NFCONF_nFCE (1<<11)
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
#define S3C2410_ADDR_NALE 4
#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;
else
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
}
修改nand_init函数:
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);
#if defined(CONFIG_S3C2410)
DEBUGN("CONFIG_S3C2410\n");
/* initialize hardware */
twrph0 = 3; twrph1 = 0; tacls = 0;
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
NFCONF = cfg;
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e00000c;
/* 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
#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
#ifdef CONFIG_S3C2410_NAND_HWECC
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
nand->ecc.correct = s3c2410_nand_correct_data;
nand->ecc.mode = NAND_ECC_HW3_512;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
DEBUGN("end of nand_init\n");
return 0;
}
NO2.至此,基本修改完成,大家make一下,烧写试试!
注意:该nand flash 芯片不能在win下通过sjf2440.exe进行烧写,可以到网上下载最新的H-JTAG来进行烧写,速度快,很好用!(免费的O(∩_∩)O)
输出效果图如下: