2015年(40)
分类: 嵌入式
2015-04-27 20:52:27
第三步、nand flash识别与操作
提供对于Nand的支持,仅仅是提供对于nand操作的支持。
首先,要说明一下CFG_NAND_LEGACY的使用。在u-boot的/drivers/mtd/下有两个目录,分别是nand和nand_legacy。在nand目录下的是nand的初始化函数和nand的操作读写函数,是移植的linux的mtd构架。此目录下的文件,只有在定义了CFG_CMD_NAND宏和没有定义CFG_NAND_LEGACY宏的情况下才会被编译。在nand_leagcy目录下的文件也是是实现nand相关操作命令,如read,write等命令的功能,但不是使用linux的mtd构架。此目录下的文件,只有在定义了CFG_CMD_NAND和定义了CFG_NAND_LEGACY宏的情况下才会定义。此目录下的文件u-boot组织已不推荐使用。事实上,此版中,S
for S
我们追踪关于Nand的启动初始化代码的执行流,我们从lib_arm目录下的board.c文件开始。启动代码的汇编部分结束,便会执行该文件中的start_armboot函数。在start_armboot函数中,我们看到这样的语句:
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init(); /* go init
the NAND */
#endif
也就是说,如果定义了宏CONFIG_CMD_NAND,将会在启动的时候执行初始化Nand的代码,也即提供对于Nand的支持。我们现在配置文件include/configs/mini2440.h 文件中添加这个宏,编译,然后,会报错,我们再根据手册,来定义其他的宏:
#if
defined(CONFIG_CMD_NAND)
#define CONFIG_NAND_S
#define
CONFIG_SYS_NAND_BASE 0x4E000000
#define
CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of NAND devices */
#define SECTORSIZE 512
#define SECTORSIZE_2K
2048
#define
NAND_SECTOR_SIZE SECTORSIZE
#define
NAND_SECTOR_SIZE_2K SECTORSIZE_2K
#define NAND_BLOCK_MASK
511
#define
NAND_BLOCK_MASK_2K 2047
#define NAND_MAX_CHIPS
1
#define
CONFIG_MTD_NAND_VERIFY_WRITE
#define
CONFIG_SYS_64BIT_VSPRINTF /* needed
for nand_util.c */
#endif /* CONFIG_CMD_NAND */
然后接着追踪执行过程。
nand_init函数在drivers/mtd/nand/nand.c文件中。
而nand_init函数则主要执行相同文件中的nand_init_chip函数。
在nand_init_chip函数中调用drivers/mtd/nand/s
#include
#include
#include 3c2410.h>
#include
#define NF_BASE 0x4E000000
#define S
#define S
#define S
#define S
#define S
#define S
#define S
#define S
#define S
ulong IO_ADDR_W = NF_BASE;
static void s
{
struct nand_chip *chip = mtd->priv;
struct s
debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd,
ctrl);
if (ctrl & NAND_CTRL_CHANGE) {
IO_ADDR_W = (ulong)nand;
if (!(ctrl & NAND_CLE))
IO_ADDR_W |= S
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S
if (ctrl & NAND_NCE)
writel(readl(&nand->NFCONT) & ~S
&nand->NFCONT);
else
writel(readl(&nand->NFCONT) | S
&nand->NFCONT);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, (void *)IO_ADDR_W);
}
static int s
{
struct s
debugX(1, "dev_ready\n");
return readl(&nand->NFSTAT) & 0x01;
}
#ifdef CONFIG_S
void s
{
struct s
debugX(1, "s
writel(readl(&nand->NFCONT) | S
}
static int s
u_char *ecc_code)
{
ecc_code[0] = NFECC0;
ecc_code[1] = NFECC1;
ecc_code[2] = NFECC2;
debugX(1, "s
mtd , ecc_code[0],
ecc_code[1], ecc_code[2]);
return 0;
}
static int s
u_char *read_ecc, u_char *calc_ecc)
{
if (read_ecc[0] == calc_ecc[0] &&
read_ecc[1] == calc_ecc[1] &&
read_ecc[2] == calc_ecc[2])
return 0;
printf("s
return -1;
}
#endif
int board_nand_init(struct nand_chip *nand)
{
u_int32_t cfg;
u_int8_t tacls, twrph0, twrph1;
struct s
struct s
debugX(1, "board_nand_init()\n");
writel(readl(&clk_power->CLKCON) | (1 << 4),
&clk_power->CLKCON);
/* initialize hardware */
twrph0 = 4;
twrph1 = 2;
tacls = 0;
cfg = 0;
cfg |= S
cfg |= S
cfg |= S
writel(cfg, &nand_reg->NFCONF);
cfg =
(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0);
writel(cfg, &nand_reg->NFCONT);
/* initialize nand_chip data structure */
nand->IO_ADDR_R = nand->IO_ADDR_W = (void
*)&nand_reg->NFDATA;
/* read_buf and write_buf are default */
/* read_byte and write_byte are default */
/* hwcontrol always must be implemented */
nand->cmd_ctrl = s
nand->dev_ready = s
#ifdef CONFIG_S
nand->ecc.hwctl = s
nand->ecc.calculate = s
nand->ecc.correct = s
nand->ecc.mode = NAND_ECC_HW3_512;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S
nand->options = NAND_USE_FLASH_BBT;
#else
nand->options = 0;
#endif
debugX(1, "end of nand_init\n");
return 0;
}
改写完毕后,u-boot可以识别出nand flash芯片是64MB的,但还不能识别是什么芯片。
在/driver/mtd/nand/nand_base.c中的nand_get_flash_type函数结尾,修改MTDDEBUG语句,改为printf,再编译,可以正常显示芯片了。
几点注意说明
1、CONFIG_MTD_NAND_VERIFY_WRITE
u-boot自带的nand-flash驱动(不定义nand_leagcy),是基于mtd驱动的。在默认情况下,不进行写入正确与否的校验。要定义CONFIG_MTD_NAND_VERIFY_WRITE宏才能进行写入校验。关于ECC校验,mtd驱动默认是用sotf_ecc的。
2、#define CONFIG_NAND_S
查看drivers/mtd/nand的Makefile文件能看到:
COBJS-$(CONFIG_NAND_S
include
$(TOPDIR)/config.mk
也就是说这个Makefile会包含顶层目录内的config.mk文件,而在顶层目录内的config.mk文件又能看到:
sinclude
$(OBJTREE)/include/autoconf.mk
这个文件是在编译的时候根据配置文件自动生成的,所以,为了使用s
自带的S
改写了,导致在写数据时出现错误。将此错误修正后,nand write才可以正常工作。修正方法是使用一全局变量替代chip->IO_ADDR_W。
接下来,在rat2440.h中加入#define CONFIG_ENV_IS_IN_NAND 1注掉原来的#define
CONFIG_ENV_IS_IN_FLASH 1,加入#define CONFIG_ENV_OFFSET
0x30000 注掉原来的#define CFG_ENV_OFFSET 0x30000。编译。saveenv功能也正常了。
至此,nand-flash驱动移植完成。
测试,nand write 0x30000000 0x40000 0x40000时,成功。用nand read也成功读出。此处要说明的,如果用vivi烧写信息到nand中,再用u-boot读取,会报错,应该是ECC校验不是由同一软件产生所致。