linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Boris Brezillon <boris.brezillon@free-electrons.com>
To: Boris Brezillon <boris.brezillon@free-electrons.com>,
	Richard Weinberger <richard@nod.at>,
	linux-mtd@lists.infradead.org,
	David Woodhouse <dwmw2@infradead.org>,
	Brian Norris <computersforpeace@gmail.com>
Cc: Hans de Goede <hdegoede@redhat.com>, linux-kernel@vger.kernel.org
Subject: [PATCH 14/15] mtd: nand: hynix: rework NAND ID decoding to extract more information
Date: Fri, 27 May 2016 14:55:00 +0200	[thread overview]
Message-ID: <1464353701-23233-15-git-send-email-boris.brezillon@free-electrons.com> (raw)
In-Reply-To: <1464353701-23233-1-git-send-email-boris.brezillon@free-electrons.com>

The current NAND ID detection in nand_hynix.c is not handling the
different scheme used by Hynix, thus forcing developers to add new
entries in the nand_ids table each time they want to support a new MLC
NAND.

Enhance the detection logic to handle all known formats. This does not
necessarily mean we are handling all the cases, but if new formats are
discovered, the code should evolve to take them into account instead of
adding more full-id entries in the nand_ids table.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/nand_hynix.c | 226 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 202 insertions(+), 24 deletions(-)

diff --git a/drivers/mtd/nand/nand_hynix.c b/drivers/mtd/nand/nand_hynix.c
index 3a4e1a4..cad1d99 100644
--- a/drivers/mtd/nand/nand_hynix.c
+++ b/drivers/mtd/nand/nand_hynix.c
@@ -14,26 +14,47 @@
 
 #include <linux/mtd/nand.h>
 
-static int hynix_nand_decode_id(struct nand_chip *chip)
+static bool hynix_nand_has_valid_jedecid(struct nand_chip *chip)
 {
 	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 jedecid[6] = { };
+	int i = 0;
 
-	/*
-	 * The NAND is compatible with the JEDEC or ONFI standard, we already
-	 * have all the information we could retrieve from the extended ID.
-	 */
-	if (chip->onfi_version || chip->jedec_version)
-		return 0;
+	chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
+	for (i = 0; i < 5; i++)
+		jedecid[i] = chip->read_byte(mtd);
+
+	return !strcmp("JEDEC", jedecid);
+}
 
-	/* Hynix MLC   (6 byte ID): Hynix H27UBG8T2B (p.22) */
-	if (chip->id.len == 6 && !nand_is_slc(chip)) {
-		u8 tmp, extid = chip->id.data[3] >> 2;
+static int hynix_nand_extract_oobsize(struct nand_chip *chip,
+				      bool valid_jedecid)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	u8 oobsize;
 
-		/* Adjust pagesize */
-		mtd->writesize <<= 1;
+	oobsize = ((chip->id.data[3] >> 2) & 0x3) |
+		  ((chip->id.data[3] >> 4) & 0x4);
 
-		/* Fix oobsize */
-		switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
+	if (valid_jedecid) {
+		switch (oobsize) {
+		case 0:
+			mtd->oobsize = 2048;
+			break;
+		case 1:
+			mtd->oobsize = 1664;
+			break;
+		case 2:
+			mtd->oobsize = 1024;
+			break;
+		case 3:
+			mtd->oobsize = 640;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (oobsize) {
 		case 0:
 			mtd->oobsize = 128;
 			break;
@@ -52,21 +73,178 @@ static int hynix_nand_decode_id(struct nand_chip *chip)
 		case 5:
 			mtd->oobsize = 16;
 			break;
-		default:
+		case 6:
 			mtd->oobsize = 640;
 			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
+					       bool valid_jedecid)
+{
+	u8 ecc_level = (chip->id.data[4] >> 4) & 0x7;
+
+	if (valid_jedecid) {
+		/* Reference: H27UCG8T2E datasheet */
+		chip->ecc_step_ds = 1024;
+
+		switch (ecc_level) {
+		case 0:
+			chip->ecc_step_ds = 0;
+			chip->ecc_strength_ds = 0;
+			break;
+		case 1:
+			chip->ecc_strength_ds = 4;
+			break;
+		case 2:
+			chip->ecc_strength_ds = 24;
+			break;
+		case 3:
+			chip->ecc_strength_ds = 32;
+			break;
+		case 4:
+			chip->ecc_strength_ds = 40;
+			break;
+		case 5:
+			chip->ecc_strength_ds = 50;
+			break;
+		case 6:
+			chip->ecc_strength_ds = 60;
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		/*
+		 * The ECC requirements field meaning depends on the
+		 * NAND technology.
+		 */
+		u8 nand_tech = chip->id.data[5] & 0x3;
+
+		if (nand_tech < 3) {
+			/* > 26nm, reference: H27UBG8T2A datasheet */
+			if (ecc_level < 5) {
+				chip->ecc_step_ds = 512;
+				chip->ecc_strength_ds = 1 << ecc_level;
+			} else if (ecc_level < 7) {
+				if (ecc_level == 5)
+					chip->ecc_step_ds = 2048;
+				else
+					chip->ecc_step_ds = 2048;
+				chip->ecc_strength_ds = 24;
+			} else {
+				return -EINVAL;
+			}
+		} else {
+			/* <= 26nm, reference: H27UBG8T2B datasheet */
+			if (!ecc_level) {
+				chip->ecc_step_ds = 0;
+				chip->ecc_strength_ds = 0;
+			} else if (ecc_level < 5) {
+				chip->ecc_step_ds = 512;
+				chip->ecc_strength_ds = 1 << (ecc_level - 1);
+			} else {
+				chip->ecc_step_ds = 1024;
+				chip->ecc_strength_ds = 24 +
+							(8 * (ecc_level - 5));
+			}
 		}
+	}
+
+	return 0;
+}
+
+static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
+						       bool valid_jedecid)
+{
+	u8 nand_tech;
+
+	/* We need scrambling on all TLC NANDs*/
+	if (chip->bits_per_cell > 2)
+		chip->options |= NAND_NEED_SCRAMBLING;
+
+	/* And on MLC NANDs with sub-3xnm process */
+	if (valid_jedecid) {
+		nand_tech = chip->id.data[5] >> 4;
+
+		/* < 3xnm */
+		if (nand_tech > 0)
+			chip->options |= NAND_NEED_SCRAMBLING;
+	} else {
+		nand_tech = chip->id.data[5] & 0x3;
 
-		/* Fix blocksize */
-		extid >>= 2;
-		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;
+		/* < 32nm */
+		if (nand_tech > 2)
+			chip->options |= NAND_NEED_SCRAMBLING;
 	}
+}
+
+static int hynix_nand_decode_id(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	bool valid_jedecid;
+	int ret;
+	u8 tmp;
+
+	/*
+	 * The NAND is compatible with the JEDEC or ONFI standard, we already
+	 * have all the information we could retrieve from the extended ID.
+	 */
+	if (chip->onfi_version || chip->jedec_version)
+		return 0;
+
+	/*
+	 * Exclude all SLC NANDs from this advanced detection scheme.
+	 * According to the ranges defined in several datasheets, it might
+	 * appear that even SLC NANDs could fall in this extended ID scheme.
+	 * If that the case rework the test to let SLC NANDs go through the
+	 * detection process.
+	 */
+	if (chip->id.len < 6 || nand_is_slc(chip))
+		return 0;
+
+	/*
+	 * Adjust pagesize. On MLC NANDs, we start at 128KiB not 64KiB,
+	 * a simple left shift does the trick.
+	 */
+	mtd->writesize <<= 1;
+
+	tmp = (chip->id.data[3] >> 4) & 0x3;
+	/*
+	 * When bit7 is set that means we start counting at 1MiB, otherwise
+	 * we start counting at 128KiB and shift this value the content of
+	 * ID[3][4:5].
+	 * The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
+	 * this case the erasesize is set to 768KiB.
+	 */
+	if (chip->id.data[3] & 0x80)
+		mtd->erasesize = SZ_1M << tmp;
+	else if (tmp == 3)
+		mtd->erasesize = SZ_512K + SZ_256K;
+	else
+		mtd->erasesize = SZ_128K << tmp;
+
+	/*
+	 * Modern Toggle DDR NANDs have a valid JEDECID even though they are
+	 * not exposing a valid JEDEC parameter table.
+	 * These NANDs use a different NAND ID scheme.
+	 */
+	valid_jedecid = hynix_nand_has_valid_jedecid(chip);
+
+	ret = hynix_nand_extract_oobsize(chip, valid_jedecid);
+	if (ret)
+		return ret;
+
+	ret = hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
+	if (ret)
+		return ret;
+
+	hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
 
 	return 0;
 }
-- 
2.7.4

  parent reply	other threads:[~2016-05-27 12:55 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-27 12:54 [PATCH 00/15] mtd: nand: allow vendor specific detection/initialization Boris Brezillon
2016-05-27 12:54 ` [PATCH 01/15] mtd: nand: get rid of the mtd parameter in all auto-detection functions Boris Brezillon
2016-05-27 12:54 ` [PATCH 02/15] mtd: nand: store nand ID in struct nand_chip Boris Brezillon
2016-05-27 12:54 ` [PATCH 03/15] mtd: nand: get rid of busw parameter Boris Brezillon
2016-05-27 12:54 ` [PATCH 04/15] mtd: nand: rename nand_get_flash_type() into nand_detect() Boris Brezillon
2016-05-27 12:54 ` [PATCH 05/15] mtd: nand: add vendor specific initialization step Boris Brezillon
2016-05-27 12:54 ` [PATCH 06/15] mtd: nand: kill the MTD_NAND_IDS Kconfig option Boris Brezillon
2016-05-27 12:54 ` [PATCH 07/15] mtd: nand: move samsung specific initialization in nand_samsung.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 08/15] mtd: nand: move hynix specific initialization in nand_hynix.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 09/15] mtd: nand: move toshiba specific initialization in nand_toshiba.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 10/15] mtd: nand: move micron specific initialization in nand_micron.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 11/15] mtd: nand: move AMD/Spansion specific initialization in nand_amd.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 12/15] mtd: nand: move Macronix specific initialization in nand_macronix.c Boris Brezillon
2016-05-27 12:54 ` [PATCH 13/15] mtd: nand: samsung: retrieve ECC requirements from extended ID Boris Brezillon
2016-05-30  0:20   ` Valdis.Kletnieks
2016-05-30  7:44     ` Boris Brezillon
2016-05-30 20:56       ` Valdis.Kletnieks
2016-05-30 22:28         ` Boris Brezillon
2016-05-30 22:32           ` Boris Brezillon
2016-05-27 12:55 ` Boris Brezillon [this message]
2016-05-27 12:55 ` [PATCH 15/15] mtd: nand: hynix: add read-retry support for 1x nm MLC NANDs Boris Brezillon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1464353701-23233-15-git-send-email-boris.brezillon@free-electrons.com \
    --to=boris.brezillon@free-electrons.com \
    --cc=computersforpeace@gmail.com \
    --cc=dwmw2@infradead.org \
    --cc=hdegoede@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mtd@lists.infradead.org \
    --cc=richard@nod.at \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).