/*在第一次移植的基础上增加了S3C2440对NAND FLASH(k9f2g08u0a)中环境变量的读取和保存,写页的软件ECC扩展到了2KB*/
/*2010.11.21--2010.11.28*/
/*交叉编绎工具:cross-3.3.2.tar.bz2*/
/*默认当前目录为:u-boot-1.1.4*/
1.不用NOR FLASH所以:
vi lib_arm/board.c
236行(size = flash_init ();)和237行(display_flash_config (size);)两个函数注释掉.
2.环境变量在NAND中:
<1>vi include/configs/fl2440.h
81行(/*CFG_CMD_NAND |*/ /)去掉注释
178行(#define CFG_ENV_IS_IN_FLASH 1) -> #define CFG_ENV_IS_IN_NAND 1
<2>vi lib_arm/board.c
42行(#if (CONFIG_COMMANDS & CFG_CMD_NAND))后加:
#define NFCONF (*(volatile unsigned *)0x4E000000) #define NFCONT (*(volatile unsigned *)0x4E000004) #define NFCMD (*(volatile unsigned *)0x4E000008) #define NFSTAT (*(volatile unsigned *)0x4E000020) #define TACLS 0 #define TWRPH0 3 #define TWRPH1 0
<3>lib_arm/board.c中添加函数:
void nand_init() { unsigned long total; NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4); NFCONT = (1<<4)|(1<<1)|(1<<0); NFCONT &= ~(1<<1); NFCMD = 0xff; /*nand reset*/ while((NFSTAT&0x1) != 1); NFCONT |= 0x2; total = nand_probe(0x4E000010); printf("%dMB/n",total/1024/1024); }
文件开头加上声明:extern unsigned long nand_probe(unsigned long physadr);
<4>vi include/linux/mtd/nand.h 添加:
#define CFG_MAX_NAND_DEVICE 1 #define NAND_ChipID_UNKNOWN 0 #define SECTORSIZE 2048 /* 1页的大小 */ #define ADDR_COLUMN 2 /*列地址(Column Address)字节数*/ #define ADDR_PAGE 3 /*行地址(Row Address)字节数*/ #define ADDR_COLUMN_PAGE 5 /*行,列总字节数*/ #define ADDR_READ_ID 0 /*读NAND FLASH芯片ID标志*/ #define NAND_MAX_FLOORS 1 #define NAND_MAX_CHIPS 1 #define CFG_ENV_OFFSET 0x60000 /*环境变量在NAND FLASH中起始地址*/
<5>vi include/linux/mtd/nand.h 添加:
#define rNFCONF (*(volatile unsigned *)0x4E000000) #define rNFCONT (*(volatile unsigned *)0x4E000004) #define rNFCMD (*(volatile unsigned *)0x4E000008) #define rNFADDR (*(volatile unsigned *)0x4E00000C) #define rNFDATA (*(volatile unsigned *)0x4E000010) #define rNFSTAT (*(volatile unsigned *)0x4E000020) #define rNFDATA8 (*(volatile unsigned char *)0x4E000010) #define NAND_WAIT_READY(nand) {while((rNFSTAT&0x1) != 1);} //等待nandflash不忙 #define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;} //写命令 #define WRITE_NAND_COLUMN_ADDRESS(d, adr) {rNFADDR = d;rNFADDR = (d>>8) & 0x0f;} //写列地址 #define WRITE_NAND_PAGE_ADDRESS(d, adr) {rNFADDR = d;} //写行地址 #define WRITE_NAND_ID_ADDRESS(d, adr) {rNFADDR = d;} //写读取芯片ID时的地址 #define WRITE_NAND(d, adr) {rNFDATA8 = d;} //写数据到NAND(1字节),直接写rNFDATA(即rNFDATA=d)会写入4字节 #define READ_NAND(adr) (rNFDATA8) //读NAND中数据(1字节),直接读rNFDATA(即rNFDATA=d)会读入4字节 #define NAND_DISABLE_CE(nand) {rNFCONT |= (1<<1);} //关闭nandflash片选 #define NAND_ENABLE_CE(nand) {rNFCONT &= ~(1<<1);} //打开nandflash片选 /* the following functions are NOP's because S3C24X0 handles this in hardware 一定要加上 */ #define NAND_CTL_CLRALE(nandptr) #define NAND_CTL_SETALE(nandptr) #define NAND_CTL_CLRCLE(nandptr) #define NAND_CTL_SETCLE(nandptr)
(2)修改76行(#define NAND_CMD_READ1 1)为:
#define NAND_CMD_READ1 0x30
(3)修改78行(#define NAND_CMD_READOOB 0x50)为:
#define NAND_CMD_RANDOMREAD1 0x05 //随意读命令周期1
#define NAND_CMD_RANDOMREAD2 0xE0 //随意读命令周期2
#define NAND_CMD_RANDOMWRITE 0x85 //随意写命令
(4)216行(#define NAND_NOOB_ECCPOS5 7)后添加:
#define NAND_NOOB_ECCPOS6 17 #define NAND_NOOB_ECCPOS7 18 #define NAND_NOOB_ECCPOS8 19 #define NAND_NOOB_ECCPOS9 20 #define NAND_NOOB_ECCPOS10 21 #define NAND_NOOB_ECCPOS11 22 #define NAND_NOOB_ECCPOS12 23 #define NAND_NOOB_ECCPOS13 24 #define NAND_NOOB_ECCPOS14 25 #define NAND_NOOB_ECCPOS15 26 #define NAND_NOOB_ECCPOS16 27 #define NAND_NOOB_ECCPOS17 28 #define NAND_NOOB_ECCPOS18 29 #define NAND_NOOB_ECCPOS19 30 #define NAND_NOOB_ECCPOS20 31 #define NAND_NOOB_ECCPOS21 32 #define NAND_NOOB_ECCPOS22 33 #define NAND_NOOB_ECCPOS23 34
(5)243行(#define NAND_JFFS2_OOB_ECCPOS5 7)后添加:
#define NAND_JFFS2_OOB_ECCPOS6 17 #define NAND_JFFS2_OOB_ECCPOS7 18 #define NAND_JFFS2_OOB_ECCPOS8 19 #define NAND_JFFS2_OOB_ECCPOS9 20 #define NAND_JFFS2_OOB_ECCPOS10 21 #define NAND_JFFS2_OOB_ECCPOS11 22 #define NAND_JFFS2_OOB_ECCPOS12 23 #define NAND_JFFS2_OOB_ECCPOS13 24 #define NAND_JFFS2_OOB_ECCPOS14 25 #define NAND_JFFS2_OOB_ECCPOS15 26 #define NAND_JFFS2_OOB_ECCPOS16 27 #define NAND_JFFS2_OOB_ECCPOS17 28 #define NAND_JFFS2_OOB_ECCPOS18 29 #define NAND_JFFS2_OOB_ECCPOS19 30 #define NAND_JFFS2_OOB_ECCPOS20 31 #define NAND_JFFS2_OOB_ECCPOS21 32 #define NAND_JFFS2_OOB_ECCPOS22 33 #define NAND_JFFS2_OOB_ECCPOS23 34
<6>vi common/cmd_nand.c
(1)修改612行(WRITE_NAND_ADDRESS(ofs, nandptr);)为:
WRITE_NAND_COLUMN_ADDRESS(ofs, nandptr);
(2)修改618行(WRITE_NAND_ADDRESS(ofs, nandptr);)为:
WRITE_NAND_PAGE_ADDRESS(ofs, nandptr);
(3)622行(NAND_CTL_CLRALE(nandptr);)上面添加:
if(numbytes == ADDR_READ_ID)
WRITE_NAND_ID_ADDRESS(ofs, nandptr);
(4)修改668行(NanD_Address(nand, ADDR_COLUMN, 0);)为:
NanD_Address(nand, ADDR_READ_ID, 0);
(5)修改720-722行(nand->oobblock = 512; nand->oobsize = 16;nand->page_shift = 9;)为:
nand->oobblock = 2048; /*页的Main区大小*/
nand->oobsize = 64; /*页的Spare区大小*/
nand->page_shift = 12; /*行地址第一位A12*/
(nand->eccsize = 256; /*ECC校验每256Byte数据产生3Byte校验码*/)
(6)修改815行( NanD_Command (nand, NAND_CMD_READ1);)为:
NanD_Command(nand,NAND_CMD_READ1);
(7)注释1125行(NanD_Command (nand, NAND_CMD_READ0);)
(8)修改函数nand_read_oob为:
static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, size_t * retlen, u_char * buf) { int num; int ret = 0; ofs += nand->oobblock; /*这里传来的ofs是页的Main区起始地址,为了读Spare区数据,要加nand->oobblock(即2048)*/ unsigned long page_number = ofs >> 12; NAND_ENABLE_CE(nand); /* set pin low */ for(num=0; num<len; num++) { page_number = ofs >> 12; NanD_Command(nand, NAND_CMD_READ0); //写入5个地址周期 WRITE_NAND_PAGE_ADDRESS(0x00, 0); //列地址A0~A7 WRITE_NAND_PAGE_ADDRESS(0x00, 0); //列地址A8~A11 WRITE_NAND_PAGE_ADDRESS((page_number) & 0xff, 0); //行地址A12~A19 WRITE_NAND_PAGE_ADDRESS((page_number >> 8) & 0xff, 0);//行地址A20~A27 WRITE_NAND_PAGE_ADDRESS((page_number >> 16) & 0xff, 0);//行地址A28 NanD_Command(nand, NAND_CMD_READ1); NanD_WaitReady(nand, 1); NanD_Command(nand, NAND_CMD_RANDOMREAD1); //随意读命令周期1 //页内地址 WRITE_NAND_PAGE_ADDRESS((char)(ofs&0xff), 0); //列地址A0~A7 WRITE_NAND_PAGE_ADDRESS((char)((ofs>>8)&0x0f), 0); //列地址A8~A11 NanD_Command(nand, NAND_CMD_RANDOMREAD2); //随意读命令周期2 *buf = READ_NAND(ofs); /*printf("Read oob addr=0x%x val=0x%x ,/n",ofs,*buf);*/ buf++; ret = NanD_WaitReady(nand, 1); ofs++; } NAND_DISABLE_CE(nand); *retlen = len; return ret; }
修改函数nand_write_oob为:
static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len, size_t * retlen, const u_char * buf) { int num; int ret = 0; ofs += nand->oobblock; /*这里传来的ofs是页的Main区起始地址,为了写Spare区数据,要加nand->oobblock(即2048)*/ unsigned long page_number = ofs >> 12; NAND_ENABLE_CE(nand); /* set pin low */ for(num=0; num<len; num++) { page_number = ofs >> 12; NanD_Command(nand, NAND_CMD_SEQIN); //写入5个地址周期 WRITE_NAND_PAGE_ADDRESS(0x00, 0); //列地址A0~A7 WRITE_NAND_PAGE_ADDRESS(0x00, 0); //列地址 WRITE_NAND_PAGE_ADDRESS((page_number) & 0xff, 0); //行地址 WRITE_NAND_PAGE_ADDRESS((page_number >> 8) & 0xff, 0);//行地址 WRITE_NAND_PAGE_ADDRESS((page_number >> 16) & 0xff, 0);//行地址 NanD_Command(nand, NAND_CMD_RANDOMWRITE); //随意写命令 //页内地址 WRITE_NAND_PAGE_ADDRESS((char)(ofs&0xff), 0); //列地址 WRITE_NAND_PAGE_ADDRESS((char)((ofs>>8)&0x0f), 0); //列地址 WRITE_NAND(*buf, 0); /*printf("Write oob addr=0x%x val=0x%x ,/n",ofs,*buf);*/ buf++; NanD_Command(nand, NAND_CMD_PAGEPROG); NanD_Command(nand, NAND_CMD_STATUS); if (READ_NAND(nandptr) & 1) { puts ("Error programming oob data/n"); /* There was an error */ NAND_DISABLE_CE(nand); /* set pin high */ *retlen = 0; return -1; } ofs++; } NAND_DISABLE_CE(nand); /* set pin high */ *retlen = len; return 0; }
(9)修改415行(int page1 = page0 + nand->oobblock;)为
int page1 = page0 + 2*nand->oobblock; /*页与页差2*nand->oobblock(即2*2048=4096)*/
(10)修改40行(int ecc_pos[6];)为
int ecc_pos[24]; /*2KB数据产生24Byte ECC校验码*/
(11)修改466行(char eccbuf[6];)为
char eccbuf[24];
(12)修改951行(for (j = 0; j < 6; j++) {)为
for (j = 0; j < 24; j++) {
(13)修改1102行(for (i = 0; i < 6; i++))为:
for (i = 0; i < 24; i++)
(14)在1109行(if ((nand->oobblock == 512) && (last == nand->oobblock)) {)上面添加:
if ((nand->oobblock == 2048) && (last == nand->oobblock)) { for(i=0; i<7; i++) nand_calculate_ecc (&nand->data_buf[i*256+256], &(ecc_code[i*3+3])); for (i = 3; i < 24; i++) { nand->data_buf[(nand->oobblock + oob_config.ecc_pos[i])] = ecc_code[i]; } if (oob_config.eccvalid_pos != -1) { nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &= 0x0f; } }
(14)修改900行(u_char ecc_calc[6];)为:
u_char ecc_calc[24];
后面再添加:
int i;
(15)975行(if (oob_config.eccvalid_pos != -1 &&nand->oobblock == 512 && (nand->data_buf[nand->oobblock +
oob_config.eccvalid_pos] & 0xf0) != 0xf0) {)上面添加:
if (oob_config.eccvalid_pos != -1 && nand->oobblock == 2048 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) { for(i=0; i<7; i++) nand_calculate_ecc (&nand->data_buf[i*256+256], &ecc_calc[i*3+3]); for(i=0; i<7; i++) { switch (nand_correct_data (&nand->data_buf[i*256+256], &ecc_code[i*3+3], &ecc_calc[i*3+3])) { case -1: printf ("%s: Failed ECC read, page 0x%08x/n", __FUNCTION__, page); ecc_failed++; break; case 1: case 2: /* transfer ECC corrected data to cache */ if (nand->data_cache) memcpy (&nand->data_cache[256], &nand->data_buf[256], 256); break; } } }
(16)1619行(oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;)后添加:
oob_config.ecc_pos[6] = NAND_JFFS2_OOB_ECCPOS6; oob_config.ecc_pos[7] = NAND_JFFS2_OOB_ECCPOS7; oob_config.ecc_pos[8] = NAND_JFFS2_OOB_ECCPOS8; oob_config.ecc_pos[9] = NAND_JFFS2_OOB_ECCPOS9; oob_config.ecc_pos[10] = NAND_JFFS2_OOB_ECCPOS10; oob_config.ecc_pos[11] = NAND_JFFS2_OOB_ECCPOS11; oob_config.ecc_pos[12] = NAND_JFFS2_OOB_ECCPOS12; oob_config.ecc_pos[13] = NAND_JFFS2_OOB_ECCPOS13; oob_config.ecc_pos[14] = NAND_JFFS2_OOB_ECCPOS14; oob_config.ecc_pos[15] = NAND_JFFS2_OOB_ECCPOS15; oob_config.ecc_pos[16] = NAND_JFFS2_OOB_ECCPOS16; oob_config.ecc_pos[17] = NAND_JFFS2_OOB_ECCPOS17; oob_config.ecc_pos[18] = NAND_JFFS2_OOB_ECCPOS18; oob_config.ecc_pos[19] = NAND_JFFS2_OOB_ECCPOS19; oob_config.ecc_pos[20] = NAND_JFFS2_OOB_ECCPOS20; oob_config.ecc_pos[21] = NAND_JFFS2_OOB_ECCPOS21; oob_config.ecc_pos[22] = NAND_JFFS2_OOB_ECCPOS22; oob_config.ecc_pos[23] = NAND_JFFS2_OOB_ECCPOS23;
(17)1645行(oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;)后添加:
oob_config.ecc_pos[6] = NAND_NOOB_ECCPOS6; oob_config.ecc_pos[7] = NAND_NOOB_ECCPOS7; oob_config.ecc_pos[8] = NAND_NOOB_ECCPOS8; oob_config.ecc_pos[9] = NAND_NOOB_ECCPOS9; oob_config.ecc_pos[10] = NAND_NOOB_ECCPOS10; oob_config.ecc_pos[11] = NAND_NOOB_ECCPOS11; oob_config.ecc_pos[12] = NAND_NOOB_ECCPOS12; oob_config.ecc_pos[13] = NAND_NOOB_ECCPOS13; oob_config.ecc_pos[14] = NAND_NOOB_ECCPOS14; oob_config.ecc_pos[15] = NAND_NOOB_ECCPOS15; oob_config.ecc_pos[16] = NAND_NOOB_ECCPOS16; oob_config.ecc_pos[17] = NAND_NOOB_ECCPOS17; oob_config.ecc_pos[18] = NAND_NOOB_ECCPOS18; oob_config.ecc_pos[19] = NAND_NOOB_ECCPOS19; oob_config.ecc_pos[20] = NAND_NOOB_ECCPOS20; oob_config.ecc_pos[21] = NAND_NOOB_ECCPOS21; oob_config.ecc_pos[22] = NAND_NOOB_ECCPOS22; oob_config.ecc_pos[23] = NAND_NOOB_ECCPOS23;
/*(18)修改204行(ret = nand_read_oob(nand_dev_desc + curr_device,off, size, (size_t *)&total, (u_char*)addr);)为:
(先定义局部变量unsigned char buf[64];unsigned char num;)
if(size > 64)
{
size = 64;
puts("Max size is 64!/n");
}
ret = nand_read_oob(nand_dev_desc + curr_device,
off, size, (size_t *)&total,
buf);
for(num=0; num<size; num++)
printf("0x%x ",buf[num]);
printf("/n");
修改后可使用命令nand read.oob addr off size读取NAND FLASH任意位置(off)开始连续size字节(最多64)数据并显示(addr无效)
修改217行(ret = nand_write_oob(nand_dev_desc + curr_device,off, size, (size_t *)&total,(u_char*)addr);)为:
if(size > 64)
{
size = 64;
puts("Max size is 64!/n");
}
for(num=0; num<size; num++)
buf[num] = (char)addr;
ret = nand_write_oob(nand_dev_desc + curr_device,
off, size, (size_t *)&total,
buf);
修改后可使用命令nand write.oob addr off size写入NAND FLASH任意位置(off)开始size字节数据addr(只能将1写为0,不能将0写
为1)
*/
<7>vi include/linux/mtd/nand_ids.h
给nand_flash_ids添加一成员:
{"Samsung k9f2g08u0a", NAND_MFR_SAMSUNG, 0xDA, 28, 0, 3, 0x20000, 0},
/************************************************************************************************
struct nand_flash_dev {
char *name; /* 芯片名称 */
int manufacture_id; /* 厂商ID */
int model_id; /* 模式ID */
int chipshift; /* Nand Flash 地址位数 */
char page256; /* 表明是否时256 字节一页。1:是;0:否。*/
char pageadrlen; /* 完成一次地址传送需要 NFADDR 中传送几次。*/
unsigned long erasesize; /* 一次块擦除可以擦除多少字节 */
int bus16; /* 地址线是否是16位,1:是;0:否 */
};
************************************************************************************************/
<8>vi include/configs/fl2440.h
修改179行(#define CFG_ENV_SIZE 0x10000)为:
#define CFG_ENV_SIZE 0x20000 /*Flash块大小,*/
到此uboot可以读取NAND中环境变量,使用saveenv命令保存环境变量到NAND中!
相关链接:
s3c2440对nandflash的操作
http://zhouxiaoxi198906.blog.163.com/blog/static/1290140362010728114118171/
s3c2440 nand 控制器(以对K9F2G08U0A 256M读操作为例)
http://blog.163.com/chenfang7977@yeah/blog/static/128274196201008101048689/
skyeye 上实现U-Boot 的Nand命令,解决nand read错误
http://student.csdn.net/space.php?uid=91306&do=blog&id=12691
U-BOOT环境变量实现
http://blog.chinaunix.net/u2/70445/showart_1852111.html