1 // SPDX-License-Identifier: GPL-2.0
4 * Felix Matouschek <felix@matouschek.org>
7 #include <linux/bitfield.h>
8 #include <linux/device.h>
9 #include <linux/kernel.h>
10 #include <linux/mtd/spinand.h>
12 #define SPINAND_MFR_XTX 0x0B
14 #define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)
15 #define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)
16 #define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
17 #define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)
19 #define XT26XXXD_STATUS_ECC3_ECC2_MASK GENMASK(7, 6)
20 #define XT26XXXD_STATUS_ECC_NO_DETECTED (0)
21 #define XT26XXXD_STATUS_ECC_1_7_CORRECTED (1)
22 #define XT26XXXD_STATUS_ECC_8_CORRECTED (3)
23 #define XT26XXXD_STATUS_ECC_UNCOR_ERROR (2)
25 static SPINAND_OP_VARIANTS(read_cache_variants
,
26 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL
, 0),
27 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL
, 0),
28 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL
, 0),
29 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL
, 0),
30 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL
, 0),
31 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL
, 0));
33 static SPINAND_OP_VARIANTS(write_cache_variants
,
34 SPINAND_PROG_LOAD_X4(true, 0, NULL
, 0),
35 SPINAND_PROG_LOAD(true, 0, NULL
, 0));
37 static SPINAND_OP_VARIANTS(update_cache_variants
,
38 SPINAND_PROG_LOAD_X4(false, 0, NULL
, 0),
39 SPINAND_PROG_LOAD(false, 0, NULL
, 0));
41 static int xt26g0xa_ooblayout_ecc(struct mtd_info
*mtd
, int section
,
42 struct mtd_oob_region
*region
)
53 static int xt26g0xa_ooblayout_free(struct mtd_info
*mtd
, int section
,
54 struct mtd_oob_region
*region
)
65 static const struct mtd_ooblayout_ops xt26g0xa_ooblayout
= {
66 .ecc
= xt26g0xa_ooblayout_ecc
,
67 .free
= xt26g0xa_ooblayout_free
,
70 static int xt26g0xa_ecc_get_status(struct spinand_device
*spinand
,
73 status
= status
& XT26G0XA_STATUS_ECC_MASK
;
76 case XT26G0XA_STATUS_ECC_NO_DETECTED
:
78 case XT26G0XA_STATUS_ECC_8_CORRECTED
:
80 case XT26G0XA_STATUS_ECC_UNCOR_ERROR
:
86 /* At this point values greater than (2 << 4) are invalid */
87 if (status
> XT26G0XA_STATUS_ECC_UNCOR_ERROR
)
90 /* (1 << 2) through (7 << 2) are 1-7 corrected errors */
94 static int xt26xxxd_ooblayout_ecc(struct mtd_info
*mtd
, int section
,
95 struct mtd_oob_region
*region
)
100 region
->offset
= mtd
->oobsize
/ 2;
101 region
->length
= mtd
->oobsize
/ 2;
106 static int xt26xxxd_ooblayout_free(struct mtd_info
*mtd
, int section
,
107 struct mtd_oob_region
*region
)
113 region
->length
= mtd
->oobsize
/ 2 - 2;
118 static const struct mtd_ooblayout_ops xt26xxxd_ooblayout
= {
119 .ecc
= xt26xxxd_ooblayout_ecc
,
120 .free
= xt26xxxd_ooblayout_free
,
123 static int xt26xxxd_ecc_get_status(struct spinand_device
*spinand
,
126 switch (FIELD_GET(STATUS_ECC_MASK
, status
)) {
127 case XT26XXXD_STATUS_ECC_NO_DETECTED
:
129 case XT26XXXD_STATUS_ECC_UNCOR_ERROR
:
131 case XT26XXXD_STATUS_ECC_1_7_CORRECTED
:
132 return 4 + FIELD_GET(XT26XXXD_STATUS_ECC3_ECC2_MASK
, status
);
133 case XT26XXXD_STATUS_ECC_8_CORRECTED
:
141 static const struct spinand_info xtx_spinand_table
[] = {
142 SPINAND_INFO("XT26G01A",
143 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0xE1),
144 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
146 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
147 &write_cache_variants
,
148 &update_cache_variants
),
150 SPINAND_ECCINFO(&xt26g0xa_ooblayout
,
151 xt26g0xa_ecc_get_status
)),
152 SPINAND_INFO("XT26G02A",
153 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0xE2),
154 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
156 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
157 &write_cache_variants
,
158 &update_cache_variants
),
160 SPINAND_ECCINFO(&xt26g0xa_ooblayout
,
161 xt26g0xa_ecc_get_status
)),
162 SPINAND_INFO("XT26G04A",
163 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0xE3),
164 NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
166 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
167 &write_cache_variants
,
168 &update_cache_variants
),
170 SPINAND_ECCINFO(&xt26g0xa_ooblayout
,
171 xt26g0xa_ecc_get_status
)),
172 SPINAND_INFO("XT26G01D",
173 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x31),
174 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
176 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
177 &write_cache_variants
,
178 &update_cache_variants
),
180 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
181 xt26xxxd_ecc_get_status
)),
182 SPINAND_INFO("XT26G11D",
183 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x34),
184 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
186 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
187 &write_cache_variants
,
188 &update_cache_variants
),
190 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
191 xt26xxxd_ecc_get_status
)),
192 SPINAND_INFO("XT26Q01D",
193 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x51),
194 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
196 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
197 &write_cache_variants
,
198 &update_cache_variants
),
200 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
201 xt26xxxd_ecc_get_status
)),
202 SPINAND_INFO("XT26G02D",
203 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x32),
204 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
206 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
207 &write_cache_variants
,
208 &update_cache_variants
),
210 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
211 xt26xxxd_ecc_get_status
)),
212 SPINAND_INFO("XT26G12D",
213 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x35),
214 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
216 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
217 &write_cache_variants
,
218 &update_cache_variants
),
220 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
221 xt26xxxd_ecc_get_status
)),
222 SPINAND_INFO("XT26Q02D",
223 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x52),
224 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
226 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
227 &write_cache_variants
,
228 &update_cache_variants
),
230 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
231 xt26xxxd_ecc_get_status
)),
232 SPINAND_INFO("XT26G04D",
233 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x33),
234 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
236 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
237 &write_cache_variants
,
238 &update_cache_variants
),
240 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
241 xt26xxxd_ecc_get_status
)),
242 SPINAND_INFO("XT26Q04D",
243 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR
, 0x53),
244 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
246 SPINAND_INFO_OP_VARIANTS(&read_cache_variants
,
247 &write_cache_variants
,
248 &update_cache_variants
),
250 SPINAND_ECCINFO(&xt26xxxd_ooblayout
,
251 xt26xxxd_ecc_get_status
)),
254 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops
= {
257 const struct spinand_manufacturer xtx_spinand_manufacturer
= {
258 .id
= SPINAND_MFR_XTX
,
260 .chips
= xtx_spinand_table
,
261 .nchips
= ARRAY_SIZE(xtx_spinand_table
),
262 .ops
= &xtx_spinand_manuf_ops
,