Chinaunix首页 | 论坛 | 博客
  • 博客访问: 568885
  • 博文数量: 114
  • 博客积分: 1620
  • 博客等级: 上尉
  • 技术积分: 1104
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-30 09:16
文章分类

全部博文(114)

文章存档

2016年(1)

2015年(2)

2014年(4)

2013年(9)

2012年(20)

2011年(78)

分类: 嵌入式

2011-03-09 16:23:05

原文地址: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))后加:

  1. #define NFCONF  (*(volatile unsigned *)0x4E000000)  
  2. #define NFCONT  (*(volatile unsigned *)0x4E000004)  
  3. #define NFCMD   (*(volatile unsigned *)0x4E000008)  
  4. #define NFSTAT  (*(volatile unsigned *)0x4E000020)  
  5. #define TACLS   0  
  6. #define TWRPH0  3  
  7. #define TWRPH1  0  
 

  <3>lib_arm/board.c中添加函数:

  1. void nand_init()  
  2. {  
  3.         unsigned long total;  
  4.         NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);  
  5.         NFCONT = (1<<4)|(1<<1)|(1<<0);  
  6.   
  7.         NFCONT &= ~(1<<1);  
  8.         NFCMD = 0xff;   /*nand reset*/  
  9.         while((NFSTAT&0x1) != 1);  
  10.         NFCONT |= 0x2;  
  11.   
  12.         total = nand_probe(0x4E000010);  
  13.   
  14.         printf("%dMB\n",total/1024/1024);  
  15. }  

文件开头加上声明:extern unsigned long nand_probe(unsigned long physadr);

   <4>vi include/linux/mtd/nand.h 添加:

  1. #define CFG_MAX_NAND_DEVICE     1  
  2. #define NAND_ChipID_UNKNOWN     0  
  3. #define SECTORSIZE              2048 /* 1页的大小 */  
  4. #define ADDR_COLUMN             2 /*列地址(Column Address)字节数*/  
  5. #define ADDR_PAGE               3 /*行地址(Row Address)字节数*/  
  6. #define ADDR_COLUMN_PAGE        5 /*行,列总字节数*/  
  7. #define ADDR_READ_ID  0 /*读NAND FLASH芯片ID标志*/  
  8. #define NAND_MAX_FLOORS         1  
  9. #define NAND_MAX_CHIPS          1  
  10. #define CFG_ENV_OFFSET          0x60000 /*环境变量在NAND FLASH中起始地址*/  
 

   <5>vi include/linux/mtd/nand.h 添加:

  1. #define rNFCONF (*(volatile unsigned *)0x4E000000)  
  2. #define rNFCONT (*(volatile unsigned *)0x4E000004)  
  3. #define rNFCMD (*(volatile unsigned *)0x4E000008)  
  4. #define rNFADDR (*(volatile unsigned *)0x4E00000C)  
  5. #define rNFDATA (*(volatile unsigned *)0x4E000010)  
  6. #define rNFSTAT (*(volatile unsigned *)0x4E000020)  
  7. #define rNFDATA8 (*(volatile unsigned char *)0x4E000010)  
  8.   
  9. #define NAND_WAIT_READY(nand) {while((rNFSTAT&0x1) != 1);} //等待nandflash不忙  
  10. #define WRITE_NAND_COMMAND(d, adr) {rNFCMD = d;}  //写命令  
  11. #define WRITE_NAND_COLUMN_ADDRESS(d, adr) {rNFADDR = d;rNFADDR = (d>>8) & 0x0f;} //写列地址  
  12. #define WRITE_NAND_PAGE_ADDRESS(d, adr) {rNFADDR = d;} //写行地址  
  13. #define WRITE_NAND_ID_ADDRESS(d, adr) {rNFADDR = d;} //写读取芯片ID时的地址  
  14. #define WRITE_NAND(d, adr) {rNFDATA8 = d;}  //写数据到NAND(1字节),直接写rNFDATA(即rNFDATA=d)会写入4字节  
  15. #define READ_NAND(adr)  (rNFDATA8)  //读NAND中数据(1字节),直接读rNFDATA(即rNFDATA=d)会读入4字节  
  16. #define NAND_DISABLE_CE(nand) {rNFCONT |= (1<<1);} //关闭nandflash片选  
  17. #define NAND_ENABLE_CE(nand) {rNFCONT &= ~(1<<1);} //打开nandflash片选  
  18.   
  19. /* the following functions are NOP's because S3C24X0 handles this in hardware  一定要加上 */  
  20. #define NAND_CTL_CLRALE(nandptr)  
  21. #define NAND_CTL_SETALE(nandptr)  
  22. #define NAND_CTL_CLRCLE(nandptr)  
  23. #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)后添加:

  1. #define NAND_NOOB_ECCPOS6  17  
  2. #define NAND_NOOB_ECCPOS7  18  
  3. #define NAND_NOOB_ECCPOS8  19  
  4. #define NAND_NOOB_ECCPOS9  20  
  5. #define NAND_NOOB_ECCPOS10  21  
  6. #define NAND_NOOB_ECCPOS11  22  
  7. #define NAND_NOOB_ECCPOS12  23  
  8. #define NAND_NOOB_ECCPOS13  24  
  9. #define NAND_NOOB_ECCPOS14  25  
  10. #define NAND_NOOB_ECCPOS15  26  
  11. #define NAND_NOOB_ECCPOS16  27  
  12. #define NAND_NOOB_ECCPOS17  28  
  13. #define NAND_NOOB_ECCPOS18  29  
  14. #define NAND_NOOB_ECCPOS19  30  
  15. #define NAND_NOOB_ECCPOS20  31  
  16. #define NAND_NOOB_ECCPOS21  32  
  17. #define NAND_NOOB_ECCPOS22  33  
  18. #define NAND_NOOB_ECCPOS23  34  
 

      (5)243行(#define NAND_JFFS2_OOB_ECCPOS5          7)后添加:

  1. #define NAND_JFFS2_OOB_ECCPOS6  17  
  2. #define NAND_JFFS2_OOB_ECCPOS7  18  
  3. #define NAND_JFFS2_OOB_ECCPOS8  19  
  4. #define NAND_JFFS2_OOB_ECCPOS9  20  
  5. #define NAND_JFFS2_OOB_ECCPOS10  21  
  6. #define NAND_JFFS2_OOB_ECCPOS11  22  
  7. #define NAND_JFFS2_OOB_ECCPOS12  23  
  8. #define NAND_JFFS2_OOB_ECCPOS13  24  
  9. #define NAND_JFFS2_OOB_ECCPOS14  25  
  10. #define NAND_JFFS2_OOB_ECCPOS15  26  
  11. #define NAND_JFFS2_OOB_ECCPOS16  27  
  12. #define NAND_JFFS2_OOB_ECCPOS17  28  
  13. #define NAND_JFFS2_OOB_ECCPOS18  29  
  14. #define NAND_JFFS2_OOB_ECCPOS19  30  
  15. #define NAND_JFFS2_OOB_ECCPOS20  31  
  16. #define NAND_JFFS2_OOB_ECCPOS21  32  
  17. #define NAND_JFFS2_OOB_ECCPOS22  33  
  18. #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为:

  1. static int nand_read_oob(struct nand_chip* nand, size_t ofs, size_t len, size_t * retlen, u_char * buf)  
  2. {  
  3.         int num;  
  4.         int ret = 0;  
  5.         ofs += nand->oobblock; /*这里传来的ofs是页的Main区起始地址,为了读Spare区数据,要加nand->oobblock(即2048)*/  
  6.         unsigned long page_number = ofs >> 12;  
  7.   
  8.         NAND_ENABLE_CE(nand);  /* set pin low */  
  9.   
  10.         for(num=0; num
  11.         {  
  12.         page_number = ofs >> 12;  
  13.   
  14.         NanD_Command(nand, NAND_CMD_READ0);  
  15.         //写入5个地址周期  
  16.         WRITE_NAND_PAGE_ADDRESS(0x00, 0);                 //列地址A0~A7  
  17.         WRITE_NAND_PAGE_ADDRESS(0x00, 0);                  //列地址A8~A11  
  18.         WRITE_NAND_PAGE_ADDRESS((page_number) & 0xff, 0); //行地址A12~A19  
  19.         WRITE_NAND_PAGE_ADDRESS((page_number >> 8) & 0xff, 0);//行地址A20~A27  
  20.         WRITE_NAND_PAGE_ADDRESS((page_number >> 16) & 0xff, 0);//行地址A28  
  21.   
  22.         NanD_Command(nand, NAND_CMD_READ1);  
  23.   
  24.         NanD_WaitReady(nand, 1);  
  25.   
  26.         NanD_Command(nand, NAND_CMD_RANDOMREAD1);    //随意读命令周期1  
  27.   
  28.          //页内地址  
  29.         WRITE_NAND_PAGE_ADDRESS((char)(ofs&0xff), 0);      //列地址A0~A7  
  30.         WRITE_NAND_PAGE_ADDRESS((char)((ofs>>8)&0x0f), 0); //列地址A8~A11  
  31.   
  32.         NanD_Command(nand, NAND_CMD_RANDOMREAD2);    //随意读命令周期2  
  33.   
  34.         *buf = READ_NAND(ofs);  
  35.         /*printf("Read oob addr=0x%x val=0x%x ,\n",ofs,*buf);*/  
  36.         buf++;  
  37.         ret = NanD_WaitReady(nand, 1);  
  38.   
  39.         ofs++;  
  40.   
  41.         }  
  42.          NAND_DISABLE_CE(nand);  
  43.   
  44.         *retlen = len;  
  45.   
  46.         return ret;  
  47. }  

修改函数nand_write_oob为:

  1. static int nand_write_oob(struct nand_chip* nand, size_t ofs, size_t len,  
  2.                   size_t * retlen, const u_char * buf)  
  3. {  
  4.         int num;  
  5.         int ret = 0;  
  6.         ofs += nand->oobblock; /*这里传来的ofs是页的Main区起始地址,为了写Spare区数据,要加nand->oobblock(即2048)*/  
  7.         unsigned long page_number = ofs >> 12;  
  8.   
  9.         NAND_ENABLE_CE(nand);  /* set pin low */  
  10.   
  11.         for(num=0; num
  12.         {  
  13.         page_number = ofs >> 12;  
  14.   
  15.         NanD_Command(nand, NAND_CMD_SEQIN);  
  16.         //写入5个地址周期  
  17.         WRITE_NAND_PAGE_ADDRESS(0x00, 0);                 //列地址A0~A7  
  18.         WRITE_NAND_PAGE_ADDRESS(0x00, 0);                  //列地址  
  19.         WRITE_NAND_PAGE_ADDRESS((page_number) & 0xff, 0); //行地址  
  20.         WRITE_NAND_PAGE_ADDRESS((page_number >> 8) & 0xff, 0);//行地址  
  21.         WRITE_NAND_PAGE_ADDRESS((page_number >> 16) & 0xff, 0);//行地址  
  22.   
  23.         NanD_Command(nand, NAND_CMD_RANDOMWRITE);     //随意写命令  
  24.   
  25.          //页内地址  
  26.         WRITE_NAND_PAGE_ADDRESS((char)(ofs&0xff), 0);      //列地址  
  27.         WRITE_NAND_PAGE_ADDRESS((char)((ofs>>8)&0x0f), 0); //列地址  
  28.   
  29.         WRITE_NAND(*buf, 0);  
  30.         /*printf("Write oob addr=0x%x val=0x%x ,\n",ofs,*buf);*/  
  31.         buf++;  
  32.   
  33.         NanD_Command(nand, NAND_CMD_PAGEPROG);  
  34.   
  35.         NanD_Command(nand, NAND_CMD_STATUS);  
  36.   
  37.         if (READ_NAND(nandptr) & 1) {  
  38.                 puts ("Error programming oob data\n");  
  39.                 /* There was an error */  
  40.                 NAND_DISABLE_CE(nand);  /* set pin high */  
  41.                 *retlen = 0;  
  42.                 return -1;  
  43.         }  
  44.         ofs++;  
  45.   
  46.         }  
  47.   
  48.         NAND_DISABLE_CE(nand);  /* set pin high */  
  49.         *retlen = len;  
  50.         return 0;  
  51. }  
 

      (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)) {)上面添加:

  1. if ((nand->oobblock == 2048) && (last == nand->oobblock)) {  
  2.   for(i=0; i<7; i++)  
  3.    nand_calculate_ecc (&nand->data_buf[i*256+256], &(ecc_code[i*3+3]));  
  4.   for (i = 3; i < 24; i++) {  
  5.    nand->data_buf[(nand->oobblock +  
  6.      oob_config.ecc_pos[i])] = ecc_code[i];  
  7.   }  
  8.   if (oob_config.eccvalid_pos != -1) {  
  9.    nand->data_buf[nand->oobblock +  
  10.            oob_config.eccvalid_pos] &= 0x0f;  
  11.   }    
  12.  }  
 

      (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) {)上面添加:

  1. if (oob_config.eccvalid_pos != -1 && nand->oobblock == 2048 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] &   
  2.   
  3. 0xf0) != 0xf0) {  
  4.   
  5.    for(i=0; i<7; i++)  
  6.     nand_calculate_ecc (&nand->data_buf[i*256+256],  &ecc_calc[i*3+3]);  
  7.   
  8.    for(i=0; i<7; i++)  
  9.    {  
  10.     switch (nand_correct_data (&nand->data_buf[i*256+256], &ecc_code[i*3+3], &ecc_calc[i*3+3])) {  
  11.     case -1:  
  12.      printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page);  
  13.      ecc_failed++;  
  14.      break;  
  15.     case 1:  
  16.     case 2: /* transfer ECC corrected data to cache */  
  17.      if (nand->data_cache)  
  18.       memcpy (&nand->data_cache[256], &nand->data_buf[256], 256);  
  19.      break;  
  20.     }  
  21.    }  
  22.   }  
 

      (16)1619行(oob_config.ecc_pos[5] = NAND_JFFS2_OOB_ECCPOS5;)后添加: 

  1. oob_config.ecc_pos[6] = NAND_JFFS2_OOB_ECCPOS6;  
  2. oob_config.ecc_pos[7] = NAND_JFFS2_OOB_ECCPOS7;  
  3. oob_config.ecc_pos[8] = NAND_JFFS2_OOB_ECCPOS8;  
  4. oob_config.ecc_pos[9] = NAND_JFFS2_OOB_ECCPOS9;  
  5. oob_config.ecc_pos[10] = NAND_JFFS2_OOB_ECCPOS10;  
  6. oob_config.ecc_pos[11] = NAND_JFFS2_OOB_ECCPOS11;  
  7. oob_config.ecc_pos[12] = NAND_JFFS2_OOB_ECCPOS12;  
  8. oob_config.ecc_pos[13] = NAND_JFFS2_OOB_ECCPOS13;  
  9. oob_config.ecc_pos[14] = NAND_JFFS2_OOB_ECCPOS14;  
  10. oob_config.ecc_pos[15] = NAND_JFFS2_OOB_ECCPOS15;  
  11. oob_config.ecc_pos[16] = NAND_JFFS2_OOB_ECCPOS16;  
  12. oob_config.ecc_pos[17] = NAND_JFFS2_OOB_ECCPOS17;  
  13. oob_config.ecc_pos[18] = NAND_JFFS2_OOB_ECCPOS18;  
  14. oob_config.ecc_pos[19] = NAND_JFFS2_OOB_ECCPOS19;  
  15. oob_config.ecc_pos[20] = NAND_JFFS2_OOB_ECCPOS20;  
  16. oob_config.ecc_pos[21] = NAND_JFFS2_OOB_ECCPOS21;  
  17. oob_config.ecc_pos[22] = NAND_JFFS2_OOB_ECCPOS22;  
  18. oob_config.ecc_pos[23] = NAND_JFFS2_OOB_ECCPOS23;  
 

      (17)1645行(oob_config.ecc_pos[5] = NAND_NOOB_ECCPOS5;)后添加:

  1. oob_config.ecc_pos[6] = NAND_NOOB_ECCPOS6;  
  2. oob_config.ecc_pos[7] = NAND_NOOB_ECCPOS7;  
  3. oob_config.ecc_pos[8] = NAND_NOOB_ECCPOS8;  
  4. oob_config.ecc_pos[9] = NAND_NOOB_ECCPOS9;  
  5. oob_config.ecc_pos[10] = NAND_NOOB_ECCPOS10;  
  6. oob_config.ecc_pos[11] = NAND_NOOB_ECCPOS11;  
  7. oob_config.ecc_pos[12] = NAND_NOOB_ECCPOS12;  
  8. oob_config.ecc_pos[13] = NAND_NOOB_ECCPOS13;  
  9. oob_config.ecc_pos[14] = NAND_NOOB_ECCPOS14;  
  10. oob_config.ecc_pos[15] = NAND_NOOB_ECCPOS15;  
  11. oob_config.ecc_pos[16] = NAND_NOOB_ECCPOS16;  
  12. oob_config.ecc_pos[17] = NAND_NOOB_ECCPOS17;  
  13. oob_config.ecc_pos[18] = NAND_NOOB_ECCPOS18;  
  14. oob_config.ecc_pos[19] = NAND_NOOB_ECCPOS19;  
  15. oob_config.ecc_pos[20] = NAND_NOOB_ECCPOS20;  
  16. oob_config.ecc_pos[21] = NAND_NOOB_ECCPOS21;  
  17. oob_config.ecc_pos[22] = NAND_NOOB_ECCPOS22;  
  18. 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

阅读(1627) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~