uboot-mediatek: update to U-Boot 2024.01 release
[openwrt/staging/jow.git] / package / boot / uboot-mediatek / patches / 100-22-mtd-spi-nand-backport-from-upstream-kernel.patch
1 From 8d0665327819c41fce2c8d50f19c967b22eae564 Mon Sep 17 00:00:00 2001
2 From: Weijie Gao <weijie.gao@mediatek.com>
3 Date: Wed, 27 Jul 2022 16:36:13 +0800
4 Subject: [PATCH 57/71] mtd: spi-nand: backport from upstream kernel
5
6 Backport new features from upstream kernel
7
8 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
9 ---
10 drivers/mtd/nand/spi/Kconfig | 1 +
11 drivers/mtd/nand/spi/Makefile | 2 +-
12 drivers/mtd/nand/spi/core.c | 102 ++++++----
13 drivers/mtd/nand/spi/etron.c | 181 +++++++++++++++++
14 drivers/mtd/nand/spi/gigadevice.c | 322 ++++++++++++++++++++++++++----
15 drivers/mtd/nand/spi/macronix.c | 173 +++++++++++++---
16 drivers/mtd/nand/spi/micron.c | 50 ++---
17 drivers/mtd/nand/spi/toshiba.c | 66 +++---
18 drivers/mtd/nand/spi/winbond.c | 164 ++++++++++++---
19 include/linux/mtd/spinand.h | 87 +++++---
20 10 files changed, 923 insertions(+), 225 deletions(-)
21 create mode 100644 drivers/mtd/nand/spi/etron.c
22
23 --- a/drivers/mtd/nand/spi/Makefile
24 +++ b/drivers/mtd/nand/spi/Makefile
25 @@ -1,4 +1,4 @@
26 # SPDX-License-Identifier: GPL-2.0
27
28 -spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
29 +spinand-objs := core.o etron.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
30 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
31 --- a/drivers/mtd/nand/spi/core.c
32 +++ b/drivers/mtd/nand/spi/core.c
33 @@ -822,6 +822,7 @@ static const struct nand_ops spinand_ops
34 };
35
36 static const struct spinand_manufacturer *spinand_manufacturers[] = {
37 + &etron_spinand_manufacturer,
38 &gigadevice_spinand_manufacturer,
39 &macronix_spinand_manufacturer,
40 &micron_spinand_manufacturer,
41 --- /dev/null
42 +++ b/drivers/mtd/nand/spi/etron.c
43 @@ -0,0 +1,181 @@
44 +// SPDX-License-Identifier: GPL-2.0
45 +/*
46 + * Copyright (c) 2020 Etron Technology, Inc.
47 + *
48 + */
49 +#ifndef __UBOOT__
50 +#include <malloc.h>
51 +#include <linux/device.h>
52 +#include <linux/kernel.h>
53 +#endif
54 +#include <linux/bug.h>
55 +#include <linux/mtd/spinand.h>
56 +
57 +#define SPINAND_MFR_ETRON 0xD5
58 +
59 +#define STATUS_ECC_LIMIT_BITFLIPS (3 << 4)
60 +
61 +static SPINAND_OP_VARIANTS(read_cache_variants,
62 + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
63 + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
64 + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
65 + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
66 + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
67 + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
68 +
69 +static SPINAND_OP_VARIANTS(write_cache_variants,
70 + SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
71 + SPINAND_PROG_LOAD(true, 0, NULL, 0));
72 +
73 +static SPINAND_OP_VARIANTS(update_cache_variants,
74 + SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
75 + SPINAND_PROG_LOAD(false, 0, NULL, 0));
76 +
77 +static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
78 + struct mtd_oob_region *region)
79 +{
80 + if (section > 3)
81 + return -ERANGE;
82 +
83 + region->offset = (14 * section) + 72;
84 + region->length = 14;
85 +
86 + return 0;
87 +}
88 +
89 +static int etron_ooblayout_free(struct mtd_info *mtd, int section,
90 + struct mtd_oob_region *region)
91 +{
92 + if (section > 3)
93 + return -ERANGE;
94 +
95 + if (section) {
96 + region->offset = 18 * section;
97 + region->length = 18;
98 + } else {
99 + /* section 0 has one byte reserved for bad block mark */
100 + region->offset = 2;
101 + region->length = 16;
102 + }
103 + return 0;
104 +}
105 +
106 +static const struct mtd_ooblayout_ops etron_ooblayout = {
107 + .ecc = etron_ooblayout_ecc,
108 + .rfree = etron_ooblayout_free,
109 +};
110 +
111 +static int etron_ecc_get_status(struct spinand_device *spinand,
112 + u8 status)
113 +{
114 + struct nand_device *nand = spinand_to_nand(spinand);
115 +
116 + switch (status & STATUS_ECC_MASK) {
117 + case STATUS_ECC_NO_BITFLIPS:
118 + return 0;
119 +
120 + case STATUS_ECC_UNCOR_ERROR:
121 + return -EBADMSG;
122 +
123 + case STATUS_ECC_HAS_BITFLIPS:
124 + return nand->eccreq.strength >> 1;
125 +
126 + case STATUS_ECC_LIMIT_BITFLIPS:
127 + return nand->eccreq.strength;
128 +
129 + default:
130 + break;
131 + }
132 +
133 + return -EINVAL;
134 +}
135 +
136 +static const struct spinand_info etron_spinand_table[] = {
137 + /* EM73C 1Gb 3.3V */
138 + SPINAND_INFO("EM73C044VCF",
139 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x25),
140 + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
141 + NAND_ECCREQ(4, 512),
142 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
143 + &write_cache_variants,
144 + &update_cache_variants),
145 + SPINAND_HAS_QE_BIT,
146 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
147 + /* EM7xD 2Gb */
148 + SPINAND_INFO("EM73D044VCR",
149 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x41),
150 + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
151 + NAND_ECCREQ(4, 512),
152 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
153 + &write_cache_variants,
154 + &update_cache_variants),
155 + SPINAND_HAS_QE_BIT,
156 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
157 + SPINAND_INFO("EM73D044VCO",
158 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3A),
159 + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
160 + NAND_ECCREQ(8, 512),
161 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
162 + &write_cache_variants,
163 + &update_cache_variants),
164 + SPINAND_HAS_QE_BIT,
165 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
166 + SPINAND_INFO("EM78D044VCM",
167 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8E),
168 + NAND_MEMORG(1, 2048, 128, 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 + SPINAND_HAS_QE_BIT,
174 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
175 + /* EM7xE 4Gb */
176 + SPINAND_INFO("EM73E044VCE",
177 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x3B),
178 + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
179 + NAND_ECCREQ(8, 512),
180 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
181 + &write_cache_variants,
182 + &update_cache_variants),
183 + SPINAND_HAS_QE_BIT,
184 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
185 + SPINAND_INFO("EM78E044VCD",
186 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x8F),
187 + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
188 + NAND_ECCREQ(8, 512),
189 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
190 + &write_cache_variants,
191 + &update_cache_variants),
192 + SPINAND_HAS_QE_BIT,
193 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
194 + /* EM7xF044VCA 8Gb */
195 + SPINAND_INFO("EM73F044VCA",
196 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x15),
197 + NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
198 + NAND_ECCREQ(8, 512),
199 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
200 + &write_cache_variants,
201 + &update_cache_variants),
202 + SPINAND_HAS_QE_BIT,
203 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
204 + SPINAND_INFO("EM78F044VCA",
205 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x8D),
206 + NAND_MEMORG(1, 4096, 256, 64, 4096, 80, 1, 1, 1),
207 + NAND_ECCREQ(8, 512),
208 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
209 + &write_cache_variants,
210 + &update_cache_variants),
211 + SPINAND_HAS_QE_BIT,
212 + SPINAND_ECCINFO(&etron_ooblayout, etron_ecc_get_status)),
213 +};
214 +
215 +static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
216 +};
217 +
218 +const struct spinand_manufacturer etron_spinand_manufacturer = {
219 + .id = SPINAND_MFR_ETRON,
220 + .name = "Etron",
221 + .chips = etron_spinand_table,
222 + .nchips = ARRAY_SIZE(etron_spinand_table),
223 + .ops = &etron_spinand_manuf_ops,
224 +};
225 --- a/drivers/mtd/nand/spi/gigadevice.c
226 +++ b/drivers/mtd/nand/spi/gigadevice.c
227 @@ -43,6 +43,24 @@ static SPINAND_OP_VARIANTS(read_cache_va
228 SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
229 SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
230
231 +/* Q5 1Gb */
232 +static SPINAND_OP_VARIANTS(dummy2_read_cache_variants,
233 + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
234 + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
235 + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
236 + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
237 + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
238 + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
239 +
240 +/* Q5 2Gb & 4Gb */
241 +static SPINAND_OP_VARIANTS(dummy4_read_cache_variants,
242 + SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
243 + SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
244 + SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
245 + SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
246 + SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
247 + SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
248 +
249 static SPINAND_OP_VARIANTS(write_cache_variants,
250 SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
251 SPINAND_PROG_LOAD(true, 0, NULL, 0));
252 @@ -268,7 +286,45 @@ static int gd5fxgq4ufxxg_ecc_get_status(
253 return -EINVAL;
254 }
255
256 +static int esmt_1_ooblayout_ecc(struct mtd_info *mtd, int section,
257 + struct mtd_oob_region *region)
258 +{
259 + if (section > 3)
260 + return -ERANGE;
261 +
262 + region->offset = (16 * section) + 8;
263 + region->length = 8;
264 +
265 + return 0;
266 +}
267 +
268 +static int esmt_1_ooblayout_free(struct mtd_info *mtd, int section,
269 + struct mtd_oob_region *region)
270 +{
271 + if (section > 3)
272 + return -ERANGE;
273 +
274 + region->offset = (16 * section) + 2;
275 + region->length = 6;
276 +
277 + return 0;
278 +}
279 +
280 +static const struct mtd_ooblayout_ops esmt_1_ooblayout = {
281 + .ecc = esmt_1_ooblayout_ecc,
282 + .rfree = esmt_1_ooblayout_free,
283 + };
284 +
285 static const struct spinand_info gigadevice_spinand_table[] = {
286 + SPINAND_INFO("F50L1G41LB",
287 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
288 + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
289 + NAND_ECCREQ(8, 512),
290 + SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
291 + &write_cache_variants,
292 + &update_cache_variants),
293 + 0,
294 + SPINAND_ECCINFO(&esmt_1_ooblayout, NULL)),
295 SPINAND_INFO("GD5F1GQ4xA",
296 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
297 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
298 @@ -349,6 +405,87 @@ static const struct spinand_info gigadev
299 SPINAND_HAS_QE_BIT,
300 SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
301 gd5fxgq5xexxg_ecc_get_status)),
302 + SPINAND_INFO("GD5F2GQ5UExxG",
303 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
304 + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
305 + NAND_ECCREQ(4, 512),
306 + SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
307 + &write_cache_variants,
308 + &update_cache_variants),
309 + SPINAND_HAS_QE_BIT,
310 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
311 + gd5fxgq5xexxg_ecc_get_status)),
312 + SPINAND_INFO("GD5F4GQ6UExxG",
313 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x55),
314 + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
315 + NAND_ECCREQ(4, 512),
316 + SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
317 + &write_cache_variants,
318 + &update_cache_variants),
319 + SPINAND_HAS_QE_BIT,
320 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
321 + gd5fxgq5xexxg_ecc_get_status)),
322 + SPINAND_INFO("GD5F1GM7UExxG",
323 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x91),
324 + NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
325 + NAND_ECCREQ(8, 512),
326 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
327 + &write_cache_variants,
328 + &update_cache_variants),
329 + SPINAND_HAS_QE_BIT,
330 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
331 + gd5fxgq4uexxg_ecc_get_status)),
332 + SPINAND_INFO("GD5F2GM7UExxG",
333 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x92),
334 + NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
335 + NAND_ECCREQ(8, 512),
336 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
337 + &write_cache_variants,
338 + &update_cache_variants),
339 + SPINAND_HAS_QE_BIT,
340 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
341 + gd5fxgq4uexxg_ecc_get_status)),
342 + SPINAND_INFO("GD5F4GM8UExxG",
343 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x95),
344 + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
345 + NAND_ECCREQ(8, 512),
346 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
347 + &write_cache_variants,
348 + &update_cache_variants),
349 + SPINAND_HAS_QE_BIT,
350 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
351 + gd5fxgq4uexxg_ecc_get_status)),
352 + SPINAND_INFO("GD5F1GQ5UExxH",
353 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x31),
354 + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
355 + NAND_ECCREQ(4, 512),
356 + SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
357 + &write_cache_variants,
358 + &update_cache_variants),
359 + SPINAND_HAS_QE_BIT,
360 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
361 + gd5fxgq5xexxg_ecc_get_status)),
362 + SPINAND_INFO("GD5F2GQ5UExxH",
363 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
364 + NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
365 + NAND_ECCREQ(4, 512),
366 + SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
367 + &write_cache_variants,
368 + &update_cache_variants),
369 + SPINAND_HAS_QE_BIT,
370 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
371 + gd5fxgq5xexxg_ecc_get_status)),
372 + SPINAND_INFO("GD5F4GQ6UExxH",
373 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
374 + NAND_MEMORG(1, 2048, 64, 64, 4096, 40, 1, 1, 1),
375 + NAND_ECCREQ(4, 512),
376 + SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
377 + &write_cache_variants,
378 + &update_cache_variants),
379 + SPINAND_HAS_QE_BIT,
380 + SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
381 + gd5fxgq5xexxg_ecc_get_status)),
382 +
383 };
384
385 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
386 --- a/drivers/mtd/nand/spi/winbond.c
387 +++ b/drivers/mtd/nand/spi/winbond.c
388 @@ -18,6 +18,23 @@
389
390 #define WINBOND_CFG_BUF_READ BIT(3)
391
392 +#define W25N02_N04KV_STATUS_ECC_MASK (3 << 4)
393 +#define W25N02_N04KV_STATUS_ECC_NO_BITFLIPS (0 << 4)
394 +#define W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS (1 << 4)
395 +#define W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS (3 << 4)
396 +#define W25N02_N04KV_STATUS_ECC_UNCOR_ERROR (2 << 4)
397 +
398 +#define W25N01_M02GV_STATUS_ECC_MASK (3 << 4)
399 +#define W25N01_M02GV_STATUS_ECC_NO_BITFLIPS (0 << 4)
400 +#define W25N01_M02GV_STATUS_ECC_1_BITFLIPS (1 << 4)
401 +#define W25N01_M02GV_STATUS_ECC_UNCOR_ERROR (2 << 4)
402 +
403 +#define W25N01KV_STATUS_ECC_MASK (3 << 4)
404 +#define W25N01KV_STATUS_ECC_NO_BITFLIPS (0 << 4)
405 +#define W25N01KV_STATUS_ECC_1_3_BITFLIPS (1 << 4)
406 +#define W25N01KV_STATUS_ECC_4_BITFLIPS (3 << 4)
407 +#define W25N01KV_STATUS_ECC_UNCOR_ERROR (2 << 4)
408 +
409 static SPINAND_OP_VARIANTS(read_cache_variants,
410 SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
411 SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
412 @@ -34,6 +51,35 @@ static SPINAND_OP_VARIANTS(update_cache_
413 SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
414 SPINAND_PROG_LOAD(false, 0, NULL, 0));
415
416 +static int w25n02kv_n04kv_ooblayout_ecc(struct mtd_info *mtd, int section,
417 + struct mtd_oob_region *region)
418 +{
419 + if (section > 3)
420 + return -ERANGE;
421 +
422 + region->offset = (16 * section) + 64;
423 + region->length = 16;
424 +
425 + return 0;
426 +}
427 +
428 +static int w25n02kv_n04kv_ooblayout_free(struct mtd_info *mtd, int section,
429 + struct mtd_oob_region *region)
430 +{
431 + if (section > 3)
432 + return -ERANGE;
433 +
434 + region->offset = (16 * section) + 2;
435 + region->length = 14;
436 +
437 + return 0;
438 +}
439 +
440 +static const struct mtd_ooblayout_ops w25n02kv_n04kv_ooblayout = {
441 + .ecc = w25n02kv_n04kv_ooblayout_ecc,
442 + .rfree = w25n02kv_n04kv_ooblayout_free,
443 +};
444 +
445 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
446 struct mtd_oob_region *region)
447 {
448 @@ -106,6 +152,58 @@ static const struct mtd_ooblayout_ops w2
449 .rfree = w25n02kv_ooblayout_free,
450 };
451
452 +static int w25n01kv_ecc_get_status(struct spinand_device *spinand,
453 + u8 status)
454 +{
455 + switch (status & W25N01KV_STATUS_ECC_MASK) {
456 + case W25N01KV_STATUS_ECC_NO_BITFLIPS:
457 + return 0;
458 +
459 + case W25N01KV_STATUS_ECC_1_3_BITFLIPS:
460 + return 3;
461 +
462 + case W25N01KV_STATUS_ECC_4_BITFLIPS:
463 + return 4;
464 +
465 + case W25N01KV_STATUS_ECC_UNCOR_ERROR:
466 + return -EBADMSG;
467 +
468 + default:
469 + break;
470 + }
471 +
472 + return -EINVAL;
473 +}
474 +
475 +static int w25n02kv_n04kv_ecc_get_status(struct spinand_device *spinand,
476 + u8 status)
477 +{
478 + switch (status & W25N02_N04KV_STATUS_ECC_MASK) {
479 + case W25N02_N04KV_STATUS_ECC_NO_BITFLIPS:
480 + return 0;
481 +
482 + case W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS:
483 + return 3;
484 +
485 + case W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS:
486 + return 4;
487 +
488 + /* W25N02_N04KV_use internal 8bit ECC algorithm.
489 + * But the ECC strength is 4 bit requried.
490 + * Return 3 if the bit bit flip count less than 5.
491 + * Return 4 if the bit bit flip count more than 5 to 8.
492 + */
493 +
494 + case W25N02_N04KV_STATUS_ECC_UNCOR_ERROR:
495 + return -EBADMSG;
496 +
497 + default:
498 + break;
499 + }
500 +
501 + return -EINVAL;
502 +}
503 +
504 static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
505 u8 status)
506 {
507 @@ -163,6 +261,15 @@ static const struct spinand_info winbond
508 &update_cache_variants),
509 0,
510 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
511 + SPINAND_INFO("W25N01KV",
512 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xae, 0x21),
513 + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
514 + NAND_ECCREQ(4, 512),
515 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
516 + &write_cache_variants,
517 + &update_cache_variants),
518 + 0,
519 + SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout, w25n01kv_ecc_get_status)),
520 SPINAND_INFO("W25N02KV",
521 SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x22),
522 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
523 @@ -172,6 +279,16 @@ static const struct spinand_info winbond
524 &update_cache_variants),
525 0,
526 SPINAND_ECCINFO(&w25n02kv_ooblayout, w25n02kv_ecc_get_status)),
527 + SPINAND_INFO("W25N04KV",
528 + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa, 0x23),
529 + NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 2, 1, 1),
530 + NAND_ECCREQ(4, 512),
531 + SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
532 + &write_cache_variants,
533 + &update_cache_variants),
534 + 0,
535 + SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
536 + w25n02kv_n04kv_ecc_get_status)),
537 };
538
539 static int winbond_spinand_init(struct spinand_device *spinand)
540 --- a/include/linux/mtd/spinand.h
541 +++ b/include/linux/mtd/spinand.h
542 @@ -245,6 +245,7 @@ struct spinand_manufacturer {
543 };
544
545 /* SPI NAND manufacturers */
546 +extern const struct spinand_manufacturer etron_spinand_manufacturer;
547 extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
548 extern const struct spinand_manufacturer macronix_spinand_manufacturer;
549 extern const struct spinand_manufacturer micron_spinand_manufacturer;