diff options
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 459 | ||||
| -rw-r--r-- | include/linux/mtd/bbm.h | 23 | ||||
| -rw-r--r-- | include/linux/mtd/nand.h | 368 | 
3 files changed, 538 insertions, 312 deletions
| diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 758b53fa2..ed2640c3e 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -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 */ - -	tmp_manf = chip->read_byte(mtd); -	tmp_id = chip->read_byte(mtd); +	for (i = 0; i < 2; i++) +		id_data[i] = 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);  } diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 7db25465d..2fb36177a 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -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 diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 527d9ae03..99668d552 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -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 */ |