u-boot for tiny210 ver4.0 (by liukun321 咕唧咕唧)

          在修改ver3.1的时候,只是扫了一眼源码,看到支持yaffs写命令,就想当然的认为“大页NAND出来这么多年了,uboot应该支持yaffs2的烧写了”。由于时间问题,当时也没有测试这个功能。这几天仔细看了源码,假象啊。ver3.1还是不支持yaffs2的烧写的。只支持yaffs(小页nand)的烧写。在此郑重的向被我“忽悠”的网友道歉。 也许现在烧写yaffs2的问题早已经被朋友们解决了,毕竟过去这么长时间了,对于有u-boot移植经验的朋友,这个小bug 1天应该就可以搞定。 现在写这个bug的解决方案,对大牛们来说可能没什么价值了,但是希望能给后来的朋友提供点移植思路。好了,废话不多说,进入正题。

ver4.0源码下载:u-boot for tiny210 ver4.0

下面的链接提供了历史版本的源码

ver3.1源码下载: u-boot for tiny210 ver3.1

ver3.0源码下载:u-boot for tiny 210 ver3.0

ver2.2源码下载:  u-boot for tiny210 ver2.2

ver2.1源码下载:u-boot for tiny210 ver2.2

ver2.1源码下载:u-boot for tiny210 ver2.1

ver2.0源码下载:u-boot for tiny210 ver2.0

各版本修改分析链接: ver2.0    ver2.1   ver2.2  ver2.2.1  ver2.2.2  ver 3.0  ver3.1

 

ver4.0的基本功能:

1. SD boot,基于linaro u-boot的SPL功能实现

2. 从SD卡的FAT分区上加载文件到SDRAM

3. 将环境变量保存至SD卡

4. 添加DM9000网卡驱动,开启网络功能(例如:tftp,nfs等)

5. 添加TAB键命令自动补全功能

6.修复bug:

修复bug 1:SD卡保存环境变量出现Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed。

修复bug 2:每次启动只能保存一次环境变量。

7.添加NandFlash驱动,开启所有Nand cmd。

8.添加Yaffs文件系统烧写支持。

9.修改在SD卡启动及nand启动时对nandflash的烧写为8bit 硬件ECC校验。

10.添加Nandflash启动。

11.添加自动识别Nand or MMC/SD启动。

+12.添加yaffs2文件系统烧写支持。  

+13.添加显示Nandflash烧写进度。

       

 

       在正式修改u-boot前,希望大家能看一下这篇bloghttp://blog.csdn.net/liukun321/article/details/8558591。对yaffs2的原理有个大概了解。其实u-boot烧写yaffs2与往nand烧写普通数据区别在于:yaffs2的.img镜像中不仅包含了根文件系统的数据,而且还包含了oob区的数据。打开.img镜像截取第一块的oob数据内容如下图:

       800h-830h就是镜像中第一块的oob数据(共64byte),u-boot烧写yaffs2时需要把这部分数据烧到nand的oob区。而800h开始的前两字节是用于标记坏块的,如果不是坏块则全为FF。从第三字节到第40个字节存放的是yaffs2每块的“标记数据”(这个词用的可能不恰当)。第41到第64字节存放的是yaffs2自己的ECC校验值。

       这里还要说一下u-boot与友善的Superboot对烧写yaffs2的区别:Superboot烧写yaffs2是用的应该是4bit HW(硬件)ECC,那么nandflash第41到第64字节存放的数据就不在是yaffs2镜像的ECC值了,而是烧写过程中产生的4bit HW(硬件)ECC值--->对应在内核配置时要开启硬件ECC校验,关yaffs2自己的ECC校验。而u-boot烧写时是把yaffs2镜像文件里的oob数据烧到nandflash的oob区中,相当于用的是yaffs2自己的ECC校验,对应内核配置---->关硬件ECC,开启yaffs2自己的ECC(对于内核配置,我后面还会具体说明)。ver4.0 修改过程如下(会贴源码,在此声明一下,贴源码不是为了凑字数,blog不是写论文没有凑字数的必要,因为在贴源码的过程会穿插解释,只是为了更直观体现修改原理,这对“牛人”来说可能没什么用,“牛人”直接看源码就可以了。但是还有很多新手,新手需要更多的解释,希望各位“牛人”见谅):

拿到ver3.1的源码

1.在include/configs/tiny210.h 文件中对应行处添加下面红字部分:

412 #define CONFIG_CMD_NAND
413 #if defined(CONFIG_CMD_NAND)
414 #define CONFIG_CMD_NAND_YAFFS 1
415 #define CONFIG_CMD_NAND_YAFFS2 1
416 #define CONFIG_CMD_MTDPARTS
417 #define CONFIG_SYS_MAX_NAND_DEVICE 1
.............................

423 #define NF_TRANSRnB()           do { while(!(NFSTAT_REG & (1 << 0))); } whil    e(0)
—424 #define CONFIG_CMD_NAND_YAFFS_SKIPFB 1
425 #define CONFIG_NAND_USE_CHIP_NAME 1
426 #undef  CFG_NAND_FLASH_BBT
427 #endif
 由于在烧写时不需要跳过第一个good block ,所以去掉定义  #define CONFIG_CMD_NAND_YAFFS_SKIPFB 1

2.修改common/cmd_nand.c

592                                                 WITH_DROP_FFS);
593 #endif
594 #if defined(CONFIG_CMD_NAND_YAFFS)&&(!defined(CONFIG_CMD_NAND_YAFFS2))
595                 } else if (!strcmp(s, ".yaffs")) {
596                         if (read) {
597                                 printf("Unknown nand command suffix '%s'.\n", s);
598                                 return 1;
599                         }ret = nand_write_skip_bad(nand, off, &rwsize,
      (u_char *)addr, WITH_YAFFS_OOB);
600 #endif
+601 #if defined(CONFIG_CMD_NAND_YAFFS)&&defined(CONFIG_CMD_NAND_YAFFS2)
+602 }else if ( s != NULL &&(!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))){
+603                         if(read)  {
+604                                   printf("nand read.yaffs[1] is not provide temporarily!");
+
605                             } else    {
+606                                 nand->rw_oob = 1;
+607 #if defined(CONFIG_CMD_NAND_YAFFS_SKIPFB)
+608                                 nand->skipfirstblk = 1;
+609 #else
+610                                 nand->skipfirstblk = 0;
+611 #endif
+612                         ret = nand_write_skip_bad(nand, off, &rwsize,
+613                                                 (u_char *)addr, WITH_YAFFS_OOB);
+614
+615 #if defined(CONFIG_CMD_NAND_YAFFS_SKIPFB)
+616                                 nand->skipfirstblk = 0;
+617 #endif
+618                                 nand->rw_oob = 0;
+619                             }
+620 #endif
621                 } else if (!strcmp(s, ".oob")) {
622                         /* out-of-band data */
623                         mtd_oob_ops_t ops = {

nand->rw_oob = 0;,nand->skipfirstblk  是新定义的两个变量,分别作为烧写oob区标记变量和跳过第一个block的标记变量.nand_write_skip_bad(nand, off, &rwsize,(u_char *)addr, WITH_YAFFS_OOB); 函数执行时在烧写nand过程中会烧写oob区。

3. 修改drivers/mtd/nand/nand_util.c 文件的int nand_write_skip_bad 函数.使之支持烧写oob区

485         u_char *p_buffer = buffer;
486         int need_skip;
487
488 /*****************Modified by lk***********************/
+489 #if defined(CONFIG_CMD_NAND_YAFFS2)
+490         if(nand->rw_oob==1)     {
+491                 size_t oobsize = nand->oobsize;
+492                 size_t datasize = nand->writesize;
+493                 int datapages = 0;
+494                
+495                
+496                 if (((*length)%(nand->oobsize+nand->writesize)) != 0) {
+497                     printf ("Attempt to write error length data!\n");
+498                     return -EINVAL;
+499             }      
+500            
+501                 datapages = *length/(datasize+oobsize);
+502                 *length = datapages*datasize;
+503                 left_to_write = *length;
+504                
+505         }      
+506                 else
+507 #else/*************************************************/
508          if (flags & WITH_YAFFS_OOB) {
509                 if (flags & ~WITH_YAFFS_OOB)
510                         return -EINVAL;
511
512                 int pages;
513                 pages = nand->erasesize / nand->writesize;
514                 blocksize = (pages * nand->oobsize) + nand->erasesize;
515                 if (*length % (nand->writesize + nand->oobsize)) {
516                         printf ("Attempt to write incomplete page"
517                                 " in yaffs mode\n");
518                         return -EINVAL;
519                 }
520         } else
+521 #endif
522         {
523                 blocksize = nand->erasesize;
524         }
.....................................

544         if (need_skip < 0) {
545                 printf ("Attempt to write outside the flash area\n");
546                 *length = 0;
547                 return -EINVAL;
548         }
549 /********************Modified by lk**********************************/
+550 #if !defined(CONFIG_CMD_NAND_YAFFS2)
551         if (!need_skip && !(flags & WITH_DROP_FFS)) {
552                 rval = nand_write (nand, offset, length, buffer);
........................... 
559                 return rval;
560                         }
+561 #endif
562 /*******************************************************************/
563         while (left_to_write > 0) {
564                 size_t block_offset = offset & (nand->erasesize - 1);
565                 size_t write_size, truncated_write_size;
567                 WATCHDOG_RESET ();
568
569                 if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
570                         printf ("Skip bad block 0x%08llx\n",
571                                 offset & ~(nand->erasesize - 1));
572                         offset += nand->erasesize - block_offset;
573                         continue;
574                 }
575 //********************Modified by lk*******************************/
+576 #if defined(CONFIG_CMD_NAND_YAFFS)&&defined(CONFIG_CMD_NAND_YAFFS2)
+577                 if(nand->skipfirstblk==1)       {
+578                         nand->skipfirstblk=0;
+579                         printf ("Skip the first good block %llx\n",
+580                                 offset & ~(nand->erasesize - 1));
+581                         offset += nand->erasesize - block_offset;
+582                         continue;
+583                 }
+584 #endif
585 /****************************************************************/
586                 if (left_to_write < (nand->erasesize- block_offset))//blocksize
587                         write_size = left_to_write;
588                 else
589                         write_size = nand->erasesize- block_offset;
590 /*******************************Modified by lk*****************************/
591 #if defined(CONFIG_CMD_NAND_YAFFS)&&(!defined(CONFIG_CMD_NAND_YAFFS2))
592                 if (flags & WITH_YAFFS_OOB) {
593
594                         int page, pages;
............................................
609                                 ops.oobbuf = ops.datbuf + pagesize;
611                                 rval = nand->write_oob(nand, offset, &ops);
612                                 if (!rval)
613                                         break;
614
615                                 offset += pagesize;
616                                 p_buffer += pagesize_oob;
617                         }
618                 }
619                 else
620 #endif/*********************************************************/
621                 {
622                         truncated_write_size = write_size;
623 #ifdef CONFIG_CMD_NAND_TRIMFFS
624                         if (flags & WITH_DROP_FFS)
625                                 truncated_write_size = drop_ffs(nand, p_buffer,
626                                                 &write_size);
627 #endif
+628                         printf("\rWriting at 0x%llx -- ",offset);//Modified by lk  显示烧写位置    
629                         rval = nand_write(nand, offset, &truncated_write_size,
630                                         p_buffer);
631 //************************Modified by lk****************************
+632 #if (defined(CONFIG_CMD_NAND_YAFFS)&&(!defined(CONFIG_CMD_NAND_YAFFS2)))
633                         offset += write_size;
634                         p_buffer += write_size;
+635 #endif
636 //******************************************************************
637                 }
638
639                 if (rval != 0) {
640                         printf ("NAND write to offset %llx failed %d\n",
641                                 offset, rval);
642                         *length -= left_to_write;
643                         return rval;
644                 }
645                 left_to_write -= write_size;
+646                 printf("%d%% is complete.",100-(left_to_write/(*length/100)));//Modified by lk 显示烧写进度
647 //**************************************Modified by lk***************************
+648 #if (defined(CONFIG_CMD_NAND_YAFFS)&&defined(CONFIG_CMD_NAND_YAFFS2))
+649                 offset        += write_size;
+650                 if(nand->rw_oob==1)     {
+651                         p_buffer += write_size+(write_size/nand->writesize*nand->oobsize);
+652                 } else  {
+653                         p_buffer += write_size;
+654                 }
+655 #else
656                 p_buffer      += write_size;
+657 #endif
658 //******************************************************************************
659         }
660
661         return 0;
662 }
 因为在上面函数中会调用nand_write函数故做下面修改。          

 

4.修改drivers/mtd/nand/nand_base.c文件,使nand_write支持64byte,oob的烧写

static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
1948                           size_t *retlen, const uint8_t *buf)
1949 {
1950         struct nand_chip *chip = mtd->priv;
1951         int ret;
+1952 #if defined(CONFIG_CMD_NAND_YAFFS)
1953 /*Modified by lk*/
+1954          int oldopsmode = 0;
+1955          if(mtd->rw_oob==1) {
+1956
+1957         size_t oobsize = mtd->oobsize;
+1958          size_t datasize = mtd->writesize;
+1959          int i = 0;
+1960          uint8_t oobtemp[oobsize];
+1961          int datapages = 0;
+1962
+1963          datapages = len/(datasize);
+1964          for(i=0;i<(datapages);i++) {
+1965          memcpy((void *)oobtemp,
+1966          (void *)(buf+datasize*(i+1)),oobsize);
+1967          memmove((void *)(buf+datasize*(i+1)),(void *)(buf+datasize*(i+1)+o     obsize),(datapages-(i+1))*(datasize)+(datapages-1)*oobsize);
+1968  }
1969 #endif
1970
1971         /* Do not allow writes past end of device */
1972         if ((to + len) > mtd->size)
1973                 return -EINVAL;
1974         if (!len)
1975                 return 0;
1976         nand_get_device(chip, mtd, FL_WRITING);
1977         chip->ops.len = len;
1978         chip->ops.datbuf = (uint8_t *)buf;
1979         //chip->ops.oobbuf = NULL;
1980
+1981 #if defined(CONFIG_CMD_NAND_YAFFS)
+1982         /*Modified by lk*/
+1983         if(mtd->rw_oob!=1)      {
+1984           chip->ops.oobbuf = NULL;
+1985         } else  {
+1986           chip->ops.oobbuf = (uint8_t *)(buf+len);
+1987           chip->ops.ooblen = mtd->oobsize;
+1988           oldopsmode = chip->ops.mode;
+1989           chip->ops.mode = MTD_OOB_RAW;
+1990         }
+1991 #else
1992         chip->ops.oobbuf = NULL;
+1993 #endif
1994
1995         ret = nand_do_write_ops(mtd, to, &chip->ops);
1996
1997         *retlen = chip->ops.retlen;
1998
1999         nand_release_device(mtd);
2000
+2001 #if defined(CONFIG_CMD_NAND_YAFFS)
+2002         /*Modified by lk*/
+2003         chip->ops.mode = oldopsmode;
+2004 #endif
2005
2006         return ret;
2007 }

5.修改include/linux/mtd/mtd.h 添加两变量定义

238         void (*put_device) (struct mtd_info *mtd);
+239 #if defined(CONFIG_CMD_NAND_YAFFS)
+240          u_char rw_oob;
+241          u_char skipfirstblk;
+242 #endif
至此 u-boot for tiny210 ver4.0修改完毕.

 

编译u-boot
$make distclean
$make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- tiny210_config
$make ARCH=arm CROSS_COMPILE=/opt/FriendlyARM/toolschain/4.5.1/bin/arm-none-linux-gnueabi- all spl
由于我的系统下装有两套交叉工具链,所以没有把 /opt/FriendlyARM/toolschain/4.5.1/bin/ 添加到环境变量,在使用工具链时要指明路径。

1.sd启动
 
将u-boot镜像写入SD卡
将SD卡通过读卡器接上电脑(或直接插入笔记本卡槽),通过"cat /proc/partitions"找出SD卡对应的设备,我的设备节点是/dev/sdb.

执行下面的命令
$sudo dd iflag=dsync oflag=dsync if=tiny210-uboot.bin of=/dev/sdb seek=1
2.nand启动
通过SD卡启动的u-boot for tiny210 将u-boot镜像写入nandflash
开发板终端下执行下面的命令
[FriendlyLEG-TINY210]# tftp 21000000 tiny210-uboot.bin
[FriendlyLEG-TINY210]# nand erase.chip
[FriendlyLEG-TINY210]# nand write 21000000 0 3c1f4 

 

另外需更改内核配置:

1.去掉S3C NAND Hardware ECC 选项                                   

 Device Drivers  --->   
 <*> Memory Technology Device (MTD) support  ---> 
  <*>   NAND Device Support  --->   
  --- NAND Device Support                                          
  │ │    [ ]   Verify NAND page writes                                    │ │  
  │ │    [ ]   Enable chip ids for obsolete ancient NAND devices          │ │  
  │ │    (0xFF108018) Denali NAND size scratch register address           │ │  
  │ │    < >   GPIO NAND Flash driver                                     │ │  
  │ │    <*>   NAND Flash support for S3C SoC                             │ │  
  │ │    []     S3C NAND driver debug                                    │ │  
  │ │    []     S3C NAND Hardware ECC                                    │ │

2.选择yaffs2自己的ECC校验算法。

  File systems  --->     

            [*] Miscellaneous filesystems  --->

                                 <*>   YAFFS2 file system support                                 │ │  
                                  -*-     512 byte / page devices                                  │ │  
                                   [ ]       Use older-style on-NAND data format with pageStatus byt│ │  
                                   [*]         Lets Yaffs do its own ECC                            │ │  
                                   [ ]           Use the same ecc byte order as Steven Hill's nand_e│ │  
                                  -*-     2048 byte (or larger) / page devices                     │ │  
                                   [*]       Autoselect yaffs2 format 

配置好内核以后重新编译内核。

3.去掉内核的软件ECC校验。
修改内核\drivers\mtd\nand\S3c_nand.c

1172:#else
1173:  nand->ecc.mode = NAND_ECC_NONE;

 

根据友善内核的分区表:

                                

内核的烧写位置是0x600000开始的区域,文件系统烧写位置为0xe00000开始的区域。

用友善的镜像做烧写文件系统的测试,用下面三条命令完成烧写yaffs2文件系统(注:在烧写yaffs2时要擦除0xe00000开始后面所有的块中的数据,否则会由于残存的数据影响Android启动

[FriendlyLEG-TINY210]#tftp 21000000 rootfs_android.img
[FriendlyLEG-TINY210]#nand erase e00000 f200000  
[FriendlyLEG-TINY210]#nand write.yaffs 21000000 e00000 b03c280

烧写过程如下图:

启动信息如下图:(注:若在校正触摸屏出现Calibration failed.的问题,多尝试校正(保存)几次就通过了。测试时偶尔出现过这个问题。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 44
    评论
评论 44
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值