|
@@ -16,21 +16,56 @@
|
|
|
*/
|
|
|
|
|
|
#include <linux/mtd/nand.h>
|
|
|
+#include <linux/sizes.h>
|
|
|
|
|
|
-static void 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;
|
|
|
+
|
|
|
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
|
|
|
+ for (i = 0; i < 5; i++)
|
|
|
+ jedecid[i] = chip->read_byte(mtd);
|
|
|
|
|
|
- /* 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];
|
|
|
+ return !strcmp("JEDEC", jedecid);
|
|
|
+}
|
|
|
|
|
|
- /* Extract pagesize */
|
|
|
- mtd->writesize = 2048 << (extid & 0x03);
|
|
|
- extid >>= 2;
|
|
|
+static void hynix_nand_extract_oobsize(struct nand_chip *chip,
|
|
|
+ bool valid_jedecid)
|
|
|
+{
|
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
|
+ u8 oobsize;
|
|
|
|
|
|
- /* Extract oobsize */
|
|
|
- switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
|
|
|
+ oobsize = ((chip->id.data[3] >> 2) & 0x3) |
|
|
|
+ ((chip->id.data[3] >> 4) & 0x4);
|
|
|
+
|
|
|
+ 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:
|
|
|
+ /*
|
|
|
+ * We should never reach this case, but if that
|
|
|
+ * happens, this probably means Hynix decided to use
|
|
|
+ * a different extended ID format, and we should find
|
|
|
+ * a way to support it.
|
|
|
+ */
|
|
|
+ WARN(1, "Invalid OOB size");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ switch (oobsize) {
|
|
|
case 0:
|
|
|
mtd->oobsize = 128;
|
|
|
break;
|
|
@@ -49,23 +84,178 @@ static void hynix_nand_decode_id(struct nand_chip *chip)
|
|
|
case 5:
|
|
|
mtd->oobsize = 16;
|
|
|
break;
|
|
|
- default:
|
|
|
+ case 6:
|
|
|
mtd->oobsize = 640;
|
|
|
break;
|
|
|
+ default:
|
|
|
+ /*
|
|
|
+ * We should never reach this case, but if that
|
|
|
+ * happens, this probably means Hynix decided to use
|
|
|
+ * a different extended ID format, and we should find
|
|
|
+ * a way to support it.
|
|
|
+ */
|
|
|
+ WARN(1, "Invalid OOB size");
|
|
|
+ break;
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void 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;
|
|
|
|
|
|
- /* Extract 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;
|
|
|
+ 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:
|
|
|
+ /*
|
|
|
+ * We should never reach this case, but if that
|
|
|
+ * happens, this probably means Hynix decided to use
|
|
|
+ * a different extended ID format, and we should find
|
|
|
+ * a way to support it.
|
|
|
+ */
|
|
|
+ WARN(1, "Invalid ECC requirements");
|
|
|
+ }
|
|
|
+ } 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 = 1024;
|
|
|
+ chip->ecc_strength_ds = 24;
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * We should never reach this case, but if that
|
|
|
+ * happens, this probably means Hynix decided
|
|
|
+ * to use a different extended ID format, and
|
|
|
+ * we should find a way to support it.
|
|
|
+ */
|
|
|
+ WARN(1, "Invalid ECC requirements");
|
|
|
+ }
|
|
|
+ } 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));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+
|
|
|
+ /* < 32nm */
|
|
|
+ if (nand_tech > 2)
|
|
|
+ chip->options |= NAND_NEED_SCRAMBLING;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void hynix_nand_decode_id(struct nand_chip *chip)
|
|
|
+{
|
|
|
+ struct mtd_info *mtd = nand_to_mtd(chip);
|
|
|
+ bool valid_jedecid;
|
|
|
+ u8 tmp;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 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)) {
|
|
|
nand_decode_ext_id(chip);
|
|
|
+ return;
|
|
|
}
|
|
|
+
|
|
|
+ /* Extract pagesize */
|
|
|
+ mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ hynix_nand_extract_oobsize(chip, valid_jedecid);
|
|
|
+ hynix_nand_extract_ecc_requirements(chip, valid_jedecid);
|
|
|
+ hynix_nand_extract_scrambling_requirements(chip, valid_jedecid);
|
|
|
}
|
|
|
|
|
|
static int hynix_nand_init(struct nand_chip *chip)
|