From 18729b17769c73fdf854dad99cd22dd0290e7f00 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sun, 3 May 2020 17:53:35 +0200 Subject: [PATCH] mtd: rawnand: Define the "distance 3" MLC pairing scheme Define a new page pairing scheme for MLC NANDs with a distance of 3 pages between the lower and upper page. Signed-off-by: Boris Brezillon Signed-off-by: Miquel Raynal Link: https://lore.kernel.org/linux-mtd/20200503155341.16712-3-miquel.raynal@bootlin.com --- drivers/mtd/nand/raw/internals.h | 3 +++ drivers/mtd/nand/raw/nand_base.c | 50 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/drivers/mtd/nand/raw/internals.h b/drivers/mtd/nand/raw/internals.h index 9d0caad..bca9b34 100644 --- a/drivers/mtd/nand/raw/internals.h +++ b/drivers/mtd/nand/raw/internals.h @@ -75,6 +75,9 @@ extern const struct nand_manufacturer_ops micron_nand_manuf_ops; extern const struct nand_manufacturer_ops samsung_nand_manuf_ops; extern const struct nand_manufacturer_ops toshiba_nand_manuf_ops; +/* MLC pairing schemes */ +extern const struct mtd_pairing_scheme dist3_pairing_scheme; + /* Core functions */ const struct nand_manufacturer *nand_get_manufacturer(u8 id); int nand_bbm_get_next_page(struct nand_chip *chip, int page); diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 52cf73c..106edd5 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -205,6 +205,56 @@ static const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { .free = nand_ooblayout_free_lp_hamming, }; +static int nand_pairing_dist3_get_info(struct mtd_info *mtd, int page, + struct mtd_pairing_info *info) +{ + int lastpage = (mtd->erasesize / mtd->writesize) - 1; + int dist = 3; + + if (page == lastpage) + dist = 2; + + if (!page || (page & 1)) { + info->group = 0; + info->pair = (page + 1) / 2; + } else { + info->group = 1; + info->pair = (page + 1 - dist) / 2; + } + + return 0; +} + +static int nand_pairing_dist3_get_wunit(struct mtd_info *mtd, + const struct mtd_pairing_info *info) +{ + int lastpair = ((mtd->erasesize / mtd->writesize) - 1) / 2; + int page = info->pair * 2; + int dist = 3; + + if (!info->group && !info->pair) + return 0; + + if (info->pair == lastpair && info->group) + dist = 2; + + if (!info->group) + page--; + else if (info->pair) + page += dist - 1; + + if (page >= mtd->erasesize / mtd->writesize) + return -EINVAL; + + return page; +} + +const struct mtd_pairing_scheme dist3_pairing_scheme = { + .ngroups = 2, + .get_info = nand_pairing_dist3_get_info, + .get_wunit = nand_pairing_dist3_get_wunit, +}; + static int check_offs_len(struct nand_chip *chip, loff_t ofs, uint64_t len) { int ret = 0; -- 2.7.4