第一次移植uboot(2)(NAND中环境变量读写)

/*在第一次移植的基础上增加了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

 

 

你可能感兴趣的:(第一次移植uboot(2)(NAND中环境变量读写))