kernel(四)NAND 8位硬件ECC

mach-smdkv210.c 中添加头文件<linux/mtd/mtd.h>


添加 nand_ecclayout 定义 OOB 布局,同时赋值给 smdk_nand_sets, 设置 disable_ecc 属性为假


修改 NAND 驱动 drivers/mtd/nand/s3c2410.c,里面所用到的寄存器索引都在arch/arm/plat-samsung/include/plat/regs-nand.h 中定义,对 s3c2410.c 的修改主要是增加几个函数

添加



/* add by JerryGou */
static void s5pv210_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
	u32 cfg;
	
	if (mode == NAND_ECC_READ)
	{
		/* set 8/12/16bit Ecc direction to Encoding */
		cfg = readl(info->regs + S5PV210_NFECCCONT) & (~(0x1 << 16));
		writel(cfg, info->regs + S5PV210_NFECCCONT);
		
		/* clear 8/12/16bit ecc encode done */
		cfg = readl(info->regs + S5PV210_NFECCSTAT) | (0x1 << 24);
		writel(cfg, info->regs + S5PV210_NFECCSTAT);
	}
	else
	{
		/* set 8/12/16bit Ecc direction to Encoding */
		cfg = readl(info->regs + S5PV210_NFECCCONT) | (0x1 << 16);
		writel(cfg, info->regs + S5PV210_NFECCCONT);
		
		/* clear 8/12/16bit ecc encode done */
		cfg = readl(info->regs + S5PV210_NFECCSTAT) | (0x1 << 25);
		writel(cfg, info->regs + S5PV210_NFECCSTAT);
	}
	
	/* Initialize main area ECC decoder/encoder */
	cfg = readl(info->regs + S5PV210_NFCONT) | (0x1 << 5);
	writel(cfg, info->regs + S5PV210_NFCONT);
	
	/* The ECC message size(For 512-byte message, you should set 511) 8-bit ECC/512B  */
	writel((511 << 16) | 0x3, info->regs + S5PV210_NFECCCONF);
			

	/* Initialize main area ECC decoder/ encoder */
	cfg = readl(info->regs + S5PV210_NFECCCONT) | (0x1 << 2);
	writel(cfg, info->regs + S5PV210_NFECCCONT);
	
	/* Unlock Main area ECC   */
	cfg = readl(info->regs + S5PV210_NFCONT) & (~(0x1 << 7));
	writel(cfg, info->regs + S5PV210_NFCONT);
}

/* add by JerryGou */
static int s5pv210_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
				      u_char *ecc_calc)
{
	u32 cfg;
	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
	u32 nfeccprgecc0 = 0, nfeccprgecc1 = 0, nfeccprgecc2 = 0, nfeccprgecc3 = 0;
	
	/* Lock Main area ECC */
	cfg = readl(info->regs + S5PV210_NFCONT) | (0x1 << 7);
	writel(cfg, info->regs + S5PV210_NFCONT);
	
	if (ecc_calc)	/* NAND_ECC_WRITE */
	{
		/* ECC encoding is completed  */
		while (!(readl(info->regs + S5PV210_NFECCSTAT) & (1 << 25)));
			
		/* 读取13 Byte的Ecc Code */
		nfeccprgecc0 = readl(info->regs + S5PV210_NFECCPRGECC0);
		nfeccprgecc1 = readl(info->regs + S5PV210_NFECCPRGECC1);
		nfeccprgecc2 = readl(info->regs + S5PV210_NFECCPRGECC2);
		nfeccprgecc3 = readl(info->regs + S5PV210_NFECCPRGECC3);

		ecc_calc[0] = nfeccprgecc0 & 0xFF;
		ecc_calc[1] = (nfeccprgecc0 >> 8) & 0xFF;
		ecc_calc[2] = (nfeccprgecc0 >> 16) & 0xFF;
		ecc_calc[3] = (nfeccprgecc0 >> 24) & 0xFF;
		ecc_calc[4] = nfeccprgecc1 & 0xFF;
		ecc_calc[5] = (nfeccprgecc1 >> 8) & 0xFF;
		ecc_calc[6] = (nfeccprgecc1 >> 16) & 0xFF;
		ecc_calc[7] = (nfeccprgecc1 >> 24) & 0xFF;
		ecc_calc[8] = nfeccprgecc2 & 0xFF;
		ecc_calc[9] = (nfeccprgecc2 >> 8) & 0xFF;
		ecc_calc[10] = (nfeccprgecc2 >> 16) & 0xFF;
		ecc_calc[11] = (nfeccprgecc2 >> 24) & 0xFF;
		ecc_calc[12] = nfeccprgecc3 & 0xFF;
	}
	else	/* NAND_ECC_READ */
	{
		/* ECC decoding is completed  */
		while (!(readl(info->regs + S5PV210_NFECCSTAT) & (1 << 24)));
	}
	return 0;
}

/* add by JerryGou */
static int s5pv210_nand_correct_data(struct mtd_info *mtd, u_char *dat,
				     u_char *read_ecc, u_char *calc_ecc)
{
	int ret = 0;
	u32 errNo;
	u32 erl0, erl1, erl2, erl3, erp0, erp1;
	struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);

	/* Wait until the 8-bit ECC decoding engine is Idle */
	while (readl(info->regs + S5PV210_NFECCSTAT) & (1 << 31));
	
	errNo = readl(info->regs + S5PV210_NFECCSECSTAT) & 0x1F;
	erl0 = readl(info->regs + S5PV210_NFECCERL0);
	erl1 = readl(info->regs + S5PV210_NFECCERL1);
	erl2 = readl(info->regs + S5PV210_NFECCERL2);
	erl3 = readl(info->regs + S5PV210_NFECCERL3);
	
	erp0 = readl(info->regs + S5PV210_NFECCERP0);
	erp1 = readl(info->regs + S5PV210_NFECCERP1);
	
	switch (errNo)
	{
	case 8:
		dat[(erl3 >> 16) & 0x3FF] ^= (erp1 >> 24) & 0xFF;
	case 7:
		dat[erl3 & 0x3FF] ^= (erp1 >> 16) & 0xFF;
	case 6:
		dat[(erl2 >> 16) & 0x3FF] ^= (erp1 >> 8) & 0xFF;
	case 5:
		dat[erl2 & 0x3FF] ^= erp1 & 0xFF;
	case 4:
		dat[(erl1 >> 16) & 0x3FF] ^= (erp0 >> 24) & 0xFF;
	case 3:
		dat[erl1 & 0x3FF] ^= (erp0 >> 16) & 0xFF;
	case 2:
		dat[(erl0 >> 16) & 0x3FF] ^= (erp0 >> 8) & 0xFF;
	case 1:
		dat[erl0 & 0x3FF] ^= erp0 & 0xFF;
	case 0:
		break;
	default:
		ret = -1;
		printk("ECC uncorrectable error detected:%d\n", errNo);
		break;
	}
	
	return ret;
}

/* add by JerryGou */
static int s5pv210_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
				uint8_t *buf, int oob_required, int page)				 
{
	int i, eccsize = chip->ecc.size;
	int eccbytes = chip->ecc.bytes;
	int eccsteps = chip->ecc.steps;
	int col = 0;
	int stat;
	uint8_t *p = buf;
	uint8_t *ecc_code = chip->buffers->ecccode;
	uint32_t *eccpos = chip->ecc.layout->eccpos;

	/* Read the OOB area first */
	col = mtd->writesize;
	chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
	chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
	
	for (i = 0; i < chip->ecc.total; i++)
		ecc_code[i] = chip->oob_poi[eccpos[i]];

	for (i = 0, col = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize, col += eccsize)
	{	
		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
		chip->ecc.hwctl(mtd, NAND_ECC_READ);
		chip->read_buf(mtd, p, eccsize);
		chip->write_buf(mtd, ecc_code + i, eccbytes);
		chip->ecc.calculate(mtd, NULL, NULL);
		stat = chip->ecc.correct(mtd, p, NULL, NULL);
		if (stat < 0)
			mtd->ecc_stats.failed++;
		else
			mtd->ecc_stats.corrected += stat;
	}
	return 0;
}
配置内核支持 NAND 硬件 ECC
Device Drivers --->
    <*> Memory Technology Device (MTD) support --->
        <*> NAND Device Support --->
            [*] Samsung S3C NAND Hardware ECC

重新编译内核,运行测试

        成功挂载 jffs2 文件系统,读写 NAND 正常,但这并不代码 ECC 校验功能生效,我们可以使用裸机程序,按照 4.11 的测试方法,把 rootfs 分区的第 1 个一个块的数据全部读出(包括 OOB),然后擦除 rootfs分区的第 1 个块,然后把读出的数据的前面 8 个数据的第 0 位取反,然后不使用 ECC 校验把读出的数据全部写入(包括 OOB),然后启动内核,看挂载文件系统是否正常。如果正常,再次重复测试,这次把 9个数据取反,挂载文件系统时应该有错误信息输出。

        注意到“ECC uncorrectable error detected:15”,这是我在 ECC 校验数据修正函数中打印出来的,表明无法修正的错误。 现在只有重新烧写文件系统才能恢复正常。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值