mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2] nand_base: fix to test for JCPV problem
@ 2013-05-08 17:03 Eric Bénard
  2013-05-08 17:11 ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 3+ messages in thread
From: Eric Bénard @ 2013-05-08 17:03 UTC (permalink / raw)
  To: barebox

Signed-off-by: Eric Bénard <eric@eukrea.com>
---
this patch sync flash detection functions with linux 3.9's code
 drivers/mtd/nand/nand_base.c | 377 ++++++++++++++++++++++++++++++-------------
 include/linux/mtd/bbm.h      |   2 +
 2 files changed, 265 insertions(+), 114 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index e8103cf..9bfddf9 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1077,7 +1077,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
 		return 0;
 
-	pr_info("ONFI flash detected ... ");
 	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
 	for (i = 0; i < 3; i++) {
 		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
@@ -1128,10 +1127,252 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 	chip->options &= ~NAND_CHIPOPTIONS_MSK;
 	chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
 
+	pr_info("ONFI flash detected ... ");
+	return 1;
+}
+
+/*
+ * nand_id_has_period - Check if an ID string has a given wraparound period
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+ * @period: the period of repitition
+ *
+ * Check if an ID string is repeated within a given sequence of bytes at
+ * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
+ * period of 3). This is a helper function for nand_id_len(). Returns non-zero
+ * if the repetition has a period of @period; otherwise, returns zero.
+ */
+static int nand_id_has_period(u8 *id_data, int arrlen, int period)
+{
+	int i, j;
+	for (i = 0; i < period; i++)
+		for (j = i + period; j < arrlen; j += period)
+			if (id_data[i] != id_data[j])
+				return 0;
 	return 1;
 }
 
 /*
+ * nand_id_len - Get the length of an ID string returned by CMD_READID
+ * @id_data: the ID string
+ * @arrlen: the length of the @id_data array
+
+ * Returns the length of the ID string, according to known wraparound/trailing
+ * zero patterns. If no pattern exists, returns the length of the array.
+ */
+static int nand_id_len(u8 *id_data, int arrlen)
+{
+	int last_nonzero, period;
+
+	/* Find last non-zero byte */
+	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
+		if (id_data[last_nonzero])
+			break;
+
+	/* All zeros */
+	if (last_nonzero < 0)
+		return 0;
+
+	/* Calculate wraparound period */
+	for (period = 1; period < arrlen; period++)
+		if (nand_id_has_period(id_data, arrlen, period))
+			break;
+
+	/* There's a repeated pattern */
+	if (period < arrlen)
+		return period;
+
+	/* There are trailing zeros */
+	if (last_nonzero < arrlen - 1)
+		return last_nonzero + 1;
+
+	/* No pattern detected */
+	return arrlen;
+}
+
+/*
+ * Many new NAND share similar device ID codes, which represent the size of the
+ * chip. The rest of the parameters must be decoded according to generic or
+ * manufacturer-specific "extended ID" decoding patterns.
+ */
+static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
+				u8 id_data[8], int *busw)
+{
+	int extid, id_len;
+	/* 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];
+
+	id_len = nand_id_len(id_data, 8);
+
+	/*
+	 * Field definitions are in the following datasheets:
+	 * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+	 * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
+	 * Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22)
+	 *
+	 * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
+	 * ID to decide what to do.
+	 */
+	if (id_len == 6 && 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 >> 2) & 0x04) | (extid & 0x03)) {
+		case 1:
+			mtd->oobsize = 128;
+			break;
+		case 2:
+			mtd->oobsize = 218;
+			break;
+		case 3:
+			mtd->oobsize = 400;
+			break;
+		case 4:
+			mtd->oobsize = 436;
+			break;
+		case 5:
+			mtd->oobsize = 512;
+			break;
+		case 6:
+		default: /* Other cases are "reserved" (unknown) */
+			mtd->oobsize = 640;
+			break;
+		}
+		extid >>= 2;
+		/* Calc blocksize */
+		mtd->erasesize = (128 * 1024) <<
+			(((extid >> 1) & 0x04) | (extid & 0x03));
+		*busw = 0;
+	} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
+			(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
+		unsigned int tmp;
+
+		/* Calc pagesize */
+		mtd->writesize = 2048 << (extid & 0x03);
+		extid >>= 2;
+		/* Calc oobsize */
+		switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
+		case 0:
+			mtd->oobsize = 128;
+			break;
+		case 1:
+			mtd->oobsize = 224;
+			break;
+		case 2:
+			mtd->oobsize = 448;
+			break;
+		case 3:
+			mtd->oobsize = 64;
+			break;
+		case 4:
+			mtd->oobsize = 32;
+			break;
+		case 5:
+			mtd->oobsize = 16;
+			break;
+		default:
+			mtd->oobsize = 640;
+			break;
+		}
+		extid >>= 2;
+		/* Calc blocksize */
+		tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
+		if (tmp < 0x03)
+			mtd->erasesize = (128 * 1024) << tmp;
+		else if (tmp == 0x03)
+			mtd->erasesize = 768 * 1024;
+		else
+			mtd->erasesize = (64 * 1024) << tmp;
+		*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;
+	}
+}
+
+/*
+ * Old devices have chip data hardcoded in the device ID table. nand_decode_id
+ * decodes a matching ID table entry and assigns the MTD size parameters for
+ * the chip.
+ */
+static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
+				struct nand_flash_dev *type, u8 id_data[8],
+				int *busw)
+{
+	int maf_id = id_data[0];
+
+	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);
+	}
+}
+
+/*
+ * Set the bad block marker/indicator (BBM/BBI) patterns according to some
+ * heuristic patterns using various detected parameters (e.g., manufacturer,
+ * page size, cell-type information).
+ */
+static void nand_decode_bbm_options(struct mtd_info *mtd,
+				    struct nand_chip *chip, u8 id_data[8])
+{
+	int maf_id = id_data[0];
+
+	/* Set the bad block position */
+	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
+		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
+	else
+		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
+
+	/*
+	 * 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,
+	 * AMD/Spansion, and Macronix.  All others scan only the first page.
+	 */
+	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+			(maf_id == NAND_MFR_SAMSUNG ||
+			 maf_id == NAND_MFR_HYNIX))
+		chip->bbt_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 ||
+				 maf_id == NAND_MFR_MACRONIX)) ||
+			(mtd->writesize == 2048 &&
+			 maf_id == NAND_MFR_MICRON))
+		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
+}
+
+/*
  * Get the flash and manufacturer id and lookup if the type is supported
  */
 static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
@@ -1140,7 +1381,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 {
 	struct nand_flash_dev *type = NULL;
 	int i, dev_id, maf_idx;
-	int id_data[8];
+	u8 id_data[8];
 	int ret;
 
 	/* Select the device */
@@ -1167,10 +1408,9 @@ static 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 */
-
-	id_data[0] = chip->read_byte(mtd);
-	id_data[1] = chip->read_byte(mtd);
+	/* Read entire ID string */
+	for (i = 0; i < 8; i++)
+		id_data[i] = chip->read_byte(mtd);
 
 	if (id_data[0] != *maf_id || id_data[1] != dev_id) {
 		pr_err("%s: second ID read did not match "
@@ -1190,20 +1430,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	if (!type->name || !type->pagesize) {
 		/* Check is chip is ONFI compliant */
 		ret = nand_flash_detect_onfi(mtd, chip, &busw);
-		if (ret)
 			goto ident_done;
-		else {
-			pr_err("NAND type unknown: %02x,%02x\n", *maf_id, dev_id);
-			return ERR_PTR(-ENODEV);
-		}
 	}
 
-	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;
@@ -1211,102 +1442,20 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 	chip->chipsize = type->chipsize << 20;
 
 	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;
-		}
-
-
+		/* Decode parameters from extended ID */
+		nand_decode_ext_id(mtd, chip, id_data, &busw);
 	} 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);
-		}
+		nand_decode_id(mtd, chip, type, id_data, &busw);
 	}
+	/* Get chip options */
+	chip->options |= type->options;
 
-	/* Try to identify manufacturer */
-	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
-		if (nand_manuf_ids[maf_idx].id == *maf_id)
-			break;
-	}
-
-	/* 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.
+	/*
+	 * Check if chip is not a Samsung device. Do not clear the
+	 * options for chips which do not have 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
@@ -1324,13 +1473,11 @@ ident_done:
 		nand_set_defaults(chip, busw);
 		if (chip->set_buswidth)
 			chip->set_buswidth(mtd, chip, busw);
-	}
-
-	/*
-	 * Check, if buswidth is correct. Hardware drivers should set
-	 * chip correct !
-	 */
-	if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+	} else 	if (busw != (chip->options & NAND_BUSWIDTH_16)) {
+		/*
+		 * Check, if buswidth is correct. Hardware drivers should set
+		 * chip correct !
+		 */
 		pr_info("NAND device: Manufacturer ID:"
 			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
 			dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
@@ -1340,6 +1487,8 @@ ident_done:
 		return ERR_PTR(-EINVAL);
 	}
 
+	nand_decode_bbm_options(mtd, chip, id_data);
+
 	/* Calculate the address shift from the page size */
 	chip->page_shift = ffs(mtd->writesize) - 1;
 	/* Convert chipsize to number of pages per chip -1. */
diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
index d546f40..50bc4d9 100644
--- a/include/linux/mtd/bbm.h
+++ b/include/linux/mtd/bbm.h
@@ -79,6 +79,8 @@ 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	0x00010000
 
 /*
  * Use a flash based bad block table. By default, OOB identifier is saved in
-- 
1.8.1.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] nand_base: fix to test for JCPV problem
  2013-05-08 17:03 [PATCH v2] nand_base: fix to test for JCPV problem Eric Bénard
@ 2013-05-08 17:11 ` Jean-Christophe PLAGNIOL-VILLARD
  2013-05-08 17:40   ` Eric Bénard
  0 siblings, 1 reply; 3+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-05-08 17:11 UTC (permalink / raw)
  To: Eric Bénard; +Cc: barebox

Hi,

	same

barebox 2013.05.0-00119-g57955f2 #613 Thu May 9 01:12:00 CST 2013


Board: Atmel at91sam9x5-ek
AT91: Detected soc type: at91sam9x5
AT91: Detected soc subtype: at91sam9x25
Clocks: CPU 400 MHz, master 133 MHz, main 12.000 MHz
netconsole: registered as cs2
CM: SAM9X25-CM [B2] from RONETIX
EK: SAM9x5-EK [B0] from FLEX
DM: SAM9x5-DM [B0] from FLEX
sn: 0x4010465, rev: 0x10421
atmel_nand: Use On Flash BBT
nand: no valid ONFI param page found
nand: Manufacturer ID: 0xad, Chip ID: 0xda (Hynix NAND 256MiB 3,3V 8-bit), page size: 0, OOB size: 0
atmel_nand atmel_nand0: Initialize PMECC params, cap: 2, sector: 512
nand: No oob scheme defined for oobsize 0
BUG: failure at /opt/work/barebox/drivers/mtd/nand/nand_base.c:1642/nand_scan_tail()!
BUG!
no stack data available

Best Regards,
J.
On 19:03 Wed 08 May     , Eric Bénard wrote:
> Signed-off-by: Eric Bénard <eric@eukrea.com>
> ---
> this patch sync flash detection functions with linux 3.9's code
>  drivers/mtd/nand/nand_base.c | 377 ++++++++++++++++++++++++++++++-------------
>  include/linux/mtd/bbm.h      |   2 +
>  2 files changed, 265 insertions(+), 114 deletions(-)
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index e8103cf..9bfddf9 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1077,7 +1077,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
>  		chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
>  		return 0;
>  
> -	pr_info("ONFI flash detected ... ");
>  	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
>  	for (i = 0; i < 3; i++) {
>  		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
> @@ -1128,10 +1127,252 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
>  	chip->options &= ~NAND_CHIPOPTIONS_MSK;
>  	chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
>  
> +	pr_info("ONFI flash detected ... ");
> +	return 1;
> +}
> +
> +/*
> + * nand_id_has_period - Check if an ID string has a given wraparound period
> + * @id_data: the ID string
> + * @arrlen: the length of the @id_data array
> + * @period: the period of repitition
> + *
> + * Check if an ID string is repeated within a given sequence of bytes at
> + * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a
> + * period of 3). This is a helper function for nand_id_len(). Returns non-zero
> + * if the repetition has a period of @period; otherwise, returns zero.
> + */
> +static int nand_id_has_period(u8 *id_data, int arrlen, int period)
> +{
> +	int i, j;
> +	for (i = 0; i < period; i++)
> +		for (j = i + period; j < arrlen; j += period)
> +			if (id_data[i] != id_data[j])
> +				return 0;
>  	return 1;
>  }
>  
>  /*
> + * nand_id_len - Get the length of an ID string returned by CMD_READID
> + * @id_data: the ID string
> + * @arrlen: the length of the @id_data array
> +
> + * Returns the length of the ID string, according to known wraparound/trailing
> + * zero patterns. If no pattern exists, returns the length of the array.
> + */
> +static int nand_id_len(u8 *id_data, int arrlen)
> +{
> +	int last_nonzero, period;
> +
> +	/* Find last non-zero byte */
> +	for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--)
> +		if (id_data[last_nonzero])
> +			break;
> +
> +	/* All zeros */
> +	if (last_nonzero < 0)
> +		return 0;
> +
> +	/* Calculate wraparound period */
> +	for (period = 1; period < arrlen; period++)
> +		if (nand_id_has_period(id_data, arrlen, period))
> +			break;
> +
> +	/* There's a repeated pattern */
> +	if (period < arrlen)
> +		return period;
> +
> +	/* There are trailing zeros */
> +	if (last_nonzero < arrlen - 1)
> +		return last_nonzero + 1;
> +
> +	/* No pattern detected */
> +	return arrlen;
> +}
> +
> +/*
> + * Many new NAND share similar device ID codes, which represent the size of the
> + * chip. The rest of the parameters must be decoded according to generic or
> + * manufacturer-specific "extended ID" decoding patterns.
> + */
> +static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
> +				u8 id_data[8], int *busw)
> +{
> +	int extid, id_len;
> +	/* 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];
> +
> +	id_len = nand_id_len(id_data, 8);
> +
> +	/*
> +	 * Field definitions are in the following datasheets:
> +	 * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
> +	 * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
> +	 * Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22)
> +	 *
> +	 * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
> +	 * ID to decide what to do.
> +	 */
> +	if (id_len == 6 && 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 >> 2) & 0x04) | (extid & 0x03)) {
> +		case 1:
> +			mtd->oobsize = 128;
> +			break;
> +		case 2:
> +			mtd->oobsize = 218;
> +			break;
> +		case 3:
> +			mtd->oobsize = 400;
> +			break;
> +		case 4:
> +			mtd->oobsize = 436;
> +			break;
> +		case 5:
> +			mtd->oobsize = 512;
> +			break;
> +		case 6:
> +		default: /* Other cases are "reserved" (unknown) */
> +			mtd->oobsize = 640;
> +			break;
> +		}
> +		extid >>= 2;
> +		/* Calc blocksize */
> +		mtd->erasesize = (128 * 1024) <<
> +			(((extid >> 1) & 0x04) | (extid & 0x03));
> +		*busw = 0;
> +	} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
> +			(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
> +		unsigned int tmp;
> +
> +		/* Calc pagesize */
> +		mtd->writesize = 2048 << (extid & 0x03);
> +		extid >>= 2;
> +		/* Calc oobsize */
> +		switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
> +		case 0:
> +			mtd->oobsize = 128;
> +			break;
> +		case 1:
> +			mtd->oobsize = 224;
> +			break;
> +		case 2:
> +			mtd->oobsize = 448;
> +			break;
> +		case 3:
> +			mtd->oobsize = 64;
> +			break;
> +		case 4:
> +			mtd->oobsize = 32;
> +			break;
> +		case 5:
> +			mtd->oobsize = 16;
> +			break;
> +		default:
> +			mtd->oobsize = 640;
> +			break;
> +		}
> +		extid >>= 2;
> +		/* Calc blocksize */
> +		tmp = ((extid >> 1) & 0x04) | (extid & 0x03);
> +		if (tmp < 0x03)
> +			mtd->erasesize = (128 * 1024) << tmp;
> +		else if (tmp == 0x03)
> +			mtd->erasesize = 768 * 1024;
> +		else
> +			mtd->erasesize = (64 * 1024) << tmp;
> +		*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;
> +	}
> +}
> +
> +/*
> + * Old devices have chip data hardcoded in the device ID table. nand_decode_id
> + * decodes a matching ID table entry and assigns the MTD size parameters for
> + * the chip.
> + */
> +static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
> +				struct nand_flash_dev *type, u8 id_data[8],
> +				int *busw)
> +{
> +	int maf_id = id_data[0];
> +
> +	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);
> +	}
> +}
> +
> +/*
> + * Set the bad block marker/indicator (BBM/BBI) patterns according to some
> + * heuristic patterns using various detected parameters (e.g., manufacturer,
> + * page size, cell-type information).
> + */
> +static void nand_decode_bbm_options(struct mtd_info *mtd,
> +				    struct nand_chip *chip, u8 id_data[8])
> +{
> +	int maf_id = id_data[0];
> +
> +	/* Set the bad block position */
> +	if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
> +		chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
> +	else
> +		chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
> +
> +	/*
> +	 * 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,
> +	 * AMD/Spansion, and Macronix.  All others scan only the first page.
> +	 */
> +	if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
> +			(maf_id == NAND_MFR_SAMSUNG ||
> +			 maf_id == NAND_MFR_HYNIX))
> +		chip->bbt_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 ||
> +				 maf_id == NAND_MFR_MACRONIX)) ||
> +			(mtd->writesize == 2048 &&
> +			 maf_id == NAND_MFR_MICRON))
> +		chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
> +}
> +
> +/*
>   * Get the flash and manufacturer id and lookup if the type is supported
>   */
>  static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
> @@ -1140,7 +1381,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  {
>  	struct nand_flash_dev *type = NULL;
>  	int i, dev_id, maf_idx;
> -	int id_data[8];
> +	u8 id_data[8];
>  	int ret;
>  
>  	/* Select the device */
> @@ -1167,10 +1408,9 @@ static 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 */
> -
> -	id_data[0] = chip->read_byte(mtd);
> -	id_data[1] = chip->read_byte(mtd);
> +	/* Read entire ID string */
> +	for (i = 0; i < 8; i++)
> +		id_data[i] = chip->read_byte(mtd);
>  
>  	if (id_data[0] != *maf_id || id_data[1] != dev_id) {
>  		pr_err("%s: second ID read did not match "
> @@ -1190,20 +1430,11 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  	if (!type->name || !type->pagesize) {
>  		/* Check is chip is ONFI compliant */
>  		ret = nand_flash_detect_onfi(mtd, chip, &busw);
> -		if (ret)
>  			goto ident_done;
> -		else {
> -			pr_err("NAND type unknown: %02x,%02x\n", *maf_id, dev_id);
> -			return ERR_PTR(-ENODEV);
> -		}
>  	}
>  
> -	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;
> @@ -1211,102 +1442,20 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
>  	chip->chipsize = type->chipsize << 20;
>  
>  	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;
> -		}
> -
> -
> +		/* Decode parameters from extended ID */
> +		nand_decode_ext_id(mtd, chip, id_data, &busw);
>  	} 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);
> -		}
> +		nand_decode_id(mtd, chip, type, id_data, &busw);
>  	}
> +	/* Get chip options */
> +	chip->options |= type->options;
>  
> -	/* Try to identify manufacturer */
> -	for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
> -		if (nand_manuf_ids[maf_idx].id == *maf_id)
> -			break;
> -	}
> -
> -	/* 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.
> +	/*
> +	 * Check if chip is not a Samsung device. Do not clear the
> +	 * options for chips which do not have 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
> @@ -1324,13 +1473,11 @@ ident_done:
>  		nand_set_defaults(chip, busw);
>  		if (chip->set_buswidth)
>  			chip->set_buswidth(mtd, chip, busw);
> -	}
> -
> -	/*
> -	 * Check, if buswidth is correct. Hardware drivers should set
> -	 * chip correct !
> -	 */
> -	if (busw != (chip->options & NAND_BUSWIDTH_16)) {
> +	} else 	if (busw != (chip->options & NAND_BUSWIDTH_16)) {
> +		/*
> +		 * Check, if buswidth is correct. Hardware drivers should set
> +		 * chip correct !
> +		 */
>  		pr_info("NAND device: Manufacturer ID:"
>  			" 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
>  			dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
> @@ -1340,6 +1487,8 @@ ident_done:
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> +	nand_decode_bbm_options(mtd, chip, id_data);
> +
>  	/* Calculate the address shift from the page size */
>  	chip->page_shift = ffs(mtd->writesize) - 1;
>  	/* Convert chipsize to number of pages per chip -1. */
> diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h
> index d546f40..50bc4d9 100644
> --- a/include/linux/mtd/bbm.h
> +++ b/include/linux/mtd/bbm.h
> @@ -79,6 +79,8 @@ 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	0x00010000
>  
>  /*
>   * Use a flash based bad block table. By default, OOB identifier is saved in
> -- 
> 1.8.1.4
> 

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] nand_base: fix to test for JCPV problem
  2013-05-08 17:11 ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-05-08 17:40   ` Eric Bénard
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Bénard @ 2013-05-08 17:40 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

Le Wed, 8 May 2013 19:11:32 +0200,
Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> a écrit :

> Hi,
> 
> 	same
> 
> barebox 2013.05.0-00119-g57955f2 #613 Thu May 9 01:12:00 CST 2013
> 
> 
> Board: Atmel at91sam9x5-ek
> AT91: Detected soc type: at91sam9x5
> AT91: Detected soc subtype: at91sam9x25
> Clocks: CPU 400 MHz, master 133 MHz, main 12.000 MHz
> netconsole: registered as cs2
> CM: SAM9X25-CM [B2] from RONETIX
> EK: SAM9x5-EK [B0] from FLEX
> DM: SAM9x5-DM [B0] from FLEX
> sn: 0x4010465, rev: 0x10421
> atmel_nand: Use On Flash BBT
> nand: no valid ONFI param page found
> nand: Manufacturer ID: 0xad, Chip ID: 0xda (Hynix NAND 256MiB 3,3V 8-bit), page size: 0, OOB size: 0
> atmel_nand atmel_nand0: Initialize PMECC params, cap: 2, sector: 512
> nand: No oob scheme defined for oobsize 0
> BUG: failure at /opt/work/barebox/drivers/mtd/nand/nand_base.c:1642/nand_scan_tail()!
> BUG!
> no stack data available
> 
behaviour should be different with v3 (I had an error in v2)

Eric

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-05-08 17:40 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-08 17:03 [PATCH v2] nand_base: fix to test for JCPV problem Eric Bénard
2013-05-08 17:11 ` Jean-Christophe PLAGNIOL-VILLARD
2013-05-08 17:40   ` Eric Bénard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox