{
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:
}
/* 2 chips in parallel */
+ memorg->pagesize <<= 1;
+ memorg->oobsize <<= 1;
mtd->size <<= 1;
mtd->erasesize <<= 1;
mtd->writesize <<= 1;
{
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;
unsigned blocks, maxblocks;
int offs, numheaders;
+ memorg = nanddev_get_memorg(&this->base);
+
buf = kmalloc(mtd->writesize, GFP_KERNEL);
if (!buf) {
return 0;
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;
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,
/* Update size of the MTD. */
chip->numchips++;
+ memorg->ntargets++;
mtd->size += chip->chipsize;
}
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);
*/
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;
}
}
*/
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 */
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;
}
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);
*/
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 {
{
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.
/* 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;
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;
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;
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:
/*
} 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:
/*
* 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,
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
}
/* 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;
/*
* 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
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)))
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;
+
+ memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+ mtd->oobsize = memorg->oobsize;
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+ 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)
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))
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;
+
+ memorg->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+ mtd->oobsize = memorg->oobsize;
- mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+ 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);
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) &&
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:
/*
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));
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);
*/
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.
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;
}
/* 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;