天天看点

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

nandflash特点:

  1. nand存在位反转的现象,所以需要ecc校验数据,ecc校验可以矫正一位的位反转,发现两位的位反转;
  2. nand存在坏块的问题,所谓坏块,就是不能擦除的块,nandflash只能从1写为0;而不能从0写为1,也就是write时,只能将某一位拉低;而擦除操作是将0拉高位1。擦除是按块擦的,写的话按页写。写的话按页写是为了提高效率,而擦除只能按块擦除。
  3. nandflash的接口有并口和spi接口的。

硬件结构

原理图

并口的nandflash,8bit flash,地址和数据线共用

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

ALE和CLE用于地址和数据选择。

内部结构

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

页结构

每一页2048 data+64OOB;OOB(out of band);OOB主要有2byte坏快标识 + ECC数据;

坏块标识0xff为好块,其他为坏。坏块标识每一块的第一页的OOB区内。

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

以上页结构信息,不同的芯片厂商结构也不一样。

nandflash命令集

#define NAND_CMD_READ0		0
#define NAND_CMD_READ1		1
#define NAND_CMD_RNDOUT		5
#define NAND_CMD_PAGEPROG	0x10
#define NAND_CMD_READOOB	0x50
#define NAND_CMD_ERASE1		0x60
#define NAND_CMD_STATUS		0x70
#define NAND_CMD_SEQIN		0x80
#define NAND_CMD_RNDIN		0x85
#define NAND_CMD_READID		0x90
#define NAND_CMD_ERASE2		0xd0
#define NAND_CMD_PARAM		0xec
#define NAND_CMD_GET_FEATURES	0xee
#define NAND_CMD_SET_FEATURES	0xef
#define NAND_CMD_RESET		0xff

/* Extended commands for large page devices */
#define NAND_CMD_READSTART	0x30
#define NAND_CMD_RNDOUTSTART	0xE0
#define NAND_CMD_CACHEDPROG	0x15

#define NAND_CMD_NONE		-1
           

mtd nandflash驱动

mtd框架分层:

设备层: mtdchar.c/mtdblock.c; 字符设备和块设备接口。

原始设备层 mtdcore.c 提供mtd_info;mtd_partion;mtd_part结构。

硬件驱动层 /mtd/nand/下

nand_base.c nand通用接口;

分rawnand;onenand,spinand;

rawnand: 地址数据总线为并口。

spinand:通过spi总线控制,相当与rawnand封装成了spi接口。多了一个spi解释单元。

onenand:可以理解为nor+nand。

mtd框架能做什么不能做什么?

  1. nand flash有坏块,mtd驱动框架能帮我们跳坏块吗?

    答:不能,mtd只提供读写page接口,和ioctl接口来测试该块是否为坏块,但是不会在读写的时候帮我们自动跳过坏块,跳坏块操作需要我们应用来自己实现。

  2. nandflash会存在位反转现象,mtd驱动框架会帮我们做ecc校验吗? 纠正一位的bitflip,发现2bit的bitflip?

    答:这个mtd驱动框架会帮做,但是ecc校验可选软件ecc和硬件ecc,软件ecc算法mtd框架提供,硬件ecc则是硬件结构提供,读数据的时候会校验。

  3. nandflash擦除是按块擦除的,写是按页写的,如果我们要写一个块中的某一页,需要将整个块读出来然后,修改然后擦除写入。即read-update-erase-write;这个操作mtd会帮我们做吗?

    答:不会。mtd只提供页写入接口,这一系列操作需要用户自己做。至于提高写入速率的操作,也需要用户自己实现。

rawnand驱动字符设备接口

字符设备写流程图:

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

1. 写数据不跳坏块

2. oob中ecc数据可以是

1> 原始数据中已经带有的

2> 软件算法生成的 3中算法;

3> 硬件实现ecc算法;需要驱动实现ecc…

3. 不提供block写buffer;即read-update-erase-write流程。

读数据流

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

1.同样不跳坏块

2.ecc校验 nand_chip.ecc.correct

见代码硬件ecc分支nand_read_page_hwecc:

static int 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, ret;
	int eccbytes = chip->ecc.bytes;
	int eccsteps = chip->ecc.steps;
	uint8_t *p = buf;
	uint8_t *ecc_calc = chip->ecc.calc_buf;
	uint8_t *ecc_code = chip->ecc.code_buf;
	unsigned int max_bitflips = 0;

	ret = nand_read_page_op(chip, page, 0, NULL, 0);
	if (ret)
		return ret;

	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
		chip->ecc.hwctl(mtd, NAND_ECC_READ);

		ret = nand_read_data_op(chip, p, eccsize, false);
		if (ret)
			return ret;

		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
	}

	ret = nand_read_data_op(chip, chip->oob_poi, mtd->oobsize, false);
	if (ret)
		return ret;

	ret = mtd_ooblayout_get_eccbytes(mtd, ecc_code, chip->oob_poi, 0,
					 chip->ecc.total);
	if (ret)
		return ret;

	eccsteps = chip->ecc.steps;
	p = buf;

	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
		int stat;

		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
		if (stat == -EBADMSG &&
		    (chip->ecc.options & NAND_ECC_GENERIC_ERASED_CHECK)) {
			/* check for empty pages with bitflips */
			stat = nand_check_erased_ecc_chunk(p, eccsize,
						&ecc_code[i], eccbytes,
						NULL, 0,
						chip->ecc.strength);
		}

		if (stat < 0) {
			mtd->ecc_stats.failed++;
		} else {
			mtd->ecc_stats.corrected += stat;
			max_bitflips = max_t(unsigned int, max_bitflips, stat);
		}
	}
	return max_bitflips;
}
           

坏快表BBT

有的厂商将坏块表存放在flash第一块的第一页中,因为厂商出厂时第一页会确保为好块的。但是如果flash用来存放代码,则不能第一页不能用来存放坏快表。有的厂商将坏块表放在最后一块,但是要确保最后一块为好块。

mtdchar iotcl判断该块是否为坏块。

case MEMGETBADBLOCK:
	{
		loff_t offs;

		if (copy_from_user(&offs, argp, sizeof(loff_t)))
			return -EFAULT;
		return mtd_block_isbad(mtd, offs);
		break;
	}
           

调用链

小张学linux内核驱动篇:5.mtd驱动框架nandflash特点:硬件结构mtd nandflash驱动rawnand驱动字符设备接口nor flash

如果内存中没有bbt(chip->bbt);则去读oob区域;

如果有bbt,则从bbt[]中读取数据;

标记坏块时,标记bbt并更新oob区域。

nor flash

cfi接口;jedec(老的接口)