Merge commit '90ba25b7cb78bd85c6af0b6429226c6616dedefa' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash
In preparation of re-sync of mtd stack, we opt to move the current stack slowly in order to have a more easy sync and test. We would like to prepare uboot to support no-jedec and no-onfi compliant nand so we need to clean up a bit the code we have now and upstream some of the support. In this series we expect no functional change Tested on: - imx6ull Micron MT29F2G08ABAGAH4 - imx8mn Macronix MX30LF4G18AC
This commit is contained in:
commit
538f6643b0
@ -14,7 +14,9 @@ obj-$(CONFIG_SPL_NAND_DENALI) += denali_spl.o
|
||||
obj-$(CONFIG_SPL_NAND_SIMPLE) += nand_spl_simple.o
|
||||
obj-$(CONFIG_SPL_NAND_LOAD) += nand_spl_load.o
|
||||
obj-$(CONFIG_SPL_NAND_ECC) += nand_ecc.o
|
||||
obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o
|
||||
obj-$(CONFIG_SPL_NAND_BASE) += nand_base.o nand_amd.o nand_hynix.o \
|
||||
nand_macronix.o nand_micron.o \
|
||||
nand_samsung.o nand_toshiba.o
|
||||
obj-$(CONFIG_SPL_NAND_IDENT) += nand_ids.o nand_timings.o
|
||||
obj-$(CONFIG_TPL_NAND_INIT) += nand.o
|
||||
ifeq ($(CONFIG_SPL_ENV_SUPPORT),y)
|
||||
@ -31,6 +33,12 @@ obj-y += nand_ids.o
|
||||
obj-y += nand_util.o
|
||||
obj-y += nand_ecc.o
|
||||
obj-y += nand_base.o
|
||||
obj-y += nand_amd.o
|
||||
obj-y += nand_hynix.o
|
||||
obj-y += nand_macronix.o
|
||||
obj-y += nand_micron.o
|
||||
obj-y += nand_samsung.o
|
||||
obj-y += nand_toshiba.o
|
||||
obj-y += nand_timings.o
|
||||
|
||||
endif # not spl
|
||||
|
@ -1186,7 +1186,7 @@ int mt7621_nfc_spl_post_init(struct mt7621_nfc *nfc)
|
||||
int nand_maf_id, nand_dev_id;
|
||||
struct nand_flash_dev *type;
|
||||
|
||||
type = nand_get_flash_type(&nand->mtd, nand, &nand_maf_id,
|
||||
type = nand_get_flash_type(nand, &nand_maf_id,
|
||||
&nand_dev_id, NULL);
|
||||
|
||||
if (IS_ERR(type))
|
||||
|
52
drivers/mtd/nand/raw/nand_amd.c
Normal file
52
drivers/mtd/nand/raw/nand_amd.c
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
static void amd_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_decode_ext_id(chip);
|
||||
|
||||
/*
|
||||
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
|
||||
* some Spansion chips have erasesize that conflicts with size
|
||||
* listed in nand_ids table.
|
||||
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
|
||||
*/
|
||||
if (chip->id.data[4] != 0x00 && chip->id.data[5] == 0x00 &&
|
||||
chip->id.data[6] == 0x00 && chip->id.data[7] == 0x00 &&
|
||||
mtd->writesize == 512) {
|
||||
mtd->erasesize = 128 * 1024;
|
||||
mtd->erasesize <<= ((chip->id.data[3] & 0x03) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int amd_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
if (nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops amd_nand_manuf_ops = {
|
||||
.detect = amd_nand_decode_id,
|
||||
.init = amd_nand_init,
|
||||
};
|
@ -3871,35 +3871,10 @@ ext_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
||||
|
||||
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
|
||||
feature);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure chip properties from Micron vendor-specific ONFI table
|
||||
*/
|
||||
static void nand_onfi_detect_micron(struct nand_chip *chip,
|
||||
struct nand_onfi_params *p)
|
||||
{
|
||||
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
|
||||
|
||||
if (le16_to_cpu(p->vendor_revision) < 1)
|
||||
return;
|
||||
|
||||
chip->read_retries = micron->read_retry_options;
|
||||
chip->setup_read_retry = nand_setup_read_retry_micron;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
|
||||
*/
|
||||
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int *busw)
|
||||
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
struct nand_onfi_params *p = &chip->onfi_params;
|
||||
char id[4];
|
||||
@ -3971,9 +3946,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->bits_per_cell = p->bits_per_cell;
|
||||
|
||||
if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
|
||||
*busw = NAND_BUSWIDTH_16;
|
||||
else
|
||||
*busw = 0;
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
if (p->ecc_bits != 0xff) {
|
||||
chip->ecc_strength_ds = p->ecc_bits;
|
||||
@ -3997,14 +3970,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
pr_warn("Could not retrieve ONFI ECC requirements\n");
|
||||
}
|
||||
|
||||
if (p->jedec_id == NAND_MFR_MICRON)
|
||||
nand_onfi_detect_micron(chip, p);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
int *busw)
|
||||
static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -4013,8 +3982,7 @@ 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)
|
||||
static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip)
|
||||
{
|
||||
struct nand_jedec_params *p = &chip->jedec_params;
|
||||
struct jedec_ecc_info *ecc;
|
||||
@ -4076,9 +4044,7 @@ static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->bits_per_cell = p->bits_per_cell;
|
||||
|
||||
if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
|
||||
*busw = NAND_BUSWIDTH_16;
|
||||
else
|
||||
*busw = 0;
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
|
||||
/* ECC info */
|
||||
ecc = &p->ecc_info[0];
|
||||
@ -4167,132 +4133,63 @@ static int nand_get_bits_per_cell(u8 cellinfo)
|
||||
* chip. The rest of the parameters must be decoded according to generic or
|
||||
* manufacturer-specific "extended ID" decoding patterns.
|
||||
*/
|
||||
static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
u8 id_data[8], int *busw)
|
||||
void nand_decode_ext_id(struct nand_chip *chip)
|
||||
{
|
||||
int extid, id_len;
|
||||
struct mtd_info *mtd = &chip->mtd;
|
||||
int extid;
|
||||
/* The 3rd id byte holds MLC / multichip data */
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
|
||||
/* The 4th id byte is the important one */
|
||||
extid = id_data[3];
|
||||
extid = chip->id.data[3];
|
||||
|
||||
id_len = nand_id_len(id_data, 8);
|
||||
/* Calc pagesize */
|
||||
mtd->writesize = 1024 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Calc oobsize */
|
||||
mtd->oobsize = (8 << (extid & 0x01)) *
|
||||
(mtd->writesize >> 9);
|
||||
extid >>= 2;
|
||||
/* Calc blocksize. Blocksize is multiples of 64KiB */
|
||||
mtd->erasesize = (64 * 1024) << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Get buswidth information */
|
||||
/* Get buswidth information */
|
||||
if (extid & 0x1)
|
||||
chip->options |= NAND_BUSWIDTH_16;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nand_decode_ext_id);
|
||||
|
||||
/*
|
||||
* Manufacturer detection. Only used when the NAND is not ONFI or JEDEC
|
||||
* compliant and does not have a full-id or legacy-id entry in the nand_ids
|
||||
* table.
|
||||
*/
|
||||
static void nand_manufacturer_detect(struct nand_chip *chip)
|
||||
{
|
||||
/*
|
||||
* Field definitions are in the following datasheets:
|
||||
* Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
|
||||
* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44)
|
||||
* Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22)
|
||||
*
|
||||
* Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung
|
||||
* ID to decide what to do.
|
||||
* Try manufacturer detection if available and use
|
||||
* nand_decode_ext_id() otherwise.
|
||||
*/
|
||||
if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG &&
|
||||
!nand_is_slc(chip) && id_data[5] != 0x00) {
|
||||
/* Calc pagesize */
|
||||
mtd->writesize = 2048 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Calc oobsize */
|
||||
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
|
||||
case 1:
|
||||
mtd->oobsize = 128;
|
||||
break;
|
||||
case 2:
|
||||
mtd->oobsize = 218;
|
||||
break;
|
||||
case 3:
|
||||
mtd->oobsize = 400;
|
||||
break;
|
||||
case 4:
|
||||
mtd->oobsize = 436;
|
||||
break;
|
||||
case 5:
|
||||
mtd->oobsize = 512;
|
||||
break;
|
||||
case 6:
|
||||
mtd->oobsize = 640;
|
||||
break;
|
||||
case 7:
|
||||
default: /* Other cases are "reserved" (unknown) */
|
||||
mtd->oobsize = 1024;
|
||||
break;
|
||||
}
|
||||
extid >>= 2;
|
||||
/* Calc blocksize */
|
||||
mtd->erasesize = (128 * 1024) <<
|
||||
(((extid >> 1) & 0x04) | (extid & 0x03));
|
||||
*busw = 0;
|
||||
} else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX &&
|
||||
!nand_is_slc(chip)) {
|
||||
unsigned int tmp;
|
||||
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
|
||||
chip->manufacturer.desc->ops->detect)
|
||||
chip->manufacturer.desc->ops->detect(chip);
|
||||
else
|
||||
nand_decode_ext_id(chip);
|
||||
}
|
||||
|
||||
/* Calc pagesize */
|
||||
mtd->writesize = 2048 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Calc oobsize */
|
||||
switch (((extid >> 2) & 0x04) | (extid & 0x03)) {
|
||||
case 0:
|
||||
mtd->oobsize = 128;
|
||||
break;
|
||||
case 1:
|
||||
mtd->oobsize = 224;
|
||||
break;
|
||||
case 2:
|
||||
mtd->oobsize = 448;
|
||||
break;
|
||||
case 3:
|
||||
mtd->oobsize = 64;
|
||||
break;
|
||||
case 4:
|
||||
mtd->oobsize = 32;
|
||||
break;
|
||||
case 5:
|
||||
mtd->oobsize = 16;
|
||||
break;
|
||||
default:
|
||||
mtd->oobsize = 640;
|
||||
break;
|
||||
}
|
||||
extid >>= 2;
|
||||
/* Calc blocksize */
|
||||
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;
|
||||
*busw = 0;
|
||||
} else {
|
||||
/* Calc pagesize */
|
||||
mtd->writesize = 1024 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Calc oobsize */
|
||||
mtd->oobsize = (8 << (extid & 0x01)) *
|
||||
(mtd->writesize >> 9);
|
||||
extid >>= 2;
|
||||
/* Calc blocksize. Blocksize is multiples of 64KiB */
|
||||
mtd->erasesize = (64 * 1024) << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
/* Get buswidth information */
|
||||
*busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
|
||||
/*
|
||||
* Manufacturer initialization. This function is called for all NANDs including
|
||||
* ONFI and JEDEC compliant ones.
|
||||
* Manufacturer drivers should put all their specific initialization code in
|
||||
* their ->init() hook.
|
||||
*/
|
||||
static int nand_manufacturer_init(struct nand_chip *chip)
|
||||
{
|
||||
if (!chip->manufacturer.desc || !chip->manufacturer.desc->ops ||
|
||||
!chip->manufacturer.desc->ops->init)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
|
||||
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
|
||||
* follows:
|
||||
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
|
||||
* 110b -> 24nm
|
||||
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
|
||||
*/
|
||||
if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
|
||||
nand_is_slc(chip) &&
|
||||
(id_data[5] & 0x7) == 0x6 /* 24nm */ &&
|
||||
!(id_data[4] & 0x80) /* !BENAND */) {
|
||||
mtd->oobsize = 32 * mtd->writesize >> 9;
|
||||
}
|
||||
|
||||
}
|
||||
return chip->manufacturer.desc->ops->init(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4300,32 +4197,16 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* decodes a matching ID table entry and assigns the MTD size parameters for
|
||||
* the chip.
|
||||
*/
|
||||
static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
struct nand_flash_dev *type, u8 id_data[8],
|
||||
int *busw)
|
||||
static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
|
||||
{
|
||||
int maf_id = id_data[0];
|
||||
struct mtd_info *mtd = &chip->mtd;
|
||||
|
||||
mtd->erasesize = type->erasesize;
|
||||
mtd->writesize = type->pagesize;
|
||||
mtd->oobsize = mtd->writesize / 32;
|
||||
*busw = type->options & NAND_BUSWIDTH_16;
|
||||
|
||||
/* All legacy ID NAND are small-page, SLC */
|
||||
chip->bits_per_cell = 1;
|
||||
|
||||
/*
|
||||
* Check for Spansion/AMD ID + repeating 5th, 6th byte since
|
||||
* some Spansion chips have erasesize that conflicts with size
|
||||
* listed in nand_ids table.
|
||||
* Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
|
||||
*/
|
||||
if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00
|
||||
&& id_data[6] == 0x00 && id_data[7] == 0x00
|
||||
&& mtd->writesize == 512) {
|
||||
mtd->erasesize = 128 * 1024;
|
||||
mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -4334,35 +4215,13 @@ static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
* page size, cell-type information).
|
||||
*/
|
||||
static void nand_decode_bbm_options(struct mtd_info *mtd,
|
||||
struct nand_chip *chip, u8 id_data[8])
|
||||
struct nand_chip *chip)
|
||||
{
|
||||
int maf_id = id_data[0];
|
||||
|
||||
/* Set the bad block position */
|
||||
if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16))
|
||||
chip->badblockpos = NAND_LARGE_BADBLOCK_POS;
|
||||
else
|
||||
chip->badblockpos = NAND_SMALL_BADBLOCK_POS;
|
||||
|
||||
/*
|
||||
* Bad block marker is stored in the last page of each block on Samsung
|
||||
* and Hynix MLC devices; stored in first two pages of each block on
|
||||
* Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba,
|
||||
* AMD/Spansion, and Macronix. All others scan only the first page.
|
||||
*/
|
||||
if (!nand_is_slc(chip) &&
|
||||
(maf_id == NAND_MFR_SAMSUNG ||
|
||||
maf_id == NAND_MFR_HYNIX))
|
||||
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
||||
else if ((nand_is_slc(chip) &&
|
||||
(maf_id == NAND_MFR_SAMSUNG ||
|
||||
maf_id == NAND_MFR_HYNIX ||
|
||||
maf_id == NAND_MFR_TOSHIBA ||
|
||||
maf_id == NAND_MFR_AMD ||
|
||||
maf_id == NAND_MFR_MACRONIX)) ||
|
||||
(mtd->writesize == 2048 &&
|
||||
maf_id == NAND_MFR_MICRON))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
}
|
||||
|
||||
static inline bool is_full_id_nand(struct nand_flash_dev *type)
|
||||
@ -4371,14 +4230,14 @@ static inline bool is_full_id_nand(struct nand_flash_dev *type)
|
||||
}
|
||||
|
||||
static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
struct nand_flash_dev *type, u8 *id_data, int *busw)
|
||||
struct nand_flash_dev *type)
|
||||
{
|
||||
if (!strncmp((char *)type->id, (char *)id_data, type->id_len)) {
|
||||
if (!strncmp((char *)type->id, (char *)chip->id.data, type->id_len)) {
|
||||
mtd->writesize = type->pagesize;
|
||||
mtd->erasesize = type->erasesize;
|
||||
mtd->oobsize = type->oobsize;
|
||||
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
|
||||
chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
|
||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||
chip->options |= type->options;
|
||||
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
|
||||
@ -4386,8 +4245,6 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
chip->onfi_timing_mode_default =
|
||||
type->onfi_timing_mode_default;
|
||||
|
||||
*busw = type->options & NAND_BUSWIDTH_16;
|
||||
|
||||
if (!mtd->name)
|
||||
mtd->name = type->name;
|
||||
|
||||
@ -4396,17 +4253,37 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* nand_get_manufacturer_desc - Get manufacturer information from the
|
||||
* manufacturer ID
|
||||
* @id: manufacturer ID
|
||||
*
|
||||
* Returns a nand_manufacturer_desc object if the manufacturer is defined
|
||||
* in the NAND manufacturers database, NULL otherwise.
|
||||
*/
|
||||
static const struct nand_manufacturers *nand_get_manufacturer_desc(u8 id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; nand_manuf_ids[i].id != 0x0; i++) {
|
||||
if (nand_manuf_ids[i].id == id)
|
||||
return &nand_manuf_ids[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the flash and manufacturer id and lookup if the type is supported.
|
||||
*/
|
||||
struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
int *maf_id, int *dev_id,
|
||||
struct nand_flash_dev *type)
|
||||
struct nand_flash_dev *nand_get_flash_type(struct nand_chip *chip, int *maf_id,
|
||||
int *dev_id,
|
||||
struct nand_flash_dev *type)
|
||||
{
|
||||
struct mtd_info *mtd = &chip->mtd;
|
||||
const struct nand_manufacturers *manufacturer_desc;
|
||||
int busw, ret;
|
||||
int maf_idx;
|
||||
u8 id_data[8];
|
||||
u8 *id_data = chip->id.data;
|
||||
|
||||
/*
|
||||
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
|
||||
@ -4446,12 +4323,33 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
chip->id.len = nand_id_len(id_data, ARRAY_SIZE(chip->id.data));
|
||||
|
||||
/* Try to identify manufacturer */
|
||||
manufacturer_desc = nand_get_manufacturer_desc(*maf_id);
|
||||
chip->manufacturer.desc = manufacturer_desc;
|
||||
|
||||
if (!type)
|
||||
type = nand_flash_ids;
|
||||
|
||||
/*
|
||||
* Save the NAND_BUSWIDTH_16 flag before letting auto-detection logic
|
||||
* override it.
|
||||
* This is required to make sure initial NAND bus width set by the
|
||||
* NAND controller driver is coherent with the real NAND bus width
|
||||
* (extracted by auto-detection code).
|
||||
*/
|
||||
busw = chip->options & NAND_BUSWIDTH_16;
|
||||
|
||||
/*
|
||||
* The flag is only set (never cleared), reset it to its default value
|
||||
* before starting auto-detection.
|
||||
*/
|
||||
chip->options &= ~NAND_BUSWIDTH_16;
|
||||
|
||||
for (; type->name != NULL; type++) {
|
||||
if (is_full_id_nand(type)) {
|
||||
if (find_full_id_nand(mtd, chip, type, id_data, &busw))
|
||||
if (find_full_id_nand(mtd, chip, type))
|
||||
goto ident_done;
|
||||
} else if (*dev_id == type->dev_id) {
|
||||
break;
|
||||
@ -4461,11 +4359,11 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
chip->onfi_version = 0;
|
||||
if (!type->name || !type->pagesize) {
|
||||
/* Check if the chip is ONFI compliant */
|
||||
if (nand_flash_detect_onfi(mtd, chip, &busw))
|
||||
if (nand_flash_detect_onfi(mtd, chip))
|
||||
goto ident_done;
|
||||
|
||||
/* Check if the chip is JEDEC compliant */
|
||||
if (nand_flash_detect_jedec(mtd, chip, &busw))
|
||||
if (nand_flash_detect_jedec(mtd, chip))
|
||||
goto ident_done;
|
||||
}
|
||||
|
||||
@ -4478,28 +4376,16 @@ struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
chip->chipsize = (uint64_t)type->chipsize << 20;
|
||||
|
||||
if (!type->pagesize) {
|
||||
/* Decode parameters from extended ID */
|
||||
nand_decode_ext_id(mtd, chip, id_data, &busw);
|
||||
nand_manufacturer_detect(chip);
|
||||
} else {
|
||||
nand_decode_id(mtd, chip, type, id_data, &busw);
|
||||
nand_decode_id(chip, type);
|
||||
}
|
||||
|
||||
/* Get chip options */
|
||||
chip->options |= type->options;
|
||||
|
||||
/*
|
||||
* Check if chip is not a Samsung device. Do not clear the
|
||||
* options for chips which do not have an extended id.
|
||||
*/
|
||||
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
|
||||
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
|
||||
ident_done:
|
||||
|
||||
/* Try to identify manufacturer */
|
||||
for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
|
||||
if (nand_manuf_ids[maf_idx].id == *maf_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (chip->options & NAND_BUSWIDTH_AUTO) {
|
||||
WARN_ON(chip->options & NAND_BUSWIDTH_16);
|
||||
chip->options |= busw;
|
||||
@ -4511,14 +4397,14 @@ ident_done:
|
||||
*/
|
||||
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
||||
*maf_id, *dev_id);
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
|
||||
pr_info("%s %s\n", manufacturer_desc->name, mtd->name);
|
||||
pr_warn("bus width %d instead %d bit\n",
|
||||
(chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
|
||||
busw ? 16 : 8);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
nand_decode_bbm_options(mtd, chip, id_data);
|
||||
nand_decode_bbm_options(mtd, chip);
|
||||
|
||||
/* Calculate the address shift from the page size */
|
||||
chip->page_shift = ffs(mtd->writesize) - 1;
|
||||
@ -4544,28 +4430,30 @@ ident_done:
|
||||
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
|
||||
chip->cmdfunc = nand_command_lp;
|
||||
|
||||
ret = nand_manufacturer_init(chip);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
|
||||
*maf_id, *dev_id);
|
||||
|
||||
#ifdef CONFIG_SYS_NAND_ONFI_DETECTION
|
||||
if (chip->onfi_version)
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
chip->onfi_params.model);
|
||||
pr_info("%s %s\n", manufacturer_desc->name,
|
||||
chip->onfi_params.model);
|
||||
else if (chip->jedec_version)
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
chip->jedec_params.model);
|
||||
pr_info("%s %s\n", manufacturer_desc->name,
|
||||
chip->jedec_params.model);
|
||||
else
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
type->name);
|
||||
pr_info("%s %s\n", manufacturer_desc->name, type->name);
|
||||
#else
|
||||
if (chip->jedec_version)
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
chip->jedec_params.model);
|
||||
pr_info("%s %s\n", manufacturer_desc->name,
|
||||
chip->jedec_params.model);
|
||||
else
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
type->name);
|
||||
pr_info("%s %s\n", manufacturer_desc->name, type->name);
|
||||
|
||||
pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
|
||||
pr_info("%s %s\n", manufacturer_desc->name,
|
||||
type->name);
|
||||
#endif
|
||||
|
||||
@ -4672,7 +4560,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
|
||||
nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
|
||||
|
||||
/* Read the flash type */
|
||||
type = nand_get_flash_type(mtd, chip, &nand_maf_id,
|
||||
type = nand_get_flash_type(chip, &nand_maf_id,
|
||||
&nand_dev_id, table);
|
||||
|
||||
if (IS_ERR(type)) {
|
||||
|
85
drivers/mtd/nand/raw/nand_hynix.c
Normal file
85
drivers/mtd/nand/raw/nand_hynix.c
Normal file
@ -0,0 +1,85 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
static void hynix_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* 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];
|
||||
|
||||
/* Extract pagesize */
|
||||
mtd->writesize = 2048 << (extid & 0x03);
|
||||
extid >>= 2;
|
||||
|
||||
/* Extract oobsize */
|
||||
switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
|
||||
case 0:
|
||||
mtd->oobsize = 128;
|
||||
break;
|
||||
case 1:
|
||||
mtd->oobsize = 224;
|
||||
break;
|
||||
case 2:
|
||||
mtd->oobsize = 448;
|
||||
break;
|
||||
case 3:
|
||||
mtd->oobsize = 64;
|
||||
break;
|
||||
case 4:
|
||||
mtd->oobsize = 32;
|
||||
break;
|
||||
case 5:
|
||||
mtd->oobsize = 16;
|
||||
break;
|
||||
default:
|
||||
mtd->oobsize = 640;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
} else {
|
||||
nand_decode_ext_id(chip);
|
||||
}
|
||||
}
|
||||
|
||||
static int hynix_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
if (!nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
||||
else
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops hynix_nand_manuf_ops = {
|
||||
.detect = hynix_nand_decode_id,
|
||||
.init = hynix_nand_init,
|
||||
};
|
@ -10,7 +10,7 @@
|
||||
#include <linux/mtd/rawnand.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
|
||||
#define LP_OPTIONS 0
|
||||
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
|
||||
|
||||
#define SP_OPTIONS NAND_NEED_READRDY
|
||||
@ -24,16 +24,6 @@
|
||||
* extended chip ID.
|
||||
*/
|
||||
struct nand_flash_dev nand_flash_ids[] = {
|
||||
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
|
||||
LEGACY_ID_NAND("NAND 1MiB 5V 8-bit", 0x6e, 1, SZ_4K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 2MiB 5V 8-bit", 0x64, 2, SZ_4K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xe8, 1, SZ_4K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 1MiB 3,3V 8-bit", 0xec, 1, SZ_4K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 2MiB 3,3V 8-bit", 0xea, 2, SZ_4K, SP_OPTIONS),
|
||||
LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xd5, 4, SZ_8K, SP_OPTIONS),
|
||||
|
||||
LEGACY_ID_NAND("NAND 8MiB 3,3V 8-bit", 0xe6, 8, SZ_8K, SP_OPTIONS),
|
||||
#endif
|
||||
/*
|
||||
* Some incompatible NAND chips share device ID's and so must be
|
||||
* listed by full ID. We list them first so that we can easily identify
|
||||
@ -188,16 +178,16 @@ struct nand_flash_dev nand_flash_ids[] = {
|
||||
|
||||
/* Manufacturer IDs */
|
||||
struct nand_manufacturers nand_manuf_ids[] = {
|
||||
{NAND_MFR_TOSHIBA, "Toshiba"},
|
||||
{NAND_MFR_SAMSUNG, "Samsung"},
|
||||
{NAND_MFR_TOSHIBA, "Toshiba", &toshiba_nand_manuf_ops},
|
||||
{NAND_MFR_SAMSUNG, "Samsung", &samsung_nand_manuf_ops},
|
||||
{NAND_MFR_FUJITSU, "Fujitsu"},
|
||||
{NAND_MFR_NATIONAL, "National"},
|
||||
{NAND_MFR_RENESAS, "Renesas"},
|
||||
{NAND_MFR_STMICRO, "ST Micro"},
|
||||
{NAND_MFR_HYNIX, "Hynix"},
|
||||
{NAND_MFR_MICRON, "Micron"},
|
||||
{NAND_MFR_AMD, "AMD/Spansion"},
|
||||
{NAND_MFR_MACRONIX, "Macronix"},
|
||||
{NAND_MFR_HYNIX, "Hynix", &hynix_nand_manuf_ops},
|
||||
{NAND_MFR_MICRON, "Micron", µn_nand_manuf_ops},
|
||||
{NAND_MFR_AMD, "AMD/Spansion", &amd_nand_manuf_ops},
|
||||
{NAND_MFR_MACRONIX, "Macronix", ¯onix_nand_manuf_ops},
|
||||
{NAND_MFR_EON, "Eon"},
|
||||
{NAND_MFR_SANDISK, "SanDisk"},
|
||||
{NAND_MFR_INTEL, "Intel"},
|
||||
|
31
drivers/mtd/nand/raw/nand_macronix.c
Normal file
31
drivers/mtd/nand/raw/nand_macronix.c
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
static int macronix_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
if (nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops macronix_nand_manuf_ops = {
|
||||
.init = macronix_nand_init,
|
||||
};
|
87
drivers/mtd/nand/raw/nand_micron.c
Normal file
87
drivers/mtd/nand/raw/nand_micron.c
Normal file
@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
struct nand_onfi_vendor_micron {
|
||||
u8 two_plane_read;
|
||||
u8 read_cache;
|
||||
u8 read_unique_id;
|
||||
u8 dq_imped;
|
||||
u8 dq_imped_num_settings;
|
||||
u8 dq_imped_feat_addr;
|
||||
u8 rb_pulldown_strength;
|
||||
u8 rb_pulldown_strength_feat_addr;
|
||||
u8 rb_pulldown_strength_num_settings;
|
||||
u8 otp_mode;
|
||||
u8 otp_page_start;
|
||||
u8 otp_data_prot_addr;
|
||||
u8 otp_num_pages;
|
||||
u8 otp_feat_addr;
|
||||
u8 read_retry_options;
|
||||
u8 reserved[72];
|
||||
u8 param_revision;
|
||||
} __packed;
|
||||
|
||||
static int micron_nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
|
||||
{
|
||||
struct nand_chip *chip = mtd_to_nand(mtd);
|
||||
u8 feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
|
||||
|
||||
return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
|
||||
feature);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure chip properties from Micron vendor-specific ONFI table
|
||||
*/
|
||||
static int micron_nand_onfi_init(struct nand_chip *chip)
|
||||
{
|
||||
struct nand_onfi_params *p = &chip->onfi_params;
|
||||
struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
|
||||
|
||||
if (!chip->onfi_version)
|
||||
return 0;
|
||||
|
||||
if (le16_to_cpu(p->vendor_revision) < 1)
|
||||
return 0;
|
||||
|
||||
chip->read_retries = micron->read_retry_options;
|
||||
chip->setup_read_retry = micron_nand_setup_read_retry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int micron_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
int ret;
|
||||
|
||||
ret = micron_nand_onfi_init(chip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mtd->writesize == 2048)
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops micron_nand_manuf_ops = {
|
||||
.init = micron_nand_init,
|
||||
};
|
90
drivers/mtd/nand/raw/nand_samsung.c
Normal file
90
drivers/mtd/nand/raw/nand_samsung.c
Normal file
@ -0,0 +1,90 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
static void samsung_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
|
||||
if (chip->id.len == 6 && !nand_is_slc(chip) &&
|
||||
chip->id.data[5] != 0x00) {
|
||||
u8 extid = chip->id.data[3];
|
||||
|
||||
/* Get pagesize */
|
||||
mtd->writesize = 2048 << (extid & 0x03);
|
||||
|
||||
extid >>= 2;
|
||||
|
||||
/* Get oobsize */
|
||||
switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
|
||||
case 1:
|
||||
mtd->oobsize = 128;
|
||||
break;
|
||||
case 2:
|
||||
mtd->oobsize = 218;
|
||||
break;
|
||||
case 3:
|
||||
mtd->oobsize = 400;
|
||||
break;
|
||||
case 4:
|
||||
mtd->oobsize = 436;
|
||||
break;
|
||||
case 5:
|
||||
mtd->oobsize = 512;
|
||||
break;
|
||||
case 6:
|
||||
mtd->oobsize = 640;
|
||||
break;
|
||||
case 7:
|
||||
default: /* Other cases are "reserved" (unknown) */
|
||||
WARN(1, "Invalid OOB size value");
|
||||
mtd->oobsize = 1024;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get blocksize */
|
||||
extid >>= 2;
|
||||
mtd->erasesize = (128 * 1024) <<
|
||||
(((extid >> 1) & 0x04) | (extid & 0x03));
|
||||
} else {
|
||||
nand_decode_ext_id(chip);
|
||||
}
|
||||
}
|
||||
|
||||
static int samsung_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
if (mtd->writesize > 512)
|
||||
chip->options |= NAND_SAMSUNG_LP_OPTIONS;
|
||||
|
||||
if (!nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCANLASTPAGE;
|
||||
else
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops samsung_nand_manuf_ops = {
|
||||
.detect = samsung_nand_decode_id,
|
||||
.init = samsung_nand_init,
|
||||
};
|
79
drivers/mtd/nand/raw/nand_toshiba.c
Normal file
79
drivers/mtd/nand/raw/nand_toshiba.c
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2017 Free Electrons
|
||||
* Copyright (C) 2017 NextThing Co
|
||||
*
|
||||
* Author: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/bug.h>
|
||||
#include <linux/mtd/rawnand.h>
|
||||
|
||||
static void toshiba_nand_decode_id(struct nand_chip *chip)
|
||||
{
|
||||
struct mtd_info *mtd = nand_to_mtd(chip);
|
||||
|
||||
nand_decode_ext_id(chip);
|
||||
|
||||
/*
|
||||
* Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
|
||||
* 512B page. For Toshiba SLC, we decode the 5th/6th byte as
|
||||
* follows:
|
||||
* - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
|
||||
* 110b -> 24nm
|
||||
* - ID byte 5, bit[7]: 1 -> BENAND, 0 -> raw SLC
|
||||
*/
|
||||
if (chip->id.len >= 6 && nand_is_slc(chip) &&
|
||||
(chip->id.data[5] & 0x7) == 0x6 /* 24nm */ &&
|
||||
!(chip->id.data[4] & 0x80) /* !BENAND */)
|
||||
mtd->oobsize = 32 * mtd->writesize >> 9;
|
||||
|
||||
/*
|
||||
* Extract ECC requirements from 6th id byte.
|
||||
* For Toshiba SLC, ecc requrements are as follows:
|
||||
* - 43nm: 1 bit ECC for each 512Byte is required.
|
||||
* - 32nm: 4 bit ECC for each 512Byte is required.
|
||||
* - 24nm: 8 bit ECC for each 512Byte is required.
|
||||
*/
|
||||
if (chip->id.len >= 6 && nand_is_slc(chip)) {
|
||||
chip->ecc_step_ds = 512;
|
||||
switch (chip->id.data[5] & 0x7) {
|
||||
case 0x4:
|
||||
chip->ecc_strength_ds = 1;
|
||||
break;
|
||||
case 0x5:
|
||||
chip->ecc_strength_ds = 4;
|
||||
break;
|
||||
case 0x6:
|
||||
chip->ecc_strength_ds = 8;
|
||||
break;
|
||||
default:
|
||||
WARN(1, "Could not get ECC info");
|
||||
chip->ecc_step_ds = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int toshiba_nand_init(struct nand_chip *chip)
|
||||
{
|
||||
if (nand_is_slc(chip))
|
||||
chip->bbt_options |= NAND_BBT_SCAN2NDPAGE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nand_manufacturer_ops toshiba_nand_manuf_ops = {
|
||||
.detect = toshiba_nand_decode_id,
|
||||
.init = toshiba_nand_init,
|
||||
};
|
@ -29,8 +29,7 @@ struct nand_flash_dev;
|
||||
struct device_node;
|
||||
|
||||
/* Get the flash and manufacturer id and lookup if the type is supported. */
|
||||
struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
|
||||
struct nand_chip *chip,
|
||||
struct nand_flash_dev *nand_get_flash_type(struct nand_chip *chip,
|
||||
int *maf_id, int *dev_id,
|
||||
struct nand_flash_dev *type);
|
||||
|
||||
@ -389,26 +388,6 @@ struct onfi_ext_param_page {
|
||||
*/
|
||||
} __packed;
|
||||
|
||||
struct nand_onfi_vendor_micron {
|
||||
u8 two_plane_read;
|
||||
u8 read_cache;
|
||||
u8 read_unique_id;
|
||||
u8 dq_imped;
|
||||
u8 dq_imped_num_settings;
|
||||
u8 dq_imped_feat_addr;
|
||||
u8 rb_pulldown_strength;
|
||||
u8 rb_pulldown_strength_feat_addr;
|
||||
u8 rb_pulldown_strength_num_settings;
|
||||
u8 otp_mode;
|
||||
u8 otp_page_start;
|
||||
u8 otp_data_prot_addr;
|
||||
u8 otp_num_pages;
|
||||
u8 otp_feat_addr;
|
||||
u8 read_retry_options;
|
||||
u8 reserved[72];
|
||||
u8 param_revision;
|
||||
} __packed;
|
||||
|
||||
struct jedec_ecc_info {
|
||||
u8 ecc_bits;
|
||||
u8 codeword_size;
|
||||
@ -507,6 +486,19 @@ static inline void nand_hw_control_init(struct nand_hw_control *nfc)
|
||||
init_waitqueue_head(&nfc->wq);
|
||||
}
|
||||
|
||||
/* The maximum expected count of bytes in the NAND ID sequence */
|
||||
#define NAND_MAX_ID_LEN 8
|
||||
|
||||
/**
|
||||
* struct nand_id - NAND id structure
|
||||
* @data: buffer containing the id bytes.
|
||||
* @len: ID length.
|
||||
*/
|
||||
struct nand_id {
|
||||
u8 data[NAND_MAX_ID_LEN];
|
||||
int len;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_ecc_step_info - ECC step information of ECC engine
|
||||
* @stepsize: data bytes per ECC step
|
||||
@ -783,6 +775,17 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
|
||||
return &conf->timings.sdr;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct nand_manufacturer_ops - NAND Manufacturer operations
|
||||
* @detect: detect the NAND memory organization and capabilities
|
||||
* @init: initialize all vendor specific fields (like the ->read_retry()
|
||||
* implementation) if any.
|
||||
*/
|
||||
struct nand_manufacturer_ops {
|
||||
void (*detect)(struct nand_chip *chip);
|
||||
int (*init)(struct nand_chip *chip);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct nand_chip - NAND Private Flash Chip Data
|
||||
* @mtd: MTD device registered to the MTD framework
|
||||
@ -884,10 +887,13 @@ nand_get_sdr_timings(const struct nand_data_interface *conf)
|
||||
* devices.
|
||||
* @priv: [OPTIONAL] pointer to private chip data
|
||||
* @write_page: [REPLACEABLE] High-level page write function
|
||||
* @manufacturer: [INTERN] Contains manufacturer information
|
||||
*/
|
||||
|
||||
struct nand_chip {
|
||||
struct mtd_info mtd;
|
||||
struct nand_id id;
|
||||
|
||||
void __iomem *IO_ADDR_R;
|
||||
void __iomem *IO_ADDR_W;
|
||||
|
||||
@ -968,6 +974,11 @@ struct nand_chip {
|
||||
struct nand_bbt_descr *badblock_pattern;
|
||||
|
||||
void *priv;
|
||||
|
||||
struct {
|
||||
const struct nand_manufacturers *desc;
|
||||
void *priv;
|
||||
} manufacturer;
|
||||
};
|
||||
|
||||
static inline void nand_set_flash_node(struct nand_chip *chip,
|
||||
@ -1001,6 +1012,17 @@ static inline void nand_set_controller_data(struct nand_chip *chip, void *priv)
|
||||
chip->priv = priv;
|
||||
}
|
||||
|
||||
static inline void nand_set_manufacturer_data(struct nand_chip *chip,
|
||||
void *priv)
|
||||
{
|
||||
chip->manufacturer.priv = priv;
|
||||
}
|
||||
|
||||
static inline void *nand_get_manufacturer_data(struct nand_chip *chip)
|
||||
{
|
||||
return chip->manufacturer.priv;
|
||||
}
|
||||
|
||||
/*
|
||||
* NAND Flash Manufacturer ID Codes
|
||||
*/
|
||||
@ -1105,15 +1127,24 @@ struct nand_flash_dev {
|
||||
* struct nand_manufacturers - NAND Flash Manufacturer ID Structure
|
||||
* @name: Manufacturer name
|
||||
* @id: manufacturer ID code of device.
|
||||
* @ops: manufacturer operations
|
||||
*/
|
||||
struct nand_manufacturers {
|
||||
int id;
|
||||
char *name;
|
||||
const struct nand_manufacturer_ops *ops;
|
||||
};
|
||||
|
||||
extern struct nand_flash_dev nand_flash_ids[];
|
||||
extern struct nand_manufacturers nand_manuf_ids[];
|
||||
|
||||
extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops samsung_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops hynix_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops micron_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops amd_nand_manuf_ops;
|
||||
extern const struct nand_manufacturer_ops macronix_nand_manuf_ops;
|
||||
|
||||
int nand_default_bbt(struct mtd_info *mtd);
|
||||
int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
|
||||
int nand_isreserved_bbt(struct mtd_info *mtd, loff_t offs);
|
||||
@ -1330,4 +1361,7 @@ int nand_read_data_op(struct nand_chip *chip, void *buf, unsigned int len,
|
||||
int nand_write_data_op(struct nand_chip *chip, const void *buf,
|
||||
unsigned int len, bool force_8bit);
|
||||
|
||||
/* Default extended ID decoding function */
|
||||
void nand_decode_ext_id(struct nand_chip *chip);
|
||||
|
||||
#endif /* __LINUX_MTD_RAWNAND_H */
|
||||
|
Loading…
Reference in New Issue
Block a user