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
6 Backport new features from upstream kernel
8 Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
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
23 --- a/drivers/mtd/nand/spi/Makefile
24 +++ b/drivers/mtd/nand/spi/Makefile
26 # SPDX-License-Identifier: GPL-2.0
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
36 static const struct spinand_manufacturer *spinand_manufacturers[] = {
37 + &etron_spinand_manufacturer,
38 &gigadevice_spinand_manufacturer,
39 ¯onix_spinand_manufacturer,
40 µn_spinand_manufacturer,
42 +++ b/drivers/mtd/nand/spi/etron.c
44 +// SPDX-License-Identifier: GPL-2.0
46 + * Copyright (c) 2020 Etron Technology, Inc.
51 +#include <linux/device.h>
52 +#include <linux/kernel.h>
54 +#include <linux/bug.h>
55 +#include <linux/mtd/spinand.h>
57 +#define SPINAND_MFR_ETRON 0xD5
59 +#define STATUS_ECC_LIMIT_BITFLIPS (3 << 4)
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));
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));
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));
77 +static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
78 + struct mtd_oob_region *region)
83 + region->offset = (14 * section) + 72;
84 + region->length = 14;
89 +static int etron_ooblayout_free(struct mtd_info *mtd, int section,
90 + struct mtd_oob_region *region)
96 + region->offset = 18 * section;
97 + region->length = 18;
99 + /* section 0 has one byte reserved for bad block mark */
100 + region->offset = 2;
101 + region->length = 16;
106 +static const struct mtd_ooblayout_ops etron_ooblayout = {
107 + .ecc = etron_ooblayout_ecc,
108 + .rfree = etron_ooblayout_free,
111 +static int etron_ecc_get_status(struct spinand_device *spinand,
114 + struct nand_device *nand = spinand_to_nand(spinand);
116 + switch (status & STATUS_ECC_MASK) {
117 + case STATUS_ECC_NO_BITFLIPS:
120 + case STATUS_ECC_UNCOR_ERROR:
123 + case STATUS_ECC_HAS_BITFLIPS:
124 + return nand->eccreq.strength >> 1;
126 + case STATUS_ECC_LIMIT_BITFLIPS:
127 + return nand->eccreq.strength;
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)),
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)),
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)),
215 +static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
218 +const struct spinand_manufacturer etron_spinand_manufacturer = {
219 + .id = SPINAND_MFR_ETRON,
221 + .chips = etron_spinand_table,
222 + .nchips = ARRAY_SIZE(etron_spinand_table),
223 + .ops = &etron_spinand_manuf_ops,
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));
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));
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));
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(
256 +static int esmt_1_ooblayout_ecc(struct mtd_info *mtd, int section,
257 + struct mtd_oob_region *region)
262 + region->offset = (16 * section) + 8;
263 + region->length = 8;
268 +static int esmt_1_ooblayout_free(struct mtd_info *mtd, int section,
269 + struct mtd_oob_region *region)
274 + region->offset = (16 * section) + 2;
275 + region->length = 6;
280 +static const struct mtd_ooblayout_ops esmt_1_ooblayout = {
281 + .ecc = esmt_1_ooblayout_ecc,
282 + .rfree = esmt_1_ooblayout_free,
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),
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
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)),
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
390 #define WINBOND_CFG_BUF_READ BIT(3)
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)
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)
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)
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));
416 +static int w25n02kv_n04kv_ooblayout_ecc(struct mtd_info *mtd, int section,
417 + struct mtd_oob_region *region)
422 + region->offset = (16 * section) + 64;
423 + region->length = 16;
428 +static int w25n02kv_n04kv_ooblayout_free(struct mtd_info *mtd, int section,
429 + struct mtd_oob_region *region)
434 + region->offset = (16 * section) + 2;
435 + region->length = 14;
440 +static const struct mtd_ooblayout_ops w25n02kv_n04kv_ooblayout = {
441 + .ecc = w25n02kv_n04kv_ooblayout_ecc,
442 + .rfree = w25n02kv_n04kv_ooblayout_free,
445 static int w25m02gv_ooblayout_ecc(struct mtd_info *mtd, int section,
446 struct mtd_oob_region *region)
448 @@ -106,6 +152,58 @@ static const struct mtd_ooblayout_ops w2
449 .rfree = w25n02kv_ooblayout_free,
452 +static int w25n01kv_ecc_get_status(struct spinand_device *spinand,
455 + switch (status & W25N01KV_STATUS_ECC_MASK) {
456 + case W25N01KV_STATUS_ECC_NO_BITFLIPS:
459 + case W25N01KV_STATUS_ECC_1_3_BITFLIPS:
462 + case W25N01KV_STATUS_ECC_4_BITFLIPS:
465 + case W25N01KV_STATUS_ECC_UNCOR_ERROR:
475 +static int w25n02kv_n04kv_ecc_get_status(struct spinand_device *spinand,
478 + switch (status & W25N02_N04KV_STATUS_ECC_MASK) {
479 + case W25N02_N04KV_STATUS_ECC_NO_BITFLIPS:
482 + case W25N02_N04KV_STATUS_ECC_1_4_BITFLIPS:
485 + case W25N02_N04KV_STATUS_ECC_5_8_BITFLIPS:
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.
494 + case W25N02_N04KV_STATUS_ECC_UNCOR_ERROR:
504 static int w25n02kv_ecc_get_status(struct spinand_device *spinand,
507 @@ -163,6 +261,15 @@ static const struct spinand_info winbond
508 &update_cache_variants),
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),
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),
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),
535 + SPINAND_ECCINFO(&w25n02kv_n04kv_ooblayout,
536 + w25n02kv_n04kv_ecc_get_status)),
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 {
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;