1d74c3648SChuanhong Guo // SPDX-License-Identifier: GPL-2.0
2d74c3648SChuanhong Guo /*
3d74c3648SChuanhong Guo * Author:
4d74c3648SChuanhong Guo * Chuanhong Guo <gch981213@gmail.com> - the main driver logic
5d74c3648SChuanhong Guo * Martin Kurbanov <mmkurbanov@sberdevices.ru> - OOB layout
6d74c3648SChuanhong Guo */
7d74c3648SChuanhong Guo
8d74c3648SChuanhong Guo #include <linux/device.h>
9d74c3648SChuanhong Guo #include <linux/kernel.h>
10d74c3648SChuanhong Guo #include <linux/mtd/spinand.h>
11d74c3648SChuanhong Guo
12d74c3648SChuanhong Guo /* ESMT uses GigaDevice 0xc8 JECDEC ID on some SPI NANDs */
13d74c3648SChuanhong Guo #define SPINAND_MFR_ESMT_C8 0xc8
14d74c3648SChuanhong Guo
15d74c3648SChuanhong Guo static SPINAND_OP_VARIANTS(read_cache_variants,
16d74c3648SChuanhong Guo SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
17d74c3648SChuanhong Guo SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
18d74c3648SChuanhong Guo SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
19d74c3648SChuanhong Guo SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
20d74c3648SChuanhong Guo
21d74c3648SChuanhong Guo static SPINAND_OP_VARIANTS(write_cache_variants,
22d74c3648SChuanhong Guo SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
23d74c3648SChuanhong Guo SPINAND_PROG_LOAD(true, 0, NULL, 0));
24d74c3648SChuanhong Guo
25d74c3648SChuanhong Guo static SPINAND_OP_VARIANTS(update_cache_variants,
26d74c3648SChuanhong Guo SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
27d74c3648SChuanhong Guo SPINAND_PROG_LOAD(false, 0, NULL, 0));
28d74c3648SChuanhong Guo
29d74c3648SChuanhong Guo /*
30d74c3648SChuanhong Guo * OOB spare area map (64 bytes)
31d74c3648SChuanhong Guo *
32d74c3648SChuanhong Guo * Bad Block Markers
33d74c3648SChuanhong Guo * filled by HW and kernel Reserved
34d74c3648SChuanhong Guo * | +-----------------------+-----------------------+
35d74c3648SChuanhong Guo * | | | |
36d74c3648SChuanhong Guo * | | OOB free data Area |non ECC protected |
37d74c3648SChuanhong Guo * | +-------------|-----+-----------------|-----+-----------------|-----+
38d74c3648SChuanhong Guo * | | | | | | | |
39d74c3648SChuanhong Guo * +-|---|----------+--|-----|--------------+--|-----|--------------+--|-----|--------------+
40d74c3648SChuanhong Guo * | | | section0 | | | section1 | | | section2 | | | section3 |
41d74c3648SChuanhong Guo * +-v-+-v-+---+----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+--v--+--v--+-----+-----+
42d74c3648SChuanhong Guo * | | | | | | | | | | | | | | | | |
43d74c3648SChuanhong Guo * |0:1|2:3|4:7|8:15|16:17|18:19|20:23|24:31|32:33|34:35|36:39|40:47|48:49|50:51|52:55|56:63|
44d74c3648SChuanhong Guo * | | | | | | | | | | | | | | | | |
45d74c3648SChuanhong Guo * +---+---+-^-+--^-+-----+-----+--^--+--^--+-----+-----+--^--+--^--+-----+-----+--^--+--^--+
46d74c3648SChuanhong Guo * | | | | | | | |
47d74c3648SChuanhong Guo * | +----------------|-----+-----------------|-----+-----------------|-----+
48d74c3648SChuanhong Guo * | ECC Area|(Main + Spare) - filled|by ESMT NAND HW |
49d74c3648SChuanhong Guo * | | | |
50d74c3648SChuanhong Guo * +---------------------+-----------------------+-----------------------+
51d74c3648SChuanhong Guo * OOB ECC protected Area - not used due to
52d74c3648SChuanhong Guo * partial programming from some filesystems
53d74c3648SChuanhong Guo * (like JFFS2 with cleanmarkers)
54d74c3648SChuanhong Guo */
55d74c3648SChuanhong Guo
56d74c3648SChuanhong Guo #define ESMT_OOB_SECTION_COUNT 4
57d74c3648SChuanhong Guo #define ESMT_OOB_SECTION_SIZE(nand) \
58d74c3648SChuanhong Guo (nanddev_per_page_oobsize(nand) / ESMT_OOB_SECTION_COUNT)
59d74c3648SChuanhong Guo #define ESMT_OOB_FREE_SIZE(nand) \
60d74c3648SChuanhong Guo (ESMT_OOB_SECTION_SIZE(nand) / 2)
61d74c3648SChuanhong Guo #define ESMT_OOB_ECC_SIZE(nand) \
62d74c3648SChuanhong Guo (ESMT_OOB_SECTION_SIZE(nand) - ESMT_OOB_FREE_SIZE(nand))
63d74c3648SChuanhong Guo #define ESMT_OOB_BBM_SIZE 2
64d74c3648SChuanhong Guo
f50l1g41lb_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)65d74c3648SChuanhong Guo static int f50l1g41lb_ooblayout_ecc(struct mtd_info *mtd, int section,
66d74c3648SChuanhong Guo struct mtd_oob_region *region)
67d74c3648SChuanhong Guo {
68d74c3648SChuanhong Guo struct nand_device *nand = mtd_to_nanddev(mtd);
69d74c3648SChuanhong Guo
70d74c3648SChuanhong Guo if (section >= ESMT_OOB_SECTION_COUNT)
71d74c3648SChuanhong Guo return -ERANGE;
72d74c3648SChuanhong Guo
73d74c3648SChuanhong Guo region->offset = section * ESMT_OOB_SECTION_SIZE(nand) +
74d74c3648SChuanhong Guo ESMT_OOB_FREE_SIZE(nand);
75d74c3648SChuanhong Guo region->length = ESMT_OOB_ECC_SIZE(nand);
76d74c3648SChuanhong Guo
77d74c3648SChuanhong Guo return 0;
78d74c3648SChuanhong Guo }
79d74c3648SChuanhong Guo
f50l1g41lb_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)80d74c3648SChuanhong Guo static int f50l1g41lb_ooblayout_free(struct mtd_info *mtd, int section,
81d74c3648SChuanhong Guo struct mtd_oob_region *region)
82d74c3648SChuanhong Guo {
83d74c3648SChuanhong Guo struct nand_device *nand = mtd_to_nanddev(mtd);
84d74c3648SChuanhong Guo
85d74c3648SChuanhong Guo if (section >= ESMT_OOB_SECTION_COUNT)
86d74c3648SChuanhong Guo return -ERANGE;
87d74c3648SChuanhong Guo
88d74c3648SChuanhong Guo /*
89d74c3648SChuanhong Guo * Reserve space for bad blocks markers (section0) and
90d74c3648SChuanhong Guo * reserved bytes (sections 1-3)
91d74c3648SChuanhong Guo */
92d74c3648SChuanhong Guo region->offset = section * ESMT_OOB_SECTION_SIZE(nand) + 2;
93d74c3648SChuanhong Guo
94d74c3648SChuanhong Guo /* Use only 2 non-protected ECC bytes per each OOB section */
95d74c3648SChuanhong Guo region->length = 2;
96d74c3648SChuanhong Guo
97d74c3648SChuanhong Guo return 0;
98d74c3648SChuanhong Guo }
99d74c3648SChuanhong Guo
100d74c3648SChuanhong Guo static const struct mtd_ooblayout_ops f50l1g41lb_ooblayout = {
101d74c3648SChuanhong Guo .ecc = f50l1g41lb_ooblayout_ecc,
102d74c3648SChuanhong Guo .free = f50l1g41lb_ooblayout_free,
103d74c3648SChuanhong Guo };
104d74c3648SChuanhong Guo
105d74c3648SChuanhong Guo static const struct spinand_info esmt_c8_spinand_table[] = {
106d74c3648SChuanhong Guo SPINAND_INFO("F50L1G41LB",
107*0a96e0daSEzra Buehler SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01, 0x7f,
108*0a96e0daSEzra Buehler 0x7f, 0x7f),
109d74c3648SChuanhong Guo NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
110d74c3648SChuanhong Guo NAND_ECCREQ(1, 512),
111d74c3648SChuanhong Guo SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
112d74c3648SChuanhong Guo &write_cache_variants,
113d74c3648SChuanhong Guo &update_cache_variants),
114d74c3648SChuanhong Guo 0,
115d74c3648SChuanhong Guo SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
116d74c3648SChuanhong Guo SPINAND_INFO("F50D1G41LB",
117*0a96e0daSEzra Buehler SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x11, 0x7f,
118*0a96e0daSEzra Buehler 0x7f, 0x7f),
119d74c3648SChuanhong Guo NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
120d74c3648SChuanhong Guo NAND_ECCREQ(1, 512),
121d74c3648SChuanhong Guo SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
122d74c3648SChuanhong Guo &write_cache_variants,
123d74c3648SChuanhong Guo &update_cache_variants),
124d74c3648SChuanhong Guo 0,
125d74c3648SChuanhong Guo SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
126aa08bf18SSridharan S N SPINAND_INFO("F50D2G41KA",
127*0a96e0daSEzra Buehler SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x51, 0x7f,
128*0a96e0daSEzra Buehler 0x7f, 0x7f),
129aa08bf18SSridharan S N NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
130aa08bf18SSridharan S N NAND_ECCREQ(8, 512),
131aa08bf18SSridharan S N SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
132aa08bf18SSridharan S N &write_cache_variants,
133aa08bf18SSridharan S N &update_cache_variants),
134aa08bf18SSridharan S N 0,
135aa08bf18SSridharan S N SPINAND_ECCINFO(&f50l1g41lb_ooblayout, NULL)),
136d74c3648SChuanhong Guo };
137d74c3648SChuanhong Guo
138d74c3648SChuanhong Guo static const struct spinand_manufacturer_ops esmt_spinand_manuf_ops = {
139d74c3648SChuanhong Guo };
140d74c3648SChuanhong Guo
141d74c3648SChuanhong Guo const struct spinand_manufacturer esmt_c8_spinand_manufacturer = {
142d74c3648SChuanhong Guo .id = SPINAND_MFR_ESMT_C8,
143d74c3648SChuanhong Guo .name = "ESMT",
144d74c3648SChuanhong Guo .chips = esmt_c8_spinand_table,
145d74c3648SChuanhong Guo .nchips = ARRAY_SIZE(esmt_c8_spinand_table),
146d74c3648SChuanhong Guo .ops = &esmt_spinand_manuf_ops,
147d74c3648SChuanhong Guo };
148