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…

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