xref: /rk3399_rockchip-uboot/drivers/mtd/nand/spi/xtx.c (revision d46ff1ab85601381d5d4c5efae9fa17e1952dbf0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2020 Rockchip Electronics Co., Ltd
4  *
5  * Authors:
6  *	Dingqiang Lin <jon.lin@rock-chips.com>
7  */
8 
9 #ifndef __UBOOT__
10 #include <linux/device.h>
11 #include <linux/kernel.h>
12 #endif
13 #include <linux/mtd/spinand.h>
14 
15 #define SPINAND_MFR_XTX			0x0B
16 
17 static SPINAND_OP_VARIANTS(read_cache_variants,
18 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
19 		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
20 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
21 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
22 
23 static SPINAND_OP_VARIANTS(write_cache_variants,
24 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
25 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
26 
27 static SPINAND_OP_VARIANTS(update_cache_variants,
28 		SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
29 		SPINAND_PROG_LOAD(false, 0, NULL, 0));
30 
31 static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
32 				  struct mtd_oob_region *region)
33 {
34 	if (section)
35 		return -ERANGE;
36 
37 	region->offset = 48;
38 	region->length = 16;
39 
40 	return 0;
41 }
42 
43 static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
44 				   struct mtd_oob_region *region)
45 {
46 	if (section)
47 		return -ERANGE;
48 
49 	region->offset = 2;
50 	region->length = mtd->oobsize - 18;
51 
52 	return 0;
53 }
54 
55 static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
56 	.ecc = xt26g0xa_ooblayout_ecc,
57 	.rfree = xt26g0xa_ooblayout_free,
58 };
59 
60 static int xt26g01b_ooblayout_ecc(struct mtd_info *mtd, int section,
61 				  struct mtd_oob_region *region)
62 {
63 	return -ERANGE;
64 }
65 
66 static int xt26g01b_ooblayout_free(struct mtd_info *mtd, int section,
67 				   struct mtd_oob_region *region)
68 {
69 	if (section)
70 		return -ERANGE;
71 
72 	region->offset = 2;
73 	region->length = mtd->oobsize - 2;
74 
75 	return 0;
76 }
77 
78 static const struct mtd_ooblayout_ops xt26g01b_ooblayout = {
79 	.ecc = xt26g01b_ooblayout_ecc,
80 	.rfree = xt26g01b_ooblayout_free,
81 };
82 
83 static int xt26g02b_ooblayout_ecc(struct mtd_info *mtd, int section,
84 				  struct mtd_oob_region *region)
85 {
86 	if (section > 3)
87 		return -ERANGE;
88 
89 	region->offset = (16 * section) + 8;
90 	region->length = 8;
91 
92 	return 0;
93 }
94 
95 static int xt26g02b_ooblayout_free(struct mtd_info *mtd, int section,
96 				   struct mtd_oob_region *region)
97 {
98 	if (section > 3)
99 		return -ERANGE;
100 
101 	region->offset = (16 * section) + 2;
102 	region->length = 6;
103 
104 	return 0;
105 }
106 
107 static const struct mtd_ooblayout_ops xt26g02b_ooblayout = {
108 	.ecc = xt26g02b_ooblayout_ecc,
109 	.rfree = xt26g02b_ooblayout_free,
110 };
111 
112 /*
113  * ecc bits: 0xC0[2,5]
114  * [0x0000], No bit errors were detected;
115  * [0x0001, 0x0111], Bit errors were detected and corrected. Not
116  *	reach Flipping Bits;
117  * [0x1000], Multiple bit errors were detected and
118  *	not corrected.
119  * [0x1100], Bit error count equals the bit flip
120  *	detectionthreshold
121  * else, reserved
122  */
123 static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
124 				   u8 status)
125 {
126 	u8 eccsr = (status & GENMASK(5, 2)) >> 2;
127 
128 	if (eccsr <= 7)
129 		return eccsr;
130 	else if (eccsr == 12)
131 		return 8;
132 	else
133 		return -EBADMSG;
134 }
135 
136 /*
137  * ecc bits: 0xC0[4,6]
138  * [0x0], No bit errors were detected;
139  * [0x001, 0x011], Bit errors were detected and corrected. Not
140  *	reach Flipping Bits;
141  * [0x100], Bit error count equals the bit flip
142  *	detectionthreshold
143  * [0x101, 0x110], Reserved;
144  * [0x111], Multiple bit errors were detected and
145  *	not corrected.
146  */
147 static int xt26g02b_ecc_get_status(struct spinand_device *spinand,
148 				   u8 status)
149 {
150 	u8 eccsr = (status & GENMASK(6, 4)) >> 4;
151 
152 	if (eccsr <= 4)
153 		return eccsr;
154 	else
155 		return -EBADMSG;
156 }
157 
158 /*
159  * ecc bits: 0xC0[4,7]
160  * [0b0000], No bit errors were detected;
161  * [0b0001, 0b0111], 1-7 Bit errors were detected and corrected. Not
162  *	reach Flipping Bits;
163  * [0b1000], 8 Bit errors were detected and corrected. Bit error count
164  *	equals the bit flip detectionthreshold;
165  * [0b1111], Bit errors greater than ECC capability(8 bits) and not corrected;
166  * others, Reserved.
167  */
168 static int xt26g01c_ecc_get_status(struct spinand_device *spinand,
169 				   u8 status)
170 {
171 	u8 eccsr = (status & GENMASK(7, 4)) >> 4;
172 
173 	if (eccsr <= 8)
174 		return eccsr;
175 	else
176 		return -EBADMSG;
177 }
178 
179 static const struct spinand_info xtx_spinand_table[] = {
180 	SPINAND_INFO("XT26G01A", 0xE1,
181 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
182 		     NAND_ECCREQ(8, 512),
183 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
184 					      &write_cache_variants,
185 					      &update_cache_variants),
186 		     SPINAND_HAS_QE_BIT,
187 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
188 				     xt26g0xa_ecc_get_status)),
189 	SPINAND_INFO("XT26G02A", 0xE2,
190 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
191 		     NAND_ECCREQ(8, 512),
192 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
193 					      &write_cache_variants,
194 					      &update_cache_variants),
195 		     SPINAND_HAS_QE_BIT,
196 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
197 				     xt26g0xa_ecc_get_status)),
198 	SPINAND_INFO("XT26G04A", 0xE3,
199 		     NAND_MEMORG(1, 2048, 64, 128, 2048, 1, 1, 1),
200 		     NAND_ECCREQ(8, 512),
201 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
202 					      &write_cache_variants,
203 					      &update_cache_variants),
204 		     SPINAND_HAS_QE_BIT,
205 		     SPINAND_ECCINFO(&xt26g0xa_ooblayout,
206 				     xt26g0xa_ecc_get_status)),
207 	SPINAND_INFO("XT26G01B", 0xF1,
208 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
209 		     NAND_ECCREQ(8, 512),
210 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
211 					      &write_cache_variants,
212 					      &update_cache_variants),
213 		     SPINAND_HAS_QE_BIT,
214 		     SPINAND_ECCINFO(&xt26g01b_ooblayout,
215 				     xt26g0xa_ecc_get_status)),
216 	SPINAND_INFO("XT26G02B", 0xF2,
217 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
218 		     NAND_ECCREQ(4, 512),
219 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
220 					      &write_cache_variants,
221 					      &update_cache_variants),
222 		     SPINAND_HAS_QE_BIT,
223 		     SPINAND_ECCINFO(&xt26g02b_ooblayout,
224 				     xt26g02b_ecc_get_status)),
225 	SPINAND_INFO("XT26G01C", 0x11,
226 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
227 		     NAND_ECCREQ(8, 512),
228 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
229 					      &write_cache_variants,
230 					      &update_cache_variants),
231 		     SPINAND_HAS_QE_BIT,
232 		     SPINAND_ECCINFO(&xt26g01b_ooblayout,
233 				     xt26g01c_ecc_get_status)),
234 	SPINAND_INFO("XT26G02C", 0x12,
235 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
236 		     NAND_ECCREQ(8, 512),
237 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
238 					      &write_cache_variants,
239 					      &update_cache_variants),
240 		     SPINAND_HAS_QE_BIT,
241 		     SPINAND_ECCINFO(&xt26g01b_ooblayout,
242 				     xt26g01c_ecc_get_status)),
243 	SPINAND_INFO("XT26G04C", 0x13,
244 		     NAND_MEMORG(1, 4096, 128, 64, 2048, 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 		     SPINAND_HAS_QE_BIT,
250 		     SPINAND_ECCINFO(&xt26g01b_ooblayout,
251 				     xt26g01c_ecc_get_status)),
252 };
253 
254 static int xtx_spinand_detect(struct spinand_device *spinand)
255 {
256 	u8 *id = spinand->id.data;
257 	int ret;
258 
259 	/*
260 	 * XTX SPI NAND read ID needs a dummy byte, so the first byte in
261 	 * raw_id is garbage.
262 	 */
263 	if (id[1] != SPINAND_MFR_XTX)
264 		return 0;
265 
266 	ret = spinand_match_and_init(spinand, xtx_spinand_table,
267 				     ARRAY_SIZE(xtx_spinand_table),
268 				     id[2]);
269 	if (ret)
270 		return ret;
271 
272 	return 1;
273 }
274 
275 static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
276 	.detect = xtx_spinand_detect,
277 };
278 
279 const struct spinand_manufacturer xtx_spinand_manufacturer = {
280 	.id = SPINAND_MFR_XTX,
281 	.name = "xtx",
282 	.ops = &xtx_spinand_manuf_ops,
283 };
284