Chinaunix首页 | 论坛 | 博客
  • 博客访问: 805640
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-07-16 10:25:10

本节实现支持nand flash

修改UBOOT支持NAND FLASH的读写,前面只是支持NAND的方式启动,这是两回事。

1. 修改配置文件,将支持NAND模块

    修改:include/configs/smdk2440.h:

#define CONFIG_CMD_NAND   // 把这句话加上,重新编译,看出错信息,进行修改源码。

编译错误
s3c2410_nand.c: In function 's3c2410_hwcontrol':
s3c2410_nand.c:57: warning: implicit declaration of function 's3c2410_get_base_nand'
s3c2410_nand.c:57: warning: initialization makes pointer from integer without a cast
s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
s3c2410_nand.c:72: error: dereferencing pointer to incomplete type
s3c2410_nand.c:75: error: dereferencing pointer to incomplete type
s3c2410_nand.c:75: error: dereferencing pointer to incomplete type
s3c2410_nand.c: In function 's3c2410_dev_ready':
s3c2410_nand.c:85: warning: initialization makes pointer from integer without a cast
s3c2410_nand.c:87: error: dereferencing pointer to incomplete type
s3c2410_nand.c: In function 'board_nand_init':
s3c2410_nand.c:129: warning: initialization makes pointer from integer without a cast
s3c2410_nand.c:150: error: dereferencing pointer to incomplete type
s3c2410_nand.c:153: error: dereferencing pointer to incomplete type
s3c2410_nand.c:154: error: dereferencing pointer to incomplete type
make[1]: *** [s3c2410_nand.o] Error 1
make[1]: Leaving directory `/work/system/u-boot-2012.04.01/drivers/mtd/nand'
make: *** [drivers/mtd/nand/libnand.o] Error 2

2440与nand flash的交互:

2440内部有nand flash控制器,数据线有8根:
(1)CLE为高电平,数据线上发送的是命令;
(2)ALE为高电平,数据线上发送的是地址;
(3)CLE,ALE为低,表示发送的是数据

2440对于nand flash操作有一类寄存器进行控制,设置。
NFCMD, NFADDR, NFDATA, 还有检测忙信号等。

而NOR flash有类似于内存接口,可以直接访问某个地址。NAND FLASH只能通过发送某些特定的序列,通过IO口的方式读取某个地址的数据。



2. 拷贝现有的NAND文件为板子所用

把drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c

但是如何将改动的文件 s3c2440_nand.c 编译进内核呢?
修改在该目录下的Makefile文件:

COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
COBJS-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
COBJS-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
COBJS-$(CONFIG_NAND_MXC) += mxc_nand.o
COBJS-$(CONFIG_NAND_MXS) += mxs_nand.o
COBJS-$(CONFIG_NAND_NDFC) += ndfc.o
COBJS-$(CONFIG_NAND_NOMADIK) += nomadik.o
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o     // 添加这句话,这个宏:CONFIG_NAND_S3C2440 在配置文件 includes\configs\smdk2440.h 中定义
COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o
COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o

所以在配置文件里应该启用这个宏 CONFIG_NAND_S3C2440

#define CONFIG_CMD_NAND  
// 启用NAND

/*

 * NAND configuration
 */
#ifdef CONFIG_CMD_NAND

#ifdef CONFIG_S3C2410

#define CONFIG_NAND_S3C2410
#define CONFIG_SYS_S3C2410_NAND_HWECC

#else // CONFIG_S3C2440配置选项

#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC

#endif

#define CONFIG_SYS_MAX_NAND_DEVICE    1
#define CONFIG_SYS_NAND_BASE        0x4E000000

#endif

3. 分析nand flash工作过程


nand_init
    nand_init_chip
        board_nand_init
            设置nand_chip结构体, 提供底层的操作函数
        nand_scan
            nand_scan_ident
                nand_set_defaults
                    chip->select_chip = nand_select_chip;
                    chip->cmdfunc = nand_command;
                    chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
                    
                nand_get_flash_type
                    chip->select_chip
                    chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
                            nand_command()  // 即可以用来发命令,也可以用来发列地址(页内地址)、行地址(哪一页)
                                chip->cmd_ctrl
                                        s3c2440_hwcontrol
                                
                    chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
                    *maf_id = chip->read_byte(mtd);
                    *dev_id = chip->read_byte(mtd);


4. 修改底层操作函数:s3c2440_nand.c

点击(此处)折叠或打开

  1. /*
  2.  * (C) Copyright 2006 OpenMoko, Inc.
  3.  * Author: Harald Welte <laforge@openmoko.org>
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License as
  7.  * published by the Free Software Foundation; either version 2 of
  8.  * the License, or (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  18.  * MA 02111-1307 USA
  19.  */

  20. #include <common.h>

  21. #include <nand.h>
  22. #include <asm/arch/s3c24x0_cpu.h>
  23. #include <asm/io.h>

  24. #define S3C2410_NFCONF_EN (1<<15)
  25. #define S3C2410_NFCONF_512BYTE (1<<14)
  26. #define S3C2410_NFCONF_4STEP (1<<13)
  27. #define S3C2410_NFCONF_INITECC (1<<12)
  28. #define S3C2410_NFCONF_nFCE (1<<11)
  29. #define S3C2410_NFCONF_TACLS(x) ((x)<<8)
  30. #define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
  31. #define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)

  32. #define S3C2410_ADDR_NALE 4
  33. #define S3C2410_ADDR_NCLE 8

  34. #ifdef CONFIG_NAND_SPL

  35. /* in the early stage of NAND flash booting, printf() is not available */
  36. #define printf(fmt, args...)

  37. static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  38. {
  39.     int i;
  40.     struct nand_chip *this = mtd->priv;

  41.     for (i = 0; i < len; i++)
  42.         buf[i] = readb(this->IO_ADDR_R);
  43. }
  44. #endif



  45. /*
  46.   *
  47.   * ctrl: 表示做什么,选中/取消选中芯片,发命令还是发地址
  48.   *
  49.   * cmd: 命令值或者地址值
  50.   *
  51.   */
  52. static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
  53. {
  54.     struct nand_chip *chip = mtd->priv;
  55. #if 0
  56.     struct s3c2410_nand *nand = s3c2410_get_base_nand();
  57. #else
  58.     // 获取nand flash 控制器的基地址
  59.     struct s3c2440_nand *nand = s3c2440_get_base_nand();
  60. #endif

  61.     if(ctrl & NAND_CLE)
  62.     {
  63.         /* 发命令 */
  64.         writeb(dat, &nand->nfcmd);
  65.     }
  66.     else if(ctrl & NAND_ALE)
  67.     {
  68.         /* 发地址 */
  69.         writeb(dat, &nand->nfaddr);
  70.     }



  71. #if 0
  72.     debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);

  73.     if (ctrl & NAND_CTRL_CHANGE) {
  74.         ulong IO_ADDR_W = (ulong)nand;

  75.         if (!(ctrl & NAND_CLE))
  76.             IO_ADDR_W |= S3C2410_ADDR_NCLE;
  77.         if (!(ctrl & NAND_ALE))
  78.             IO_ADDR_W |= S3C2410_ADDR_NALE;

  79.         chip->IO_ADDR_W = (void *)IO_ADDR_W;

  80.         if (ctrl & NAND_NCE) /* 使能选中*/
  81.         {
  82.          #if 0
  83.                 writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,
  84.                  &nand->nfconf);
  85.            #else
  86.                 writel(readl(&nand->nfcont) & ~(1<<1), // nfcont bit1 clear
  87.                  &nand->nfcont);
  88.            #endif
  89.         }
  90.         else /* 取消选中*/
  91.         {
  92.          #if 0
  93.                 writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
  94.                  &nand->nfconf);

  95.          #else
  96.                 writel(readl(&nand->nfcont) | (1<<1),
  97.                  &nand->nfcont);

  98.          #endif
  99.         }

  100.         
  101. #ifdef BOGUS
  102.             writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
  103.              &nand->nfconf);
  104. #endif /* BOGUS */
  105.     }

  106.     if (cmd != NAND_CMD_NONE)
  107.         writeb(cmd, chip->IO_ADDR_W);
  108. #endif


  109. }

  110. static int s3c2440_dev_ready(struct mtd_info *mtd)
  111. {
  112.     //struct s3c2410_nand *nand = s3c2410_get_base_nand();
  113.     struct s3c2440_nand *nand = s3c2440_get_base_nand();

  114.     debug("dev_ready\n");
  115.     return readl(&nand->nfstat) & 0x01;
  116. }


  117. // 参考已知代码,添加下面的这个函数
  118. static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
  119. {
  120.     struct s3c2440_nand *nand = s3c2440_get_base_nand();

  121.     switch (chipnr) {
  122.     
  123.     case -1: /* 取消选中*/
  124.         nand->nfcont |= (1<<1);
  125.         break;
  126.     case 0: /* 选中*/
  127.         nand->nfcont &=~ (1<<1);
  128.     break;

  129.     default:
  130.         BUG();
  131.     }
  132. }



  133. int board_nand_init(struct nand_chip *nand)
  134. {
  135.     u_int32_t cfg;
  136.     u_int8_t tacls, twrph0, twrph1;
  137.     struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();

  138. #if 0 // grant modify
  139.     struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
  140. #else    
  141.     struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
  142. #endif

  143.     debug("board_nand_init()\n");

  144.     writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);

  145.     /* initialize hardware */
  146. #if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
  147.     tacls = CONFIG_S3C24XX_TACLS;
  148.     twrph0 = CONFIG_S3C24XX_TWRPH0;
  149.     twrph1 = CONFIG_S3C24XX_TWRPH1;
  150. #else

  151.     // 根据不同的开发板,设置时间参数
  152.     tacls = 4;
  153.     twrph0 = 8;
  154.     twrph1 = 8;
  155. #endif

  156. #if 0
  157.     // 适用于2410
  158.     
  159.     cfg = S3C2410_NFCONF_EN;
  160.     cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
  161.     cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
  162.     cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
  163. #else

  164.     /* 初始化时序 */
  165.     cfg = ((tacls-1) << 12) | ((twrph0-1) << 8) | ((twrph1-1) << 4);
  166. #endif
  167.     
  168.     writel(cfg, &nand_reg->nfconf);

  169.     /* 增加下面的语句,使能NAND FLASH控制器,初始化ECC, 禁止片选*/
  170.     writel((1<<4) | (1<<1) | (1<<0), &nand_reg->nfcont);
  171.     

  172.     /* initialize nand_chip data structure */
  173.     nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
  174.     nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

  175.     // nand->select_chip = NULL;
  176.     // 修改为下面的语句
  177.     nand->select_chip = s3c2440_nand_select;  // 增加这个函数 s3c2440_nand_select

  178.     /* read_buf and write_buf are default */
  179.     /* read_byte and write_byte are default */
  180. #ifdef CONFIG_NAND_SPL
  181.     nand->read_buf = nand_read_buf;
  182. #endif

  183.     /* hwcontrol always must be implemented */
  184.     nand->cmd_ctrl = s3c2440_hwcontrol;

  185.     nand->dev_ready = s3c2440_dev_ready;

  186. // ECC的引入是为了解决NAND FLASH的缺陷
  187. #ifdef CONFIG_S3C2410_NAND_HWECC
  188.     nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
  189.     nand->ecc.calculate = s3c2410_nand_calculate_ecc;
  190.     nand->ecc.correct = s3c2410_nand_correct_data;
  191.     nand->ecc.mode = NAND_ECC_HW;
  192.     nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
  193.     nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
  194. #else
  195.     nand->ecc.mode = NAND_ECC_SOFT;  // 软件ECC模式
  196. #endif

  197. #ifdef CONFIG_S3C2410_NAND_BBT
  198.     nand->options = NAND_USE_FLASH_BBT;
  199. #else
  200.     nand->options = 0;
  201. #endif

  202.     debug("end of nand_init\n");

  203.     return 0;
  204. }

nand 相关说明:


分层思想:
1. nand协议层:知道发什么,因为对于协议来说,是一个标准的协议,可以写成一个通用的文件
2. 单板相关层:对于不同的控制器和nand芯片,具体怎么发送是不一样的,所以在这里我们需要根据实际使用来进行修改,就是需要添加:不同的底层操作函数
对于驱动开发来说,也是这样。

ECC主要是为了解决NAND FLASH天生的缺陷问题:位反转。



5. 测试

5.1 烧写到NOR中启动

编译,烧写到nor,nor启动,看打印输出:
这里检测到:
NOR Flash: 2M
NAND: 256M
U-Boot 2012.04.01 (Jul 16 2015 - 09:44:17)

CPUID: 32440001
FCLK:      400 MHz
HCLK:      100 MHz
PCLK:       50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: 2 MiB
NAND:  256 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   CS8900-0
SMDK2410 #



5.2 烧写到NAND中启动

利用u-boot将nor上的代码拷贝到nand上去
1. 擦出从0地址开始的512k字节大小空间
SMDK2410 # nand erase 0 80000

NAND erase: device 0 offset 0x0, size 0x80000
Erasing at 0x60000 -- 100% complete.
OK

2. 拷贝从nor的0地址开始512K字节大小的数据到nand的0地址开始处512K字节的空间
SMDK2410 # nand write 0 0 80000

NAND write: device 0 offset 0x0, size 0x80000
 524288 bytes written: OK

3. 从nand的0地址开始处的512K字节的数据拷贝到内存30000000处
SMDK2410 # nand read 30000000 0 80000

NAND read: device 0 offset 0x0, size 0x80000
 524288 bytes read: OK

4. 比较,完全相同
SMDK2410 # cmp.b 0 30000000 80000
Total of 524288 bytes were the same
SMDK2410 #


断电,从nand启动,看打印信息:
Flash: 0KB    ---->这个是nor flash的大小,为什么是0呢??思考一下 (因为NAND启动时,0地址对应的是2440内部的RAM,所以无法访问到NOR flash
NAND:  256 MiB
U-Boot 2012.04.01 (Jul 16 2015 - 09:44:17)

CPUID: 32440001
FCLK:      400 MHz
HCLK:      100 MHz
PCLK:       50 MHz
DRAM:  64 MiB
WARNING: Caches not enabled
Flash: 0KB
NAND:  256 MiB
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   CS8900-0
SMDK2410 #



总结:

1. 分析NAND检测过程
2. 在配置文件中,增加对NAND支持的宏。
3. 根据自己的硬件NAND手册,修改NAND操作函数
4. 测试



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