tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——NAND 8位硬件ECC

这节我们实现nand的ecc,保存环境变量到nand flash 中。然后把我们之前的led灯烧写到nand flash 中,开机启动,在 tiny210.h 中定义宏 CONFIG_S5PV210_NAND_HWECC、CONFIG_SYS_NAND_ECCSIZE、CONFIG_SYS_NAND_ECCBYTES

CONFIG_SYS_NAND_ECCSIZE 定义了消息长度,即每多少字节进行 1 次 ECC 校验

CONFIG_SYS_NAND_ECCBYTES 定义为 13Byte,将 drivers/mtd/nand/s5pv210_nand.c 中的 CONFIG_S3C2410_NAND_HWECC 替换为CONFIG_S5PV210_NAND_HWECC,我们只进行 ECC 校验写,ECC 校验读使用三星提供的函数,我们必须按照三星手册规定的 ECC 校验码在
Spare Field  中的存储格式进行存储。

因此我们需要自定义 nand_ecclayout 结构体,这个结构体描述了如何存储 ECC 数据,同时将这个结构体赋值给 nand->ecc.layout

其他的代码请看源码:

/*
 * (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/nand_reg.h>
#include <asm/io.h>

#define MP0_1CON  (*(volatile u32 *)0xE02002E0)
#define	MP0_3CON  (*(volatile u32 *)0xE0200320)
#define	MP0_6CON  (*(volatile u32 *)0xE0200380)

/* modied by shl */
static void s5pv210_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
	struct nand_chip *chip = mtd->priv;
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	debug("hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl);
	ulong IO_ADDR_W = (ulong)nand;
	if (ctrl & NAND_CTRL_CHANGE) {

		if (ctrl & NAND_CLE)
			IO_ADDR_W = IO_ADDR_W | 0x8;	/* Command Register  */
		else if (ctrl & NAND_ALE)
			IO_ADDR_W = IO_ADDR_W | 0xC;	/* Address Register */

		chip->IO_ADDR_W = (void *)IO_ADDR_W;

		if (ctrl & NAND_NCE)	/* select */
			writel(readl(&nand->nfcont) & ~(1 << 1), &nand->nfcont);
		else					/* deselect */
			writel(readl(&nand->nfcont) | (1 << 1), &nand->nfcont);
	}

	if (cmd != NAND_CMD_NONE)
		writeb(cmd, chip->IO_ADDR_W);
	else
		chip->IO_ADDR_W = &nand->nfdata;

}

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

#ifdef CONFIG_S5PV210_NAND_HWECC
void s5pv210_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	debug("s5pv210_nand_enable_hwecc(%p, %d)\n", mtd, mode);

	writel(readl(&nand->nfconf) | (0x3 << 23), &nand->nfconf);

	if (mode == NAND_ECC_READ)
	{
	}
	else if (mode == NAND_ECC_WRITE)
	{
		/* set 8/12/16bit Ecc direction to Encoding */
		writel(readl(&nand->nfecccont) | (0x1 << 16), &nand->nfecccont);
		/* clear 8/12/16bit ecc encode done */
		writel(readl(&nand->nfeccstat) | (0x1 << 25), &nand->nfeccstat);
	}

	/* Initialize main area ECC decoder/encoder */
	writel(readl(&nand->nfcont) | (0x1 << 5), &nand->nfcont);

	/* The ECC message size(For 512-byte message, you should set 511)
	* 8-bit ECC/512B */
	writel((511 << 16) | 0x3, &nand->nfeccconf);

	writel(readl(&nand->nfstat) | (0x1 << 4) | (0x1 << 5), &nand->nfstat);

	/* Initialize main area ECC decoder/ encoder */
	writel(readl(&nand->nfecccont) | (0x1 << 2), &nand->nfecccont);

	/* Unlock Main area ECC   */
	writel(readl(&nand->nfcont) & ~(0x1 << 7), &nand->nfcont);
}

/* modied by shl */
static int s5pv210_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
				      u_char *ecc_code)
{
	struct s5pv210_nand *nand = (struct s5pv210_nand *)samsung_get_base_nand();
	u32 nfeccprgecc0 = 0, nfeccprgecc1 = 0, nfeccprgecc2 = 0, nfeccprgecc3 = 0;

	/* Lock Main area ECC */
	writel(readl(&nand->nfcont) | (1 << 7), &nand->nfcont);

	/* 读取13 Byte的Ecc Code */
	nfeccprgecc0 = readl(&nand->nfeccprgecc0);
	nfeccprgecc1 = readl(&nand->nfeccprgecc1);
	nfeccprgecc2 = readl(&nand->nfeccprgecc2);
	nfeccprgecc3 = readl(&nand->nfeccprgecc3);

	ecc_code[0] = nfeccprgecc0 & 0xff;
	ecc_code[1] = (nfeccprgecc0 >> 8) & 0xff;
	ecc_code[2] = (nfeccprgecc0 >> 16) & 0xff;
	ecc_code[3] = (nfeccprgecc0 >> 24) & 0xff;
	ecc_code[4] = nfeccprgecc1 & 0xff;
	ecc_code[5] = (nfeccprgecc1 >> 8) & 0xff;
	ecc_code[6] = (nfeccprgecc1 >> 16) & 0xff;
	ecc_code[7] = (nfeccprgecc1 >> 24) & 0xff;
	ecc_code[8] = nfeccprgecc2 & 0xff;
	ecc_code[9] = (nfeccprgecc2 >> 8) & 0xff;
	ecc_code[10] = (nfeccprgecc2 >> 16) & 0xff;
	ecc_code[11] = (nfeccprgecc2 >> 24) & 0xff;
	ecc_code[12] = nfeccprgecc3 & 0xff;

	debug("s5pv210_nand_calculate_hwecc(%p,):\n"
		"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n"
		"0x%02x 0x%02x 0x%02x\n", mtd , ecc_code[0], ecc_code[1], ecc_code[2],
		ecc_code[3], ecc_code[4], ecc_code[5], ecc_code[6], ecc_code[7],
		ecc_code[8], ecc_code[9], ecc_code[10], ecc_code[11], ecc_code[12]);

	return 0;
}

/* add by shl */
#define NF8_ReadPage_Adv(a,b,c) (((int(*)(u32, u32, u8*))(*((u32 *)0xD0037F90)))(a,b,c))
static int s5pv210_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
				uint8_t *buf, int oob_required, int page)
{
	/* tiny210使用的NAND FLASH一个块64页 */
	return NF8_ReadPage_Adv(page / 64, page % 64, buf);
}

static int s5pv210_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("s5pv210_nand_correct_data: not implemented\n");
	return -1;
}
#endif

/*
 * add by shl
 * nand_select_chip
 * @mtd: MTD device structure
 * @ctl: 0 to select, -1 for deselect
 *
 * Default select function for 1 chip devices.
 */
static void s5pv210_nand_select_chip(struct mtd_info *mtd, int ctl)
{
	struct nand_chip *chip = mtd->priv;

	switch (ctl) {
	case -1:	/* deselect the chip */
		chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
		break;
	case 0:		/* Select the chip */
		chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
		break;

	default:
		BUG();
	}
}

/* add by shl */
static struct nand_ecclayout nand_oob_64 = {
	.eccbytes = 52,		/* 2048 / 512 * 13 */
	.eccpos = {	12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
				22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
				32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
				42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
				52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
				62, 63},
	/* 0和1用于保存坏块标记,12~63保存ecc,剩余2~11为free */
	.oobfree = {
			{.offset = 2,
			.length = 10}
		}
};

/* modied by shl */
int board_nand_init(struct nand_chip *nand)
{
	u32 cfg = 0;
	struct s5pv210_nand *nand_reg = (struct s5pv210_nand *)(struct s5pv210_nand *)samsung_get_base_nand();

	debug("board_nand_init()\n");

	/* initialize hardware */
	/* HCLK_PSYS=133MHz(7.5ns) */
	cfg =	(0x1 << 23) |	/* Disable 1-bit and 4-bit ECC */
			/* 下面3个时间参数稍微比计算出的值大些(我这里依次加1),否则读写不稳定 */
			(0x3 << 12) |	/* 7.5ns * 2 > 12ns tALS tCLS */
			(0x2 << 8) | 	/* (1+1) * 7.5ns > 12ns (tWP) */
			(0x1 << 4) | 	/* (0+1) * 7.5 > 5ns (tCLH/tALH) */
			(0x0 << 3) | 	/* SLC NAND Flash */
			(0x0 << 2) |	/* 2KBytes/Page */
			(0x1 << 1);		/* 5 address cycle */

	writel(cfg, &nand_reg->nfconf);

	writel((0x1 << 1) | (0x1 << 0), &nand_reg->nfcont);
	/* Disable chip select and Enable NAND Flash Controller */

	/* Config GPIO */
	MP0_1CON &= ~(0xFFFF << 8);
	MP0_1CON |= (0x3333 << 8);
	MP0_3CON = 0x22222222;
	MP0_6CON = 0x22222222;

	/* initialize nand_chip data structure */
	nand->IO_ADDR_R = (void *)&nand_reg->nfdata;
	nand->IO_ADDR_W = (void *)&nand_reg->nfdata;

	nand->select_chip = s5pv210_nand_select_chip;

	/* read_buf and write_buf are default */
	/* read_byte and write_byte are default */

	/* hwcontrol always must be implemented */
	nand->cmd_ctrl = s5pv210_hwcontrol;

	nand->dev_ready = s5pv210_dev_ready;

#ifdef CONFIG_S5PV210_NAND_HWECC
	nand->ecc.hwctl = s5pv210_nand_enable_hwecc;
	nand->ecc.calculate = s5pv210_nand_calculate_ecc;
	nand->ecc.correct = s5pv210_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;
	/* add by shl */
	nand->ecc.layout = &nand_oob_64;
	nand->ecc.read_page = s5pv210_nand_read_page_hwecc;
#else
	nand->ecc.mode = NAND_ECC_SOFT;
#endif

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

	debug("end of nand_init\n");

	return 0;
}

重新编译,成功生成 u-boot.bin,将它烧写到 SD 卡的扇区 32,从 SD 卡启动开发板:

下面进行 NAND 启动试验,将之前的led程序烧写到 NAND,然后从 NAND 启动,可以看到 LED 全亮的效果。首先我们先编译
led.c,生成 led.bin,然后 添加 16B 的头信息生成 210.bin,然后将 210.bin 拷贝到 tftp 服务器目录。

然后使用最新的 u-boot 将 210.bin 烧写到 NAND 的第 0 页,然后从 NAND 启动

从 NAND 启动可以看到 4 个 LED 全亮。

时间: 2024-08-01 04:16:43

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——NAND 8位硬件ECC的相关文章

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——NAND 启动

我们知道 s5pv210启动方式有很多种,sd卡和nand flash 启动就是其中的两种,前面我们实现的都是基于sd卡启动,这节我们开始实现从nand flash 启动: 从 NAND 启动 u-boot,需要 BL1 初始化 NAND 控制器,然后从 NAND 拷贝 BL2 到 DDR 内存.这里的BL1 即我们移植的 u-boot-spl.bin,BL2 即我们移植的 u-boot.bin.在 u-boot.bin 中的 NAND 驱动比较大,它包含了很多功能,而 u-boot-spl.b

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——NAND添加分区

这里的分区只是为了操作的方便.假设有个分区 kernel,其地址区间为 0x20000~0x320000,其大小为 0x300000 在没有分区的情况下,对这块区间的操作如下: nand erase 20000 300000        擦除操作 nand write 20000000 20000 300000    写操作 nand read 20000000 20000 300000    读操作 而有了分区的情况下,操作将变得非常简单,如下(其中 kernel 为分区名) nand er

tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——NAND 启动

我们知道 s5pv210启动方式有非常多种,sd卡和nand flash 启动就是当中的两种,前面我们实现的都是基于sd卡启动,这节我们開始实现从nand flash 启动: 从 NAND 启动 u-boot,须要 BL1 初始化 NAND 控制器,然后从 NAND 拷贝 BL2 到 DDR 内存.这里的BL1 即我们移植的 u-boot-spl.bin,BL2 即我们移植的 u-boot.bin.在 u-boot.bin 中的 NAND 驱动比較大,它包括了非常多功能,而 u-boot-spl

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植NAND FLASH

这节我们开始移植nand flash:通过查看帮助文档 doc/README.nand,要支持 NAND,需要配置CONFIG_CMD_NAND我们修改 tiny210.h,把 CONFIG_CMD_ONENAND 屏蔽掉,同时加上CONFIG_CMD_NAND: 编译出错 ,没有定义 CONFIG_SYS_MAX_NAND_DEVICE,最大 NAND 设备数,我们的板子只有 1 个 NAND,将其 定义为 1 再次编译,出错:未定义 NAND 的基地址,查看 S5PV210 手册, NAND

tiny210(s5pv210)移植u-boot(基于 2014.4 版本号)——移植u-boot.bin(打印串口控制台)

在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的信息打印. 在上节.我们看到调用 relocate_code 重定位.在 u-boot 的帮助文档 doc/README.arm-relocation 中对重定位有说明. u-boot 为了生成位置无关码,在链接时指定了-pie 选项,这个选项在 u-boot-2014.04/arch/arm/config.mk 中指定: 当使用-pie 选项后.链接器会生成一个修正表(fixup  tables).在终于的二进制文件 u-boot

tiny210(s5pv210)移植u-boot(基于 2014.4 版本)——移植u-boot.bin(打印串口控制台)

在之前我们移植的代码中,都没看到明显的效果,这节我们实现控制台的打印信息. 在上节,我们看到调用 relocate_code 重定位.在 u-boot 的帮助文档 doc/README.arm-relocation 中对重定位有说明.u-boot 为了生成位置无关码,在链接时指定了-pie 选项,这个选项在 u-boot-2014.04/arch/arm/config.mk 中指定: 当使用-pie 选项后,链接器会生成一个修正表(fixup  tables),在最终的二进制文件 u-boot.

s5pv210 移植 ubuntu(uboot + linux3.9.7 + ubuntu12.11 + xfce)

手里的s5pv210有两年了,性能也远远不如当下的应用处理器 但是跑比较简单的系统还是绰绰有余的 给s5pv210 移植 linaro ubuntu根文件系统 12.11 + xfce桌面系统,运行速度还是可以的,能上网. uboot + linux3.9.7 + ubuntu12.11 + xfce 可以作为远程tiny服务器. show下: 桌面 浏览器和设置界面 睡眠时的屏保界面

u-boot-2016.03 在mini2440上移植之nandflash 硬件ecc

MINI2440 开发板使用的是8bit,256M blocksize= 128k,pagesize =2k的nandflash. 宽带为8bit ,由S3C2440 datasheet 可知硬件生产的ecc为4byte. S3C2440 硬件ecc 操作流程: 1.先读出NFMECC0寄存器中由硬件生产的ecc data. 2.将读出的ecc数据,进行处理之后,分别写入NFMECCD0和NFMECCD1寄存器, 硬件自动检测,检测结果可从NFESTAT0 寄存器读取. 3. 读取NFESTAT

基于vs2005以上版本Qt程序发布的注意事项(讲了manifest的问题)

最近发现了一个非常恼人的程序deployment的问题,估计大家有可能也会遇到,特此memo. 问题的出现我觉得主要还是微软搞的花头太多, 一个不知所谓的manifest文件让本来简单的程序发布变得困难重重. 找了找关于manifest的介绍,貌似这个文件是用来描述程序或者库的依赖关系, 特别是对程序依赖的版本进行描述, 这样系统可以通过manifest的内容找到正确的库版本. 理论上讲这个dd确实是不错, 可以解决版本不兼容的问题, 保证程序运行的时候用的是指定版本的库. 不过实际操作起来麻烦