AM3352 uboot中对NandFlash坏块的处理

本文用于学习uboot中对NandFlash坏块的处理,适用于AM3352u-boot-2011.09H27_2G8 NandFlash

1.1.1    出厂时的坏块标记

依据datasheet中的说明,每2Gb中最多有40个坏块(5MB),且出厂时的第一个块保证不是坏块。

(*) Each 2Gb hasmaximum 40 bad blocks

NOTE: The 1stblock is quranteed to be a valid blick at the time of shipment.

在硬件上,只要每一块的第一页或者第二页的spare area的第一个字节不是FF,即认为这是一个块坏。

Any block wherethe 1st Byte in the spare area of the 1st or 2nd th page (if the 1st page isBad) does not contain FFh is a Bad Block. The Bad Block Information must be readbefore any erase is attempted as the Bad Block Information may be erased.

 

1.1.2    Uboot的坏块标记

与硬件datasheet说明略有不同的是,uboot将这个坏块标记做了更进一步的区分,使用下面的几种模式进行标记:

static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };

在默认情况下,将使用scan_ff_pattern,即与硬件保持一致。

 

1.1.3    坏块表的建立

uboot启动时,会快速扫描NandFlash上的坏块并在内存中建立坏块表。

这个过程由下面的函数完成:

/**
 * create_bbt - [GENERIC] Create a bad block table by scanning the device
 * @mtd:	MTD device structure
 * @buf:	temporary buffer
 * @bd:		descriptor for the good/bad block search pattern
 * @chip:	create the table for a specific chip, -1 read all chips.
 *		Applies only if NAND_BBT_PERCHIP option is set
 *
 * Create a bad block table by scanning the device
 * for the given good/bad block identify pattern
 */
static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
	struct nand_bbt_descr *bd, int chip)
 

1.1.4    手工标识坏块

uboot提供了一个叫nand markbad的命令,可以将指定的坏标识为坏块。

使用nand dump.oob命令可以发现,markbad将坏块页的oob前两个字节写为00 00

 

1.1.5    擦除所有坏块标记

nand erase支持一个叫scrub的参数,当加上此参数后,nand erase将擦除所有出厂时标定的坏块标记。

 

1.2  块擦除

当在uboot下执行nand erase时,最终将调用下面的函数:

/**
 * nand_erase_opts: - erase NAND flash with support for various options
 *		      (jffs2 formating)
 *
 * @param meminfo	NAND device to erase
 * @param opts		options,  @see struct nand_erase_options
 * @return		0 in case of success
 *
 * This code is ported from flash_eraseall.c from Linux mtd utils by
 * Arcom Control System Ltd.
 */
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
 

1.2.1    对已有坏块的处理

当执行擦除操作时,除非指定scrub参数,否则将直接跳过坏块的处理:

		if (!opts->scrub && bbtest) {
			int ret = meminfo->block_isbad(meminfo, erase.addr);
			if (ret > 0) {
				if (!opts->quiet)
					printf("\rSkipping bad block at  "
					       "0x%08llx                 "
					       "                         \n",
					       erase.addr);

				if (!opts->spread)
					erased_length++;

				continue;

			} else if (ret < 0) {
				printf("\n%s: MTD get bad block failed: %d\n",
				       mtd_device,
				       ret);
				return -1;
			}
		}
 

1.2.2    擦除时坏块的处理

当擦除发现坏块而导致擦除失败时,uboot没有做任何处理,直接返回。

/**
 * nand_erase_nand - [Internal] erase block(s)
 * @mtd:	MTD device structure
 * @instr:	erase instruction
 * @allowbbt:	allow erasing the bbt area
 *
 * Erase one ore more blocks
 */
int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
		    int allowbbt)
{.....
		chip->erase_cmd(mtd, page & chip->pagemask);

		status = chip->waitfunc(mtd, chip);

		/*
		 * See if operation failed and additional status checks are
		 * available
		 */
		if ((status & NAND_STATUS_FAIL) && (chip->errstat))
			status = chip->errstat(mtd, chip, FL_ERASING,
					       status, page);

		/* See if block erase succeeded */
		if (status & NAND_STATUS_FAIL) {
			MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: "
				  "Failed erase, page 0x%08x\n", page);
			instr->state = MTD_ERASE_FAILED;
			instr->fail_addr = ((loff_t)page << chip->page_shift);
			goto erase_exit;
		}
......
}
 

1.3  写入操作

当在uboot下使用nand write写入时,实际执行下面的函数:

/**
 * nand_write_skip_bad:
 *
 * Write image to NAND flash.
 * Blocks that are marked bad are skipped and the is written to the next
 * block instead as long as the image is short enough to fit even after
 * skipping the bad blocks.
 *
 * @param nand  	NAND device
 * @param offset	offset in flash
 * @param length	buffer length
 * @param buffer        buffer to read from
 * @param flags		flags modifying the behaviour of the write to NAND
 * @return		0 in case of success
 */
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
			u_char *buffer, int flags)

从下面的代码可以看出nand write对坏块的处理:

	while (left_to_write > 0) {
		size_t block_offset = offset & (nand->erasesize - 1);
		size_t write_size, truncated_write_size;

		WATCHDOG_RESET ();

		if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
			printf ("Skip bad block 0x%08llx\n",
				offset & ~(nand->erasesize - 1));
			offset += nand->erasesize - block_offset;
			continue;
		}
......
		left_to_write -= write_size;
	}

也就是说,nandwrite将跳过坏块并持续到数据完全写入。

此操作保证数据的完全写入,除非NandFlash已经没有空间。

 

1.4  读取操作

nand读取操作由下面的函数实现:

/**
 * nand_read_skip_bad:
 *
 * Read image from NAND flash.
 * Blocks that are marked bad are skipped and the next block is readen
 * instead as long as the image is short enough to fit even after skipping the
 * bad blocks.
 *
 * @param nand NAND device
 * @param offset offset in flash
 * @param length buffer length, on return holds remaining bytes to read
 * @param buffer buffer to write to
 * @return 0 in case of success
 */
int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
		       u_char *buffer)
 

下面是它的读取流程。

	while (left_to_read > 0) {
		size_t block_offset = offset & (nand->erasesize - 1);
		size_t read_length;

		WATCHDOG_RESET ();

		if (nand_block_isbad (nand, offset & ~(nand->erasesize - 1))) {
			printf ("Skipping bad block 0x%08llx\n",
				offset & ~(nand->erasesize - 1));
			offset += nand->erasesize - block_offset;
			continue;
		}
.....

		left_to_read -= read_length;
		offset       += read_length;
		p_buffer     += read_length;
	}


可以明确,读取操作保证读取足够数量的数据,当有坏块时直接跳过坏块。

 





已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页