linux/drivers/mtd/nand/raw/nand_jedec.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
   4 *                2002-2006 Thomas Gleixner (tglx@linutronix.de)
   5 *
   6 *  Credits:
   7 *      David Woodhouse for adding multichip support
   8 *
   9 *      Aleph One Ltd. and Toby Churchill Ltd. for supporting the
  10 *      rework for 2K page size chips
  11 *
  12 * This file contains all ONFI helpers.
  13 */
  14
  15#include <linux/slab.h>
  16
  17#include "internals.h"
  18
  19#define JEDEC_PARAM_PAGES 3
  20
  21/*
  22 * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
  23 */
  24int nand_jedec_detect(struct nand_chip *chip)
  25{
  26        struct nand_device *base = &chip->base;
  27        struct mtd_info *mtd = nand_to_mtd(chip);
  28        struct nand_memory_organization *memorg;
  29        struct nand_jedec_params *p;
  30        struct jedec_ecc_info *ecc;
  31        bool use_datain = false;
  32        int jedec_version = 0;
  33        char id[5];
  34        int i, val, ret;
  35        u16 crc;
  36
  37        memorg = nanddev_get_memorg(&chip->base);
  38
  39        /* Try JEDEC for unknown chip or LP */
  40        ret = nand_readid_op(chip, 0x40, id, sizeof(id));
  41        if (ret || strncmp(id, "JEDEC", sizeof(id)))
  42                return 0;
  43
  44        /* JEDEC chip: allocate a buffer to hold its parameter page */
  45        p = kzalloc(sizeof(*p), GFP_KERNEL);
  46        if (!p)
  47                return -ENOMEM;
  48
  49        if (!nand_has_exec_op(chip) ||
  50            !nand_read_data_op(chip, p, sizeof(*p), true, true))
  51                use_datain = true;
  52
  53        for (i = 0; i < JEDEC_PARAM_PAGES; i++) {
  54                if (!i)
  55                        ret = nand_read_param_page_op(chip, 0x40, p,
  56                                                      sizeof(*p));
  57                else if (use_datain)
  58                        ret = nand_read_data_op(chip, p, sizeof(*p), true,
  59                                                false);
  60                else
  61                        ret = nand_change_read_column_op(chip, sizeof(*p) * i,
  62                                                         p, sizeof(*p), true);
  63                if (ret) {
  64                        ret = 0;
  65                        goto free_jedec_param_page;
  66                }
  67
  68                crc = onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 510);
  69                if (crc == le16_to_cpu(p->crc))
  70                        break;
  71        }
  72
  73        if (i == JEDEC_PARAM_PAGES) {
  74                pr_err("Could not find valid JEDEC parameter page; aborting\n");
  75                goto free_jedec_param_page;
  76        }
  77
  78        /* Check version */
  79        val = le16_to_cpu(p->revision);
  80        if (val & (1 << 2))
  81                jedec_version = 10;
  82        else if (val & (1 << 1))
  83                jedec_version = 1; /* vendor specific version */
  84
  85        if (!jedec_version) {
  86                pr_info("unsupported JEDEC version: %d\n", val);
  87                goto free_jedec_param_page;
  88        }
  89
  90        sanitize_string(p->manufacturer, sizeof(p->manufacturer));
  91        sanitize_string(p->model, sizeof(p->model));
  92        chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
  93        if (!chip->parameters.model) {
  94                ret = -ENOMEM;
  95                goto free_jedec_param_page;
  96        }
  97
  98        memorg->pagesize = le32_to_cpu(p->byte_per_page);
  99        mtd->writesize = memorg->pagesize;
 100
 101        /* Please reference to the comment for nand_flash_detect_onfi. */
 102        memorg->pages_per_eraseblock =
 103                        1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
 104        mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
 105
 106        memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
 107        mtd->oobsize = memorg->oobsize;
 108
 109        memorg->luns_per_target = p->lun_count;
 110        memorg->planes_per_lun = 1 << p->multi_plane_addr;
 111
 112        /* Please reference to the comment for nand_flash_detect_onfi. */
 113        memorg->eraseblocks_per_lun =
 114                1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
 115        memorg->bits_per_cell = p->bits_per_cell;
 116
 117        if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
 118                chip->options |= NAND_BUSWIDTH_16;
 119
 120        /* ECC info */
 121        ecc = &p->ecc_info[0];
 122
 123        if (ecc->codeword_size >= 9) {
 124                struct nand_ecc_props requirements = {
 125                        .strength = ecc->ecc_bits,
 126                        .step_size = 1 << ecc->codeword_size,
 127                };
 128
 129                nanddev_set_ecc_requirements(base, &requirements);
 130        } else {
 131                pr_warn("Invalid codeword size\n");
 132        }
 133
 134        ret = 1;
 135
 136free_jedec_param_page:
 137        kfree(p);
 138        return ret;
 139}
 140