在上一篇中我们重点介绍了K9GAG08U0D 和 K9GAG08U0E的区别,除了这些外还有一个需要重点关注的地方,下面我们详细讲解。

        Uboot从NandFlash启动第一步就是把NandFlash的前8K代码拷贝到s3c6410内部的SRAM中,然后运行,这8K的代码会从NandFlash中把完整的Uboot代码拷贝到6410开发板片外内存中,我这里使用的是256M的DDR,Uboot的存放地址为0x5FE00000,虚拟地址为 0xCFE00000.

注意:关键的8K代码不是在U0D(每页4K)的前两页存放,也不是在U0E(每页8K)的第一页存放,而是在U0E或者U0D的             前四页中存放的,前四页分为每页2K,总共8K,这是由s3c6410芯片本身所规定的。这8K字节外后面的数据就是按实             际的页数存放了,U0D 每页存放4K字节,U0E每页存放8K字节。

              s3c6410支持从SD卡启动,从SD卡启动后就可以把Uboot.bin文件写入NandFlash了,可以认真的看一下Uboot 里面 的 nand write.uboot 命令是如何把数据写入NandFlash前4页 的。写入成功后就可以从NandFlash启动Uboot。

       nand write.uboot 的关键代码 位于uboot1.1.6/common/cmd_nand.c文件中:

            if (!read && s != NULL && (!strcmp(s, ".uboot")) && nand->writesize == 4096) //U0D 

           {    

            size=4096;
            nand_write(nand, off, &size, (u_char *)addr);
            off+=4096;
            addr+=2048;
           nand_write(nand, off, &size, (u_char *)addr);
            off+=4096;
            addr+=2048;
           nand_write(nand, off, &size, (u_char *)addr);
           off+=4096;
           addr+=2048;
           nand_write(nand, off, &size, (u_char *)addr);
           off+=4096;
           addr+=2048;

            size=1024*1024-4*4096;
            ret = nand_write(nand, off, &size, (u_char *)addr);

            }else if(!read && s != NULL && (!strcmp(s, ".uboot")) && nand->writesize == 8192) //U0E
                {
                    size=8192;  
                    ret=nand_write(nand, off, &size, (u_char *)addr);

                    off+=8192;
                    addr+=2048;
                    ret=nand_write(nand, off, &size, (u_char *)addr);
                    off+=8192;
                    addr+=2048;
                    ret=nand_write(nand, off, &size, (u_char *)addr);
                    off+=8192;
                    addr+=2048;
                    ret=nand_write(nand, off, &size, (u_char *)addr);

                    off+=8192;
                    addr+=2048;
//写剩余的页面,这里的Uboot占用1M的NandFlash地址空间,在U0E里面占用128个页面(128Page=1M),上面已经写了四个页面了,这里写剩余的124个页,124个页面足够存放Uboot的有效数据了。
                    size=1024*1024-4*8192;
                    ret = nand_write(nand, off, &size, (u_char *)addr);
                }

现在我们重点要看 Uboot代码,uboot1.1.6/cpu/s3c64xx/nand_cp.c 文件:

 //该函数在Uboot.bin前8K代码中,这个函数实现把Uboot从Nandflash拷贝到外部内存中,是Uboot从Nandflash启动的关键地方

int copy_uboot_to_ram (void)

{
      int large_block = 0;
      int i;
      vu_char id;

        NAND_ENABLE_CE();
        NFCMD_REG=NAND_CMD_RESET;
        NF_TRANSRnB();


        NFCMD_REG = NAND_CMD_READID;
        NFADDR_REG =  0x00;
        NF_TRANSRnB();
/* wait for a while */
        for (i=0; i<200; i++);


        int factory = NFDATA8_REG;
        id = NFDATA8_REG;

        int cellinfo=NFDATA8_REG;
        int tmp= NFDATA8_REG;

        int childType=tmp & 0x03; //Page size

        if (id > 0x80)
        {
            large_block = 1;
        }
        if(id == 0xd5 && childType==0x01 ) //K9GAG08U0D
        {
            large_block = 2;
        }else if(id == 0xd5 && childType==0x02 ) //K9GAG08U0D
        {
            large_block = 3;
        }

    /* read NAND Block.
    * 128KB ->240KB because of U-Boot size increase. by scsuh
    * So, read 0x3c000 bytes not 0x20000(128KB).
    */
   return nandll_read_blocks(CFG_PHY_UBOOT_BASE, 0x3c000, large_block);

}

static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
{
       uchar *buf = (uchar *)dst_addr;
       int i;
       uint page_shift = 9;

      if (large_block==1)
        page_shift = 11;

      if(large_block==2)
          page_shift = 12;

      if(large_block==3)
                page_shift =13;

      if(large_block == 2) // K9GAG08U0D

       {
                /* Read pages */
         for (i = 0; i < 4; i++, buf+=(1<<(page_shift-1))) 

          {
                  nandll_read_page(buf, i, large_block);
          }

       /* Read pages */
      for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) 

      {
       nandll_read_page(buf, i, large_block);
     }
      }else if(large_block == 3)  //K9GAG08U0E
        {
            /* Read pages */
            for (i = 0; i < 4; i++, buf+=(1<<(page_shift-2))) 

            {
                    nandll_read_page(buf, i, large_block);
            }
            /* Read pages */
            for (i = 4; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) 

            {
                    nandll_read_page(buf, i, large_block);
            }
        }

    else
      {
            for (i = 0; i < (0x3c000>>page_shift); i++, buf+=(1<<page_shift)) 

             {
                   nandll_read_page(buf, i, large_block);
               }
       }
        return 0;
}

static int nandll_read_page (uchar *buf, ulong addr, int large_block)
{
     int i;
     int page_size = 512;

     if (large_block==1)
         page_size = 2048;
     if (large_block==2)
         page_size = 4096;
     if(large_block==3)
         page_size = 8192;

       NAND_ENABLE_CE();
       NFCMD_REG = NAND_CMD_READ0;


        /* Write Address */ //5 个寻址周期,参看下图
        NFADDR_REG = 0;
        if (large_block)
       NFADDR_REG = 0;
       NFADDR_REG = (addr) & 0xff;
       NFADDR_REG = (addr >> 8) & 0xff;
       NFADDR_REG = (addr >> 16) & 0xff;


        if (large_block)
           NFCMD_REG = NAND_CMD_READSTART;

        NF_TRANSRnB(); //等待NandFlash 状态引脚可读。


       /* for compatibility(2460). u32 cannot be used. by scsuh */
       for(i=0; i < page_size; i++) 

        {
                *buf++ = NFDATA8_REG;
        }

        NAND_DISABLE_CE();
        return 0;
}

寻址周期图:

具体的说明请参考K9GAG08U0E  DataSheet 第9页。

这里用两片文章写了s3c6410支持K9GAG08U0E 的关键地方,当然还有一些具体的细节了,比如给关键结构体 nand  chip, mtd_device 等赋值Page大小,Block大小,OOB大小的操作,硬件ECC 8bit 纠错等功能,当然这些不是K9GAG08U0E特有的功能,K9GAG08U0D也需要这样的操作,这里就不详细的介绍了。

希望这两篇文章对需要了解NandFlash如何通过软件工作的朋友有参考价值。



GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐