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


     新版本下载:

    下面的链接提供了较新版本的源码

    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
     
    tiny210的uboot是基于  linaro-2011.10 for mini210 修改实现的,在此感谢Alex Ling。
     
     linaro-2011.10 for mini210 源码地址uboot for mini210 
    按下面的说明修改,即可在tiny210上启动。 
     
     
    源码下载:uboot for tiny210   version1.0 (版本 u-boot 2011.06)
    目前功能还是比较少的,后面我还会继续添加。
    基本功能:
    1. SD boot,基于linaro u-boot的SPL功能实现
    2. 从SD卡的FAT分区上加载文件到SDRAM
    3. 将环境变量保存至SD卡(有Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed), 但数据保存是成功的,后续会修改。

     
    但是linaro-2011.10 for mini210是无法直接在tiny210上启动的,终端仅打印OK。而主要问题存在于内存的初始化,板子上电后RAM没有实现正确初始化,而到uboot的lowlevel阶段,无法实现代码的搬运。
     
    进行内存初始化的核心部分位于/board/samsug/mini210/memsteup.S。这段代码的操作是没错误的,那问题可能出在memorycontrol的配置上,对210 的内存配置在/include/configs/mini210.h 中实现。
    tiny210的DDR2 仅挂载在DRAM0区域,而mini210.h 给出的信息显示mini210SDram是在DRAM0和DRAM1分别挂载256M,故作以下修改:
    行:
    142:  #define CONFIG_SYS_LOAD_ADDR  (PHYS_SDRAM_1 + 0x1000000)
     162:       #define CONFIG_NR_DRAM_BANKS  1// 2
    #define SDRAM_BANK_SIZE(512UL << 20UL)//0x10000000/* 256256 MB */
    #define PHYS_SDRAM_1 MEMORY_BASE_ADDRESS
    #define PHYS_SDRAM_1_SIZESDRAM_BANK_SIZE
    +#if 0
    #define PHYS_SDRAM_2(MEMORY_BASE_ADDRESS + 0x20000000) /* SDRAM Bank #2 */
    #define PHYS_SDRAM_2_SIZESDRAM_BANK_SIZE
    +#endif
    tiny210的ram是挂在DRAM0区域的,如下图:
     
    从核心板原理图看出四片128MDDR2作为 1 chip故有如下配置(配置均在mini210.h中):
    315:#define DMC0_MEMCONTROL0x00202400//MemControlBL=4, 1Chip, DDR2 Type, dynamic self refresh, force precharge, dynamic power down off
     
    DRAM0区域起始地址0x20000000,offset 0x1fffffff(512M),根据这个思路参考手册配置MEMCONFIG0 ( chip_base = 0x20  chip_mask = 0xE0 ), 这样我们就可以操作0x20000000 ~0x3fffffff(512M的内存空间)
     
     
     
    tiny210的ram地址线14根(故chip_row 0x2 = 14 bit),见下图
     
     
     
    故有如下配置
     
    316:#define DMC0_MEMCONFIG_0  0x20E00323// MemConfig0512MB config, 8banks,Mapping Method[12:15]0:linear, 1:linterleaved, 2:Mixed
    317:#define DMC0_MEMCONFIG_1  0x00E00323// MemConfig1
     
    另外启动在初始化RAM时会读取ram的大小,函数在/board/samsug/mini210/mini210.c 实现,需要作如下修改:
    +187:#if defined(PHYS_SDRAM_2)
    188:gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
    189 : gd->bd->bi_dram[1].size = get_ram_size((long *)PHYS_SDRAM_2,
    190:                                                      PHYS_SDRAM_2_SIZE);
    +191:#endif
     
     
     
    PS:
    添加tiny210目标板:
    1、修改uboot源码根目录 boards.cfg 文件,183行添加:
     tiny210                      arm         armv7       tiny210             samsung        s5pc1xx
    2、cp board/samsung/mini210 board/samsung/tiny210
    3、将board/samsung/tiny210 下的mini210替换为 tiny210,并将此目录下的Makefile的29行修改为
    COBJS   := tiny210.o ;  再将此目录下 lowlevel_init.S 第35行修改为#include "tiny210_val.h"。
    4、cp include/configs/mini210  include/configs/tiny210.h
    5、vim  include/configs/tiny210.h
    修改:
    #define CONFIG_MINI210   ----> #define CONFIG_TINY210
    #define MACH_TYPE_ MINI210  ----->#define MACH_TYPE_TINY210
    #define CONFIG_MACH_TYPE                MACH_TYPE_MINI210  ---->#define CONFIG_MACH_TYPE                MACH_TYPE_TINY210
     

     
     
    编译u-boot
    $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/ 添加到环境变量,在使用工具链时要指明路径。

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

    执行下面的命令
    $sudo dd iflag=dsync oflag=dsync if=spl/tiny210-spl.bin of=/dev/sdb seek=1
    $sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb  seek=49
     
     
    附:
    烧写完成将卡插入开发板,启动:

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

    version2.0是根据我上一个版本的uboot修改而来的,可以下载源码u-boot for tiny210 version1 后参照下面的内容进行修改 。

    也可以参照version1 从头构建tiny210的uboot 。
     
     
    下面链接提供了较新版本和较老版本的下载链接:

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

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

     
     
    version2实现的基本功能:
    1. SD boot,基于linaro u-boot的SPL功能实现
    2. 从SD卡的FAT分区上加载文件到SDRAM
    3. 将环境变量保存至SD卡(有Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed), 但数据保存是成功的,后续会修改。
    +4. 添加DM9000网卡驱动,开启网络功能(例如:tftp,nfs等)
    +5. 添加TAB键命令自动补全功能

    网络部分修改过程:

    1. 在include/configs/tiny210.h 添加下述宏

    #define DM9000_16BIT_DATA
    #define CONFIG_CMD_NET
    #define CONFIG_DRIVER_DM9000       1
    #define CONFIG_NET_MULTI               1
    #define CONFIG_NET_RETRY_COUNT 1
    #define CONFIG_DM9000_NO_SROM 1
    #ifdef CONFIG_DRIVER_DM9000  
    #define CONFIG_DM9000_BASE              (0x88001000)
    #define DM9000_IO                       (CONFIG_DM9000_BASE)
    #if defined(DM9000_16BIT_DATA)
    #define DM9000_DATA                     (CONFIG_DM9000_BASE+0x300C)
    #else
    #define DM9000_DATA                     (CONFIG_DM9000_BASE+1)
    #endif
    #endif
     
     
    #define CFG_PHY_UBOOT_BASE      MEMORY_BASE_ADDRESS + 0x3e00000
    #define CFG_PHY_KERNEL_BASE     MEMORY_BASE_ADDRESS + 0x8000
     
    #define CONFIG_ETHADDR          00:40:5c:26:0a:5b
    #define CONFIG_NETMASK          255.255.255.0
    #define CONFIG_IPADDR           192.168.186.13
    #define CONFIG_SERVERIP         192.168.186.13
    #define CONFIG_GATEWAYIP        192.168.0.1
     
    #define CONFIG_CMD_DATE
     
    #define CONFIG_ENV_OVERWRITE
    #define CONFIG_OVERWRITE_ETHADDR_ONCE
     
     
    123行:
    #if 0
    #undef CONFIG_CMD_NET
    #undef CONFIG_CMD_NFS
    #endif

    红字部分与dm9000 相关的关键内容. 下面对关键部分作简要分析:

    dm9000挂载的位置通过下图可以得到,并确定dm9000工作在16bit 模式,需定义#define DM9000_16BIT_DATA
     
     
    nCS1是SROMC_BANK1的片选线,可见dm9000是挂在SROMC_BANK1区域的,再根据datasheet可以推算出,dm9000挂载的位置,参见下图:

    另外根据友善提供的linux-2.6.35 内核,参考其中dm9000的初始化配置,

    #define S5PV210_PA_DM9000_A     (0x88001000)
    #define S5PV210_PA_DM9000_F     (S5PV210_PA_DM9000_A + 0x300C)

    static struct resource dm9000_resources[] = {
     [0] = {
      .start = S5PV210_PA_DM9000_A,
      .end = S5PV210_PA_DM9000_A + SZ_1K*4 - 1,
      .flags = IORESOURCE_MEM,
     },
     [1] = {
      .start = S5PV210_PA_DM9000_F,
      .end = S5PV210_PA_DM9000_F + SZ_1K*4 - 1,
      .flags = IORESOURCE_MEM,
     },
     [2] = {
      .start = IRQ_EINT(7),
      .end = IRQ_EINT(7),
      .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
     },
    };

    可以分别得到

    #define CONFIG_DM9000_BASE              (0x88001000)
    #define DM9000_IO                       (CONFIG_DM9000_BASE)
    #define DM9000_DATA                     (CONFIG_DM9000_BASE+0x300C)

    2.修改common/cmd_date.c

    +32:#if !defined(CONFIG_S5PC100) && !defined(CONFIG_S5PC110) && !defined(CONFIG_S5P6442)
    +229:#endif
     
    3.修改 board/samsung/tiny210/tiny210.c 
     
    (1)添加#include <netdev.h>//有int board_eth_init(bd_t *bis)的函数声明
     
    (2)屏蔽掉下面smc9115_pre_init(); 函数的调用
    158:
    int board_init(void)
    {
    /* Set Initial global variables */
    s5pc110_gpio = (struct s5pc110_gpio *)S5PC110_GPIO_BASE;
     
    //smc9115_pre_init();
            pwm_pre_init();
     
    #ifdef CONFIG_DRIVER_DM9000
    dm9000_pre_init();
    #endif
     
    gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
    gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
     
    return 0;
    }

    (3)243:添加int board_eth_init(bd_t *bis)函数
     
    int board_eth_init(bd_t *bis)
    {
    int rc = 0;
    #ifdef CONFIG_DRIVER_DM9000
    rc = dm9000_initialize(bis);
    #endif
    return rc;
    }
    (4)修改 115: static void dm9000_pre_init(void) 函数,参考linux内核及datasheet,
     
     
     
     
     
    可作如下修改.
    static void dm9000_pre_init(void)
    {
    unsigned int tmp;
     
    #if defined(DM9000_16BIT_DATA)
    //SROM_BW_REG &= ~(0xf << 20);
    //SROM_BW_REG |= (0<<23) | (0<<22) | (0<<21) | (1<<20);
    SROM_BW_REG &= ~(0xf << 4);
    SROM_BW_REG |= (0x1 << 4);
     
    #else
    SROM_BW_REG &= ~(0xf << 20);
    SROM_BW_REG |= (0<<19) | (0<<18) | (0<<16);
    #endif
    SROM_BC1_REG = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0));
     
    tmp = MP01CON_REG;
    tmp &=~(0xf<<4);
    tmp |=(2<<4);
    MP01CON_REG = tmp;
    }

    3.修改driver/net/dm9000x.c
    551:
    static void dm9000_get_enetaddr(struct eth_device *dev)
    {
    #if !defined(CONFIG_DM9000_NO_SROM)
    int i;
    for (i = 0; i < 3; i++)
    dm9000_read_srom_word(i, dev->enetaddr + (2 * i));
    #else 
     
    if (!eth_getenv_enetaddr("ethaddr", mac_addr)) {
    printf("Please set ethaddr! ");
    }
    //memcpy(dev->enetaddr, "x08x90x90x90x90x90", 6);
     
    #endif
    }
    4.修改/net/eth.h
    308:
     if (!eth_write_hwaddr(dev, "eth", eth_number))
                                    puts("Warning: failed to set MAC address ");
     
     
    TAB键命令补全修改过程:
     
    在include/configs/tiny210.h 添加下述宏
     
    /*auto complete command*/
    #define CONFIG_CMDLINE_EDITING
    #define CONFIG_AUTO_COMPLETE    实现
    #define CONFIG_SYS_HUSH_PARSER
    可以参考我的另一篇blog uboot命令自动补全.
     
    至此version2 修改完成.
     
    编译u-boot
    $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/ 添加到环境变量,在使用工具链时要指明路径。

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

    执行下面的命令
    $sudo dd iflag=dsync oflag=dsync if=spl/tiny210-spl.bin of=/dev/sdb seek=1
    $sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb  seek=49
     
     
    将SD卡插入开发板启动:
    启动:
     
    测试ping:
     
    测试tftp:
     
     
     
    PS: 本来u-boot for tiny210 会更新的快些,可是开学以后发现周围的同学都在玩命复习,我也不淡定了,这学期主要精力会用在复习考研,每周只拿出一下午的时间完善tiny210的u-boot,Android恐怕没时间弄了.
     u-boot for tiny210 ver2.1(by liukun321咕唧咕唧)
     

    前两次修改的u-boot写SD卡的过程存在问题,虽然保存环境变量到SD能够成功,但是会有Writing to MMC(0)... mmc_send_cmd: error during transfer: 0x00208001 mmc write failed,这样的提示。而且每次启动只能够保存一次环境变量,若再次写SD卡会有failed提示并无法保存。这一次更新修复了这两个bug。

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

    下面的链接提供了前两次修改的源码

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

    你还可以参考下面两篇blog从头构建自己的u-boot for tiny210

    ver1.0   ver2.0

    ver2.1的基本功能:

    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:每次启动只能保存一次环境变量。

    ver2.1代码改动量非常小,一步就可完成,但是由于经验不足,我在bug的定位上花了很多时间.

    具体修改如下:

    drivers/mmc/s5p_mmc.c 屏蔽红字部分即可.
    231:if (data) {
                    while (1) {
                            mask = readl(&host->reg->norintsts);
                            //e_num++;
                    /*      if (mask & (1 << 15)) {
                                                                   writel(mask, &host->reg->norintsts);
                                    printf("%s: error during transfer: 0x%08x ",
                                                    __func__, mask);
                                    
                                                           return -1;
                                                                          } else*/  if (mask & (1 << 3)) {


     

    编译u-boot
    $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/ 添加到环境变量,在使用工具链时要指明路径。

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

    执行下面的命令
    $sudo dd iflag=dsync oflag=dsync if=spl/tiny210-spl.bin of=/dev/sdb seek=1
    $sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb  seek=49
     
     
    将SD卡插入开发板启动:

    测试saveenv:

     

    PS : 简单记录解决过程

    错误的打印出处的确不难找,printf("%s: error during transfer: 0x%08x ",   __func__, mask);即是.可是仔细看看被屏蔽部分代码是没什么问题的,

     if (mask & (1 << 15)) {

                                    writel(mask, &host->reg->norintsts);
                                    printf("%s: error during transfer: 0x%08x ",
                                                    __func__, mask);
                                    
                                                           return -1;
                                                                          }
    是对210 NORINTSTS寄存器的第15位进行判断是否为1,及是否存在error status.
    若error状态位为1,则返回,则会导致写失败,如果读SD卡,data= NULL 则if (data) 不满足,不会进入这个循环.
    分析起来这部分代码貌似也不是错误所在。于是把查找重点放在SD卡控制寄存器的配置,及读写流程上。分
    析了几个小时依然不能发现问题.
     
    0x00208001按照这个错误号,对照NORINTSTS寄存器表,可以发现这个提示是CRC校验报的.关CRC校验是
    万万不能的,于是试了一下强制不检测NORINTSTS寄存器的 第15bit.如果写过程真有错误,不通过
    if (mask & (1 << 15)) {
                                     writel(mask, &host->reg->norintsts);
                                    printf("%s: error during transfer: 0x%08x ",
                                                    __func__, mask);
                                    
                                                           return -1;
                                                                          }
     
    是不会退出循环的。于是屏蔽上面那段代码后,重新saveenv.提示:done问题解决了,但是感觉这中强制手段不
    是最安全的,我曾认为是延时不足导致的,于是作如下修改:
    if (mask & (1 << 15)) {
                                    int e_num;
                                    for(e_num = 0;e_num<100;e_num++)
                                    udelay(1000);
                                    mask = readl(&host->reg->norintsts);
                            if (mask & (1 << 15)) { 
                                    writel(mask, &host->reg->norintsts);
                                    printf("%s: error during transfer: 0x%08x ",
                                                    __func__, mask);
                                    
                            //printf("mask = %x,e_mum = %d ",mask,e_num);
                                    return -1;
                                                    }
                            }
    但是依然不能解决问题,没办法只好暂且屏蔽它.
    如果大家发现更好的解决方式,要留言啊.
     
     
     

    前三个版本都不支持nandflash的读写,这次更新(ver2.2)添加了nandflash驱动及yaffs文件系统的烧写功能。在kasim的建议下我从ver2.2开始用git源代码仓库管理我的源码。并发布上一版本的补丁文件。
    你可以点击下面的链接浏览u-boot for tiny210 ver2.2 源码:

    Git source u-boot for tiny210 ver2.2

    下面的提供了在CSDN资源库的下载链接:

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

    下面的提供了补丁包的下载链接:

    ver2.2补丁下载: u-boot-for-tiny210-patch-ver2.2

    下面的链接提供了前几次修改的源码:

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

    你还可以参考下三篇blog从头构建自己的u-boot for tiny210

    ver1.0   ver2.0   ver2.1 

    ver2.2的基本功能:

    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文件系统烧写支持。

    参照本文后面内容修改完后:

    编译u-boot
    $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/ 添加到环境变量,在使用工具链时要指明路径。

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

    执行下面的命令
    $sudo dd iflag=dsync oflag=dsync if=spl/tiny210-spl.bin of=/dev/sdb seek=1
    $sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb  seek=49
     
     
    将SD卡插入开发板启动:

    启动:

     

    部分NAND CMD测试:

     

     

    下面简要介绍ver2.2的修改步骤

    左边的数字为旧行号,右边的数字为新行号,大家可以对应行号阅读修改部分的源码,或自己从ver2.1修改至ver2.2

    1.tiny210-u-boot-version2.1/board/samsung/tiny210/Makefile 在此目录下修改Makefile

    (4 / 0)
           
      31 31  
      32 32 ifdef CONFIG_SPL_BUILD
      33 33 COBJS += mmc_boot.o
        34 #COBJS += nand.o
        35 #COBJS += nand_cp.o
      34 36 endif
        37 COBJS += nand.o
        38 COBJS += nand_cp.o
      35 39  
      36 40 SOBJS := lowlevel_init.o mem_setup.o
      37 41  
      17 int add_mtd_device(struct mtd_info *mtd)
    修改此目录下的nand.c  (4 / 1)
           
      64 64 * Add MTD device so that we can reference it later
      65 65 * via the mtdcore infrastructure (e.g. ubi).
      66 66 */
      67   sprintf(dev_name[i], "nand%d", i);
        67 #if CONFIG_NAND_NO_USE_CHIP_NAME
        68 sprintf(dev_name[i], "nand%d", i);
      68 69 mtd->name = dev_name[i++];
        70 #endif
      69 71 add_mtd_device(mtd);
        72  
      70 73 #endif
      71 74 } else
      72 75 mtd->name = NULL;
     
     
    修改此目录下的tiny210.h (33 /0)
           
      430 430 #define CONFIG_CMDLINE_EDITING
      431 431 #define CONFIG_AUTO_COMPLETE
      432 432 #define CONFIG_SYS_HUSH_PARSER
        433  
        434 /*****************************Modified by lk for nand driver*************/
        435 #define CONFIG_CMD_NAND
        436 #if defined(CONFIG_CMD_NAND)
        437 #define CONFIG_CMD_NAND_YAFFS
        438 #define CONFIG_CMD_MTDPARTS
        439 #define CONFIG_SYS_MAX_NAND_DEVICE 1
        440 #define CONFIG_SYS_NAND_BASE (0xB0E000000)
        441 #define NAND_MAX_CHIPS 1
        442  
        443 #define CONFIG_MTD_DEVICE /* needed for mtdparts commands add by lkmcu */
        444  
        445 #define NAND_DISABLE_CE() (NFCONT_REG |= (1 << 1))
        446 #define NAND_ENABLE_CE() (NFCONT_REG &= ~(1 << 1))
        447 #define NF_TRANSRnB() do { while(!(NFSTAT_REG & (1 << 0))); } while(0)
        448 #define CONFIG_CMD_NAND_YAFFS_SKIPFB
        449  
        450 #define CONFIG_NAND_USE_CHIP_NAME 1
        451  
        452 #if 0
        453  
        454 #define CONFIG_MTD_DEBUG
        455 #define CONFIG_MTD_DEBUG_VERBOSE
        456  
        457 #define CFG_NAND_SKIP_BAD_DOT_I 1
        458 #define CFG_NAND_HWECC
        459  
        460 #define CONFIG_NAND_BL1_8BIT_ECC
        461 #endif
        462 #undef CFG_NAND_FLASH_BBT
        463 #endif
        464  
        465  
      433 466 #endif /* __CONFIG_H */
     
     
    修改此目录下的mtd-abi.h(2 /0)
           
      126 126 uint32_t eccpos[128];
      127 127 uint32_t oobavail;
      128 128 struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
        129 uint32_t useecc;
        130 uint32_t reserved;
      129 131 };
      130 132  
      131 133 /**
     
    5.在tiny210-u-boot-version2.1/board/samsung/tiny210/ 目录下添加nand.c nand_cp.c(本版本未启用nand_cp.c文件)。nand.c文件内容如下:
    [csharp] view plaincopyprint?
     
    1. #include <common.h>  
    2.  
    3. #if defined(CONFIG_CMD_NAND)  
    4. #include <nand.h>  
    5. #include <bedbug/regs.h>  
    6. #include <s5pc110.h>  
    7.  
    8. #include <asm/io.h>  
    9. #include <asm/errno.h>  
    10.   
    11. /* Nand flash definition values by jsgood */  
    12. #define S3C_NAND_TYPE_UNKNOWN   0x0  
    13. #define S3C_NAND_TYPE_SLC   0x1  
    14. #define S3C_NAND_TYPE_MLC   0x2  
    15. #undef  S3C_NAND_DEBUG  
    16.   
    17. /* Nand flash global values by jsgood */  
    18. int cur_ecc_mode = 0;  
    19. int nand_type = S3C_NAND_TYPE_UNKNOWN;  
    20.   
    21. /* Nand flash oob definition for SLC 512b page size by jsgood */  
    22. static struct nand_ecclayout s3c_nand_oob_16 = {  
    23.     .useecc = MTD_NANDECC_AUTOPLACE,    /* Only for U-Boot */  
    24.     .eccbytes = 4,  
    25.     .eccpos = {1, 2, 3, 4},  
    26.     .oobfree = {  
    27.         {.offset = 6,  
    28.          . length = 10}}  
    29. };  
    30.   
    31. /* Nand flash oob definition for SLC 2k page size by jsgood */  
    32. static struct nand_ecclayout s3c_nand_oob_64 = {  
    33.     .useecc = MTD_NANDECC_AUTOPLACE,    /* Only for U-Boot */  
    34.     .eccbytes = 16,  
    35.     .eccpos = {40, 41, 42, 43, 44, 45, 46, 47,  
    36.            48, 49, 50, 51, 52, 53, 54, 55},  
    37.     .oobfree = {  
    38.         {.offset = 2,  
    39.          .length = 38}}  
    40. };  
    41.    
    42. /* Nand flash oob definition for MLC 2k page size by jsgood */  
    43. static struct nand_ecclayout s3c_nand_oob_mlc_64 = {  
    44.     .useecc = MTD_NANDECC_AUTOPLACE,    /* Only for U-Boot */  
    45.     .eccbytes = 32,  
    46.     .eccpos = {  
    47.            32, 33, 34, 35, 36, 37, 38, 39,  
    48.            40, 41, 42, 43, 44, 45, 46, 47,  
    49.            48, 49, 50, 51, 52, 53, 54, 55,  
    50.            56, 57, 58, 59, 60, 61, 62, 63},  
    51.     .oobfree = {  
    52.         {.offset = 2,  
    53.          .length = 28}}  
    54. };  
    55.   
    56. /* Nand flash oob definition for 4Kb page size with 8_bit ECC */  
    57. static struct nand_ecclayout s3c_nand_oob_128 = {  
    58.         .useecc = MTD_NANDECC_AUTOPLACE,  
    59.         .eccbytes = 104,  
    60.         .eccpos = {  
    61.                    24, 25, 26, 27, 28, 29, 30, 31,  
    62.                    32, 33, 34, 35, 36, 37, 38, 39,  
    63.                    40, 41, 42, 43, 44, 45, 46, 47,  
    64.                    48, 49, 50, 51, 52, 53, 54, 55,  
    65.                    56, 57, 58, 59, 60, 61, 62, 63,  
    66.                    64, 65, 66, 67, 68, 69, 70, 71,  
    67.                    72, 73, 74, 75, 76, 77, 78, 79,  
    68.                    80, 81, 82, 83, 84, 85, 86, 87,  
    69.                    88, 89, 90, 91, 92, 93, 94, 95,  
    70.                    96, 97, 98, 99, 100, 101, 102, 103,  
    71.                    104, 105, 106, 107, 108, 109, 110, 111,  
    72.                    112, 113, 114, 115, 116, 117, 118, 119,  
    73.                    120, 121, 122, 123, 124, 125, 126, 127},  
    74.         .oobfree = {  
    75.                 {.offset = 2,  
    76.                  .length = 22}}  
    77. };  
    78. #if defined(S3C_NAND_DEBUG)  
    79. /* 
    80.  * Function to print out oob buffer for debugging 
    81.  * Written by jsgood 
    82.  */  
    83. static void print_oob(const char *header, struct mtd_info *mtd)  
    84. {  
    85.     int i;  
    86.     struct nand_chip *chip = mtd->priv;  
    87.   
    88.     printk("%s: ", header);  
    89.   
    90.     for(i = 0; i < 64; i++)  
    91.         printk("%02x ", chip->oob_poi[i]);  
    92.   
    93.     printk(" ");  
    94. }  
    95. #endif  
    96.   
    97. /* 
    98.  * Hardware specific access to control-lines function 
    99.  * Written by jsgood 
    100.  */  
    101. static void s3c_nand_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)  
    102. {  
    103.     unsigned int cur;  
    104.  
    105. #if 1  
    106.     if (ctrl & NAND_CTRL_CHANGE) {  
    107.         if (ctrl & NAND_NCE) {  
    108.             if (dat != NAND_CMD_NONE) {  
    109.                 cur = readl(NFCONT);  
    110.                 /* Forced Enable CS */  
    111.                 cur &= ~NFCONT_CS;  
    112.   
    113.                 writel(cur, NFCONT);  
    114.             }  
    115.         } else {  
    116.             cur = readl(NFCONT);  
    117.             /* Forced Enable CS */  
    118.             cur |= NFCONT_CS;  
    119.   
    120.             writel(cur, NFCONT);  
    121.         }  
    122.     }  
    123.   
    124.     if (dat != NAND_CMD_NONE) {  
    125.         if (ctrl & NAND_CLE)  
    126.             writeb(dat, NFCMMD);  
    127.         else if (ctrl & NAND_ALE)  
    128.             writeb(dat, NFADDR);  
    129.     }  
    130. #endif  
    131. }  
    132.   
    133. /* 
    134.  * Function for checking device ready pin 
    135.  * Written by jsgood 
    136.  */  
    137. static int s3c_nand_device_ready(struct mtd_info *mtdinfo)  
    138. {  
    139.     while (!(readl(NFSTAT) & NFSTAT_RnB)) {}  
    140.     return 1;  
    141. }  
    142.   
    143. /* 
    144.  * We don't use bad block table 
    145.  */  
    146. static int s3c_nand_scan_bbt(struct mtd_info *mtdinfo)  
    147. {  
    148.     return nand_default_bbt(mtdinfo);  
    149. }  
    150.  
    151. #if defined(CFG_NAND_HWECC)  
    152.   
    153. /* 
    154.  * Function for checking ECCEncDone in NFSTAT 
    155.  * Written by jsgood 
    156.  */  
    157. static void s3c_nand_wait_enc(void)  
    158. {  
    159.     while (!(readl(NFECCSTAT) & NFSTAT_ECCENCDONE)) {}  
    160. }  
    161.   
    162. /* 
    163.  * Function for checking ECCDecDone in NFSTAT 
    164.  * Written by jsgood 
    165.  */  
    166. static void s3c_nand_wait_dec(void)  
    167. {  
    168.     while (!(readl(NFECCSTAT) & NFSTAT_ECCDECDONE)) {}  
    169. }  
    170.   
    171. /* 
    172.  * Function for checking ECC Busy 
    173.  * Written by jsgood 
    174.  */  
    175. static void s3c_nand_wait_ecc_busy(void)  
    176. {  
    177.     while (readl(NFECCSTAT) & NFESTAT0_ECCBUSY) {}  
    178. }  
    179.   
    180. /* 
    181.  * This function is called before encoding ecc codes to ready ecc engine. 
    182.  * Written by jsgood 
    183.  */  
    184. static void s3c_nand_enable_hwecc(struct mtd_info *mtd, int mode)  
    185. {  
    186.     u_long nfcont, nfconf;  
    187.   
    188.     cur_ecc_mode = mode;  
    189.   
    190.     nfconf = readl(NFCONF);  
    191.   
    192.     if (nand_type == S3C_NAND_TYPE_SLC)  
    193.         nfconf &= ~NFCONF_ECC_MLC;  /* SLC */  
    194.     else  
    195.         nfconf |= NFCONF_ECC_MLC;   /* MLC */  
    196.   
    197.     writel(nfconf, NFCONF);  
    198.     printf("NFCONF = %x ",nfconf);  
    199.     /* Initialize & unlock */  
    200.     nfcont = readl(NFCONT);  
    201.     nfcont |= NFCONT_INITMECC;  
    202.     nfcont &= ~NFCONT_MECCLOCK;  
    203.   
    204.     if (nand_type == S3C_NAND_TYPE_MLC) {  
    205.         if (mode == NAND_ECC_WRITE)  
    206.             nfcont |= NFCONT_ECC_ENC;  
    207.         else if (mode == NAND_ECC_READ)  
    208.             nfcont &= ~NFCONT_ECC_ENC;  
    209.     }  
    210.   
    211.     writel(nfcont, NFCONT);  
    212. }  
    213.   
    214. /* 
    215.  * This function is called immediately after encoding ecc codes. 
    216.  * This function returns encoded ecc codes. 
    217.  * Written by jsgood 
    218.  */  
    219. static int s3c_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)  
    220. {  
    221.     u_long nfcont, nfmecc0, nfmecc1;  
    222.   
    223.     /* Lock */  
    224.     nfcont = readl(NFCONT);  
    225.     nfcont |= NFCONT_MECCLOCK;  
    226.     writel(nfcont, NFCONT);  
    227.   
    228.     if (nand_type == S3C_NAND_TYPE_SLC) {  
    229.         nfmecc0 = readl(NFMECC0);  
    230.   
    231.         ecc_code[0] = nfmecc0 & 0xff;  
    232.         ecc_code[1] = (nfmecc0 >> 8) & 0xff;  
    233.         ecc_code[2] = (nfmecc0 >> 16) & 0xff;  
    234.         ecc_code[3] = (nfmecc0 >> 24) & 0xff;  
    235.     } else {  
    236.         if (cur_ecc_mode == NAND_ECC_READ)  
    237.             s3c_nand_wait_dec();  
    238.         else {  
    239.             s3c_nand_wait_enc();  
    240.   
    241.             nfmecc0 = readl(NFMECC0);  
    242.             nfmecc1 = readl(NFMECC1);  
    243.   
    244.             ecc_code[0] = nfmecc0 & 0xff;  
    245.             ecc_code[1] = (nfmecc0 >> 8) & 0xff;  
    246.             ecc_code[2] = (nfmecc0 >> 16) & 0xff;  
    247.             ecc_code[3] = (nfmecc0 >> 24) & 0xff;  
    248.             ecc_code[4] = nfmecc1 & 0xff;  
    249.             ecc_code[5] = (nfmecc1 >> 8) & 0xff;  
    250.             ecc_code[6] = (nfmecc1 >> 16) & 0xff;  
    251.             ecc_code[7] = (nfmecc1 >> 24) & 0xff;  
    252.         }  
    253.     }  
    254.   
    255.     return 0;  
    256. }  
    257.   
    258. /* 
    259.  * This function determines whether read data is good or not. 
    260.  * If SLC, must write ecc codes to controller before reading status bit. 
    261.  * If MLC, status bit is already set, so only reading is needed. 
    262.  * If status bit is good, return 0. 
    263.  * If correctable errors occured, do that. 
    264.  * If uncorrectable errors occured, return -1. 
    265.  * Written by jsgood 
    266.  */  
    267. static int s3c_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)  
    268. {  
    269.     int ret = -1;  
    270.     u_long nfestat0, nfestat1, nfmeccdata0, nfmeccdata1, nfmlcbitpt;  
    271.     u_char err_type;  
    272.   
    273.     if (nand_type == S3C_NAND_TYPE_SLC) {  
    274.         /* SLC: Write ecc to compare */  
    275.         nfmeccdata0 = (read_ecc[1] << 16) | read_ecc[0];  
    276.         nfmeccdata1 = (read_ecc[3] << 16) | read_ecc[2];  
    277.         writel(nfmeccdata0, NFMECCDATA0);  
    278.         writel(nfmeccdata1, NFMECCDATA1);  
    279.   
    280.         /* Read ecc status */  
    281.         nfestat0 = readl(NFESTAT0);  
    282.         err_type = nfestat0 & 0x3;  
    283.   
    284.         switch (err_type) {  
    285.         case 0: /* No error */  
    286.             ret = 0;  
    287.             break;  
    288.   
    289.         case 1: /* 1 bit error (Correctable) 
    290.                (nfestat0 >> 7) & 0x7ff    :error byte number 
    291.                (nfestat0 >> 4) & 0x7  :error bit number */  
    292.             printk("s3c-nand: 1 bit error detected at byte %ld, correcting from "  
    293.                     "0x%02x ", (nfestat0 >> 7) & 0x7ff, dat[(nfestat0 >> 7) & 0x7ff]);  
    294.             dat[(nfestat0 >> 7) & 0x7ff] ^= (1 << ((nfestat0 >> 4) & 0x7));  
    295.             printk("to 0x%02x...OK ", dat[(nfestat0 >> 7) & 0x7ff]);  
    296.             ret = 1;  
    297.             break;  
    298.   
    299.         case 2: /* Multiple error */  
    300.         case 3: /* ECC area error */  
    301.             printk("s3c-nand: ECC uncorrectable error detected ");  
    302.             ret = -1;  
    303.             break;  
    304.         }  
    305.     } else {  
    306.         /* MLC: */  
    307.         s3c_nand_wait_ecc_busy();  
    308.   
    309.         nfestat0 = readl(NFESTAT0);  
    310.         nfestat1 = readl(NFESTAT1);  
    311.         nfmlcbitpt = readl(NFMLCBITPT);  
    312.   
    313.         err_type = (nfestat0 >> 26) & 0x7;  
    314.   
    315.         /* No error, If free page (all 0xff) */  
    316.         if ((nfestat0 >> 29) & 0x1) {  
    317.             err_type = 0;  
    318.         } else {  
    319.             /* No error, If all 0xff from 17th byte in oob (in case of JFFS2 format) */  
    320.             if (dat) {  
    321.                 if (dat[17] == 0xff && dat[26] == 0xff && dat[35] == 0xff && dat[44] == 0xff && dat[54] == 0xff)  
    322.                     err_type = 0;  
    323.             }  
    324.         }  
    325.   
    326.         switch (err_type) {  
    327.         case 5: /* Uncorrectable */  
    328.             printk("s3c-nand: ECC uncorrectable error detected ");  
    329.             ret = -1;  
    330.             break;  
    331.   
    332.         case 4: /* 4 bit error (Correctable) */  
    333.             dat[(nfestat1 >> 16) & 0x3ff] ^= ((nfmlcbitpt >> 24) & 0xff);  
    334.   
    335.         case 3: /* 3 bit error (Correctable) */  
    336.             dat[nfestat1 & 0x3ff] ^= ((nfmlcbitpt >> 16) & 0xff);  
    337.   
    338.         case 2: /* 2 bit error (Correctable) */  
    339.             dat[(nfestat0 >> 16) & 0x3ff] ^= ((nfmlcbitpt >> 8) & 0xff);  
    340.   
    341.         case 1: /* 1 bit error (Correctable) */  
    342.             printk("s3c-nand: %d bit(s) error detected, corrected successfully ", err_type);  
    343.             dat[nfestat0 & 0x3ff] ^= (nfmlcbitpt & 0xff);  
    344.             ret = err_type;  
    345.             break;  
    346.   
    347.         case 0: /* No error */  
    348.             ret = 0;  
    349.             break;  
    350.         }  
    351.     }  
    352.   
    353.     return ret;  
    354. }  
    355.  
    356. #if defined(CONFIG_NAND_BL1_8BIT_ECC) && defined(CONFIG_S5PC110)  
    357. /*************************************************************** 
    358.  * jsgood: Temporary 8 Bit H/W ECC supports for BL1 (6410/6430 only) 
    359.  ***************************************************************/  
    360. static void s3c_nand_wait_ecc_busy_8bit(void)  
    361. {  
    362.     while (readl(NFECCSTAT) & NFESTAT0_ECCBUSY) {  
    363.     }  
    364. }  
    365.   
    366. void s3c_nand_enable_hwecc_8bit(struct mtd_info *mtd, int mode)  
    367. {  
    368.     u_long nfreg;  
    369.       
    370.     cur_ecc_mode = mode;  
    371.   
    372.     if(cur_ecc_mode == NAND_ECC_WRITE){  
    373.   
    374.     /* 8 bit selection */  
    375.     nfreg = readl(NFCONF);  
    376.     nfreg &= ~(0x3 << 23);  
    377.     nfreg |= (0x3<< 23);  
    378.     writel(nfreg, NFCONF);  
    379.       
    380.     /* Set ECC type */  
    381.     nfreg = readl(NFECCCONF);  
    382.     nfreg &= 0xf;  
    383.     nfreg |= 0x3;  
    384.     writel(nfreg, NFECCCONF);  
    385.   
    386.     /* set 8/12/16bit Ecc direction to Encoding */  
    387.     nfreg = readl(NFECCCONT);  
    388.     nfreg &= ~(0x1 << 16);  
    389.     nfreg |= (0x1 << 16);  
    390.     writel(nfreg, NFECCCONT);  
    391.   
    392.     /* set 8/12/16bit ECC message length  to msg */  
    393.     nfreg = readl(NFECCCONF);  
    394.     nfreg &= ~((0x3ff<<16));  
    395.     nfreg |= (0x1ff << 16);  
    396.     writel(nfreg, NFECCCONF);  
    397.   
    398.     /* write '1' to clear this bit. */  
    399.     /* clear illegal access status bit */  
    400.     nfreg = readl(NFSTAT);  
    401.     nfreg |= (0x1 << 4);  
    402.     nfreg |= (0x1 << 5);  
    403.     writel(nfreg, NFSTAT);  
    404.   
    405.     /* clear 8/12/16bit ecc encode done */  
    406.     nfreg = readl(NFECCSTAT);  
    407.     nfreg |= (0x1 << 25);  
    408.     writel(nfreg, NFECCSTAT);  
    409.   
    410.     nfreg = readl(NFCONT);  
    411.     nfreg &= ~(0x1 << 1);  
    412.     writel(nfreg, NFCONT);  
    413.       
    414.     /* Initialize & unlock */  
    415.     nfreg = readl(NFCONT);  
    416.     nfreg &= ~NFCONT_MECCLOCK;  
    417.     nfreg |= NFCONT_INITECC;      
    418.     writel(nfreg, NFCONT);  
    419.   
    420.     /* Reset ECC value. */  
    421.     nfreg = readl(NFECCCONT);  
    422.     nfreg |= (0x1 << 2);  
    423.     writel(nfreg, NFECCCONT);  
    424.       
    425.     }else{  
    426.   
    427.     /* set 8/12/16bit ECC message length  to msg */  
    428.     nfreg = readl(NFECCCONF);  
    429.     nfreg &= ~((0x3ff<<16));  
    430.     nfreg |= (0x1ff << 16);  
    431.     writel(nfreg, NFECCCONF);  
    432.       
    433.     /* set 8/12/16bit Ecc direction to Decoding */  
    434.     nfreg = readl(NFECCCONT);  
    435.     nfreg &= ~(0x1 << 16);  
    436.     writel(nfreg, NFECCCONT);  
    437.       
    438.     /* write '1' to clear this bit. */  
    439.     /* clear illegal access status bit */  
    440.     nfreg = readl(NFSTAT);  
    441.     nfreg |= (0x1 << 4);  
    442.     nfreg |= (0x1 << 5);  
    443.     writel(nfreg, NFSTAT);  
    444.   
    445.     /* Lock */  
    446.     nfreg = readl(NFCONT);  
    447.     nfreg |= NFCONT_MECCLOCK;  
    448.     writel(nfreg, NFCONT);  
    449.   
    450.     nfreg = readl(NFCONT);  
    451.     nfreg &= ~(0x1 << 1);  
    452.     writel(nfreg, NFCONT);  
    453.   
    454.     /* clear 8/12/16bit ecc decode done */  
    455.     nfreg = readl(NFECCSTAT);  
    456.     nfreg |= (0x1 << 24);  
    457.     writel(nfreg, NFECCSTAT);  
    458.       
    459.     /* Initialize & lock */  
    460.     nfreg = readl(NFCONT);  
    461.     nfreg &= ~NFCONT_MECCLOCK;  
    462.     nfreg |= NFCONT_MECCLOCK;  
    463.     writel(nfreg, NFCONT);  
    464.   
    465.     /* write '1' to clear this bit. */  
    466.     nfreg = readl(NFSTAT);  
    467.     nfreg &= ~(1<<4);  
    468.     nfreg |= (1<<4);  
    469.     writel(nfreg, NFSTAT);  
    470.   
    471.     while(!(nfreg &(1<<4))){  
    472.         nfreg = readl(NFSTAT);  
    473.         }  
    474.   
    475.     /* write '1' to clear this bit. */  
    476.     nfreg = readl(NFSTAT);  
    477.     nfreg &= ~(1<<4);  
    478.     nfreg |= (1<<4);  
    479.     writel(nfreg, NFSTAT);  
    480.       
    481.     /* Initialize & unlock */  
    482.     nfreg = readl(NFCONT);  
    483.     nfreg &= ~NFCONT_MECCLOCK;  
    484.     nfreg |= NFCONT_INITECC;      
    485.     writel(nfreg, NFCONT);  
    486.   
    487.     /* Reset ECC value. */  
    488.     nfreg = readl(NFECCCONT);  
    489.     nfreg |= (0x1 << 2);  
    490.     writel(nfreg, NFECCCONT);  
    491.     }  
    492.   
    493. }  
    494.   
    495. int s3c_nand_calculate_ecc_8bit(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)  
    496. {  
    497.     u_long nfcont, nfeccprgecc0, nfeccprgecc1, nfeccprgecc2, nfeccprgecc3;  
    498.   
    499.     if (cur_ecc_mode == NAND_ECC_READ) {  
    500.         /* Lock */  
    501.         nfcont = readl(NFCONT);  
    502.         nfcont |= NFCONT_MECCLOCK;  
    503.         writel(nfcont, NFCONT);  
    504.           
    505.         s3c_nand_wait_dec();  
    506.   
    507.         /* clear 8/12/16bit ecc decode done */  
    508.         nfcont = readl(NFECCSTAT);  
    509.         nfcont |= (1<<24);  
    510.         writel(nfcont, NFECCSTAT);  
    511.   
    512.         s3c_nand_wait_ecc_busy_8bit();  
    513.   
    514.         if(readl(NFSTAT)&(1<<5))  
    515.         {  
    516.             /* clear illegal access status bit */  
    517.             nfcont = readl(NFSTAT);  
    518.             nfcont |= (1<<5);  
    519.             writel(nfcont, NFSTAT);  
    520.   
    521.             printf("  Accessed locked area!!  ");  
    522.               
    523.             nfcont = readl(NFCONT);  
    524.             nfcont |= (1<<1);  
    525.             writel(nfcont, NFCONT);  
    526.               
    527.             return -1;  
    528.         }  
    529.           
    530.         nfcont = readl(NFCONT);  
    531.         nfcont |= (1<<1);  
    532.         writel(nfcont, NFCONT);  
    533.   
    534.           
    535.     } else {  
    536.         /* Lock */  
    537.         nfcont = readl(NFCONT);  
    538.         nfcont |= NFCONT_MECCLOCK;  
    539.         writel(nfcont, NFCONT);  
    540.           
    541.         s3c_nand_wait_enc();  
    542.   
    543.         /* clear 8/12/16bit ecc encode done */  
    544.         nfcont = readl(NFECCSTAT);  
    545.         nfcont |= (1<<25);  
    546.         writel(nfcont, NFECCSTAT);  
    547.   
    548.         nfeccprgecc0 = readl(NFECCPRGECC0);  
    549.         nfeccprgecc1 = readl(NFECCPRGECC1);  
    550.         nfeccprgecc2 = readl(NFECCPRGECC2);  
    551.         nfeccprgecc3 = readl(NFECCPRGECC3);  
    552.       
    553.         ecc_code[0] = nfeccprgecc0 & 0xff;  
    554.         ecc_code[1] = (nfeccprgecc0 >> 8) & 0xff;  
    555.         ecc_code[2] = (nfeccprgecc0 >> 16) & 0xff;  
    556.         ecc_code[3] = (nfeccprgecc0 >> 24) & 0xff;  
    557.         ecc_code[4] = nfeccprgecc1 & 0xff;  
    558.         ecc_code[5] = (nfeccprgecc1 >> 8) & 0xff;  
    559.         ecc_code[6] = (nfeccprgecc1 >> 16) & 0xff;  
    560.         ecc_code[7] = (nfeccprgecc1 >> 24) & 0xff;  
    561.         ecc_code[8] = nfeccprgecc2 & 0xff;  
    562.         ecc_code[9] = (nfeccprgecc2 >> 8) & 0xff;  
    563.         ecc_code[10] = (nfeccprgecc2 >> 16) & 0xff;  
    564.         ecc_code[11] = (nfeccprgecc2 >> 24) & 0xff;  
    565.         ecc_code[12] = nfeccprgecc3 & 0xff;  
    566.   
    567.           
    568.   
    569.     }  
    570.   
    571.     return 0;  
    572. }  
    573.   
    574. int s3c_nand_correct_data_8bit(struct mtd_info *mtd, u_char *dat)  
    575. {  
    576.     int ret = -1;  
    577.     u_long nf8eccerr0, nf8eccerr1, nf8eccerr2, nf8eccerr3, nf8eccerr4, nfmlc8bitpt0, nfmlc8bitpt1;  
    578.     u_char err_type;  
    579.   
    580.     s3c_nand_wait_ecc_busy_8bit();  
    581.   
    582.     nf8eccerr0 = readl(NFECCSECSTAT);  
    583.     nf8eccerr1 = readl(NFECCERL0);  
    584.     nf8eccerr2 = readl(NFECCERL1);  
    585.     nf8eccerr3 = readl(NFECCERL2);  
    586.     nf8eccerr4 = readl(NFECCERL3);  
    587.     nfmlc8bitpt0 = readl(NFECCERP0);  
    588.     nfmlc8bitpt1 = readl(NFECCERP1);  
    589.   
    590.     err_type = (nf8eccerr0) & 0xf;  
    591.   
    592.     /* No error, If free page (all 0xff) */  
    593.     if ((nf8eccerr0 >> 29) & 0x1)  
    594.         err_type = 0;  
    595.   
    596.     switch (err_type) {  
    597.     case 9: /* Uncorrectable */  
    598.         printk("s3c-nand: ECC uncorrectable error detected ");  
    599.         ret = -1;  
    600.         break;  
    601.   
    602.     case 8: /* 8 bit error (Correctable) */  
    603.         dat[(nf8eccerr4 >> 16) & 0x3ff] ^= ((nfmlc8bitpt1 >> 24) & 0xff);  
    604.   
    605.     case 7: /* 7 bit error (Correctable) */  
    606.         dat[(nf8eccerr4) & 0x3ff] ^= ((nfmlc8bitpt1 >> 16) & 0xff);  
    607.   
    608.     case 6: /* 6 bit error (Correctable) */  
    609.         dat[(nf8eccerr3 >> 16) & 0x3ff] ^= ((nfmlc8bitpt1 >> 8) & 0xff);  
    610.   
    611.     case 5: /* 5 bit error (Correctable) */  
    612.         dat[(nf8eccerr3) & 0x3ff] ^= ((nfmlc8bitpt1) & 0xff);  
    613.   
    614.     case 4: /* 8 bit error (Correctable) */  
    615.         dat[(nf8eccerr2 >> 16) & 0x3ff] ^= ((nfmlc8bitpt0 >> 24) & 0xff);  
    616.   
    617.     case 3: /* 7 bit error (Correctable) */  
    618.         dat[(nf8eccerr2) & 0x3ff] ^= ((nfmlc8bitpt0>> 16) & 0xff);  
    619.   
    620.     case 2: /* 6 bit error (Correctable) */  
    621.         dat[(nf8eccerr1 >> 16) & 0x3ff] ^= ((nfmlc8bitpt0>> 8) & 0xff);  
    622.   
    623.     case 1: /* 1 bit error (Correctable) */  
    624.         printk("s3c-nand: %d bit(s) error detected, corrected successfully ", err_type);  
    625.         dat[(nf8eccerr1) & 0x3ff] ^= ((nfmlc8bitpt0) & 0xff);  
    626.         ret = err_type;  
    627.         break;  
    628.   
    629.     case 0: /* No error */  
    630.         ret = 0;  
    631.         break;  
    632.     }  
    633.   
    634.     return ret;  
    635. }  
    636.   
    637. void s3c_nand_write_page_8bit(struct mtd_info *mtd, struct nand_chip *chip,  
    638.                   const uint8_t *buf)  
    639. {     
    640.     u_long nfreg;  
    641.     int i, eccsize = 512;  
    642.     int eccbytes = 13;  
    643.     int eccsteps = mtd->writesize / eccsize;  
    644.     int badoffs = mtd->writesize == 512 ? NAND_SMALL_BADBLOCK_POS : NAND_LARGE_BADBLOCK_POS;  
    645.   
    646.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    647.     uint8_t *p = buf;  
    648.       
    649.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    650.         s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_WRITE);  
    651.         chip->write_buf(mtd, p, eccsize);  
    652.         s3c_nand_calculate_ecc_8bit(mtd, p, &ecc_calc[i]);  
    653.     }  
    654.   
    655.     chip->oob_poi[badoffs] = 0xff;  
    656.     for (i = 0; i <= eccbytes * (mtd->writesize / eccsize); i++) {  
    657. #if defined(CONFIG_EVT1)  
    658.         chip->oob_poi[i+12] = ecc_calc[i];  
    659. #else  
    660.         chip->oob_poi[i] = ecc_calc[i];  
    661. #endif  
    662.     }  
    663.   
    664.     chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);  
    665. }  
    666.   
    667. int s3c_nand_read_page_8bit(struct mtd_info *mtd, struct nand_chip *chip,  
    668.                 uint8_t *buf)  
    669. {  
    670.     u_long nfreg;  
    671.     int i, stat, eccsize = 512;  
    672.     int eccbytes = 13;  
    673.     int eccsteps = mtd->writesize / eccsize;  
    674.     int col = 0;  
    675.     uint8_t *p = buf;  
    676.       
    677.     /* Step1: read whole oob */  
    678.     col = mtd->writesize;  
    679. #if defined(CONFIG_EVT1)  
    680.     chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col+12, -1);  
    681. #else  
    682.     chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    683. #endif  
    684.     chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  
    685.   
    686.     col = 0;  
    687.   
    688.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    689.   
    690.         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    691.         s3c_nand_enable_hwecc_8bit(mtd, NAND_ECC_READ);  
    692.         chip->read_buf(mtd, p, eccsize);  
    693.         chip->write_buf(mtd, chip->oob_poi + (((mtd->writesize / eccsize) - eccsteps) * eccbytes), eccbytes);  
    694.         s3c_nand_calculate_ecc_8bit(mtd, 0, 0);  
    695.         stat = s3c_nand_correct_data_8bit(mtd, p);  
    696.   
    697.         if (stat == -1)  
    698.             mtd->ecc_stats.failed++;  
    699.   
    700.         col = eccsize * ((mtd->writesize / eccsize) + 1 - eccsteps);  
    701.     }  
    702.   
    703.     return 0;  
    704. }  
    705.   
    706. int s3c_nand_read_oob_8bit(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd)  
    707. {  
    708.         int eccbytes = chip->ecc.bytes;  
    709.         int secc_start = mtd->oobsize - eccbytes;  
    710.   
    711.         if (sndcmd) {  
    712.                 chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);  
    713.                 sndcmd = 0;  
    714.         }  
    715.   
    716.         chip->read_buf(mtd, chip->oob_poi, 0); //secc_start);  
    717.         return sndcmd;  
    718. }  
    719.   
    720. int s3c_nand_write_oob_8bit(struct mtd_info *mtd, struct nand_chip *chip, int page)  
    721. {  
    722.         int status = 0;  
    723.         int eccbytes = chip->ecc.bytes;  
    724.         int secc_start = mtd->oobsize - eccbytes;  
    725.   
    726.         chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);  
    727.   
    728.         /* spare area */  
    729.         chip->write_buf(mtd, chip->oob_poi, 0); //secc_start);  
    730.   
    731.         /* Send command to program the OOB data */  
    732.         chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);  
    733.         status = chip->waitfunc(mtd, chip);  
    734.         return status & NAND_STATUS_FAIL ? -EIO : 0;  
    735. }  
    736.   
    737. /********************************************************/  
    738. #endif  
    739.   
    740. static int s3c_nand_write_oob_1bit(struct mtd_info *mtd, struct nand_chip *chip,  
    741.                   int page)  
    742. {  
    743.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    744.     int status = 0;  
    745.     int eccbytes = chip->ecc.bytes;  
    746.     int secc_start = mtd->oobsize - eccbytes;  
    747.     int i;  
    748.   
    749.     chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);  
    750.   
    751.     /* spare area */  
    752.     chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
    753.     chip->write_buf(mtd, chip->oob_poi, secc_start);  
    754.     chip->ecc.calculate(mtd, 0, &ecc_calc[chip->ecc.total]);  
    755.   
    756.     for (i = 0; i < eccbytes; i++)  
    757.         chip->oob_poi[secc_start + i] = ecc_calc[chip->ecc.total + i];  
    758.   
    759.     chip->write_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
    760.   
    761.     /* Send command to program the OOB data */  
    762.     chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);  
    763.   
    764.     status = chip->waitfunc(mtd, chip);  
    765.   
    766.     return status & NAND_STATUS_FAIL ? -EIO : 0;  
    767. }  
    768.   
    769. static int s3c_nand_read_oob_1bit(struct mtd_info *mtd, struct nand_chip *chip,  
    770.                  int page, int sndcmd)  
    771. {  
    772.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    773.     int eccbytes = chip->ecc.bytes;  
    774.     int secc_start = mtd->oobsize - eccbytes;  
    775.   
    776.     if (sndcmd) {  
    777.         chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);  
    778.         sndcmd = 0;  
    779.     }  
    780.   
    781.     chip->ecc.hwctl(mtd, NAND_ECC_READ);  
    782.     chip->read_buf(mtd, chip->oob_poi, secc_start);  
    783.     chip->ecc.calculate(mtd, 0, &ecc_calc[chip->ecc.total]);  
    784.     chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
    785.   
    786.     /* jffs2 special case */  
    787.     if (!(chip->oob_poi[2] == 0x85 && chip->oob_poi[3] == 0x19))  
    788.         chip->ecc.correct(mtd, chip->oob_poi, chip->oob_poi + secc_start, 0);  
    789.   
    790.     return sndcmd;  
    791. }  
    792.   
    793. static void s3c_nand_write_page_1bit(struct mtd_info *mtd, struct nand_chip *chip,  
    794.                   const uint8_t *buf)  
    795. {  
    796.     int i, eccsize = chip->ecc.size;  
    797.     int eccbytes = chip->ecc.bytes;  
    798.     int eccsteps = chip->ecc.steps;  
    799.     int secc_start = mtd->oobsize - eccbytes;  
    800.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    801.     const uint8_t *p = buf;  
    802.   
    803.     uint32_t *eccpos = chip->ecc.layout->eccpos;  
    804.   
    805.     /* main area */  
    806.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    807.         chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
    808.         chip->write_buf(mtd, p, eccsize);  
    809.         chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
    810.     }  
    811.   
    812.     for (i = 0; i < chip->ecc.total; i++)  
    813.         chip->oob_poi[eccpos[i]] = ecc_calc[i];  
    814.   
    815.     /* spare area */  
    816.     chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
    817.     chip->write_buf(mtd, chip->oob_poi, secc_start);  
    818.     chip->ecc.calculate(mtd, p, &ecc_calc[chip->ecc.total]);  
    819.   
    820.     for (i = 0; i < eccbytes; i++)  
    821.         chip->oob_poi[secc_start + i] = ecc_calc[chip->ecc.total + i];  
    822.   
    823.     chip->write_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
    824. }  
    825.   
    826. static int s3c_nand_read_page_1bit(struct mtd_info *mtd, struct nand_chip *chip,  
    827.                 uint8_t *buf)  
    828. {  
    829.     int i, stat, eccsize = chip->ecc.size;  
    830.     int eccbytes = chip->ecc.bytes;  
    831.     int eccsteps = chip->ecc.steps;  
    832.     int secc_start = mtd->oobsize - eccbytes;  
    833.     int col = 0;  
    834.     uint8_t *p = buf;  
    835.     uint32_t *mecc_pos = chip->ecc.layout->eccpos;  
    836.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    837.   
    838.     col = mtd->writesize;  
    839.     chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    840.   
    841.     /* spare area */  
    842.     chip->ecc.hwctl(mtd, NAND_ECC_READ);  
    843.     chip->read_buf(mtd, chip->oob_poi, secc_start);  
    844.     chip->ecc.calculate(mtd, p, &ecc_calc[chip->ecc.total]);  
    845.     chip->read_buf(mtd, chip->oob_poi + secc_start, eccbytes);  
    846.   
    847.     /* jffs2 special case */  
    848.     if (!(chip->oob_poi[2] == 0x85 && chip->oob_poi[3] == 0x19))  
    849.         chip->ecc.correct(mtd, chip->oob_poi, chip->oob_poi + secc_start, 0);  
    850.   
    851.     col = 0;  
    852.   
    853.     /* main area */  
    854.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    855.         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    856.         chip->ecc.hwctl(mtd, NAND_ECC_READ);  
    857.         chip->read_buf(mtd, p, eccsize);  
    858.         chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
    859.   
    860.         stat = chip->ecc.correct(mtd, p, chip->oob_poi + mecc_pos[0] + ((chip->ecc.steps - eccsteps) * eccbytes), 0);  
    861.         if (stat == -1)  
    862.             mtd->ecc_stats.failed++;  
    863.   
    864.         col = eccsize * (chip->ecc.steps + 1 - eccsteps);  
    865.     }  
    866.   
    867.     return 0;  
    868. }  
    869.   
    870. /* 
    871.  * Hardware specific page read function for MLC. 
    872.  * Written by jsgood 
    873.  */  
    874. static int s3c_nand_read_page_4bit(struct mtd_info *mtd, struct nand_chip *chip,  
    875.                 uint8_t *buf)  
    876. {  
    877.     int i, stat, eccsize = chip->ecc.size;  
    878.     int eccbytes = chip->ecc.bytes;  
    879.     int eccsteps = chip->ecc.steps;  
    880.     int col = 0;  
    881.     uint8_t *p = buf;  
    882.     uint32_t *mecc_pos = chip->ecc.layout->eccpos;  
    883.   
    884.     /* Step1: read whole oob */  
    885.     col = mtd->writesize;  
    886.     chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    887.     chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);  
    888.   
    889.     col = 0;  
    890.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    891.         chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);  
    892.         chip->ecc.hwctl(mtd, NAND_ECC_READ);  
    893.         chip->read_buf(mtd, p, eccsize);  
    894.         chip->write_buf(mtd, chip->oob_poi + mecc_pos[0] + ((chip->ecc.steps - eccsteps) * eccbytes), eccbytes);  
    895.         chip->ecc.calculate(mtd, 0, 0);  
    896.         stat = chip->ecc.correct(mtd, p, 0, 0);  
    897.   
    898.         if (stat == -1)  
    899.             mtd->ecc_stats.failed++;  
    900.   
    901.         col = eccsize * (chip->ecc.steps + 1 - eccsteps);  
    902.     }  
    903.   
    904.     return 0;  
    905. }  
    906.   
    907. /* 
    908.  * Hardware specific page write function for MLC. 
    909.  * Written by jsgood 
    910.  */  
    911. static void s3c_nand_write_page_4bit(struct mtd_info *mtd, struct nand_chip *chip,  
    912.                   const uint8_t *buf)  
    913. {  
    914.     int i, eccsize = chip->ecc.size;  
    915.     int eccbytes = chip->ecc.bytes;  
    916.     int eccsteps = chip->ecc.steps;  
    917.     const uint8_t *p = buf;  
    918.     uint8_t *ecc_calc = chip->buffers->ecccalc;  
    919.     uint32_t *mecc_pos = chip->ecc.layout->eccpos;  
    920.   
    921.     /* Step1: write main data and encode mecc */  
    922.     for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  
    923.         chip->ecc.hwctl(mtd, NAND_ECC_WRITE);  
    924.         chip->write_buf(mtd, p, eccsize);  
    925.         chip->ecc.calculate(mtd, p, &ecc_calc[i]);  
    926.     }  
    927.   
    928.     /* Step2: save encoded mecc */  
    929.     for (i = 0; i < chip->ecc.total; i++)  
    930.         chip->oob_poi[mecc_pos[i]] = ecc_calc[i];  
    931.   
    932.     chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);  
    933. }  
    934. #endif  
    935.   
    936. /* 
    937.  * Board-specific NAND initialization. The following members of the 
    938.  * argument are board-specific (per include/linux/mtd/nand.h): 
    939.  * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device 
    940.  * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device 
    941.  * - hwcontrol: hardwarespecific function for accesing control-lines 
    942.  * - dev_ready: hardwarespecific function for  accesing device ready/busy line 
    943.  * - enable_hwecc?: function to enable (reset)  hardware ecc generator. Must 
    944.  *   only be provided if a hardware ECC is available 
    945.  * - eccmode: mode of ecc, see defines 
    946.  * - chip_delay: chip dependent delay for transfering data from array to 
    947.  *   read regs (tR) 
    948.  * - options: various chip options. They can partly be set to inform 
    949.  *   nand_scan about special functionality. See the defines for further 
    950.  *   explanation 
    951.  * Members with a "?" were not set in the merged testing-NAND branch, 
    952.  * so they are not set here either. 
    953.  */  
    954. int board_nand_init(struct nand_chip *nand)  
    955. {   unsigned int  cur;  
    956. #if defined(CFG_NAND_HWECC)  
    957.     int i;  
    958.     u_char tmp;  
    959.     struct nand_flash_dev *type = NULL;  
    960. #endif  
    961.     /*Modified by lk*/  
    962.         cur = MP01CON_REG;  
    963.     cur = (0x3<<12)|(0x3<<8)|(cur&(~(0xff<<8)));  
    964.       
    965.     MP01CON_REG = cur;   
    966.     cur = MP03CON_REG;  
    967.     cur = (cur&(~(0xfff<<0)));  
    968.     cur = (cur&(~(0xf<<16)));  
    969.     cur |= (0x2<<16)|(0x2<<8)|(0x2<<4)|(0x2<<0);  
    970.     MP03CON_REG = cur;   
    971.       
    972.     NFCONF_REG |= (7<<12)|(7<<8)|(7<<4)|(2<<23)|(1<<1);//NFCONF_VAL;  
    973.     NFCONT_REG |= (3<<4)|(1<<0);//NFCONT_VAL;  
    974.       
    975.   
    976.     NFCONT_REG              &= ~((0x1<<16)|(0x1<<6)|(0x1<<7));  
    977.     /*Modified by lk*/    
    978.   
    979.     nand->IO_ADDR_R      = (void __iomem *)(NFDATA);  
    980.     nand->IO_ADDR_W      = (void __iomem *)(NFDATA);  
    981.     nand->cmd_ctrl       = s3c_nand_hwcontrol;  
    982.     nand->dev_ready      = s3c_nand_device_ready;  
    983.     nand->scan_bbt       = s3c_nand_scan_bbt;  
    984.     nand->options        = 0;  
    985.  
    986. #if defined(CFG_NAND_FLASH_BBT)  
    987.         nand->options        |= NAND_USE_FLASH_BBT;  
    988. #else  
    989.         nand->options        |= NAND_SKIP_BBTSCAN;  
    990. #endif  
    991.  
    992. #if defined(CFG_NAND_HWECC)  
    993.     nand->ecc.mode       = NAND_ECC_HW;  
    994.     nand->ecc.hwctl      = s3c_nand_enable_hwecc;  
    995.     nand->ecc.calculate  = s3c_nand_calculate_ecc;  
    996.     nand->ecc.correct    = s3c_nand_correct_data;  
    997.   
    998.     s3c_nand_hwcontrol(0, NAND_CMD_READID, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);  
    999.     s3c_nand_hwcontrol(0, 0x00, NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE);  
    1000.     s3c_nand_hwcontrol(0, 0x00, NAND_NCE | NAND_ALE);  
    1001.     s3c_nand_hwcontrol(0, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);  
    1002.     s3c_nand_device_ready(0);  
    1003.   
    1004.     tmp = readb(nand->IO_ADDR_R); /* Maf. ID */  
    1005.     tmp = readb(nand->IO_ADDR_R); /* Device ID */  
    1006.   
    1007.     for (i = 0; nand_flash_ids[i].name != NULL; i++) {  
    1008.         if (tmp == nand_flash_ids[i].id) {  
    1009.             type = &nand_flash_ids[i];  
    1010.             break;  
    1011.         }  
    1012.     }  
    1013.     printf("id = %x ",nand_flash_ids[i].id);  
    1014.   
    1015.     nand->cellinfo = readb(nand->IO_ADDR_R);  /* 3rd byte */  
    1016.     tmp = readb(nand->IO_ADDR_R);            /* 4th byte */  
    1017.   
    1018.     if (!type->pagesize) {  
    1019.         if (((nand->cellinfo >> 2) & 0x3) == 0) {  
    1020.             nand_type = S3C_NAND_TYPE_SLC;  
    1021.             nand->ecc.size = 512;  
    1022.             nand->ecc.bytes  = 4;  
    1023.   
    1024.             if ((1024 << (tmp & 0x3)) > 512) {  
    1025.                 nand->ecc.read_page = s3c_nand_read_page_1bit;  
    1026.                 nand->ecc.write_page = s3c_nand_write_page_1bit;  
    1027.                 nand->ecc.read_oob = s3c_nand_read_oob_1bit;  
    1028.                 nand->ecc.write_oob = s3c_nand_write_oob_1bit;  
    1029.                 nand->ecc.layout = &s3c_nand_oob_64;  
    1030.                 nand->ecc.hwctl = s3c_nand_enable_hwecc;  
    1031.                                 nand->ecc.calculate = s3c_nand_calculate_ecc;  
    1032.                                 nand->ecc.correct = s3c_nand_correct_data;  
    1033.                                 nand->options |= NAND_NO_SUBPAGE_WRITE;  
    1034.             } else {  
    1035.                 nand->ecc.layout = &s3c_nand_oob_16;  
    1036.             }  
    1037.         } else {  
    1038.             nand_type = S3C_NAND_TYPE_MLC;  
    1039.             nand->options |= NAND_NO_SUBPAGE_WRITE;  /* NOP = 1 if MLC */  
    1040.             nand->ecc.read_page = s3c_nand_read_page_4bit;  
    1041.             nand->ecc.write_page = s3c_nand_write_page_4bit;  
    1042.             nand->ecc.size = 512;  
    1043.             nand->ecc.bytes = 8; /* really 7 bytes */  
    1044.             nand->ecc.layout = &s3c_nand_oob_mlc_64;  
    1045.         }  
    1046.     } else {  
    1047.         nand_type = S3C_NAND_TYPE_SLC;  
    1048.         nand->ecc.size = 512;  
    1049.         nand->cellinfo = 0;  
    1050.         nand->ecc.bytes = 4;  
    1051.         nand->ecc.layout = &s3c_nand_oob_16;  
    1052.     }  
    1053. #else  
    1054.     nand->ecc.mode = NAND_ECC_SOFT;  
    1055. #endif  
    1056.     return 0;  
    1057. }  
    1058. #endif /* (CONFIG_CMD_NAND) */  
     
     
    添加nand_cp.c
    [csharp] view plaincopyprint?
     
    1. /* 
    2.  * $Id: nand_cp.c,v 1.1 2008/11/20 01:08:36 boyko Exp $ 
    3.  * 
    4.  * (C) Copyright 2006 Samsung Electronics 
    5.  * 
    6.  * See file CREDITS for list of people who contributed to this 
    7.  * project. 
    8.  * 
    9.  * This program is free software; you can redistribute it and/or 
    10.  * modify it under the terms of the GNU General Public License as 
    11.  * published by the Free Software Foundation; either version 2 of 
    12.  * the License, or (at your option) any later version. 
    13.  * 
    14.  * This program is distributed in the hope that it will be useful, 
    15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of 
    16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
    17.  * GNU General Public License for more details. 
    18.  * 
    19.  * You should have received a copy of the GNU General Public License 
    20.  * along with this program; if not, write to the Free Software 
    21.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
    22.  * MA 02111-1307 USA 
    23.  */  
    24.   
    25. /* 
    26.  * You must make sure that all functions in this file are designed 
    27.  * to load only U-Boot image. 
    28.  * 
    29.  * So, DO NOT USE in common read. 
    30.  * 
    31.  * By scsuh. 
    32.  */  
    33.  
    34.  
    35. #include <common.h>  
    36.  
    37. #ifdef CONFIG_S5PC11X  
    38. #include <asm/io.h>  
    39. #include <linux/mtd/nand.h>  
    40. #include <regs.h>  
    41.  
    42. #define NAND_CONTROL_ENABLE()   (NFCONT_REG |= (1 << 0))  
    43.   
    44. /* 
    45.  * address format 
    46.  *              17 16         9 8            0 
    47.  * -------------------------------------------- 
    48.  * | block(12bit) | page(5bit) | offset(9bit) | 
    49.  * -------------------------------------------- 
    50.  */  
    51.   
    52. static int nandll_read_page (uchar *buf, ulong addr, int large_block)  
    53. {  
    54.         int i;  
    55.     int page_size = 512;  
    56.   
    57.     if (large_block)  
    58.         page_size = 2048;  
    59.   
    60.         NAND_ENABLE_CE();  
    61.   
    62.         NFCMD_REG = NAND_CMD_READ0;  
    63.   
    64.         /* Write Address */  
    65.         NFADDR_REG = 0;  
    66.   
    67.     if (large_block)  
    68.             NFADDR_REG = 0;  
    69.   
    70.     NFADDR_REG = (addr) & 0xff;  
    71.     NFADDR_REG = (addr >> 8) & 0xff;  
    72.     NFADDR_REG = (addr >> 16) & 0xff;  
    73.   
    74.     if (large_block)  
    75.         NFCMD_REG = NAND_CMD_READSTART;  
    76.   
    77.         NF_TRANSRnB();  
    78.   
    79.     /* for compatibility(2460). u32 cannot be used. by scsuh */  
    80.     for(i=0; i < page_size; i++) {  
    81.                 *buf++ = NFDATA8_REG;  
    82.         }  
    83.   
    84.         NAND_DISABLE_CE();  
    85.         return 0;  
    86. }  
    87.   
    88. /* 
    89.  * Read data from NAND. 
    90.  */  
    91. static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)  
    92. {  
    93.         uchar *buf = (uchar *)dst_addr;  
    94.         int i;  
    95.     uint page_shift = 9;  
    96.   
    97.     if (large_block)  
    98.         page_shift = 11;  
    99.   
    100.         /* Read pages */  
    101.         for (i = 0; i < (size>>page_shift); i++, buf+=(1<<page_shift)) {  
    102.                 nandll_read_page(buf, i, large_block);  
    103.         }  
    104.   
    105.         return 0;  
    106. }  
    107.   
    108. int copy_uboot_to_ram (void)  
    109. {  
    110.     int large_block = 0;  
    111.     int i;  
    112.     vu_char id;  
    113.   
    114.     NAND_CONTROL_ENABLE();  
    115.         NAND_ENABLE_CE();  
    116.         NFCMD_REG = NAND_CMD_READID;  
    117.         NFADDR_REG =  0x00;  
    118.   
    119.     /* wait for a while */  
    120.         for (i=0; i<200; i++);  
    121.     id = NFDATA8_REG;  
    122.     id = NFDATA8_REG;  
    123.   
    124.     if (id > 0x80)  
    125.         large_block = 1;  
    126.   
    127.     /* read NAND Block. 
    128.      * 128KB ->240KB because of U-Boot size increase. by scsuh 
    129.      * So, read 0x3c000 bytes not 0x20000(128KB). 
    130.      */  
    131.     return nandll_read_blocks(CFG_PHY_UBOOT_BASE, COPY_BL2_SIZE, large_block);  
    132. }  
    133.   
    134. #endif  

    u-boot for tiny210 ver2.2.1(by liukun321咕唧咕唧)

    这次更新没有增加具体功能,只修复了小bug。另外用一定篇幅说明如何解决u-boot for tiny210 在启动友善提供的mini210 linux内核/android出现卡死在Uncompressing Linux... done, booting the kernel.阶段。在这里再次感谢CSDN网友niyufeng 提出的问题。

    ver2.2的基本功能:

    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.修复bug:uboot for tiny210在tftp时经常出现超时现象,出现TTTT#######TTTTTT,然后Retry count exceeded; starting again问题。 

    本次更新对源码改动较小,只需按下面提供内容修改即可完成,故本次更新不提供源码下载。

    新版本及历史版本源码下载:

    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

    解决tftp超时,以及总出现ARP Retry count exceeded; starting again 的重复提示 bug: 

    修改步骤:

    1.在u-boot for tiny210 源码net/tftp.c18:

    #define TIMEOUT         50000UL 

     2.在net/net.c中

    #define ARP_TIMEOUT         50000UL 

    解决卡死在Uncompressing Linux... done, booting the kernel:

    PS:解决u-boot for tiny210 在启动友善提供的mini210 linux内核/android出现卡死在Uncompressing Linux... done, booting the kernel.  

    1.由于友善提供的内核时mini210的,第一步先修改u-boot for tiny210的机器码,使之与内核机器码匹配。

    修改include/configs/tiny210.h

    #define MACH_TYPE_TINY210 3466 

    2.友善提供的是mini210的内核,根据内核和mini210 uboot里的配置(我手里没有mini210开发板),可以知道mini210的DDR2ram

    和tiny210DDR2ram在bank的挂载方式是不同的,详见我的http://blog.csdn.net/liukun321/article/details/7270426 ,故需要修改内核

    源码的arch/arm/mach-s5pv210/include/mach/memory.h文件26,27行内容,将Maximum of 256MiB in one bank的限制改为Maximum

     of 512MiB in one bank  作如下修改:

    #define SECTION_SIZE_BITS    29
    #define NODE_MEM_SIZE_BITS    29 

    通过上述两步修改u-boot for tiny210即可成功引导linux/android.

     

    u-boot for tiny210 ver2.2.2(by liukun321咕唧咕唧)

    本次更新,修复了SD卡写入出现"data CRC error"的bug。我曾在u-boot for tiny210 ver2.1做过对这个bug的修复,我也提到过上次做的修改是不安全的,可能会对其它平台的代码产生副作用。而本次修改彻底解决了这个问题。感谢kasim,本次修改的源码由kasim提供。由于时间所限这次不再详细分析过程。只贴上本次修改的补丁文件内容。以后有时间,我会具体分析修改原因。

    历史版本下载:

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

    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

    --- a/board/samsung/tiny210/tiny210.c
    +++ b/board/samsung/tiny210/tiny210.c
    @@ -32,6 +32,8 @@
     #include <asm/io.h>
     #include <asm/arch/gpio.h>
     #include <asm/arch/mmc.h>
    +#include <asm/arch/clk.h> 
    +#include <asm/arch/clock.h> 
     /*Add by lk for DM9000 driver */
     //#include <drivers/net/dm9000x.h>
     #include <netdev.h>
    @@ -302,9 +304,13 @@ void nand_init(void)
     #endif
     
     #ifdef CONFIG_GENERIC_MMC
    +#define MOUTMMC (50000000) /* 50MHz */
     int board_mmc_init(bd_t *bis)
     {
      int i;
    + struct s5pc110_clock *clk = 
    +     (struct s5pc110_clock *)samsung_get_base_clock(); 
    +    unsigned long clk_src, clk_div, mpll, div; 
     
      /*
       * MMC0 GPIO
    @@ -336,6 +342,19 @@ int board_mmc_init(bd_t *bis)
       /* GPG1[0:6] drv 4x */
       s5p_gpio_set_drv(&s5pc110_gpio->g1, i, GPIO_DRV_4X);
      }
    + clk_src = readl(&clk->res9[0]); /* CLK_SRC4 */ 
    +    clk_src &= ~((0xf << 4) | 0xf); 
    +    clk_src |= (0x6 << 4) | 0x6; /* Set MMC0/1_SEL to SCLK_MPLL */ 
    +    
    +    mpll = get_pll_clk(MPLL); 
    +    div = ((mpll + MOUTMMC) / MOUTMMC) - 1; 
    +    
    +    clk_div = readl(&clk->div4); 
    +    clk_div &= ~((0xf << 4) | 0xf); 
    +    clk_div |= (div << 4) | div; 
    +    
    +    writel(clk_src, &clk->res9[0]); 
    +    writel(clk_div, &clk->div4); 
     
      return (s5p_mmc_init(0, 4) || s5p_mmc_init(1, 4));
     }

    如果您现在拿到的是从我CSDN资源上下载的源码,您还需修改drivers/mmc/s5p_mmc.c去掉对下面红色代码部分的屏蔽:

    225: while (1) {
    226                         mask = readl(&host->reg->norintsts);
    227 
    228                         if (mask & (1 << 15)) {
    229                                 /* Error Interrupt */
    230                                 writel(mask, &host->reg->norintsts);
    231                                 printf("%s: error during transfer: 0x%08x "    ,                                          
    232                                                 __func__, mask);
    233                                 return -1;
    234                         } else
     if (mask & (1 << 3)) {

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

    在此首先要特别感谢网友李明老师和Alex Ling对我无私的帮助和支持。

    这次更新,主要实现了Nand启动,并修改了前几个版本的几个小bug。ver3.0已经基本完成了u-boot的主线功能。后面我还会继续更新其它辅助功能。

    之前上传的几个版本,对nandflash烧写时ECC校验是基于软件ECC,由于S5PV210的IROM中固化的启动代码(暂且称其为BL0)在读nandflash时

    用的是8bit 硬件ECC。因此在烧写u-boot for tiny210到nandflash时,需要用开启了8bit 硬件ECC的 SD卡启动的u-boot 进行烧写(详见后面分析)。

     您可以从下面的链接获得源码,也可以下载历史版本,并参考后面的步骤修改获得ver3.0.

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

     您也可以打开下面的链接阅读ver3.0源码

    Git source tree(这是我在Gitorious建的第一个工程,对它的管理还是显的比较混乱。等我整理好另一个clone的工程,我会把链接贴上来)。

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

    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
     

    ver3.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卡启动时对nandflash的烧写为8bit 硬件ECC校验。(nand启动仍为软件ECC)

    +10.添加Nandflash启动。
     
    在介绍修改步骤之前,先对S5PV210的启动流程,及BL0阶段需要注意的问题作简要分析:
    (1)启动流程:
    启动的详细过程见datasheet,如下:
    Program code starts from internal ROM(iROM) and moves to internal SRAM(iRAM). Finally, program executes on DRAM.
    The booting sequence in internal ROM is as follows:
    1. Disable the watchdog timer.
    2. Initialize the instruction cache controller.
    3. Initialize the stack and heap region.
    4. Check secure key.
    5. Set Clock divider, lock time, PLL (MPS value), and source clock.
    6. Check OM pin and load the first boot loader (The size of boot loader depends on S/W) from specific device (block number 0) to iRAM.
    7. If secure booting is successful, execute integrity check
    8. If integrity check passes, then jump to the first boot loader in iRAM (0xD002_0010)
    The booting sequence in internal SRAM is as follows:
    1. Load the second boot loader from boot device to iRAM.
    2. If secure booting is successful, execute integrity check.
    3. If integrity check passes, then jump to the second boot loader in iRAM (The jumping address depends on user's software)
    4. If integrity check fails, then stop the first boot loader.
    5. The second boot loader Initializes the DRAM controller.
    6. Load the OS image from specific device (block number 1) to DRAM.
    7. Jump to OS code in DRAM (0x2000_0000 or 0x4000_0000)
    (2)BL0阶段需要注意的几个问题:
    1.在BL0阶段 nand或SD启动,前16K内容搬运到IRAM。
    S5PV210有64k的irom,里面固化的代码用于将Nandflash或sd卡中的前16K代码cp到IRAM中(这个过程暂且称之为BL0,例如:在2440中的nand启动时BL0复制的是nandflash的前4K内容),只有在BL0成功完成以后,u-boot的BL1和BL2阶段才能够完成。IROM和Iram在地址空间的分布如下图:
     
     
    2.关于BL0阶段的ECC校验。
     由于我之前用过2440,就拿2440与s5pv210对比分析。2440在BL0阶段读nandflash时并没有开启ECC校验,而s5pv210在BL0阶段开启了8bit 硬件ECC校验。所以我们在nandflash中烧写uboot时要开启8bit 硬件ECC校验(因此我将ver3.0的SDboot版对nand的读写修改为8bit 硬件ECC校验,用于向nandflash烧写uboot)。如
    果用非8bit 硬件ECC校验的方式向nandflash烧写uboot,BL0阶段就会stop(ECC校验错误:这是导致BL0 stop的第一个原因)。
    ECC校验的算法有很多种,至于用哪一种,我是通过分析用Superboot210烧写过的nandflash的oob区猜得的:
     
    通过uboot的nand dump命令 ,如上图我用nand dump 0 读取了第零页及其oob的内容,该校验算法使用了52个字节的oob区,而tiny210用的nand的每page大小为2048byte。
    从datasheet可也以得到:
    这似乎可以联系到BCH算法(详细内容见附录)。因为以8bit/512Byte BCH方式,控制器写数据到NAND Flash时,每512Byte数据经过BCH模块就会生成13Byte的校验数据。这样修改 8bit  硬件ECC校验(SD启动的uboot开启了此校验方式,因为我们要用它在nand中烧写uboot)的基本方向就确定了。更多关于ECC的信息请参考手册。
     
    3.关于spl/tiny210-spl.bin文件前16字节内容的分析。
    u-boot for tiny210 是基于spl的。
    在使用前几个版本的u-boot for tiny210时,我们会把spl/tiny210-spl.bin烧到SD卡第一扇区。分析spl/Makefile 及 u-boot-spl.map我们可以知道:libtiny210.o(start.S)  lowlevel_init.o  mem_setup.o  nand_cp.o  nand.o  这几个文件会被最先链接生成.bin,该.bin文件经board/samsung/tiny210/tools/mktiny210spl.exe处理后最终得到tiny210-spl.bin。mktiny210spl.exe是由board/samsung/tiny210/tools/mkv210_image.c文件得到。
     
    board/samsung/tiny210/tools/mktiny210spl.exe处理过程:根据mkv210_image.c文件的内容不难看出它的功能是将未被处理的.bin文件内容读到BUFSIZE大小的缓冲区,然后统计.bin文件中1的个数(作为用于BL0过程的校验和)。校验和存放在tiny210-spl.bin 文件最前面16字节的高8个字节中,而低8个字节则是存放#define SPL_HEADER              "S5PC110 HEADER  "字串的前8个字符也就是"S5PC110 "   。高8个字节的校验和将直接决定BL0阶段是否能够成功完成(校验和错误:这是导致BL0 stop的第二个原因)。当#define IMG_SIZE                (X*1024)大于未被处理的.bin文件时,生成的新文件尾会被0填充直至生成的tiny210-spl.bin的大小等于IMG_SIZE。
     
    在BL0阶段,Irom内固化的代码读取nandflash或SD卡前16K的内容,并比对前16字节中的校验和是否正确,正确则继续,错误则停止。
     
    a = Buf + SPL_HEADER_SIZE;
     for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
      checksum += (0x000000FF) & *a++;
    上面这段代码位于board/samsung/tiny210/tools/mkv210_image.c中即是统计校验和。
    (3)下面介绍一下修改步骤(以下步骤是基于u-boot for tiny210 ver2.2.X的),并作简要的分析。
     
    1.首先在include/configs/tiny210.h 中修改下述宏:
    删除172-183行:

    -/* FLASH and environment organization */
    -#define CONFIG_SYS_NO_FLASH  1
    -#undef CONFIG_CMD_IMLS
    -#define CONFIG_IDENT_STRING " for FriendlyLEG-TINY210"
    -
    -#define CONFIG_ENV_IS_IN_MMC  1
    -#define CONFIG_SYS_MMC_ENV_DEV  0
    -#define CONFIG_ENV_SIZE  0x4000 /* 16KB */
    -#define RESERVE_BLOCK_SIZE              (512)
    -#define BL1_SIZE                        (8 << 10) /*8 K reserved for BL1*/
    -#define CONFIG_ENV_OFFSET               (RESERVE_BLOCK_SIZE + BL1_SIZE + ((16 + 512) * 1024))
    -#define CONFIG_DOS_PARTITION  1

    然后在

    460:

    +/* FLASH and environment organization */
    +#define CONFIG_SYS_NO_FLASH             1
    +#undef CONFIG_CMD_IMLS
    +#define CONFIG_IDENT_STRING     " for FriendlyLEG-TINY210"
    +#if 1
    +#define CONFIG_TINY210_NAND_BOOT               1
    +#endif
    +#if 0
    +#define CONFIG_TINY210_MMC_BOOT               1
    +#endif
    +/*MMC BOOT   */
    +#if defined(CONFIG_TINY210_MMC_BOOT)
    +#define CFG_NAND_HWECC
    +#define CONFIG_NAND_BL1_8BIT_ECC
    +#define CONFIG_ENV_IS_IN_MMC            1
    +#define CONFIG_SYS_MMC_ENV_DEV          0
    +#define CONFIG_ENV_SIZE         0x4000  /* 16KB */
    +#define RESERVE_BLOCK_SIZE              (512)
    +#define BL1_SIZE                        (8 << 10) /*8 K reserved for BL1*/
    +#define CONFIG_ENV_OFFSET               (RESERVE_BLOCK_SIZE + BL1_SIZE + ((16 + 512) * 1024))
    +#endif
    +
    +#define CONFIG_DOS_PARTITION            1
    +
    +/*NAND_BOOT  by lk  */
    +#if defined(CONFIG_TINY210_NAND_BOOT)

    +#define CONFIG_S5PC11X
    +#define CONFIG_ENV_IS_IN_NAND            1
    +#define CONFIG_ENV_SIZE         0x4000  /* 16KB */
    +#define CONFIG_ENV_OFFSET               0x40000

    +#endif

    #define CONFIG_TINY210_NAND_BOOT               1
    即可实现nand启动

    #define CONFIG_TINY210_MMC_BOOT               1

    即可实现sd启动

    2.修改board/samsung/tiny210/Makefile 即可通过定义CONFIG_TINY210_MMC_BOOT/CONFIG_TINY210_NAND_BOOT,分别实现SD启动和NAND启动。
    ifdef CONFIG_SPL_BUILD
    +
    +ifdef CONFIG_TINY210_MMC_BOOT
     COBJS  += mmc_boot.o
     endif

    +ifdef CONFIG_TINY210_NAND_BOOT
     COBJS  += nand_cp.o
    +endif

    +endif
    屏蔽掉38行的COBJS  += nand_cp.o

    3.修改实现8bit 硬件ECC校验。board/samsung/tiny210/nand.c中

    44:static struct nand_ecclayout s3c_nand_oob_16 = {
      .eccbytes = 4,
      .eccpos = {1, 2, 3, 4},
      .oobfree = {
       {.offset = 6,
        . length = 10}}
     };
    -
    52:+static struct nand_ecclayout s3c_nand_oob_64_8bit = {
    + .eccbytes = 52,
    + .eccpos = {
    +   12,13,14,15,
    +   16,17,18,19,20,21,22,23, 
    +     24, 25, 26, 27, 28, 29, 30, 31,
    +     32, 33, 34, 35, 36, 37, 38, 39,
    +     40, 41, 42, 43, 44, 45, 46, 47,
    +      48, 49, 50, 51, 52, 53, 54, 55,
    +        56, 57, 58, 59, 60, 61, 62, 63},
    + .oobfree = {
    +  {.offset = 2,
    +   .length = 10}}
    +};
     /* Nand flash oob definition for SLC 2k page size by jsgood */
     static struct nand_ecclayout s3c_nand_oob_64 = {

    屏蔽掉下面两个函数中的while

    上面的信息可见【25】【24】位是对MLC nandflash的状态位,而tiny210上用的是SLC的nandflash。所以进行下面的屏蔽。

     static void s3c_nand_wait_enc(void)
     {
    +// while (!(readl(NFECCSTAT) & NFSTAT_ECCENCDONE)) {}
     }
     
     /*
    @@ -187,7 +200,7 @@ static void s3c_nand_wait_enc(void)
      */
     static void s3c_nand_wait_dec(void)
     {
    +// while (!(readl(NFECCSTAT) & NFSTAT_ECCDECDONE)) {}
     }

    @@ -1042,9 +1067,24 @@

     int board_nand_init(struct nand_chip *nand)
        nand_type = S3C_NAND_TYPE_SLC;
        nand->ecc.size = 512;
        nand->ecc.bytes = 4;
    -
    1060:+ 
    + if ((1024 << (tmp & 3)) == 4096) {
    +     /* Page size is 4Kbytes */
    + nand->ecc.read_page = s3c_nand_read_page_8bit;
    + nand->ecc.write_page = s3c_nand_write_page_8bit;
    + nand->ecc.read_oob = s3c_nand_read_oob_8bit;
    + nand->ecc.write_oob = s3c_nand_write_oob_8bit;
    + nand->ecc.layout = &s3c_nand_oob_128;
    + nand->ecc.hwctl = s3c_nand_enable_hwecc_8bit;
    + nand->ecc.calculate = s3c_nand_calculate_ecc_8bit;
    + nand->ecc.correct = s3c_nand_correct_data_8bit;
    + nand->ecc.size = 512;
    + nand->ecc.bytes = 13;
    + nand->options |= NAND_NO_SUBPAGE_WRITE;}
    +  else 
        if ((1024 << (tmp & 0x3)) > 512) {
    -    nand->ecc.read_page = s3c_nand_read_page_1bit;
    1073:+#if defined(CONFIG_NAND_4BIT_ECC)

    +   nand->ecc.read_page = s3c_nand_read_page_1bit;
         nand->ecc.write_page = s3c_nand_write_page_1bit;
         nand->ecc.read_oob = s3c_nand_read_oob_1bit;
         nand->ecc.write_oob = s3c_nand_write_oob_1bit;
    @@ -1053,6 +1093,18 @@ int board_nand_init(struct nand_chip *nand)
                                     nand->ecc.calculate = s3c_nand_calculate_ecc;
                                     nand->ecc.correct = s3c_nand_correct_data;
                                     nand->options |= NAND_NO_SUBPAGE_WRITE;

    1083:+#endif
    +nand->ecc.read_page = s3c_nand_read_page_8bit;
    + nand->ecc.write_page = s3c_nand_write_page_8bit;
    + nand->ecc.read_oob = s3c_nand_read_oob_8bit;
    + nand->ecc.write_oob = s3c_nand_write_oob_8bit;
    + nand->ecc.layout = &s3c_nand_oob_64_8bit;
    + nand->ecc.hwctl = s3c_nand_enable_hwecc_8bit;
    + nand->ecc.calculate = s3c_nand_calculate_ecc_8bit;
    + nand->ecc.correct = s3c_nand_correct_data_8bit;
    + nand->ecc.size = 512;
    + nand->ecc.bytes = 13;
    + nand->options |= NAND_NO_SUBPAGE_WRITE;
        } else {
         nand->ecc.layout = &s3c_nand_oob_16;
        }

    4,修改nand_cp.c文件。

    +//#include <regs.h>
    +#include <s5pc110.h>

    +#define COPY_BL2_SIZE  0x80000

    @@ -98,7 +98,7 @@ static int nandll_read_blocks (ulong dst_addr, ulong size, int large_block)
       page_shift = 11;
     
             /* Read pages */
    98:        for (i =(0x6000>>page_shift); i < (size>>page_shift); i++, buf+=(1<<page_shift)) {
                     nandll_read_page(buf, i, large_block);
             }

    0x6000是24k后的第一个地址,也就是从这个nandflash的这个偏移地址开始cp内容到DRAM。

    @@ -128,8 +128,29 @@ int copy_uboot_to_ram (void)

    128:+ return nandll_read_blocks(CONFIG_SYS_TEXT_BASE, COPY_BL2_SIZE, large_block);
    +}
    +void board_init_f(unsigned long bootflag)
    +{
    +        __attribute__((noreturn)) void (*uboot)(void);
    +        copy_uboot_to_ram();
    +
    +        /* Jump to U-Boot image */
    +        uboot = (void *)CONFIG_SYS_TEXT_BASE;
    +        //while(1);
    + (*uboot)();
    +        /* Never returns Here */
     }

    +
    +/* Place Holders */
    +void board_init_r(gd_t *id, ulong dest_addr)
    +{
    +        /* Function attribute is no-return */
    +        /* This Function never executes */
    +        while (1)
    +                ;
    +}
    +
    +void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {}

    5.修改board/samsung/tiny210/tools/mkv210_image.c

    8:#define BUFSIZE                 (24*1024)
          #define IMG_SIZE                (24*1024)

    这个参数的修改是为了便于实现nandboot和SDboot的切换,因为
    在board/samsung/tiny210/mmc_boot.c第四十九行可以找到

    #define MOVI_BL2_POS            ((eFUSE_SIZE / MOVI_BLKSIZE) + MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT)
    当sdboot的BL1阶段要从MOVI_BL2_POS(24k + 1k(sd卡的第0扇区))这个偏移位置开始向DRAM cp代码。虽然启动时只会从nand或SD卡一次性读取16K内容,但是为了统一两种启动方式tiny210-spl.bin的大小,生成24k大小的tiny210-spl.bin(这并不会影响校验和,因为文件尾是由0填充)。

    另外我在源码的根目录下写了一个简单的脚本make-tiny210-boot.sh,用于合并tiny210-spl.bin和u-boot.bin文件->生成tiny210-uboot.bin。这样我们以后烧写uboot时就不用像老版本那样分别烧写两个文件了。

    至此ver3,0修改完成.

    编译u-boot
    $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
    $./make-tiny210-boot.sh
    由于我的系统下装有两套交叉工具链,所以没有把 /opt/FriendlyARM/toolschain/4.5.1/bin/ 添加到环境变量,在使用工具链时要指明路径。

    1.sd启动
    当我们在include/configs/tiny210.h定义了#define CONFIG_TINY210_MMC_BOOT               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.nandflash启动
    当我们在include/configs/tiny210.h定义了#define CONFIG_TINY210_NAND_BOOT               1 为NANDFLASH启动
    通过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 3b4c4
     
     
    测试保存环境变量:
     
     
    附录:BCH算法

    对于BCH算法目前通常以512Byte或者1024Byte为单位处理,因为BCH按位处理数据,所以是4096bit或者8192bit,这里的4096/8192bit是原始数据,BCH需要生成一定的校验数据。下面简要介绍下原理

    设最大纠错能力为t

    如果选用4096bit的原始数据长度,则模式为BCH(8191,8191-13×t,t,13)

    如果选用8192bit的原始数据长度,则模式为BCH(16383,16383-14×t,t,14)

    校验数据长度就是13×t,或者14×tbit

    所以平均1024+32Byte的MLC 大多建议使用8bit/512Byte ECC

    平均1024+45Byte的MLC大多建议使用24Bit/1024Byte ECC, 此时需要14×24bit=42Byte的检验数据空间

    以8bit/512Byte BCH方式的ECC为例,控制器写数据到NAND Flash时,每512Byte数据经过BCH模块就会生成13Byte的校验数据(当然剩下的16-13=3Byte也可以作为某种用途的数据,可以任意使用0-3Byte而不会改变ECC的使用),这些数据一起写入到NAND Flash中。控制器从NAND Flash中读取数据的时候需要将原始数据和校验数据一起读出经过BCH模块,BCH模块计算伴随矩阵首先可以判断出是否出现了错误,如果出现了错误需要计算错误位置多项式,然后解多项式,得到错误位置(目前主要使用Chien-search方法),因为是位错误,找到错误的位置以后取反以后就是正确的数据。只要是错误个数小于等于8,BCH都能够找到错误的位置,但是如果错误个数超过了8,对于BCH来说已经没有办法纠正错误了,只能报告出现了不可以纠正的情况。

    u-boot for tiny210 ver3.1 (by liukun321咕唧咕唧)

    这次更新,实现了自动识别Nand或MMC/SD启动(环境变量统一存放于Nandflash中),统一SD及Nand启动模式的nandflash驱动均为8bit HW ECC校验,并调整部分源码文件的结构。 您可以从下面的链接获得源码,也可以下载历史版本,并参考后面的步骤修改获得ver3.1。本次修改的原理简单不做太详细的分析。

    最新源码下载:

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

    ver3.1下载:

    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
    ver3.1的基本功能:

    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启动。
     
    关于源码结构的调整,请参考ver3.1的源码包。
     
     
    下面介绍修改过程并作简要的分析:
     
    1.修改arch/arm/cpu/armv7/start.S文件,在此文件中添加"+"后内容:
     
    @@ -32,7 +32,9 @@
     #include <asm-offsets.h>
     #include <config.h>
     #include <version.h>
    -
    +#include <common.h>
    +#include <configs/tiny210.h>
    +#include <s5pc110.h>
     .globl _start
     _start: b reset
      ldr pc, _undefined_instruction
    @@ -176,8 +178,61 @@ call_board_init_f:
      ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
      bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
      ldr r0,=0x00000000
    +#if defined(CONFIG_TINY210) || defined(CONFIG_MINI210)
    + adr r4, _start
    + ldr r5,_TEXT_BASE
    + cmp     r5,r4
    + beq board_init_in_ram

    + ldr r0, =PRO_ID_BASE
    +        ldr r1, [r0,#OMR_OFFSET]
    +        bic r2, r1, #0xffffffc1
    +
    + /* NAND BOOT */
    + cmp r2, #0x0 @ 512B 4-cycle
    + moveq r3, #BOOT_NAND
    +
    + cmp r2, #0x2 @ 2KB 5-cycle
    + moveq r3, #BOOT_NAND
    +
    + cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
    + moveq r3, #BOOT_NAND
    +
    + cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
    + moveq r3, #BOOT_NAND
    +
    + cmp r2, #0x8 @ OneNAND Mux
    + moveq r3, #BOOT_ONENAND
    +
    + /* SD/MMC BOOT */
    + cmp     r2, #0xc
    + moveq   r3, #BOOT_MMCSD 
    +
    + /* NOR BOOT */
    + cmp     r2, #0x14
    + moveq   r3, #BOOT_NOR 
    +
    + /* Uart BOOTONG failed */
    + cmp     r2, #(0x1<<4)
    + moveq   r3, #BOOT_SEC_DEV

    + ldr r0, =INF_REG_BASE
    + str r3, [r0, #INF_REG3_OFFSET]
    +
    + ldr r1, [r0, #INF_REG3_OFFSET]
    + cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */
    + beq nand_boot_210
    + cmp     r1, #BOOT_MMCSD
    + beq     mmcsd_boot_210

    +nand_boot_210:
    + bl     board_init_f_nand
    +
    +mmcsd_boot_210:
    + bl     board_init_f
    +board_init_in_ram:
    +#endif
      bl board_init_f
    -
    蓝色代码实现的功能:将PRO_ID_BASE + OMR_OFFSET (这是一个启动方式寄存器,从中可以得到上电时的启动状态)地址处的读取启动信息,值0x0~0x6分别对应几种不同的nandflash启动,0xc对应MMC/SD启动。当确定是某一种启动方式后,将其对应的十六进制存放于INFORM3寄存器中。
    红色代码实现的功能:将INFORM3的内容读出,并和预先定义的BOOT_NAND  BOOT_MMCSD cmp,并进行对应的跳转,跳转到相应启动方式的代码搬运函数中。
     
     
    2.将board/samsung/tiny210/nand_cp.c移动到 -->arch/arm/cpu/armv7/s5pc1xx/目录下
    将board/samsung/tiny210/mmc_boot.c移动到-->arch/arm/cpu/armv7/s5pc1xx/目录下
    nand_cp.cmmc_boot.c的移动主要是为了让目录层次更加清晰减少代码的重复。
    在arch/arm/cpu/armv7/s5pc1xx/Makefile中
    添加红色代码:
    @@ -32,6 +32,10 @@ SOBJS = cache.o
     SOBJS += reset.o
     
     COBJS += clock.o
    +ifdef CONFIG_SPL_BUILD
    +COBJS  += mmc_boot.o
    +COBJS  += nand_cp.o
    +endif
     
     SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
     OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
    修改board/samsung/tiny210/
    Makefile删除下面红色代码:
    -ifdef CONFIG_SPL_BUILD
    -ifdef CONFIG_TINY210_NAND_BOOT
    -COBJS  += mmc_boot.o
    -endif
    -ifdef CONFIG_TINY210_NAND_BOOT
    -COBJS  += nand_cp.o
    -endif
    -endif
     
     
    3.修改arch/arm/cpu/armv7/s5pc1xx/nand_cp.c
    将void board_init_f(unsigned long bootflag)-->void board_init_f_nand(unsigned long bootflag)
    134 void board_init_f_nand(unsigned long bootflag)
    135 {
    136         __attribute__((noreturn)) void (*uboot)(void);
    137         copy_uboot_to_ram_nand();
    删除下面代码:
    -void board_init_r(gd_t *id, ulong dest_addr)
    -{
    -        /* Function attribute is no-return */
    -       /* This Function never executes */
    -        while (1)
    -                ;
    -}
     
    -void save_boot_params(u32 r0, u32 r1, u32 r2, u32 r3) {}
     
    4.修改include/common.h,添加下面红色代码:
     
    243 /* arch/$(ARCH)/lib/board.c */
    244 void    board_init_f  (ulong) __attribute__ ((noreturn));
    245 #if defined(CONFIG_TINY210) || defined(CONFIG_MINI210)
    246 void    board_init_f_nand  (ulong) __attribute__ ((noreturn));
    247 #endif
    248 void    board_init_r  (gd_t *, ulong) __attribute__ ((noreturn));
    249 int     checkboard    (void);
    5.修改arch/arm/lib/board.c
    261 void board_init_f_nand(ulong bootflag)
    262 {
    263         while(1);
    264 }
    265 
    266 void board_init_f(ulong bootflag)
    267 {
    268         bd_t *bd;
    269         init_fnc_t **init_fnc_ptr;
    270         gd_t *id;
     
    6.修改spl/Makefile
    在make过程合并 tiny210-spl.bin u-boot.bin
    104         $(TOPDIR)/board/$(BOARDDIR)/tools/mk$(BOARD)spl.exe
    105                 $(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin
    +106          cat $(obj)$(BOARD)-spl.bin $(TOPDIR)/u-boot.bin > $(TOPDIR)/$(BOARD)-uboot.bin
    7.修改include/configs/tiny210.h
    将427行以后的内容替换为
     /* FLASH and environment organization */
    429 #define CONFIG_SYS_NO_FLASH             1
    430 #undef CONFIG_CMD_IMLS
    431 #define CONFIG_IDENT_STRING     " for FriendlyLEG-TINY210"
    432 #define CONFIG_DOS_PARTITION            1
    433 
    434 /*NAND_BOOT & MMCSD_BOOT  by lk  */
    435 #define CONFIG_S5PC11X
    436 #define CONFIG_ENV_IS_IN_NAND            1
    437 #define CONFIG_ENV_SIZE         0x4000  /* 16KB */
    438 #define RESERVE_BLOCK_SIZE              (2048)
    439 #define BL1_SIZE                        (8 << 10) /*8 K reserved for BL1*/
    440 #define CONFIG_ENV_OFFSET               0x40000
    441 #define CFG_NAND_HWECC
    442 #define CONFIG_NAND_BL1_8BIT_ECC
    443 #define CONFIG_8BIT_HW_ECC_SLC      1
     
    至此ver3.0 --> ver3.1修改完成.
     
     
    编译u-boot
    $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 
     
     
     

     在修改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'. ", 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! "); 
    +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 ");
    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 ");
    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 ",
    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 ",
    +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(" Writing 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 ",
    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校验。
    修改内核driversmtd andS3c_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.的问题,多尝试校正(保存)几次就通过了。测试时偶尔出现过这个问题。

  • 相关阅读:
    [如何构建自己的轮式移动机器人系统·从入门到放弃]机器人底层篇
    Readme.txt
    [MATLAB&SIMULINK] 如何提取并处理Simscape Power System 中powergui的谐波分析数据
    记录2016年12月11日
    [深度强化学习] blog翻译使用Keras与Gym仿真环境进行深度Q学习(DQL)
    使用PARL与Gym仿真环境进行深度Q学习(DQL)
    Telerik控件使用Expression_DarkTheme后引发Combobx下拉问题
    [Win系统][临时方案]系统任务管理器不能使用临时性解决方案
    [Visual Studio]重置开发环境
    WPF中使用DataGrid后,里面的Button的Command不响应的问题
  • 原文地址:https://www.cnblogs.com/cainiaoaixuexi/p/3498066.html
Copyright © 2020-2023  润新知