1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (c) 2018 exceet electronics GmbH |
4 | * Copyright (c) 2018 Kontron Electronics GmbH |
5 | * |
6 | * Author: Frieder Schrempf <frieder.schrempf@kontron.de> |
7 | */ |
8 | |
9 | #include <linux/device.h> |
10 | #include <linux/kernel.h> |
11 | #include <linux/mtd/spinand.h> |
12 | |
13 | /* Kioxia is new name of Toshiba memory. */ |
14 | #define SPINAND_MFR_TOSHIBA 0x98 |
15 | #define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4) |
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_x4_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_x4_variants, |
28 | SPINAND_PROG_LOAD_X4(false, 0, NULL, 0), |
29 | SPINAND_PROG_LOAD(false, 0, NULL, 0)); |
30 | |
31 | /* |
32 | * Backward compatibility for 1st generation Serial NAND devices |
33 | * which don't support Quad Program Load operation. |
34 | */ |
35 | static SPINAND_OP_VARIANTS(write_cache_variants, |
36 | SPINAND_PROG_LOAD(true, 0, NULL, 0)); |
37 | |
38 | static SPINAND_OP_VARIANTS(update_cache_variants, |
39 | SPINAND_PROG_LOAD(false, 0, NULL, 0)); |
40 | |
41 | static int tx58cxgxsxraix_ooblayout_ecc(struct mtd_info *mtd, int section, |
42 | struct mtd_oob_region *region) |
43 | { |
44 | if (section > 0) |
45 | return -ERANGE; |
46 | |
47 | region->offset = mtd->oobsize / 2; |
48 | region->length = mtd->oobsize / 2; |
49 | |
50 | return 0; |
51 | } |
52 | |
53 | static int tx58cxgxsxraix_ooblayout_free(struct mtd_info *mtd, int section, |
54 | struct mtd_oob_region *region) |
55 | { |
56 | if (section > 0) |
57 | return -ERANGE; |
58 | |
59 | /* 2 bytes reserved for BBM */ |
60 | region->offset = 2; |
61 | region->length = (mtd->oobsize / 2) - 2; |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | static const struct mtd_ooblayout_ops tx58cxgxsxraix_ooblayout = { |
67 | .ecc = tx58cxgxsxraix_ooblayout_ecc, |
68 | .free = tx58cxgxsxraix_ooblayout_free, |
69 | }; |
70 | |
71 | static int tx58cxgxsxraix_ecc_get_status(struct spinand_device *spinand, |
72 | u8 status) |
73 | { |
74 | struct nand_device *nand = spinand_to_nand(spinand); |
75 | u8 mbf = 0; |
76 | struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, spinand->scratchbuf); |
77 | |
78 | switch (status & STATUS_ECC_MASK) { |
79 | case STATUS_ECC_NO_BITFLIPS: |
80 | return 0; |
81 | |
82 | case STATUS_ECC_UNCOR_ERROR: |
83 | return -EBADMSG; |
84 | |
85 | case STATUS_ECC_HAS_BITFLIPS: |
86 | case TOSH_STATUS_ECC_HAS_BITFLIPS_T: |
87 | /* |
88 | * Let's try to retrieve the real maximum number of bitflips |
89 | * in order to avoid forcing the wear-leveling layer to move |
90 | * data around if it's not necessary. |
91 | */ |
92 | if (spi_mem_exec_op(mem: spinand->spimem, op: &op)) |
93 | return nanddev_get_ecc_conf(nand)->strength; |
94 | |
95 | mbf = *(spinand->scratchbuf) >> 4; |
96 | |
97 | if (WARN_ON(mbf > nanddev_get_ecc_conf(nand)->strength || !mbf)) |
98 | return nanddev_get_ecc_conf(nand)->strength; |
99 | |
100 | return mbf; |
101 | |
102 | default: |
103 | break; |
104 | } |
105 | |
106 | return -EINVAL; |
107 | } |
108 | |
109 | static const struct spinand_info toshiba_spinand_table[] = { |
110 | /* 3.3V 1Gb (1st generation) */ |
111 | SPINAND_INFO("TC58CVG0S3HRAIG" , |
112 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2), |
113 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
114 | NAND_ECCREQ(8, 512), |
115 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
116 | &write_cache_variants, |
117 | &update_cache_variants), |
118 | 0, |
119 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
120 | tx58cxgxsxraix_ecc_get_status)), |
121 | /* 3.3V 2Gb (1st generation) */ |
122 | SPINAND_INFO("TC58CVG1S3HRAIG" , |
123 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB), |
124 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
125 | NAND_ECCREQ(8, 512), |
126 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
127 | &write_cache_variants, |
128 | &update_cache_variants), |
129 | 0, |
130 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
131 | tx58cxgxsxraix_ecc_get_status)), |
132 | /* 3.3V 4Gb (1st generation) */ |
133 | SPINAND_INFO("TC58CVG2S0HRAIG" , |
134 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD), |
135 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
136 | NAND_ECCREQ(8, 512), |
137 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
138 | &write_cache_variants, |
139 | &update_cache_variants), |
140 | 0, |
141 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
142 | tx58cxgxsxraix_ecc_get_status)), |
143 | /* 1.8V 1Gb (1st generation) */ |
144 | SPINAND_INFO("TC58CYG0S3HRAIG" , |
145 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2), |
146 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
147 | NAND_ECCREQ(8, 512), |
148 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
149 | &write_cache_variants, |
150 | &update_cache_variants), |
151 | 0, |
152 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
153 | tx58cxgxsxraix_ecc_get_status)), |
154 | /* 1.8V 2Gb (1st generation) */ |
155 | SPINAND_INFO("TC58CYG1S3HRAIG" , |
156 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB), |
157 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
158 | NAND_ECCREQ(8, 512), |
159 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
160 | &write_cache_variants, |
161 | &update_cache_variants), |
162 | 0, |
163 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
164 | tx58cxgxsxraix_ecc_get_status)), |
165 | /* 1.8V 4Gb (1st generation) */ |
166 | SPINAND_INFO("TC58CYG2S0HRAIG" , |
167 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD), |
168 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
169 | NAND_ECCREQ(8, 512), |
170 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
171 | &write_cache_variants, |
172 | &update_cache_variants), |
173 | 0, |
174 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
175 | tx58cxgxsxraix_ecc_get_status)), |
176 | |
177 | /* |
178 | * 2nd generation serial nand has HOLD_D which is equivalent to |
179 | * QE_BIT. |
180 | */ |
181 | /* 3.3V 1Gb (2nd generation) */ |
182 | SPINAND_INFO("TC58CVG0S3HRAIJ" , |
183 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2), |
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_x4_variants, |
188 | &update_cache_x4_variants), |
189 | SPINAND_HAS_QE_BIT, |
190 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
191 | tx58cxgxsxraix_ecc_get_status)), |
192 | /* 3.3V 2Gb (2nd generation) */ |
193 | SPINAND_INFO("TC58CVG1S3HRAIJ" , |
194 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xEB), |
195 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
196 | NAND_ECCREQ(8, 512), |
197 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
198 | &write_cache_x4_variants, |
199 | &update_cache_x4_variants), |
200 | SPINAND_HAS_QE_BIT, |
201 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
202 | tx58cxgxsxraix_ecc_get_status)), |
203 | /* 3.3V 4Gb (2nd generation) */ |
204 | SPINAND_INFO("TC58CVG2S0HRAIJ" , |
205 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xED), |
206 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
207 | NAND_ECCREQ(8, 512), |
208 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
209 | &write_cache_x4_variants, |
210 | &update_cache_x4_variants), |
211 | SPINAND_HAS_QE_BIT, |
212 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
213 | tx58cxgxsxraix_ecc_get_status)), |
214 | /* 3.3V 8Gb (2nd generation) */ |
215 | SPINAND_INFO("TH58CVG3S0HRAIJ" , |
216 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), |
217 | NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), |
218 | NAND_ECCREQ(8, 512), |
219 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
220 | &write_cache_x4_variants, |
221 | &update_cache_x4_variants), |
222 | SPINAND_HAS_QE_BIT, |
223 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
224 | tx58cxgxsxraix_ecc_get_status)), |
225 | /* 1.8V 1Gb (2nd generation) */ |
226 | SPINAND_INFO("TC58CYG0S3HRAIJ" , |
227 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD2), |
228 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
229 | NAND_ECCREQ(8, 512), |
230 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
231 | &write_cache_x4_variants, |
232 | &update_cache_x4_variants), |
233 | SPINAND_HAS_QE_BIT, |
234 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
235 | tx58cxgxsxraix_ecc_get_status)), |
236 | /* 1.8V 2Gb (2nd generation) */ |
237 | SPINAND_INFO("TC58CYG1S3HRAIJ" , |
238 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDB), |
239 | NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1), |
240 | NAND_ECCREQ(8, 512), |
241 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
242 | &write_cache_x4_variants, |
243 | &update_cache_x4_variants), |
244 | SPINAND_HAS_QE_BIT, |
245 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
246 | tx58cxgxsxraix_ecc_get_status)), |
247 | /* 1.8V 4Gb (2nd generation) */ |
248 | SPINAND_INFO("TC58CYG2S0HRAIJ" , |
249 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xDD), |
250 | NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1), |
251 | NAND_ECCREQ(8, 512), |
252 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
253 | &write_cache_x4_variants, |
254 | &update_cache_x4_variants), |
255 | SPINAND_HAS_QE_BIT, |
256 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
257 | tx58cxgxsxraix_ecc_get_status)), |
258 | /* 1.8V 8Gb (2nd generation) */ |
259 | SPINAND_INFO("TH58CYG3S0HRAIJ" , |
260 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xD4), |
261 | NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), |
262 | NAND_ECCREQ(8, 512), |
263 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
264 | &write_cache_x4_variants, |
265 | &update_cache_x4_variants), |
266 | SPINAND_HAS_QE_BIT, |
267 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
268 | tx58cxgxsxraix_ecc_get_status)), |
269 | /* 1.8V 1Gb (1st generation) */ |
270 | SPINAND_INFO("TC58NYG0S3HBAI4" , |
271 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA1), |
272 | NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), |
273 | NAND_ECCREQ(8, 512), |
274 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
275 | &write_cache_variants, |
276 | &update_cache_variants), |
277 | 0, |
278 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
279 | tx58cxgxsxraix_ecc_get_status)), |
280 | /* 1.8V 4Gb (1st generation) */ |
281 | SPINAND_INFO("TH58NYG2S3HBAI4" , |
282 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xAC), |
283 | NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 2, 1), |
284 | NAND_ECCREQ(8, 512), |
285 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
286 | &write_cache_x4_variants, |
287 | &update_cache_x4_variants), |
288 | SPINAND_HAS_QE_BIT, |
289 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
290 | tx58cxgxsxraix_ecc_get_status)), |
291 | /* 1.8V 8Gb (1st generation) */ |
292 | SPINAND_INFO("TH58NYG3S0HBAI6" , |
293 | SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xA3), |
294 | NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1), |
295 | NAND_ECCREQ(8, 512), |
296 | SPINAND_INFO_OP_VARIANTS(&read_cache_variants, |
297 | &write_cache_x4_variants, |
298 | &update_cache_x4_variants), |
299 | SPINAND_HAS_QE_BIT, |
300 | SPINAND_ECCINFO(&tx58cxgxsxraix_ooblayout, |
301 | tx58cxgxsxraix_ecc_get_status)), |
302 | }; |
303 | |
304 | static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = { |
305 | }; |
306 | |
307 | const struct spinand_manufacturer toshiba_spinand_manufacturer = { |
308 | .id = SPINAND_MFR_TOSHIBA, |
309 | .name = "Toshiba" , |
310 | .chips = toshiba_spinand_table, |
311 | .nchips = ARRAY_SIZE(toshiba_spinand_table), |
312 | .ops = &toshiba_spinand_manuf_ops, |
313 | }; |
314 | |