原文地址:http://blog.csdn.net/ll_0520/archive/2010/11/29/6043675.aspx
/*在第一次移植的基础上增加了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;
- 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片选
-
-
- #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;
- unsigned long page_number = ofs >> 12;
-
- NAND_ENABLE_CE(nand);
-
- for(num=0; num
- {
- page_number = ofs >> 12;
-
- NanD_Command(nand, NAND_CMD_READ0);
-
- WRITE_NAND_PAGE_ADDRESS(0x00, 0);
- 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_READ1);
-
- NanD_WaitReady(nand, 1);
-
- NanD_Command(nand, NAND_CMD_RANDOMREAD1);
-
-
- WRITE_NAND_PAGE_ADDRESS((char)(ofs&0xff), 0);
- WRITE_NAND_PAGE_ADDRESS((char)((ofs>>8)&0x0f), 0);
-
- NanD_Command(nand, NAND_CMD_RANDOMREAD2);
-
- *buf = READ_NAND(ofs);
-
- 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;
- unsigned long page_number = ofs >> 12;
-
- NAND_ENABLE_CE(nand);
-
- for(num=0; num
- {
- page_number = ofs >> 12;
-
- NanD_Command(nand, NAND_CMD_SEQIN);
-
- WRITE_NAND_PAGE_ADDRESS(0x00, 0);
- 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);
-
- buf++;
-
- NanD_Command(nand, NAND_CMD_PAGEPROG);
-
- NanD_Command(nand, NAND_CMD_STATUS);
-
- if (READ_NAND(nandptr) & 1) {
- puts ("Error programming oob data\n");
-
- NAND_DISABLE_CE(nand);
- *retlen = 0;
- return -1;
- }
- ofs++;
-
- }
-
- NAND_DISABLE_CE(nand);
- *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:
- 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 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 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