blob: cd096d3b30a768be37e41f8165a5ec9dc82e88e2 [file] [log] [blame]
developer722ab5f2024-02-22 11:01:46 +08001Index: linux-5.4.260/drivers/mtd/nand/spi/core.c
2===================================================================
3--- linux-5.4.260.orig/drivers/mtd/nand/spi/core.c
4+++ linux-5.4.260/drivers/mtd/nand/spi/core.c
5@@ -16,6 +16,7 @@
6 #include <linux/mtd/spinand.h>
7 #include <linux/of.h>
8 #include <linux/slab.h>
9+#include <linux/string.h>
10 #include <linux/spi/spi.h>
11 #include <linux/spi/spi-mem.h>
12
13@@ -370,10 +371,11 @@ out:
14 return status & STATUS_BUSY ? -ETIMEDOUT : 0;
15 }
16
17-static int spinand_read_id_op(struct spinand_device *spinand, u8 *buf)
18+static int spinand_read_id_op(struct spinand_device *spinand, u8 naddr,
19+ u8 ndummy, u8 *buf)
20 {
21- struct spi_mem_op op = SPINAND_READID_OP(0, spinand->scratchbuf,
22- SPINAND_MAX_ID_LEN);
23+ struct spi_mem_op op = SPINAND_READID_OP(
24+ naddr, ndummy, spinand->scratchbuf, SPINAND_MAX_ID_LEN);
25 int ret;
26
27 ret = spi_mem_exec_op(spinand->spimem, &op);
28@@ -760,24 +762,62 @@ static const struct spinand_manufacturer
29 &winbond_spinand_manufacturer,
30 };
31
32-static int spinand_manufacturer_detect(struct spinand_device *spinand)
33+static int spinand_manufacturer_match(struct spinand_device *spinand,
34+ enum spinand_readid_method rdid_method)
35 {
36+ u8 *id = spinand->id.data;
37 unsigned int i;
38 int ret;
39
40 for (i = 0; i < ARRAY_SIZE(spinand_manufacturers); i++) {
41- ret = spinand_manufacturers[i]->ops->detect(spinand);
42- if (ret > 0) {
43- spinand->manufacturer = spinand_manufacturers[i];
44- return 0;
45- } else if (ret < 0) {
46- return ret;
47- }
48- }
49+ const struct spinand_manufacturer *manufacturer =
50+ spinand_manufacturers[i];
51+
52+ if (id[0] != manufacturer->id)
53+ continue;
54
55+ ret = spinand_match_and_init(spinand,
56+ manufacturer->chips,
57+ manufacturer->nchips,
58+ rdid_method);
59+ if (ret < 0)
60+ continue;
61+
62+ spinand->manufacturer = manufacturer;
63+ return 0;
64+ }
65 return -ENOTSUPP;
66 }
67
68+static int spinand_id_detect(struct spinand_device *spinand)
69+{
70+ u8 *id = spinand->id.data;
71+ int ret;
72+
73+ ret = spinand_read_id_op(spinand, 0, 0, id);
74+ if (ret)
75+ return ret;
76+ ret = spinand_manufacturer_match(spinand, SPINAND_READID_METHOD_OPCODE);
77+ if (!ret)
78+ return 0;
79+
80+ ret = spinand_read_id_op(spinand, 1, 0, id);
81+ if (ret)
82+ return ret;
83+ ret = spinand_manufacturer_match(spinand,
84+ SPINAND_READID_METHOD_OPCODE_ADDR);
85+ if (!ret)
86+ return 0;
87+
88+ ret = spinand_read_id_op(spinand, 0, 1, id);
89+ if (ret)
90+ return ret;
91+ ret = spinand_manufacturer_match(spinand,
92+ SPINAND_READID_METHOD_OPCODE_DUMMY);
93+
94+ return ret;
95+}
96+
97 static int spinand_manufacturer_init(struct spinand_device *spinand)
98 {
99 if (spinand->manufacturer->ops->init)
100@@ -833,9 +873,9 @@ spinand_select_op_variant(struct spinand
101 * @spinand: SPI NAND object
102 * @table: SPI NAND device description table
103 * @table_size: size of the device description table
104+ * @rdid_method: read id method to match
105 *
106- * Should be used by SPI NAND manufacturer drivers when they want to find a
107- * match between a device ID retrieved through the READ_ID command and an
108+ * Match between a device ID retrieved through the READ_ID command and an
109 * entry in the SPI NAND description table. If a match is found, the spinand
110 * object will be initialized with information provided by the matching
111 * spinand_info entry.
112@@ -844,8 +884,10 @@ spinand_select_op_variant(struct spinand
113 */
114 int spinand_match_and_init(struct spinand_device *spinand,
115 const struct spinand_info *table,
116- unsigned int table_size, u16 devid)
117+ unsigned int table_size,
118+ enum spinand_readid_method rdid_method)
119 {
120+ u8 *id = spinand->id.data;
121 struct nand_device *nand = spinand_to_nand(spinand);
122 unsigned int i;
123
124@@ -853,13 +895,17 @@ int spinand_match_and_init(struct spinan
125 const struct spinand_info *info = &table[i];
126 const struct spi_mem_op *op;
127
128- if (devid != info->devid)
129+ if (rdid_method != info->devid.method)
130+ continue;
131+
132+ if (memcmp(id + 1, info->devid.id, info->devid.len))
133 continue;
134
135 nand->memorg = table[i].memorg;
136 nand->eccreq = table[i].eccreq;
137 spinand->eccinfo = table[i].eccinfo;
138 spinand->flags = table[i].flags;
139+ spinand->id.len = 1 + table[i].devid.len;
140 spinand->select_target = table[i].select_target;
141
142 op = spinand_select_op_variant(spinand,
143@@ -896,13 +942,7 @@ static int spinand_detect(struct spinand
144 if (ret)
145 return ret;
146
147- ret = spinand_read_id_op(spinand, spinand->id.data);
148- if (ret)
149- return ret;
150-
151- spinand->id.len = SPINAND_MAX_ID_LEN;
152-
153- ret = spinand_manufacturer_detect(spinand);
154+ ret = spinand_id_detect(spinand);
155 if (ret) {
156 dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
157 spinand->id.data);
158Index: linux-5.4.260/include/linux/mtd/spinand.h
159===================================================================
160--- linux-5.4.260.orig/include/linux/mtd/spinand.h
161+++ linux-5.4.260/include/linux/mtd/spinand.h
162@@ -32,9 +32,9 @@
163 SPI_MEM_OP_NO_DUMMY, \
164 SPI_MEM_OP_NO_DATA)
165
166-#define SPINAND_READID_OP(ndummy, buf, len) \
167+#define SPINAND_READID_OP(naddr, ndummy, buf, len) \
168 SPI_MEM_OP(SPI_MEM_OP_CMD(0x9f, 1), \
169- SPI_MEM_OP_NO_ADDR, \
170+ SPI_MEM_OP_ADDR(naddr, 0, 1), \
171 SPI_MEM_OP_DUMMY(ndummy, 1), \
172 SPI_MEM_OP_DATA_IN(len, buf, 1))
173
174@@ -176,37 +176,46 @@ struct spinand_device;
175 * @data: buffer containing the id bytes. Currently 4 bytes large, but can
176 * be extended if required
177 * @len: ID length
178- *
179- * struct_spinand_id->data contains all bytes returned after a READ_ID command,
180- * including dummy bytes if the chip does not emit ID bytes right after the
181- * READ_ID command. The responsibility to extract real ID bytes is left to
182- * struct_manufacurer_ops->detect().
183 */
184 struct spinand_id {
185 u8 data[SPINAND_MAX_ID_LEN];
186 int len;
187 };
188
189+enum spinand_readid_method {
190+ SPINAND_READID_METHOD_OPCODE,
191+ SPINAND_READID_METHOD_OPCODE_ADDR,
192+ SPINAND_READID_METHOD_OPCODE_DUMMY,
193+};
194+
195+/**
196+ * struct spinand_devid - SPI NAND device id structure
197+ * @id: device id of current chip
198+ * @len: number of bytes in device id
199+ * @method: method to read chip id
200+ * There are 3 possible variants:
201+ * SPINAND_READID_METHOD_OPCODE: chip id is returned immediately
202+ * after read_id opcode.
203+ * SPINAND_READID_METHOD_OPCODE_ADDR: chip id is returned after
204+ * read_id opcode + 1-byte address.
205+ * SPINAND_READID_METHOD_OPCODE_DUMMY: chip id is returned after
206+ * read_id opcode + 1 dummy byte.
207+ */
208+struct spinand_devid {
209+ const u8 *id;
210+ const u8 len;
211+ const enum spinand_readid_method method;
212+};
213+
214 /**
215 * struct manufacurer_ops - SPI NAND manufacturer specific operations
216- * @detect: detect a SPI NAND device. Every time a SPI NAND device is probed
217- * the core calls the struct_manufacurer_ops->detect() hook of each
218- * registered manufacturer until one of them return 1. Note that
219- * the first thing to check in this hook is that the manufacturer ID
220- * in struct_spinand_device->id matches the manufacturer whose
221- * ->detect() hook has been called. Should return 1 if there's a
222- * match, 0 if the manufacturer ID does not match and a negative
223- * error code otherwise. When true is returned, the core assumes
224- * that properties of the NAND chip (spinand->base.memorg and
225- * spinand->base.eccreq) have been filled
226 * @init: initialize a SPI NAND device
227 * @cleanup: cleanup a SPI NAND device
228 *
229 * Each SPI NAND manufacturer driver should implement this interface so that
230- * NAND chips coming from this vendor can be detected and initialized properly.
231+ * NAND chips coming from this vendor can be initialized properly.
232 */
233 struct spinand_manufacturer_ops {
234- int (*detect)(struct spinand_device *spinand);
235 int (*init)(struct spinand_device *spinand);
236 void (*cleanup)(struct spinand_device *spinand);
237 };
238@@ -215,11 +224,16 @@ struct spinand_manufacturer_ops {
239 * struct spinand_manufacturer - SPI NAND manufacturer instance
240 * @id: manufacturer ID
241 * @name: manufacturer name
242+ * @devid_len: number of bytes in device ID
243+ * @chips: supported SPI NANDs under current manufacturer
244+ * @nchips: number of SPI NANDs available in chips array
245 * @ops: manufacturer operations
246 */
247 struct spinand_manufacturer {
248 u8 id;
249 char *name;
250+ const struct spinand_info *chips;
251+ const size_t nchips;
252 const struct spinand_manufacturer_ops *ops;
253 };
254
255@@ -270,6 +284,7 @@ struct spinand_ecc_info {
256 };
257
258 #define SPINAND_HAS_QE_BIT BIT(0)
259+#define SPINAND_HAS_CR_FEAT_BIT BIT(1)
260
261 /**
262 * struct spinand_info - Structure used to describe SPI NAND chips
263@@ -291,7 +306,7 @@ struct spinand_ecc_info {
264 */
265 struct spinand_info {
266 const char *model;
267- u16 devid;
268+ struct spinand_devid devid;
269 u32 flags;
270 struct nand_memory_organization memorg;
271 struct nand_ecc_req eccreq;
272@@ -305,6 +320,13 @@ struct spinand_info {
273 unsigned int target);
274 };
275
276+#define SPINAND_ID(__method, ...) \
277+ { \
278+ .id = (const u8[]){ __VA_ARGS__ }, \
279+ .len = sizeof((u8[]){ __VA_ARGS__ }), \
280+ .method = __method, \
281+ }
282+
283 #define SPINAND_INFO_OP_VARIANTS(__read, __write, __update) \
284 { \
285 .read_cache = __read, \
286@@ -451,9 +473,10 @@ static inline void spinand_set_of_node(s
287 nanddev_set_of_node(&spinand->base, np);
288 }
289
290-int spinand_match_and_init(struct spinand_device *dev,
291+int spinand_match_and_init(struct spinand_device *spinand,
292 const struct spinand_info *table,
293- unsigned int table_size, u16 devid);
294+ unsigned int table_size,
295+ enum spinand_readid_method rdid_method);
296
297 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
298 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
299Index: linux-5.4.260/drivers/mtd/nand/spi/winbond.c
300===================================================================
301--- linux-5.4.260.orig/drivers/mtd/nand/spi/winbond.c
302+++ linux-5.4.260/drivers/mtd/nand/spi/winbond.c
303@@ -75,7 +75,8 @@ static int w25m02gv_select_target(struct
304 }
305
306 static const struct spinand_info winbond_spinand_table[] = {
307- SPINAND_INFO("W25M02GV", 0xAB,
308+ SPINAND_INFO("W25M02GV",
309+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xab),
310 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 2),
311 NAND_ECCREQ(1, 512),
312 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
313@@ -84,7 +85,8 @@ static const struct spinand_info winbond
314 0,
315 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
316 SPINAND_SELECT_TARGET(w25m02gv_select_target)),
317- SPINAND_INFO("W25N01GV", 0xAA,
318+ SPINAND_INFO("W25N01GV",
319+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xaa),
320 NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
321 NAND_ECCREQ(1, 512),
322 SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
323@@ -94,31 +96,6 @@ static const struct spinand_info winbond
324 SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
325 };
326
327-/**
328- * winbond_spinand_detect - initialize device related part in spinand_device
329- * struct if it is a Winbond device.
330- * @spinand: SPI NAND device structure
331- */
332-static int winbond_spinand_detect(struct spinand_device *spinand)
333-{
334- u8 *id = spinand->id.data;
335- int ret;
336-
337- /*
338- * Winbond SPI NAND read ID need a dummy byte,
339- * so the first byte in raw_id is dummy.
340- */
341- if (id[1] != SPINAND_MFR_WINBOND)
342- return 0;
343-
344- ret = spinand_match_and_init(spinand, winbond_spinand_table,
345- ARRAY_SIZE(winbond_spinand_table), id[2]);
346- if (ret)
347- return ret;
348-
349- return 1;
350-}
351-
352 static int winbond_spinand_init(struct spinand_device *spinand)
353 {
354 struct nand_device *nand = spinand_to_nand(spinand);
355@@ -138,12 +115,13 @@ static int winbond_spinand_init(struct s
356 }
357
358 static const struct spinand_manufacturer_ops winbond_spinand_manuf_ops = {
359- .detect = winbond_spinand_detect,
360 .init = winbond_spinand_init,
361 };
362
363 const struct spinand_manufacturer winbond_spinand_manufacturer = {
364 .id = SPINAND_MFR_WINBOND,
365 .name = "Winbond",
366+ .chips = winbond_spinand_table,
367+ .nchips = ARRAY_SIZE(winbond_spinand_table),
368 .ops = &winbond_spinand_manuf_ops,
369 };