blob: f9c3542a4c41a55dc0d5119dc10c2690e9d97d57 [file] [log] [blame]
developer5d148cb2023-06-02 13:08:11 +08001From 0aeb63ff705a42b9140cad179ebe7f5fc54d285c Mon Sep 17 00:00:00 2001
2From: Sam Shih <sam.shih@mediatek.com>
3Date: Fri, 2 Jun 2023 13:06:09 +0800
4Subject: [PATCH]
5 [spi-and-storage][999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch]
6
7---
8 drivers/mtd/nand/spi/core.c | 86 ++++++++++++++++++++++---------
9 drivers/mtd/nand/spi/gigadevice.c | 45 +++++-----------
10 drivers/mtd/nand/spi/macronix.c | 30 +++--------
11 drivers/mtd/nand/spi/micron.c | 26 ++--------
12 drivers/mtd/nand/spi/paragon.c | 28 +++-------
13 drivers/mtd/nand/spi/toshiba.c | 42 +++++----------
14 drivers/mtd/nand/spi/winbond.c | 34 +++---------
15 include/linux/mtd/spinand.h | 66 ++++++++++++++++--------
16 8 files changed, 155 insertions(+), 202 deletions(-)
17
18diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
19index 55e636efc..9f5f95ff7 100644
developer41370d52022-03-16 16:01:59 +080020--- a/drivers/mtd/nand/spi/core.c
21+++ b/drivers/mtd/nand/spi/core.c
22@@ -16,6 +16,7 @@
23 #include <linux/mtd/spinand.h>
24 #include <linux/of.h>
25 #include <linux/slab.h>
26+#include <linux/string.h>
27 #include <linux/spi/spi.h>
28 #include <linux/spi/spi-mem.h>
29
30@@ -370,10 +371,11 @@ out:
31 return status & STATUS_BUSY ? -ETIMEDOUT : 0;
32 }
33
34-static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
35+static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
36+ u8 ndummy, u8 *buf)
37 {
38- struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
39- SPINAND_MAX_ID_LEN);
40+ struct spi_mem_op op = SPINAND_READID_OP(
41+ naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
42 int ret;
43
44 ret = spi_mem_exec_op(spinand->spimem, &op);
developer5d148cb2023-06-02 13:08:11 +080045@@ -760,24 +762,62 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = {
developer41370d52022-03-16 16:01:59 +080046 &winbond_spinand_manufacturer,
47 };
48
49-static int spinand_manufacturer_detect(struct spinand_device *spinand)
50+static int spinand_manufacturer_match(struct spinand_device *spinand,
51+ enum spinand_readid_method rdid_method)
52 {
53+ u8 *id = spinand->id.data;
54 unsigned int i;
55 int ret;
56
57 for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
58- ret = spinand_manufacturers[i]->ops->detect(spinand);
59- if (ret > 0) {
60- spinand->manufacturer = spinand_manufacturers[i];
61- return 0;
62- } else if (ret < 0) {
63- return ret;
64- }
65- }
66+ const struct spinand_manufacturer *manufacturer =
67+ spinand_manufacturers[i];
68+
69+ if (id[0] != manufacturer->id)
70+ continue;
71
72+ ret = spinand_match_and_init(spinand,
73+ manufacturer->chips,
74+ manufacturer->nchips,
75+ rdid_method);
76+ if (ret < 0)
77+ continue;
78+
79+ spinand->manufacturer = manufacturer;
80+ return 0;
81+ }
82 return -ENOTSUPP;
83 }
84
85+static int spinand_id_detect(struct spinand_device *spinand)
86+{
87+ u8 *id = spinand->id.data;
88+ int ret;
89+
90+ ret = spinand_read_id_op(spinand, 0, 0, id);
91+ if (ret)
92+ return ret;
93+ ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE);
94+ if (!ret)
95+ return 0;
96+
97+ ret = spinand_read_id_op(spinand, 1, 0, id);
98+ if (ret)
99+ return ret;
100+ ret = spinand_manufacturer_match(spinand,
101+ SPINAND_READID_METHOD_OPCODE_ADDR);
102+ if (!ret)
103+ return 0;
104+
105+ ret = spinand_read_id_op(spinand, 0, 1, id);
106+ if (ret)
107+ return ret;
108+ ret = spinand_manufacturer_match(spinand,
109+ SPINAND_READID_METHOD_OPCODE_DUMMY);
110+
111+ return ret;
112+}
113+
114 static int spinand_manufacturer_init(struct spinand_device *spinand)
115 {
116 if (spinand->manufacturer->ops->init)
developer5d148cb2023-06-02 13:08:11 +0800117@@ -833,9 +873,9 @@ spinand_select_op_variant(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800118 * @spinand: SPI NAND object
119 * @table: SPI NAND device description table
120 * @table_size: size of the device description table
121+ * @rdid_method: read id method to match
122 *
123- * Should be used by SPI NAND manufacturer drivers when they want to find a
124- * match between a device ID retrieved through the READ_ID command and an
125+ * Match between a device ID retrieved through the READ_ID command and an
126 * entry in the SPI NAND description table. If a match is found, the spinand
127 * object will be initialized with information provided by the matching
128 * spinand_info entry.
developer5d148cb2023-06-02 13:08:11 +0800129@@ -844,8 +884,10 @@ spinand_select_op_variant(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800130 */
131 int spinand_match_and_init(struct spinand_device *spinand,
132 const struct spinand_info *table,
133- unsigned int table_size, u16 devid)
134+ unsigned int table_size,
135+ enum spinand_readid_method rdid_method)
136 {
137+ u8 *id = spinand->id.data;
138 struct nand_device *nand = spinand_to_nand(spinand);
139 unsigned int i;
140
developer5d148cb2023-06-02 13:08:11 +0800141@@ -853,13 +895,17 @@ int spinand_match_and_init(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800142 const struct spinand_info *info = &table[i];
143 const struct spi_mem_op *op;
144
145- if (devid != info->devid)
146+ if (rdid_method != info->devid.method)
147+ continue;
148+
149+ if (memcmp(id + 1, info->devid.id, info->devid.len))
150 continue;
151
152 nand->memorg = table[i].memorg;
153 nand->eccreq = table[i].eccreq;
154 spinand->eccinfo = table[i].eccinfo;
155 spinand->flags = table[i].flags;
156+ spinand->id.len = 1 + table[i].devid.len;
157 spinand->select_target = table[i].select_target;
158
159 op = spinand_select_op_variant(spinand,
developer5d148cb2023-06-02 13:08:11 +0800160@@ -896,13 +942,7 @@ static int spinand_detect(struct spinand_device *spinand)
developer41370d52022-03-16 16:01:59 +0800161 if (ret)
162 return ret;
163
164- ret = spinand_read_id_op(spinand, spinand->id.data);
165- if (ret)
166- return ret;
167-
168- spinand->id.len = SPINAND_MAX_ID_LEN;
169-
170- ret = spinand_manufacturer_detect(spinand);
171+ ret = spinand_id_detect(spinand);
172 if (ret) {
173 dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
174 spinand->id.data);
developer5d148cb2023-06-02 13:08:11 +0800175diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
176index b13b39763..a34c5ede1 100644
developer41370d52022-03-16 16:01:59 +0800177--- a/drivers/mtd/nand/spi/gigadevice.c
178+++ b/drivers/mtd/nand/spi/gigadevice.c
developer5d148cb2023-06-02 13:08:11 +0800179@@ -195,7 +195,8 @@ static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800180 }
181
182 static const struct spinand_info gigadevice_spinand_table[] = {
183- SPINAND_INFO("GD5F1GQ4xA", 0xF1,
184+ SPINAND_INFO("GD5F1GQ4xA",
185+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
186 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
187 NAND_ECCREQ(8, 512),
188 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800189@@ -204,7 +205,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800190 SPINAND_HAS_QE_BIT,
191 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
192 gd5fxgq4xa_ecc_get_status)),
193- SPINAND_INFO("GD5F2GQ4xA", 0xF2,
194+ SPINAND_INFO("GD5F2GQ4xA",
195+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
196 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
197 NAND_ECCREQ(8, 512),
198 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800199@@ -213,7 +215,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800200 SPINAND_HAS_QE_BIT,
201 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
202 gd5fxgq4xa_ecc_get_status)),
203- SPINAND_INFO("GD5F4GQ4xA", 0xF4,
204+ SPINAND_INFO("GD5F4GQ4xA",
205+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
206 NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
207 NAND_ECCREQ(8, 512),
208 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800209@@ -222,7 +225,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800210 SPINAND_HAS_QE_BIT,
211 SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
212 gd5fxgq4xa_ecc_get_status)),
213- SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
214+ SPINAND_INFO("GD5F1GQ4UExxG",
215+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
216 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
217 NAND_ECCREQ(8, 512),
218 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800219@@ -231,7 +235,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800220 SPINAND_HAS_QE_BIT,
221 SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
222 gd5fxgq4uexxg_ecc_get_status)),
223- SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
224+ SPINAND_INFO("GD5F1GQ4UFxxG",
225+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
226 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
227 NAND_ECCREQ(8, 512),
228 SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
developer5d148cb2023-06-02 13:08:11 +0800229@@ -242,39 +247,13 @@ static const struct spinand_info gigadevice_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800230 gd5fxgq4ufxxg_ecc_get_status)),
231 };
232
233-static int gigadevice_spinand_detect(struct spinand_device *spinand)
234-{
235- u8 *id = spinand->id.data;
236- u16 did;
237- int ret;
238-
239- /*
240- * Earlier GDF5-series devices (A,E) return [0][MID][DID]
241- * Later (F) devices return [MID][DID1][DID2]
242- */
243-
244- if (id[0] == SPINAND_MFR_GIGADEVICE)
245- did = (id[1] << 8) + id[2];
246- else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
247- did = id[2];
248- else
249- return 0;
250-
251- ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
252- ARRAY_SIZE(gigadevice_spinand_table),
253- did);
254- if (ret)
255- return ret;
256-
257- return 1;
258-}
259-
260 static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
261- .detect = gigadevice_spinand_detect,
262 };
263
264 const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
265 .id = SPINAND_MFR_GIGADEVICE,
266 .name = "GigaDevice",
267+ .chips = gigadevice_spinand_table,
268+ .nchips = ARRAY_SIZE(gigadevice_spinand_table),
269 .ops = &gigadevice_spinand_manuf_ops,
270 };
developer5d148cb2023-06-02 13:08:11 +0800271diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
272index 21def3f8f..0f900f3aa 100644
developer41370d52022-03-16 16:01:59 +0800273--- a/drivers/mtd/nand/spi/macronix.c
274+++ b/drivers/mtd/nand/spi/macronix.c
developer5d148cb2023-06-02 13:08:11 +0800275@@ -99,7 +99,8 @@ static int mx35lf1ge4ab_ecc_get_status(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800276 }
277
278 static const struct spinand_info macronix_spinand_table[] = {
279- SPINAND_INFO("MX35LF1GE4AB", 0x12,
280+ SPINAND_INFO("MX35LF1GE4AB",
281+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x12),
282 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
283 NAND_ECCREQ(4, 512),
284 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800285@@ -108,7 +109,8 @@ static const struct spinand_info macronix_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800286 SPINAND_HAS_QE_BIT,
287 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
288 mx35lf1ge4ab_ecc_get_status)),
289- SPINAND_INFO("MX35LF2GE4AB", 0x22,
290+ SPINAND_INFO("MX35LF2GE4AB",
291+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x22),
292 NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
293 NAND_ECCREQ(4, 512),
294 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800295@@ -118,33 +120,13 @@ static const struct spinand_info macronix_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800296 SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
297 };
298
299-static int macronix_spinand_detect(struct spinand_device *spinand)
300-{
301- u8 *id = spinand->id.data;
302- int ret;
303-
304- /*
305- * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
306- * raw_id is garbage.
307- */
308- if (id[1] != SPINAND_MFR_MACRONIX)
309- return 0;
310-
311- ret = spinand_match_and_init(spinand, macronix_spinand_table,
312- ARRAY_SIZE(macronix_spinand_table),
313- id[2]);
314- if (ret)
315- return ret;
316-
317- return 1;
318-}
319-
320 static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
321- .detect = macronix_spinand_detect,
322 };
323
324 const struct spinand_manufacturer macronix_spinand_manufacturer = {
325 .id = SPINAND_MFR_MACRONIX,
326 .name = "Macronix",
327+ .chips = macronix_spinand_table,
328+ .nchips = ARRAY_SIZE(macronix_spinand_table),
329 .ops = &macronix_spinand_manuf_ops,
330 };
developer5d148cb2023-06-02 13:08:11 +0800331diff --git a/drivers/mtd/nand/spi/micron.c b/drivers/mtd/nand/spi/micron.c
332index 7d7b1f7fc..f56f81325 100644
developer41370d52022-03-16 16:01:59 +0800333--- a/drivers/mtd/nand/spi/micron.c
334+++ b/drivers/mtd/nand/spi/micron.c
developer5d148cb2023-06-02 13:08:11 +0800335@@ -91,7 +91,8 @@ static int mt29f2g01abagd_ecc_get_status(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800336 }
337
338 static const struct spinand_info micron_spinand_table[] = {
339- SPINAND_INFO("MT29F2G01ABAGD", 0x24,
340+ SPINAND_INFO("MT29F2G01ABAGD",
341+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
342 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
343 NAND_ECCREQ(8, 512),
344 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800345@@ -102,32 +103,13 @@ static const struct spinand_info micron_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800346 mt29f2g01abagd_ecc_get_status)),
347 };
348
349-static int micron_spinand_detect(struct spinand_device *spinand)
350-{
351- u8 *id = spinand->id.data;
352- int ret;
353-
354- /*
355- * Micron SPI NAND read ID need a dummy byte,
356- * so the first byte in raw_id is dummy.
357- */
358- if (id[1] != SPINAND_MFR_MICRON)
359- return 0;
360-
361- ret = spinand_match_and_init(spinand, micron_spinand_table,
362- ARRAY_SIZE(micron_spinand_table), id[2]);
363- if (ret)
364- return ret;
365-
366- return 1;
367-}
368-
369 static const struct spinand_manufacturer_ops micron_spinand_manuf_ops = {
370- .detect = micron_spinand_detect,
371 };
372
373 const struct spinand_manufacturer micron_spinand_manufacturer = {
374 .id = SPINAND_MFR_MICRON,
375 .name = "Micron",
376+ .chips = micron_spinand_table,
377+ .nchips = ARRAY_SIZE(micron_spinand_table),
378 .ops = &micron_spinand_manuf_ops,
379 };
developer5d148cb2023-06-02 13:08:11 +0800380diff --git a/drivers/mtd/nand/spi/paragon.c b/drivers/mtd/nand/spi/paragon.c
381index 52307681c..519ade513 100644
developer41370d52022-03-16 16:01:59 +0800382--- a/drivers/mtd/nand/spi/paragon.c
383+++ b/drivers/mtd/nand/spi/paragon.c
developer5d148cb2023-06-02 13:08:11 +0800384@@ -97,7 +97,8 @@ static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
developer41370d52022-03-16 16:01:59 +0800385
386
387 static const struct spinand_info paragon_spinand_table[] = {
388- SPINAND_INFO("PN26G01A", 0xe1,
389+ SPINAND_INFO("PN26G01A",
390+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe1),
391 NAND_MEMORG(1, 2048, 128, 64, 1024, 21, 1, 1, 1),
392 NAND_ECCREQ(8, 512),
393 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800394@@ -106,7 +107,8 @@ static const struct spinand_info paragon_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800395 0,
396 SPINAND_ECCINFO(&pn26g0xa_ooblayout,
397 pn26g0xa_ecc_get_status)),
398- SPINAND_INFO("PN26G02A", 0xe2,
399+ SPINAND_INFO("PN26G02A",
400+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xe2),
401 NAND_MEMORG(1, 2048, 128, 64, 2048, 41, 1, 1, 1),
402 NAND_ECCREQ(8, 512),
403 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800404@@ -117,31 +119,13 @@ static const struct spinand_info paragon_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800405 pn26g0xa_ecc_get_status)),
406 };
407
408-static int paragon_spinand_detect(struct spinand_device *spinand)
409-{
410- u8 *id = spinand->id.data;
411- int ret;
412-
413- /* Read ID returns [0][MID][DID] */
414-
415- if (id[1] != SPINAND_MFR_PARAGON)
416- return 0;
417-
418- ret = spinand_match_and_init(spinand, paragon_spinand_table,
419- ARRAY_SIZE(paragon_spinand_table),
420- id[2]);
421- if (ret)
422- return ret;
423-
424- return 1;
425-}
426-
427 static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
428- .detect = paragon_spinand_detect,
429 };
430
431 const struct spinand_manufacturer paragon_spinand_manufacturer = {
432 .id = SPINAND_MFR_PARAGON,
433 .name = "Paragon",
434+ .chips = paragon_spinand_table,
435+ .nchips = ARRAY_SIZE(paragon_spinand_table),
436 .ops = &paragon_spinand_manuf_ops,
437 };
developer5d148cb2023-06-02 13:08:11 +0800438diff --git a/drivers/mtd/nand/spi/toshiba.c b/drivers/mtd/nand/spi/toshiba.c
439index 1cb3760ff..35da3c6e9 100644
developer41370d52022-03-16 16:01:59 +0800440--- a/drivers/mtd/nand/spi/toshiba.c
441+++ b/drivers/mtd/nand/spi/toshiba.c
developer5d148cb2023-06-02 13:08:11 +0800442@@ -95,7 +95,8 @@ static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800443
444 static const struct spinand_info toshiba_spinand_table[] = {
445 /* 3.3V 1Gb */
446- SPINAND_INFO("TC58CVG0S3", 0xC2,
447+ SPINAND_INFO("TC58CVG0S3",
448+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xC2),
449 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
450 NAND_ECCREQ(8, 512),
451 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800452@@ -105,7 +106,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800453 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
454 tc58cxgxsx_ecc_get_status)),
455 /* 3.3V 2Gb */
456- SPINAND_INFO("TC58CVG1S3", 0xCB,
457+ SPINAND_INFO("TC58CVG1S3",
458+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCB),
459 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
460 NAND_ECCREQ(8, 512),
461 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800462@@ -115,7 +117,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800463 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
464 tc58cxgxsx_ecc_get_status)),
465 /* 3.3V 4Gb */
466- SPINAND_INFO("TC58CVG2S0", 0xCD,
467+ SPINAND_INFO("TC58CVG2S0",
468+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xCD),
469 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
470 NAND_ECCREQ(8, 512),
471 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800472@@ -125,7 +128,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800473 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
474 tc58cxgxsx_ecc_get_status)),
475 /* 1.8V 1Gb */
476- SPINAND_INFO("TC58CYG0S3", 0xB2,
477+ SPINAND_INFO("TC58CYG0S3",
478+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xB2),
479 NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
480 NAND_ECCREQ(8, 512),
481 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800482@@ -135,7 +139,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800483 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
484 tc58cxgxsx_ecc_get_status)),
485 /* 1.8V 2Gb */
486- SPINAND_INFO("TC58CYG1S3", 0xBB,
487+ SPINAND_INFO("TC58CYG1S3",
488+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBB),
489 NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
490 NAND_ECCREQ(8, 512),
491 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800492@@ -145,7 +150,8 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800493 SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
494 tc58cxgxsx_ecc_get_status)),
495 /* 1.8V 4Gb */
496- SPINAND_INFO("TC58CYG2S0", 0xBD,
497+ SPINAND_INFO("TC58CYG2S0",
498+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xBD),
499 NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
500 NAND_ECCREQ(8, 512),
501 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800502@@ -156,33 +162,13 @@ static const struct spinand_info toshiba_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800503 tc58cxgxsx_ecc_get_status)),
504 };
505
506-static int toshiba_spinand_detect(struct spinand_device *spinand)
507-{
508- u8 *id = spinand->id.data;
509- int ret;
510-
511- /*
512- * Toshiba SPI NAND read ID needs a dummy byte,
513- * so the first byte in id is garbage.
514- */
515- if (id[1] != SPINAND_MFR_TOSHIBA)
516- return 0;
517-
518- ret = spinand_match_and_init(spinand, toshiba_spinand_table,
519- ARRAY_SIZE(toshiba_spinand_table),
520- id[2]);
521- if (ret)
522- return ret;
523-
524- return 1;
525-}
526-
527 static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
528- .detect = toshiba_spinand_detect,
529 };
530
531 const struct spinand_manufacturer toshiba_spinand_manufacturer = {
532 .id = SPINAND_MFR_TOSHIBA,
533 .name = "Toshiba",
534+ .chips = toshiba_spinand_table,
535+ .nchips = ARRAY_SIZE(toshiba_spinand_table),
536 .ops = &toshiba_spinand_manuf_ops,
537 };
developer5d148cb2023-06-02 13:08:11 +0800538diff --git a/drivers/mtd/nand/spi/winbond.c b/drivers/mtd/nand/spi/winbond.c
539index a6c17e0ca..766844283 100644
developer41370d52022-03-16 16:01:59 +0800540--- a/drivers/mtd/nand/spi/winbond.c
541+++ b/drivers/mtd/nand/spi/winbond.c
developer5d148cb2023-06-02 13:08:11 +0800542@@ -75,7 +75,8 @@ static int w25m02gv_select_target(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800543 }
544
545 static const struct spinand_info winbond_spinand_table[] = {
546- SPINAND_INFO("W25M02GV", 0xAB,
547+ SPINAND_INFO("W25M02GV",
548+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
549 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
550 NAND_ECCREQ(1, 512),
551 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800552@@ -84,7 +85,8 @@ static const struct spinand_info winbond_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800553 0,
554 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
555 SPINAND_SELECT_TARGET(w25m02gv_select_target)),
556- SPINAND_INFO("W25N01GV", 0xAA,
557+ SPINAND_INFO("W25N01GV",
558+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
559 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
560 NAND_ECCREQ(1, 512),
561 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
developer5d148cb2023-06-02 13:08:11 +0800562@@ -94,31 +96,6 @@ static const struct spinand_info winbond_spinand_table[] = {
developer41370d52022-03-16 16:01:59 +0800563 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
564 };
565
566-/**
567- * winbond_spinand_detect - initialize device related part in spinand_device
568- * struct if it is a Winbond device.
569- * @spinand: SPI NAND device structure
570- */
571-static int winbond_spinand_detect(struct spinand_device *spinand)
572-{
573- u8 *id = spinand->id.data;
574- int ret;
575-
576- /*
577- * Winbond SPI NAND read ID need a dummy byte,
578- * so the first byte in raw_id is dummy.
579- */
580- if (id[1] != SPINAND_MFR_WINBOND)
581- return 0;
582-
583- ret = spinand_match_and_init(spinand, winbond_spinand_table,
584- ARRAY_SIZE(winbond_spinand_table), id[2]);
585- if (ret)
586- return ret;
587-
588- return 1;
589-}
590-
591 static int winbond_spinand_init(struct spinand_device *spinand)
592 {
593 struct nand_device *nand = spinand_to_nand(spinand);
developer5d148cb2023-06-02 13:08:11 +0800594@@ -138,12 +115,13 @@ static int winbond_spinand_init(struct spinand_device *spinand)
developer41370d52022-03-16 16:01:59 +0800595 }
596
597 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
598- .detect = winbond_spinand_detect,
599 .init = winbond_spinand_init,
600 };
601
602 const struct spinand_manufacturer winbond_spinand_manufacturer = {
603 .id = SPINAND_MFR_WINBOND,
604 .name = "Winbond",
605+ .chips = winbond_spinand_table,
606+ .nchips = ARRAY_SIZE(winbond_spinand_table),
607 .ops = &winbond_spinand_manuf_ops,
608 };
developer5d148cb2023-06-02 13:08:11 +0800609diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
610index 4ea558bd3..f4c4ae871 100644
developer41370d52022-03-16 16:01:59 +0800611--- a/include/linux/mtd/spinand.h
612+++ b/include/linux/mtd/spinand.h
613@@ -32,9 +32,9 @@
614 SPI_MEM_OP_NO_DUMMY, \
615 SPI_MEM_OP_NO_DATA)
616
617-#define SPINAND_READID_OP(ndummy, buf, len) \
618+#define SPINAND_READID_OP(naddr, ndummy, buf, len) \
619 SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
620- SPI_MEM_OP_NO_ADDR, \
621+ SPI_MEM_OP_ADDR(naddr, 0, 1), \
622 SPI_MEM_OP_DUMMY(ndummy, 1), \
623 SPI_MEM_OP_DATA_IN(len, buf, 1))
624
625@@ -176,37 +176,46 @@ struct spinand_device;
626 * @data: buffer containing the id bytes. Currently 4 bytes large, but can
627 * be extended if required
628 * @len: ID length
629- *
630- * struct_spinand_id->data contains all bytes returned after a READ_ID command,
631- * including dummy bytes if the chip does not emit ID bytes right after the
632- * READ_ID command. The responsibility to extract real ID bytes is left to
633- * struct_manufacurer_ops->detect().
634 */
635 struct spinand_id {
636 u8 data[SPINAND_MAX_ID_LEN];
637 int len;
638 };
639
640+enum spinand_readid_method {
641+ SPINAND_READID_METHOD_OPCODE,
642+ SPINAND_READID_METHOD_OPCODE_ADDR,
643+ SPINAND_READID_METHOD_OPCODE_DUMMY,
644+};
645+
646+/**
647+ * struct spinand_devid - SPI NAND device id structure
648+ * @id: device id of current chip
649+ * @len: number of bytes in device id
650+ * @method: method to read chip id
651+ * There are 3 possible variants:
652+ * SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
653+ * after read_id opcode.
654+ * SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
655+ * read_id opcode + 1-byte address.
656+ * SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
657+ * read_id opcode + 1 dummy byte.
658+ */
659+struct spinand_devid {
660+ const u8 *id;
661+ const u8 len;
662+ const enum spinand_readid_method method;
663+};
664+
665 /**
666 * struct manufacurer_ops - SPI NAND manufacturer specific operations
667- * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
668- * the core calls the struct_manufacurer_ops->detect() hook of each
669- * registered manufacturer until one of them return 1. Note that
670- * the first thing to check in this hook is that the manufacturer ID
671- * in struct_spinand_device->id matches the manufacturer whose
672- * ->detect() hook has been called. Should return 1 if there's a
673- * match, 0 if the manufacturer ID does not match and a negative
674- * error code otherwise. When true is returned, the core assumes
675- * that properties of the NAND chip (spinand->base.memorg and
676- * spinand->base.eccreq) have been filled
677 * @init: initialize a SPI NAND device
678 * @cleanup: cleanup a SPI NAND device
679 *
680 * Each SPI NAND manufacturer driver should implement this interface so that
681- * NAND chips coming from this vendor can be detected and initialized properly.
682+ * NAND chips coming from this vendor can be initialized properly.
683 */
684 struct spinand_manufacturer_ops {
685- int (*detect)(struct spinand_device *spinand);
686 int (*init)(struct spinand_device *spinand);
687 void (*cleanup)(struct spinand_device *spinand);
688 };
689@@ -215,11 +224,16 @@ struct spinand_manufacturer_ops {
690 * struct spinand_manufacturer - SPI NAND manufacturer instance
691 * @id: manufacturer ID
692 * @name: manufacturer name
693+ * @devid_len: number of bytes in device ID
694+ * @chips: supported SPI NANDs under current manufacturer
695+ * @nchips: number of SPI NANDs available in chips array
696 * @ops: manufacturer operations
697 */
698 struct spinand_manufacturer {
699 u8 id;
700 char *name;
701+ const struct spinand_info *chips;
702+ const size_t nchips;
703 const struct spinand_manufacturer_ops *ops;
704 };
705
706@@ -291,7 +305,7 @@ struct spinand_ecc_info {
707 */
708 struct spinand_info {
709 const char *model;
710- u16 devid;
711+ struct spinand_devid devid;
712 u32 flags;
713 struct nand_memory_organization memorg;
714 struct nand_ecc_req eccreq;
715@@ -305,6 +319,13 @@ struct spinand_info {
716 unsigned int target);
717 };
718
719+#define SPINAND_ID(__method, ...) \
720+ { \
721+ .id = (const u8[]){ __VA_ARGS__ }, \
722+ .len = sizeof((u8[]){ __VA_ARGS__ }), \
723+ .method = __method, \
724+ }
725+
726 #define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \
727 { \
728 .read_cache = __read, \
developer5d148cb2023-06-02 13:08:11 +0800729@@ -451,9 +472,10 @@ static inline void spinand_set_of_node(struct spinand_device *spinand,
developer41370d52022-03-16 16:01:59 +0800730 nanddev_set_of_node(&spinand->base, np);
731 }
732
733-int spinand_match_and_init(struct spinand_device *dev,
734+int spinand_match_and_init(struct spinand_device *spinand,
735 const struct spinand_info *table,
736- unsigned int table_size, u16 devid);
737+ unsigned int table_size,
738+ enum spinand_readid_method rdid_method);
739
740 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
741 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
developer5d148cb2023-06-02 13:08:11 +0800742--
7432.34.1
744