xref: /linux/drivers/mtd/nand/spi/xtx.c (revision 0ea5c948cb64bab5bc7a5516774eb8536f05aa0d)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Author:
4  * Felix Matouschek <felix@matouschek.org>
5  */
6 
7 #include <linux/bitfield.h>
8 #include <linux/device.h>
9 #include <linux/kernel.h>
10 #include <linux/mtd/spinand.h>
11 
12 #define SPINAND_MFR_XTX	0x0B
13 
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)
18 
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)
24 
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));
32 
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));
36 
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));
40 
xt26g0xa_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)41 static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
42 				   struct mtd_oob_region *region)
43 {
44 	if (section)
45 		return -ERANGE;
46 
47 	region->offset = 48;
48 	region->length = 16;
49 
50 	return 0;
51 }
52 
xt26g0xa_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)53 static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
54 				   struct mtd_oob_region *region)
55 {
56 	if (section)
57 		return -ERANGE;
58 
59 	region->offset = 1;
60 	region->length = 47;
61 
62 	return 0;
63 }
64 
65 static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
66 	.ecc = xt26g0xa_ooblayout_ecc,
67 	.free = xt26g0xa_ooblayout_free,
68 };
69 
xt26g0xa_ecc_get_status(struct spinand_device * spinand,u8 status)70 static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
71 					 u8 status)
72 {
73 	status = status & XT26G0XA_STATUS_ECC_MASK;
74 
75 	switch (status) {
76 	case XT26G0XA_STATUS_ECC_NO_DETECTED:
77 		return 0;
78 	case XT26G0XA_STATUS_ECC_8_CORRECTED:
79 		return 8;
80 	case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
81 		return -EBADMSG;
82 	default:
83 		break;
84 	}
85 
86 	/* At this point values greater than (2 << 4) are invalid  */
87 	if (status > XT26G0XA_STATUS_ECC_UNCOR_ERROR)
88 		return -EINVAL;
89 
90 	/* (1 << 2) through (7 << 2) are 1-7 corrected errors */
91 	return status >> 2;
92 }
93 
xt26xxxd_ooblayout_ecc(struct mtd_info * mtd,int section,struct mtd_oob_region * region)94 static int xt26xxxd_ooblayout_ecc(struct mtd_info *mtd, int section,
95 				  struct mtd_oob_region *region)
96 {
97 	if (section)
98 		return -ERANGE;
99 
100 	region->offset = mtd->oobsize / 2;
101 	region->length = mtd->oobsize / 2;
102 
103 	return 0;
104 }
105 
xt26xxxd_ooblayout_free(struct mtd_info * mtd,int section,struct mtd_oob_region * region)106 static int xt26xxxd_ooblayout_free(struct mtd_info *mtd, int section,
107 				   struct mtd_oob_region *region)
108 {
109 	if (section)
110 		return -ERANGE;
111 
112 	region->offset = 2;
113 	region->length = mtd->oobsize / 2 - 2;
114 
115 	return 0;
116 }
117 
118 static const struct mtd_ooblayout_ops xt26xxxd_ooblayout = {
119 	.ecc = xt26xxxd_ooblayout_ecc,
120 	.free = xt26xxxd_ooblayout_free,
121 };
122 
xt26xxxd_ecc_get_status(struct spinand_device * spinand,u8 status)123 static int xt26xxxd_ecc_get_status(struct spinand_device *spinand,
124 				   u8 status)
125 {
126 	switch (FIELD_GET(STATUS_ECC_MASK, status)) {
127 	case XT26XXXD_STATUS_ECC_NO_DETECTED:
128 		return 0;
129 	case XT26XXXD_STATUS_ECC_UNCOR_ERROR:
130 		return -EBADMSG;
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:
134 		return 8;
135 	default:
136 		break;
137 	}
138 
139 	return -EINVAL;
140 }
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),
145 		     NAND_ECCREQ(8, 512),
146 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
147 					      &write_cache_variants,
148 					      &update_cache_variants),
149 		     SPINAND_HAS_QE_BIT,
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),
155 		     NAND_ECCREQ(8, 512),
156 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
157 					      &write_cache_variants,
158 					      &update_cache_variants),
159 		     SPINAND_HAS_QE_BIT,
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),
165 		     NAND_ECCREQ(8, 512),
166 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
167 					      &write_cache_variants,
168 					      &update_cache_variants),
169 		     SPINAND_HAS_QE_BIT,
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),
175 		     NAND_ECCREQ(8, 512),
176 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
177 					      &write_cache_variants,
178 					      &update_cache_variants),
179 		     0,
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),
185 		     NAND_ECCREQ(8, 512),
186 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
187 					      &write_cache_variants,
188 					      &update_cache_variants),
189 		     0,
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),
195 		     NAND_ECCREQ(8, 512),
196 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
197 					      &write_cache_variants,
198 					      &update_cache_variants),
199 		     0,
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),
205 		     NAND_ECCREQ(8, 512),
206 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
207 					      &write_cache_variants,
208 					      &update_cache_variants),
209 		     0,
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),
215 		     NAND_ECCREQ(8, 512),
216 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
217 					      &write_cache_variants,
218 					      &update_cache_variants),
219 		     0,
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),
225 		     NAND_ECCREQ(8, 512),
226 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
227 					      &write_cache_variants,
228 					      &update_cache_variants),
229 		     0,
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),
235 		     NAND_ECCREQ(8, 512),
236 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
237 					      &write_cache_variants,
238 					      &update_cache_variants),
239 		     0,
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),
245 		     NAND_ECCREQ(8, 512),
246 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
247 					      &write_cache_variants,
248 					      &update_cache_variants),
249 		     0,
250 		     SPINAND_ECCINFO(&xt26xxxd_ooblayout,
251 				     xt26xxxd_ecc_get_status)),
252 };
253 
254 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
255 };
256 
257 const struct spinand_manufacturer xtx_spinand_manufacturer = {
258 	.id = SPINAND_MFR_XTX,
259 	.name = "XTX",
260 	.chips = xtx_spinand_table,
261 	.nchips = ARRAY_SIZE(xtx_spinand_table),
262 	.ops = &xtx_spinand_manuf_ops,
263 };
264