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