1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2005, Intec Automation Inc. |
4 | * Copyright (C) 2014, Freescale Semiconductor, Inc. |
5 | */ |
6 | |
7 | #include <linux/mtd/spi-nor.h> |
8 | |
9 | #include "core.h" |
10 | |
11 | /* flash_info mfr_flag. Used to read proprietary FSR register. */ |
12 | #define USE_FSR BIT(0) |
13 | |
14 | #define SPINOR_OP_MT_DIE_ERASE 0xc4 /* Chip (die) erase opcode */ |
15 | #define SPINOR_OP_RDFSR 0x70 /* Read flag status register */ |
16 | #define SPINOR_OP_CLFSR 0x50 /* Clear flag status register */ |
17 | #define SPINOR_OP_MT_DTR_RD 0xfd /* Fast Read opcode in DTR mode */ |
18 | #define SPINOR_OP_MT_RD_ANY_REG 0x85 /* Read volatile register */ |
19 | #define SPINOR_OP_MT_WR_ANY_REG 0x81 /* Write volatile register */ |
20 | #define SPINOR_REG_MT_CFR0V 0x00 /* For setting octal DTR mode */ |
21 | #define SPINOR_REG_MT_CFR1V 0x01 /* For setting dummy cycles */ |
22 | #define SPINOR_REG_MT_CFR1V_DEF 0x1f /* Default dummy cycles */ |
23 | #define SPINOR_MT_OCT_DTR 0xe7 /* Enable Octal DTR. */ |
24 | #define SPINOR_MT_EXSPI 0xff /* Enable Extended SPI (default) */ |
25 | |
26 | /* Flag Status Register bits */ |
27 | #define FSR_READY BIT(7) /* Device status, 0 = Busy, 1 = Ready */ |
28 | #define FSR_E_ERR BIT(5) /* Erase operation status */ |
29 | #define FSR_P_ERR BIT(4) /* Program operation status */ |
30 | #define FSR_PT_ERR BIT(1) /* Protection error bit */ |
31 | |
32 | /* Micron ST SPI NOR flash operations. */ |
33 | #define MICRON_ST_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ |
34 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 0), \ |
35 | SPI_MEM_OP_ADDR(naddr, addr, 0), \ |
36 | SPI_MEM_OP_NO_DUMMY, \ |
37 | SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) |
38 | |
39 | #define MICRON_ST_RDFSR_OP(buf) \ |
40 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0), \ |
41 | SPI_MEM_OP_NO_ADDR, \ |
42 | SPI_MEM_OP_NO_DUMMY, \ |
43 | SPI_MEM_OP_DATA_IN(1, buf, 0)) |
44 | |
45 | #define MICRON_ST_CLFSR_OP \ |
46 | SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0), \ |
47 | SPI_MEM_OP_NO_ADDR, \ |
48 | SPI_MEM_OP_NO_DUMMY, \ |
49 | SPI_MEM_OP_NO_DATA) |
50 | |
51 | static int micron_st_nor_octal_dtr_en(struct spi_nor *nor) |
52 | { |
53 | struct spi_mem_op op; |
54 | u8 *buf = nor->bouncebuf; |
55 | int ret; |
56 | u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; |
57 | |
58 | /* Use 20 dummy cycles for memory array reads. */ |
59 | *buf = 20; |
60 | op = (struct spi_mem_op) |
61 | MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, |
62 | SPINOR_REG_MT_CFR1V, 1, buf); |
63 | ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: nor->reg_proto); |
64 | if (ret) |
65 | return ret; |
66 | |
67 | buf[0] = SPINOR_MT_OCT_DTR; |
68 | op = (struct spi_mem_op) |
69 | MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes, |
70 | SPINOR_REG_MT_CFR0V, 1, buf); |
71 | ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: nor->reg_proto); |
72 | if (ret) |
73 | return ret; |
74 | |
75 | /* Read flash ID to make sure the switch was successful. */ |
76 | ret = spi_nor_read_id(nor, naddr: 0, ndummy: 8, id: buf, reg_proto: SNOR_PROTO_8_8_8_DTR); |
77 | if (ret) { |
78 | dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n" , ret); |
79 | return ret; |
80 | } |
81 | |
82 | if (memcmp(p: buf, q: nor->info->id->bytes, size: nor->info->id->len)) |
83 | return -EINVAL; |
84 | |
85 | return 0; |
86 | } |
87 | |
88 | static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) |
89 | { |
90 | struct spi_mem_op op; |
91 | u8 *buf = nor->bouncebuf; |
92 | int ret; |
93 | |
94 | /* |
95 | * The register is 1-byte wide, but 1-byte transactions are not allowed |
96 | * in 8D-8D-8D mode. The next register is the dummy cycle configuration |
97 | * register. Since the transaction needs to be at least 2 bytes wide, |
98 | * set the next register to its default value. This also makes sense |
99 | * because the value was changed when enabling 8D-8D-8D mode, it should |
100 | * be reset when disabling. |
101 | */ |
102 | buf[0] = SPINOR_MT_EXSPI; |
103 | buf[1] = SPINOR_REG_MT_CFR1V_DEF; |
104 | op = (struct spi_mem_op) |
105 | MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes, |
106 | SPINOR_REG_MT_CFR0V, 2, buf); |
107 | ret = spi_nor_write_any_volatile_reg(nor, op: &op, proto: SNOR_PROTO_8_8_8_DTR); |
108 | if (ret) |
109 | return ret; |
110 | |
111 | /* Read flash ID to make sure the switch was successful. */ |
112 | ret = spi_nor_read_id(nor, naddr: 0, ndummy: 0, id: buf, reg_proto: SNOR_PROTO_1_1_1); |
113 | if (ret) { |
114 | dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n" , ret); |
115 | return ret; |
116 | } |
117 | |
118 | if (memcmp(p: buf, q: nor->info->id->bytes, size: nor->info->id->len)) |
119 | return -EINVAL; |
120 | |
121 | return 0; |
122 | } |
123 | |
124 | static int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable) |
125 | { |
126 | return enable ? micron_st_nor_octal_dtr_en(nor) : |
127 | micron_st_nor_octal_dtr_dis(nor); |
128 | } |
129 | |
130 | static void mt35xu512aba_default_init(struct spi_nor *nor) |
131 | { |
132 | nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr; |
133 | } |
134 | |
135 | static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor) |
136 | { |
137 | /* Set the Fast Read settings. */ |
138 | nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR; |
139 | spi_nor_set_read_settings(read: &nor->params->reads[SNOR_CMD_READ_8_8_8_DTR], |
140 | num_mode_clocks: 0, num_wait_states: 20, SPINOR_OP_MT_DTR_RD, |
141 | proto: SNOR_PROTO_8_8_8_DTR); |
142 | |
143 | nor->cmd_ext_type = SPI_NOR_EXT_REPEAT; |
144 | nor->params->rdsr_dummy = 8; |
145 | nor->params->rdsr_addr_nbytes = 0; |
146 | |
147 | /* |
148 | * The BFPT quad enable field is set to a reserved value so the quad |
149 | * enable function is ignored by spi_nor_parse_bfpt(). Make sure we |
150 | * disable it. |
151 | */ |
152 | nor->params->quad_enable = NULL; |
153 | |
154 | return 0; |
155 | } |
156 | |
157 | static const struct spi_nor_fixups mt35xu512aba_fixups = { |
158 | .default_init = mt35xu512aba_default_init, |
159 | .post_sfdp = mt35xu512aba_post_sfdp_fixup, |
160 | }; |
161 | |
162 | static const struct flash_info micron_nor_parts[] = { |
163 | { |
164 | .id = SNOR_ID(0x2c, 0x5b, 0x1a), |
165 | .name = "mt35xu512aba" , |
166 | .sector_size = SZ_128K, |
167 | .size = SZ_64M, |
168 | .no_sfdp_flags = SECT_4K | SPI_NOR_OCTAL_READ | |
169 | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_OCTAL_DTR_PP, |
170 | .mfr_flags = USE_FSR, |
171 | .fixup_flags = SPI_NOR_4B_OPCODES | SPI_NOR_IO_MODE_EN_VOLATILE, |
172 | .fixups = &mt35xu512aba_fixups, |
173 | }, { |
174 | .id = SNOR_ID(0x2c, 0x5b, 0x1c), |
175 | .name = "mt35xu02g" , |
176 | .sector_size = SZ_128K, |
177 | .size = SZ_256M, |
178 | .no_sfdp_flags = SECT_4K | SPI_NOR_OCTAL_READ, |
179 | .mfr_flags = USE_FSR, |
180 | .fixup_flags = SPI_NOR_4B_OPCODES, |
181 | }, |
182 | }; |
183 | |
184 | static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor, |
185 | const struct sfdp_parameter_header *, |
186 | const struct sfdp_bfpt *bfpt) |
187 | { |
188 | nor->flags &= ~SNOR_F_HAS_16BIT_SR; |
189 | return 0; |
190 | } |
191 | |
192 | static struct spi_nor_fixups mt25qu512a_fixups = { |
193 | .post_bfpt = mt25qu512a_post_bfpt_fixup, |
194 | }; |
195 | |
196 | static int st_nor_four_die_late_init(struct spi_nor *nor) |
197 | { |
198 | struct spi_nor_flash_parameter *params = nor->params; |
199 | |
200 | params->die_erase_opcode = SPINOR_OP_MT_DIE_ERASE; |
201 | params->n_dice = 4; |
202 | |
203 | /* |
204 | * Unfortunately the die erase opcode does not have a 4-byte opcode |
205 | * correspondent for these flashes. The SFDP 4BAIT table fails to |
206 | * consider the die erase too. We're forced to enter in the 4 byte |
207 | * address mode in order to benefit of the die erase. |
208 | */ |
209 | return spi_nor_set_4byte_addr_mode(nor, enable: true); |
210 | } |
211 | |
212 | static int st_nor_two_die_late_init(struct spi_nor *nor) |
213 | { |
214 | struct spi_nor_flash_parameter *params = nor->params; |
215 | |
216 | params->die_erase_opcode = SPINOR_OP_MT_DIE_ERASE; |
217 | params->n_dice = 2; |
218 | |
219 | /* |
220 | * Unfortunately the die erase opcode does not have a 4-byte opcode |
221 | * correspondent for these flashes. The SFDP 4BAIT table fails to |
222 | * consider the die erase too. We're forced to enter in the 4 byte |
223 | * address mode in order to benefit of the die erase. |
224 | */ |
225 | return spi_nor_set_4byte_addr_mode(nor, enable: true); |
226 | } |
227 | |
228 | static struct spi_nor_fixups n25q00_fixups = { |
229 | .late_init = st_nor_four_die_late_init, |
230 | }; |
231 | |
232 | static struct spi_nor_fixups mt25q01_fixups = { |
233 | .late_init = st_nor_two_die_late_init, |
234 | }; |
235 | |
236 | static struct spi_nor_fixups mt25q02_fixups = { |
237 | .late_init = st_nor_four_die_late_init, |
238 | }; |
239 | |
240 | static const struct flash_info st_nor_parts[] = { |
241 | { |
242 | .name = "m25p05-nonjedec" , |
243 | .sector_size = SZ_32K, |
244 | .size = SZ_64K, |
245 | }, { |
246 | .name = "m25p10-nonjedec" , |
247 | .sector_size = SZ_32K, |
248 | .size = SZ_128K, |
249 | }, { |
250 | .name = "m25p20-nonjedec" , |
251 | .size = SZ_256K, |
252 | }, { |
253 | .name = "m25p40-nonjedec" , |
254 | .size = SZ_512K, |
255 | }, { |
256 | .name = "m25p80-nonjedec" , |
257 | .size = SZ_1M, |
258 | }, { |
259 | .name = "m25p16-nonjedec" , |
260 | .size = SZ_2M, |
261 | }, { |
262 | .name = "m25p32-nonjedec" , |
263 | .size = SZ_4M, |
264 | }, { |
265 | .name = "m25p64-nonjedec" , |
266 | .size = SZ_8M, |
267 | }, { |
268 | .name = "m25p128-nonjedec" , |
269 | .sector_size = SZ_256K, |
270 | .size = SZ_16M, |
271 | }, { |
272 | .id = SNOR_ID(0x20, 0x20, 0x10), |
273 | .name = "m25p05" , |
274 | .sector_size = SZ_32K, |
275 | .size = SZ_64K, |
276 | }, { |
277 | .id = SNOR_ID(0x20, 0x20, 0x11), |
278 | .name = "m25p10" , |
279 | .sector_size = SZ_32K, |
280 | .size = SZ_128K, |
281 | }, { |
282 | .id = SNOR_ID(0x20, 0x20, 0x12), |
283 | .name = "m25p20" , |
284 | .size = SZ_256K, |
285 | }, { |
286 | .id = SNOR_ID(0x20, 0x20, 0x13), |
287 | .name = "m25p40" , |
288 | .size = SZ_512K, |
289 | }, { |
290 | .id = SNOR_ID(0x20, 0x20, 0x14), |
291 | .name = "m25p80" , |
292 | .size = SZ_1M, |
293 | }, { |
294 | .id = SNOR_ID(0x20, 0x20, 0x15), |
295 | .name = "m25p16" , |
296 | .size = SZ_2M, |
297 | }, { |
298 | .id = SNOR_ID(0x20, 0x20, 0x16), |
299 | .name = "m25p32" , |
300 | .size = SZ_4M, |
301 | }, { |
302 | .id = SNOR_ID(0x20, 0x20, 0x17), |
303 | .name = "m25p64" , |
304 | .size = SZ_8M, |
305 | }, { |
306 | .id = SNOR_ID(0x20, 0x20, 0x18), |
307 | .name = "m25p128" , |
308 | .sector_size = SZ_256K, |
309 | .size = SZ_16M, |
310 | }, { |
311 | .id = SNOR_ID(0x20, 0x40, 0x11), |
312 | .name = "m45pe10" , |
313 | .size = SZ_128K, |
314 | }, { |
315 | .id = SNOR_ID(0x20, 0x40, 0x14), |
316 | .name = "m45pe80" , |
317 | .size = SZ_1M, |
318 | }, { |
319 | .id = SNOR_ID(0x20, 0x40, 0x15), |
320 | .name = "m45pe16" , |
321 | .size = SZ_2M, |
322 | }, { |
323 | .id = SNOR_ID(0x20, 0x63, 0x16), |
324 | .name = "m25px32-s1" , |
325 | .size = SZ_4M, |
326 | .no_sfdp_flags = SECT_4K, |
327 | }, { |
328 | .id = SNOR_ID(0x20, 0x71, 0x14), |
329 | .name = "m25px80" , |
330 | .size = SZ_1M, |
331 | }, { |
332 | .id = SNOR_ID(0x20, 0x71, 0x15), |
333 | .name = "m25px16" , |
334 | .size = SZ_2M, |
335 | .no_sfdp_flags = SECT_4K, |
336 | }, { |
337 | .id = SNOR_ID(0x20, 0x71, 0x16), |
338 | .name = "m25px32" , |
339 | .size = SZ_4M, |
340 | .no_sfdp_flags = SECT_4K, |
341 | }, { |
342 | .id = SNOR_ID(0x20, 0x71, 0x17), |
343 | .name = "m25px64" , |
344 | .size = SZ_8M, |
345 | }, { |
346 | .id = SNOR_ID(0x20, 0x73, 0x16), |
347 | .name = "m25px32-s0" , |
348 | .size = SZ_4M, |
349 | .no_sfdp_flags = SECT_4K, |
350 | }, { |
351 | .id = SNOR_ID(0x20, 0x80, 0x12), |
352 | .name = "m25pe20" , |
353 | .size = SZ_256K, |
354 | }, { |
355 | .id = SNOR_ID(0x20, 0x80, 0x14), |
356 | .name = "m25pe80" , |
357 | .size = SZ_1M, |
358 | }, { |
359 | .id = SNOR_ID(0x20, 0x80, 0x15), |
360 | .name = "m25pe16" , |
361 | .size = SZ_2M, |
362 | .no_sfdp_flags = SECT_4K, |
363 | }, { |
364 | .id = SNOR_ID(0x20, 0xba, 0x16), |
365 | .name = "n25q032" , |
366 | .size = SZ_4M, |
367 | .no_sfdp_flags = SPI_NOR_QUAD_READ, |
368 | }, { |
369 | .id = SNOR_ID(0x20, 0xba, 0x17), |
370 | .name = "n25q064" , |
371 | .size = SZ_8M, |
372 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
373 | }, { |
374 | .id = SNOR_ID(0x20, 0xba, 0x18), |
375 | .name = "n25q128a13" , |
376 | .size = SZ_16M, |
377 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
378 | SPI_NOR_BP3_SR_BIT6, |
379 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
380 | .mfr_flags = USE_FSR, |
381 | }, { |
382 | .id = SNOR_ID(0x20, 0xba, 0x19, 0x10, 0x44, 0x00), |
383 | .name = "mt25ql256a" , |
384 | .size = SZ_32M, |
385 | .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, |
386 | .fixup_flags = SPI_NOR_4B_OPCODES, |
387 | .mfr_flags = USE_FSR, |
388 | }, { |
389 | .id = SNOR_ID(0x20, 0xba, 0x19), |
390 | .name = "n25q256a" , |
391 | .size = SZ_32M, |
392 | .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, |
393 | .mfr_flags = USE_FSR, |
394 | }, { |
395 | .id = SNOR_ID(0x20, 0xba, 0x20, 0x10, 0x44, 0x00), |
396 | .name = "mt25ql512a" , |
397 | .size = SZ_64M, |
398 | .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, |
399 | .fixup_flags = SPI_NOR_4B_OPCODES, |
400 | .mfr_flags = USE_FSR, |
401 | }, { |
402 | .id = SNOR_ID(0x20, 0xba, 0x20), |
403 | .name = "n25q512ax3" , |
404 | .size = SZ_64M, |
405 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
406 | SPI_NOR_BP3_SR_BIT6, |
407 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
408 | .mfr_flags = USE_FSR, |
409 | }, { |
410 | .id = SNOR_ID(0x20, 0xba, 0x21), |
411 | .name = "n25q00" , |
412 | .size = SZ_128M, |
413 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
414 | SPI_NOR_BP3_SR_BIT6, |
415 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
416 | .mfr_flags = USE_FSR, |
417 | .fixups = &n25q00_fixups, |
418 | }, { |
419 | .id = SNOR_ID(0x20, 0xba, 0x22), |
420 | .name = "mt25ql02g" , |
421 | .size = SZ_256M, |
422 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
423 | .mfr_flags = USE_FSR, |
424 | .fixups = &mt25q02_fixups, |
425 | }, { |
426 | .id = SNOR_ID(0x20, 0xbb, 0x15), |
427 | .name = "n25q016a" , |
428 | .size = SZ_2M, |
429 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
430 | }, { |
431 | .id = SNOR_ID(0x20, 0xbb, 0x16), |
432 | .name = "n25q032a" , |
433 | .size = SZ_4M, |
434 | .no_sfdp_flags = SPI_NOR_QUAD_READ, |
435 | }, { |
436 | .id = SNOR_ID(0x20, 0xbb, 0x17), |
437 | .name = "n25q064a" , |
438 | .size = SZ_8M, |
439 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
440 | }, { |
441 | .id = SNOR_ID(0x20, 0xbb, 0x18), |
442 | .name = "n25q128a11" , |
443 | .size = SZ_16M, |
444 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
445 | SPI_NOR_BP3_SR_BIT6, |
446 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
447 | .mfr_flags = USE_FSR, |
448 | }, { |
449 | .id = SNOR_ID(0x20, 0xbb, 0x19, 0x10, 0x44, 0x00), |
450 | .name = "mt25qu256a" , |
451 | .size = SZ_32M, |
452 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
453 | SPI_NOR_BP3_SR_BIT6, |
454 | .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, |
455 | .fixup_flags = SPI_NOR_4B_OPCODES, |
456 | .mfr_flags = USE_FSR, |
457 | }, { |
458 | .id = SNOR_ID(0x20, 0xbb, 0x19), |
459 | .name = "n25q256ax1" , |
460 | .size = SZ_32M, |
461 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
462 | .mfr_flags = USE_FSR, |
463 | }, { |
464 | .id = SNOR_ID(0x20, 0xbb, 0x20, 0x10, 0x44, 0x00), |
465 | .name = "mt25qu512a" , |
466 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
467 | SPI_NOR_BP3_SR_BIT6, |
468 | .mfr_flags = USE_FSR, |
469 | .fixups = &mt25qu512a_fixups, |
470 | }, { |
471 | .id = SNOR_ID(0x20, 0xbb, 0x20), |
472 | .name = "n25q512a" , |
473 | .size = SZ_64M, |
474 | .flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP | |
475 | SPI_NOR_BP3_SR_BIT6, |
476 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
477 | .mfr_flags = USE_FSR, |
478 | }, { |
479 | .id = SNOR_ID(0x20, 0xbb, 0x21, 0x10, 0x44, 0x00), |
480 | .name = "mt25qu01g" , |
481 | .mfr_flags = USE_FSR, |
482 | .fixups = &mt25q01_fixups, |
483 | }, { |
484 | .id = SNOR_ID(0x20, 0xbb, 0x21), |
485 | .name = "n25q00a" , |
486 | .size = SZ_128M, |
487 | .no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ, |
488 | .mfr_flags = USE_FSR, |
489 | .fixups = &n25q00_fixups, |
490 | }, { |
491 | .id = SNOR_ID(0x20, 0xbb, 0x22), |
492 | .name = "mt25qu02g" , |
493 | .size = SZ_256M, |
494 | .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ, |
495 | .mfr_flags = USE_FSR, |
496 | .fixups = &mt25q02_fixups, |
497 | } |
498 | }; |
499 | |
500 | /** |
501 | * micron_st_nor_read_fsr() - Read the Flag Status Register. |
502 | * @nor: pointer to 'struct spi_nor' |
503 | * @fsr: pointer to a DMA-able buffer where the value of the |
504 | * Flag Status Register will be written. Should be at least 2 |
505 | * bytes. |
506 | * |
507 | * Return: 0 on success, -errno otherwise. |
508 | */ |
509 | static int micron_st_nor_read_fsr(struct spi_nor *nor, u8 *fsr) |
510 | { |
511 | int ret; |
512 | |
513 | if (nor->spimem) { |
514 | struct spi_mem_op op = MICRON_ST_RDFSR_OP(fsr); |
515 | |
516 | if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) { |
517 | op.addr.nbytes = nor->params->rdsr_addr_nbytes; |
518 | op.dummy.nbytes = nor->params->rdsr_dummy; |
519 | /* |
520 | * We don't want to read only one byte in DTR mode. So, |
521 | * read 2 and then discard the second byte. |
522 | */ |
523 | op.data.nbytes = 2; |
524 | } |
525 | |
526 | spi_nor_spimem_setup_op(nor, op: &op, proto: nor->reg_proto); |
527 | |
528 | ret = spi_mem_exec_op(mem: nor->spimem, op: &op); |
529 | } else { |
530 | ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, buf: fsr, |
531 | len: 1); |
532 | } |
533 | |
534 | if (ret) |
535 | dev_dbg(nor->dev, "error %d reading FSR\n" , ret); |
536 | |
537 | return ret; |
538 | } |
539 | |
540 | /** |
541 | * micron_st_nor_clear_fsr() - Clear the Flag Status Register. |
542 | * @nor: pointer to 'struct spi_nor'. |
543 | */ |
544 | static void micron_st_nor_clear_fsr(struct spi_nor *nor) |
545 | { |
546 | int ret; |
547 | |
548 | if (nor->spimem) { |
549 | struct spi_mem_op op = MICRON_ST_CLFSR_OP; |
550 | |
551 | spi_nor_spimem_setup_op(nor, op: &op, proto: nor->reg_proto); |
552 | |
553 | ret = spi_mem_exec_op(mem: nor->spimem, op: &op); |
554 | } else { |
555 | ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR, |
556 | NULL, len: 0); |
557 | } |
558 | |
559 | if (ret) |
560 | dev_dbg(nor->dev, "error %d clearing FSR\n" , ret); |
561 | } |
562 | |
563 | /** |
564 | * micron_st_nor_ready() - Query the Status Register as well as the Flag Status |
565 | * Register to see if the flash is ready for new commands. If there are any |
566 | * errors in the FSR clear them. |
567 | * @nor: pointer to 'struct spi_nor'. |
568 | * |
569 | * Return: 1 if ready, 0 if not ready, -errno on errors. |
570 | */ |
571 | static int micron_st_nor_ready(struct spi_nor *nor) |
572 | { |
573 | int sr_ready, ret; |
574 | |
575 | sr_ready = spi_nor_sr_ready(nor); |
576 | if (sr_ready < 0) |
577 | return sr_ready; |
578 | |
579 | ret = micron_st_nor_read_fsr(nor, fsr: nor->bouncebuf); |
580 | if (ret) { |
581 | /* |
582 | * Some controllers, such as Intel SPI, do not support low |
583 | * level operations such as reading the flag status |
584 | * register. They only expose small amount of high level |
585 | * operations to the software. If this is the case we use |
586 | * only the status register value. |
587 | */ |
588 | return ret == -EOPNOTSUPP ? sr_ready : ret; |
589 | } |
590 | |
591 | if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) { |
592 | if (nor->bouncebuf[0] & FSR_E_ERR) |
593 | dev_err(nor->dev, "Erase operation failed.\n" ); |
594 | else |
595 | dev_err(nor->dev, "Program operation failed.\n" ); |
596 | |
597 | if (nor->bouncebuf[0] & FSR_PT_ERR) |
598 | dev_err(nor->dev, |
599 | "Attempted to modify a protected sector.\n" ); |
600 | |
601 | micron_st_nor_clear_fsr(nor); |
602 | |
603 | /* |
604 | * WEL bit remains set to one when an erase or page program |
605 | * error occurs. Issue a Write Disable command to protect |
606 | * against inadvertent writes that can possibly corrupt the |
607 | * contents of the memory. |
608 | */ |
609 | ret = spi_nor_write_disable(nor); |
610 | if (ret) |
611 | return ret; |
612 | |
613 | return -EIO; |
614 | } |
615 | |
616 | return sr_ready && !!(nor->bouncebuf[0] & FSR_READY); |
617 | } |
618 | |
619 | static void micron_st_nor_default_init(struct spi_nor *nor) |
620 | { |
621 | nor->flags |= SNOR_F_HAS_LOCK; |
622 | nor->flags &= ~SNOR_F_HAS_16BIT_SR; |
623 | nor->params->quad_enable = NULL; |
624 | } |
625 | |
626 | static int micron_st_nor_late_init(struct spi_nor *nor) |
627 | { |
628 | struct spi_nor_flash_parameter *params = nor->params; |
629 | |
630 | if (nor->info->mfr_flags & USE_FSR) |
631 | params->ready = micron_st_nor_ready; |
632 | |
633 | if (!params->set_4byte_addr_mode) |
634 | params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b; |
635 | |
636 | return 0; |
637 | } |
638 | |
639 | static const struct spi_nor_fixups micron_st_nor_fixups = { |
640 | .default_init = micron_st_nor_default_init, |
641 | .late_init = micron_st_nor_late_init, |
642 | }; |
643 | |
644 | const struct spi_nor_manufacturer spi_nor_micron = { |
645 | .name = "micron" , |
646 | .parts = micron_nor_parts, |
647 | .nparts = ARRAY_SIZE(micron_nor_parts), |
648 | .fixups = µn_st_nor_fixups, |
649 | }; |
650 | |
651 | const struct spi_nor_manufacturer spi_nor_st = { |
652 | .name = "st" , |
653 | .parts = st_nor_parts, |
654 | .nparts = ARRAY_SIZE(st_nor_parts), |
655 | .fixups = µn_st_nor_fixups, |
656 | }; |
657 | |