root/drivers/mtd/nand/raw/nand_jedec.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nand_jedec_detect

   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 /*
  20  * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
  21  */
  22 int nand_jedec_detect(struct nand_chip *chip)
  23 {
  24         struct mtd_info *mtd = nand_to_mtd(chip);
  25         struct nand_memory_organization *memorg;
  26         struct nand_jedec_params *p;
  27         struct jedec_ecc_info *ecc;
  28         int jedec_version = 0;
  29         char id[5];
  30         int i, val, ret;
  31 
  32         memorg = nanddev_get_memorg(&chip->base);
  33 
  34         /* Try JEDEC for unknown chip or LP */
  35         ret = nand_readid_op(chip, 0x40, id, sizeof(id));
  36         if (ret || strncmp(id, "JEDEC", sizeof(id)))
  37                 return 0;
  38 
  39         /* JEDEC chip: allocate a buffer to hold its parameter page */
  40         p = kzalloc(sizeof(*p), GFP_KERNEL);
  41         if (!p)
  42                 return -ENOMEM;
  43 
  44         ret = nand_read_param_page_op(chip, 0x40, NULL, 0);
  45         if (ret) {
  46                 ret = 0;
  47                 goto free_jedec_param_page;
  48         }
  49 
  50         for (i = 0; i < 3; i++) {
  51                 ret = nand_read_data_op(chip, p, sizeof(*p), true);
  52                 if (ret) {
  53                         ret = 0;
  54                         goto free_jedec_param_page;
  55                 }
  56 
  57                 if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
  58                                 le16_to_cpu(p->crc))
  59                         break;
  60         }
  61 
  62         if (i == 3) {
  63                 pr_err("Could not find valid JEDEC parameter page; aborting\n");
  64                 goto free_jedec_param_page;
  65         }
  66 
  67         /* Check version */
  68         val = le16_to_cpu(p->revision);
  69         if (val & (1 << 2))
  70                 jedec_version = 10;
  71         else if (val & (1 << 1))
  72                 jedec_version = 1; /* vendor specific version */
  73 
  74         if (!jedec_version) {
  75                 pr_info("unsupported JEDEC version: %d\n", val);
  76                 goto free_jedec_param_page;
  77         }
  78 
  79         sanitize_string(p->manufacturer, sizeof(p->manufacturer));
  80         sanitize_string(p->model, sizeof(p->model));
  81         chip->parameters.model = kstrdup(p->model, GFP_KERNEL);
  82         if (!chip->parameters.model) {
  83                 ret = -ENOMEM;
  84                 goto free_jedec_param_page;
  85         }
  86 
  87         memorg->pagesize = le32_to_cpu(p->byte_per_page);
  88         mtd->writesize = memorg->pagesize;
  89 
  90         /* Please reference to the comment for nand_flash_detect_onfi. */
  91         memorg->pages_per_eraseblock =
  92                         1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
  93         mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
  94 
  95         memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
  96         mtd->oobsize = memorg->oobsize;
  97 
  98         memorg->luns_per_target = p->lun_count;
  99         memorg->planes_per_lun = 1 << p->multi_plane_addr;
 100 
 101         /* Please reference to the comment for nand_flash_detect_onfi. */
 102         memorg->eraseblocks_per_lun =
 103                 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
 104         memorg->bits_per_cell = p->bits_per_cell;
 105 
 106         if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)
 107                 chip->options |= NAND_BUSWIDTH_16;
 108 
 109         /* ECC info */
 110         ecc = &p->ecc_info[0];
 111 
 112         if (ecc->codeword_size >= 9) {
 113                 chip->base.eccreq.strength = ecc->ecc_bits;
 114                 chip->base.eccreq.step_size = 1 << ecc->codeword_size;
 115         } else {
 116                 pr_warn("Invalid codeword size\n");
 117         }
 118 
 119         ret = 1;
 120 
 121 free_jedec_param_page:
 122         kfree(p);
 123         return ret;
 124 }

/* [<][>][^][v][top][bottom][index][help] */