mtd: rawnand: Define the "distance 3" MLC pairing scheme
authorBoris Brezillon <bbrezillon@kernel.org>
Sun, 3 May 2020 15:53:35 +0000 (17:53 +0200)
committerMiquel Raynal <miquel.raynal@bootlin.com>
Mon, 11 May 2020 07:51:41 +0000 (09:51 +0200)
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 <bbrezillon@kernel.org>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200503155341.16712-3-miquel.raynal@bootlin.com
drivers/mtd/nand/raw/internals.h
drivers/mtd/nand/raw/nand_base.c

index 9d0caad..bca9b34 100644 (file)
@@ -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);
index 52cf73c..106edd5 100644 (file)
@@ -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;