mtd: rawnand: Fill memorg during detection

If we want to use the generic NAND layer, we need to have the memorg
struct appropriately filled. Patch the detection code to fill this
struct.

Signed-off-by: Boris Brezillon <bbrezillon@kernel.org>
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
This commit is contained in:
Boris Brezillon 2018-10-25 17:10:37 +02:00 committed by Miquel Raynal
parent 3020e30af6
commit 629a442cad
11 changed files with 177 additions and 46 deletions

View file

@ -1096,6 +1096,9 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
{
struct nand_chip *chip = &denali->nand;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
/*
* Support for multi device:
@ -1125,6 +1128,8 @@ static int denali_multidev_fixup(struct denali_nand_info *denali)
}
/* 2 chips in parallel */
memorg->pagesize <<= 1;
memorg->oobsize <<= 1;
mtd->size <<= 1;
mtd->erasesize <<= 1;
mtd->writesize <<= 1;

View file

@ -1028,6 +1028,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
{
struct nand_chip *this = mtd_to_nand(mtd);
struct doc_priv *doc = nand_get_controller_data(this);
struct nand_memory_organization *memorg;
int ret = 0;
u_char *buf;
struct NFTLMediaHeader *mh;
@ -1036,6 +1037,8 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
unsigned blocks, maxblocks;
int offs, numheaders;
memorg = nanddev_get_memorg(&this->base);
buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
return 0;
@ -1082,6 +1085,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
implementation of the NAND layer. */
if (mh->UnitSizeFactor != 0xff) {
this->bbt_erase_shift += (0xff - mh->UnitSizeFactor);
memorg->pages_per_eraseblock <<= (0xff - mh->UnitSizeFactor);
mtd->erasesize <<= (0xff - mh->UnitSizeFactor);
pr_info("Setting virtual erase size to %d\n", mtd->erasesize);
blocks = mtd->size >> this->bbt_erase_shift;

View file

@ -313,8 +313,11 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
uint32_t ctrl;
struct nand_chip *chip = &nand->chip;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
u8 id[2];
memorg = nanddev_get_memorg(&chip->base);
/* Request I/O resource. */
sprintf(res_name, "bank%d", bank);
ret = jz_nand_ioremap_resource(pdev, res_name,
@ -352,6 +355,7 @@ static int jz_nand_detect_bank(struct platform_device *pdev,
/* Update size of the MTD. */
chip->numchips++;
memorg->ntargets++;
mtd->size += chip->chipsize;
}

View file

@ -20,6 +20,9 @@
static void amd_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
nand_decode_ext_id(chip);
@ -31,9 +34,11 @@ static void amd_nand_decode_id(struct nand_chip *chip)
*/
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);
memorg->pagesize == 512) {
memorg->pages_per_eraseblock = 256;
memorg->pages_per_eraseblock <<= ((chip->id.data[3] & 0x03) << 1);
mtd->erasesize = memorg->pages_per_eraseblock *
memorg->pagesize;
}
}

View file

@ -4485,21 +4485,30 @@ static int nand_get_bits_per_cell(u8 cellinfo)
*/
void nand_decode_ext_id(struct nand_chip *chip)
{
struct nand_memory_organization *memorg;
struct mtd_info *mtd = nand_to_mtd(chip);
int extid;
u8 *id_data = chip->id.data;
memorg = nanddev_get_memorg(&chip->base);
/* The 3rd id byte holds MLC / multichip data */
memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
/* The 4th id byte is the important one */
extid = id_data[3];
/* Calc pagesize */
mtd->writesize = 1024 << (extid & 0x03);
memorg->pagesize = 1024 << (extid & 0x03);
mtd->writesize = memorg->pagesize;
extid >>= 2;
/* Calc oobsize */
mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
memorg->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
mtd->oobsize = memorg->oobsize;
extid >>= 2;
/* Calc blocksize. Blocksize is multiples of 64KiB */
memorg->pages_per_eraseblock = ((64 * 1024) << (extid & 0x03)) /
memorg->pagesize;
mtd->erasesize = (64 * 1024) << (extid & 0x03);
extid >>= 2;
/* Get buswidth information */
@ -4516,12 +4525,19 @@ EXPORT_SYMBOL_GPL(nand_decode_ext_id);
static void nand_decode_id(struct nand_chip *chip, struct nand_flash_dev *type)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
memorg->pages_per_eraseblock = type->erasesize / type->pagesize;
mtd->erasesize = type->erasesize;
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
memorg->pagesize = type->pagesize;
mtd->writesize = memorg->pagesize;
memorg->oobsize = memorg->pagesize / 32;
mtd->oobsize = memorg->oobsize;
/* All legacy ID NAND are small-page, SLC */
memorg->bits_per_cell = 1;
chip->bits_per_cell = 1;
}
@ -4550,15 +4566,27 @@ static bool find_full_id_nand(struct nand_chip *chip,
struct nand_flash_dev *type)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
u8 *id_data = chip->id.data;
if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
memorg = nanddev_get_memorg(&chip->base);
if (!strncmp(type->id, id_data, type->id_len)) {
memorg->pagesize = type->pagesize;
mtd->writesize = memorg->pagesize;
memorg->pages_per_eraseblock = type->erasesize /
type->pagesize;
mtd->erasesize = type->erasesize;
memorg->oobsize = type->oobsize;
mtd->oobsize = memorg->oobsize;
memorg->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->bits_per_cell = nand_get_bits_per_cell(id_data[2]);
chip->chipsize = (uint64_t)type->chipsize << 20;
memorg->eraseblocks_per_lun =
DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20,
memorg->pagesize *
memorg->pages_per_eraseblock);
chip->options |= type->options;
chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
chip->ecc_step_ds = NAND_ECC_STEP(type);
@ -4587,7 +4615,12 @@ static void nand_manufacturer_detect(struct nand_chip *chip)
*/
if (chip->manufacturer.desc && chip->manufacturer.desc->ops &&
chip->manufacturer.desc->ops->detect) {
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
/* The 3rd id byte holds MLC / multichip data */
memorg->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
chip->bits_per_cell = nand_get_bits_per_cell(chip->id.data[2]);
chip->manufacturer.desc->ops->detect(chip);
} else {
@ -4637,10 +4670,20 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
{
const struct nand_manufacturer *manufacturer;
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
int busw, ret;
u8 *id_data = chip->id.data;
u8 maf_id, dev_id;
/*
* Let's start by initializing memorg fields that might be left
* unassigned by the ID-based detection logic.
*/
memorg = nanddev_get_memorg(&chip->base);
memorg->planes_per_lun = 1;
memorg->luns_per_target = 1;
memorg->ntargets = 1;
/*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up.
@ -4745,6 +4788,11 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type)
/* Get chip options */
chip->options |= type->options;
memorg->eraseblocks_per_lun =
DIV_ROUND_DOWN_ULL((u64)type->chipsize << 20,
memorg->pagesize *
memorg->pages_per_eraseblock);
ident_done:
if (!mtd->name)
mtd->name = chip->parameters.model;
@ -4971,10 +5019,13 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
struct nand_flash_dev *table)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
int nand_maf_id, nand_dev_id;
unsigned int i;
int ret;
memorg = nanddev_get_memorg(&chip->base);
/* Assume all dies are deselected when we enter nand_scan_ident(). */
chip->cur_cs = -1;
@ -5042,6 +5093,7 @@ static int nand_scan_ident(struct nand_chip *chip, unsigned int maxchips,
pr_info("%d chips detected\n", i);
/* Store the number of chips and calc total size for mtd */
memorg->ntargets = i;
chip->numchips = i;
mtd->size = i * chip->chipsize;

View file

@ -418,24 +418,27 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
bool valid_jedecid)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
u8 oobsize;
memorg = nanddev_get_memorg(&chip->base);
oobsize = ((chip->id.data[3] >> 2) & 0x3) |
((chip->id.data[3] >> 4) & 0x4);
if (valid_jedecid) {
switch (oobsize) {
case 0:
mtd->oobsize = 2048;
memorg->oobsize = 2048;
break;
case 1:
mtd->oobsize = 1664;
memorg->oobsize = 1664;
break;
case 2:
mtd->oobsize = 1024;
memorg->oobsize = 1024;
break;
case 3:
mtd->oobsize = 640;
memorg->oobsize = 640;
break;
default:
/*
@ -450,25 +453,25 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
} else {
switch (oobsize) {
case 0:
mtd->oobsize = 128;
memorg->oobsize = 128;
break;
case 1:
mtd->oobsize = 224;
memorg->oobsize = 224;
break;
case 2:
mtd->oobsize = 448;
memorg->oobsize = 448;
break;
case 3:
mtd->oobsize = 64;
memorg->oobsize = 64;
break;
case 4:
mtd->oobsize = 32;
memorg->oobsize = 32;
break;
case 5:
mtd->oobsize = 16;
memorg->oobsize = 16;
break;
case 6:
mtd->oobsize = 640;
memorg->oobsize = 640;
break;
default:
/*
@ -492,8 +495,10 @@ static void hynix_nand_extract_oobsize(struct nand_chip *chip,
* the actual OOB size for this chip is: 640 * 16k / 8k).
*/
if (chip->id.data[1] == 0xde)
mtd->oobsize *= mtd->writesize / SZ_8K;
memorg->oobsize *= memorg->pagesize / SZ_8K;
}
mtd->oobsize = memorg->oobsize;
}
static void hynix_nand_extract_ecc_requirements(struct nand_chip *chip,
@ -609,9 +614,12 @@ static void hynix_nand_extract_scrambling_requirements(struct nand_chip *chip,
static void hynix_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
bool valid_jedecid;
u8 tmp;
memorg = nanddev_get_memorg(&chip->base);
/*
* Exclude all SLC NANDs from this advanced detection scheme.
* According to the ranges defined in several datasheets, it might
@ -625,7 +633,8 @@ static void hynix_nand_decode_id(struct nand_chip *chip)
}
/* Extract pagesize */
mtd->writesize = 2048 << (chip->id.data[3] & 0x03);
memorg->pagesize = 2048 << (chip->id.data[3] & 0x03);
mtd->writesize = memorg->pagesize;
tmp = (chip->id.data[3] >> 4) & 0x3;
/*
@ -635,12 +644,19 @@ static void hynix_nand_decode_id(struct nand_chip *chip)
* The only exception is when ID[3][4:5] == 3 and ID[3][7] == 0, in
* this case the erasesize is set to 768KiB.
*/
if (chip->id.data[3] & 0x80)
if (chip->id.data[3] & 0x80) {
memorg->pages_per_eraseblock = (SZ_1M << tmp) /
memorg->pagesize;
mtd->erasesize = SZ_1M << tmp;
else if (tmp == 3)
} else if (tmp == 3) {
memorg->pages_per_eraseblock = (SZ_512K + SZ_256K) /
memorg->pagesize;
mtd->erasesize = SZ_512K + SZ_256K;
else
} else {
memorg->pages_per_eraseblock = (SZ_128K << tmp) /
memorg->pagesize;
mtd->erasesize = SZ_128K << tmp;
}
/*
* Modern Toggle DDR NANDs have a valid JEDECID even though they are

View file

@ -22,12 +22,15 @@
int nand_jedec_detect(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
struct nand_jedec_params *p;
struct jedec_ecc_info *ecc;
int jedec_version = 0;
char id[5];
int i, val, ret;
memorg = nanddev_get_memorg(&chip->base);
/* Try JEDEC for unknown chip or LP */
ret = nand_readid_op(chip, 0x40, id, sizeof(id));
if (ret || strncmp(id, "JEDEC", sizeof(id)))
@ -81,17 +84,26 @@ int nand_jedec_detect(struct nand_chip *chip)
goto free_jedec_param_page;
}
mtd->writesize = le32_to_cpu(p->byte_per_page);
memorg->pagesize = le32_to_cpu(p->byte_per_page);
mtd->writesize = memorg->pagesize;
/* 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;
memorg->pages_per_eraseblock =
1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
mtd->oobsize = memorg->oobsize;
memorg->luns_per_target = p->lun_count;
memorg->planes_per_lun = 1 << p->multi_plane_addr;
/* Please reference to the comment for nand_flash_detect_onfi. */
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
memorg->eraseblocks_per_lun =
1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
chip->chipsize = memorg->eraseblocks_per_lun;
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
memorg->bits_per_cell = p->bits_per_cell;
chip->bits_per_cell = p->bits_per_cell;
if (le16_to_cpu(p->features) & JEDEC_FEATURE_16_BIT_BUS)

View file

@ -140,12 +140,15 @@ static void nand_bit_wise_majority(const void **srcbufs,
int nand_onfi_detect(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
struct nand_onfi_params *p;
struct onfi_params *onfi;
int onfi_version = 0;
char id[4];
int i, ret, val;
memorg = nanddev_get_memorg(&chip->base);
/* Try ONFI for unknown chip or LP */
ret = nand_readid_op(chip, 0x20, id, sizeof(id));
if (ret || strncmp(id, "ONFI", 4))
@ -221,21 +224,31 @@ int nand_onfi_detect(struct nand_chip *chip)
goto free_onfi_param_page;
}
mtd->writesize = le32_to_cpu(p->byte_per_page);
memorg->pagesize = le32_to_cpu(p->byte_per_page);
mtd->writesize = memorg->pagesize;
/*
* pages_per_block and blocks_per_lun may not be a power-of-2 size
* (don't ask me who thought of this...). MTD assumes that these
* dimensions will be power-of-2, so just truncate the remaining area.
*/
mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
mtd->erasesize *= mtd->writesize;
memorg->pages_per_eraseblock =
1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
mtd->erasesize = memorg->pages_per_eraseblock * memorg->pagesize;
mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
mtd->oobsize = memorg->oobsize;
memorg->luns_per_target = p->lun_count;
memorg->planes_per_lun = 1 << p->interleaved_bits;
/* See erasesize comment */
chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
memorg->eraseblocks_per_lun =
1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
memorg->max_bad_eraseblocks_per_lun = le32_to_cpu(p->blocks_per_lun);
chip->chipsize = memorg->eraseblocks_per_lun;
chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
memorg->bits_per_cell = p->bits_per_cell;
chip->bits_per_cell = p->bits_per_cell;
chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun);

View file

@ -20,6 +20,9 @@
static void samsung_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
/* New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) */
if (chip->id.len == 6 && !nand_is_slc(chip) &&
@ -27,29 +30,30 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
u8 extid = chip->id.data[3];
/* Get pagesize */
mtd->writesize = 2048 << (extid & 0x03);
memorg->pagesize = 2048 << (extid & 0x03);
mtd->writesize = memorg->pagesize;
extid >>= 2;
/* Get oobsize */
switch (((extid >> 2) & 0x4) | (extid & 0x3)) {
case 1:
mtd->oobsize = 128;
memorg->oobsize = 128;
break;
case 2:
mtd->oobsize = 218;
memorg->oobsize = 218;
break;
case 3:
mtd->oobsize = 400;
memorg->oobsize = 400;
break;
case 4:
mtd->oobsize = 436;
memorg->oobsize = 436;
break;
case 5:
mtd->oobsize = 512;
memorg->oobsize = 512;
break;
case 6:
mtd->oobsize = 640;
memorg->oobsize = 640;
break;
default:
/*
@ -62,8 +66,14 @@ static void samsung_nand_decode_id(struct nand_chip *chip)
break;
}
mtd->oobsize = memorg->oobsize;
/* Get blocksize */
extid >>= 2;
memorg->pages_per_eraseblock = (128 * 1024) <<
(((extid >> 1) & 0x04) |
(extid & 0x03)) /
memorg->pagesize;
mtd->erasesize = (128 * 1024) <<
(((extid >> 1) & 0x04) | (extid & 0x03));

View file

@ -101,6 +101,9 @@ static void toshiba_nand_benand_init(struct nand_chip *chip)
static void toshiba_nand_decode_id(struct nand_chip *chip)
{
struct mtd_info *mtd = nand_to_mtd(chip);
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
nand_decode_ext_id(chip);
@ -114,8 +117,10 @@ static void toshiba_nand_decode_id(struct nand_chip *chip)
*/
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;
!(chip->id.data[4] & 0x80) /* !BENAND */) {
memorg->oobsize = 32 * memorg->pagesize >> 9;
mtd->oobsize = memorg->oobsize;
}
/*
* Extract ECC requirements from 6th id byte.

View file

@ -2304,6 +2304,10 @@ static int __init ns_init_module(void)
if (overridesize) {
uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize;
struct nand_memory_organization *memorg;
memorg = nanddev_get_memorg(&chip->base);
if (new_size >> overridesize != nsmtd->erasesize) {
NS_ERR("overridesize is too big\n");
retval = -EINVAL;
@ -2311,6 +2315,7 @@ static int __init ns_init_module(void)
}
/* N.B. This relies on nand_scan not doing anything with the size before we change it */
nsmtd->size = new_size;
memorg->eraseblocks_per_lun = 1 << overridesize;
chip->chipsize = new_size;
chip->chip_shift = ffs(nsmtd->erasesize) + overridesize - 1;
chip->pagemask = (chip->chipsize >> chip->page_shift) - 1;