diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 85 |
1 files changed, 85 insertions, 0 deletions
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 @@ -3163,6 +3163,87 @@ 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, 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 * @arrlen: the length of the @id_data array @@ -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) |