TQ2440移植u-boot2016.11全过程记录-【6】NAND FLASH驱动移植

TQ2440移植u-boot2016.11-NAND FLASH驱动


修改s3c24x0的NAND控制结构体:
gedit arch/arm/include/asm/arch-s3c24x0/s3c24x0.h

找到:struct s3c24x0_nand结构体,替换为:

/* NAND FLASH (see manual chapter 6) */
struct s3c24x0_nand {
	u32	nfconf;
	u32	nfcont;
	u32	nfcmd;
	u32	nfaddr;
	u32	nfdata;
	u32	nfeccd0;
	u32	nfeccd1;
	u32	nfeccd;
	u32	nfstat;
	u32	nfstat0;
	u32	nfstat1;
};

修改nand flash驱动:
gedit drivers/mtd/nand/s3c2440_nand.c
将该文件代码全选然后替换为:

/*
 * (C) Copyright 2006 OpenMoko, Inc.
 * Author: Harald Welte <[email protected]>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>

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

#define S3C2440_NFCONT_SECCL        (1<<6)
#define S3C2440_NFCONT_MECCL        (1<<5)
#define S3C2440_NFCONT_INITECC      (1<<4)
#define S3C2440_NFCONT_nCE          (1<<1)
#define S3C2440_NFCONT_MODE         (1<<0)
#define S3C2440_NFCONF_TACLS(x)     ((x)<<12)
#define S3C2440_NFCONF_TWRPH0(x)    ((x)<<8)
#define S3C2440_NFCONF_TWRPH1(x)    ((x)<<4)

#define S3C2440_ADDR_NALE           0x08
#define S3C2440_ADDR_NCLE           0x0C

#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_to_nand(mtd);

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

static void s3c24x0_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

	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 |= S3C2440_ADDR_NCLE;
		if (!(ctrl & NAND_ALE))
			IO_ADDR_W |= S3C2440_ADDR_NALE;
		if(cmd == NAND_CMD_NONE)
			IO_ADDR_W = (ulong)&nand->nfdata;
		
		chip->IO_ADDR_W = (void *)IO_ADDR_W;

		if(ctrl & NAND_NCE)
			writel(readl(&nand->nfcont) & ~S3C2440_NFCONT_nCE, &nand->nfcont);
		else
			writel(readl(&nand->nfcont) | S3C2440_NFCONT_nCE, &nand->nfcont);
	}

	if (cmd != NAND_CMD_NONE)
		writeb(cmd, chip->IO_ADDR_W);
}

static int s3c24x0_dev_ready(struct mtd_info *mtd)
{
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
	debug("dev_ready\n");
	return readl(&nand->nfstat) & 0x01;
}

#ifdef CONFIG_S3C2440_NAND_HWECC

void s3c24x0_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();
	debug("s3c24x0_nand_enable_hwecc(0x%p, %d)\n", mtd, mode);
	writel(readl(&nand->nfcont) | S3C2440_NFCONT_INITECC, &nand->nfcont);
}

static int s3c24x0_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
{
	unsigned int mecc0 = 0;
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

	writel(readl(&nand->nfcont) | S3C2440_NFCONT_MECCL,&nand->nfcont);
	mecc0 = readl(&nand->nfeccd);
	ecc_code[0] = mecc0 & 0xff;
	ecc_code[1] = (mecc0 >> 8) & 0xff;
	ecc_code[2] = (mecc0 >>16) & 0xff;
	ecc_code[3] = (mecc0 >>24) & 0xff;
	debug("s3c24x0_nand_calculate_hwecc(0x%p): 0x%02x 0x%02x 0x%02x 0x%02x\n", mtd, ecc_code[0], ecc_code[1], ecc_code[2],ecc_code[3]);
	return 0;
}

static int s3c24x0_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
{
	u32 meccdata0 = 0, meccdata1 = 0, estat0 = 0, err_byte_addr = 0;
	int ret = -1;
	u8 repaired = 0;
	struct s3c24x0_nand *nand = s3c24x0_get_base_nand();

	meccdata0 = (read_ecc[1] << 16) | read_ecc[0];
	meccdata1 = (read_ecc[3] << 16) | read_ecc[2];
	writel(meccdata0, &nand->nfeccd0);
	writel(meccdata1, &nand->nfeccd1);

	/* read ecc status */
	estat0 = readl(&nand->nfstat0);
	switch (estat0 & 0x3)
	{
	/* no error */
	case 0:
		ret = 0;
		break;
	case 1:
		/*
		* 1bit error(correctable)
		* (nfestat0 >>7) & 0x7ff    error byte number
		* (nfestat0 >>4) & 0x7      error bit number
		*/
		err_byte_addr = (estat0 >> 7 ) & 0x7ff;
		repaired = dat[err_byte_addr] ^ (1 << ((estat0 >> 4) & 0x7));
		printf("s3c nand: 1 bit error detected at byte %ld,correcting from 0x%02x to0x%02x...OK\n", (long int) err_byte_addr, dat[err_byte_addr], repaired);
		dat[err_byte_addr] = repaired;
		ret = 1;
		break;
	case 2: /* multiple error */
	case 3: /* ecc area error */
		printf("s3c nand: ecc uncorrectable errordetected,not correctable.\n");
		ret = -1;
		break;
	}
	return ret;
}

#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 s3c24x0_nand *nand_reg = s3c24x0_get_base_nand();

	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 = 2;
	twrph0 = 3;
	twrph1 = 1;
#endif

	cfg  = S3C2440_NFCONF_TACLS(tacls - 1);
	cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
	cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
	writel(cfg, &nand_reg->nfconf);

	cfg  = S3C2440_NFCONT_SECCL;
	cfg |= S3C2440_NFCONT_MECCL;
	cfg |= S3C2440_NFCONT_MODE;
	writel(cfg, &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;

	/* 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 = s3c24x0_hwcontrol;

	nand->dev_ready = s3c24x0_dev_ready;

#ifdef CONFIG_S3C2440_NAND_HWECC
	nand->ecc.hwctl = s3c24x0_nand_enable_hwecc;
	nand->ecc.calculate = s3c24x0_nand_calculate_ecc;
	nand->ecc.correct = s3c24x0_nand_correct_data;
	nand->ecc.mode = NAND_ECC_HW;
	nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
	nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
	nand->ecc.strength = 1;
#else
	nand->ecc.mode = NAND_ECC_SOFT;
#endif

#ifdef CONFIG_S3C2440_NAND_BBT
	nand->bbt_options |= NAND_BBT_USE_FLASH;
#endif

	debug("end of nand_init\n");

	return 0;
}

修改NAND FLASH的全局宏配置:
gedit include/configs/tq2440.h
定位到的NAND FLASH的宏配置:

/*
 * NAND configuration
 */
#ifdef CONFIG_CMD_NAND
#define CONFIG_NAND_S3C2440
#define CONFIG_SYS_S3C2440_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE	1
#define CONFIG_SYS_NAND_BASE		0x4E000000
#endif

替换为:

/*
 * NAND configuration
 */
#ifdef CONFIG_CMD_NAND
#define CONFIG_NAND_S3C2440
#define CONFIG_S3C2440_NAND_HWECC
#define CONFIG_SYS_S3C2440_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE	1
#define CONFIG_SYS_NAND_BASE		0x4E000000
#define CONFIG_SYS_NAND_ECCSIZE           2048     /* 单次校验字节长度 */
#define CONFIG_SYS_NAND_ECCBYTES             4     /* ECC字节长度     */
#endif

编译并使用tftpboot下载到开发板0x30008000地址处并运行,可以看到已经正确识别出NAND:在这里插入图片描述
下面开始进行NAND的读写测试:

  • 擦除起始地址开始的2M字节:
    nand erase 0x0 0x200000
  • 读取内存0x32000000地址处开始的4K字节写入到NAND FLASH起始地址:
    nand write 0x32000000 0x0 0x1000
  • 读取NAND FLASH 起始地址处开始的4K字节的数据放到内存0x31000000地址处:
    nand read 0x31000000 0x0 0x1000
  • 比较是否一样:
    cmp.b 0x32000000 0x0 0x1000

下面开始对NAND FLASH进行分区设置:

将代码:

/*
 * NAND configuration
 */
#ifdef CONFIG_CMD_NAND
#define CONFIG_NAND_S3C2440
#define CONFIG_S3C2440_NAND_HWECC
#define CONFIG_SYS_S3C2440_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE	1
#define CONFIG_SYS_NAND_BASE		0x4E000000
#define CONFIG_SYS_NAND_ECCSIZE           2048     /* 单次校验字节长度 */
#define CONFIG_SYS_NAND_ECCBYTES             4     /* ECC字节长度     */
#endif

替换为:

/*
 * NAND configuration
 */
#ifdef CONFIG_CMD_NAND

#define CONFIG_NAND_S3C2440
#define CONFIG_S3C2440_NAND_HWECC
#define CONFIG_SYS_S3C2440_NAND_HWECC
#define CONFIG_SYS_MAX_NAND_DEVICE	1
#define CONFIG_SYS_NAND_BASE		0x4E000000
#define CONFIG_SYS_NAND_ECCSIZE           2048     /* 单次校验字节长度 */
#define CONFIG_SYS_NAND_ECCBYTES             4     /* ECC字节长度     */

/* 默认名称 */
#define MTDIDS_DEFAULT "nand0=tq2440-nand.0"

/* NAND FLASH 分区情况如下所示
 * +--------------------------------------------------------------------+
 * | 512k u-boot-spl | 1m u-boot | 256k env params | 4m kernel | rootfs |
 * +--------------------------------------------------------------------+
 */
#define MTDPARTS_DEFAULT "mtdparts=tq2440-nand.0:512k(u-boot-spl)," \
                         "1m(u-boot)," \
                         "256k(params)," \
                         "4m(kernel)," \
                         "-(yaffs2)"

/* 默认启动参数 */
#define CONFIG_BOOTARGS "root=/dev/mtdblock4 rootfstype=yaffs2 init=/linuxrc console=ttySAC0,115200"

/* 默认启动命令,nand读取kernel分区的内容放到内存0x32000000处并跳转运行 */
#define CONFIG_BOOTCOMMAND "nand read 0x32000000 kernel;bootm 0x32000000"
#endif

设置环境变量保存到NAND FLASH,先屏蔽原本的环境变量存入NOR FLASH的设置:

#if 0
#define CONFIG_ENV_ADDR			(CONFIG_SYS_FLASH_BASE + 0x100000)		/* 环境变量保存位置  */
#define CONFIG_ENV_IS_IN_FLASH											/* 定义该宏后环境变量保存入NOR FLASH */
#define CONFIG_ENV_SIZE			0x10000									/* 环境变量大小为64K */
#define CONFIG_ENV_OVERWRITE											/* 允许覆写环境变量 */
#endif

在下方添加环境变量存入NAND的配置:

#define CONFIG_ENV_IS_IN_NAND								/* 定义该宏表示环境变量存入NAND FLASH */
#define CONFIG_ENV_OFFSET 0x00100000						/* 环境变量保存位置 */
#define CONFIG_ENV_SIZE 0x40000								/* 环境变量大小为256K */
#define CONFIG_ENV_RANGE CONFIG_ENV_SIZE					/* 环境变量范围限制 */

重新编译后下载到开发板并运行:

加载默认分区:

  • mtd default

查看分区情况:

  • mtd

结果:
在这里插入图片描述


ends…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章