diff mbox

[4/5,fix] mtd: nand: parse out the JEDEC compliant nand

Message ID 1388137870-11421-1-git-send-email-b32955@freescale.com
State Superseded, archived
Headers show

Commit Message

Huang Shijie Dec. 27, 2013, 9:51 a.m. UTC
This patch adds the parsing code for the JEDEC compliant nand.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
Add version check.

---
 drivers/mtd/nand/nand_base.c |   93 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 93 insertions(+), 0 deletions(-)

Comments

Brian Norris Jan. 31, 2014, 6:23 p.m. UTC | #1
On Fri, Dec 27, 2013 at 05:51:10PM +0800, Huang Shijie wrote:
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -3038,6 +3038,95 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
>  }
>  
>  /*
> + * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
> + */
> +static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
> +					int *busw)
> +{
...
> +	/*
> +	 * JEDEC must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not
> +	 * with NAND_BUSWIDTH_16
> +	 */
> +	if (chip->options & NAND_BUSWIDTH_16) {
> +		pr_err("JEDEC cannot be probed in 16-bit mode; aborting\n");
> +		return 0;
> +	}

According to the patches that recently went in for ONFI, I think we can
support x16 devices. See my comment below.

> +	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
> +	for (i = 0; i < 3; i++) {
> +		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));

Rather than using read_buf(), can you run read_byte() in a loop? That
will solve our problems with x16 bus devices, I think.

> +		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
> +				le16_to_cpu(p->crc))
> +			break;
> +	}
> +
...

I have yet to look closely at the JEDEC spec, so I can't comment much
more yet.

Thanks,
Brian
Huang Shijie Feb. 7, 2014, 5:51 a.m. UTC | #2
On Fri, Jan 31, 2014 at 10:23:17AM -0800, Brian Norris wrote:
 
> > +	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
> > +	for (i = 0; i < 3; i++) {
> > +		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
> 
> Rather than using read_buf(), can you run read_byte() in a loop? That
> will solve our problems with x16 bus devices, I think.
thanks.

I will use the read_byte() in the next version.

thanks
Huang Shijie
diff mbox

Patch

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index db45ab3..077eae1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3038,6 +3038,95 @@  static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 }
 
 /*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
+					int *busw)
+{
+	struct nand_jedec_params *p = &chip->jedec_params;
+	struct jedec_ecc_info *ecc;
+	int val;
+	int i;
+
+	/* Try JEDEC for unknown chip or LP */
+	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
+	if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
+		chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
+		chip->read_byte(mtd) != 'C')
+		return 0;
+
+	/*
+	 * JEDEC must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not
+	 * with NAND_BUSWIDTH_16
+	 */
+	if (chip->options & NAND_BUSWIDTH_16) {
+		pr_err("JEDEC cannot be probed in 16-bit mode; aborting\n");
+		return 0;
+	}
+
+	chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
+	for (i = 0; i < 3; i++) {
+		chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
+		if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+				le16_to_cpu(p->crc))
+			break;
+	}
+
+	if (i == 3) {
+		pr_err("Could not find valid JEDEC parameter page; aborting\n");
+		return 0;
+	}
+
+	/* Check version */
+	val = le16_to_cpu(p->revision);
+	if (val & (1 << 2))
+		chip->jedec_version = 10;
+	else if (val & (1 << 1))
+		chip->jedec_version = 1; /* vendor specific version */
+
+	if (!chip->jedec_version) {
+		pr_info("unsupported JEDEC version: %d\n", 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);
+
+	/* Please reference to the comment for nand_flash_detect_onfi. */
+	mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+	mtd->erasesize *= mtd->writesize;
+
+	mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+	/* Please reference to the comment for nand_flash_detect_onfi. */
+	chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+	chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+	chip->bits_per_cell = p->bits_per_cell;
+
+	if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
+		*busw = NAND_BUSWIDTH_16;
+	else
+		*busw = 0;
+
+	/* ECC info */
+	ecc = p->ecc_info;
+
+	if (ecc->codeword_size) {
+		chip->ecc_strength_ds = ecc->ecc_bits;
+		chip->ecc_step_ds = 1 << ecc->codeword_size;
+	} else {
+		pr_debug("Invalid codeword size\n");
+		return 0;
+	}
+
+	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
@@ -3450,6 +3539,10 @@  static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
 		/* Check is chip is ONFI compliant */
 		if (nand_flash_detect_onfi(mtd, chip, &busw))
 			goto ident_done;
+
+		/* Check if the chip is JEDEC compliant */
+		if (nand_flash_detect_jedec(mtd, chip, &busw))
+			goto ident_done;
 	}
 
 	if (!type->name)