本节实现支持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
-
/*
-
* (C) Copyright 2006 OpenMoko, Inc.
-
* Author: Harald Welte <laforge@openmoko.org>
-
*
-
* This program is free software; you can redistribute it and/or
-
* modify it under the terms of the GNU General Public License as
-
* published by the Free Software Foundation; either version 2 of
-
* the License, or (at your option) any later version.
-
*
-
* This program is distributed in the hope that it will be useful,
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-
* GNU General Public License for more details.
-
*
-
* You should have received a copy of the GNU General Public License
-
* along with this program; if not, write to the Free Software
-
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
-
* MA 02111-1307 USA
-
*/
-
-
#include <common.h>
-
-
#include <nand.h>
-
#include <asm/arch/s3c24x0_cpu.h>
-
#include <asm/io.h>
-
-
#define S3C2410_NFCONF_EN (1<<15)
-
#define S3C2410_NFCONF_512BYTE (1<<14)
-
#define S3C2410_NFCONF_4STEP (1<<13)
-
#define S3C2410_NFCONF_INITECC (1<<12)
-
#define S3C2410_NFCONF_nFCE (1<<11)
-
#define S3C2410_NFCONF_TACLS(x) ((x)<<8)
-
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<4)
-
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<0)
-
-
#define S3C2410_ADDR_NALE 4
-
#define S3C2410_ADDR_NCLE 8
-
-
#ifdef CONFIG_NAND_SPL
-
-
/* in the early stage of NAND flash booting, printf() is not available */
-
#define printf(fmt, args...)
-
-
static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-
{
-
int i;
-
struct nand_chip *this = mtd->priv;
-
-
for (i = 0; i < len; i++)
-
buf[i] = readb(this->IO_ADDR_R);
-
}
-
#endif
-
-
-
-
/*
-
*
-
* ctrl: 表示做什么,选中/取消选中芯片,发命令还是发地址
-
*
-
* cmd: 命令值或者地址值
-
*
-
*/
-
static void s3c2440_hwcontrol(struct mtd_info *mtd, int dat, unsigned int ctrl)
-
{
-
struct nand_chip *chip = mtd->priv;
-
#if 0
-
struct s3c2410_nand *nand = s3c2410_get_base_nand();
-
#else
-
// 获取nand flash 控制器的基地址
-
struct s3c2440_nand *nand = s3c2440_get_base_nand();
-
#endif
-
-
if(ctrl & NAND_CLE)
-
{
-
/* 发命令 */
-
writeb(dat, &nand->nfcmd);
-
}
-
else if(ctrl & NAND_ALE)
-
{
-
/* 发地址 */
-
writeb(dat, &nand->nfaddr);
-
}
-
-
-
-
#if 0
-
debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
-
-
if (ctrl & NAND_CTRL_CHANGE) {
-
ulong IO_ADDR_W = (ulong)nand;
-
-
if (!(ctrl & NAND_CLE))
-
IO_ADDR_W |= S3C2410_ADDR_NCLE;
-
if (!(ctrl & NAND_ALE))
-
IO_ADDR_W |= S3C2410_ADDR_NALE;
-
-
chip->IO_ADDR_W = (void *)IO_ADDR_W;
-
-
if (ctrl & NAND_NCE) /* 使能选中*/
-
{
-
#if 0
-
writel(readl(&nand->nfconf) & ~S3C2410_NFCONF_nFCE,
-
&nand->nfconf);
-
#else
-
writel(readl(&nand->nfcont) & ~(1<<1), // nfcont bit1 clear
-
&nand->nfcont);
-
#endif
-
}
-
else /* 取消选中*/
-
{
-
#if 0
-
writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
-
&nand->nfconf);
-
-
#else
-
writel(readl(&nand->nfcont) | (1<<1),
-
&nand->nfcont);
-
-
#endif
-
}
-
-
-
#ifdef BOGUS
-
writel(readl(&nand->nfconf) | S3C2410_NFCONF_nFCE,
-
&nand->nfconf);
-
#endif /* BOGUS */
-
}
-
-
if (cmd != NAND_CMD_NONE)
-
writeb(cmd, chip->IO_ADDR_W);
-
#endif
-
-
-
}
-
-
static int s3c2440_dev_ready(struct mtd_info *mtd)
-
{
-
//struct s3c2410_nand *nand = s3c2410_get_base_nand();
-
struct s3c2440_nand *nand = s3c2440_get_base_nand();
-
-
debug("dev_ready\n");
-
return readl(&nand->nfstat) & 0x01;
-
}
-
-
-
// 参考已知代码,添加下面的这个函数
-
static void s3c2440_nand_select(struct mtd_info *mtd, int chipnr)
-
{
-
struct s3c2440_nand *nand = s3c2440_get_base_nand();
-
-
switch (chipnr) {
-
-
case -1: /* 取消选中*/
-
nand->nfcont |= (1<<1);
-
break;
-
case 0: /* 选中*/
-
nand->nfcont &=~ (1<<1);
-
break;
-
-
default:
-
BUG();
-
}
-
}
-
-
-
-
int board_nand_init(struct nand_chip *nand)
-
{
-
u_int32_t cfg;
-
u_int8_t tacls, twrph0, twrph1;
-
struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power();
-
-
#if 0 // grant modify
-
struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
-
#else
-
struct s3c2440_nand *nand_reg = s3c2440_get_base_nand();
-
#endif
-
-
debug("board_nand_init()\n");
-
-
writel(readl(&clk_power->clkcon) | (1 << 4), &clk_power->clkcon);
-
-
/* initialize hardware */
-
#if defined(CONFIG_S3C24XX_CUSTOM_NAND_TIMING)
-
tacls = CONFIG_S3C24XX_TACLS;
-
twrph0 = CONFIG_S3C24XX_TWRPH0;
-
twrph1 = CONFIG_S3C24XX_TWRPH1;
-
#else
-
-
// 根据不同的开发板,设置时间参数
-
tacls = 4;
-
twrph0 = 8;
-
twrph1 = 8;
-
#endif
-
-
#if 0
-
// 适用于2410
-
-
cfg = S3C2410_NFCONF_EN;
-
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
-
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
-
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
-
#else
-
-
/* 初始化时序 */
-
cfg = ((tacls-1) << 12) | ((twrph0-1) << 8) | ((twrph1-1) << 4);
-
#endif
-
-
writel(cfg, &nand_reg->nfconf);
-
-
/* 增加下面的语句,使能NAND FLASH控制器,初始化ECC, 禁止片选*/
-
writel((1<<4) | (1<<1) | (1<<0), &nand_reg->nfcont);
-
-
-
/* initialize nand_chip data structure */
-
nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
-
nand->IO_ADDR_W = (void *)&nand_reg->nfdata;
-
-
// nand->select_chip = NULL;
-
// 修改为下面的语句
-
nand->select_chip = s3c2440_nand_select; // 增加这个函数 s3c2440_nand_select
-
-
/* read_buf and write_buf are default */
-
/* read_byte and write_byte are default */
-
#ifdef CONFIG_NAND_SPL
-
nand->read_buf = nand_read_buf;
-
#endif
-
-
/* hwcontrol always must be implemented */
-
nand->cmd_ctrl = s3c2440_hwcontrol;
-
-
nand->dev_ready = s3c2440_dev_ready;
-
-
// ECC的引入是为了解决NAND FLASH的缺陷
-
#ifdef CONFIG_S3C2410_NAND_HWECC
-
nand->ecc.hwctl = s3c2410_nand_enable_hwecc;
-
nand->ecc.calculate = s3c2410_nand_calculate_ecc;
-
nand->ecc.correct = s3c2410_nand_correct_data;
-
nand->ecc.mode = NAND_ECC_HW;
-
nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
-
nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
-
#else
-
nand->ecc.mode = NAND_ECC_SOFT; // 软件ECC模式
-
#endif
-
-
#ifdef CONFIG_S3C2410_NAND_BBT
-
nand->options = NAND_USE_FLASH_BBT;
-
#else
-
nand->options = 0;
-
#endif
-
-
debug("end of nand_init\n");
-
-
return 0;
-
}
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. 测试
阅读(1497) | 评论(0) | 转发(0) |