]> Git Repo - linux.git/blob - drivers/mtd/nand/spi/gigadevice.c
Merge tag 'trace-v5.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux.git] / drivers / mtd / nand / spi / gigadevice.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Author:
4  *      Chuanhong Guo <[email protected]>
5  */
6
7 #include <linux/device.h>
8 #include <linux/kernel.h>
9 #include <linux/mtd/spinand.h>
10
11 #define SPINAND_MFR_GIGADEVICE                  0xC8
12
13 #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS      (1 << 4)
14 #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS        (3 << 4)
15
16 #define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS      (1 << 4)
17 #define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS        (3 << 4)
18
19 #define GD5FXGQXXEXXG_REG_STATUS2               0xf0
20
21 #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK          (7 << 4)
22 #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS   (0 << 4)
23 #define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS  (1 << 4)
24 #define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR   (7 << 4)
25
26 static SPINAND_OP_VARIANTS(read_cache_variants,
27                 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
28                 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
29                 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
30                 SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
31                 SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
32                 SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
33
34 static SPINAND_OP_VARIANTS(read_cache_variants_f,
35                 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
36                 SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
37                 SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
38                 SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
39                 SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
40                 SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
41
42 static SPINAND_OP_VARIANTS(write_cache_variants,
43                 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
44                 SPINAND_PROG_LOAD(true, 0, NULL, 0));
45
46 static SPINAND_OP_VARIANTS(update_cache_variants,
47                 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
48                 SPINAND_PROG_LOAD(false, 0, NULL, 0));
49
50 static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
51                                   struct mtd_oob_region *region)
52 {
53         if (section > 3)
54                 return -ERANGE;
55
56         region->offset = (16 * section) + 8;
57         region->length = 8;
58
59         return 0;
60 }
61
62 static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
63                                    struct mtd_oob_region *region)
64 {
65         if (section > 3)
66                 return -ERANGE;
67
68         if (section) {
69                 region->offset = 16 * section;
70                 region->length = 8;
71         } else {
72                 /* section 0 has one byte reserved for bad block mark */
73                 region->offset = 1;
74                 region->length = 7;
75         }
76         return 0;
77 }
78
79 static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
80         .ecc = gd5fxgq4xa_ooblayout_ecc,
81         .free = gd5fxgq4xa_ooblayout_free,
82 };
83
84 static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
85                                          u8 status)
86 {
87         switch (status & STATUS_ECC_MASK) {
88         case STATUS_ECC_NO_BITFLIPS:
89                 return 0;
90
91         case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
92                 /* 1-7 bits are flipped. return the maximum. */
93                 return 7;
94
95         case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
96                 return 8;
97
98         case STATUS_ECC_UNCOR_ERROR:
99                 return -EBADMSG;
100
101         default:
102                 break;
103         }
104
105         return -EINVAL;
106 }
107
108 static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
109                                        struct mtd_oob_region *region)
110 {
111         if (section)
112                 return -ERANGE;
113
114         region->offset = 64;
115         region->length = 64;
116
117         return 0;
118 }
119
120 static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
121                                         struct mtd_oob_region *region)
122 {
123         if (section)
124                 return -ERANGE;
125
126         /* Reserve 1 bytes for the BBM. */
127         region->offset = 1;
128         region->length = 63;
129
130         return 0;
131 }
132
133 /* Valid for Q4/Q5 and Q6 (untested) devices */
134 static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
135         .ecc = gd5fxgqx_variant2_ooblayout_ecc,
136         .free = gd5fxgqx_variant2_ooblayout_free,
137 };
138
139 static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
140                                         struct mtd_oob_region *oobregion)
141 {
142         if (section)
143                 return -ERANGE;
144
145         oobregion->offset = 128;
146         oobregion->length = 128;
147
148         return 0;
149 }
150
151 static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
152                                          struct mtd_oob_region *oobregion)
153 {
154         if (section)
155                 return -ERANGE;
156
157         oobregion->offset = 1;
158         oobregion->length = 127;
159
160         return 0;
161 }
162
163 static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
164         .ecc = gd5fxgq4xc_ooblayout_256_ecc,
165         .free = gd5fxgq4xc_ooblayout_256_free,
166 };
167
168 static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
169                                         u8 status)
170 {
171         u8 status2;
172         struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
173                                                       &status2);
174         int ret;
175
176         switch (status & STATUS_ECC_MASK) {
177         case STATUS_ECC_NO_BITFLIPS:
178                 return 0;
179
180         case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
181                 /*
182                  * Read status2 register to determine a more fine grained
183                  * bit error status
184                  */
185                 ret = spi_mem_exec_op(spinand->spimem, &op);
186                 if (ret)
187                         return ret;
188
189                 /*
190                  * 4 ... 7 bits are flipped (1..4 can't be detected, so
191                  * report the maximum of 4 in this case
192                  */
193                 /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
194                 return ((status & STATUS_ECC_MASK) >> 2) |
195                         ((status2 & STATUS_ECC_MASK) >> 4);
196
197         case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
198                 return 8;
199
200         case STATUS_ECC_UNCOR_ERROR:
201                 return -EBADMSG;
202
203         default:
204                 break;
205         }
206
207         return -EINVAL;
208 }
209
210 static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
211                                         u8 status)
212 {
213         u8 status2;
214         struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
215                                                       &status2);
216         int ret;
217
218         switch (status & STATUS_ECC_MASK) {
219         case STATUS_ECC_NO_BITFLIPS:
220                 return 0;
221
222         case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
223                 /*
224                  * Read status2 register to determine a more fine grained
225                  * bit error status
226                  */
227                 ret = spi_mem_exec_op(spinand->spimem, &op);
228                 if (ret)
229                         return ret;
230
231                 /*
232                  * 1 ... 4 bits are flipped (and corrected)
233                  */
234                 /* bits sorted this way (1...0): ECCSE1, ECCSE0 */
235                 return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
236
237         case STATUS_ECC_UNCOR_ERROR:
238                 return -EBADMSG;
239
240         default:
241                 break;
242         }
243
244         return -EINVAL;
245 }
246
247 static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
248                                         u8 status)
249 {
250         switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
251         case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
252                 return 0;
253
254         case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
255                 return 3;
256
257         case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
258                 return -EBADMSG;
259
260         default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
261                 return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
262         }
263
264         return -EINVAL;
265 }
266
267 static const struct spinand_info gigadevice_spinand_table[] = {
268         SPINAND_INFO("GD5F1GQ4xA",
269                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
270                      NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
271                      NAND_ECCREQ(8, 512),
272                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
273                                               &write_cache_variants,
274                                               &update_cache_variants),
275                      SPINAND_HAS_QE_BIT,
276                      SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
277                                      gd5fxgq4xa_ecc_get_status)),
278         SPINAND_INFO("GD5F2GQ4xA",
279                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
280                      NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
281                      NAND_ECCREQ(8, 512),
282                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
283                                               &write_cache_variants,
284                                               &update_cache_variants),
285                      SPINAND_HAS_QE_BIT,
286                      SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
287                                      gd5fxgq4xa_ecc_get_status)),
288         SPINAND_INFO("GD5F4GQ4xA",
289                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
290                      NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
291                      NAND_ECCREQ(8, 512),
292                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
293                                               &write_cache_variants,
294                                               &update_cache_variants),
295                      SPINAND_HAS_QE_BIT,
296                      SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
297                                      gd5fxgq4xa_ecc_get_status)),
298         SPINAND_INFO("GD5F4GQ4RC",
299                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
300                      NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
301                      NAND_ECCREQ(8, 512),
302                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
303                                               &write_cache_variants,
304                                               &update_cache_variants),
305                      SPINAND_HAS_QE_BIT,
306                      SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
307                                      gd5fxgq4ufxxg_ecc_get_status)),
308         SPINAND_INFO("GD5F4GQ4UC",
309                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
310                      NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
311                      NAND_ECCREQ(8, 512),
312                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
313                                               &write_cache_variants,
314                                               &update_cache_variants),
315                      SPINAND_HAS_QE_BIT,
316                      SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
317                                      gd5fxgq4ufxxg_ecc_get_status)),
318         SPINAND_INFO("GD5F1GQ4UExxG",
319                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
320                      NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
321                      NAND_ECCREQ(8, 512),
322                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
323                                               &write_cache_variants,
324                                               &update_cache_variants),
325                      SPINAND_HAS_QE_BIT,
326                      SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
327                                      gd5fxgq4uexxg_ecc_get_status)),
328         SPINAND_INFO("GD5F1GQ4UFxxG",
329                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
330                      NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
331                      NAND_ECCREQ(8, 512),
332                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
333                                               &write_cache_variants,
334                                               &update_cache_variants),
335                      SPINAND_HAS_QE_BIT,
336                      SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
337                                      gd5fxgq4ufxxg_ecc_get_status)),
338         SPINAND_INFO("GD5F1GQ5UExxG",
339                      SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
340                      NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
341                      NAND_ECCREQ(4, 512),
342                      SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
343                                               &write_cache_variants,
344                                               &update_cache_variants),
345                      SPINAND_HAS_QE_BIT,
346                      SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
347                                      gd5fxgq5xexxg_ecc_get_status)),
348 };
349
350 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
351 };
352
353 const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
354         .id = SPINAND_MFR_GIGADEVICE,
355         .name = "GigaDevice",
356         .chips = gigadevice_spinand_table,
357         .nchips = ARRAY_SIZE(gigadevice_spinand_table),
358         .ops = &gigadevice_spinand_manuf_ops,
359 };
This page took 0.060443 seconds and 4 git commands to generate.