162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005, Intec Automation Inc.
462306a36Sopenharmony_ci * Copyright (C) 2014, Freescale Semiconductor, Inc.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/mtd/spi-nor.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "core.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/* flash_info mfr_flag. Used to read proprietary FSR register. */
1262306a36Sopenharmony_ci#define USE_FSR		BIT(0)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define SPINOR_OP_RDFSR		0x70	/* Read flag status register */
1562306a36Sopenharmony_ci#define SPINOR_OP_CLFSR		0x50	/* Clear flag status register */
1662306a36Sopenharmony_ci#define SPINOR_OP_MT_DTR_RD	0xfd	/* Fast Read opcode in DTR mode */
1762306a36Sopenharmony_ci#define SPINOR_OP_MT_RD_ANY_REG	0x85	/* Read volatile register */
1862306a36Sopenharmony_ci#define SPINOR_OP_MT_WR_ANY_REG	0x81	/* Write volatile register */
1962306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR0V	0x00	/* For setting octal DTR mode */
2062306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR1V	0x01	/* For setting dummy cycles */
2162306a36Sopenharmony_ci#define SPINOR_REG_MT_CFR1V_DEF	0x1f	/* Default dummy cycles */
2262306a36Sopenharmony_ci#define SPINOR_MT_OCT_DTR	0xe7	/* Enable Octal DTR. */
2362306a36Sopenharmony_ci#define SPINOR_MT_EXSPI		0xff	/* Enable Extended SPI (default) */
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Flag Status Register bits */
2662306a36Sopenharmony_ci#define FSR_READY		BIT(7)	/* Device status, 0 = Busy, 1 = Ready */
2762306a36Sopenharmony_ci#define FSR_E_ERR		BIT(5)	/* Erase operation status */
2862306a36Sopenharmony_ci#define FSR_P_ERR		BIT(4)	/* Program operation status */
2962306a36Sopenharmony_ci#define FSR_PT_ERR		BIT(1)	/* Protection error bit */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci/* Micron ST SPI NOR flash operations. */
3262306a36Sopenharmony_ci#define MICRON_ST_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf)		\
3362306a36Sopenharmony_ci	SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 0),		\
3462306a36Sopenharmony_ci		   SPI_MEM_OP_ADDR(naddr, addr, 0),			\
3562306a36Sopenharmony_ci		   SPI_MEM_OP_NO_DUMMY,					\
3662306a36Sopenharmony_ci		   SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define MICRON_ST_RDFSR_OP(buf)						\
3962306a36Sopenharmony_ci	SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 0),			\
4062306a36Sopenharmony_ci		   SPI_MEM_OP_NO_ADDR,					\
4162306a36Sopenharmony_ci		   SPI_MEM_OP_NO_DUMMY,					\
4262306a36Sopenharmony_ci		   SPI_MEM_OP_DATA_IN(1, buf, 0))
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define MICRON_ST_CLFSR_OP						\
4562306a36Sopenharmony_ci	SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLFSR, 0),			\
4662306a36Sopenharmony_ci		   SPI_MEM_OP_NO_ADDR,					\
4762306a36Sopenharmony_ci		   SPI_MEM_OP_NO_DUMMY,					\
4862306a36Sopenharmony_ci		   SPI_MEM_OP_NO_DATA)
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic int micron_st_nor_octal_dtr_en(struct spi_nor *nor)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	struct spi_mem_op op;
5362306a36Sopenharmony_ci	u8 *buf = nor->bouncebuf;
5462306a36Sopenharmony_ci	int ret;
5562306a36Sopenharmony_ci	u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Use 20 dummy cycles for memory array reads. */
5862306a36Sopenharmony_ci	*buf = 20;
5962306a36Sopenharmony_ci	op = (struct spi_mem_op)
6062306a36Sopenharmony_ci		MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
6162306a36Sopenharmony_ci					    SPINOR_REG_MT_CFR1V, 1, buf);
6262306a36Sopenharmony_ci	ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
6362306a36Sopenharmony_ci	if (ret)
6462306a36Sopenharmony_ci		return ret;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	buf[0] = SPINOR_MT_OCT_DTR;
6762306a36Sopenharmony_ci	op = (struct spi_mem_op)
6862306a36Sopenharmony_ci		MICRON_ST_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
6962306a36Sopenharmony_ci					    SPINOR_REG_MT_CFR0V, 1, buf);
7062306a36Sopenharmony_ci	ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
7162306a36Sopenharmony_ci	if (ret)
7262306a36Sopenharmony_ci		return ret;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	/* Read flash ID to make sure the switch was successful. */
7562306a36Sopenharmony_ci	ret = spi_nor_read_id(nor, 0, 8, buf, SNOR_PROTO_8_8_8_DTR);
7662306a36Sopenharmony_ci	if (ret) {
7762306a36Sopenharmony_ci		dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
7862306a36Sopenharmony_ci		return ret;
7962306a36Sopenharmony_ci	}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (memcmp(buf, nor->info->id, nor->info->id_len))
8262306a36Sopenharmony_ci		return -EINVAL;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	return 0;
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int micron_st_nor_octal_dtr_dis(struct spi_nor *nor)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct spi_mem_op op;
9062306a36Sopenharmony_ci	u8 *buf = nor->bouncebuf;
9162306a36Sopenharmony_ci	int ret;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	/*
9462306a36Sopenharmony_ci	 * The register is 1-byte wide, but 1-byte transactions are not allowed
9562306a36Sopenharmony_ci	 * in 8D-8D-8D mode. The next register is the dummy cycle configuration
9662306a36Sopenharmony_ci	 * register. Since the transaction needs to be at least 2 bytes wide,
9762306a36Sopenharmony_ci	 * set the next register to its default value. This also makes sense
9862306a36Sopenharmony_ci	 * because the value was changed when enabling 8D-8D-8D mode, it should
9962306a36Sopenharmony_ci	 * be reset when disabling.
10062306a36Sopenharmony_ci	 */
10162306a36Sopenharmony_ci	buf[0] = SPINOR_MT_EXSPI;
10262306a36Sopenharmony_ci	buf[1] = SPINOR_REG_MT_CFR1V_DEF;
10362306a36Sopenharmony_ci	op = (struct spi_mem_op)
10462306a36Sopenharmony_ci		MICRON_ST_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
10562306a36Sopenharmony_ci					    SPINOR_REG_MT_CFR0V, 2, buf);
10662306a36Sopenharmony_ci	ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
10762306a36Sopenharmony_ci	if (ret)
10862306a36Sopenharmony_ci		return ret;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Read flash ID to make sure the switch was successful. */
11162306a36Sopenharmony_ci	ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
11262306a36Sopenharmony_ci	if (ret) {
11362306a36Sopenharmony_ci		dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret);
11462306a36Sopenharmony_ci		return ret;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (memcmp(buf, nor->info->id, nor->info->id_len))
11862306a36Sopenharmony_ci		return -EINVAL;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic int micron_st_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	return enable ? micron_st_nor_octal_dtr_en(nor) :
12662306a36Sopenharmony_ci			micron_st_nor_octal_dtr_dis(nor);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void mt35xu512aba_default_init(struct spi_nor *nor)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	nor->params->set_octal_dtr = micron_st_nor_set_octal_dtr;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic int mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	/* Set the Fast Read settings. */
13762306a36Sopenharmony_ci	nor->params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
13862306a36Sopenharmony_ci	spi_nor_set_read_settings(&nor->params->reads[SNOR_CMD_READ_8_8_8_DTR],
13962306a36Sopenharmony_ci				  0, 20, SPINOR_OP_MT_DTR_RD,
14062306a36Sopenharmony_ci				  SNOR_PROTO_8_8_8_DTR);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
14362306a36Sopenharmony_ci	nor->params->rdsr_dummy = 8;
14462306a36Sopenharmony_ci	nor->params->rdsr_addr_nbytes = 0;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	/*
14762306a36Sopenharmony_ci	 * The BFPT quad enable field is set to a reserved value so the quad
14862306a36Sopenharmony_ci	 * enable function is ignored by spi_nor_parse_bfpt(). Make sure we
14962306a36Sopenharmony_ci	 * disable it.
15062306a36Sopenharmony_ci	 */
15162306a36Sopenharmony_ci	nor->params->quad_enable = NULL;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	return 0;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic const struct spi_nor_fixups mt35xu512aba_fixups = {
15762306a36Sopenharmony_ci	.default_init = mt35xu512aba_default_init,
15862306a36Sopenharmony_ci	.post_sfdp = mt35xu512aba_post_sfdp_fixup,
15962306a36Sopenharmony_ci};
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic const struct flash_info micron_nor_parts[] = {
16262306a36Sopenharmony_ci	{ "mt35xu512aba", INFO(0x2c5b1a, 0, 128 * 1024, 512)
16362306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ |
16462306a36Sopenharmony_ci			   SPI_NOR_OCTAL_DTR_READ | SPI_NOR_OCTAL_DTR_PP)
16562306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES | SPI_NOR_IO_MODE_EN_VOLATILE)
16662306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
16762306a36Sopenharmony_ci		.fixups = &mt35xu512aba_fixups
16862306a36Sopenharmony_ci	},
16962306a36Sopenharmony_ci	{ "mt35xu02g", INFO(0x2c5b1c, 0, 128 * 1024, 2048)
17062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_OCTAL_READ)
17162306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
17262306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
17362306a36Sopenharmony_ci	},
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic const struct flash_info st_nor_parts[] = {
17762306a36Sopenharmony_ci	{ "n25q016a",	 INFO(0x20bb15, 0, 64 * 1024,   32)
17862306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
17962306a36Sopenharmony_ci	{ "n25q032",	 INFO(0x20ba16, 0, 64 * 1024,   64)
18062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SPI_NOR_QUAD_READ) },
18162306a36Sopenharmony_ci	{ "n25q032a",	 INFO(0x20bb16, 0, 64 * 1024,   64)
18262306a36Sopenharmony_ci		NO_SFDP_FLAGS(SPI_NOR_QUAD_READ) },
18362306a36Sopenharmony_ci	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128)
18462306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
18562306a36Sopenharmony_ci	{ "n25q064a",    INFO(0x20bb17, 0, 64 * 1024,  128)
18662306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ) },
18762306a36Sopenharmony_ci	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256)
18862306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
18962306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6)
19062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
19162306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
19262306a36Sopenharmony_ci	},
19362306a36Sopenharmony_ci	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256)
19462306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
19562306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6)
19662306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
19762306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
19862306a36Sopenharmony_ci	},
19962306a36Sopenharmony_ci	{ "mt25ql256a",  INFO6(0x20ba19, 0x104400, 64 * 1024,  512)
20062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
20162306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
20262306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
20362306a36Sopenharmony_ci	},
20462306a36Sopenharmony_ci	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512)
20562306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
20662306a36Sopenharmony_ci			      SPI_NOR_QUAD_READ)
20762306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
20862306a36Sopenharmony_ci	},
20962306a36Sopenharmony_ci	{ "mt25qu256a",  INFO6(0x20bb19, 0x104400, 64 * 1024,  512)
21062306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
21162306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6)
21262306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
21362306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
21462306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
21562306a36Sopenharmony_ci	},
21662306a36Sopenharmony_ci	{ "n25q256ax1",  INFO(0x20bb19, 0, 64 * 1024,  512)
21762306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
21862306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
21962306a36Sopenharmony_ci	},
22062306a36Sopenharmony_ci	{ "mt25ql512a",  INFO6(0x20ba20, 0x104400, 64 * 1024, 1024)
22162306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
22262306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
22362306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
22462306a36Sopenharmony_ci	},
22562306a36Sopenharmony_ci	{ "n25q512ax3",  INFO(0x20ba20, 0, 64 * 1024, 1024)
22662306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
22762306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6)
22862306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
22962306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
23062306a36Sopenharmony_ci	},
23162306a36Sopenharmony_ci	{ "mt25qu512a",  INFO6(0x20bb20, 0x104400, 64 * 1024, 1024)
23262306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
23362306a36Sopenharmony_ci		FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
23462306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
23562306a36Sopenharmony_ci	},
23662306a36Sopenharmony_ci	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024)
23762306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
23862306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6)
23962306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
24062306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
24162306a36Sopenharmony_ci	},
24262306a36Sopenharmony_ci	{ "n25q00",      INFO(0x20ba21, 0, 64 * 1024, 2048)
24362306a36Sopenharmony_ci		FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4BIT_BP |
24462306a36Sopenharmony_ci		      SPI_NOR_BP3_SR_BIT6 | NO_CHIP_ERASE)
24562306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
24662306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
24762306a36Sopenharmony_ci	},
24862306a36Sopenharmony_ci	{ "n25q00a",     INFO(0x20bb21, 0, 64 * 1024, 2048)
24962306a36Sopenharmony_ci		FLAGS(NO_CHIP_ERASE)
25062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
25162306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
25262306a36Sopenharmony_ci	},
25362306a36Sopenharmony_ci	{ "mt25ql02g",   INFO(0x20ba22, 0, 64 * 1024, 4096)
25462306a36Sopenharmony_ci		FLAGS(NO_CHIP_ERASE)
25562306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_QUAD_READ)
25662306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
25762306a36Sopenharmony_ci	},
25862306a36Sopenharmony_ci	{ "mt25qu02g",   INFO(0x20bb22, 0, 64 * 1024, 4096)
25962306a36Sopenharmony_ci		FLAGS(NO_CHIP_ERASE)
26062306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
26162306a36Sopenharmony_ci			      SPI_NOR_QUAD_READ)
26262306a36Sopenharmony_ci		MFR_FLAGS(USE_FSR)
26362306a36Sopenharmony_ci	},
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2) },
26662306a36Sopenharmony_ci	{ "m25p10",  INFO(0x202011,  0,  32 * 1024,   4) },
26762306a36Sopenharmony_ci	{ "m25p20",  INFO(0x202012,  0,  64 * 1024,   4) },
26862306a36Sopenharmony_ci	{ "m25p40",  INFO(0x202013,  0,  64 * 1024,   8) },
26962306a36Sopenharmony_ci	{ "m25p80",  INFO(0x202014,  0,  64 * 1024,  16) },
27062306a36Sopenharmony_ci	{ "m25p16",  INFO(0x202015,  0,  64 * 1024,  32) },
27162306a36Sopenharmony_ci	{ "m25p32",  INFO(0x202016,  0,  64 * 1024,  64) },
27262306a36Sopenharmony_ci	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128) },
27362306a36Sopenharmony_ci	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64) },
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2) },
27662306a36Sopenharmony_ci	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4) },
27762306a36Sopenharmony_ci	{ "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4) },
27862306a36Sopenharmony_ci	{ "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8) },
27962306a36Sopenharmony_ci	{ "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16) },
28062306a36Sopenharmony_ci	{ "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32) },
28162306a36Sopenharmony_ci	{ "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64) },
28262306a36Sopenharmony_ci	{ "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128) },
28362306a36Sopenharmony_ci	{ "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64) },
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	{ "m45pe10", INFO(0x204011,  0, 64 * 1024,    2) },
28662306a36Sopenharmony_ci	{ "m45pe80", INFO(0x204014,  0, 64 * 1024,   16) },
28762306a36Sopenharmony_ci	{ "m45pe16", INFO(0x204015,  0, 64 * 1024,   32) },
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	{ "m25pe20", INFO(0x208012,  0, 64 * 1024,  4) },
29062306a36Sopenharmony_ci	{ "m25pe80", INFO(0x208014,  0, 64 * 1024, 16) },
29162306a36Sopenharmony_ci	{ "m25pe16", INFO(0x208015,  0, 64 * 1024, 32)
29262306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K) },
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	{ "m25px16",    INFO(0x207115,  0, 64 * 1024, 32)
29562306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K) },
29662306a36Sopenharmony_ci	{ "m25px32",    INFO(0x207116,  0, 64 * 1024, 64)
29762306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K) },
29862306a36Sopenharmony_ci	{ "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64)
29962306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K) },
30062306a36Sopenharmony_ci	{ "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64)
30162306a36Sopenharmony_ci		NO_SFDP_FLAGS(SECT_4K) },
30262306a36Sopenharmony_ci	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128) },
30362306a36Sopenharmony_ci	{ "m25px80",    INFO(0x207114,  0, 64 * 1024, 16) },
30462306a36Sopenharmony_ci};
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/**
30762306a36Sopenharmony_ci * micron_st_nor_read_fsr() - Read the Flag Status Register.
30862306a36Sopenharmony_ci * @nor:	pointer to 'struct spi_nor'
30962306a36Sopenharmony_ci * @fsr:	pointer to a DMA-able buffer where the value of the
31062306a36Sopenharmony_ci *              Flag Status Register will be written. Should be at least 2
31162306a36Sopenharmony_ci *              bytes.
31262306a36Sopenharmony_ci *
31362306a36Sopenharmony_ci * Return: 0 on success, -errno otherwise.
31462306a36Sopenharmony_ci */
31562306a36Sopenharmony_cistatic int micron_st_nor_read_fsr(struct spi_nor *nor, u8 *fsr)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	int ret;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	if (nor->spimem) {
32062306a36Sopenharmony_ci		struct spi_mem_op op = MICRON_ST_RDFSR_OP(fsr);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci		if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
32362306a36Sopenharmony_ci			op.addr.nbytes = nor->params->rdsr_addr_nbytes;
32462306a36Sopenharmony_ci			op.dummy.nbytes = nor->params->rdsr_dummy;
32562306a36Sopenharmony_ci			/*
32662306a36Sopenharmony_ci			 * We don't want to read only one byte in DTR mode. So,
32762306a36Sopenharmony_ci			 * read 2 and then discard the second byte.
32862306a36Sopenharmony_ci			 */
32962306a36Sopenharmony_ci			op.data.nbytes = 2;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		ret = spi_mem_exec_op(nor->spimem, &op);
33562306a36Sopenharmony_ci	} else {
33662306a36Sopenharmony_ci		ret = spi_nor_controller_ops_read_reg(nor, SPINOR_OP_RDFSR, fsr,
33762306a36Sopenharmony_ci						      1);
33862306a36Sopenharmony_ci	}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (ret)
34162306a36Sopenharmony_ci		dev_dbg(nor->dev, "error %d reading FSR\n", ret);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	return ret;
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/**
34762306a36Sopenharmony_ci * micron_st_nor_clear_fsr() - Clear the Flag Status Register.
34862306a36Sopenharmony_ci * @nor:	pointer to 'struct spi_nor'.
34962306a36Sopenharmony_ci */
35062306a36Sopenharmony_cistatic void micron_st_nor_clear_fsr(struct spi_nor *nor)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	int ret;
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (nor->spimem) {
35562306a36Sopenharmony_ci		struct spi_mem_op op = MICRON_ST_CLFSR_OP;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		ret = spi_mem_exec_op(nor->spimem, &op);
36062306a36Sopenharmony_ci	} else {
36162306a36Sopenharmony_ci		ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLFSR,
36262306a36Sopenharmony_ci						       NULL, 0);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	if (ret)
36662306a36Sopenharmony_ci		dev_dbg(nor->dev, "error %d clearing FSR\n", ret);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/**
37062306a36Sopenharmony_ci * micron_st_nor_ready() - Query the Status Register as well as the Flag Status
37162306a36Sopenharmony_ci * Register to see if the flash is ready for new commands. If there are any
37262306a36Sopenharmony_ci * errors in the FSR clear them.
37362306a36Sopenharmony_ci * @nor:	pointer to 'struct spi_nor'.
37462306a36Sopenharmony_ci *
37562306a36Sopenharmony_ci * Return: 1 if ready, 0 if not ready, -errno on errors.
37662306a36Sopenharmony_ci */
37762306a36Sopenharmony_cistatic int micron_st_nor_ready(struct spi_nor *nor)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	int sr_ready, ret;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	sr_ready = spi_nor_sr_ready(nor);
38262306a36Sopenharmony_ci	if (sr_ready < 0)
38362306a36Sopenharmony_ci		return sr_ready;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	ret = micron_st_nor_read_fsr(nor, nor->bouncebuf);
38662306a36Sopenharmony_ci	if (ret) {
38762306a36Sopenharmony_ci		/*
38862306a36Sopenharmony_ci		 * Some controllers, such as Intel SPI, do not support low
38962306a36Sopenharmony_ci		 * level operations such as reading the flag status
39062306a36Sopenharmony_ci		 * register. They only expose small amount of high level
39162306a36Sopenharmony_ci		 * operations to the software. If this is the case we use
39262306a36Sopenharmony_ci		 * only the status register value.
39362306a36Sopenharmony_ci		 */
39462306a36Sopenharmony_ci		return ret == -EOPNOTSUPP ? sr_ready : ret;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (nor->bouncebuf[0] & (FSR_E_ERR | FSR_P_ERR)) {
39862306a36Sopenharmony_ci		if (nor->bouncebuf[0] & FSR_E_ERR)
39962306a36Sopenharmony_ci			dev_err(nor->dev, "Erase operation failed.\n");
40062306a36Sopenharmony_ci		else
40162306a36Sopenharmony_ci			dev_err(nor->dev, "Program operation failed.\n");
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		if (nor->bouncebuf[0] & FSR_PT_ERR)
40462306a36Sopenharmony_ci			dev_err(nor->dev,
40562306a36Sopenharmony_ci				"Attempted to modify a protected sector.\n");
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		micron_st_nor_clear_fsr(nor);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		/*
41062306a36Sopenharmony_ci		 * WEL bit remains set to one when an erase or page program
41162306a36Sopenharmony_ci		 * error occurs. Issue a Write Disable command to protect
41262306a36Sopenharmony_ci		 * against inadvertent writes that can possibly corrupt the
41362306a36Sopenharmony_ci		 * contents of the memory.
41462306a36Sopenharmony_ci		 */
41562306a36Sopenharmony_ci		ret = spi_nor_write_disable(nor);
41662306a36Sopenharmony_ci		if (ret)
41762306a36Sopenharmony_ci			return ret;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		return -EIO;
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	return sr_ready && !!(nor->bouncebuf[0] & FSR_READY);
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic void micron_st_nor_default_init(struct spi_nor *nor)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	nor->flags |= SNOR_F_HAS_LOCK;
42862306a36Sopenharmony_ci	nor->flags &= ~SNOR_F_HAS_16BIT_SR;
42962306a36Sopenharmony_ci	nor->params->quad_enable = NULL;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_cistatic int micron_st_nor_late_init(struct spi_nor *nor)
43362306a36Sopenharmony_ci{
43462306a36Sopenharmony_ci	struct spi_nor_flash_parameter *params = nor->params;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	if (nor->info->mfr_flags & USE_FSR)
43762306a36Sopenharmony_ci		params->ready = micron_st_nor_ready;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	if (!params->set_4byte_addr_mode)
44062306a36Sopenharmony_ci		params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode_wren_en4b_ex4b;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct spi_nor_fixups micron_st_nor_fixups = {
44662306a36Sopenharmony_ci	.default_init = micron_st_nor_default_init,
44762306a36Sopenharmony_ci	.late_init = micron_st_nor_late_init,
44862306a36Sopenharmony_ci};
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ciconst struct spi_nor_manufacturer spi_nor_micron = {
45162306a36Sopenharmony_ci	.name = "micron",
45262306a36Sopenharmony_ci	.parts = micron_nor_parts,
45362306a36Sopenharmony_ci	.nparts = ARRAY_SIZE(micron_nor_parts),
45462306a36Sopenharmony_ci	.fixups = &micron_st_nor_fixups,
45562306a36Sopenharmony_ci};
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciconst struct spi_nor_manufacturer spi_nor_st = {
45862306a36Sopenharmony_ci	.name = "st",
45962306a36Sopenharmony_ci	.parts = st_nor_parts,
46062306a36Sopenharmony_ci	.nparts = ARRAY_SIZE(st_nor_parts),
46162306a36Sopenharmony_ci	.fixups = &micron_st_nor_fixups,
46262306a36Sopenharmony_ci};
463