U-Boot 的移植入门(2)——nand flash识别与操作
来源:互联网 发布:淘宝twizzlers扭扭糖 编辑:程序博客网 时间:2024/04/30 16:20
第三步、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组织已不推荐使用。事实上,此版中,S3C2410构架已不支持对nand_leagcy,因此,在移植中,是用的不定义CFG_NAND_LEGACY的方式,即非nand_leagcy方式。此版的u-boot已自带board_nand_init(),此函数在drivers/mtd/nand/s3c2410_nand.c中实现。并且此版已不支持定义CFG_NAND_LEGACY,如定义此宏,则编译是会报 #error "U-Boot legacy NAND support not available
for S3C2410"的错误。
我们追踪关于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_S3C2410
#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/s3c2410_nand.c文件中的board_nand_init函数,由该函数来完成针对特定的板子的nand控制器的初始化。这个文件也就是针对特定板子相关的nand部分代码,移植工作主要修改的也就是这个文件了。根据手册,仔细修改这个文件中的几个函数。注意,S3C2410_ADDR_NALE是用来设置命令寄存器的,而S3C2410_ADDR_NCLE则是用来设置地址寄存器的。同时还要根据手册正确定义结构体struct s3c2410_nand。完整文件为:
#include
#include
#include <s3c2410.h>
#include
#define NF_BASE 0x4E000000
#define S3C2410_NFCONT_EN (1<<0)
#define S3C2410_NFCONT_INITECC (1<<4)
#define S3C2410_NFCONF_nFCE (1<<1)
#define S3C2410_NFCONT_MAINECCLOCK (1<<5)
#define S3C2410_NFCONF_TACLS(x) ((x)<<12)
#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8)
#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4)
#define S3C2410_ADDR_NALE 0x08
#define S3C2410_ADDR_NCLE 0x0C
ulong IO_ADDR_W = NF_BASE;
static void s3c2410_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *chip = mtd->priv;
struct s3c2410_nand *nand = s3c2410_get_base_nand();
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 |= S3C2410_ADDR_NCLE;
if (!(ctrl & NAND_ALE))
IO_ADDR_W |= S3C2410_ADDR_NALE;
if (ctrl & NAND_NCE)
writel(readl(&nand->NFCONT) & ~S3C2410_NFCONF_nFCE,
&nand->NFCONT);
else
writel(readl(&nand->NFCONT) | S3C2410_NFCONF_nFCE,
&nand->NFCONT);
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, (void *)IO_ADDR_W);
}
static int s3c2410_dev_ready(struct mtd_info *mtd)
{
struct s3c2410_nand *nand = s3c2410_get_base_nand();
debugX(1, "dev_ready\n");
return readl(&nand->NFSTAT) & 0x01;
}
#ifdef CONFIG_S3C2410_NAND_HWECC
void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand *nand = s3c2410_get_base_nand();
debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode);
writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT);
}
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
ecc_code[0] = NFECC0;
ecc_code[1] = NFECC1;
ecc_code[2] = NFECC2;
debugX(1, "s3c2410_nand_calculate_hwecc(%p,): 0x%02x 0x%02x 0x%02x\n",
mtd , ecc_code[0], ecc_code[1], ecc_code[2]);
return 0;
}
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
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("s3c2410_nand_correct_data: not implemented\n");
return -1;
}
#endif
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();
struct s3c2410_nand *nand_reg = s3c2410_get_base_nand();
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 |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
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 = s3c2410_hwcontrol;
nand->dev_ready = s3c2410_dev_ready;
#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_HW3_512;
#else
nand->ecc.mode = NAND_ECC_SOFT;
#endif
#ifdef CONFIG_S3C2410_NAND_BBT
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_S3C2410
查看drivers/mtd/nand的Makefile文件能看到:
COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
include $(TOPDIR)/config.mk
也就是说这个Makefile会包含顶层目录内的config.mk文件,而在顶层目录内的config.mk文件又能看到:
sinclude $(OBJTREE)/include/autoconf.mk
这个文件是在编译的时候根据配置文件自动生成的,所以,为了使用s3c2410_nand.c文件,需要定义这个宏。
自带的S3C2410的s3c2410_hwcontrol函数有错。在此函数中,把chip->IO_ADDR_W值
改写了,导致在写数据时出现错误。将此错误修正后,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校验不是由同一软件产生所致。
- U-Boot 的移植入门(2)——nand flash识别与操作
- u-boot-2009.08在飞凌OK2440/FL2440上的移植(四)——让u-boot支持nand flash识别与操作
- U-Boot移植——Nand Flash
- U-Boot移植——Nand Flash启动
- u-boot-2011.03在mini2440/micro2440上的移植(五)——支持Nand Flash
- u-boot移植后的 nand flash命令
- u-boot移植--4、对于NAND FLASH的支持
- tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植NAND FLASH
- tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植NAND FLASH
- u-boot-2011.03在mini2440/micro2440上的移植(七)——支持Nand Flash启动
- u-boot-2009.08在mini2440上的移植(三)---增加nand flash功能——调试心得
- u-boot-2009.08在飞凌OK2440/FL2440上的移植(五)——让u-boot从nand flash启动
- 移植u-boot-2011.03到S3C2440(utu2440)的方法与步骤###7.NAND FLASH部分移植和支持NAND FLASH启动和读写
- U-boot操作Flash (NOR, NAND & SPI)
- U-Boot操作Flash (NOR, NAND & SPI)
- U-Boot操作Flash (NOR, NAND & SPI)
- u-boot:从NOR FLASH启动并支持NAND FLASH读写的移植
- 基于TQ2440的u-boot 1.1.6移植(二)(支持nor flash nand flash )
- java中list转数组操作
- 实现jqgrid 行编辑,级联查询,并点击按钮保存
- JMeter基础之-使用技巧
- ScalaReference路径
- Object size checking to prevent (some) buffer overflows
- U-Boot 的移植入门(2)——nand flash识别与操作
- ibatis 批处理
- hdu1025
- cisco路由器密码恢复
- Mac上更新Ruby
- java回调函数
- jmeter 脚本增强(参数化)
- 领土划分
- 使用shiro框架,AuthorizationInfo方法没有被执行的问题