mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	nand: Merge changes from Linux nand driver
[backport from linux commit 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe] This patch synchronizes the nand driver with the Linux 3.0 state. Signed-off-by: Christian Hitz <christian.hitz@aizo.com> Cc: Scott Wood <scottwood@freescale.com> [scottwood@freescale.com: minor fixes] Signed-off-by: Scott Wood <scottwood@freescale.com>
This commit is contained in:
		
				
					committed by
					
						 Scott Wood
						Scott Wood
					
				
			
			
				
	
			
			
			
						parent
						
							90e3f395bf
						
					
				
				
					commit
					2a8e0fc8b3
				
			| @@ -115,6 +115,35 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | ||||
|  | ||||
| static int nand_wait(struct mtd_info *mtd, struct nand_chip *this); | ||||
|  | ||||
| static int check_offs_len(struct mtd_info *mtd, | ||||
| 					loff_t ofs, uint64_t len) | ||||
| { | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	int ret = 0; | ||||
|  | ||||
| 	/* Start address must align on block boundary */ | ||||
| 	if (ofs & ((1 << chip->phys_erase_shift) - 1)) { | ||||
| 		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); | ||||
| 		ret = -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	/* Length must align on block boundary */ | ||||
| 	if (len & ((1 << chip->phys_erase_shift) - 1)) { | ||||
| 		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", | ||||
| 					__func__); | ||||
| 		ret = -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	/* Do not allow past end of device */ | ||||
| 	if (ofs + len > mtd->size) { | ||||
| 		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", | ||||
| 					__func__); | ||||
| 		ret = -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * nand_release_device - [GENERIC] release chip | ||||
|  * @mtd:	MTD device structure | ||||
| @@ -123,8 +152,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this); | ||||
|  */ | ||||
| static void nand_release_device(struct mtd_info *mtd) | ||||
| { | ||||
| 	struct nand_chip *this = mtd->priv; | ||||
| 	this->select_chip(mtd, -1);	/* De-select the NAND device */ | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
|  | ||||
| 	/* De-select the NAND device */ | ||||
| 	chip->select_chip(mtd, -1); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -316,6 +347,9 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	u16 bad; | ||||
|  | ||||
| 	if (chip->options & NAND_BBT_SCANLASTPAGE) | ||||
| 		ofs += mtd->erasesize - mtd->writesize; | ||||
|  | ||||
| 	page = (int)(ofs >> chip->page_shift) & chip->pagemask; | ||||
|  | ||||
| 	if (getchip) { | ||||
| @@ -333,14 +367,18 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) | ||||
| 		bad = cpu_to_le16(chip->read_word(mtd)); | ||||
| 		if (chip->badblockpos & 0x1) | ||||
| 			bad >>= 8; | ||||
| 		if ((bad & 0xFF) != 0xff) | ||||
| 			res = 1; | ||||
| 		else | ||||
| 			bad &= 0xFF; | ||||
| 	} else { | ||||
| 		chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); | ||||
| 		if (chip->read_byte(mtd) != 0xff) | ||||
| 			res = 1; | ||||
| 		bad = chip->read_byte(mtd); | ||||
| 	} | ||||
|  | ||||
| 	if (likely(chip->badblockbits == 8)) | ||||
| 		res = bad != 0xFF; | ||||
| 	else | ||||
| 		res = hweight8(bad) < chip->badblockbits; | ||||
|  | ||||
| 	if (getchip) | ||||
| 		nand_release_device(mtd); | ||||
|  | ||||
| @@ -359,7 +397,10 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||||
| { | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	uint8_t buf[2] = { 0, 0 }; | ||||
| 	int block, ret; | ||||
| 	int block, ret, i = 0; | ||||
|  | ||||
| 	if (chip->options & NAND_BBT_SCANLASTPAGE) | ||||
| 		ofs += mtd->erasesize - mtd->writesize; | ||||
|  | ||||
| 	/* Get block number */ | ||||
| 	block = (int)(ofs >> chip->bbt_erase_shift); | ||||
| @@ -370,17 +411,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||||
| 	if (chip->options & NAND_USE_FLASH_BBT) | ||||
| 		ret = nand_update_bbt(mtd, ofs); | ||||
| 	else { | ||||
| 		/* We write two bytes, so we dont have to mess with 16 bit | ||||
| 		 * access | ||||
| 		 */ | ||||
| 		nand_get_device(chip, mtd, FL_WRITING); | ||||
| 		ofs += mtd->oobsize; | ||||
| 		chip->ops.len = chip->ops.ooblen = 2; | ||||
| 		chip->ops.datbuf = NULL; | ||||
| 		chip->ops.oobbuf = buf; | ||||
| 		chip->ops.ooboffs = chip->badblockpos & ~0x01; | ||||
|  | ||||
| 		ret = nand_do_write_oob(mtd, ofs, &chip->ops); | ||||
| 		/* Write to first two pages and to byte 1 and 6 if necessary. | ||||
| 		 * If we write to more than one location, the first error | ||||
| 		 * encountered quits the procedure. We write two bytes per | ||||
| 		 * location, so we dont have to mess with 16 bit access. | ||||
| 		 */ | ||||
| 		do { | ||||
| 			chip->ops.len = chip->ops.ooblen = 2; | ||||
| 			chip->ops.datbuf = NULL; | ||||
| 			chip->ops.oobbuf = buf; | ||||
| 			chip->ops.ooboffs = chip->badblockpos & ~0x01; | ||||
|  | ||||
| 			ret = nand_do_write_oob(mtd, ofs, &chip->ops); | ||||
|  | ||||
| 			if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { | ||||
| 				chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS | ||||
| 					& ~0x01; | ||||
| 				ret = nand_do_write_oob(mtd, ofs, &chip->ops); | ||||
| 			} | ||||
| 			i++; | ||||
| 			ofs += mtd->writesize; | ||||
| 		} while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && | ||||
| 				i < 2); | ||||
|  | ||||
| 		nand_release_device(mtd); | ||||
| 	} | ||||
| 	if (!ret) | ||||
| @@ -399,6 +454,11 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||||
| static int nand_check_wp(struct mtd_info *mtd) | ||||
| { | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
|  | ||||
| 	/* broken xD cards report WP despite being writable */ | ||||
| 	if (chip->options & NAND_BROKEN_XD) | ||||
| 		return 0; | ||||
|  | ||||
| 	/* Check the WP bit */ | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | ||||
| 	return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1; | ||||
| @@ -419,11 +479,6 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, | ||||
| { | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
|  | ||||
| 	if (!(chip->options & NAND_BBT_SCANNED)) { | ||||
| 		chip->options |= NAND_BBT_SCANNED; | ||||
| 		chip->scan_bbt(mtd); | ||||
| 	} | ||||
|  | ||||
| 	if (!chip->bbt) | ||||
| 		return chip->block_bad(mtd, ofs, getchip); | ||||
|  | ||||
| @@ -686,9 +741,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | ||||
|  * | ||||
|  * Get the device and lock it for exclusive access | ||||
|  */ | ||||
| static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) | ||||
| static int | ||||
| nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | ||||
| { | ||||
| 	this->state = new_state; | ||||
| 	chip->state = new_state; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -701,10 +757,10 @@ static int nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int ne | ||||
|  * Erase can take up to 400ms and program up to 20ms according to | ||||
|  * general NAND and SmartMedia specs | ||||
|  */ | ||||
| static int nand_wait(struct mtd_info *mtd, struct nand_chip *this) | ||||
| static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | ||||
| { | ||||
| 	unsigned long	timeo; | ||||
| 	int state = this->state; | ||||
| 	int state = chip->state; | ||||
| 	u32 time_start; | ||||
|  | ||||
| 	if (state == FL_ERASING) | ||||
| @@ -712,10 +768,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this) | ||||
| 	else | ||||
| 		timeo = (CONFIG_SYS_HZ * 20) / 1000; | ||||
|  | ||||
| 	if ((state == FL_ERASING) && (this->options & NAND_IS_AND)) | ||||
| 		this->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); | ||||
| 	if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) | ||||
| 		chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); | ||||
| 	else | ||||
| 		this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | ||||
| 		chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | ||||
|  | ||||
| 	time_start = get_timer(0); | ||||
|  | ||||
| @@ -725,11 +781,11 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this) | ||||
| 			return 0x01; | ||||
| 		} | ||||
|  | ||||
| 		if (this->dev_ready) { | ||||
| 			if (this->dev_ready(mtd)) | ||||
| 		if (chip->dev_ready) { | ||||
| 			if (chip->dev_ready(mtd)) | ||||
| 				break; | ||||
| 		} else { | ||||
| 			if (this->read_byte(mtd) & NAND_STATUS_READY) | ||||
| 			if (chip->read_byte(mtd) & NAND_STATUS_READY) | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| @@ -739,7 +795,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this) | ||||
| 		; | ||||
| #endif /*  PPCHAMELON_NAND_TIMER_HACK */ | ||||
|  | ||||
| 	return this->read_byte(mtd); | ||||
| 	return (int)chip->read_byte(mtd); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -860,6 +916,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 	int data_col_addr, i, gaps = 0; | ||||
| 	int datafrag_len, eccfrag_len, aligned_len, aligned_pos; | ||||
| 	int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; | ||||
| 	int index = 0; | ||||
|  | ||||
| 	/* Column address wihin the page aligned to ECC size (256bytes). */ | ||||
| 	start_step = data_offs / chip->ecc.size; | ||||
| @@ -898,26 +955,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 	} else { | ||||
| 		/* send the command to read the particular ecc bytes */ | ||||
| 		/* take care about buswidth alignment in read_buf */ | ||||
| 		aligned_pos = eccpos[start_step * chip->ecc.bytes] & ~(busw - 1); | ||||
| 		index = start_step * chip->ecc.bytes; | ||||
|  | ||||
| 		aligned_pos = eccpos[index] & ~(busw - 1); | ||||
| 		aligned_len = eccfrag_len; | ||||
| 		if (eccpos[start_step * chip->ecc.bytes] & (busw - 1)) | ||||
| 		if (eccpos[index] & (busw - 1)) | ||||
| 			aligned_len++; | ||||
| 		if (eccpos[(start_step + num_steps) * chip->ecc.bytes] & (busw - 1)) | ||||
| 		if (eccpos[index + (num_steps * chip->ecc.bytes)] & (busw - 1)) | ||||
| 			aligned_len++; | ||||
|  | ||||
| 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize + aligned_pos, -1); | ||||
| 		chip->cmdfunc(mtd, NAND_CMD_RNDOUT, | ||||
| 					mtd->writesize + aligned_pos, -1); | ||||
| 		chip->read_buf(mtd, &chip->oob_poi[aligned_pos], aligned_len); | ||||
| 	} | ||||
|  | ||||
| 	for (i = 0; i < eccfrag_len; i++) | ||||
| 		chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + start_step * chip->ecc.bytes]]; | ||||
| 		chip->buffers->ecccode[i] = chip->oob_poi[eccpos[i + index]]; | ||||
|  | ||||
| 	p = bufpoi + data_col_addr; | ||||
| 	for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) { | ||||
| 		int stat; | ||||
|  | ||||
| 		stat = chip->ecc.correct(mtd, p, &chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | ||||
| 		if (stat == -1) | ||||
| 		stat = chip->ecc.correct(mtd, p, | ||||
| 			&chip->buffers->ecccode[i], &chip->buffers->ecccalc[i]); | ||||
| 		if (stat < 0) | ||||
| 			mtd->ecc_stats.failed++; | ||||
| 		else | ||||
| 			mtd->ecc_stats.corrected += stat; | ||||
| @@ -1142,6 +1203,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | ||||
| 	int ret = 0; | ||||
| 	uint32_t readlen = ops->len; | ||||
| 	uint32_t oobreadlen = ops->ooblen; | ||||
| 	uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? | ||||
| 		mtd->oobavail : mtd->oobsize; | ||||
|  | ||||
| 	uint8_t *bufpoi, *oob, *buf; | ||||
|  | ||||
| 	stats = mtd->ecc_stats; | ||||
| @@ -1187,7 +1251,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | ||||
|  | ||||
| 			/* Transfer not aligned data */ | ||||
| 			if (!aligned) { | ||||
| 				if (!NAND_SUBPAGE_READ(chip) && !oob) | ||||
| 				if (!NAND_SUBPAGE_READ(chip) && !oob && | ||||
| 				    !(mtd->ecc_stats.failed - stats.failed)) | ||||
| 					chip->pagebuf = realpage; | ||||
| 				memcpy(buf, chip->buffers->databuf + col, bytes); | ||||
| 			} | ||||
| @@ -1195,18 +1260,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | ||||
| 			buf += bytes; | ||||
|  | ||||
| 			if (unlikely(oob)) { | ||||
| 				/* Raw mode does data:oob:data:oob */ | ||||
| 				if (ops->mode != MTD_OOB_RAW) { | ||||
| 					int toread = min(oobreadlen, | ||||
| 						chip->ecc.layout->oobavail); | ||||
| 					if (toread) { | ||||
| 						oob = nand_transfer_oob(chip, | ||||
| 							oob, ops, toread); | ||||
| 						oobreadlen -= toread; | ||||
| 					} | ||||
| 				} else | ||||
| 					buf = nand_transfer_oob(chip, | ||||
| 						buf, ops, mtd->oobsize); | ||||
|  | ||||
| 				int toread = min(oobreadlen, max_oobsize); | ||||
|  | ||||
| 				if (toread) { | ||||
| 					oob = nand_transfer_oob(chip, | ||||
| 						oob, ops, toread); | ||||
| 					oobreadlen -= toread; | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if (!(chip->options & NAND_NO_READRDY)) { | ||||
| @@ -1793,13 +1854,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | ||||
|  * nand_fill_oob - [Internal] Transfer client buffer to oob | ||||
|  * @chip:	nand chip structure | ||||
|  * @oob:	oob data buffer | ||||
|  * @len:	oob data write length | ||||
|  * @ops:	oob ops structure | ||||
|  */ | ||||
| static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, | ||||
| 				  struct mtd_oob_ops *ops) | ||||
| static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, | ||||
| 						struct mtd_oob_ops *ops) | ||||
| { | ||||
| 	size_t len = ops->ooblen; | ||||
|  | ||||
| 	switch (ops->mode) { | ||||
|  | ||||
| 	case MTD_OOB_PLACE: | ||||
| @@ -1838,7 +1898,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #define NOTALIGNED(x)	(x & (chip->subpagesize - 1)) != 0 | ||||
| #define NOTALIGNED(x)	((x & (chip->subpagesize - 1)) != 0) | ||||
|  | ||||
| /** | ||||
|  * nand_do_write_ops - [Internal] NAND write with ECC | ||||
| @@ -1854,6 +1914,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | ||||
| 	int chipnr, realpage, page, blockmask, column; | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	uint32_t writelen = ops->len; | ||||
|  | ||||
| 	uint32_t oobwritelen = ops->ooblen; | ||||
| 	uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? | ||||
| 				mtd->oobavail : mtd->oobsize; | ||||
|  | ||||
| 	uint8_t *oob = ops->oobbuf; | ||||
| 	uint8_t *buf = ops->datbuf; | ||||
| 	int ret, subpage; | ||||
| @@ -1890,6 +1955,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | ||||
| 	if (likely(!oob)) | ||||
| 		memset(chip->oob_poi, 0xff, mtd->oobsize); | ||||
|  | ||||
| 	/* Don't allow multipage oob writes with offset */ | ||||
| 	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) | ||||
| 		return -EINVAL; | ||||
|  | ||||
| 	while (1) { | ||||
| 		WATCHDOG_RESET(); | ||||
|  | ||||
| @@ -1907,8 +1976,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | ||||
| 			wbuf = chip->buffers->databuf; | ||||
| 		} | ||||
|  | ||||
| 		if (unlikely(oob)) | ||||
| 			oob = nand_fill_oob(chip, oob, ops); | ||||
| 		if (unlikely(oob)) { | ||||
| 			size_t len = min(oobwritelen, oobmaxlen); | ||||
| 			oob = nand_fill_oob(chip, oob, len, ops); | ||||
| 			oobwritelen -= len; | ||||
| 		} | ||||
|  | ||||
| 		ret = chip->write_page(mtd, chip, wbuf, page, cached, | ||||
| 				       (ops->mode == MTD_OOB_RAW)); | ||||
| @@ -2043,7 +2115,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | ||||
| 		chip->pagebuf = -1; | ||||
|  | ||||
| 	memset(chip->oob_poi, 0xff, mtd->oobsize); | ||||
| 	nand_fill_oob(chip, ops->oobbuf, ops); | ||||
| 	nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); | ||||
| 	status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); | ||||
| 	memset(chip->oob_poi, 0xff, mtd->oobsize); | ||||
|  | ||||
| @@ -2166,27 +2238,10 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | ||||
| 				__func__, (unsigned long long)instr->addr, | ||||
| 				(unsigned long long)instr->len); | ||||
|  | ||||
| 	/* Start address must align on block boundary */ | ||||
| 	if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { | ||||
| 		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); | ||||
| 	if (check_offs_len(mtd, instr->addr, instr->len)) | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	/* Length must align on block boundary */ | ||||
| 	if (instr->len & ((1 << chip->phys_erase_shift) - 1)) { | ||||
| 		MTDDEBUG (MTD_DEBUG_LEVEL0, | ||||
| 			  "nand_erase: Length not block aligned\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	/* Do not allow erase past end of device */ | ||||
| 	if ((instr->len + instr->addr) > mtd->size) { | ||||
| 		MTDDEBUG (MTD_DEBUG_LEVEL0, | ||||
| 			  "nand_erase: Erase past end of device\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
|  | ||||
| 	instr->fail_addr = 0xffffffff; | ||||
| 	instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; | ||||
|  | ||||
| 	/* Grab the lock and see if the device is available */ | ||||
| 	nand_get_device(chip, mtd, FL_ERASING); | ||||
| @@ -2371,7 +2426,8 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) | ||||
| 	struct nand_chip *chip = mtd->priv; | ||||
| 	int ret; | ||||
|  | ||||
| 	if ((ret = nand_block_isbad(mtd, ofs))) { | ||||
| 	ret = nand_block_isbad(mtd, ofs); | ||||
| 	if (ret) { | ||||
| 		/* If it was bad already, return success and do nothing. */ | ||||
| 		if (ret > 0) | ||||
| 			return 0; | ||||
| @@ -2444,6 +2500,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 	int i; | ||||
| 	int val; | ||||
|  | ||||
| 	/* try ONFI for unknow chip or LP */ | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); | ||||
| 	if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || | ||||
| 		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') | ||||
| @@ -2486,7 +2543,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | ||||
|  | ||||
| 	if (!mtd->name) | ||||
| 		mtd->name = p->model; | ||||
|  | ||||
| 	mtd->writesize = le32_to_cpu(p->byte_per_page); | ||||
| 	mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; | ||||
| 	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); | ||||
| @@ -2495,6 +2551,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 	if (le16_to_cpu(p->features) & 1) | ||||
| 		*busw = NAND_BUSWIDTH_16; | ||||
|  | ||||
| 	chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= (NAND_NO_READRDY | | ||||
| 			NAND_NO_AUTOINCR) & NAND_CHIPOPTIONS_MSK; | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| #else | ||||
| @@ -2506,41 +2566,6 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd, | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static void nand_flash_detect_non_onfi(struct mtd_info *mtd, | ||||
| 					struct nand_chip *chip, | ||||
| 					const struct nand_flash_dev *type, | ||||
| 					int *busw) | ||||
| { | ||||
| 	/* Newer devices have all the information in additional id bytes */ | ||||
| 	if (!type->pagesize) { | ||||
| 		int extid; | ||||
| 		/* The 3rd id byte holds MLC / multichip data */ | ||||
| 		chip->cellinfo = chip->read_byte(mtd); | ||||
| 		/* The 4th id byte is the important one */ | ||||
| 		extid = chip->read_byte(mtd); | ||||
| 		/* Calc pagesize */ | ||||
| 		mtd->writesize = 1024 << (extid & 0x3); | ||||
| 		extid >>= 2; | ||||
| 		/* Calc oobsize */ | ||||
| 		mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); | ||||
| 		extid >>= 2; | ||||
| 		/* Calc blocksize. Blocksize is multiples of 64KiB */ | ||||
| 		mtd->erasesize = (64 * 1024) << (extid & 0x03); | ||||
| 		extid >>= 2; | ||||
| 		/* Get buswidth information */ | ||||
| 		*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | ||||
|  | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * Old devices have chip data hardcoded in the device id table | ||||
| 		 */ | ||||
| 		mtd->erasesize = type->erasesize; | ||||
| 		mtd->writesize = type->pagesize; | ||||
| 		mtd->oobsize = mtd->writesize / 32; | ||||
| 		*busw = type->options & NAND_BUSWIDTH_16; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Get the flash and manufacturer id and lookup if the type is supported | ||||
|  */ | ||||
| @@ -2550,8 +2575,9 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | ||||
| 						  int *maf_id, int *dev_id, | ||||
| 						  const struct nand_flash_dev *type) | ||||
| { | ||||
| 	int ret, maf_idx; | ||||
| 	int tmp_id, tmp_manf; | ||||
| 	int i, maf_idx; | ||||
| 	u8 id_data[8]; | ||||
| 	int ret; | ||||
|  | ||||
| 	/* Select the device */ | ||||
| 	chip->select_chip(mtd, 0); | ||||
| @@ -2577,15 +2603,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | ||||
|  | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | ||||
|  | ||||
| 	/* Read manufacturer and device IDs */ | ||||
| 	for (i = 0; i < 2; i++) | ||||
| 		id_data[i] = chip->read_byte(mtd); | ||||
|  | ||||
| 	tmp_manf = chip->read_byte(mtd); | ||||
| 	tmp_id = chip->read_byte(mtd); | ||||
|  | ||||
| 	if (tmp_manf != *maf_id || tmp_id != *dev_id) { | ||||
| 	if (id_data[0] != *maf_id || id_data[1] != *dev_id) { | ||||
| 		printk(KERN_INFO "%s: second ID read did not match " | ||||
| 		       "%02x,%02x against %02x,%02x\n", __func__, | ||||
| 		       *maf_id, *dev_id, tmp_manf, tmp_id); | ||||
| 		       *maf_id, *dev_id, id_data[0], id_data[1]); | ||||
| 		return ERR_PTR(-ENODEV); | ||||
| 	} | ||||
|  | ||||
| @@ -2596,30 +2620,121 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | ||||
| 		if (*dev_id == type->id) | ||||
| 			break; | ||||
|  | ||||
| 	if (!type->name) { | ||||
| 		/* supress warning if there is no nand */ | ||||
| 		if (*maf_id != 0x00 && *maf_id != 0xff && | ||||
| 		    *dev_id  != 0x00 && *dev_id  != 0xff) | ||||
| 			printk(KERN_INFO "%s: unknown NAND device: " | ||||
| 				"Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n", | ||||
| 				__func__, *maf_id, *dev_id); | ||||
| 		return ERR_PTR(-ENODEV); | ||||
| 	chip->onfi_version = 0; | ||||
| 	if (!type->name || !type->pagesize) { | ||||
| 		/* Check is chip is ONFI compliant */ | ||||
| 		ret = nand_flash_detect_onfi(mtd, chip, &busw); | ||||
| 		if (ret) | ||||
| 			goto ident_done; | ||||
| 	} | ||||
|  | ||||
| 	chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); | ||||
|  | ||||
| 	/* Read entire ID string */ | ||||
|  | ||||
| 	for (i = 0; i < 8; i++) | ||||
| 		id_data[i] = chip->read_byte(mtd); | ||||
|  | ||||
| 	if (!type->name) | ||||
| 		return ERR_PTR(-ENODEV); | ||||
|  | ||||
| 	if (!mtd->name) | ||||
| 		mtd->name = type->name; | ||||
|  | ||||
| 	chip->chipsize = (uint64_t)type->chipsize << 20; | ||||
| 	chip->onfi_version = 0; | ||||
|  | ||||
| 	ret = nand_flash_detect_onfi(mtd, chip, &busw); | ||||
| 	if (!ret) | ||||
| 		nand_flash_detect_non_onfi(mtd, chip, type, &busw); | ||||
| 	if (!type->pagesize && chip->init_size) { | ||||
| 		/* set the pagesize, oobsize, erasesize by the driver*/ | ||||
| 		busw = chip->init_size(mtd, chip, id_data); | ||||
| 	} else if (!type->pagesize) { | ||||
| 		int extid; | ||||
| 		/* The 3rd id byte holds MLC / multichip data */ | ||||
| 		chip->cellinfo = id_data[2]; | ||||
| 		/* The 4th id byte is the important one */ | ||||
| 		extid = id_data[3]; | ||||
|  | ||||
| 		/* | ||||
| 		 * Field definitions are in the following datasheets: | ||||
| 		 * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) | ||||
| 		 * New style   (6 byte ID): Samsung K9GBG08U0M (p.40) | ||||
| 		 * | ||||
| 		 * Check for wraparound + Samsung ID + nonzero 6th byte | ||||
| 		 * to decide what to do. | ||||
| 		 */ | ||||
| 		if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && | ||||
| 				id_data[0] == NAND_MFR_SAMSUNG && | ||||
| 				(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && | ||||
| 				id_data[5] != 0x00) { | ||||
| 			/* Calc pagesize */ | ||||
| 			mtd->writesize = 2048 << (extid & 0x03); | ||||
| 			extid >>= 2; | ||||
| 			/* Calc oobsize */ | ||||
| 			switch (extid & 0x03) { | ||||
| 			case 1: | ||||
| 				mtd->oobsize = 128; | ||||
| 				break; | ||||
| 			case 2: | ||||
| 				mtd->oobsize = 218; | ||||
| 				break; | ||||
| 			case 3: | ||||
| 				mtd->oobsize = 400; | ||||
| 				break; | ||||
| 			default: | ||||
| 				mtd->oobsize = 436; | ||||
| 				break; | ||||
| 			} | ||||
| 			extid >>= 2; | ||||
| 			/* Calc blocksize */ | ||||
| 			mtd->erasesize = (128 * 1024) << | ||||
| 				(((extid >> 1) & 0x04) | (extid & 0x03)); | ||||
| 			busw = 0; | ||||
| 		} else { | ||||
| 			/* Calc pagesize */ | ||||
| 			mtd->writesize = 1024 << (extid & 0x03); | ||||
| 			extid >>= 2; | ||||
| 			/* Calc oobsize */ | ||||
| 			mtd->oobsize = (8 << (extid & 0x01)) * | ||||
| 				(mtd->writesize >> 9); | ||||
| 			extid >>= 2; | ||||
| 			/* Calc blocksize. Blocksize is multiples of 64KiB */ | ||||
| 			mtd->erasesize = (64 * 1024) << (extid & 0x03); | ||||
| 			extid >>= 2; | ||||
| 			/* Get buswidth information */ | ||||
| 			busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* | ||||
| 		 * Old devices have chip data hardcoded in the device id table | ||||
| 		 */ | ||||
| 		mtd->erasesize = type->erasesize; | ||||
| 		mtd->writesize = type->pagesize; | ||||
| 		mtd->oobsize = mtd->writesize / 32; | ||||
| 		busw = type->options & NAND_BUSWIDTH_16; | ||||
|  | ||||
| 		/* | ||||
| 		 * Check for Spansion/AMD ID + repeating 5th, 6th byte since | ||||
| 		 * some Spansion chips have erasesize that conflicts with size | ||||
| 		 * listed in nand_ids table | ||||
| 		 * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) | ||||
| 		 */ | ||||
| 		if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && | ||||
| 				id_data[5] == 0x00 && id_data[6] == 0x00 && | ||||
| 				id_data[7] == 0x00 && mtd->writesize == 512) { | ||||
| 			mtd->erasesize = 128 * 1024; | ||||
| 			mtd->erasesize <<= ((id_data[3] & 0x03) << 1); | ||||
| 		} | ||||
| 	} | ||||
| 	/* Get chip options, preserve non chip based options */ | ||||
| 	chip->options &= ~NAND_CHIPOPTIONS_MSK; | ||||
| 	chip->options |= type->options & NAND_CHIPOPTIONS_MSK; | ||||
|  | ||||
| 	/* Check if chip is a not a samsung device. Do not clear the | ||||
| 	 * options for chips which are not having an extended id. | ||||
| 	 */ | ||||
| 	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) | ||||
| 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | ||||
| ident_done: | ||||
|  | ||||
| 	/* | ||||
| 	 * Set chip as a default. Board drivers can override it, if necessary | ||||
| 	 */ | ||||
| @@ -2654,18 +2769,48 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | ||||
| 		ffs(mtd->erasesize) - 1; | ||||
| 	if (chip->chipsize & 0xffffffff) | ||||
| 		chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; | ||||
| 	else | ||||
| 		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 31; | ||||
| 	else { | ||||
| 		chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)); | ||||
| 		chip->chip_shift += 32 - 1; | ||||
| 	} | ||||
|  | ||||
| 	chip->badblockbits = 8; | ||||
|  | ||||
| 	/* Set the bad block position */ | ||||
| 	chip->badblockpos = mtd->writesize > 512 ? | ||||
| 		NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; | ||||
| 	if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) | ||||
| 		chip->badblockpos = NAND_LARGE_BADBLOCK_POS; | ||||
| 	else | ||||
| 		chip->badblockpos = NAND_SMALL_BADBLOCK_POS; | ||||
|  | ||||
| 	/* Check if chip is a not a samsung device. Do not clear the | ||||
| 	 * options for chips which are not having an extended id. | ||||
| 	/* | ||||
| 	 * Bad block marker is stored in the last page of each block | ||||
| 	 * on Samsung and Hynix MLC devices; stored in first two pages | ||||
| 	 * of each block on Micron devices with 2KiB pages and on | ||||
| 	 * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan | ||||
| 	 * only the first page. | ||||
| 	 */ | ||||
| 	if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) | ||||
| 		chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; | ||||
| 	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && | ||||
| 			(*maf_id == NAND_MFR_SAMSUNG || | ||||
| 			 *maf_id == NAND_MFR_HYNIX)) | ||||
| 		chip->options |= NAND_BBT_SCANLASTPAGE; | ||||
| 	else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && | ||||
| 				(*maf_id == NAND_MFR_SAMSUNG || | ||||
| 				 *maf_id == NAND_MFR_HYNIX || | ||||
| 				 *maf_id == NAND_MFR_TOSHIBA || | ||||
| 				 *maf_id == NAND_MFR_AMD)) || | ||||
| 			(mtd->writesize == 2048 && | ||||
| 			 *maf_id == NAND_MFR_MICRON)) | ||||
| 		chip->options |= NAND_BBT_SCAN2NDPAGE; | ||||
|  | ||||
| 	/* | ||||
| 	 * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 | ||||
| 	 */ | ||||
| 	if (!(busw & NAND_BUSWIDTH_16) && | ||||
| 			*maf_id == NAND_MFR_STMICRO && | ||||
| 			mtd->writesize == 2048) { | ||||
| 		chip->options |= NAND_BBT_SCANBYTE1AND6; | ||||
| 		chip->badblockpos = 0; | ||||
| 	} | ||||
|  | ||||
| 	/* Check for AND chips with 4 page planes */ | ||||
| 	if (chip->options & NAND_4PAGE_ARRAY) | ||||
| @@ -2677,9 +2822,15 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, | ||||
| 	if (mtd->writesize > 512 && chip->cmdfunc == nand_command) | ||||
| 		chip->cmdfunc = nand_command_lp; | ||||
|  | ||||
| 	/* TODO onfi flash name */ | ||||
| 	MTDDEBUG (MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:" | ||||
| 		  " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, | ||||
| 		  nand_manuf_ids[maf_idx].name, type->name); | ||||
| 		" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, | ||||
| 		nand_manuf_ids[maf_idx].name, | ||||
| #ifdef CONFIG_SYS_NAND_ONFI_DETECTION | ||||
| 		chip->onfi_version ? chip->onfi_params.model : type->name); | ||||
| #else | ||||
| 		type->name); | ||||
| #endif | ||||
|  | ||||
| 	return type; | ||||
| } | ||||
| @@ -2865,7 +3016,8 @@ int nand_scan_tail(struct mtd_info *mtd) | ||||
| 		chip->ecc.write_page_raw = nand_write_page_raw; | ||||
| 		chip->ecc.read_oob = nand_read_oob_std; | ||||
| 		chip->ecc.write_oob = nand_write_oob_std; | ||||
| 		chip->ecc.size = 256; | ||||
| 		if (!chip->ecc.size) | ||||
| 			chip->ecc.size = 256; | ||||
| 		chip->ecc.bytes = 3; | ||||
| 		break; | ||||
|  | ||||
| @@ -2973,7 +3125,8 @@ int nand_scan_tail(struct mtd_info *mtd) | ||||
|  | ||||
| 	/* Fill in remaining MTD driver data */ | ||||
| 	mtd->type = MTD_NANDFLASH; | ||||
| 	mtd->flags = MTD_CAP_NANDFLASH; | ||||
| 	mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : | ||||
| 						MTD_CAP_NANDFLASH; | ||||
| 	mtd->erase = nand_erase; | ||||
| 	mtd->point = NULL; | ||||
| 	mtd->unpoint = NULL; | ||||
| @@ -2992,9 +3145,10 @@ int nand_scan_tail(struct mtd_info *mtd) | ||||
|  | ||||
| 	/* Check, if we should skip the bad block table scan */ | ||||
| 	if (chip->options & NAND_SKIP_BBTSCAN) | ||||
| 		chip->options |= NAND_BBT_SCANNED; | ||||
| 		return 0; | ||||
|  | ||||
| 	return 0; | ||||
| 	/* Build bad block table */ | ||||
| 	return chip->scan_bbt(mtd); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -3039,4 +3193,9 @@ void nand_release(struct mtd_info *mtd) | ||||
| 	kfree(chip->bbt); | ||||
| 	if (!(chip->options & NAND_OWN_BUFFERS)) | ||||
| 		kfree(chip->buffers); | ||||
|  | ||||
| 	/* Free bad block descriptor memory */ | ||||
| 	if (chip->badblock_pattern && chip->badblock_pattern->options | ||||
| 			& NAND_BBT_DYNAMICSTRUCT) | ||||
| 		kfree(chip->badblock_pattern); | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,19 @@ | ||||
|  *  Thomas Gleixner <tglx@linuxtronix.de> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
|  * published by the Free Software Foundation. | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|  * | ||||
|  */ | ||||
| #ifndef __LINUX_MTD_BBM_H | ||||
| #define __LINUX_MTD_BBM_H | ||||
| @@ -76,7 +87,7 @@ struct nand_bbt_descr { | ||||
| #define NAND_BBT_PERCHIP	0x00000080 | ||||
| /* bbt has a version counter at offset veroffs */ | ||||
| #define NAND_BBT_VERSION	0x00000100 | ||||
| /* Create a bbt if none axists */ | ||||
| /* Create a bbt if none exists */ | ||||
| #define NAND_BBT_CREATE		0x00000200 | ||||
| /* Search good / bad pattern through all pages of a block */ | ||||
| #define NAND_BBT_SCANALLPAGES	0x00000400 | ||||
| @@ -88,6 +99,12 @@ struct nand_bbt_descr { | ||||
| #define NAND_BBT_SAVECONTENT	0x00002000 | ||||
| /* Search good / bad pattern on the first and the second page */ | ||||
| #define NAND_BBT_SCAN2NDPAGE	0x00004000 | ||||
| /* Search good / bad pattern on the last page of the eraseblock */ | ||||
| #define NAND_BBT_SCANLASTPAGE	0x00008000 | ||||
| /* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */ | ||||
| #define NAND_BBT_SCANBYTE1AND6 0x00100000 | ||||
| /* The nand_bbt_descr was created dynamicaly and must be freed */ | ||||
| #define NAND_BBT_DYNAMICSTRUCT 0x00200000 | ||||
|  | ||||
| /* The maximum number of blocks to scan for a bbt */ | ||||
| #define NAND_BBT_SCAN_MAXBLOCKS	4 | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| /* | ||||
|  *  linux/include/linux/mtd/nand.h | ||||
|  * | ||||
|  *  Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org> | ||||
|  *                     Steven J. Hill <sjhill@realitydiluted.com> | ||||
|  *		       Thomas Gleixner <tglx@linutronix.de> | ||||
|  *  Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org> | ||||
|  *                        Steven J. Hill <sjhill@realitydiluted.com> | ||||
|  *		          Thomas Gleixner <tglx@linutronix.de> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License version 2 as | ||||
| @@ -36,17 +36,18 @@ extern int nand_scan_ident(struct mtd_info *mtd, int max_chips, | ||||
| extern int nand_scan_tail(struct mtd_info *mtd); | ||||
|  | ||||
| /* Free resources held by the NAND device */ | ||||
| extern void nand_release (struct mtd_info *mtd); | ||||
| extern void nand_release(struct mtd_info *mtd); | ||||
|  | ||||
| /* Internal helper for board drivers which need to override command function */ | ||||
| extern void nand_wait_ready(struct mtd_info *mtd); | ||||
|  | ||||
| /* This constant declares the max. oobsize / page, which | ||||
| /* | ||||
|  * This constant declares the max. oobsize / page, which | ||||
|  * is supported now. If you add a chip with bigger oobsize/page | ||||
|  * adjust this accordingly. | ||||
|  */ | ||||
| #define NAND_MAX_OOBSIZE	218 | ||||
| #define NAND_MAX_PAGESIZE	4096 | ||||
| #define NAND_MAX_OOBSIZE	576 | ||||
| #define NAND_MAX_PAGESIZE	8192 | ||||
|  | ||||
| /* | ||||
|  * Constants for hardware specific CLE/ALE/NCE function | ||||
| @@ -79,10 +80,14 @@ extern void nand_wait_ready(struct mtd_info *mtd); | ||||
| #define NAND_CMD_SEQIN		0x80 | ||||
| #define NAND_CMD_RNDIN		0x85 | ||||
| #define NAND_CMD_READID		0x90 | ||||
| #define NAND_CMD_PARAM		0xec | ||||
| #define NAND_CMD_ERASE2		0xd0 | ||||
| #define NAND_CMD_PARAM		0xec | ||||
| #define NAND_CMD_RESET		0xff | ||||
|  | ||||
| #define NAND_CMD_LOCK		0x2a | ||||
| #define NAND_CMD_UNLOCK1	0x23 | ||||
| #define NAND_CMD_UNLOCK2	0x24 | ||||
|  | ||||
| /* Extended commands for large page devices */ | ||||
| #define NAND_CMD_READSTART	0x30 | ||||
| #define NAND_CMD_RNDOUTSTART	0xE0 | ||||
| @@ -142,9 +147,10 @@ typedef enum { | ||||
| #define NAND_GET_DEVICE		0x80 | ||||
|  | ||||
|  | ||||
| /* Option constants for bizarre disfunctionality and real | ||||
| *  features | ||||
| */ | ||||
| /* | ||||
|  * Option constants for bizarre disfunctionality and real | ||||
|  * features. | ||||
|  */ | ||||
| /* Chip can not auto increment pages */ | ||||
| #define NAND_NO_AUTOINCR	0x00000001 | ||||
| /* Buswitdh is 16 bit */ | ||||
| @@ -155,23 +161,36 @@ typedef enum { | ||||
| #define NAND_CACHEPRG		0x00000008 | ||||
| /* Chip has copy back function */ | ||||
| #define NAND_COPYBACK		0x00000010 | ||||
| /* AND Chip which has 4 banks and a confusing page / block | ||||
|  * assignment. See Renesas datasheet for further information */ | ||||
| /* | ||||
|  * AND Chip which has 4 banks and a confusing page / block | ||||
|  * assignment. See Renesas datasheet for further information. | ||||
|  */ | ||||
| #define NAND_IS_AND		0x00000020 | ||||
| /* Chip has a array of 4 pages which can be read without | ||||
|  * additional ready /busy waits */ | ||||
| /* | ||||
|  * Chip has a array of 4 pages which can be read without | ||||
|  * additional ready /busy waits. | ||||
|  */ | ||||
| #define NAND_4PAGE_ARRAY	0x00000040 | ||||
| /* Chip requires that BBT is periodically rewritten to prevent | ||||
| /* | ||||
|  * Chip requires that BBT is periodically rewritten to prevent | ||||
|  * bits from adjacent blocks from 'leaking' in altering data. | ||||
|  * This happens with the Renesas AG-AND chips, possibly others.  */ | ||||
|  * This happens with the Renesas AG-AND chips, possibly others. | ||||
|  */ | ||||
| #define BBT_AUTO_REFRESH	0x00000080 | ||||
| /* Chip does not require ready check on read. True | ||||
| /* | ||||
|  * Chip does not require ready check on read. True | ||||
|  * for all large page devices, as they do not support | ||||
|  * autoincrement.*/ | ||||
|  * autoincrement. | ||||
|  */ | ||||
| #define NAND_NO_READRDY		0x00000100 | ||||
| /* Chip does not allow subpage writes */ | ||||
| #define NAND_NO_SUBPAGE_WRITE	0x00000200 | ||||
|  | ||||
| /* Device is one of 'new' xD cards that expose fake nand command set */ | ||||
| #define NAND_BROKEN_XD		0x00000400 | ||||
|  | ||||
| /* Device behaves just like nand, but is readonly */ | ||||
| #define NAND_ROM		0x00000800 | ||||
|  | ||||
| /* Options valid for Samsung large page devices */ | ||||
| #define NAND_SAMSUNG_LP_OPTIONS \ | ||||
| @@ -190,17 +209,29 @@ typedef enum { | ||||
| #define NAND_CHIPOPTIONS_MSK	(0x0000ffff & ~NAND_NO_AUTOINCR) | ||||
|  | ||||
| /* Non chip related options */ | ||||
| /* Use a flash based bad block table. This option is passed to the | ||||
|  * default bad block table function. */ | ||||
| /* | ||||
|  * Use a flash based bad block table. OOB identifier is saved in OOB area. | ||||
|  * This option is passed to the default bad block table function. | ||||
|  */ | ||||
| #define NAND_USE_FLASH_BBT	0x00010000 | ||||
| /* This option skips the bbt scan during initialization. */ | ||||
| #define NAND_SKIP_BBTSCAN	0x00020000 | ||||
| /* This option is defined if the board driver allocates its own buffers | ||||
|    (e.g. because it needs them DMA-coherent */ | ||||
| /* | ||||
|  * This option is defined if the board driver allocates its own buffers | ||||
|  * (e.g. because it needs them DMA-coherent). | ||||
|  */ | ||||
| #define NAND_OWN_BUFFERS	0x00040000 | ||||
| /* Chip may not exist, so silence any errors in scan */ | ||||
| #define NAND_SCAN_SILENT_NODEV	0x00080000 | ||||
| /* | ||||
|  * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch | ||||
|  * the OOB area. | ||||
|  */ | ||||
| #define NAND_USE_FLASH_BBT_NO_OOB	0x00800000 | ||||
| /* Create an empty BBT with no vendor information if the BBT is available */ | ||||
| #define NAND_CREATE_EMPTY_BBT		0x01000000 | ||||
|  | ||||
| /* Options set by nand scan */ | ||||
| /* bbt has already been read */ | ||||
| #define NAND_BBT_SCANNED	0x40000000 | ||||
| /* Nand scan has allocated controller struct */ | ||||
| #define NAND_CONTROLLER_ALLOC	0x80000000 | ||||
|  | ||||
| @@ -275,13 +306,13 @@ struct nand_onfi_params { | ||||
|  | ||||
| #define ONFI_CRC_BASE	0x4F4E | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices | ||||
|  * @lock:               protection lock | ||||
|  * @active:		the mtd device which holds the controller currently | ||||
|  * @wq:			wait queue to sleep on if a NAND operation is in progress | ||||
|  *                      used instead of the per chip wait queue when a hw controller is available | ||||
|  * @wq:			wait queue to sleep on if a NAND operation is in | ||||
|  *			progress used instead of the per chip wait queue | ||||
|  *			when a hw controller is available. | ||||
|  */ | ||||
| struct nand_hw_control { | ||||
| /* XXX U-BOOT XXX */ | ||||
| @@ -302,58 +333,50 @@ struct nand_hw_control { | ||||
|  * @prepad:	padding information for syndrome based ecc generators | ||||
|  * @postpad:	padding information for syndrome based ecc generators | ||||
|  * @layout:	ECC layout control struct pointer | ||||
|  * @priv:       pointer to private ecc control data | ||||
|  * @priv:	pointer to private ecc control data | ||||
|  * @hwctl:	function to control hardware ecc generator. Must only | ||||
|  *		be provided if an hardware ECC is available | ||||
|  * @calculate:	function for ecc calculation or readback from ecc hardware | ||||
|  * @correct:	function for ecc correction, matching to ecc generator (sw/hw) | ||||
|  * @read_page_raw:	function to read a raw page without ECC | ||||
|  * @write_page_raw:	function to write a raw page without ECC | ||||
|  * @read_page:	function to read a page according to the ecc generator requirements | ||||
|  * @write_page:	function to write a page according to the ecc generator requirements | ||||
|  * @read_page:	function to read a page according to the ecc generator | ||||
|  *		requirements. | ||||
|  * @read_subpage:	function to read parts of the page covered by ECC. | ||||
|  * @write_page:	function to write a page according to the ecc generator | ||||
|  *		requirements. | ||||
|  * @read_oob:	function to read chip OOB data | ||||
|  * @write_oob:	function to write chip OOB data | ||||
|  */ | ||||
| struct nand_ecc_ctrl { | ||||
| 	nand_ecc_modes_t	mode; | ||||
| 	int			steps; | ||||
| 	int			size; | ||||
| 	int			bytes; | ||||
| 	int			total; | ||||
| 	int			prepad; | ||||
| 	int			postpad; | ||||
| 	nand_ecc_modes_t mode; | ||||
| 	int steps; | ||||
| 	int size; | ||||
| 	int bytes; | ||||
| 	int total; | ||||
| 	int prepad; | ||||
| 	int postpad; | ||||
| 	struct nand_ecclayout	*layout; | ||||
| 	void			*priv; | ||||
| 	void			(*hwctl)(struct mtd_info *mtd, int mode); | ||||
| 	int			(*calculate)(struct mtd_info *mtd, | ||||
| 					     const uint8_t *dat, | ||||
| 					     uint8_t *ecc_code); | ||||
| 	int			(*correct)(struct mtd_info *mtd, uint8_t *dat, | ||||
| 					   uint8_t *read_ecc, | ||||
| 					   uint8_t *calc_ecc); | ||||
| 	int			(*read_page_raw)(struct mtd_info *mtd, | ||||
| 						 struct nand_chip *chip, | ||||
| 						 uint8_t *buf, int page); | ||||
| 	void			(*write_page_raw)(struct mtd_info *mtd, | ||||
| 						  struct nand_chip *chip, | ||||
| 						  const uint8_t *buf); | ||||
| 	int			(*read_page)(struct mtd_info *mtd, | ||||
| 					     struct nand_chip *chip, | ||||
| 					     uint8_t *buf, int page); | ||||
| 	int			(*read_subpage)(struct mtd_info *mtd, | ||||
| 					     struct nand_chip *chip, | ||||
| 					     uint32_t offs, uint32_t len, | ||||
| 					     uint8_t *buf); | ||||
| 	void			(*write_page)(struct mtd_info *mtd, | ||||
| 					      struct nand_chip *chip, | ||||
| 					      const uint8_t *buf); | ||||
| 	int			(*read_oob)(struct mtd_info *mtd, | ||||
| 					    struct nand_chip *chip, | ||||
| 					    int page, | ||||
| 					    int sndcmd); | ||||
| 	int			(*write_oob)(struct mtd_info *mtd, | ||||
| 					     struct nand_chip *chip, | ||||
| 					     int page); | ||||
| 	void *priv; | ||||
| 	void (*hwctl)(struct mtd_info *mtd, int mode); | ||||
| 	int (*calculate)(struct mtd_info *mtd, const uint8_t *dat, | ||||
| 			uint8_t *ecc_code); | ||||
| 	int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, | ||||
| 			uint8_t *calc_ecc); | ||||
| 	int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			uint8_t *buf, int page); | ||||
| 	void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			const uint8_t *buf); | ||||
| 	int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			uint8_t *buf, int page); | ||||
| 	int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			uint32_t offs, uint32_t len, uint8_t *buf); | ||||
| 	void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			const uint8_t *buf); | ||||
| 	int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, | ||||
| 			int sndcmd); | ||||
| 	int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			int page); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -373,125 +396,150 @@ struct nand_buffers { | ||||
|  | ||||
| /** | ||||
|  * struct nand_chip - NAND Private Flash Chip Data | ||||
|  * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the flash device | ||||
|  * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the flash device | ||||
|  * @IO_ADDR_R:		[BOARDSPECIFIC] address to read the 8 I/O lines of the | ||||
|  *			flash device | ||||
|  * @IO_ADDR_W:		[BOARDSPECIFIC] address to write the 8 I/O lines of the | ||||
|  *			flash device. | ||||
|  * @read_byte:		[REPLACEABLE] read one byte from the chip | ||||
|  * @read_word:		[REPLACEABLE] read one word from the chip | ||||
|  * @write_buf:		[REPLACEABLE] write data from the buffer to the chip | ||||
|  * @read_buf:		[REPLACEABLE] read data from the chip into the buffer | ||||
|  * @verify_buf:		[REPLACEABLE] verify buffer contents against the chip data | ||||
|  * @verify_buf:		[REPLACEABLE] verify buffer contents against the chip | ||||
|  *			data. | ||||
|  * @select_chip:	[REPLACEABLE] select chip nr | ||||
|  * @block_bad:		[REPLACEABLE] check, if the block is bad | ||||
|  * @block_markbad:	[REPLACEABLE] mark the block bad | ||||
|  * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific funtion for controlling | ||||
|  * @cmd_ctrl:		[BOARDSPECIFIC] hardwarespecific function for controlling | ||||
|  *			ALE/CLE/nCE. Also used to write command and address | ||||
|  * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accesing device ready/busy line | ||||
|  *			If set to NULL no access to ready/busy is available and the ready/busy information | ||||
|  *			is read from the chip status register | ||||
|  * @cmdfunc:		[REPLACEABLE] hardwarespecific function for writing commands to the chip | ||||
|  * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on ready | ||||
|  * @init_size:		[BOARDSPECIFIC] hardwarespecific function for setting | ||||
|  *			mtd->oobsize, mtd->writesize and so on. | ||||
|  *			@id_data contains the 8 bytes values of NAND_CMD_READID. | ||||
|  *			Return with the bus width. | ||||
|  * @dev_ready:		[BOARDSPECIFIC] hardwarespecific function for accesing | ||||
|  *			device ready/busy line. If set to NULL no access to | ||||
|  *			ready/busy is available and the ready/busy information | ||||
|  *			is read from the chip status register. | ||||
|  * @cmdfunc:		[REPLACEABLE] hardwarespecific function for writing | ||||
|  *			commands to the chip. | ||||
|  * @waitfunc:		[REPLACEABLE] hardwarespecific function for wait on | ||||
|  *			ready. | ||||
|  * @ecc:		[BOARDSPECIFIC] ecc control ctructure | ||||
|  * @buffers:		buffer structure for read/write | ||||
|  * @hwcontrol:		platform-specific hardware control structure | ||||
|  * @ops:		oob operation operands | ||||
|  * @erase_cmd:		[INTERN] erase command write function, selectable due to AND support | ||||
|  * @erase_cmd:		[INTERN] erase command write function, selectable due | ||||
|  *			to AND support. | ||||
|  * @scan_bbt:		[REPLACEABLE] function to scan bad block table | ||||
|  * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transfering data from array to read regs (tR) | ||||
|  * @wq:			[INTERN] wait queue to sleep on if a NAND operation is in progress | ||||
|  * @chip_delay:		[BOARDSPECIFIC] chip dependent delay for transferring | ||||
|  *			data from array to read regs (tR). | ||||
|  * @state:		[INTERN] the current state of the NAND device | ||||
|  * @oob_poi:		poison value buffer | ||||
|  * @page_shift:		[INTERN] number of address bits in a page (column address bits) | ||||
|  * @page_shift:		[INTERN] number of address bits in a page (column | ||||
|  *			address bits). | ||||
|  * @phys_erase_shift:	[INTERN] number of address bits in a physical eraseblock | ||||
|  * @bbt_erase_shift:	[INTERN] number of address bits in a bbt entry | ||||
|  * @chip_shift:		[INTERN] number of address bits in one chip | ||||
|  * @datbuf:		[INTERN] internal buffer for one page + oob | ||||
|  * @oobbuf:		[INTERN] oob buffer for one eraseblock | ||||
|  * @oobdirty:		[INTERN] indicates that oob_buf must be reinitialized | ||||
|  * @data_poi:		[INTERN] pointer to a data buffer | ||||
|  * @options:		[BOARDSPECIFIC] various chip options. They can partly be set to inform nand_scan about | ||||
|  *			special functionality. See the defines for further explanation | ||||
|  * @badblockpos:	[INTERN] position of the bad block marker in the oob area | ||||
|  * @options:		[BOARDSPECIFIC] various chip options. They can partly | ||||
|  *			be set to inform nand_scan about special functionality. | ||||
|  *			See the defines for further explanation. | ||||
|  * @badblockpos:	[INTERN] position of the bad block marker in the oob | ||||
|  *			area. | ||||
|  * @badblockbits:	[INTERN] number of bits to left-shift the bad block | ||||
|  *			number | ||||
|  * @cellinfo:		[INTERN] MLC/multichip data from chip ident | ||||
|  * @numchips:		[INTERN] number of physical chips | ||||
|  * @chipsize:		[INTERN] the size of one chip for multichip arrays | ||||
|  * @pagemask:		[INTERN] page number mask = number of (pages / chip) - 1 | ||||
|  * @pagebuf:		[INTERN] holds the pagenumber which is currently in data_buf | ||||
|  * @pagebuf:		[INTERN] holds the pagenumber which is currently in | ||||
|  *			data_buf. | ||||
|  * @subpagesize:	[INTERN] holds the subpagesize | ||||
|  * @onfi_version:	[INTERN] holds the chip ONFI version (BCD encoded), | ||||
|  *			non 0 if ONFI supported. | ||||
|  * @onfi_params:	[INTERN] holds the ONFI page parameter when ONFI is | ||||
|  *			supported, 0 otherwise. | ||||
|  * @ecclayout:		[REPLACEABLE] the default ecc placement scheme | ||||
|  * @bbt:		[INTERN] bad block table pointer | ||||
|  * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash lookup | ||||
|  * @bbt_td:		[REPLACEABLE] bad block table descriptor for flash | ||||
|  *			lookup. | ||||
|  * @bbt_md:		[REPLACEABLE] bad block table mirror descriptor | ||||
|  * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial bad block scan | ||||
|  * @controller:		[REPLACEABLE] a pointer to a hardware controller structure | ||||
|  *			which is shared among multiple independend devices | ||||
|  * @badblock_pattern:	[REPLACEABLE] bad block scan pattern used for initial | ||||
|  *			bad block scan. | ||||
|  * @controller:		[REPLACEABLE] a pointer to a hardware controller | ||||
|  *			structure which is shared among multiple independend | ||||
|  *			devices. | ||||
|  * @priv:		[OPTIONAL] pointer to private chip date | ||||
|  * @errstat:		[OPTIONAL] hardware specific function to perform additional error status checks | ||||
|  *			(determine if errors are correctable) | ||||
|  * @errstat:		[OPTIONAL] hardware specific function to perform | ||||
|  *			additional error status checks (determine if errors are | ||||
|  *			correctable). | ||||
|  * @write_page:		[REPLACEABLE] High-level page write function | ||||
|  */ | ||||
|  | ||||
| struct nand_chip { | ||||
| 	void  __iomem	*IO_ADDR_R; | ||||
| 	void  __iomem	*IO_ADDR_W; | ||||
| 	void __iomem *IO_ADDR_R; | ||||
| 	void __iomem *IO_ADDR_W; | ||||
|  | ||||
| 	uint8_t		(*read_byte)(struct mtd_info *mtd); | ||||
| 	u16		(*read_word)(struct mtd_info *mtd); | ||||
| 	void		(*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | ||||
| 	void		(*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); | ||||
| 	int		(*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | ||||
| 	void		(*select_chip)(struct mtd_info *mtd, int chip); | ||||
| 	int		(*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); | ||||
| 	int		(*block_markbad)(struct mtd_info *mtd, loff_t ofs); | ||||
| 	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat, | ||||
| 				    unsigned int ctrl); | ||||
| 	int		(*dev_ready)(struct mtd_info *mtd); | ||||
| 	void		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); | ||||
| 	int		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); | ||||
| 	void		(*erase_cmd)(struct mtd_info *mtd, int page); | ||||
| 	int		(*scan_bbt)(struct mtd_info *mtd); | ||||
| 	int		(*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); | ||||
| 	int		(*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 				      const uint8_t *buf, int page, int cached, int raw); | ||||
| 	uint8_t (*read_byte)(struct mtd_info *mtd); | ||||
| 	u16 (*read_word)(struct mtd_info *mtd); | ||||
| 	void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | ||||
| 	void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); | ||||
| 	int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); | ||||
| 	void (*select_chip)(struct mtd_info *mtd, int chip); | ||||
| 	int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); | ||||
| 	int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); | ||||
| 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); | ||||
| 	int (*init_size)(struct mtd_info *mtd, struct nand_chip *this, | ||||
| 			u8 *id_data); | ||||
| 	int (*dev_ready)(struct mtd_info *mtd); | ||||
| 	void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, | ||||
| 			int page_addr); | ||||
| 	int(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); | ||||
| 	void (*erase_cmd)(struct mtd_info *mtd, int page); | ||||
| 	int (*scan_bbt)(struct mtd_info *mtd); | ||||
| 	int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, | ||||
| 			int status, int page); | ||||
| 	int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, | ||||
| 			const uint8_t *buf, int page, int cached, int raw); | ||||
|  | ||||
| 	int		chip_delay; | ||||
| 	unsigned int	options; | ||||
| 	int chip_delay; | ||||
| 	unsigned int options; | ||||
|  | ||||
| 	int		page_shift; | ||||
| 	int		phys_erase_shift; | ||||
| 	int		bbt_erase_shift; | ||||
| 	int		chip_shift; | ||||
| 	int		numchips; | ||||
| 	uint64_t	chipsize; | ||||
| 	int		pagemask; | ||||
| 	int		pagebuf; | ||||
| 	int		subpagesize; | ||||
| 	uint8_t		cellinfo; | ||||
| 	int		badblockpos; | ||||
| 	int		onfi_version; | ||||
| 	int page_shift; | ||||
| 	int phys_erase_shift; | ||||
| 	int bbt_erase_shift; | ||||
| 	int chip_shift; | ||||
| 	int numchips; | ||||
| 	uint64_t chipsize; | ||||
| 	int pagemask; | ||||
| 	int pagebuf; | ||||
| 	int subpagesize; | ||||
| 	uint8_t cellinfo; | ||||
| 	int badblockpos; | ||||
| 	int badblockbits; | ||||
|  | ||||
| 	int onfi_version; | ||||
| #ifdef CONFIG_SYS_NAND_ONFI_DETECTION | ||||
| 	struct nand_onfi_params onfi_params; | ||||
| #endif | ||||
|  | ||||
| 	int 		state; | ||||
| 	int state; | ||||
|  | ||||
| 	uint8_t		*oob_poi; | ||||
| 	struct nand_hw_control  *controller; | ||||
| 	struct nand_ecclayout	*ecclayout; | ||||
| 	uint8_t *oob_poi; | ||||
| 	struct nand_hw_control *controller; | ||||
| 	struct nand_ecclayout *ecclayout; | ||||
|  | ||||
| 	struct nand_ecc_ctrl ecc; | ||||
| 	struct nand_buffers *buffers; | ||||
|  | ||||
| 	struct nand_hw_control hwcontrol; | ||||
|  | ||||
| 	struct mtd_oob_ops ops; | ||||
|  | ||||
| 	uint8_t		*bbt; | ||||
| 	struct nand_bbt_descr	*bbt_td; | ||||
| 	struct nand_bbt_descr	*bbt_md; | ||||
| 	uint8_t *bbt; | ||||
| 	struct nand_bbt_descr *bbt_td; | ||||
| 	struct nand_bbt_descr *bbt_md; | ||||
|  | ||||
| 	struct nand_bbt_descr	*badblock_pattern; | ||||
| 	struct nand_bbt_descr *badblock_pattern; | ||||
|  | ||||
| 	void		*priv; | ||||
| 	void *priv; | ||||
| }; | ||||
|  | ||||
| /* | ||||
| @@ -535,7 +583,7 @@ struct nand_flash_dev { | ||||
| */ | ||||
| struct nand_manufacturers { | ||||
| 	int id; | ||||
| 	char * name; | ||||
| 	char *name; | ||||
| }; | ||||
|  | ||||
| extern const struct nand_flash_dev nand_flash_ids[]; | ||||
| @@ -548,7 +596,7 @@ extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt); | ||||
| extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | ||||
| 			   int allowbbt); | ||||
| extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | ||||
| 			size_t * retlen, uint8_t * buf); | ||||
| 			size_t *retlen, uint8_t *buf); | ||||
|  | ||||
| /* | ||||
| * Constants for oob configuration | ||||
| @@ -569,17 +617,20 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, | ||||
|  * @priv:		hardware controller specific settings | ||||
|  */ | ||||
| struct platform_nand_chip { | ||||
| 	int			nr_chips; | ||||
| 	int			chip_offset; | ||||
| 	int			nr_partitions; | ||||
| 	struct mtd_partition	*partitions; | ||||
| 	struct nand_ecclayout	*ecclayout; | ||||
| 	int			chip_delay; | ||||
| 	unsigned int		options; | ||||
| 	const char		**part_probe_types; | ||||
| 	void			*priv; | ||||
| 	int nr_chips; | ||||
| 	int chip_offset; | ||||
| 	int nr_partitions; | ||||
| 	struct mtd_partition *partitions; | ||||
| 	struct nand_ecclayout *ecclayout; | ||||
| 	int chip_delay; | ||||
| 	unsigned int options; | ||||
| 	const char **part_probe_types; | ||||
| 	void *priv; | ||||
| }; | ||||
|  | ||||
| /* Keep gcc happy */ | ||||
| struct platform_device; | ||||
|  | ||||
| /** | ||||
|  * struct platform_nand_ctrl - controller level device structure | ||||
|  * @hwcontrol:		platform specific hardware control structure | ||||
| @@ -592,12 +643,11 @@ struct platform_nand_chip { | ||||
|  * All fields are optional and depend on the hardware driver requirements | ||||
|  */ | ||||
| struct platform_nand_ctrl { | ||||
| 	void		(*hwcontrol)(struct mtd_info *mtd, int cmd); | ||||
| 	int		(*dev_ready)(struct mtd_info *mtd); | ||||
| 	void		(*select_chip)(struct mtd_info *mtd, int chip); | ||||
| 	void		(*cmd_ctrl)(struct mtd_info *mtd, int dat, | ||||
| 				    unsigned int ctrl); | ||||
| 	void		*priv; | ||||
| 	void (*hwcontrol)(struct mtd_info *mtd, int cmd); | ||||
| 	int (*dev_ready)(struct mtd_info *mtd); | ||||
| 	void (*select_chip)(struct mtd_info *mtd, int chip); | ||||
| 	void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); | ||||
| 	void *priv; | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -606,8 +656,8 @@ struct platform_nand_ctrl { | ||||
|  * @ctrl:		controller level device structure | ||||
|  */ | ||||
| struct platform_nand_data { | ||||
| 	struct platform_nand_chip	chip; | ||||
| 	struct platform_nand_ctrl	ctrl; | ||||
| 	struct platform_nand_chip chip; | ||||
| 	struct platform_nand_ctrl ctrl; | ||||
| }; | ||||
|  | ||||
| /* Some helpers to access the data structures */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user