diff options
Diffstat (limited to 'drivers/mtd/onenand/onenand_base.c')
| -rw-r--r-- | drivers/mtd/onenand/onenand_base.c | 131 | 
1 files changed, 94 insertions, 37 deletions
| diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ded1706ab..eaa48f948 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -331,7 +331,7 @@ static inline int onenand_bufferram_offset(struct mtd_info *mtd, int area)  	if (ONENAND_CURRENT_BUFFERRAM(this)) {  		if (area == ONENAND_DATARAM) -			return mtd->oobblock; +			return mtd->writesize;  		if (area == ONENAND_SPARERAM)  			return mtd->oobsize;  	} @@ -482,6 +482,30 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,  }  /** + * onenand_invalidate_bufferram - [GENERIC] Invalidate BufferRAM information + * @param mtd           MTD data structure + * @param addr          start address to invalidate + * @param len           length to invalidate + * + * Invalidate BufferRAM information + */ +static void onenand_invalidate_bufferram(struct mtd_info *mtd, loff_t addr, +                                         unsigned int len) +{ +	struct onenand_chip *this = mtd->priv; +	int i; +	loff_t end_addr = addr + len; + +	/* Invalidate BufferRAM */ +	for (i = 0; i < MAX_BUFFERRAM; i++) { +		loff_t buf_addr = this->bufferram[i].block << this->erase_shift; + +		if (buf_addr >= addr && buf_addr < end_addr) +			this->bufferram[i].valid = 0; +	} +} + +/**   * onenand_get_device - [GENERIC] Get chip for selected access   * @param mtd		MTD device structure   * @param new_state	the state which is requested @@ -541,15 +565,15 @@ static int onenand_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,  	onenand_get_device(mtd, FL_READING);  	while (read < len) { -		thislen = min_t(int, mtd->oobblock, len - read); +		thislen = min_t(int, mtd->writesize, len - read); -		column = from & (mtd->oobblock - 1); -		if (column + thislen > mtd->oobblock) -			thislen = mtd->oobblock - column; +		column = from & (mtd->writesize - 1); +		if (column + thislen > mtd->writesize) +			thislen = mtd->writesize - column;  		if (!onenand_check_bufferram(mtd, from)) {  			this->command(mtd, ONENAND_CMD_READ, from, -				      mtd->oobblock); +				      mtd->writesize);  			ret = this->wait(mtd, FL_READING);  			/* First copy data and check return value for ECC handling */  			onenand_update_bufferram(mtd, from, 1); @@ -664,7 +688,7 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, size_t len,  		/* Read more? */  		if (read < len) {  			/* Page size */ -			from += mtd->oobblock; +			from += mtd->writesize;  			column = 0;  		}  	} @@ -691,7 +715,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf,  	void __iomem *dataram0, *dataram1;  	int ret = 0; -	this->command(mtd, ONENAND_CMD_READ, addr, mtd->oobblock); +	this->command(mtd, ONENAND_CMD_READ, addr, mtd->writesize);  	ret = this->wait(mtd, FL_READING);  	if (ret) @@ -701,9 +725,9 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf,  	/* Check, if the two dataram areas are same */  	dataram0 = this->base + ONENAND_DATARAM; -	dataram1 = dataram0 + mtd->oobblock; +	dataram1 = dataram0 + mtd->writesize; -	if (memcmp(dataram0, dataram1, mtd->oobblock)) +	if (memcmp(dataram0, dataram1, mtd->writesize))  		return -EBADMSG;  	return 0; @@ -712,7 +736,7 @@ static int onenand_verify_page(struct mtd_info *mtd, u_char * buf,  #define onenand_verify_page(...)	(0)  #endif -#define NOTALIGNED(x)	((x & (mtd->oobblock - 1)) != 0) +#define NOTALIGNED(x)	((x & (mtd->writesize - 1)) != 0)  /**   * onenand_write_ecc - [MTD Interface] OneNAND write with ECC @@ -760,15 +784,15 @@ static int onenand_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,  	/* Loop until all data write */  	while (written < len) { -		int thislen = min_t(int, mtd->oobblock, len - written); +		int thislen = min_t(int, mtd->writesize, len - written); -		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->oobblock); +		this->command(mtd, ONENAND_CMD_BUFFERRAM, to, mtd->writesize);  		this->write_bufferram(mtd, ONENAND_DATARAM, buf, 0, thislen);  		this->write_bufferram(mtd, ONENAND_SPARERAM, ffchars, 0,  				      mtd->oobsize); -		this->command(mtd, ONENAND_CMD_PROG, to, mtd->oobblock); +		this->command(mtd, ONENAND_CMD_PROG, to, mtd->writesize);  		onenand_update_bufferram(mtd, to, 1); @@ -893,6 +917,25 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, size_t len,  }  /** + * onenand_block_isbad_nolock - [GENERIC] Check if a block is marked bad + * @param mtd		MTD device structure + * @param ofs		offset from device start + * @param allowbbt	1, if its allowed to access the bbt area + * + * Check, if the block is bad, Either by reading the bad block table or + * calling of the scan function. + */ +static int onenand_block_isbad_nolock(struct mtd_info *mtd, loff_t ofs, int allowbbt) +{ +	struct onenand_chip *this = mtd->priv; +	struct bbm_info *bbm = this->bbm; + +	/* Return info from the table */ +	return bbm->isbad_bbt(mtd, ofs, allowbbt); +} + + +/**   * onenand_erase - [MTD Interface] erase block(s)   * @param mtd		MTD device structure   * @param instr		erase instruction @@ -950,6 +993,8 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)  		this->command(mtd, ONENAND_CMD_ERASE, addr, block_size); +		onenand_invalidate_bufferram(mtd, addr, block_size); +  		ret = this->wait(mtd, FL_ERASING);  		/* Check, if it is write protected */  		if (ret) { @@ -1005,30 +1050,45 @@ void onenand_sync(struct mtd_info *mtd)   * onenand_block_isbad - [MTD Interface] Check whether the block at the given offset is bad   * @param mtd		MTD device structure   * @param ofs		offset relative to mtd start + * + * Check whether the block is bad   */  int onenand_block_isbad(struct mtd_info *mtd, loff_t ofs)  { -	/* -	 * TODO -	 * 1. Bad block table (BBT) -	 *   -> using NAND BBT to support JFFS2 -	 * 2. Bad block management (BBM) -	 *   -> bad block replace scheme -	 * -	 * Currently we do nothing -	 */ -	return 0; +	int ret; + +	/* Check for invalid offset */ +	if (ofs > mtd->size) +		return -EINVAL; + +	onenand_get_device(mtd, FL_READING); +	ret = onenand_block_isbad_nolock(mtd,ofs, 0); +	onenand_release_device(mtd); +	return ret;  }  /**   * onenand_block_markbad - [MTD Interface] Mark the block at the given offset as bad   * @param mtd		MTD device structure   * @param ofs		offset relative to mtd start + * + * Mark the block as bad   */  int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs)  { -	/* see above */ -	return 0; +	struct onenand_chip *this = mtd->priv; +	int ret; + +	ret = onenand_block_isbad(mtd, ofs); +	if (ret) { +		/* If it was bad already, return success and do nothing */ +		if (ret > 0) +			return 0; +		return ret; +	} + +	ret = this->block_markbad(mtd, ofs); +	return ret;  }  /** @@ -1184,10 +1244,8 @@ static int onenand_probe(struct mtd_info *mtd)  	/* Reset OneNAND to read default register values */  	this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM); -	{ -		int i; -		for (i = 0; i < 10000; i++) ; -	} +	/* Wait reset */ +	this->wait(mtd, FL_RESETING);  	/* Read manufacturer and device IDs from Register */  	maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID); @@ -1212,16 +1270,16 @@ static int onenand_probe(struct mtd_info *mtd)  	/* OneNAND page size & block size */  	/* The data buffer size is equal to page size */ -	mtd->oobblock = +	mtd->writesize =  	    this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE); -	mtd->oobsize = mtd->oobblock >> 5; +	mtd->oobsize = mtd->writesize >> 5;  	/* Pagers per block is always 64 in OneNAND */ -	mtd->erasesize = mtd->oobblock << 6; +	mtd->erasesize = mtd->writesize << 6;  	this->erase_shift = ffs(mtd->erasesize) - 1; -	this->page_shift = ffs(mtd->oobblock) - 1; +	this->page_shift = ffs(mtd->writesize) - 1;  	this->ppb_shift = (this->erase_shift - this->page_shift); -	this->page_mask = (mtd->erasesize / mtd->oobblock) - 1; +	this->page_mask = (mtd->erasesize / mtd->writesize) - 1;  	/* REVIST: Multichip handling */ @@ -1240,11 +1298,10 @@ static int onenand_probe(struct mtd_info *mtd)  		this->options |= ONENAND_CONT_LOCK;  	} +	mtd->flags = MTD_CAP_NANDFLASH;  	mtd->erase = onenand_erase;  	mtd->read = onenand_read;  	mtd->write = onenand_write; -	mtd->read_ecc = onenand_read_ecc; -	mtd->write_ecc = onenand_write_ecc;  	mtd->read_oob = onenand_read_oob;  	mtd->write_oob = onenand_write_oob;  	mtd->sync = onenand_sync; |