File Index
Files and directories
Sign in
FILE

micron-st.c

File preview with syntax highlighting.

linux-6.19.14/drivers/mtd/spi-nor/micron-st.c C
  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
 51static 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, 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, 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, 0, 8, buf, 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(buf, nor->info->id->bytes, nor->info->id->len))
 83		return -EINVAL;
 84
 85	return 0;
 86}
 87
 88static 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, 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, 0, 0, buf, 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(buf, nor->info->id->bytes, nor->info->id->len))
119		return -EINVAL;
120
121	return 0;
122}
123
124static 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
130static int micron_st_nor_four_die_late_init(struct spi_nor *nor)
131{
132	struct spi_nor_flash_parameter *params = nor->params;
133
134	params->die_erase_opcode = SPINOR_OP_MT_DIE_ERASE;
135	params->n_dice = 4;
136
137	/*
138	 * Unfortunately the die erase opcode does not have a 4-byte opcode
139	 * correspondent for these flashes. The SFDP 4BAIT table fails to
140	 * consider the die erase too. We're forced to enter in the 4 byte
141	 * address mode in order to benefit of the die erase.
142	 */
143	return spi_nor_set_4byte_addr_mode(nor, true);
144}
145
146static int micron_st_nor_two_die_late_init(struct spi_nor *nor)
147{
148	struct spi_nor_flash_parameter *params = nor->params;
149
150	params->die_erase_opcode = SPINOR_OP_MT_DIE_ERASE;
151	params->n_dice = 2;
152
153	/*
154	 * Unfortunately the die erase opcode does not have a 4-byte opcode
155	 * correspondent for these flashes. The SFDP 4BAIT table fails to
156	 * consider the die erase too. We're forced to enter in the 4 byte
157	 * address mode in order to benefit of the die erase.
158	 */
159	return spi_nor_set_4byte_addr_mode(nor, true);
160}
161
162static int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
163{
164	/* Set the Fast Read settings. */
165	nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
166	spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
167				  0, 20, SPINOR_OP_MT_DTR_RD,
168				  SNOR_PROTO_8_8_8_DTR);
169
170	nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
171	nor->params->rdsr_dummy = 8;
172	nor->params->rdsr_addr_nbytes = 0;
173
174	/*
175	 * The BFPT quad enable field is set to a reserved value so the quad
176	 * enable function is ignored by spi_nor_parse_bfpt(). Make sure we
177	 * disable it.
178	 */
179	nor->params->quad_enable = NULL;
180
181	return 0;
182}
183
184static const struct spi_nor_fixups mt35xu512aba_fixups = {
185	.post_sfdp = mt35xu512aba_post_sfdp_fixup,
186};
187
188static const struct spi_nor_fixups mt35xu01gbba_fixups = {
189	.post_sfdp = mt35xu512aba_post_sfdp_fixup,
190	.late_init = micron_st_nor_two_die_late_init,
191};
192
193static const struct flash_info micron_nor_parts[] = {
194	{
195		/* MT35XU512ABA */
196		.id = SNOR_ID(0x2c, 0x5b, 0x1a),
197		.mfr_flags = USE_FSR,
198		.fixup_flags = SPI_NOR_IO_MODE_EN_VOLATILE,
199		.fixups = &mt35xu512aba_fixups,
200	}, {
201		/* MT35XU01GBBA */
202		.id = SNOR_ID(0x2c, 0x5b, 0x1b),
203		.mfr_flags = USE_FSR,
204		.fixup_flags = SPI_NOR_IO_MODE_EN_VOLATILE,
205		.fixups = &mt35xu01gbba_fixups,
206	}, {
207		/*
208		 * The MT35XU02GCBA flash device does not support chip erase,
209		 * according to its datasheet. It supports die erase, which
210		 * means the current driver implementation will likely need to
211		 * be converted to use die erase. Furthermore, similar to the
212		 * MT35XU01GBBA, the SPI_NOR_IO_MODE_EN_VOLATILE flag probably
213		 * needs to be enabled.
214		 *
215		 * TODO: Fix these and test on real hardware.
216		 */
217		.id = SNOR_ID(0x2c, 0x5b, 0x1c),
218		.name = "mt35xu02g",
219		.sector_size = SZ_128K,
220		.size = SZ_256M,
221		.no_sfdp_flags = SECT_4K | SPI_NOR_OCTAL_READ,
222		.mfr_flags = USE_FSR,
223		.fixup_flags = SPI_NOR_4B_OPCODES,
224	},
225};
226
227static int mt25qu512a_post_bfpt_fixup(struct spi_nor *nor,
228				      const struct sfdp_parameter_header *bfpt_header,
229				      const struct sfdp_bfpt *bfpt)
230{
231	nor->flags &= ~SNOR_F_HAS_16BIT_SR;
232	return 0;
233}
234
235static const struct spi_nor_fixups mt25qu512a_fixups = {
236	.post_bfpt = mt25qu512a_post_bfpt_fixup,
237};
238
239static const struct spi_nor_fixups n25q00_fixups = {
240	.late_init = micron_st_nor_four_die_late_init,
241};
242
243static const struct spi_nor_fixups mt25q01_fixups = {
244	.late_init = micron_st_nor_two_die_late_init,
245};
246
247static const struct spi_nor_fixups mt25q02_fixups = {
248	.late_init = micron_st_nor_four_die_late_init,
249};
250
251static const struct flash_info st_nor_parts[] = {
252	{
253		.name = "m25p05-nonjedec",
254		.sector_size = SZ_32K,
255		.size = SZ_64K,
256	}, {
257		.name = "m25p10-nonjedec",
258		.sector_size = SZ_32K,
259		.size = SZ_128K,
260	}, {
261		.name = "m25p20-nonjedec",
262		.size = SZ_256K,
263	}, {
264		.name = "m25p40-nonjedec",
265		.size = SZ_512K,
266	}, {
267		.name = "m25p80-nonjedec",
268		.size = SZ_1M,
269	}, {
270		.name = "m25p16-nonjedec",
271		.size = SZ_2M,
272	}, {
273		.name = "m25p32-nonjedec",
274		.size = SZ_4M,
275	}, {
276		.name = "m25p64-nonjedec",
277		.size = SZ_8M,
278	}, {
279		.name = "m25p128-nonjedec",
280		.sector_size = SZ_256K,
281		.size = SZ_16M,
282	}, {
283		.id = SNOR_ID(0x20, 0x20, 0x10),
284		.name = "m25p05",
285		.sector_size = SZ_32K,
286		.size = SZ_64K,
287	}, {
288		.id = SNOR_ID(0x20, 0x20, 0x11),
289		.name = "m25p10",
290		.sector_size = SZ_32K,
291		.size = SZ_128K,
292	}, {
293		.id = SNOR_ID(0x20, 0x20, 0x12),
294		.name = "m25p20",
295		.size = SZ_256K,
296	}, {
297		.id = SNOR_ID(0x20, 0x20, 0x13),
298		.name = "m25p40",
299		.size = SZ_512K,
300	}, {
301		.id = SNOR_ID(0x20, 0x20, 0x14),
302		.name = "m25p80",
303		.size = SZ_1M,
304	}, {
305		.id = SNOR_ID(0x20, 0x20, 0x15),
306		.name = "m25p16",
307		.size = SZ_2M,
308	}, {
309		.id = SNOR_ID(0x20, 0x20, 0x16),
310		.name = "m25p32",
311		.size = SZ_4M,
312	}, {
313		.id = SNOR_ID(0x20, 0x20, 0x17),
314		.name = "m25p64",
315		.size = SZ_8M,
316	}, {
317		.id = SNOR_ID(0x20, 0x20, 0x18),
318		.name = "m25p128",
319		.sector_size = SZ_256K,
320		.size = SZ_16M,
321	}, {
322		.id = SNOR_ID(0x20, 0x40, 0x11),
323		.name = "m45pe10",
324		.size = SZ_128K,
325	}, {
326		.id = SNOR_ID(0x20, 0x40, 0x14),
327		.name = "m45pe80",
328		.size = SZ_1M,
329	}, {
330		.id = SNOR_ID(0x20, 0x40, 0x15),
331		.name = "m45pe16",
332		.size = SZ_2M,
333	}, {
334		.id = SNOR_ID(0x20, 0x63, 0x16),
335		.name = "m25px32-s1",
336		.size = SZ_4M,
337		.no_sfdp_flags = SECT_4K,
338	}, {
339		.id = SNOR_ID(0x20, 0x71, 0x14),
340		.name = "m25px80",
341		.size = SZ_1M,
342	}, {
343		.id = SNOR_ID(0x20, 0x71, 0x15),
344		.name = "m25px16",
345		.size = SZ_2M,
346		.no_sfdp_flags = SECT_4K,
347	}, {
348		.id = SNOR_ID(0x20, 0x71, 0x16),
349		.name = "m25px32",
350		.size = SZ_4M,
351		.no_sfdp_flags = SECT_4K,
352	}, {
353		.id = SNOR_ID(0x20, 0x71, 0x17),
354		.name = "m25px64",
355		.size = SZ_8M,
356	}, {
357		.id = SNOR_ID(0x20, 0x73, 0x16),
358		.name = "m25px32-s0",
359		.size = SZ_4M,
360		.no_sfdp_flags = SECT_4K,
361	}, {
362		.id = SNOR_ID(0x20, 0x80, 0x12),
363		.name = "m25pe20",
364		.size = SZ_256K,
365	}, {
366		.id = SNOR_ID(0x20, 0x80, 0x14),
367		.name = "m25pe80",
368		.size = SZ_1M,
369	}, {
370		.id = SNOR_ID(0x20, 0x80, 0x15),
371		.name = "m25pe16",
372		.size = SZ_2M,
373		.no_sfdp_flags = SECT_4K,
374	}, {
375		.id = SNOR_ID(0x20, 0xba, 0x16),
376		.name = "n25q032",
377		.size = SZ_4M,
378		.no_sfdp_flags = SPI_NOR_QUAD_READ,
379	}, {
380		.id = SNOR_ID(0x20, 0xba, 0x17),
381		.name = "n25q064",
382		.size = SZ_8M,
383		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
384	}, {
385		.id = SNOR_ID(0x20, 0xba, 0x18),
386		.name = "n25q128a13",
387		.size = SZ_16M,
388		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
389			 SPI_NOR_BP3_SR_BIT6,
390		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
391		.mfr_flags = USE_FSR,
392	}, {
393		.id = SNOR_ID(0x20, 0xba, 0x19, 0x10, 0x44, 0x00),
394		.name = "mt25ql256a",
395		.size = SZ_32M,
396		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
397		.fixup_flags = SPI_NOR_4B_OPCODES,
398		.mfr_flags = USE_FSR,
399	}, {
400		.id = SNOR_ID(0x20, 0xba, 0x19),
401		.name = "n25q256a",
402		.size = SZ_32M,
403		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
404		.mfr_flags = USE_FSR,
405	}, {
406		.id = SNOR_ID(0x20, 0xba, 0x20, 0x10, 0x44, 0x00),
407		.name = "mt25ql512a",
408		.size = SZ_64M,
409		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
410		.fixup_flags = SPI_NOR_4B_OPCODES,
411		.mfr_flags = USE_FSR,
412	}, {
413		.id = SNOR_ID(0x20, 0xba, 0x20),
414		.name = "n25q512ax3",
415		.size = SZ_64M,
416		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
417			 SPI_NOR_BP3_SR_BIT6,
418		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
419		.mfr_flags = USE_FSR,
420	}, {
421		.id = SNOR_ID(0x20, 0xba, 0x21),
422		.name = "n25q00",
423		.size = SZ_128M,
424		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
425			 SPI_NOR_BP3_SR_BIT6,
426		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
427		.mfr_flags = USE_FSR,
428		.fixups = &n25q00_fixups,
429	}, {
430		.id = SNOR_ID(0x20, 0xba, 0x22),
431		.name = "mt25ql02g",
432		.size = SZ_256M,
433		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
434		.mfr_flags = USE_FSR,
435		.fixups = &mt25q02_fixups,
436	}, {
437		.id = SNOR_ID(0x20, 0xbb, 0x15),
438		.name = "n25q016a",
439		.size = SZ_2M,
440		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
441	}, {
442		.id = SNOR_ID(0x20, 0xbb, 0x16),
443		.name = "n25q032a",
444		.size = SZ_4M,
445		.no_sfdp_flags = SPI_NOR_QUAD_READ,
446	}, {
447		.id = SNOR_ID(0x20, 0xbb, 0x17),
448		.name = "n25q064a",
449		.size = SZ_8M,
450		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
451			 SPI_NOR_BP3_SR_BIT6,
452		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
453	}, {
454		.id = SNOR_ID(0x20, 0xbb, 0x18),
455		.name = "n25q128a11",
456		.size = SZ_16M,
457		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
458			 SPI_NOR_BP3_SR_BIT6,
459		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
460		.mfr_flags = USE_FSR,
461	}, {
462		.id = SNOR_ID(0x20, 0xbb, 0x19, 0x10, 0x44, 0x00),
463		.name = "mt25qu256a",
464		.size = SZ_32M,
465		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
466			 SPI_NOR_BP3_SR_BIT6,
467		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
468		.fixup_flags = SPI_NOR_4B_OPCODES,
469		.mfr_flags = USE_FSR,
470	}, {
471		.id = SNOR_ID(0x20, 0xbb, 0x19),
472		.name = "n25q256ax1",
473		.size = SZ_32M,
474		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
475		.mfr_flags = USE_FSR,
476	}, {
477		.id = SNOR_ID(0x20, 0xbb, 0x20, 0x10, 0x44, 0x00),
478		.name = "mt25qu512a",
479		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
480			 SPI_NOR_BP3_SR_BIT6,
481		.mfr_flags = USE_FSR,
482		.fixups = &mt25qu512a_fixups,
483	}, {
484		.id = SNOR_ID(0x20, 0xbb, 0x20),
485		.name = "n25q512a",
486		.size = SZ_64M,
487		.flags = SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
488			 SPI_NOR_BP3_SR_BIT6,
489		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
490		.mfr_flags = USE_FSR,
491	}, {
492		.id = SNOR_ID(0x20, 0xbb, 0x21, 0x10, 0x44, 0x00),
493		.name = "mt25qu01g",
494		.mfr_flags = USE_FSR,
495		.fixups = &mt25q01_fixups,
496	}, {
497		.id = SNOR_ID(0x20, 0xbb, 0x21),
498		.name = "n25q00a",
499		.size = SZ_128M,
500		.no_sfdp_flags = SECT_4K | SPI_NOR_QUAD_READ,
501		.mfr_flags = USE_FSR,
502		.fixups = &n25q00_fixups,
503	}, {
504		.id = SNOR_ID(0x20, 0xbb, 0x22),
505		.name = "mt25qu02g",
506		.size = SZ_256M,
507		.no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
508		.mfr_flags = USE_FSR,
509		.fixups = &mt25q02_fixups,
510	}
511};
512
513/**
514 * micron_st_nor_read_fsr() - Read the Flag Status Register.
515 * @nor:	pointer to 'struct spi_nor'
516 * @fsr:	pointer to a DMA-able buffer where the value of the
517 *              Flag Status Register will be written. Should be at least 2
518 *              bytes.
519 *
520 * Return: 0 on success, -errno otherwise.
521 */
522static int micron_st_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
523{
524	int ret;
525
526	if (nor->spimem) {
527		struct spi_mem_op op = MICRON_ST_RDFSR_OP(fsr);
528
529		if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
530			op.addr.nbytes = nor->params->rdsr_addr_nbytes;
531			op.dummy.nbytes = nor->params->rdsr_dummy;
532			/*
533			 * We don't want to read only one byte in DTR mode. So,
534			 * read 2 and then discard the second byte.
535			 */
536			op.data.nbytes = 2;
537		}
538
539		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
540
541		ret = spi_mem_exec_op(nor->spimem, &op);
542	} else {
543		ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
544						      1);
545	}
546
547	if (ret)
548		dev_dbg(nor->dev, "error %d reading FSR\n", ret);
549
550	return ret;
551}
552
553/**
554 * micron_st_nor_clear_fsr() - Clear the Flag Status Register.
555 * @nor:	pointer to 'struct spi_nor'.
556 */
557static void micron_st_nor_clear_fsr(struct spi_nor *nor)
558{
559	int ret;
560
561	if (nor->spimem) {
562		struct spi_mem_op op = MICRON_ST_CLFSR_OP;
563
564		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
565
566		ret = spi_mem_exec_op(nor->spimem, &op);
567	} else {
568		ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
569						       NULL, 0);
570	}
571
572	if (ret)
573		dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
574}
575
576/**
577 * micron_st_nor_ready() - Query the Status Register as well as the Flag Status
578 * Register to see if the flash is ready for new commands. If there are any
579 * errors in the FSR clear them.
580 * @nor:	pointer to 'struct spi_nor'.
581 *
582 * Return: 1 if ready, 0 if not ready, -errno on errors.
583 */
584static int micron_st_nor_ready(struct spi_nor *nor)
585{
586	int sr_ready, ret;
587
588	sr_ready = spi_nor_sr_ready(nor);
589	if (sr_ready < 0)
590		return sr_ready;
591
592	ret = micron_st_nor_read_fsr(nor, nor->bouncebuf);
593	if (ret) {
594		/*
595		 * Some controllers, such as Intel SPI, do not support low
596		 * level operations such as reading the flag status
597		 * register. They only expose small amount of high level
598		 * operations to the software. If this is the case we use
599		 * only the status register value.
600		 */
601		return ret == -EOPNOTSUPP ? sr_ready : ret;
602	}
603
604	if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
605		if (nor->bouncebuf[0] & FSR_E_ERR)
606			dev_err(nor->dev, "Erase operation failed.\n");
607		else
608			dev_err(nor->dev, "Program operation failed.\n");
609
610		if (nor->bouncebuf[0] & FSR_PT_ERR)
611			dev_err(nor->dev,
612				"Attempted to modify a protected sector.\n");
613
614		micron_st_nor_clear_fsr(nor);
615
616		/*
617		 * WEL bit remains set to one when an erase or page program
618		 * error occurs. Issue a Write Disable command to protect
619		 * against inadvertent writes that can possibly corrupt the
620		 * contents of the memory.
621		 */
622		ret = spi_nor_write_disable(nor);
623		if (ret)
624			return ret;
625
626		return -EIO;
627	}
628
629	return sr_ready && !!(nor->bouncebuf[0] & FSR_READY);
630}
631
632static void micron_st_nor_default_init(struct spi_nor *nor)
633{
634	nor->flags |= SNOR_F_HAS_LOCK;
635	nor->flags &= ~SNOR_F_HAS_16BIT_SR;
636	nor->params->quad_enable = NULL;
637}
638
639static int micron_st_nor_late_init(struct spi_nor *nor)
640{
641	struct spi_nor_flash_parameter *params = nor->params;
642
643	if (nor->info->mfr_flags & USE_FSR)
644		params->ready = micron_st_nor_ready;
645
646	if (!params->set_4byte_addr_mode)
647		params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
648
649	params->set_octal_dtr = micron_st_nor_set_octal_dtr;
650
651	return 0;
652}
653
654static const struct spi_nor_fixups micron_st_nor_fixups = {
655	.default_init = micron_st_nor_default_init,
656	.late_init = micron_st_nor_late_init,
657};
658
659const struct spi_nor_manufacturer spi_nor_micron = {
660	.name = "micron",
661	.parts = micron_nor_parts,
662	.nparts = ARRAY_SIZE(micron_nor_parts),
663	.fixups = &micron_st_nor_fixups,
664};
665
666const struct spi_nor_manufacturer spi_nor_st = {
667	.name = "st",
668	.parts = st_nor_parts,
669	.nparts = ARRAY_SIZE(st_nor_parts),
670	.fixups = &micron_st_nor_fixups,
671};
~/ Read-only file preview.