From 913618185e51ee1fcbc193b2f121a9d072405619 Mon Sep 17 00:00:00 2001 From: Huang Shijie Date: Fri, 21 Feb 2014 13:39:40 +0800 Subject: [PATCH] mtd: nand: parse out the JEDEC compliant NAND This patch adds the parsing code for the JEDEC compliant NAND. Since we need the 0x40 as the column address, this patch also makes the NAND_CMD_PARAM to use the 8-bit address only. Signed-off-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 85 ++++++++++++++++++++++++++++++++++++ include/linux/mtd/nand.h | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 3cb1cefcd926..30416ecf44ef 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3162,6 +3162,87 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, return 1; } +/* + * 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, j; + + /* 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; + + chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1); + for (i = 0; i < 3; i++) { + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); + + 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[0]; + + if (ecc->codeword_size >= 9) { + chip->ecc_strength_ds = ecc->ecc_bits; + chip->ecc_step_ds = 1 << ecc->codeword_size; + } else { + pr_warn("Invalid codeword size\n"); + } + + return 1; +} + /* * nand_id_has_period - Check if an ID string has a given wraparound period * @id_data: the ID string @@ -3527,6 +3608,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) diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index afd1cf9b5eaf..aa005e87d161 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -925,7 +925,7 @@ static inline bool nand_is_slc(struct nand_chip *chip) */ static inline int nand_opcode_8bits(unsigned int command) { - return command == NAND_CMD_READID; + return command == NAND_CMD_READID || command == NAND_CMD_PARAM; } /* return the supported JEDEC features. */ -- 2.30.2