Skip to content

Commit

Permalink
mtd: rawnand: Fill memorg during detection
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
bbrezillon authored and miquelraynal committed Apr 8, 2019
1 parent 3020e30 commit 629a442
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 44 deletions.
5 changes: 5 additions & 0 deletions drivers/mtd/nand/raw/denali.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/mtd/nand/raw/diskonchip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions drivers/mtd/nand/raw/ingenic/jz4740_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down
11 changes: 8 additions & 3 deletions drivers/mtd/nand/raw/nand_amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
}
}

Expand Down
64 changes: 58 additions & 6 deletions drivers/mtd/nand/raw/nand_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

memorg = nanddev_get_memorg(&chip->base);

if (!strncmp(type->id, id_data, type->id_len)) {
mtd->writesize = type->pagesize;
memorg->pagesize = type->pagesize;
mtd->writesize = memorg->pagesize;
memorg->pages_per_eraseblock = type->erasesize /
type->pagesize;
mtd->erasesize = type->erasesize;
mtd->oobsize = type->oobsize;
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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
Expand Down Expand 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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
48 changes: 32 additions & 16 deletions drivers/mtd/nand/raw/nand_hynix.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
/*
Expand All @@ -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:
/*
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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;
/*
Expand All @@ -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
Expand Down
Loading

0 comments on commit 629a442

Please sign in to comment.