diff options
| author | Wolfgang Denk <wd@denx.de> | 2012-02-11 22:14:56 +0100 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2012-02-11 22:14:56 +0100 | 
| commit | f57a94c2b566a647003c7885a450ba0f28dbff34 (patch) | |
| tree | 4ed0e63aaaad760e9494c1cb83e405e2ac7c07ed | |
| parent | 6e4c1da86e77576476b566977305ddd82f9e6b8c (diff) | |
| parent | 0990dc61787ec03b0ae7579a51e5eb661112f13f (diff) | |
| download | olio-uboot-2014.01-f57a94c2b566a647003c7885a450ba0f28dbff34.tar.xz olio-uboot-2014.01-f57a94c2b566a647003c7885a450ba0f28dbff34.zip | |
Merge branch 'master' of /home/wd/git/u-boot/custodians
* 'master' of /home/wd/git/u-boot/custodians:
  nand/fsl_elbc: Convert to self-init
  nand: Introduce CONFIG_SYS_NAND_SELF_INIT
  nand_spl: store ecc data on the stack
  mtd/nand: Add ONFI support for FSL NAND controller
  nand: make 1-bit software ECC configurable
  nand: Sanitize ONFI strings.
  nand: Merge changes to BBT from Linux nand driver
  nand: Merge changes from Linux nand driver
  nand: cleanup whitespace
  nand: Add more NAND types from Linux nand driver
  nand: Merge BCH code from Linux nand driver
  NAND: Remove additional (CONFIG_SYS)_NAND_MAX_CHIPS
  NAND: remove NAND_MAX_CHIPS definitions
  nand_spl_simple: store ecc data on the stack
66 files changed, 3082 insertions, 690 deletions
| diff --git a/doc/README.nand b/doc/README.nand index 023740e1d..04a87c991 100644 --- a/doc/README.nand +++ b/doc/README.nand @@ -120,6 +120,68 @@ Configuration Options:     CONFIG_SYS_NAND_MAX_CHIPS        The maximum number of NAND chips per device to be supported. +   CONFIG_SYS_NAND_SELF_INIT +      Traditionally, glue code in drivers/mtd/nand/nand.c has driven +      the initialization process -- it provides the mtd and nand +      structs, calls a board init function for a specific device, +      calls nand_scan(), and registers with mtd. + +      This arrangement does not provide drivers with the flexibility to +      run code between nand_scan_ident() and nand_scan_tail(), or other +      deviations from the "normal" flow. + +      If a board defines CONFIG_SYS_NAND_SELF_INIT, drivers/mtd/nand/nand.c +      will make one call to board_nand_init(), with no arguments.  That +      function is responsible for calling a driver init function for +      each NAND device on the board, that performs all initialization +      tasks except setting mtd->name, and registering with the rest of +      U-Boot.  Those last tasks are accomplished by calling  nand_register() +      on the new mtd device. + +      Example of new init to be added to the end of an existing driver +      init: + +	/* +	 * devnum is the device number to be used in nand commands +	 * and in mtd->name.  Must be less than +	 * CONFIG_SYS_NAND_MAX_DEVICE. +	 */ +	mtd = &nand_info[devnum]; + +	/* chip is struct nand_chip, and is now provided by the driver. */ +	mtd->priv = &chip; + +	/* +	 * Fill in appropriate values if this driver uses these fields, +	 * or uses the standard read_byte/write_buf/etc. functions from +	 * nand_base.c that use these fields. +	 */ +	chip.IO_ADDR_R = ...; +	chip.IO_ADDR_W = ...; + +	if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_CHIPS, NULL)) +		error out + +	/* +	 * Insert here any code you wish to run after the chip has been +	 * identified, but before any other I/O is done. +	 */ + +	if (nand_scan_tail(mtd)) +		error out + +	if (nand_register(devnum)) +		error out + +      In addition to providing more flexibility to the driver, it reduces +      the difference between a U-Boot driver and its Linux counterpart. +      nand_init() is now reduced to calling board_nand_init() once, and +      printing a size summary.  This should also make it easier to +      transition to delayed NAND initialization. + +      Please convert your driver even if you don't need the extra +      flexibility, so that one day we can eliminate the old mechanism. +  NOTE:  ===== diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 36ee45430..998fc7349 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -39,8 +39,9 @@ COBJS-y += nand_bbt.o  COBJS-y += nand_ids.o  COBJS-y += nand_util.o  endif -COBJS-y += nand_ecc.o +COBJS-$(CONFIG_MTD_ECC_SOFT) += nand_ecc.o  COBJS-y += nand_base.o +COBJS-$(CONFIG_NAND_ECC_BCH) += nand_bch.o  COBJS-$(CONFIG_NAND_ATMEL) += atmel_nand.o  COBJS-$(CONFIG_DRIVER_NAND_BFIN) += bfin_nand.o diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4d1e527db..9076ad4cd 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -22,6 +22,7 @@  #include <common.h>  #include <malloc.h> +#include <nand.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> @@ -57,7 +58,6 @@ struct fsl_elbc_ctrl;  /* mtd information per set */  struct fsl_elbc_mtd { -	struct mtd_info mtd;  	struct nand_chip chip;  	struct fsl_elbc_ctrl *ctrl; @@ -340,18 +340,21 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,  	/* READID must read all 5 possible bytes while CEB is active */  	case NAND_CMD_READID: -		vdbg("fsl_elbc_cmdfunc: NAND_CMD_READID.\n"); +	case NAND_CMD_PARAM: +		vdbg("fsl_elbc_cmdfunc: NAND_CMD 0x%x.\n", command);  		out_be32(&lbc->fir, (FIR_OP_CW0 << FIR_OP0_SHIFT) |  				    (FIR_OP_UA  << FIR_OP1_SHIFT) |  				    (FIR_OP_RBW << FIR_OP2_SHIFT)); -		out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT); -		/* 5 bytes for manuf, device and exts */ -		out_be32(&lbc->fbcr, 5); -		ctrl->read_bytes = 5; +		out_be32(&lbc->fcr, command << FCR_CMD0_SHIFT); +		/* +		 * although currently it's 8 bytes for READID, we always read +		 * the maximum 256 bytes(for PARAM) +		 */ +		out_be32(&lbc->fbcr, 256); +		ctrl->read_bytes = 256;  		ctrl->use_mdr = 1; -		ctrl->mdr = 0; - +		ctrl->mdr = column;  		set_addr(mtd, 0, 0, 0);  		fsl_elbc_run_command(mtd);  		return; @@ -683,10 +686,13 @@ static void fsl_elbc_ctrl_init(void)  	elbc_ctrl->addr = NULL;  } -int board_nand_init(struct nand_chip *nand) +static int fsl_elbc_chip_init(int devnum, u8 *addr)  { +	struct mtd_info *mtd = &nand_info[devnum]; +	struct nand_chip *nand;  	struct fsl_elbc_mtd *priv;  	uint32_t br = 0, or = 0; +	int ret;  	if (!elbc_ctrl) {  		fsl_elbc_ctrl_init(); @@ -699,19 +705,19 @@ int board_nand_init(struct nand_chip *nand)  		return -ENOMEM;  	priv->ctrl = elbc_ctrl; -	priv->vbase = nand->IO_ADDR_R; +	priv->vbase = addr;  	/* Find which chip select it is connected to.  It'd be nice  	 * if we could pass more than one datum to the NAND driver...  	 */  	for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { -		phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R); +		phys_addr_t phys_addr = virt_to_phys(addr);  		br = in_be32(&elbc_ctrl->regs->bank[priv->bank].br);  		or = in_be32(&elbc_ctrl->regs->bank[priv->bank].or);  		if ((br & BR_V) && (br & BR_MSEL) == BR_MS_FCM && -		    (br & or & BR_BA) == BR_PHYS_ADDR(base_addr)) +		    (br & or & BR_BA) == BR_PHYS_ADDR(phys_addr))  			break;  	} @@ -721,6 +727,9 @@ int board_nand_init(struct nand_chip *nand)  		return -ENODEV;  	} +	nand = &priv->chip; +	mtd->priv = nand; +  	elbc_ctrl->chips[priv->bank] = priv;  	/* fill in nand_chip structure */ @@ -791,5 +800,32 @@ int board_nand_init(struct nand_chip *nand)  		}  	} +	ret = nand_scan_ident(mtd, 1, NULL); +	if (ret) +		return ret; + +	ret = nand_scan_tail(mtd); +	if (ret) +		return ret; + +	ret = nand_register(devnum); +	if (ret) +		return ret; +  	return 0;  } + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = +	CONFIG_SYS_NAND_BASE_LIST; + +void board_nand_init(void) +{ +	int i; + +	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) +		fsl_elbc_chip_init(i, (u8 *)base_address[i]); +} diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c index d987f4c85..4cf4c1c70 100644 --- a/drivers/mtd/nand/nand.c +++ b/drivers/mtd/nand/nand.c @@ -23,6 +23,7 @@  #include <common.h>  #include <nand.h> +#include <errno.h>  #ifndef CONFIG_SYS_NAND_BASE_LIST  #define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } @@ -31,63 +32,84 @@  DECLARE_GLOBAL_DATA_PTR;  int nand_curr_device = -1; + +  nand_info_t nand_info[CONFIG_SYS_MAX_NAND_DEVICE]; +#ifndef CONFIG_SYS_NAND_SELF_INIT  static struct nand_chip nand_chip[CONFIG_SYS_MAX_NAND_DEVICE];  static ulong base_address[CONFIG_SYS_MAX_NAND_DEVICE] = CONFIG_SYS_NAND_BASE_LIST; +#endif + +static char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; + +static unsigned long total_nand_size; /* in kiB */ + +/* Register an initialized NAND mtd device with the U-Boot NAND command. */ +int nand_register(int devnum) +{ +	struct mtd_info *mtd; + +	if (devnum >= CONFIG_SYS_MAX_NAND_DEVICE) +		return -EINVAL; + +	mtd = &nand_info[devnum]; + +	sprintf(dev_name[devnum], "nand%d", devnum); +	mtd->name = dev_name[devnum]; + +#ifdef CONFIG_MTD_DEVICE +	/* +	 * Add MTD device so that we can reference it later +	 * via the mtdcore infrastructure (e.g. ubi). +	 */ +	add_mtd_device(mtd); +#endif + +	total_nand_size += mtd->size / 1024; -static const char default_nand_name[] = "nand"; -static __attribute__((unused)) char dev_name[CONFIG_SYS_MAX_NAND_DEVICE][8]; +	if (nand_curr_device == -1) +		nand_curr_device = devnum; + +	return 0; +} -static void nand_init_chip(struct mtd_info *mtd, struct nand_chip *nand, -			   ulong base_addr) +#ifndef CONFIG_SYS_NAND_SELF_INIT +static void nand_init_chip(int i)  { +	struct mtd_info *mtd = &nand_info[i]; +	struct nand_chip *nand = &nand_chip[i]; +	ulong base_addr = base_address[i];  	int maxchips = CONFIG_SYS_NAND_MAX_CHIPS; -	static int __attribute__((unused)) i = 0;  	if (maxchips < 1)  		maxchips = 1; -	mtd->priv = nand; +	mtd->priv = nand;  	nand->IO_ADDR_R = nand->IO_ADDR_W = (void  __iomem *)base_addr; -	if (board_nand_init(nand) == 0) { -		if (nand_scan(mtd, maxchips) == 0) { -			if (!mtd->name) -				mtd->name = (char *)default_nand_name; -#ifdef CONFIG_NEEDS_MANUAL_RELOC -			else -				mtd->name += gd->reloc_off; -#endif -#ifdef CONFIG_MTD_DEVICE -			/* -			 * Add MTD device so that we can reference it later -			 * via the mtdcore infrastructure (e.g. ubi). -			 */ -			sprintf(dev_name[i], "nand%d", i); -			mtd->name = dev_name[i++]; -			add_mtd_device(mtd); -#endif -		} else -			mtd->name = NULL; -	} else { -		mtd->name = NULL; -		mtd->size = 0; -	} +	if (board_nand_init(nand)) +		return; +	if (nand_scan(mtd, maxchips)) +		return; + +	nand_register(i);  } +#endif  void nand_init(void)  { +#ifdef CONFIG_SYS_NAND_SELF_INIT +	board_nand_init(); +#else  	int i; -	unsigned int size = 0; -	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) { -		nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]); -		size += nand_info[i].size / 1024; -		if (nand_curr_device == -1) -			nand_curr_device = i; -	} -	printf("%u MiB\n", size / 1024); + +	for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) +		nand_init_chip(i); +#endif + +	printf("%lu MiB\n", total_nand_size / 1024);  #ifdef CONFIG_SYS_NAND_SELECT_DEVICE  	/* diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 27f6c776b..12b960fdb 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -43,6 +43,7 @@  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h>  #include <linux/mtd/nand_ecc.h> +#include <linux/mtd/nand_bch.h>  #ifdef CONFIG_MTD_PARTITIONS  #include <linux/mtd/partitions.h> @@ -70,7 +71,7 @@ static struct nand_ecclayout nand_oob_8 = {  		{.offset = 3,  		 .length = 2},  		{.offset = 6, -		 .length = 2}} +		 .length = 2} }  };  static struct nand_ecclayout nand_oob_16 = { @@ -78,7 +79,7 @@ static struct nand_ecclayout nand_oob_16 = {  	.eccpos = {0, 1, 2, 3, 6, 7},  	.oobfree = {  		{.offset = 8, -		 . length = 8}} +		 . length = 8} }  };  static struct nand_ecclayout nand_oob_64 = { @@ -89,24 +90,23 @@ static struct nand_ecclayout nand_oob_64 = {  		   56, 57, 58, 59, 60, 61, 62, 63},  	.oobfree = {  		{.offset = 2, -		 .length = 38}} +		 .length = 38} }  };  static struct nand_ecclayout nand_oob_128 = {  	.eccbytes = 48,  	.eccpos = { -		    80,  81,  82,  83,	84,  85,  86,  87, -		    88,  89,  90,  91,	92,  93,  94,  95, -		    96,  97,  98,  99, 100, 101, 102, 103, +		   80, 81, 82, 83, 84, 85, 86, 87, +		   88, 89, 90, 91, 92, 93, 94, 95, +		   96, 97, 98, 99, 100, 101, 102, 103,  		   104, 105, 106, 107, 108, 109, 110, 111,  		   112, 113, 114, 115, 116, 117, 118, 119,  		   120, 121, 122, 123, 124, 125, 126, 127},  	.oobfree = {  		{.offset = 2, -		 .length = 78}} +		 .length = 78} }  }; -  static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,  			   int new_state); @@ -115,16 +115,47 @@ 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   *   * Deselect, release chip lock and wake up anyone waiting on the device   */ -static void nand_release_device (struct mtd_info *mtd) +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);  }  /** @@ -768,8 +824,9 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,   *   * We need a special oob layout and handling even when OOB isn't used.   */ -static int nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, -			      uint8_t *buf, int page) +static int nand_read_page_raw_syndrome(struct mtd_info *mtd, +					struct nand_chip *chip, +					uint8_t *buf, int page)  {  	int eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -850,7 +907,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,   * @readlen:	data length   * @bufpoi:	buffer to store read data   */ -static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) +static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, +			uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)  {  	int start_step, end_step, num_steps;  	uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -858,6 +916,7 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3  	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; @@ -896,26 +955,30 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint3  	} 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; @@ -1082,7 +1145,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,  static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  				  struct mtd_oob_ops *ops, size_t len)  { -	switch(ops->mode) { +	switch (ops->mode) {  	case MTD_OOB_PLACE:  	case MTD_OOB_RAW: @@ -1094,7 +1157,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,  		uint32_t boffs = 0, roffs = ops->ooboffs;  		size_t bytes = 0; -		for(; free->length && len; free++, len -= bytes) { +		for (; free->length && len; free++, len -= bytes) {  			/* Read request not from offset 0 ? */  			if (unlikely(roffs)) {  				if (roffs >= free->length) { @@ -1140,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; @@ -1155,7 +1221,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	buf = ops->datbuf;  	oob = ops->oobbuf; -	while(1) { +	while (1) {  		WATCHDOG_RESET();  		bytes = min(mtd->writesize - col, readlen); @@ -1173,18 +1239,20 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  			/* Now read the page into the buffer */  			if (unlikely(ops->mode == MTD_OOB_RAW))  				ret = chip->ecc.read_page_raw(mtd, chip, -						bufpoi, page); +							      bufpoi, page);  			else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) -				ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); +				ret = chip->ecc.read_subpage(mtd, chip, +							col, bytes, bufpoi);  			else  				ret = chip->ecc.read_page(mtd, chip, bufpoi, -						page); +							  page);  			if (ret < 0)  				break;  			/* 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);  			} @@ -1192,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)) { @@ -1259,11 +1323,11 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,  	if (mtd->ecc_stats.failed - stats.failed)  		return -EBADMSG; -	return	mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; +	return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;  }  /** - * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc + * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc   * @mtd:	MTD device structure   * @from:	offset to read from   * @len:	number of bytes to read @@ -1456,8 +1520,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	int len;  	uint8_t *buf = ops->oobbuf; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", -		  (unsigned long long)from, readlen); +	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", +			__func__, (unsigned long long)from, readlen);  	if (ops->mode == MTD_OOB_AUTO)  		len = chip->ecc.layout->oobavail; @@ -1465,8 +1529,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  		len = mtd->oobsize;  	if (unlikely(ops->ooboffs >= len)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt to start read outside oob\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " +					"outside oob\n", __func__);  		return -EINVAL;  	} @@ -1474,8 +1538,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	if (unlikely(from >= mtd->size ||  		     ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -  					(from >> chip->page_shift)) * len)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt read beyond end of device\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " +					"of device\n", __func__);  		return -EINVAL;  	} @@ -1486,7 +1550,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,  	realpage = (int)(from >> chip->page_shift);  	page = realpage & chip->pagemask; -	while(1) { +	while (1) {  		WATCHDOG_RESET();  		sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); @@ -1550,14 +1614,14 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,  	/* Do not allow reads past end of device */  	if (ops->datbuf && (from + ops->len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt read beyond end of device\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " +				"beyond end of device\n", __func__);  		return -EINVAL;  	}  	nand_get_device(chip, mtd, FL_READING); -	switch(ops->mode) { +	switch (ops->mode) {  	case MTD_OOB_PLACE:  	case MTD_OOB_AUTO:  	case MTD_OOB_RAW: @@ -1572,7 +1636,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,  	else  		ret = nand_do_read_ops(mtd, from, ops); - out: +out:  	nand_release_device(mtd);  	return ret;  } @@ -1601,8 +1665,9 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,   *   * We need a special oob layout and handling even when ECC isn't checked.   */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, -				const uint8_t *buf) +static void nand_write_page_raw_syndrome(struct mtd_info *mtd, +					struct nand_chip *chip, +					const uint8_t *buf)  {  	int eccsize = chip->ecc.size;  	int eccbytes = chip->ecc.bytes; @@ -1789,14 +1854,13 @@ 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) { +	switch (ops->mode) {  	case MTD_OOB_PLACE:  	case MTD_OOB_RAW: @@ -1808,7 +1872,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,  		uint32_t boffs = 0, woffs = ops->ooboffs;  		size_t bytes = 0; -		for(; free->length && len; free++, len -= bytes) { +		for (; free->length && len; free++, len -= bytes) {  			/* Write request not from offset 0 ? */  			if (unlikely(woffs)) {  				if (woffs >= free->length) { @@ -1834,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 @@ -1850,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; @@ -1886,7 +1955,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,  	if (likely(!oob))  		memset(chip->oob_poi, 0xff, mtd->oobsize); -	while(1) { +	/* Don't allow multipage oob writes with offset */ +	if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) +		return -EINVAL; + +	while (1) {  		WATCHDOG_RESET();  		int bytes = mtd->writesize; @@ -1903,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)); @@ -1985,8 +2061,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	int chipnr, page, status, len;  	struct nand_chip *chip = mtd->priv; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", -		  (unsigned int)to, (int)ops->ooblen); +	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", +			 __func__, (unsigned int)to, (int)ops->ooblen);  	if (ops->mode == MTD_OOB_AUTO)  		len = chip->ecc.layout->oobavail; @@ -1995,24 +2071,24 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,  	/* Do not allow write past end of page */  	if ((ops->ooboffs + ops->ooblen) > len) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " -			  "Attempt to write past end of page\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " +				"past end of page\n", __func__);  		return -EINVAL;  	}  	if (unlikely(ops->ooboffs >= len)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt to start write outside oob\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " +				"write outside oob\n", __func__);  		return -EINVAL;  	} -	/* Do not allow reads past end of device */ +	/* Do not allow write past end of device */  	if (unlikely(to >= mtd->size ||  		     ops->ooboffs + ops->ooblen >  			((mtd->size >> chip->page_shift) -  			 (to >> chip->page_shift)) * len)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt write beyond end of device\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " +				"end of device\n", __func__);  		return -EINVAL;  	} @@ -2039,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); @@ -2067,14 +2143,14 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,  	/* Do not allow writes past end of device */  	if (ops->datbuf && (to + ops->len) > mtd->size) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: " -			  "Attempt read beyond end of device\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " +				"end of device\n", __func__);  		return -EINVAL;  	}  	nand_get_device(chip, mtd, FL_WRITING); -	switch(ops->mode) { +	switch (ops->mode) {  	case MTD_OOB_PLACE:  	case MTD_OOB_AUTO:  	case MTD_OOB_RAW: @@ -2089,7 +2165,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,  	else  		ret = nand_do_write_ops(mtd, to, ops); - out: +out:  	nand_release_device(mtd);  	return ret;  } @@ -2158,31 +2234,14 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	unsigned int bbt_masked_page = 0xffffffff;  	loff_t len; -	MTDDEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, " -		 "len = %llu\n", (unsigned long long) instr->addr, -		 (unsigned long long) instr->len); +	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", +				__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); @@ -2199,8 +2258,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	/* Check, if it is write protected */  	if (nand_check_wp(mtd)) { -		MTDDEBUG (MTD_DEBUG_LEVEL0, -			  "nand_erase: Device is write protected!!!\n"); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", +					__func__);  		instr->state = MTD_ERASE_FAILED;  		goto erase_exit;  	} @@ -2226,8 +2285,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		 */  		if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) <<  					chip->page_shift, 0, allowbbt)) { -			printk(KERN_WARNING "nand_erase: attempt to erase a " -			       "bad block at page 0x%08x\n", page); +			printk(KERN_WARNING "%s: attempt to erase a bad block " +					"at page 0x%08x\n", __func__, page);  			instr->state = MTD_ERASE_FAILED;  			goto erase_exit;  		} @@ -2254,10 +2313,11 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		/* See if block erase succeeded */  		if (status & NAND_STATUS_FAIL) { -			MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " -				  "Failed erase, page 0x%08x\n", page); +			MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " +					"page 0x%08x\n", __func__, page);  			instr->state = MTD_ERASE_FAILED; -			instr->fail_addr = ((loff_t)page << chip->page_shift); +			instr->fail_addr = +				((loff_t)page << chip->page_shift);  			goto erase_exit;  		} @@ -2292,7 +2352,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  	}  	instr->state = MTD_ERASE_DONE; - erase_exit: +erase_exit:  	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO; @@ -2314,9 +2374,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,  		if (!rewrite_bbt[chipnr])  			continue;  		/* update the BBT for chip */ -		MTDDEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " -			  "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], -			  chip->bbt_td->pages[chipnr]); +		MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " +			"(%d:0x%0llx 0x%0x)\n", __func__, chipnr, +			rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]);  		nand_update_bbt(mtd, rewrite_bbt[chipnr]);  	} @@ -2334,7 +2394,7 @@ static void nand_sync(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; -	MTDDEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); +	MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__);  	/* Grab the lock and see if the device is available */  	nand_get_device(chip, mtd, FL_SYNCING); @@ -2366,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; @@ -2416,10 +2477,29 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)  }  #ifdef CONFIG_SYS_NAND_ONFI_DETECTION +/* + * sanitize ONFI strings so we can safely print them + */ +static void sanitize_string(char *s, size_t len) +{ +	ssize_t i; + +	/* null terminate */ +	s[len - 1] = 0; + +	/* remove non printable chars */ +	for (i = 0; i < len - 1; i++) { +		if (s[i] < ' ' || s[i] > 127) +			s[i] = '?'; +	} + +	/* remove trailing spaces */ +	strim(s); +} +  static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)  {  	int i; -  	while (len--) {  		crc ^= *p++ << 8;  		for (i = 0; i < 8; i++) @@ -2432,14 +2512,14 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)  /*   * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise   */ -static int nand_flash_detect_onfi(struct mtd_info *mtd, -					struct nand_chip *chip, +static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,  					int *busw)  {  	struct nand_onfi_params *p = &chip->onfi_params;  	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') @@ -2450,7 +2530,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,  	for (i = 0; i < 3; i++) {  		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));  		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == -						le16_to_cpu(p->crc)) { +				le16_to_cpu(p->crc)) {  			printk(KERN_INFO "ONFI param page %d valid\n", i);  			break;  		} @@ -2475,14 +2555,15 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,  		chip->onfi_version = 0;  	if (!chip->onfi_version) { -		printk(KERN_INFO "%s: unsupported ONFI " -					"version: %d\n", __func__, val); +		printk(KERN_INFO "%s: unsupported ONFI version: %d\n", +								__func__, val);  		return 0;  	} +	sanitize_string(p->manufacturer, sizeof(p->manufacturer)); +	sanitize_string(p->model, sizeof(p->model));  	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); @@ -2491,6 +2572,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd,  	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 @@ -2502,41 +2587,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   */ @@ -2546,8 +2596,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); @@ -2573,15 +2624,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);  	} @@ -2592,30 +2641,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  	 */ @@ -2650,18 +2790,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) @@ -2673,9 +2843,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;  } @@ -2704,7 +2880,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,  	nand_set_defaults(chip, busw);  	/* Read the flash type */ -	type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id, &nand_dev_id, table); +	type = nand_get_flash_type(mtd, chip, busw, +				&nand_maf_id, &nand_dev_id, table);  	if (IS_ERR(type)) {  #ifndef CONFIG_SYS_NAND_QUIET_TEST @@ -2763,7 +2940,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	/*  	 * If no default placement scheme is given, select an appropriate one  	 */ -	if (!chip->ecc.layout) { +	if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {  		switch (mtd->oobsize) {  		case 8:  			chip->ecc.layout = &nand_oob_8; @@ -2796,7 +2973,7 @@ int nand_scan_tail(struct mtd_info *mtd)  		/* Similar to NAND_ECC_HW, but a separate read_page handle */  		if (!chip->ecc.calculate || !chip->ecc.correct ||  		     !chip->ecc.hwctl) { -			printk(KERN_WARNING "No ECC functions supplied, " +			printk(KERN_WARNING "No ECC functions supplied; "  			       "Hardware ECC not possible\n");  			BUG();  		} @@ -2825,7 +3002,7 @@ int nand_scan_tail(struct mtd_info *mtd)  		     chip->ecc.read_page == nand_read_page_hwecc ||  		     !chip->ecc.write_page ||  		     chip->ecc.write_page == nand_write_page_hwecc)) { -			printk(KERN_WARNING "No ECC functions supplied, " +			printk(KERN_WARNING "No ECC functions supplied; "  			       "Hardware ECC not possible\n");  			BUG();  		} @@ -2851,6 +3028,10 @@ int nand_scan_tail(struct mtd_info *mtd)  		chip->ecc.mode = NAND_ECC_SOFT;  	case NAND_ECC_SOFT: +		if (!mtd_nand_has_ecc_soft()) { +			printk(KERN_WARNING "CONFIG_MTD_ECC_SOFT not enabled\n"); +			return -EINVAL; +		}  		chip->ecc.calculate = nand_calculate_ecc;  		chip->ecc.correct = nand_correct_data;  		chip->ecc.read_page = nand_read_page_swecc; @@ -2860,10 +3041,44 @@ 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; +	case NAND_ECC_SOFT_BCH: +		if (!mtd_nand_has_bch()) { +			printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); +			return -EINVAL; +		} +		chip->ecc.calculate = nand_bch_calculate_ecc; +		chip->ecc.correct = nand_bch_correct_data; +		chip->ecc.read_page = nand_read_page_swecc; +		chip->ecc.read_subpage = nand_read_subpage; +		chip->ecc.write_page = nand_write_page_swecc; +		chip->ecc.read_page_raw = nand_read_page_raw; +		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; +		/* +		 * Board driver should supply ecc.size and ecc.bytes values to +		 * select how many bits are correctable; see nand_bch_init() +		 * for details. +		 * Otherwise, default to 4 bits for large page devices +		 */ +		if (!chip->ecc.size && (mtd->oobsize >= 64)) { +			chip->ecc.size = 512; +			chip->ecc.bytes = 7; +		} +		chip->ecc.priv = nand_bch_init(mtd, +					       chip->ecc.size, +					       chip->ecc.bytes, +					       &chip->ecc.layout); +		if (!chip->ecc.priv) +			printk(KERN_WARNING "BCH ECC initialization failed!\n"); + +		break; +  	case NAND_ECC_NONE:  		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "  		       "This is not recommended !!\n"); @@ -2899,7 +3114,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	 * mode  	 */  	chip->ecc.steps = mtd->writesize / chip->ecc.size; -	if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { +	if (chip->ecc.steps * chip->ecc.size != mtd->writesize) {  		printk(KERN_WARNING "Invalid ecc parameters\n");  		BUG();  	} @@ -2911,7 +3126,7 @@ int nand_scan_tail(struct mtd_info *mtd)  	 */  	if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&  	    !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { -		switch(chip->ecc.steps) { +		switch (chip->ecc.steps) {  		case 2:  			mtd->subpage_sft = 1;  			break; @@ -2935,7 +3150,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; @@ -2954,9 +3170,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);  }  /** @@ -2989,6 +3206,9 @@ void nand_release(struct mtd_info *mtd)  {  	struct nand_chip *chip = mtd->priv; +	if (chip->ecc.mode == NAND_ECC_SOFT_BCH) +		nand_bch_free((struct nand_bch_control *)chip->ecc.priv); +  #ifdef CONFIG_MTD_PARTITIONS  	/* Deregister partitions */  	del_mtd_partitions(mtd); @@ -2998,4 +3218,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/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ded652be3..2b730e09c 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -13,27 +13,36 @@   * Description:   *   * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a - * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number - * than the mirror bbt is used to build the memory based bbt. + * depending on the options in the BBT descriptor(s). If no flash based BBT + * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * marked good / bad blocks. This information is used to create a memory BBT. + * Once a new bad block is discovered then the "factory" information is updated + * on the device. + * If a flash based BBT is specified then the function first tries to find the + * BBT on flash. If a BBT is found then the contents are read and the memory + * based BBT is created. If a mirrored BBT is selected then the mirror is + * searched too and the versions are compared. If the mirror has a greater + * version number than the mirror BBT is used to build the memory based BBT.   * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked + * If one of the BBTs is out of date or does not exist it is (re)created. + * If no BBT exists at all then the device is scanned for factory marked   * good / bad blocks and the bad block tables are created.   * - * For manufacturer created bbts like the one found on M-SYS DOC devices - * the bbt is searched and read but never created + * For manufacturer created BBTs like the one found on M-SYS DOC devices + * the BBT is searched and read but never created   * - * The autogenerated bad block table is located in the last good blocks + * The auto generated bad block table is located in the last good blocks   * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version - * number which indicates which of both tables is more up to date. + * The table is marked in the OOB area with an ident pattern and a version + * number which indicates which of both tables is more up to date. If the NAND + * controller needs the complete OOB area for the ECC information then the + * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern + * and the version byte into the data area and the OOB area will remain + * untouched.   *   * The table uses 2 bits per block - * 11b:	block is good - * 00b:	block is factory marked bad + * 11b:		block is good + * 00b:		block is factory marked bad   * 01b, 10b:	block is marked bad due to wear   *   * The memory bad block table uses the following scheme: @@ -55,9 +64,21 @@  #include <linux/mtd/compat.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/bitops.h>  #include <asm/errno.h> +static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) +{ +	int ret; + +	ret = memcmp(buf, td->pattern, td->len); +	if (!ret) +		return ret; +	return -1; +} +  /**   * check_pattern - [GENERIC] check if a pattern is in the buffer   * @buf:	the buffer to search @@ -76,6 +97,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  	int i, end = 0;  	uint8_t *p = buf; +	if (td->options & NAND_BBT_NO_OOB) +		return check_pattern_no_oob(buf, td); +  	end = paglen + td->offs;  	if (td->options & NAND_BBT_SCANEMPTY) {  		for (i = 0; i < end; i++) { @@ -91,6 +115,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  			return -1;  	} +	/* Check both positions 1 and 6 for pattern? */ +	if (td->options & NAND_BBT_SCANBYTE1AND6) { +		if (td->options & NAND_BBT_SCANEMPTY) { +			p += td->len; +			end += NAND_SMALL_BADBLOCK_POS - td->offs; +			/* Check region between positions 1 and 6 */ +			for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; +					i++) { +				if (*p++ != 0xff) +					return -1; +			} +		} +		else { +			p += NAND_SMALL_BADBLOCK_POS - td->offs; +		} +		/* Compare the pattern */ +		for (i = 0; i < td->len; i++) { +			if (p[i] != td->pattern[i]) +				return -1; +		} +	} +  	if (td->options & NAND_BBT_SCANEMPTY) {  		p += td->len;  		end += td->len; @@ -122,36 +168,74 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)  		if (p[td->offs + i] != td->pattern[i])  			return -1;  	} +	/* Need to check location 1 AND 6? */ +	if (td->options & NAND_BBT_SCANBYTE1AND6) { +		for (i = 0; i < td->len; i++) { +			if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) +				return -1; +		} +	}  	return 0;  }  /** + * add_marker_len - compute the length of the marker in data area + * @td:		BBT descriptor used for computation + * + * The length will be 0 if the markeris located in OOB area. + */ +static u32 add_marker_len(struct nand_bbt_descr *td) +{ +	u32 len; + +	if (!(td->options & NAND_BBT_NO_OOB)) +		return 0; + +	len = td->len; +	if (td->options & NAND_BBT_VERSION) +		len++; +	return len; +} + +/**   * read_bbt - [GENERIC] Read the bad block table starting from page   * @mtd:	MTD device structure   * @buf:	temporary buffer   * @page:	the starting page   * @num:	the number of bbt descriptors to read - * @bits:	number of bits per block + * @td:		the bbt describtion table   * @offs:	offset in the memory table - * @reserved_block_code:	Pattern to identify reserved blocks   *   * Read the bad block table starting from page.   *   */  static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, -		    int bits, int offs, int reserved_block_code) +		struct nand_bbt_descr *td, int offs)  {  	int res, i, j, act = 0;  	struct nand_chip *this = mtd->priv;  	size_t retlen, len, totlen;  	loff_t from; +	int bits = td->options & NAND_BBT_NRBITS_MSK;  	uint8_t msk = (uint8_t) ((1 << bits) - 1); +	u32 marker_len; +	int reserved_block_code = td->reserved_block_code;  	totlen = (num * bits) >> 3; +	marker_len = add_marker_len(td);  	from = ((loff_t) page) << this->page_shift;  	while (totlen) {  		len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); +		if (marker_len) { +			/* +			 * In case the BBT marker is not in the OOB area it +			 * will be just in the first page. +			 */ +			len -= marker_len; +			from += marker_len; +			marker_len = 0; +		}  		res = mtd->read(mtd, from, len, &retlen, buf);  		if (res < 0) {  			if (retlen != len) { @@ -170,9 +254,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  					continue;  				if (reserved_block_code && (tmp == reserved_block_code)) {  					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", -						(loff_t)((offs << 2) + -						(act >> 1)) << -						this->bbt_erase_shift); +					       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);  					mtd->ecc_stats.bbtblocks++;  					continue; @@ -180,8 +262,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  				/* Leave it for now, if its matured we can move this  				 * message to MTD_DEBUG_LEVEL0 */  				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", -					(loff_t)((offs << 2) + (act >> 1)) << -					this->bbt_erase_shift); +				       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  				/* Factory marked bad or worn out ? */  				if (tmp == 0)  					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -211,20 +292,21 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  {  	struct nand_chip *this = mtd->priv;  	int res = 0, i; -	int bits; -	bits = td->options & NAND_BBT_NRBITS_MSK;  	if (td->options & NAND_BBT_PERCHIP) {  		int offs = 0;  		for (i = 0; i < this->numchips; i++) {  			if (chip == -1 || chip == i) -				res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); +				res = read_bbt(mtd, buf, td->pages[i], +					this->chipsize >> this->bbt_erase_shift, +					td, offs);  			if (res)  				return res;  			offs += this->chipsize >> (this->bbt_erase_shift + 2);  		}  	} else { -		res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); +		res = read_bbt(mtd, buf, td->pages[0], +				mtd->size >> this->bbt_erase_shift, td, 0);  		if (res)  			return res;  	} @@ -232,21 +314,64 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  }  /* + * BBT marker is in the first page, no OOB. + */ +static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +			 struct nand_bbt_descr *td) +{ +	size_t retlen; +	size_t len; + +	len = td->len; +	if (td->options & NAND_BBT_VERSION) +		len++; + +	return mtd->read(mtd, offs, len, &retlen, buf); +} + +/*   * Scan read raw data from flash   */ -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 size_t len)  {  	struct mtd_oob_ops ops; +	int res;  	ops.mode = MTD_OOB_RAW;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize; -	ops.oobbuf = buf; -	ops.datbuf = buf; -	ops.len = len; -	return mtd->read_oob(mtd, offs, &ops); + +	while (len > 0) { +		if (len <= mtd->writesize) { +			ops.oobbuf = buf + len; +			ops.datbuf = buf; +			ops.len = len; +			return mtd->read_oob(mtd, offs, &ops); +		} else { +			ops.oobbuf = buf + mtd->writesize; +			ops.datbuf = buf; +			ops.len = mtd->writesize; +			res = mtd->read_oob(mtd, offs, &ops); + +			if (res) +				return res; +		} + +		buf += mtd->oobsize + mtd->writesize; +		len -= mtd->writesize; +	} +	return 0; +} + +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +			 size_t len, struct nand_bbt_descr *td) +{ +	if (td->options & NAND_BBT_NO_OOB) +		return scan_read_raw_data(mtd, buf, offs, td); +	else +		return scan_read_raw_oob(mtd, buf, offs, len);  }  /* @@ -267,6 +392,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,  	return mtd->write_oob(mtd, offs, &ops);  } +static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ +	u32 ver_offs = td->veroffs; + +	if (!(td->options & NAND_BBT_NO_OOB)) +		ver_offs += mtd->writesize; +	return ver_offs; +} +  /**   * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page   * @mtd:	MTD device structure @@ -285,18 +419,18 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,  	/* Read the primary version, if available */  	if (td->options & NAND_BBT_VERSION) { -		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << -				this->page_shift, mtd->writesize); -		td->version[0] = buf[mtd->writesize + td->veroffs]; +		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, +			      mtd->writesize, td); +		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];  		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",  		       td->pages[0], td->version[0]);  	}  	/* Read the mirror version, if available */  	if (md && (md->options & NAND_BBT_VERSION)) { -		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << -				this->page_shift, mtd->writesize); -		md->version[0] = buf[mtd->writesize + md->veroffs]; +		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, +			      mtd->writesize, td); +		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];  		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",  		       md->pages[0], md->version[0]);  	} @@ -312,7 +446,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  {  	int ret, j; -	ret = scan_read_raw(mtd, buf, offs, readlen); +	ret = scan_read_raw_oob(mtd, buf, offs, readlen);  	if (ret)  		return ret; @@ -376,16 +510,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	loff_t from;  	size_t readlen; -	MTDDEBUG (MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n"); +	MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");  	if (bd->options & NAND_BBT_SCANALLPAGES)  		len = 1 << (this->bbt_erase_shift - this->page_shift); -	else { -		if (bd->options & NAND_BBT_SCAN2NDPAGE) -			len = 2; -		else -			len = 1; -	} +	else if (bd->options & NAND_BBT_SCAN2NDPAGE) +		len = 2; +	else +		len = 1;  	if (!(bd->options & NAND_BBT_SCANEMPTY)) {  		/* We need only read few bytes from the OOB area */ @@ -415,9 +547,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		from = (loff_t)startblock << (this->bbt_erase_shift - 1);  	} +	if (this->options & NAND_BBT_SCANLASTPAGE) +		from += mtd->erasesize - (mtd->writesize * len); +  	for (i = startblock; i < numblocks;) {  		int ret; +		BUG_ON(bd->options & NAND_BBT_NO_OOB); +  		if (bd->options & NAND_BBT_SCANALLPAGES)  			ret = scan_block_full(mtd, bd, from, buf, readlen,  					      scanlen, len); @@ -429,7 +566,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (ret) {  			this->bbt[i >> 3] |= 0x03 << (i & 0x6); -			MTDDEBUG (MTD_DEBUG_LEVEL0, +			MTDDEBUG(MTD_DEBUG_LEVEL0,  				  "Bad eraseblock %d at 0x%012llx\n",  				  i >> 1, (unsigned long long)from);  			mtd->ecc_stats.badblocks++; @@ -497,11 +634,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;  			/* Read first page */ -			scan_read_raw(mtd, buf, offs, mtd->writesize); +			scan_read_raw(mtd, buf, offs, mtd->writesize, td);  			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {  				td->pages[i] = actblock << blocktopage;  				if (td->options & NAND_BBT_VERSION) { -					td->version[i] = buf[mtd->writesize + td->veroffs]; +					offs = bbt_get_ver_offs(mtd, td); +					td->version[i] = buf[offs];  				}  				break;  			} @@ -685,12 +823,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));  			ooboffs = len + (pageoffs * mtd->oobsize); +		} else if (td->options & NAND_BBT_NO_OOB) { +			ooboffs = 0; +			offs = td->len; +			/* the version byte */ +			if (td->options & NAND_BBT_VERSION) +				offs++; +			/* Calc length */ +			len = (size_t) (numblocks >> sft); +			len += offs; +			/* Make it page aligned ! */ +			len = ALIGN(len, mtd->writesize); +			/* Preset the buffer with 0xff */ +			memset(buf, 0xff, len); +			/* Pattern is located at the begin of first page */ +			memcpy(buf, td->pattern, td->len);  		} else {  			/* Calc length */  			len = (size_t) (numblocks >> sft);  			/* Make it page aligned ! */ -			len = (len + (mtd->writesize - 1)) & -				~(mtd->writesize - 1); +			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len +  			       (len >> this->page_shift)* mtd->oobsize); @@ -724,13 +876,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (res < 0)  			goto outerr; -		res = scan_write_bbt(mtd, to, len, buf, &buf[len]); +		res = scan_write_bbt(mtd, to, len, buf, +				td->options & NAND_BBT_NO_OOB ? NULL : +				&buf[len]);  		if (res < 0)  			goto outerr; -		printk(KERN_DEBUG "Bad block table written to 0x%012llx, " -		       "version 0x%02X\n", (unsigned long long)to, -		       td->version[chip]); +		printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " +		       "0x%02X\n", (unsigned long long)to, td->version[chip]);  		/* Mark it as used */  		td->pages[chip] = page; @@ -791,7 +944,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  		rd2 = NULL;  		/* Per chip or per device ? */  		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; -		/* Mirrored table avilable ? */ +		/* Mirrored table available ? */  		if (md) {  			if (td->pages[i] == -1 && md->pages[i] == -1) {  				writeops = 0x03; @@ -845,7 +998,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  			continue;  		/* Create the table in memory by scanning the chip(s) */ -		create_bbt(mtd, buf, bd, chipsel); +		if (!(this->options & NAND_CREATE_EMPTY_BBT)) +			create_bbt(mtd, buf, bd, chipsel);  		td->version[i] = 1;  		if (md) @@ -910,8 +1064,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  			newval = oldval | (0x2 << (block & 0x06));  			this->bbt[(block >> 3)] = newval;  			if ((oldval != newval) && td->reserved_block_code) -				nand_update_bbt(mtd, (loff_t)block << -					(this->bbt_erase_shift - 1)); +				nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));  			continue;  		}  		update = 0; @@ -932,9 +1085,56 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  		   new ones have been marked, then we need to update the stored  		   bbts.  This should only happen once. */  		if (update && td->reserved_block_code) -			nand_update_bbt(mtd, (loff_t)(block - 2) << -				(this->bbt_erase_shift - 1)); +			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); +	} +} + +/** + * verify_bbt_descr - verify the bad block description + * @mtd:	MTD device structure + * @bd:		the table to verify + * + * This functions performs a few sanity checks on the bad block description + * table. + */ +static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ +	struct nand_chip *this = mtd->priv; +	u32 pattern_len; +	u32 bits; +	u32 table_size; + +	if (!bd) +		return; + +	pattern_len = bd->len; +	bits = bd->options & NAND_BBT_NRBITS_MSK; + +	BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && +			!(this->options & NAND_USE_FLASH_BBT)); +	BUG_ON(!bits); + +	if (bd->options & NAND_BBT_VERSION) +		pattern_len++; + +	if (bd->options & NAND_BBT_NO_OOB) { +		BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); +		BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); +		BUG_ON(bd->offs); +		if (bd->options & NAND_BBT_VERSION) +			BUG_ON(bd->veroffs != bd->len); +		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);  	} + +	if (bd->options & NAND_BBT_PERCHIP) +		table_size = this->chipsize >> this->bbt_erase_shift; +	else +		table_size = mtd->size >> this->bbt_erase_shift; +	table_size >>= 3; +	table_size *= bits; +	if (bd->options & NAND_BBT_NO_OOB) +		table_size += pattern_len; +	BUG_ON(table_size > (1 << this->bbt_erase_shift));  }  /** @@ -978,6 +1178,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  		}  		return res;  	} +	verify_bbt_descr(mtd, td); +	verify_bbt_descr(mtd, md);  	/* Allocate a temporary buffer for one eraseblock incl. oob */  	len = (1 << this->bbt_erase_shift); @@ -1073,34 +1275,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)   * while scanning a device for factory marked good / bad blocks. */  static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; -static struct nand_bbt_descr smallpage_memorybased = { -	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 5, -	.len = 1, -	.pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_memorybased = { -	.options = 0, -	.offs = 0, -	.len = 2, -	.pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr smallpage_flashbased = { -	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 5, -	.len = 1, -	.pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_flashbased = { -	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 0, -	.len = 2, -	.pattern = scan_ff_pattern -}; -  static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };  static struct nand_bbt_descr agand_flashbased = { @@ -1135,6 +1309,59 @@ static struct nand_bbt_descr bbt_mirror_descr = {  	.pattern = mirror_pattern  }; +static struct nand_bbt_descr bbt_main_no_bbt_descr = { +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE +		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP +		| NAND_BBT_NO_OOB, +	.len = 4, +	.veroffs = 4, +	.maxblocks = 4, +	.pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE +		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP +		| NAND_BBT_NO_OOB, +	.len = 4, +	.veroffs = 4, +	.maxblocks = 4, +	.pattern = mirror_pattern +}; + +#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ +		NAND_BBT_SCANBYTE1AND6) +/** + * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure + * @this:	NAND chip to create descriptor for + * + * This function allocates and initializes a nand_bbt_descr for BBM detection + * based on the properties of "this". The new descriptor is stored in + * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when + * passed to this function. + * + */ +static int nand_create_default_bbt_descr(struct nand_chip *this) +{ +	struct nand_bbt_descr *bd; +	if (this->badblock_pattern) { +		printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); +		return -EINVAL; +	} +	bd = kzalloc(sizeof(*bd), GFP_KERNEL); +	if (!bd) { +		printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); +		return -ENOMEM; +	} +	bd->options = this->options & BBT_SCAN_OPTIONS; +	bd->offs = this->badblockpos; +	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; +	bd->pattern = scan_ff_pattern; +	bd->options |= NAND_BBT_DYNAMICSTRUCT; +	this->badblock_pattern = bd; +	return 0; +} +  /**   * nand_default_bbt - [NAND Interface] Select a default bad block table for the device   * @mtd:	MTD device structure @@ -1168,20 +1395,22 @@ int nand_default_bbt(struct mtd_info *mtd)  	if (this->options & NAND_USE_FLASH_BBT) {  		/* Use the default pattern descriptors */  		if (!this->bbt_td) { -			this->bbt_td = &bbt_main_descr; -			this->bbt_md = &bbt_mirror_descr; -		} -		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; +			if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { +				this->bbt_td = &bbt_main_no_bbt_descr; +				this->bbt_md = &bbt_mirror_no_bbt_descr; +			} else { +				this->bbt_td = &bbt_main_descr; +				this->bbt_md = &bbt_mirror_descr; +			}  		}  	} else {  		this->bbt_td = NULL;  		this->bbt_md = NULL; -		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->writesize > 512) ? -			    &largepage_memorybased : &smallpage_memorybased; -		}  	} + +	if (!this->badblock_pattern) +		nand_create_default_bbt_descr(this); +  	return nand_scan_bbt(mtd, this->badblock_pattern);  } @@ -1202,8 +1431,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  	block = (int)(offs >> (this->bbt_erase_shift - 1));  	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; -	MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: " -	          "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1); +	MTDDEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", +	      (unsigned int)offs, block >> 1, res);  	switch ((int)res) {  	case 0x00: diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c new file mode 100644 index 000000000..7835fce29 --- /dev/null +++ b/drivers/mtd/nand/nand_bch.c @@ -0,0 +1,236 @@ +/* + * This file provides ECC correction for more than 1 bit per block of data, + * using binary BCH codes. It relies on the generic BCH library lib/bch.c. + * + * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 or (at your option) any + * later version. + * + * This file 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 file; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <common.h> +/*#include <asm/io.h>*/ +#include <linux/types.h> + +#include <linux/bitops.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/nand_bch.h> +#include <linux/bch.h> +#include <malloc.h> + +/** + * struct nand_bch_control - private NAND BCH control structure + * @bch:       BCH control structure + * @ecclayout: private ecc layout for this BCH configuration + * @errloc:    error location array + * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid + */ +struct nand_bch_control { +	struct bch_control   *bch; +	struct nand_ecclayout ecclayout; +	unsigned int         *errloc; +	unsigned char        *eccmask; +}; + +/** + * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block + * @mtd:	MTD block structure + * @buf:	input buffer with raw data + * @code:	output buffer with ECC + */ +int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, +			   unsigned char *code) +{ +	const struct nand_chip *chip = mtd->priv; +	struct nand_bch_control *nbc = chip->ecc.priv; +	unsigned int i; + +	memset(code, 0, chip->ecc.bytes); +	encode_bch(nbc->bch, buf, chip->ecc.size, code); + +	/* apply mask so that an erased page is a valid codeword */ +	for (i = 0; i < chip->ecc.bytes; i++) +		code[i] ^= nbc->eccmask[i]; + +	return 0; +} + +/** + * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd:	MTD block structure + * @buf:	raw data read from the chip + * @read_ecc:	ECC from the chip + * @calc_ecc:	the ECC calculated from raw data + * + * Detect and correct bit errors for a data byte block + */ +int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, +			  unsigned char *read_ecc, unsigned char *calc_ecc) +{ +	const struct nand_chip *chip = mtd->priv; +	struct nand_bch_control *nbc = chip->ecc.priv; +	unsigned int *errloc = nbc->errloc; +	int i, count; + +	count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, +			   NULL, errloc); +	if (count > 0) { +		for (i = 0; i < count; i++) { +			if (errloc[i] < (chip->ecc.size*8)) +				/* error is located in data, correct it */ +				buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); +			/* else error in ecc, no action needed */ + +			MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", +			      __func__, errloc[i]); +		} +	} else if (count < 0) { +		printk(KERN_ERR "ecc unrecoverable error\n"); +		count = -1; +	} +	return count; +} + +/** + * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction + * @mtd:	MTD block structure + * @eccsize:	ecc block size in bytes + * @eccbytes:	ecc length in bytes + * @ecclayout:	output default layout + * + * Returns: + *  a pointer to a new NAND BCH control structure, or NULL upon failure + * + * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes + * are used to compute BCH parameters m (Galois field order) and t (error + * correction capability). @eccbytes should be equal to the number of bytes + * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. + * + * Example: to configure 4 bit correction per 512 bytes, you should pass + * @eccsize = 512  (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) + * @eccbytes = 7   (7 bytes are required to store m*t = 13*4 = 52 bits) + */ +struct nand_bch_control * +nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes, +	      struct nand_ecclayout **ecclayout) +{ +	unsigned int m, t, eccsteps, i; +	struct nand_ecclayout *layout; +	struct nand_bch_control *nbc = NULL; +	unsigned char *erased_page; + +	if (!eccsize || !eccbytes) { +		printk(KERN_WARNING "ecc parameters not supplied\n"); +		goto fail; +	} + +	m = fls(1+8*eccsize); +	t = (eccbytes*8)/m; + +	nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); +	if (!nbc) +		goto fail; + +	nbc->bch = init_bch(m, t, 0); +	if (!nbc->bch) +		goto fail; + +	/* verify that eccbytes has the expected value */ +	if (nbc->bch->ecc_bytes != eccbytes) { +		printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", +		       eccbytes, nbc->bch->ecc_bytes); +		goto fail; +	} + +	eccsteps = mtd->writesize/eccsize; + +	/* if no ecc placement scheme was provided, build one */ +	if (!*ecclayout) { + +		/* handle large page devices only */ +		if (mtd->oobsize < 64) { +			printk(KERN_WARNING "must provide an oob scheme for " +			       "oobsize %d\n", mtd->oobsize); +			goto fail; +		} + +		layout = &nbc->ecclayout; +		layout->eccbytes = eccsteps*eccbytes; + +		/* reserve 2 bytes for bad block marker */ +		if (layout->eccbytes+2 > mtd->oobsize) { +			printk(KERN_WARNING "no suitable oob scheme available " +			       "for oobsize %d eccbytes %u\n", mtd->oobsize, +			       eccbytes); +			goto fail; +		} +		/* put ecc bytes at oob tail */ +		for (i = 0; i < layout->eccbytes; i++) +			layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i; + +		layout->oobfree[0].offset = 2; +		layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; + +		*ecclayout = layout; +	} + +	/* sanity checks */ +	if (8*(eccsize+eccbytes) >= (1 << m)) { +		printk(KERN_WARNING "eccsize %u is too large\n", eccsize); +		goto fail; +	} +	if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) { +		printk(KERN_WARNING "invalid ecc layout\n"); +		goto fail; +	} + +	nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); +	nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); +	if (!nbc->eccmask || !nbc->errloc) +		goto fail; +	/* +	 * compute and store the inverted ecc of an erased ecc block +	 */ +	erased_page = kmalloc(eccsize, GFP_KERNEL); +	if (!erased_page) +		goto fail; + +	memset(erased_page, 0xff, eccsize); +	memset(nbc->eccmask, 0, eccbytes); +	encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); +	kfree(erased_page); + +	for (i = 0; i < eccbytes; i++) +		nbc->eccmask[i] ^= 0xff; + +	return nbc; +fail: +	nand_bch_free(nbc); +	return NULL; +} + +/** + * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources + * @nbc:	NAND BCH control structure + */ +void nand_bch_free(struct nand_bch_control *nbc) +{ +	if (nbc) { +		free_bch(nbc->bch); +		kfree(nbc->errloc); +		kfree(nbc->eccmask); +		kfree(nbc); +	} +} diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 8d7ea767d..39535497f 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -76,9 +76,13 @@ const struct nand_flash_dev nand_flash_ids[] = {  	/*512 Megabit */  	{"NAND 64MiB 1,8V 8-bit",	0xA2, 0,  64, 0, LP_OPTIONS}, +	{"NAND 64MiB 1,8V 8-bit",	0xA0, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 3,3V 8-bit",	0xF2, 0,  64, 0, LP_OPTIONS}, +	{"NAND 64MiB 3,3V 8-bit",	0xD0, 0,  64, 0, LP_OPTIONS},  	{"NAND 64MiB 1,8V 16-bit",	0xB2, 0,  64, 0, LP_OPTIONS16}, +	{"NAND 64MiB 1,8V 16-bit",	0xB0, 0,  64, 0, LP_OPTIONS16},  	{"NAND 64MiB 3,3V 16-bit",	0xC2, 0,  64, 0, LP_OPTIONS16}, +	{"NAND 64MiB 3,3V 16-bit",	0xC0, 0,  64, 0, LP_OPTIONS16},  	/* 1 Gigabit */  	{"NAND 128MiB 1,8V 8-bit",	0xA1, 0, 128, 0, LP_OPTIONS}, @@ -86,6 +90,7 @@ const struct nand_flash_dev nand_flash_ids[] = {  	{"NAND 128MiB 3,3V 8-bit",	0xD1, 0, 128, 0, LP_OPTIONS},  	{"NAND 128MiB 1,8V 16-bit",	0xB1, 0, 128, 0, LP_OPTIONS16},  	{"NAND 128MiB 3,3V 16-bit",	0xC1, 0, 128, 0, LP_OPTIONS16}, +	{"NAND 128MiB 1,8V 16-bit",     0xAD, 0, 128, 0, LP_OPTIONS16},  	/* 2 Gigabit */  	{"NAND 256MiB 1,8V 8-bit",	0xAA, 0, 256, 0, LP_OPTIONS}, @@ -111,6 +116,36 @@ const struct nand_flash_dev nand_flash_ids[] = {  	{"NAND 2GiB 1,8V 16-bit",	0xB5, 0, 2048, 0, LP_OPTIONS16},  	{"NAND 2GiB 3,3V 16-bit",	0xC5, 0, 2048, 0, LP_OPTIONS16}, +	/* 32 Gigabit */ +	{"NAND 4GiB 1,8V 8-bit",	0xA7, 0, 4096, 0, LP_OPTIONS}, +	{"NAND 4GiB 3,3V 8-bit",	0xD7, 0, 4096, 0, LP_OPTIONS}, +	{"NAND 4GiB 1,8V 16-bit",	0xB7, 0, 4096, 0, LP_OPTIONS16}, +	{"NAND 4GiB 3,3V 16-bit",	0xC7, 0, 4096, 0, LP_OPTIONS16}, + +	/* 64 Gigabit */ +	{"NAND 8GiB 1,8V 8-bit",	0xAE, 0, 8192, 0, LP_OPTIONS}, +	{"NAND 8GiB 3,3V 8-bit",	0xDE, 0, 8192, 0, LP_OPTIONS}, +	{"NAND 8GiB 1,8V 16-bit",	0xBE, 0, 8192, 0, LP_OPTIONS16}, +	{"NAND 8GiB 3,3V 16-bit",	0xCE, 0, 8192, 0, LP_OPTIONS16}, + +	/* 128 Gigabit */ +	{"NAND 16GiB 1,8V 8-bit",	0x1A, 0, 16384, 0, LP_OPTIONS}, +	{"NAND 16GiB 3,3V 8-bit",	0x3A, 0, 16384, 0, LP_OPTIONS}, +	{"NAND 16GiB 1,8V 16-bit",	0x2A, 0, 16384, 0, LP_OPTIONS16}, +	{"NAND 16GiB 3,3V 16-bit",	0x4A, 0, 16384, 0, LP_OPTIONS16}, + +	/* 256 Gigabit */ +	{"NAND 32GiB 1,8V 8-bit",	0x1C, 0, 32768, 0, LP_OPTIONS}, +	{"NAND 32GiB 3,3V 8-bit",	0x3C, 0, 32768, 0, LP_OPTIONS}, +	{"NAND 32GiB 1,8V 16-bit",	0x2C, 0, 32768, 0, LP_OPTIONS16}, +	{"NAND 32GiB 3,3V 16-bit",	0x4C, 0, 32768, 0, LP_OPTIONS16}, + +	/* 512 Gigabit */ +	{"NAND 64GiB 1,8V 8-bit",	0x1E, 0, 65536, 0, LP_OPTIONS}, +	{"NAND 64GiB 3,3V 8-bit",	0x3E, 0, 65536, 0, LP_OPTIONS}, +	{"NAND 64GiB 1,8V 16-bit",	0x2E, 0, 65536, 0, LP_OPTIONS16}, +	{"NAND 64GiB 3,3V 16-bit",	0x4E, 0, 65536, 0, LP_OPTIONS16}, +  	/*  	 * Renesas AND 1 Gigabit. Those chips do not support extended id and  	 * have a strange page/block layout !  The chosen minimum erasesize is diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c index 7eb08a3b0..4a4d02f4c 100644 --- a/drivers/mtd/nand/nand_spl_simple.c +++ b/drivers/mtd/nand/nand_spl_simple.c @@ -27,6 +27,11 @@ static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS;  static nand_info_t mtd;  static struct nand_chip nand_chip; +#define ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ +					CONFIG_SYS_NAND_ECCSIZE) +#define ECCTOTAL	(ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) + +  #if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)  /*   * NAND command for small page NAND devices (512) @@ -145,29 +150,21 @@ static int nand_is_bad_block(int block)  static int nand_read_page(int block, int page, uchar *dst)  {  	struct nand_chip *this = mtd.priv; -	u_char *ecc_calc; -	u_char *ecc_code; -	u_char *oob_data; +	u_char ecc_calc[ECCTOTAL]; +	u_char ecc_code[ECCTOTAL]; +	u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];  	int i;  	int eccsize = CONFIG_SYS_NAND_ECCSIZE;  	int eccbytes = CONFIG_SYS_NAND_ECCBYTES; -	int eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	int eccsteps = ECCSTEPS;  	uint8_t *p = dst; -	/* -	 * No malloc available for now, just use some temporary locations -	 * in SDRAM -	 */ -	ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000); -	ecc_code = ecc_calc + 0x100; -	oob_data = ecc_calc + 0x200; -  	nand_command(block, page, 0, NAND_CMD_READOOB);  	this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);  	nand_command(block, page, 0, NAND_CMD_READ0);  	/* Pick the ECC bytes out of the oob data */ -	for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++) +	for (i = 0; i < ECCTOTAL; i++)  		ecc_code[i] = oob_data[nand_ecc_pos[i]]; @@ -184,24 +181,17 @@ static int nand_read_page(int block, int page, uchar *dst)  static int nand_read_page(int block, int page, void *dst)  {  	struct nand_chip *this = mtd.priv; -	u_char *ecc_calc; -	u_char *ecc_code; -	u_char *oob_data; +	u_char ecc_calc[ECCTOTAL]; +	u_char ecc_code[ECCTOTAL]; +	u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];  	int i;  	int eccsize = CONFIG_SYS_NAND_ECCSIZE;  	int eccbytes = CONFIG_SYS_NAND_ECCBYTES; -	int eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	int eccsteps = ECCSTEPS;  	uint8_t *p = dst;  	nand_command(block, page, 0, NAND_CMD_READ0); -	/* No malloc available for now, just use some temporary locations -	 * in SDRAM -	 */ -	ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000); -	ecc_code = ecc_calc + 0x100; -	oob_data = ecc_calc + 0x200; -  	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  		if (this->ecc.mode != NAND_ECC_SOFT)  			this->ecc.hwctl(&mtd, NAND_ECC_READ); @@ -211,10 +201,10 @@ static int nand_read_page(int block, int page, void *dst)  	this->read_buf(&mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);  	/* Pick the ECC bytes out of the oob data */ -	for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++) +	for (i = 0; i < ECCTOTAL; i++)  		ecc_code[i] = oob_data[nand_ecc_pos[i]]; -	eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	eccsteps = ECCSTEPS;  	p = dst;  	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { diff --git a/include/configs/P1_P2_RDB.h b/include/configs/P1_P2_RDB.h index 00fa74d6f..cee788ab1 100644 --- a/include/configs/P1_P2_RDB.h +++ b/include/configs/P1_P2_RDB.h @@ -273,11 +273,10 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);  #endif  #endif +#define CONFIG_CMD_NAND  #define CONFIG_SYS_NAND_BASE_LIST	{CONFIG_SYS_NAND_BASE}  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			1  #define CONFIG_MTD_NAND_VERIFY_WRITE -#define CONFIG_CMD_NAND			1  #define CONFIG_NAND_FSL_ELBC		1  #define CONFIG_SYS_NAND_BLOCK_SIZE	(16 * 1024) diff --git a/include/configs/PMC440.h b/include/configs/PMC440.h index ed47a8782..b82095454 100644 --- a/include/configs/PMC440.h +++ b/include/configs/PMC440.h @@ -200,9 +200,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	16 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{0, 1, 2, 3, 6, 7}  #endif diff --git a/include/configs/SIMPC8313.h b/include/configs/SIMPC8313.h index 77be3600f..09760774f 100644 --- a/include/configs/SIMPC8313.h +++ b/include/configs/SIMPC8313.h @@ -144,10 +144,9 @@  #endif  #define CONFIG_SYS_FPGA_BASE		0xFF000000 +#define CONFIG_CMD_NAND  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			1  #define CONFIG_MTD_NAND_VERIFY_WRITE -#define CONFIG_CMD_NAND			1  #define CONFIG_NAND_FSL_ELBC		1  #define CONFIG_SYS_NAND_BR_PRELIM	(CONFIG_SYS_NAND_BASE \ diff --git a/include/configs/VCMA9.h b/include/configs/VCMA9.h index a370c150b..5cc8ece7d 100644 --- a/include/configs/VCMA9.h +++ b/include/configs/VCMA9.h @@ -237,7 +237,6 @@  #define CONFIG_NAND_S3C2410  #define CONFIG_SYS_S3C2410_NAND_HWECC  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			1  #define CONFIG_SYS_NAND_BASE		0x4E000000  #define CONFIG_S3C24XX_CUSTOM_NAND_TIMING  #define CONFIG_S3C24XX_TACLS		1 diff --git a/include/configs/acadia.h b/include/configs/acadia.h index 5573dc7a3..8c447ca95 100644 --- a/include/configs/acadia.h +++ b/include/configs/acadia.h @@ -185,9 +185,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	16 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{0, 1, 2, 3, 6, 7}  #ifdef CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/am3517_crane.h b/include/configs/am3517_crane.h index 0a0c261bf..b0dd2f0af 100644 --- a/include/configs/am3517_crane.h +++ b/include/configs/am3517_crane.h @@ -359,10 +359,6 @@  						10, 11, 12, 13}  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/am3517_evm.h b/include/configs/am3517_evm.h index d44eeec5b..f797f3ffd 100644 --- a/include/configs/am3517_evm.h +++ b/include/configs/am3517_evm.h @@ -360,10 +360,6 @@  						10, 11, 12, 13}  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/aria.h b/include/configs/aria.h index cf2e7d432..c9f0076ee 100644 --- a/include/configs/aria.h +++ b/include/configs/aria.h @@ -247,13 +247,9 @@   */  #define CONFIG_CMD_NAND					/* enable NAND support */  #define CONFIG_JFFS2_NAND				/* with JFFS2 on it */ - -  #define CONFIG_NAND_MPC5121_NFC  #define CONFIG_SYS_NAND_BASE		0x40000000 -  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			CONFIG_SYS_MAX_NAND_DEVICE  /*   * Configuration parameters for MPC5121 NAND driver diff --git a/include/configs/at91sam9m10g45ek.h b/include/configs/at91sam9m10g45ek.h index 5ef6bd230..6a0218810 100644 --- a/include/configs/at91sam9m10g45ek.h +++ b/include/configs/at91sam9m10g45ek.h @@ -128,7 +128,6 @@  /* NAND flash */  #ifdef CONFIG_CMD_NAND -#define CONFIG_NAND_MAX_CHIPS			1  #define CONFIG_NAND_ATMEL  #define CONFIG_SYS_MAX_NAND_DEVICE		1  #define CONFIG_SYS_NAND_BASE			ATMEL_BASE_CS3 diff --git a/include/configs/bamboo.h b/include/configs/bamboo.h index 7b66fc092..506a558f1 100644 --- a/include/configs/bamboo.h +++ b/include/configs/bamboo.h @@ -179,9 +179,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	16 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{0, 1, 2, 3, 6, 7}  #ifdef CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/bf526-ezbrd.h b/include/configs/bf526-ezbrd.h index 1945c032a..003109329 100644 --- a/include/configs/bf526-ezbrd.h +++ b/include/configs/bf526-ezbrd.h @@ -70,7 +70,6 @@  #define CONFIG_DRIVER_NAND_BFIN  #define CONFIG_SYS_NAND_BASE		0 /* not actually used */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS		1  #define CONFIG_CMD_NAND  #endif diff --git a/include/configs/bf527-ad7160-eval.h b/include/configs/bf527-ad7160-eval.h index 9c35f2d0b..fa05103e5 100644 --- a/include/configs/bf527-ad7160-eval.h +++ b/include/configs/bf527-ad7160-eval.h @@ -69,7 +69,6 @@  #define CONFIG_DRIVER_NAND_BFIN  #define CONFIG_SYS_NAND_BASE		0 /* not actually used */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS		1  #endif diff --git a/include/configs/bf527-ezkit.h b/include/configs/bf527-ezkit.h index 1256e815d..d80eac22d 100644 --- a/include/configs/bf527-ezkit.h +++ b/include/configs/bf527-ezkit.h @@ -69,7 +69,6 @@  #define CONFIG_DRIVER_NAND_BFIN  #define CONFIG_SYS_NAND_BASE		0 /* not actually used */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS		1  #endif diff --git a/include/configs/bf548-ezkit.h b/include/configs/bf548-ezkit.h index 3eadcefb8..89adfefee 100644 --- a/include/configs/bf548-ezkit.h +++ b/include/configs/bf548-ezkit.h @@ -131,7 +131,6 @@  #define CONFIG_DRIVER_NAND_BFIN  #define CONFIG_SYS_NAND_BASE		0 /* not actually used */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS		1  /* diff --git a/include/configs/cam_enc_4xx.h b/include/configs/cam_enc_4xx.h index a21d4482a..5d9672fbc 100644 --- a/include/configs/cam_enc_4xx.h +++ b/include/configs/cam_enc_4xx.h @@ -90,7 +90,6 @@  #define CONFIG_SYS_NAND_BASE_LIST	{ 0x02000000, }  /* socket has two chipselects, nCE0 gated by address BIT(14) */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define CONFIG_SYS_NAND_MAX_CHIPS	1  /* SPI support */  #define CONFIG_SPI @@ -236,9 +235,6 @@  #define CONFIG_SYS_NAND_ECCBYTES	10  #define CONFIG_SYS_NAND_OOBSIZE		64  #define CONFIG_SYS_NAND_5_ADDR_CYCLE -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE /	 \ -					 CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	(40)  /*   * RBL searches from Block n (n = 1..24) diff --git a/include/configs/canyonlands.h b/include/configs/canyonlands.h index 8c03582c8..acb127c1d 100644 --- a/include/configs/canyonlands.h +++ b/include/configs/canyonlands.h @@ -197,9 +197,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	64 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{40, 41, 42, 43, 44, 45, 46, 47, \  				 48, 49, 50, 51, 52, 53, 54, 55, \  				 56, 57, 58, 59, 60, 61, 62, 63} diff --git a/include/configs/cm-bf527.h b/include/configs/cm-bf527.h index 4f2b904d5..b15a1eb7a 100644 --- a/include/configs/cm-bf527.h +++ b/include/configs/cm-bf527.h @@ -68,7 +68,6 @@  #define CONFIG_BFIN_NFC_CTL_VAL	0x0033  #define CONFIG_SYS_NAND_BASE		0 /* not actually used */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS		1  #define CONFIG_CMD_NAND  #endif diff --git a/include/configs/cpu9260.h b/include/configs/cpu9260.h index 8674a35d2..8b6a68798 100644 --- a/include/configs/cpu9260.h +++ b/include/configs/cpu9260.h @@ -295,7 +295,6 @@  /* NAND flash */  #define CONFIG_NAND_ATMEL -#define NAND_MAX_CHIPS				1  #define CONFIG_SYS_MAX_NAND_DEVICE		1  #define CONFIG_SYS_NAND_BASE			0x40000000  #define CONFIG_SYS_NAND_DBW_8			1 diff --git a/include/configs/da830evm.h b/include/configs/da830evm.h index 6ac25d2b9..e8c021262 100644 --- a/include/configs/da830evm.h +++ b/include/configs/da830evm.h @@ -115,7 +115,6 @@  #define CONFIG_SYS_CLE_MASK		0x10  #define CONFIG_SYS_ALE_MASK		0x8  #define CONFIG_SYS_MAX_NAND_DEVICE	1 /* Max number of NAND devices */ -#define NAND_MAX_CHIPS			1  #endif  #ifdef CONFIG_USE_NOR diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h index fcbbace1c..220890dfd 100644 --- a/include/configs/da850evm.h +++ b/include/configs/da850evm.h @@ -182,7 +182,6 @@  #define CONFIG_SYS_ALE_MASK		0x8  #undef CONFIG_SYS_NAND_HW_ECC  #define CONFIG_SYS_MAX_NAND_DEVICE	1 /* Max number of NAND devices */ -#define NAND_MAX_CHIPS			1  #endif  /* diff --git a/include/configs/davinci_dm355leopard.h b/include/configs/davinci_dm355leopard.h index dfa0a0047..dc5b408a6 100644 --- a/include/configs/davinci_dm355leopard.h +++ b/include/configs/davinci_dm355leopard.h @@ -69,7 +69,6 @@  #define CONFIG_SYS_NAND_BASE_LIST	{ 0x02000000, }  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define CONFIG_SYS_NAND_MAX_CHIPS	1  /* U-Boot command configuration */  #include <config_cmd_default.h> diff --git a/include/configs/devkit8000.h b/include/configs/devkit8000.h index 758326bb9..2b6a6ee09 100644 --- a/include/configs/devkit8000.h +++ b/include/configs/devkit8000.h @@ -343,11 +343,6 @@  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS) -  #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/ea20.h b/include/configs/ea20.h index 74fec3f8b..cc0f5b05c 100644 --- a/include/configs/ea20.h +++ b/include/configs/ea20.h @@ -197,7 +197,6 @@  #define CONFIG_SYS_NAND_4BIT_HW_ECC_OOBFIRST  #define	CONFIG_SYS_NAND_USE_FLASH_BBT  #define CONFIG_SYS_MAX_NAND_DEVICE	1 /* Max number of NAND devices */ -#define NAND_MAX_CHIPS			1  #define CONFIG_SYS_64BIT_VSPRINTF	/* needed for nand_util.c */  #endif diff --git a/include/configs/eb_cpux9k2.h b/include/configs/eb_cpux9k2.h index b08de4a72..9046cf0c0 100644 --- a/include/configs/eb_cpux9k2.h +++ b/include/configs/eb_cpux9k2.h @@ -270,7 +270,6 @@  /* NAND */ -#define CONFIG_SYS_NAND_MAX_CHIPS	1  #define CONFIG_SYS_MAX_NAND_DEVICE	1  #define CONFIG_SYS_NAND_BASE		0x40000000  #define CONFIG_SYS_NAND_DBW_8		1 diff --git a/include/configs/enbw_cmc.h b/include/configs/enbw_cmc.h index c427dc7c6..83aec790e 100644 --- a/include/configs/enbw_cmc.h +++ b/include/configs/enbw_cmc.h @@ -115,7 +115,6 @@  #define CONFIG_SYS_ALE_MASK		0x8  #undef CONFIG_SYS_NAND_HW_ECC  #define CONFIG_SYS_MAX_NAND_DEVICE	1 /* Max number of NAND devices */ -#define NAND_MAX_CHIPS			1  #define MTDIDS_DEFAULT		"nor0=physmap-flash.0,nand0=davinci_nand.1"  #define MTDPARTS_DEFAULT			\ diff --git a/include/configs/hawkboard.h b/include/configs/hawkboard.h index 12acb27ae..fa214941a 100644 --- a/include/configs/hawkboard.h +++ b/include/configs/hawkboard.h @@ -114,7 +114,6 @@  /* Max number of NAND devices */  #define CONFIG_SYS_MAX_NAND_DEVICE	1  #define CONFIG_SYS_NAND_BASE_LIST	{ 0x62000000, } -#define NAND_MAX_CHIPS			1  /* Block 0--not used by bootcode */  #define CONFIG_ENV_OFFSET		0x0 @@ -138,11 +137,8 @@  #define CONFIG_SYS_NAND_BAD_BLOCK_POS	0  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	10 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE /	 \ -					 CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE		64 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES *	\ -					CONFIG_SYS_NAND_ECCSTEPS) +  #endif /* CONFIG_SYS_USE_NAND */  /* diff --git a/include/configs/kilauea.h b/include/configs/kilauea.h index e66aadf97..621dbb8fa 100644 --- a/include/configs/kilauea.h +++ b/include/configs/kilauea.h @@ -210,9 +210,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	16 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{0, 1, 2, 3, 6, 7}  #ifdef CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/km/km_arm.h b/include/configs/km/km_arm.h index 700124c0c..9c8d222c2 100644 --- a/include/configs/km/km_arm.h +++ b/include/configs/km/km_arm.h @@ -133,7 +133,6 @@   * NAND Flash configuration   */  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			1  #define BOOTFLASH_START		0x0 diff --git a/include/configs/m28evk.h b/include/configs/m28evk.h index b891b12fe..4efff0992 100644 --- a/include/configs/m28evk.h +++ b/include/configs/m28evk.h @@ -154,7 +154,6 @@  #define	CONFIG_SYS_MAX_NAND_DEVICE	1  #define	CONFIG_SYS_NAND_BASE		0x60000000  #define	CONFIG_SYS_NAND_5_ADDR_CYCLE -#define	NAND_MAX_CHIPS			8  /* Environment is in NAND */  #define	CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/mecp5123.h b/include/configs/mecp5123.h index ed9282b99..f5765b0d4 100644 --- a/include/configs/mecp5123.h +++ b/include/configs/mecp5123.h @@ -178,9 +178,7 @@  #define CONFIG_CMD_NAND  #define CONFIG_NAND_MPC5121_NFC  #define CONFIG_SYS_NAND_BASE            0x40000000 -  #define CONFIG_SYS_MAX_NAND_DEVICE      1 -#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE  /*   * Configuration parameters for MPC5121 NAND driver diff --git a/include/configs/mpc5121ads.h b/include/configs/mpc5121ads.h index c3d3afde0..01df8b127 100644 --- a/include/configs/mpc5121ads.h +++ b/include/configs/mpc5121ads.h @@ -242,7 +242,6 @@  #define CONFIG_SYS_NAND_BASE            0x40000000  #define CONFIG_SYS_MAX_NAND_DEVICE      2 -#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE  #define CONFIG_SYS_NAND_SELECT_DEVICE	/* driver supports mutipl. chips */  /* diff --git a/include/configs/mv-common.h b/include/configs/mv-common.h index 3f5fcc69a..1a6379176 100644 --- a/include/configs/mv-common.h +++ b/include/configs/mv-common.h @@ -132,7 +132,6 @@   */  #ifdef CONFIG_CMD_NAND  #define CONFIG_SYS_MAX_NAND_DEVICE     1 -#define NAND_MAX_CHIPS                 1  #define CONFIG_SYS_64BIT_VSPRINTF      /* needed for nand_util.c */  #endif diff --git a/include/configs/omap3_beagle.h b/include/configs/omap3_beagle.h index 91af8a025..4c7a686d3 100644 --- a/include/configs/omap3_beagle.h +++ b/include/configs/omap3_beagle.h @@ -418,10 +418,6 @@  						10, 11, 12, 13}  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/omap3_evm.h b/include/configs/omap3_evm.h index 2ce3959fd..1fcb7af9f 100644 --- a/include/configs/omap3_evm.h +++ b/include/configs/omap3_evm.h @@ -121,10 +121,6 @@  						10, 11, 12, 13}  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/omap3_evm_quick_nand.h b/include/configs/omap3_evm_quick_nand.h index 2f879c0bf..362fa1d72 100644 --- a/include/configs/omap3_evm_quick_nand.h +++ b/include/configs/omap3_evm_quick_nand.h @@ -91,10 +91,6 @@  						10, 11, 12, 13}  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL       (CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_U_BOOT_START   CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/pdm360ng.h b/include/configs/pdm360ng.h index f0154e091..8afc3c03d 100644 --- a/include/configs/pdm360ng.h +++ b/include/configs/pdm360ng.h @@ -225,9 +225,7 @@  #define CONFIG_CMD_NAND			/* enable NAND support */  #define CONFIG_NAND_MPC5121_NFC  #define CONFIG_SYS_NAND_BASE            0x40000000 -  #define CONFIG_SYS_MAX_NAND_DEVICE      1 -#define NAND_MAX_CHIPS                  CONFIG_SYS_MAX_NAND_DEVICE  #define CONFIG_SYS_NAND_SELECT_DEVICE	/* driver supports mutipl. chips */  /* diff --git a/include/configs/pm9261.h b/include/configs/pm9261.h index 1e803169e..eba5616dd 100644 --- a/include/configs/pm9261.h +++ b/include/configs/pm9261.h @@ -233,7 +233,6 @@  /* NAND flash */  #define CONFIG_NAND_ATMEL -#define NAND_MAX_CHIPS				1  #define CONFIG_SYS_MAX_NAND_DEVICE		1  #define CONFIG_SYS_NAND_BASE			0x40000000  #define CONFIG_SYS_NAND_DBW_8			1 diff --git a/include/configs/pm9263.h b/include/configs/pm9263.h index 32c596241..bf31c13bd 100644 --- a/include/configs/pm9263.h +++ b/include/configs/pm9263.h @@ -253,7 +253,6 @@  /* NAND flash */  #ifdef CONFIG_CMD_NAND  #define CONFIG_NAND_ATMEL -#define CONFIG_SYS_NAND_MAX_CHIPS	1  #define CONFIG_SYS_MAX_NAND_DEVICE	1  #define CONFIG_SYS_NAND_BASE		0x40000000  #define CONFIG_SYS_NAND_DBW_8		1 diff --git a/include/configs/pm9g45.h b/include/configs/pm9g45.h index eec915330..47798787d 100644 --- a/include/configs/pm9g45.h +++ b/include/configs/pm9g45.h @@ -115,7 +115,6 @@  /* NAND flash */  #ifdef CONFIG_CMD_NAND -#define CONFIG_NAND_MAX_CHIPS		1  #define CONFIG_NAND_ATMEL  #define CONFIG_SYS_MAX_NAND_DEVICE	1  #define CONFIG_SYS_NAND_BASE		0x40000000 diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h index f989595d0..ebd8223d6 100644 --- a/include/configs/qi_lb60.h +++ b/include/configs/qi_lb60.h @@ -99,10 +99,6 @@  #define CONFIG_SYS_NAND_ECC_POS		(6 * NANONOTE_NAND_SIZE)  #define CONFIG_SYS_NAND_ECCSIZE		512  #define CONFIG_SYS_NAND_ECCBYTES	9 -#define CONFIG_SYS_NAND_ECCSTEPS	\ -	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	\ -	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		\  		{12, 13, 14, 15, 16, 17, 18, 19,\  		20, 21, 22, 23, 24, 25, 26, 27, \ @@ -117,7 +113,6 @@  #define CONFIG_SYS_NAND_OOBSIZE		128  #define CONFIG_SYS_NAND_BASE		0xB8000000  #define CONFIG_SYS_ONENAND_BASE		CONFIG_SYS_NAND_BASE -#define NAND_MAX_CHIPS			1  #define CONFIG_SYS_MAX_NAND_DEVICE	1  #define CONFIG_SYS_NAND_SELECT_DEVICE	1 /* nand driver supports mutipl.*/  #define CONFIG_NAND_SPL_TEXT_BASE	0x80000000 diff --git a/include/configs/sequoia.h b/include/configs/sequoia.h index a406ca032..8e6954e3a 100644 --- a/include/configs/sequoia.h +++ b/include/configs/sequoia.h @@ -205,9 +205,7 @@  #define CONFIG_SYS_NAND_ECCSIZE	256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  #define CONFIG_SYS_NAND_OOBSIZE	16 -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  #define CONFIG_SYS_NAND_ECCPOS		{0, 1, 2, 3, 6, 7}  #ifdef CONFIG_ENV_IS_IN_NAND diff --git a/include/configs/smdk2410.h b/include/configs/smdk2410.h index 77c0a08d4..73159846e 100644 --- a/include/configs/smdk2410.h +++ b/include/configs/smdk2410.h @@ -211,7 +211,6 @@  #define CONFIG_NAND_S3C2410  #define CONFIG_SYS_S3C2410_NAND_HWECC  #define CONFIG_SYS_MAX_NAND_DEVICE	1 -#define NAND_MAX_CHIPS			1  #define CONFIG_SYS_NAND_BASE		0x4E000000  #endif diff --git a/include/configs/smdk6400.h b/include/configs/smdk6400.h index 4d0b7b2d4..a2b944105 100644 --- a/include/configs/smdk6400.h +++ b/include/configs/smdk6400.h @@ -262,12 +262,8 @@  #define CONFIG_SYS_NAND_ECCSIZE	CONFIG_SYS_NAND_PAGE_SIZE  /* Number of ECC bytes per OOB - S3C6400 calculates 4 bytes ECC in 1-bit mode */  #define CONFIG_SYS_NAND_ECCBYTES	4 -/* Number of ECC-blocks per NAND page */ -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / CONFIG_SYS_NAND_ECCSIZE)  /* Size of a single OOB region */  #define CONFIG_SYS_NAND_OOBSIZE	64 -/* Number of ECC bytes per page */ -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * CONFIG_SYS_NAND_ECCSTEPS)  /* ECC byte positions */  #define CONFIG_SYS_NAND_ECCPOS		{40, 41, 42, 43, 44, 45, 46, 47, \  				 48, 49, 50, 51, 52, 53, 54, 55, \ diff --git a/include/configs/tam3517-common.h b/include/configs/tam3517-common.h index 817d468a7..f4963ac07 100644 --- a/include/configs/tam3517-common.h +++ b/include/configs/tam3517-common.h @@ -278,11 +278,6 @@  #define CONFIG_SYS_NAND_ECCSIZE		256  #define CONFIG_SYS_NAND_ECCBYTES	3 -#define CONFIG_SYS_NAND_ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ -						CONFIG_SYS_NAND_ECCSIZE) -#define CONFIG_SYS_NAND_ECCTOTAL	(CONFIG_SYS_NAND_ECCBYTES * \ -						CONFIG_SYS_NAND_ECCSTEPS) -  #define CONFIG_SYS_NAND_U_BOOT_START	CONFIG_SYS_TEXT_BASE  #define CONFIG_SYS_NAND_U_BOOT_OFFS	0x80000 diff --git a/include/configs/tnetv107x_evm.h b/include/configs/tnetv107x_evm.h index 4bced0c99..7c3f33427 100644 --- a/include/configs/tnetv107x_evm.h +++ b/include/configs/tnetv107x_evm.h @@ -90,7 +90,6 @@  #define CONFIG_CMD_MTDPARTS  #define CONFIG_MTD_DEVICE  #define CONFIG_JFFS2_NAND -#define NAND_MAX_CHIPS			1  #define CONFIG_ENV_OFFSET		0x180000  /* diff --git a/include/configs/tt01.h b/include/configs/tt01.h index a55371269..7e293c676 100644 --- a/include/configs/tt01.h +++ b/include/configs/tt01.h @@ -231,7 +231,6 @@  #define CONFIG_NAND_MXC  #define CONFIG_SYS_MAX_NAND_DEVICE		1 -#define CONFIG_SYS_NAND_MAX_CHIPS		1  /*   * actually this is nothing someone wants to configure! diff --git a/include/linux/bch.h b/include/linux/bch.h new file mode 100644 index 000000000..295b4ef15 --- /dev/null +++ b/include/linux/bch.h @@ -0,0 +1,79 @@ +/* + * Generic binary BCH encoding/decoding library + * + * 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. + * + * 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. + * + * Copyright © 2011 Parrot S.A. + * + * Author: Ivan Djelic <ivan.djelic@parrot.com> + * + * Description: + * + * This library provides runtime configurable encoding/decoding of binary + * Bose-Chaudhuri-Hocquenghem (BCH) codes. +*/ +#ifndef _BCH_H +#define _BCH_H + +#include <linux/types.h> + +/** + * struct bch_control - BCH control structure + * @m:          Galois field order + * @n:          maximum codeword size in bits (= 2^m-1) + * @t:          error correction capability in bits + * @ecc_bits:   ecc exact size in bits, i.e. generator polynomial degree (<=m*t) + * @ecc_bytes:  ecc max size (m*t bits) in bytes + * @a_pow_tab:  Galois field GF(2^m) exponentiation lookup table + * @a_log_tab:  Galois field GF(2^m) log lookup table + * @mod8_tab:   remainder generator polynomial lookup tables + * @ecc_buf:    ecc parity words buffer + * @ecc_buf2:   ecc parity words buffer + * @xi_tab:     GF(2^m) base for solving degree 2 polynomial roots + * @syn:        syndrome buffer + * @cache:      log-based polynomial representation buffer + * @elp:        error locator polynomial + * @poly_2t:    temporary polynomials of degree 2t + */ +struct bch_control { +	unsigned int    m; +	unsigned int    n; +	unsigned int    t; +	unsigned int    ecc_bits; +	unsigned int    ecc_bytes; +/* private: */ +	uint16_t       *a_pow_tab; +	uint16_t       *a_log_tab; +	uint32_t       *mod8_tab; +	uint32_t       *ecc_buf; +	uint32_t       *ecc_buf2; +	unsigned int   *xi_tab; +	unsigned int   *syn; +	int            *cache; +	struct gf_poly *elp; +	struct gf_poly *poly_2t[4]; +}; + +struct bch_control *init_bch(int m, int t, unsigned int prim_poly); + +void free_bch(struct bch_control *bch); + +void encode_bch(struct bch_control *bch, const uint8_t *data, +		unsigned int len, uint8_t *ecc); + +int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, +	       const uint8_t *recv_ecc, const uint8_t *calc_ecc, +	       const unsigned int *syn, unsigned int *errloc); + +#endif /* _BCH_H */ diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 7db25465d..8cbcdae11 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,14 @@ 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 bad block table does not OOB for marker */ +#define NAND_BBT_NO_OOB		0x00400000  /* 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 1cdc7ae27..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 @@ -18,13 +18,6 @@  #ifndef __LINUX_MTD_NAND_H  #define __LINUX_MTD_NAND_H -/* XXX U-BOOT XXX */ -#if 0 -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/mtd/mtd.h> -#endif -  #include "config.h"  #include "linux/mtd/compat.h" @@ -43,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 @@ -86,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 @@ -132,6 +130,7 @@ typedef enum {  	NAND_ECC_HW,  	NAND_ECC_HW_SYNDROME,  	NAND_ECC_HW_OOB_FIRST, +	NAND_ECC_SOFT_BCH,  } nand_ecc_modes_t;  /* @@ -148,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 */ @@ -161,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 \ @@ -196,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 @@ -281,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 */ @@ -308,56 +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   * @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			(*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);  };  /** @@ -377,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 (*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); -	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); +	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 badblockbits; -	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 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;  };  /* @@ -539,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[]; @@ -552,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 @@ -573,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 @@ -596,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;  };  /** @@ -610,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 */ diff --git a/include/linux/mtd/nand_bch.h b/include/linux/mtd/nand_bch.h new file mode 100644 index 000000000..d8754dd8c --- /dev/null +++ b/include/linux/mtd/nand_bch.h @@ -0,0 +1,72 @@ +/* + * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com> + * + * 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. + * + * This file is the header for the NAND BCH ECC implementation. + */ + +#ifndef __MTD_NAND_BCH_H__ +#define __MTD_NAND_BCH_H__ + +struct mtd_info; +struct nand_bch_control; + +#if defined(CONFIG_NAND_ECC_BCH) + +static inline int mtd_nand_has_bch(void) { return 1; } + +/* + * Calculate BCH ecc code + */ +int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, +			   u_char *ecc_code); + +/* + * Detect and correct bit errors + */ +int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, +			  u_char *calc_ecc); +/* + * Initialize BCH encoder/decoder + */ +struct nand_bch_control * +nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, +	      unsigned int eccbytes, struct nand_ecclayout **ecclayout); +/* + * Release BCH encoder/decoder resources + */ +void nand_bch_free(struct nand_bch_control *nbc); + +#else /* !CONFIG_NAND_ECC_BCH */ + +static inline int mtd_nand_has_bch(void) { return 0; } + +static inline int +nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat, +		       u_char *ecc_code) +{ +	return -1; +} + +static inline int +nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, +		      unsigned char *read_ecc, unsigned char *calc_ecc) +{ +	return -1; +} + +static inline struct nand_bch_control * +nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, +	      unsigned int eccbytes, struct nand_ecclayout **ecclayout) +{ +	return NULL; +} + +static inline void nand_bch_free(struct nand_bch_control *nbc) {} + +#endif /* CONFIG_NAND_ECC_BCH */ + +#endif /* __MTD_NAND_BCH_H__ */ diff --git a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h index 090da5054..9715a53d8 100644 --- a/include/linux/mtd/nand_ecc.h +++ b/include/linux/mtd/nand_ecc.h @@ -15,6 +15,10 @@  struct mtd_info; +#if defined(CONFIG_MTD_ECC_SOFT) + +static inline int mtd_nand_has_ecc_soft(void) { return 1; } +  /*   * Calculate 3 byte ECC code for 256 byte block   */ @@ -25,4 +29,25 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code   */  int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); +#else + +static inline int mtd_nand_has_ecc_soft(void) { return 0; } + +static inline int +nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ +	return -1; +} + +static inline int +nand_correct_data(struct mtd_info *mtd, +			u_char *dat, +			u_char *read_ecc, +			u_char *calc_ecc) +{ +	return -1; +} + +#endif +  #endif /* __MTD_NAND_ECC_H__ */ diff --git a/include/linux/string.h b/include/linux/string.h index 62390399b..9a8cbc24c 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -47,6 +47,10 @@ extern char * strchr(const char *,int);  #ifndef __HAVE_ARCH_STRRCHR  extern char * strrchr(const char *,int);  #endif +extern char * skip_spaces(const char *); + +extern char *strim(char *); +  #ifndef __HAVE_ARCH_STRSTR  extern char * strstr(const char *,const char *);  #endif diff --git a/include/nand.h b/include/nand.h index d444ddcef..8b3a1a77a 100644 --- a/include/nand.h +++ b/include/nand.h @@ -24,13 +24,29 @@  #ifndef _NAND_H_  #define _NAND_H_ +#include <config.h> + +/* + * All boards using a given driver must convert to self-init + * at the same time, so do it here.  When all drivers are + * converted, this will go away. + */ +#if defined(CONFIG_NAND_FSL_ELBC) +#define CONFIG_SYS_NAND_SELF_INIT +#endif +  extern void nand_init(void);  #include <linux/mtd/compat.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> +#ifdef CONFIG_SYS_NAND_SELF_INIT +void board_nand_init(void); +int nand_register(int devnum); +#else  extern int board_nand_init(struct nand_chip *nand); +#endif  typedef struct mtd_info nand_info_t; diff --git a/lib/Makefile b/lib/Makefile index 35ba7ffe4..e6e6ec637 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,6 +27,7 @@ LIB	= $(obj)libgeneric.o  ifndef CONFIG_SPL_BUILD  COBJS-$(CONFIG_ADDR_MAP) += addr_map.o +COBJS-$(CONFIG_BCH) += bch.o  COBJS-$(CONFIG_BZIP2) += bzlib.o  COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o  COBJS-$(CONFIG_BZIP2) += bzlib_decompress.o diff --git a/lib/bch.c b/lib/bch.c new file mode 100644 index 000000000..7f4ca9270 --- /dev/null +++ b/lib/bch.c @@ -0,0 +1,1358 @@ +/* + * Generic binary BCH encoding/decoding library + * + * 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. + * + * 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. + * + * Copyright © 2011 Parrot S.A. + * + * Author: Ivan Djelic <ivan.djelic@parrot.com> + * + * Description: + * + * This library provides runtime configurable encoding/decoding of binary + * Bose-Chaudhuri-Hocquenghem (BCH) codes. + * + * Call init_bch to get a pointer to a newly allocated bch_control structure for + * the given m (Galois field order), t (error correction capability) and + * (optional) primitive polynomial parameters. + * + * Call encode_bch to compute and store ecc parity bytes to a given buffer. + * Call decode_bch to detect and locate errors in received data. + * + * On systems supporting hw BCH features, intermediate results may be provided + * to decode_bch in order to skip certain steps. See decode_bch() documentation + * for details. + * + * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of + * parameters m and t; thus allowing extra compiler optimizations and providing + * better (up to 2x) encoding performance. Using this option makes sense when + * (m,t) are fixed and known in advance, e.g. when using BCH error correction + * on a particular NAND flash device. + * + * Algorithmic details: + * + * Encoding is performed by processing 32 input bits in parallel, using 4 + * remainder lookup tables. + * + * The final stage of decoding involves the following internal steps: + * a. Syndrome computation + * b. Error locator polynomial computation using Berlekamp-Massey algorithm + * c. Error locator root finding (by far the most expensive step) + * + * In this implementation, step c is not performed using the usual Chien search. + * Instead, an alternative approach described in [1] is used. It consists in + * factoring the error locator polynomial using the Berlekamp Trace algorithm + * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial + * solving techniques [2] are used. The resulting algorithm, called BTZ, yields + * much better performance than Chien search for usual (m,t) values (typically + * m >= 13, t < 32, see [1]). + * + * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields + * of characteristic 2, in: Western European Workshop on Research in Cryptology + * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear. + * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over + * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996. + */ + +#include <common.h> +#include <ubi_uboot.h> + +#include <linux/bitops.h> +#include <asm/byteorder.h> +#include <linux/bch.h> + +#if defined(CONFIG_BCH_CONST_PARAMS) +#define GF_M(_p)               (CONFIG_BCH_CONST_M) +#define GF_T(_p)               (CONFIG_BCH_CONST_T) +#define GF_N(_p)               ((1 << (CONFIG_BCH_CONST_M))-1) +#else +#define GF_M(_p)               ((_p)->m) +#define GF_T(_p)               ((_p)->t) +#define GF_N(_p)               ((_p)->n) +#endif + +#define BCH_ECC_WORDS(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32) +#define BCH_ECC_BYTES(_p)      DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8) + +#ifndef dbg +#define dbg(_fmt, args...)     do {} while (0) +#endif + +/* + * represent a polynomial over GF(2^m) + */ +struct gf_poly { +	unsigned int deg;    /* polynomial degree */ +	unsigned int c[0];   /* polynomial terms */ +}; + +/* given its degree, compute a polynomial size in bytes */ +#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int)) + +/* polynomial of degree 1 */ +struct gf_poly_deg1 { +	struct gf_poly poly; +	unsigned int   c[2]; +}; + +/* + * same as encode_bch(), but process input data one byte at a time + */ +static void encode_bch_unaligned(struct bch_control *bch, +				 const unsigned char *data, unsigned int len, +				 uint32_t *ecc) +{ +	int i; +	const uint32_t *p; +	const int l = BCH_ECC_WORDS(bch)-1; + +	while (len--) { +		p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff); + +		for (i = 0; i < l; i++) +			ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++); + +		ecc[l] = (ecc[l] << 8)^(*p); +	} +} + +/* + * convert ecc bytes to aligned, zero-padded 32-bit ecc words + */ +static void load_ecc8(struct bch_control *bch, uint32_t *dst, +		      const uint8_t *src) +{ +	uint8_t pad[4] = {0, 0, 0, 0}; +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; + +	for (i = 0; i < nwords; i++, src += 4) +		dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3]; + +	memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords); +	dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3]; +} + +/* + * convert 32-bit ecc words to ecc bytes + */ +static void store_ecc8(struct bch_control *bch, uint8_t *dst, +		       const uint32_t *src) +{ +	uint8_t pad[4]; +	unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; + +	for (i = 0; i < nwords; i++) { +		*dst++ = (src[i] >> 24); +		*dst++ = (src[i] >> 16) & 0xff; +		*dst++ = (src[i] >>  8) & 0xff; +		*dst++ = (src[i] >>  0) & 0xff; +	} +	pad[0] = (src[nwords] >> 24); +	pad[1] = (src[nwords] >> 16) & 0xff; +	pad[2] = (src[nwords] >>  8) & 0xff; +	pad[3] = (src[nwords] >>  0) & 0xff; +	memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords); +} + +/** + * encode_bch - calculate BCH ecc parity of data + * @bch:   BCH control structure + * @data:  data to encode + * @len:   data length in bytes + * @ecc:   ecc parity data, must be initialized by caller + * + * The @ecc parity array is used both as input and output parameter, in order to + * allow incremental computations. It should be of the size indicated by member + * @ecc_bytes of @bch, and should be initialized to 0 before the first call. + * + * The exact number of computed ecc parity bits is given by member @ecc_bits of + * @bch; it may be less than m*t for large values of t. + */ +void encode_bch(struct bch_control *bch, const uint8_t *data, +		unsigned int len, uint8_t *ecc) +{ +	const unsigned int l = BCH_ECC_WORDS(bch)-1; +	unsigned int i, mlen; +	unsigned long m; +	uint32_t w, r[l+1]; +	const uint32_t * const tab0 = bch->mod8_tab; +	const uint32_t * const tab1 = tab0 + 256*(l+1); +	const uint32_t * const tab2 = tab1 + 256*(l+1); +	const uint32_t * const tab3 = tab2 + 256*(l+1); +	const uint32_t *pdata, *p0, *p1, *p2, *p3; + +	if (ecc) { +		/* load ecc parity bytes into internal 32-bit buffer */ +		load_ecc8(bch, bch->ecc_buf, ecc); +	} else { +		memset(bch->ecc_buf, 0, sizeof(r)); +	} + +	/* process first unaligned data bytes */ +	m = ((unsigned long)data) & 3; +	if (m) { +		mlen = (len < (4-m)) ? len : 4-m; +		encode_bch_unaligned(bch, data, mlen, bch->ecc_buf); +		data += mlen; +		len  -= mlen; +	} + +	/* process 32-bit aligned data words */ +	pdata = (uint32_t *)data; +	mlen  = len/4; +	data += 4*mlen; +	len  -= 4*mlen; +	memcpy(r, bch->ecc_buf, sizeof(r)); + +	/* +	 * split each 32-bit word into 4 polynomials of weight 8 as follows: +	 * +	 * 31 ...24  23 ...16  15 ... 8  7 ... 0 +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt +	 *                               tttttttt  mod g = r0 (precomputed) +	 *                     zzzzzzzz  00000000  mod g = r1 (precomputed) +	 *           yyyyyyyy  00000000  00000000  mod g = r2 (precomputed) +	 * xxxxxxxx  00000000  00000000  00000000  mod g = r3 (precomputed) +	 * xxxxxxxx  yyyyyyyy  zzzzzzzz  tttttttt  mod g = r0^r1^r2^r3 +	 */ +	while (mlen--) { +		/* input data is read in big-endian format */ +		w = r[0]^cpu_to_be32(*pdata++); +		p0 = tab0 + (l+1)*((w >>  0) & 0xff); +		p1 = tab1 + (l+1)*((w >>  8) & 0xff); +		p2 = tab2 + (l+1)*((w >> 16) & 0xff); +		p3 = tab3 + (l+1)*((w >> 24) & 0xff); + +		for (i = 0; i < l; i++) +			r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i]; + +		r[l] = p0[l]^p1[l]^p2[l]^p3[l]; +	} +	memcpy(bch->ecc_buf, r, sizeof(r)); + +	/* process last unaligned bytes */ +	if (len) +		encode_bch_unaligned(bch, data, len, bch->ecc_buf); + +	/* store ecc parity bytes into original parity buffer */ +	if (ecc) +		store_ecc8(bch, ecc, bch->ecc_buf); +} + +static inline int modulo(struct bch_control *bch, unsigned int v) +{ +	const unsigned int n = GF_N(bch); +	while (v >= n) { +		v -= n; +		v = (v & n) + (v >> GF_M(bch)); +	} +	return v; +} + +/* + * shorter and faster modulo function, only works when v < 2N. + */ +static inline int mod_s(struct bch_control *bch, unsigned int v) +{ +	const unsigned int n = GF_N(bch); +	return (v < n) ? v : v-n; +} + +static inline int deg(unsigned int poly) +{ +	/* polynomial degree is the most-significant bit index */ +	return fls(poly)-1; +} + +static inline int parity(unsigned int x) +{ +	/* +	 * public domain code snippet, lifted from +	 * http://www-graphics.stanford.edu/~seander/bithacks.html +	 */ +	x ^= x >> 1; +	x ^= x >> 2; +	x = (x & 0x11111111U) * 0x11111111U; +	return (x >> 28) & 1; +} + +/* Galois field basic operations: multiply, divide, inverse, etc. */ + +static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a, +				  unsigned int b) +{ +	return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ +					       bch->a_log_tab[b])] : 0; +} + +static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a) +{ +	return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0; +} + +static inline unsigned int gf_div(struct bch_control *bch, unsigned int a, +				  unsigned int b) +{ +	return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ +					GF_N(bch)-bch->a_log_tab[b])] : 0; +} + +static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a) +{ +	return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]]; +} + +static inline unsigned int a_pow(struct bch_control *bch, int i) +{ +	return bch->a_pow_tab[modulo(bch, i)]; +} + +static inline int a_log(struct bch_control *bch, unsigned int x) +{ +	return bch->a_log_tab[x]; +} + +static inline int a_ilog(struct bch_control *bch, unsigned int x) +{ +	return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]); +} + +/* + * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t + */ +static void compute_syndromes(struct bch_control *bch, uint32_t *ecc, +			      unsigned int *syn) +{ +	int i, j, s; +	unsigned int m; +	uint32_t poly; +	const int t = GF_T(bch); + +	s = bch->ecc_bits; + +	/* make sure extra bits in last ecc word are cleared */ +	m = ((unsigned int)s) & 31; +	if (m) +		ecc[s/32] &= ~((1u << (32-m))-1); +	memset(syn, 0, 2*t*sizeof(*syn)); + +	/* compute v(a^j) for j=1 .. 2t-1 */ +	do { +		poly = *ecc++; +		s -= 32; +		while (poly) { +			i = deg(poly); +			for (j = 0; j < 2*t; j += 2) +				syn[j] ^= a_pow(bch, (j+1)*(i+s)); + +			poly ^= (1 << i); +		} +	} while (s > 0); + +	/* v(a^(2j)) = v(a^j)^2 */ +	for (j = 0; j < t; j++) +		syn[2*j+1] = gf_sqr(bch, syn[j]); +} + +static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src) +{ +	memcpy(dst, src, GF_POLY_SZ(src->deg)); +} + +static int compute_error_locator_polynomial(struct bch_control *bch, +					    const unsigned int *syn) +{ +	const unsigned int t = GF_T(bch); +	const unsigned int n = GF_N(bch); +	unsigned int i, j, tmp, l, pd = 1, d = syn[0]; +	struct gf_poly *elp = bch->elp; +	struct gf_poly *pelp = bch->poly_2t[0]; +	struct gf_poly *elp_copy = bch->poly_2t[1]; +	int k, pp = -1; + +	memset(pelp, 0, GF_POLY_SZ(2*t)); +	memset(elp, 0, GF_POLY_SZ(2*t)); + +	pelp->deg = 0; +	pelp->c[0] = 1; +	elp->deg = 0; +	elp->c[0] = 1; + +	/* use simplified binary Berlekamp-Massey algorithm */ +	for (i = 0; (i < t) && (elp->deg <= t); i++) { +		if (d) { +			k = 2*i-pp; +			gf_poly_copy(elp_copy, elp); +			/* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */ +			tmp = a_log(bch, d)+n-a_log(bch, pd); +			for (j = 0; j <= pelp->deg; j++) { +				if (pelp->c[j]) { +					l = a_log(bch, pelp->c[j]); +					elp->c[j+k] ^= a_pow(bch, tmp+l); +				} +			} +			/* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */ +			tmp = pelp->deg+k; +			if (tmp > elp->deg) { +				elp->deg = tmp; +				gf_poly_copy(pelp, elp_copy); +				pd = d; +				pp = 2*i; +			} +		} +		/* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */ +		if (i < t-1) { +			d = syn[2*i+2]; +			for (j = 1; j <= elp->deg; j++) +				d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]); +		} +	} +	dbg("elp=%s\n", gf_poly_str(elp)); +	return (elp->deg > t) ? -1 : (int)elp->deg; +} + +/* + * solve a m x m linear system in GF(2) with an expected number of solutions, + * and return the number of found solutions + */ +static int solve_linear_system(struct bch_control *bch, unsigned int *rows, +			       unsigned int *sol, int nsol) +{ +	const int m = GF_M(bch); +	unsigned int tmp, mask; +	int rem, c, r, p, k, param[m]; + +	k = 0; +	mask = 1 << m; + +	/* Gaussian elimination */ +	for (c = 0; c < m; c++) { +		rem = 0; +		p = c-k; +		/* find suitable row for elimination */ +		for (r = p; r < m; r++) { +			if (rows[r] & mask) { +				if (r != p) { +					tmp = rows[r]; +					rows[r] = rows[p]; +					rows[p] = tmp; +				} +				rem = r+1; +				break; +			} +		} +		if (rem) { +			/* perform elimination on remaining rows */ +			tmp = rows[p]; +			for (r = rem; r < m; r++) { +				if (rows[r] & mask) +					rows[r] ^= tmp; +			} +		} else { +			/* elimination not needed, store defective row index */ +			param[k++] = c; +		} +		mask >>= 1; +	} +	/* rewrite system, inserting fake parameter rows */ +	if (k > 0) { +		p = k; +		for (r = m-1; r >= 0; r--) { +			if ((r > m-1-k) && rows[r]) +				/* system has no solution */ +				return 0; + +			rows[r] = (p && (r == param[p-1])) ? +				p--, 1u << (m-r) : rows[r-p]; +		} +	} + +	if (nsol != (1 << k)) +		/* unexpected number of solutions */ +		return 0; + +	for (p = 0; p < nsol; p++) { +		/* set parameters for p-th solution */ +		for (c = 0; c < k; c++) +			rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1); + +		/* compute unique solution */ +		tmp = 0; +		for (r = m-1; r >= 0; r--) { +			mask = rows[r] & (tmp|1); +			tmp |= parity(mask) << (m-r); +		} +		sol[p] = tmp >> 1; +	} +	return nsol; +} + +/* + * this function builds and solves a linear system for finding roots of a degree + * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m). + */ +static int find_affine4_roots(struct bch_control *bch, unsigned int a, +			      unsigned int b, unsigned int c, +			      unsigned int *roots) +{ +	int i, j, k; +	const int m = GF_M(bch); +	unsigned int mask = 0xff, t, rows[16] = {0,}; + +	j = a_log(bch, b); +	k = a_log(bch, a); +	rows[0] = c; + +	/* buid linear system to solve X^4+aX^2+bX+c = 0 */ +	for (i = 0; i < m; i++) { +		rows[i+1] = bch->a_pow_tab[4*i]^ +			(a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^ +			(b ? bch->a_pow_tab[mod_s(bch, j)] : 0); +		j++; +		k += 2; +	} +	/* +	 * transpose 16x16 matrix before passing it to linear solver +	 * warning: this code assumes m < 16 +	 */ +	for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) { +		for (k = 0; k < 16; k = (k+j+1) & ~j) { +			t = ((rows[k] >> j)^rows[k+j]) & mask; +			rows[k] ^= (t << j); +			rows[k+j] ^= t; +		} +	} +	return solve_linear_system(bch, rows, roots, 4); +} + +/* + * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r)) + */ +static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly, +				unsigned int *roots) +{ +	int n = 0; + +	if (poly->c[0]) +		/* poly[X] = bX+c with c!=0, root=c/b */ +		roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+ +				   bch->a_log_tab[poly->c[1]]); +	return n; +} + +/* + * compute roots of a degree 2 polynomial over GF(2^m) + */ +static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly, +				unsigned int *roots) +{ +	int n = 0, i, l0, l1, l2; +	unsigned int u, v, r; + +	if (poly->c[0] && poly->c[1]) { + +		l0 = bch->a_log_tab[poly->c[0]]; +		l1 = bch->a_log_tab[poly->c[1]]; +		l2 = bch->a_log_tab[poly->c[2]]; + +		/* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */ +		u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1)); +		/* +		 * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi): +		 * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) = +		 * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u) +		 * i.e. r and r+1 are roots iff Tr(u)=0 +		 */ +		r = 0; +		v = u; +		while (v) { +			i = deg(v); +			r ^= bch->xi_tab[i]; +			v ^= (1 << i); +		} +		/* verify root */ +		if ((gf_sqr(bch, r)^r) == u) { +			/* reverse z=a/bX transformation and compute log(1/r) */ +			roots[n++] = modulo(bch, 2*GF_N(bch)-l1- +					    bch->a_log_tab[r]+l2); +			roots[n++] = modulo(bch, 2*GF_N(bch)-l1- +					    bch->a_log_tab[r^1]+l2); +		} +	} +	return n; +} + +/* + * compute roots of a degree 3 polynomial over GF(2^m) + */ +static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly, +				unsigned int *roots) +{ +	int i, n = 0; +	unsigned int a, b, c, a2, b2, c2, e3, tmp[4]; + +	if (poly->c[0]) { +		/* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */ +		e3 = poly->c[3]; +		c2 = gf_div(bch, poly->c[0], e3); +		b2 = gf_div(bch, poly->c[1], e3); +		a2 = gf_div(bch, poly->c[2], e3); + +		/* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */ +		c = gf_mul(bch, a2, c2);           /* c = a2c2      */ +		b = gf_mul(bch, a2, b2)^c2;        /* b = a2b2 + c2 */ +		a = gf_sqr(bch, a2)^b2;            /* a = a2^2 + b2 */ + +		/* find the 4 roots of this affine polynomial */ +		if (find_affine4_roots(bch, a, b, c, tmp) == 4) { +			/* remove a2 from final list of roots */ +			for (i = 0; i < 4; i++) { +				if (tmp[i] != a2) +					roots[n++] = a_ilog(bch, tmp[i]); +			} +		} +	} +	return n; +} + +/* + * compute roots of a degree 4 polynomial over GF(2^m) + */ +static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly, +				unsigned int *roots) +{ +	int i, l, n = 0; +	unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4; + +	if (poly->c[0] == 0) +		return 0; + +	/* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */ +	e4 = poly->c[4]; +	d = gf_div(bch, poly->c[0], e4); +	c = gf_div(bch, poly->c[1], e4); +	b = gf_div(bch, poly->c[2], e4); +	a = gf_div(bch, poly->c[3], e4); + +	/* use Y=1/X transformation to get an affine polynomial */ +	if (a) { +		/* first, eliminate cX by using z=X+e with ae^2+c=0 */ +		if (c) { +			/* compute e such that e^2 = c/a */ +			f = gf_div(bch, c, a); +			l = a_log(bch, f); +			l += (l & 1) ? GF_N(bch) : 0; +			e = a_pow(bch, l/2); +			/* +			 * use transformation z=X+e: +			 * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d +			 * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d +			 * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d +			 * z^4 + az^3 +     b'z^2 + d' +			 */ +			d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d; +			b = gf_mul(bch, a, e)^b; +		} +		/* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */ +		if (d == 0) +			/* assume all roots have multiplicity 1 */ +			return 0; + +		c2 = gf_inv(bch, d); +		b2 = gf_div(bch, a, d); +		a2 = gf_div(bch, b, d); +	} else { +		/* polynomial is already affine */ +		c2 = d; +		b2 = c; +		a2 = b; +	} +	/* find the 4 roots of this affine polynomial */ +	if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) { +		for (i = 0; i < 4; i++) { +			/* post-process roots (reverse transformations) */ +			f = a ? gf_inv(bch, roots[i]) : roots[i]; +			roots[i] = a_ilog(bch, f^e); +		} +		n = 4; +	} +	return n; +} + +/* + * build monic, log-based representation of a polynomial + */ +static void gf_poly_logrep(struct bch_control *bch, +			   const struct gf_poly *a, int *rep) +{ +	int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]); + +	/* represent 0 values with -1; warning, rep[d] is not set to 1 */ +	for (i = 0; i < d; i++) +		rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1; +} + +/* + * compute polynomial Euclidean division remainder in GF(2^m)[X] + */ +static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a, +			const struct gf_poly *b, int *rep) +{ +	int la, p, m; +	unsigned int i, j, *c = a->c; +	const unsigned int d = b->deg; + +	if (a->deg < d) +		return; + +	/* reuse or compute log representation of denominator */ +	if (!rep) { +		rep = bch->cache; +		gf_poly_logrep(bch, b, rep); +	} + +	for (j = a->deg; j >= d; j--) { +		if (c[j]) { +			la = a_log(bch, c[j]); +			p = j-d; +			for (i = 0; i < d; i++, p++) { +				m = rep[i]; +				if (m >= 0) +					c[p] ^= bch->a_pow_tab[mod_s(bch, +								     m+la)]; +			} +		} +	} +	a->deg = d-1; +	while (!c[a->deg] && a->deg) +		a->deg--; +} + +/* + * compute polynomial Euclidean division quotient in GF(2^m)[X] + */ +static void gf_poly_div(struct bch_control *bch, struct gf_poly *a, +			const struct gf_poly *b, struct gf_poly *q) +{ +	if (a->deg >= b->deg) { +		q->deg = a->deg-b->deg; +		/* compute a mod b (modifies a) */ +		gf_poly_mod(bch, a, b, NULL); +		/* quotient is stored in upper part of polynomial a */ +		memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int)); +	} else { +		q->deg = 0; +		q->c[0] = 0; +	} +} + +/* + * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X] + */ +static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a, +				   struct gf_poly *b) +{ +	struct gf_poly *tmp; + +	dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b)); + +	if (a->deg < b->deg) { +		tmp = b; +		b = a; +		a = tmp; +	} + +	while (b->deg > 0) { +		gf_poly_mod(bch, a, b, NULL); +		tmp = b; +		b = a; +		a = tmp; +	} + +	dbg("%s\n", gf_poly_str(a)); + +	return a; +} + +/* + * Given a polynomial f and an integer k, compute Tr(a^kX) mod f + * This is used in Berlekamp Trace algorithm for splitting polynomials + */ +static void compute_trace_bk_mod(struct bch_control *bch, int k, +				 const struct gf_poly *f, struct gf_poly *z, +				 struct gf_poly *out) +{ +	const int m = GF_M(bch); +	int i, j; + +	/* z contains z^2j mod f */ +	z->deg = 1; +	z->c[0] = 0; +	z->c[1] = bch->a_pow_tab[k]; + +	out->deg = 0; +	memset(out, 0, GF_POLY_SZ(f->deg)); + +	/* compute f log representation only once */ +	gf_poly_logrep(bch, f, bch->cache); + +	for (i = 0; i < m; i++) { +		/* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */ +		for (j = z->deg; j >= 0; j--) { +			out->c[j] ^= z->c[j]; +			z->c[2*j] = gf_sqr(bch, z->c[j]); +			z->c[2*j+1] = 0; +		} +		if (z->deg > out->deg) +			out->deg = z->deg; + +		if (i < m-1) { +			z->deg *= 2; +			/* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */ +			gf_poly_mod(bch, z, f, bch->cache); +		} +	} +	while (!out->c[out->deg] && out->deg) +		out->deg--; + +	dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out)); +} + +/* + * factor a polynomial using Berlekamp Trace algorithm (BTA) + */ +static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f, +			      struct gf_poly **g, struct gf_poly **h) +{ +	struct gf_poly *f2 = bch->poly_2t[0]; +	struct gf_poly *q  = bch->poly_2t[1]; +	struct gf_poly *tk = bch->poly_2t[2]; +	struct gf_poly *z  = bch->poly_2t[3]; +	struct gf_poly *gcd; + +	dbg("factoring %s...\n", gf_poly_str(f)); + +	*g = f; +	*h = NULL; + +	/* tk = Tr(a^k.X) mod f */ +	compute_trace_bk_mod(bch, k, f, z, tk); + +	if (tk->deg > 0) { +		/* compute g = gcd(f, tk) (destructive operation) */ +		gf_poly_copy(f2, f); +		gcd = gf_poly_gcd(bch, f2, tk); +		if (gcd->deg < f->deg) { +			/* compute h=f/gcd(f,tk); this will modify f and q */ +			gf_poly_div(bch, f, gcd, q); +			/* store g and h in-place (clobbering f) */ +			*h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly; +			gf_poly_copy(*g, gcd); +			gf_poly_copy(*h, q); +		} +	} +} + +/* + * find roots of a polynomial, using BTZ algorithm; see the beginning of this + * file for details + */ +static int find_poly_roots(struct bch_control *bch, unsigned int k, +			   struct gf_poly *poly, unsigned int *roots) +{ +	int cnt; +	struct gf_poly *f1, *f2; + +	switch (poly->deg) { +		/* handle low degree polynomials with ad hoc techniques */ +	case 1: +		cnt = find_poly_deg1_roots(bch, poly, roots); +		break; +	case 2: +		cnt = find_poly_deg2_roots(bch, poly, roots); +		break; +	case 3: +		cnt = find_poly_deg3_roots(bch, poly, roots); +		break; +	case 4: +		cnt = find_poly_deg4_roots(bch, poly, roots); +		break; +	default: +		/* factor polynomial using Berlekamp Trace Algorithm (BTA) */ +		cnt = 0; +		if (poly->deg && (k <= GF_M(bch))) { +			factor_polynomial(bch, k, poly, &f1, &f2); +			if (f1) +				cnt += find_poly_roots(bch, k+1, f1, roots); +			if (f2) +				cnt += find_poly_roots(bch, k+1, f2, roots+cnt); +		} +		break; +	} +	return cnt; +} + +#if defined(USE_CHIEN_SEARCH) +/* + * exhaustive root search (Chien) implementation - not used, included only for + * reference/comparison tests + */ +static int chien_search(struct bch_control *bch, unsigned int len, +			struct gf_poly *p, unsigned int *roots) +{ +	int m; +	unsigned int i, j, syn, syn0, count = 0; +	const unsigned int k = 8*len+bch->ecc_bits; + +	/* use a log-based representation of polynomial */ +	gf_poly_logrep(bch, p, bch->cache); +	bch->cache[p->deg] = 0; +	syn0 = gf_div(bch, p->c[0], p->c[p->deg]); + +	for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) { +		/* compute elp(a^i) */ +		for (j = 1, syn = syn0; j <= p->deg; j++) { +			m = bch->cache[j]; +			if (m >= 0) +				syn ^= a_pow(bch, m+j*i); +		} +		if (syn == 0) { +			roots[count++] = GF_N(bch)-i; +			if (count == p->deg) +				break; +		} +	} +	return (count == p->deg) ? count : 0; +} +#define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc) +#endif /* USE_CHIEN_SEARCH */ + +/** + * decode_bch - decode received codeword and find bit error locations + * @bch:      BCH control structure + * @data:     received data, ignored if @calc_ecc is provided + * @len:      data length in bytes, must always be provided + * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc + * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data + * @syn:      hw computed syndrome data (if NULL, syndrome is calculated) + * @errloc:   output array of error locations + * + * Returns: + *  The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if + *  invalid parameters were provided + * + * Depending on the available hw BCH support and the need to compute @calc_ecc + * separately (using encode_bch()), this function should be called with one of + * the following parameter configurations - + * + * by providing @data and @recv_ecc only: + *   decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc) + * + * by providing @recv_ecc and @calc_ecc: + *   decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc) + * + * by providing ecc = recv_ecc XOR calc_ecc: + *   decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc) + * + * by providing syndrome results @syn: + *   decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc) + * + * Once decode_bch() has successfully returned with a positive value, error + * locations returned in array @errloc should be interpreted as follows - + * + * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for + * data correction) + * + * if (errloc[n] < 8*len), then n-th error is located in data and can be + * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8); + * + * Note that this function does not perform any data correction by itself, it + * merely indicates error locations. + */ +int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, +	       const uint8_t *recv_ecc, const uint8_t *calc_ecc, +	       const unsigned int *syn, unsigned int *errloc) +{ +	const unsigned int ecc_words = BCH_ECC_WORDS(bch); +	unsigned int nbits; +	int i, err, nroots; +	uint32_t sum; + +	/* sanity check: make sure data length can be handled */ +	if (8*len > (bch->n-bch->ecc_bits)) +		return -EINVAL; + +	/* if caller does not provide syndromes, compute them */ +	if (!syn) { +		if (!calc_ecc) { +			/* compute received data ecc into an internal buffer */ +			if (!data || !recv_ecc) +				return -EINVAL; +			encode_bch(bch, data, len, NULL); +		} else { +			/* load provided calculated ecc */ +			load_ecc8(bch, bch->ecc_buf, calc_ecc); +		} +		/* load received ecc or assume it was XORed in calc_ecc */ +		if (recv_ecc) { +			load_ecc8(bch, bch->ecc_buf2, recv_ecc); +			/* XOR received and calculated ecc */ +			for (i = 0, sum = 0; i < (int)ecc_words; i++) { +				bch->ecc_buf[i] ^= bch->ecc_buf2[i]; +				sum |= bch->ecc_buf[i]; +			} +			if (!sum) +				/* no error found */ +				return 0; +		} +		compute_syndromes(bch, bch->ecc_buf, bch->syn); +		syn = bch->syn; +	} + +	err = compute_error_locator_polynomial(bch, syn); +	if (err > 0) { +		nroots = find_poly_roots(bch, 1, bch->elp, errloc); +		if (err != nroots) +			err = -1; +	} +	if (err > 0) { +		/* post-process raw error locations for easier correction */ +		nbits = (len*8)+bch->ecc_bits; +		for (i = 0; i < err; i++) { +			if (errloc[i] >= nbits) { +				err = -1; +				break; +			} +			errloc[i] = nbits-1-errloc[i]; +			errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7)); +		} +	} +	return (err >= 0) ? err : -EBADMSG; +} + +/* + * generate Galois field lookup tables + */ +static int build_gf_tables(struct bch_control *bch, unsigned int poly) +{ +	unsigned int i, x = 1; +	const unsigned int k = 1 << deg(poly); + +	/* primitive polynomial must be of degree m */ +	if (k != (1u << GF_M(bch))) +		return -1; + +	for (i = 0; i < GF_N(bch); i++) { +		bch->a_pow_tab[i] = x; +		bch->a_log_tab[x] = i; +		if (i && (x == 1)) +			/* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ +			return -1; +		x <<= 1; +		if (x & k) +			x ^= poly; +	} +	bch->a_pow_tab[GF_N(bch)] = 1; +	bch->a_log_tab[0] = 0; + +	return 0; +} + +/* + * compute generator polynomial remainder tables for fast encoding + */ +static void build_mod8_tables(struct bch_control *bch, const uint32_t *g) +{ +	int i, j, b, d; +	uint32_t data, hi, lo, *tab; +	const int l = BCH_ECC_WORDS(bch); +	const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32); +	const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32); + +	memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab)); + +	for (i = 0; i < 256; i++) { +		/* p(X)=i is a small polynomial of weight <= 8 */ +		for (b = 0; b < 4; b++) { +			/* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */ +			tab = bch->mod8_tab + (b*256+i)*l; +			data = i << (8*b); +			while (data) { +				d = deg(data); +				/* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */ +				data ^= g[0] >> (31-d); +				for (j = 0; j < ecclen; j++) { +					hi = (d < 31) ? g[j] << (d+1) : 0; +					lo = (j+1 < plen) ? +						g[j+1] >> (31-d) : 0; +					tab[j] ^= hi|lo; +				} +			} +		} +	} +} + +/* + * build a base for factoring degree 2 polynomials + */ +static int build_deg2_base(struct bch_control *bch) +{ +	const int m = GF_M(bch); +	int i, j, r; +	unsigned int sum, x, y, remaining, ak = 0, xi[m]; + +	/* find k s.t. Tr(a^k) = 1 and 0 <= k < m */ +	for (i = 0; i < m; i++) { +		for (j = 0, sum = 0; j < m; j++) +			sum ^= a_pow(bch, i*(1 << j)); + +		if (sum) { +			ak = bch->a_pow_tab[i]; +			break; +		} +	} +	/* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */ +	remaining = m; +	memset(xi, 0, sizeof(xi)); + +	for (x = 0; (x <= GF_N(bch)) && remaining; x++) { +		y = gf_sqr(bch, x)^x; +		for (i = 0; i < 2; i++) { +			r = a_log(bch, y); +			if (y && (r < m) && !xi[r]) { +				bch->xi_tab[r] = x; +				xi[r] = 1; +				remaining--; +				dbg("x%d = %x\n", r, x); +				break; +			} +			y ^= ak; +		} +	} +	/* should not happen but check anyway */ +	return remaining ? -1 : 0; +} + +static void *bch_alloc(size_t size, int *err) +{ +	void *ptr; + +	ptr = kmalloc(size, GFP_KERNEL); +	if (ptr == NULL) +		*err = 1; +	return ptr; +} + +/* + * compute generator polynomial for given (m,t) parameters. + */ +static uint32_t *compute_generator_polynomial(struct bch_control *bch) +{ +	const unsigned int m = GF_M(bch); +	const unsigned int t = GF_T(bch); +	int n, err = 0; +	unsigned int i, j, nbits, r, word, *roots; +	struct gf_poly *g; +	uint32_t *genpoly; + +	g = bch_alloc(GF_POLY_SZ(m*t), &err); +	roots = bch_alloc((bch->n+1)*sizeof(*roots), &err); +	genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err); + +	if (err) { +		kfree(genpoly); +		genpoly = NULL; +		goto finish; +	} + +	/* enumerate all roots of g(X) */ +	memset(roots , 0, (bch->n+1)*sizeof(*roots)); +	for (i = 0; i < t; i++) { +		for (j = 0, r = 2*i+1; j < m; j++) { +			roots[r] = 1; +			r = mod_s(bch, 2*r); +		} +	} +	/* build generator polynomial g(X) */ +	g->deg = 0; +	g->c[0] = 1; +	for (i = 0; i < GF_N(bch); i++) { +		if (roots[i]) { +			/* multiply g(X) by (X+root) */ +			r = bch->a_pow_tab[i]; +			g->c[g->deg+1] = 1; +			for (j = g->deg; j > 0; j--) +				g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1]; + +			g->c[0] = gf_mul(bch, g->c[0], r); +			g->deg++; +		} +	} +	/* store left-justified binary representation of g(X) */ +	n = g->deg+1; +	i = 0; + +	while (n > 0) { +		nbits = (n > 32) ? 32 : n; +		for (j = 0, word = 0; j < nbits; j++) { +			if (g->c[n-1-j]) +				word |= 1u << (31-j); +		} +		genpoly[i++] = word; +		n -= nbits; +	} +	bch->ecc_bits = g->deg; + +finish: +	kfree(g); +	kfree(roots); + +	return genpoly; +} + +/** + * init_bch - initialize a BCH encoder/decoder + * @m:          Galois field order, should be in the range 5-15 + * @t:          maximum error correction capability, in bits + * @prim_poly:  user-provided primitive polynomial (or 0 to use default) + * + * Returns: + *  a newly allocated BCH control structure if successful, NULL otherwise + * + * This initialization can take some time, as lookup tables are built for fast + * encoding/decoding; make sure not to call this function from a time critical + * path. Usually, init_bch() should be called on module/driver init and + * free_bch() should be called to release memory on exit. + * + * You may provide your own primitive polynomial of degree @m in argument + * @prim_poly, or let init_bch() use its default polynomial. + * + * Once init_bch() has successfully returned a pointer to a newly allocated + * BCH control structure, ecc length in bytes is given by member @ecc_bytes of + * the structure. + */ +struct bch_control *init_bch(int m, int t, unsigned int prim_poly) +{ +	int err = 0; +	unsigned int i, words; +	uint32_t *genpoly; +	struct bch_control *bch = NULL; + +	const int min_m = 5; +	const int max_m = 15; + +	/* default primitive polynomials */ +	static const unsigned int prim_poly_tab[] = { +		0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b, +		0x402b, 0x8003, +	}; + +#if defined(CONFIG_BCH_CONST_PARAMS) +	if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) { +		printk(KERN_ERR "bch encoder/decoder was configured to support " +		       "parameters m=%d, t=%d only!\n", +		       CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T); +		goto fail; +	} +#endif +	if ((m < min_m) || (m > max_m)) +		/* +		 * values of m greater than 15 are not currently supported; +		 * supporting m > 15 would require changing table base type +		 * (uint16_t) and a small patch in matrix transposition +		 */ +		goto fail; + +	/* sanity checks */ +	if ((t < 1) || (m*t >= ((1 << m)-1))) +		/* invalid t value */ +		goto fail; + +	/* select a primitive polynomial for generating GF(2^m) */ +	if (prim_poly == 0) +		prim_poly = prim_poly_tab[m-min_m]; + +	bch = kzalloc(sizeof(*bch), GFP_KERNEL); +	if (bch == NULL) +		goto fail; + +	bch->m = m; +	bch->t = t; +	bch->n = (1 << m)-1; +	words  = DIV_ROUND_UP(m*t, 32); +	bch->ecc_bytes = DIV_ROUND_UP(m*t, 8); +	bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err); +	bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err); +	bch->mod8_tab  = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err); +	bch->ecc_buf   = bch_alloc(words*sizeof(*bch->ecc_buf), &err); +	bch->ecc_buf2  = bch_alloc(words*sizeof(*bch->ecc_buf2), &err); +	bch->xi_tab    = bch_alloc(m*sizeof(*bch->xi_tab), &err); +	bch->syn       = bch_alloc(2*t*sizeof(*bch->syn), &err); +	bch->cache     = bch_alloc(2*t*sizeof(*bch->cache), &err); +	bch->elp       = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err); + +	for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) +		bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err); + +	if (err) +		goto fail; + +	err = build_gf_tables(bch, prim_poly); +	if (err) +		goto fail; + +	/* use generator polynomial for computing encoding tables */ +	genpoly = compute_generator_polynomial(bch); +	if (genpoly == NULL) +		goto fail; + +	build_mod8_tables(bch, genpoly); +	kfree(genpoly); + +	err = build_deg2_base(bch); +	if (err) +		goto fail; + +	return bch; + +fail: +	free_bch(bch); +	return NULL; +} + +/** + *  free_bch - free the BCH control structure + *  @bch:    BCH control structure to release + */ +void free_bch(struct bch_control *bch) +{ +	unsigned int i; + +	if (bch) { +		kfree(bch->a_pow_tab); +		kfree(bch->a_log_tab); +		kfree(bch->mod8_tab); +		kfree(bch->ecc_buf); +		kfree(bch->ecc_buf2); +		kfree(bch->xi_tab); +		kfree(bch->syn); +		kfree(bch->cache); +		kfree(bch->elp); + +		for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) +			kfree(bch->poly_2t[i]); + +		kfree(bch); +	} +} diff --git a/lib/string.c b/lib/string.c index 2c4f0ec9a..c3ad055e2 100644 --- a/lib/string.c +++ b/lib/string.c @@ -214,6 +214,45 @@ char * strrchr(const char * s, int c)  }  #endif + +/** + * skip_spaces - Removes leading whitespace from @str. + * @str: The string to be stripped. + * + * Returns a pointer to the first non-whitespace character in @str. + */ +char *skip_spaces(const char *str) +{ +	while (isspace(*str)) +		++str; +	return (char *)str; +} + +/** + * strim - Removes leading and trailing whitespace from @s. + * @s: The string to be stripped. + * + * Note that the first trailing whitespace is replaced with a %NUL-terminator + * in the given string @s. Returns a pointer to the first non-whitespace + * character in @s. + */ +char *strim(char *s) +{ +	size_t size; +	char *end; + +	s = skip_spaces(s); +	size = strlen(s); +	if (!size) +		return s; + +	end = s + size - 1; +	while (end >= s && isspace(*end)) +		end--; +	*(end + 1) = '\0'; + +	return s; +}  #ifndef __HAVE_ARCH_STRLEN  /**   * strlen - Find the length of a string diff --git a/nand_spl/nand_boot.c b/nand_spl/nand_boot.c index 2326962b2..bfaabd319 100644 --- a/nand_spl/nand_boot.c +++ b/nand_spl/nand_boot.c @@ -24,6 +24,11 @@  static int nand_ecc_pos[] = CONFIG_SYS_NAND_ECCPOS; +#define ECCSTEPS	(CONFIG_SYS_NAND_PAGE_SIZE / \ +					CONFIG_SYS_NAND_ECCSIZE) +#define ECCTOTAL	(ECCSTEPS * CONFIG_SYS_NAND_ECCBYTES) + +  #if (CONFIG_SYS_NAND_PAGE_SIZE <= 512)  /*   * NAND command for small page NAND devices (512) @@ -139,29 +144,21 @@ static int nand_is_bad_block(struct mtd_info *mtd, int block)  static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)  {  	struct nand_chip *this = mtd->priv; -	u_char *ecc_calc; -	u_char *ecc_code; -	u_char *oob_data; +	u_char ecc_calc[ECCTOTAL]; +	u_char ecc_code[ECCTOTAL]; +	u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];  	int i;  	int eccsize = CONFIG_SYS_NAND_ECCSIZE;  	int eccbytes = CONFIG_SYS_NAND_ECCBYTES; -	int eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	int eccsteps = ECCSTEPS;  	uint8_t *p = dst; -	/* -	 * No malloc available for now, just use some temporary locations -	 * in SDRAM -	 */ -	ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000); -	ecc_code = ecc_calc + 0x100; -	oob_data = ecc_calc + 0x200; -  	nand_command(mtd, block, page, 0, NAND_CMD_READOOB);  	this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);  	nand_command(mtd, block, page, 0, NAND_CMD_READ0);  	/* Pick the ECC bytes out of the oob data */ -	for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++) +	for (i = 0; i < ECCTOTAL; i++)  		ecc_code[i] = oob_data[nand_ecc_pos[i]]; @@ -178,24 +175,17 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)  static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)  {  	struct nand_chip *this = mtd->priv; -	u_char *ecc_calc; -	u_char *ecc_code; -	u_char *oob_data; +	u_char ecc_calc[ECCTOTAL]; +	u_char ecc_code[ECCTOTAL]; +	u_char oob_data[CONFIG_SYS_NAND_OOBSIZE];  	int i;  	int eccsize = CONFIG_SYS_NAND_ECCSIZE;  	int eccbytes = CONFIG_SYS_NAND_ECCBYTES; -	int eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	int eccsteps = ECCSTEPS;  	uint8_t *p = dst;  	nand_command(mtd, block, page, 0, NAND_CMD_READ0); -	/* No malloc available for now, just use some temporary locations -	 * in SDRAM -	 */ -	ecc_calc = (u_char *)(CONFIG_SYS_SDRAM_BASE + 0x10000); -	ecc_code = ecc_calc + 0x100; -	oob_data = ecc_calc + 0x200; -  	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {  		this->ecc.hwctl(mtd, NAND_ECC_READ);  		this->read_buf(mtd, p, eccsize); @@ -204,10 +194,10 @@ static int nand_read_page(struct mtd_info *mtd, int block, int page, uchar *dst)  	this->read_buf(mtd, oob_data, CONFIG_SYS_NAND_OOBSIZE);  	/* Pick the ECC bytes out of the oob data */ -	for (i = 0; i < CONFIG_SYS_NAND_ECCTOTAL; i++) +	for (i = 0; i < ECCTOTAL; i++)  		ecc_code[i] = oob_data[nand_ecc_pos[i]]; -	eccsteps = CONFIG_SYS_NAND_ECCSTEPS; +	eccsteps = ECCSTEPS;  	p = dst;  	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) { |