xref: /openbmc/linux/drivers/mtd/spi-nor/spansion.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
10173c32aSBoris Brezillon // SPDX-License-Identifier: GPL-2.0
20173c32aSBoris Brezillon /*
30173c32aSBoris Brezillon  * Copyright (C) 2005, Intec Automation Inc.
40173c32aSBoris Brezillon  * Copyright (C) 2014, Freescale Semiconductor, Inc.
50173c32aSBoris Brezillon  */
60173c32aSBoris Brezillon 
71e611e10STakahiro Kuwano #include <linux/bitfield.h>
8d534fd97STakahiro Kuwano #include <linux/device.h>
9362f786eSTakahiro Kuwano #include <linux/errno.h>
100173c32aSBoris Brezillon #include <linux/mtd/spi-nor.h>
110173c32aSBoris Brezillon 
120173c32aSBoris Brezillon #include "core.h"
130173c32aSBoris Brezillon 
1451c55506SMichael Walle /* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */
1551c55506SMichael Walle #define USE_CLSR	BIT(0)
16d534fd97STakahiro Kuwano #define USE_CLPEF	BIT(1)
1751c55506SMichael Walle 
18837d5181SMichael Walle #define SPINOR_OP_CLSR		0x30	/* Clear status register 1 */
19d534fd97STakahiro Kuwano #define SPINOR_OP_CLPEF		0x82	/* Clear program/erase failure flags */
20c3266af1SPratyush Yadav #define SPINOR_OP_RD_ANY_REG			0x65	/* Read any register */
21c3266af1SPratyush Yadav #define SPINOR_OP_WR_ANY_REG			0x71	/* Write any register */
226c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_VREG			0x00800000
236c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_STR1			0x0
246c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_STR1V					\
256c01ae11STakahiro Kuwano 	(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1)
266c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR1			0x2
27ca5a16dbSTudor Ambarus #define SPINOR_REG_CYPRESS_CFR1_QUAD_EN		BIT(1)	/* Quad Enable */
286c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR2			0x3
296c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR2V					\
306c01ae11STakahiro Kuwano 	(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
311e611e10STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK	GENMASK(3, 0)
32ca5a16dbSTudor Ambarus #define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24	0xb
33c87c9b11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR2_ADRBYT		BIT(7)
346c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR3			0x4
35ca5a16dbSTudor Ambarus #define SPINOR_REG_CYPRESS_CFR3_PGSZ		BIT(4) /* Page size. */
366c01ae11STakahiro Kuwano #define SPINOR_REG_CYPRESS_CFR5			0x6
373f592a86STudor Ambarus #define SPINOR_REG_CYPRESS_CFR5_BIT6		BIT(6)
383f592a86STudor Ambarus #define SPINOR_REG_CYPRESS_CFR5_DDR		BIT(1)
393f592a86STudor Ambarus #define SPINOR_REG_CYPRESS_CFR5_OPI		BIT(0)
40ca5a16dbSTudor Ambarus #define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN				\
413f592a86STudor Ambarus 	(SPINOR_REG_CYPRESS_CFR5_BIT6 |	SPINOR_REG_CYPRESS_CFR5_DDR |	\
423f592a86STudor Ambarus 	 SPINOR_REG_CYPRESS_CFR5_OPI)
43ca5a16dbSTudor Ambarus #define SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS	SPINOR_REG_CYPRESS_CFR5_BIT6
44c3266af1SPratyush Yadav #define SPINOR_OP_CYPRESS_RD_FAST		0xee
456afcc840STakahiro Kuwano #define SPINOR_REG_CYPRESS_ARCFN		0x00000006
46c3266af1SPratyush Yadav 
4727ff0d34STudor Ambarus /* Cypress SPI NOR flash operations. */
4827ff0d34STudor Ambarus #define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf)		\
4927ff0d34STudor Ambarus 	SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 0),		\
5027ff0d34STudor Ambarus 		   SPI_MEM_OP_ADDR(naddr, addr, 0),			\
5127ff0d34STudor Ambarus 		   SPI_MEM_OP_NO_DUMMY,					\
5227ff0d34STudor Ambarus 		   SPI_MEM_OP_DATA_OUT(ndata, buf, 0))
5327ff0d34STudor Ambarus 
54d628783cSTakahiro Kuwano #define CYPRESS_NOR_RD_ANY_REG_OP(naddr, addr, ndummy, buf)		\
55c0abb861STudor Ambarus 	SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 0),		\
56c0abb861STudor Ambarus 		   SPI_MEM_OP_ADDR(naddr, addr, 0),			\
57d628783cSTakahiro Kuwano 		   SPI_MEM_OP_DUMMY(ndummy, 0),				\
58c0abb861STudor Ambarus 		   SPI_MEM_OP_DATA_IN(1, buf, 0))
59c0abb861STudor Ambarus 
60d534fd97STakahiro Kuwano #define SPANSION_OP(opcode)						\
61d534fd97STakahiro Kuwano 	SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0),				\
62c0abb861STudor Ambarus 		   SPI_MEM_OP_NO_ADDR,					\
63c0abb861STudor Ambarus 		   SPI_MEM_OP_NO_DUMMY,					\
64c0abb861STudor Ambarus 		   SPI_MEM_OP_NO_DATA)
65c0abb861STudor Ambarus 
6691f3c430STakahiro Kuwano /**
67d534fd97STakahiro Kuwano  * struct spansion_nor_params - Spansion private parameters.
68d534fd97STakahiro Kuwano  * @clsr:	Clear Status Register or Clear Program and Erase Failure Flag
69d534fd97STakahiro Kuwano  *		opcode.
70d534fd97STakahiro Kuwano  */
71d534fd97STakahiro Kuwano struct spansion_nor_params {
72d534fd97STakahiro Kuwano 	u8 clsr;
73d534fd97STakahiro Kuwano };
74d534fd97STakahiro Kuwano 
75d534fd97STakahiro Kuwano /**
7691f3c430STakahiro Kuwano  * spansion_nor_clear_sr() - Clear the Status Register.
7791f3c430STakahiro Kuwano  * @nor:	pointer to 'struct spi_nor'.
7891f3c430STakahiro Kuwano  */
spansion_nor_clear_sr(struct spi_nor * nor)7991f3c430STakahiro Kuwano static void spansion_nor_clear_sr(struct spi_nor *nor)
8091f3c430STakahiro Kuwano {
81d534fd97STakahiro Kuwano 	const struct spansion_nor_params *priv_params = nor->params->priv;
8291f3c430STakahiro Kuwano 	int ret;
8391f3c430STakahiro Kuwano 
8491f3c430STakahiro Kuwano 	if (nor->spimem) {
85d534fd97STakahiro Kuwano 		struct spi_mem_op op = SPANSION_OP(priv_params->clsr);
8691f3c430STakahiro Kuwano 
8791f3c430STakahiro Kuwano 		spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
8891f3c430STakahiro Kuwano 
8991f3c430STakahiro Kuwano 		ret = spi_mem_exec_op(nor->spimem, &op);
9091f3c430STakahiro Kuwano 	} else {
9191f3c430STakahiro Kuwano 		ret = spi_nor_controller_ops_write_reg(nor, SPINOR_OP_CLSR,
9291f3c430STakahiro Kuwano 						       NULL, 0);
9391f3c430STakahiro Kuwano 	}
9491f3c430STakahiro Kuwano 
9591f3c430STakahiro Kuwano 	if (ret)
9691f3c430STakahiro Kuwano 		dev_dbg(nor->dev, "error %d clearing SR\n", ret);
9791f3c430STakahiro Kuwano }
9891f3c430STakahiro Kuwano 
cypress_nor_sr_ready_and_clear_reg(struct spi_nor * nor,u64 addr)9991f3c430STakahiro Kuwano static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
10091f3c430STakahiro Kuwano {
101eff96043STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
10291f3c430STakahiro Kuwano 	struct spi_mem_op op =
103eff96043STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(params->addr_mode_nbytes, addr,
10491f3c430STakahiro Kuwano 					  0, nor->bouncebuf);
10591f3c430STakahiro Kuwano 	int ret;
10691f3c430STakahiro Kuwano 
107eff96043STakahiro Kuwano 	if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
108*8a064359STakahiro Kuwano 		op.addr.nbytes = nor->addr_nbytes;
109eff96043STakahiro Kuwano 		op.dummy.nbytes = params->rdsr_dummy;
110eff96043STakahiro Kuwano 		op.data.nbytes = 2;
111eff96043STakahiro Kuwano 	}
112eff96043STakahiro Kuwano 
11391f3c430STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
11491f3c430STakahiro Kuwano 	if (ret)
11591f3c430STakahiro Kuwano 		return ret;
11691f3c430STakahiro Kuwano 
11791f3c430STakahiro Kuwano 	if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
11891f3c430STakahiro Kuwano 		if (nor->bouncebuf[0] & SR_E_ERR)
11991f3c430STakahiro Kuwano 			dev_err(nor->dev, "Erase Error occurred\n");
12091f3c430STakahiro Kuwano 		else
12191f3c430STakahiro Kuwano 			dev_err(nor->dev, "Programming Error occurred\n");
12291f3c430STakahiro Kuwano 
12391f3c430STakahiro Kuwano 		spansion_nor_clear_sr(nor);
12491f3c430STakahiro Kuwano 
12591f3c430STakahiro Kuwano 		ret = spi_nor_write_disable(nor);
12691f3c430STakahiro Kuwano 		if (ret)
12791f3c430STakahiro Kuwano 			return ret;
12891f3c430STakahiro Kuwano 
12991f3c430STakahiro Kuwano 		return -EIO;
13091f3c430STakahiro Kuwano 	}
13191f3c430STakahiro Kuwano 
13291f3c430STakahiro Kuwano 	return !(nor->bouncebuf[0] & SR_WIP);
13391f3c430STakahiro Kuwano }
13491f3c430STakahiro Kuwano /**
13591f3c430STakahiro Kuwano  * cypress_nor_sr_ready_and_clear() - Query the Status Register of each die by
13691f3c430STakahiro Kuwano  * using Read Any Register command to see if the whole flash is ready for new
13791f3c430STakahiro Kuwano  * commands and clear it if there are any errors.
13891f3c430STakahiro Kuwano  * @nor:	pointer to 'struct spi_nor'.
13991f3c430STakahiro Kuwano  *
14091f3c430STakahiro Kuwano  * Return: 1 if ready, 0 if not ready, -errno on errors.
14191f3c430STakahiro Kuwano  */
cypress_nor_sr_ready_and_clear(struct spi_nor * nor)14291f3c430STakahiro Kuwano static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
14391f3c430STakahiro Kuwano {
14491f3c430STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
14591f3c430STakahiro Kuwano 	u64 addr;
14691f3c430STakahiro Kuwano 	int ret;
14791f3c430STakahiro Kuwano 	u8 i;
14891f3c430STakahiro Kuwano 
14991f3c430STakahiro Kuwano 	for (i = 0; i < params->n_dice; i++) {
15091f3c430STakahiro Kuwano 		addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_STR1;
15191f3c430STakahiro Kuwano 		ret = cypress_nor_sr_ready_and_clear_reg(nor, addr);
15291f3c430STakahiro Kuwano 		if (ret < 0)
15391f3c430STakahiro Kuwano 			return ret;
15491f3c430STakahiro Kuwano 		else if (ret == 0)
15591f3c430STakahiro Kuwano 			return 0;
15691f3c430STakahiro Kuwano 	}
15791f3c430STakahiro Kuwano 
15891f3c430STakahiro Kuwano 	return 1;
15991f3c430STakahiro Kuwano }
16091f3c430STakahiro Kuwano 
cypress_nor_set_memlat(struct spi_nor * nor,u64 addr)161c0aa0512STakahiro Kuwano static int cypress_nor_set_memlat(struct spi_nor *nor, u64 addr)
16227ff0d34STudor Ambarus {
16327ff0d34STudor Ambarus 	struct spi_mem_op op;
16427ff0d34STudor Ambarus 	u8 *buf = nor->bouncebuf;
16527ff0d34STudor Ambarus 	int ret;
16605ebc1ccSTudor Ambarus 	u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
16727ff0d34STudor Ambarus 
16827ff0d34STudor Ambarus 	op = (struct spi_mem_op)
169c0aa0512STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf);
1701e611e10STakahiro Kuwano 
1711e611e10STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
1721e611e10STakahiro Kuwano 	if (ret)
1731e611e10STakahiro Kuwano 		return ret;
1741e611e10STakahiro Kuwano 
17527ff0d34STudor Ambarus 	/* Use 24 dummy cycles for memory array reads. */
1761e611e10STakahiro Kuwano 	*buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK;
1771e611e10STakahiro Kuwano 	*buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK,
1781e611e10STakahiro Kuwano 			   SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24);
17927ff0d34STudor Ambarus 	op = (struct spi_mem_op)
180c0aa0512STakahiro Kuwano 		CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf);
18127ff0d34STudor Ambarus 
18227ff0d34STudor Ambarus 	ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
18327ff0d34STudor Ambarus 	if (ret)
18427ff0d34STudor Ambarus 		return ret;
18527ff0d34STudor Ambarus 
18627ff0d34STudor Ambarus 	nor->read_dummy = 24;
18727ff0d34STudor Ambarus 
188c0aa0512STakahiro Kuwano 	return 0;
189c0aa0512STakahiro Kuwano }
190c0aa0512STakahiro Kuwano 
cypress_nor_set_octal_dtr_bits(struct spi_nor * nor,u64 addr)191c0aa0512STakahiro Kuwano static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr)
192c0aa0512STakahiro Kuwano {
193c0aa0512STakahiro Kuwano 	struct spi_mem_op op;
194c0aa0512STakahiro Kuwano 	u8 *buf = nor->bouncebuf;
195c0aa0512STakahiro Kuwano 
19627ff0d34STudor Ambarus 	/* Set the octal and DTR enable bits. */
197ca5a16dbSTudor Ambarus 	buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
19827ff0d34STudor Ambarus 	op = (struct spi_mem_op)
199c0aa0512STakahiro Kuwano 		CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes,
200c0aa0512STakahiro Kuwano 					  addr, 1, buf);
20127ff0d34STudor Ambarus 
202c0aa0512STakahiro Kuwano 	return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
203c0aa0512STakahiro Kuwano }
204c0aa0512STakahiro Kuwano 
cypress_nor_octal_dtr_en(struct spi_nor * nor)205c0aa0512STakahiro Kuwano static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
206c0aa0512STakahiro Kuwano {
207362f786eSTakahiro Kuwano 	const struct spi_nor_flash_parameter *params = nor->params;
208c0aa0512STakahiro Kuwano 	u8 *buf = nor->bouncebuf;
209362f786eSTakahiro Kuwano 	u64 addr;
2107d896a94STakahiro Kuwano 	int i, ret;
211c0aa0512STakahiro Kuwano 
2127d896a94STakahiro Kuwano 	for (i = 0; i < params->n_dice; i++) {
2137d896a94STakahiro Kuwano 		addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2;
214362f786eSTakahiro Kuwano 		ret = cypress_nor_set_memlat(nor, addr);
21527ff0d34STudor Ambarus 		if (ret)
21627ff0d34STudor Ambarus 			return ret;
21727ff0d34STudor Ambarus 
2187d896a94STakahiro Kuwano 		addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
219362f786eSTakahiro Kuwano 		ret = cypress_nor_set_octal_dtr_bits(nor, addr);
22027ff0d34STudor Ambarus 		if (ret)
22127ff0d34STudor Ambarus 			return ret;
2227d896a94STakahiro Kuwano 	}
22327ff0d34STudor Ambarus 
22427ff0d34STudor Ambarus 	/* Read flash ID to make sure the switch was successful. */
22505ebc1ccSTudor Ambarus 	ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf,
22605ebc1ccSTudor Ambarus 			      SNOR_PROTO_8_8_8_DTR);
22727ff0d34STudor Ambarus 	if (ret) {
22827ff0d34STudor Ambarus 		dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret);
22927ff0d34STudor Ambarus 		return ret;
23027ff0d34STudor Ambarus 	}
23127ff0d34STudor Ambarus 
23227ff0d34STudor Ambarus 	if (memcmp(buf, nor->info->id, nor->info->id_len))
23327ff0d34STudor Ambarus 		return -EINVAL;
23427ff0d34STudor Ambarus 
23527ff0d34STudor Ambarus 	return 0;
23627ff0d34STudor Ambarus }
23727ff0d34STudor Ambarus 
cypress_nor_set_single_spi_bits(struct spi_nor * nor,u64 addr)238c0aa0512STakahiro Kuwano static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr)
23927ff0d34STudor Ambarus {
24027ff0d34STudor Ambarus 	struct spi_mem_op op;
24127ff0d34STudor Ambarus 	u8 *buf = nor->bouncebuf;
24227ff0d34STudor Ambarus 
24327ff0d34STudor Ambarus 	/*
24427ff0d34STudor Ambarus 	 * The register is 1-byte wide, but 1-byte transactions are not allowed
24527ff0d34STudor Ambarus 	 * in 8D-8D-8D mode. Since there is no register at the next location,
24627ff0d34STudor Ambarus 	 * just initialize the value to 0 and let the transaction go on.
24727ff0d34STudor Ambarus 	 */
248ca5a16dbSTudor Ambarus 	buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
24927ff0d34STudor Ambarus 	buf[1] = 0;
25027ff0d34STudor Ambarus 	op = (struct spi_mem_op)
251c0aa0512STakahiro Kuwano 		CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf);
252c0aa0512STakahiro Kuwano 	return spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
253c0aa0512STakahiro Kuwano }
254c0aa0512STakahiro Kuwano 
cypress_nor_octal_dtr_dis(struct spi_nor * nor)255c0aa0512STakahiro Kuwano static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
256c0aa0512STakahiro Kuwano {
2577d896a94STakahiro Kuwano 	const struct spi_nor_flash_parameter *params = nor->params;
258c0aa0512STakahiro Kuwano 	u8 *buf = nor->bouncebuf;
259362f786eSTakahiro Kuwano 	u64 addr;
2607d896a94STakahiro Kuwano 	int i, ret;
261c0aa0512STakahiro Kuwano 
2627d896a94STakahiro Kuwano 	for (i = 0; i < params->n_dice; i++) {
2637d896a94STakahiro Kuwano 		addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
264362f786eSTakahiro Kuwano 		ret = cypress_nor_set_single_spi_bits(nor, addr);
26527ff0d34STudor Ambarus 		if (ret)
26627ff0d34STudor Ambarus 			return ret;
2677d896a94STakahiro Kuwano 	}
26827ff0d34STudor Ambarus 
26927ff0d34STudor Ambarus 	/* Read flash ID to make sure the switch was successful. */
27027ff0d34STudor Ambarus 	ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
27127ff0d34STudor Ambarus 	if (ret) {
27227ff0d34STudor Ambarus 		dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret);
27327ff0d34STudor Ambarus 		return ret;
27427ff0d34STudor Ambarus 	}
27527ff0d34STudor Ambarus 
27627ff0d34STudor Ambarus 	if (memcmp(buf, nor->info->id, nor->info->id_len))
27727ff0d34STudor Ambarus 		return -EINVAL;
27827ff0d34STudor Ambarus 
27927ff0d34STudor Ambarus 	return 0;
28027ff0d34STudor Ambarus }
28127ff0d34STudor Ambarus 
cypress_nor_quad_enable_volatile_reg(struct spi_nor * nor,u64 addr)282f24d423aSTakahiro Kuwano static int cypress_nor_quad_enable_volatile_reg(struct spi_nor *nor, u64 addr)
283f24d423aSTakahiro Kuwano {
284f24d423aSTakahiro Kuwano 	struct spi_mem_op op;
285f24d423aSTakahiro Kuwano 	u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
286f24d423aSTakahiro Kuwano 	u8 cfr1v_written;
287f24d423aSTakahiro Kuwano 	int ret;
288f24d423aSTakahiro Kuwano 
289f24d423aSTakahiro Kuwano 	op = (struct spi_mem_op)
290f24d423aSTakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
291f24d423aSTakahiro Kuwano 					  nor->bouncebuf);
292f24d423aSTakahiro Kuwano 
293f24d423aSTakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
294f24d423aSTakahiro Kuwano 	if (ret)
295f24d423aSTakahiro Kuwano 		return ret;
296f24d423aSTakahiro Kuwano 
297f24d423aSTakahiro Kuwano 	if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1_QUAD_EN)
298f24d423aSTakahiro Kuwano 		return 0;
299f24d423aSTakahiro Kuwano 
300f24d423aSTakahiro Kuwano 	/* Update the Quad Enable bit. */
301f24d423aSTakahiro Kuwano 	nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1_QUAD_EN;
302f24d423aSTakahiro Kuwano 	op = (struct spi_mem_op)
303f24d423aSTakahiro Kuwano 		CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1,
304f24d423aSTakahiro Kuwano 					  nor->bouncebuf);
305f24d423aSTakahiro Kuwano 	ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
306f24d423aSTakahiro Kuwano 	if (ret)
307f24d423aSTakahiro Kuwano 		return ret;
308f24d423aSTakahiro Kuwano 
309f24d423aSTakahiro Kuwano 	cfr1v_written = nor->bouncebuf[0];
310f24d423aSTakahiro Kuwano 
311f24d423aSTakahiro Kuwano 	/* Read back and check it. */
312f24d423aSTakahiro Kuwano 	op = (struct spi_mem_op)
313f24d423aSTakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0,
314f24d423aSTakahiro Kuwano 					  nor->bouncebuf);
315f24d423aSTakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
316f24d423aSTakahiro Kuwano 	if (ret)
317f24d423aSTakahiro Kuwano 		return ret;
318f24d423aSTakahiro Kuwano 
319f24d423aSTakahiro Kuwano 	if (nor->bouncebuf[0] != cfr1v_written) {
320f24d423aSTakahiro Kuwano 		dev_err(nor->dev, "CFR1: Read back test failed\n");
321f24d423aSTakahiro Kuwano 		return -EIO;
322f24d423aSTakahiro Kuwano 	}
323f24d423aSTakahiro Kuwano 
324f24d423aSTakahiro Kuwano 	return 0;
325f24d423aSTakahiro Kuwano }
326f24d423aSTakahiro Kuwano 
327c3266af1SPratyush Yadav /**
328b6b23833STakahiro Kuwano  * cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile
329b6b23833STakahiro Kuwano  *                                      register.
330b6b23833STakahiro Kuwano  * @nor:	pointer to a 'struct spi_nor'
331b6b23833STakahiro Kuwano  *
332b6b23833STakahiro Kuwano  * It is recommended to update volatile registers in the field application due
333b6b23833STakahiro Kuwano  * to a risk of the non-volatile registers corruption by power interrupt. This
334b6b23833STakahiro Kuwano  * function sets Quad Enable bit in CFR1 volatile. If users set the Quad Enable
335b6b23833STakahiro Kuwano  * bit in the CFR1 non-volatile in advance (typically by a Flash programmer
336b6b23833STakahiro Kuwano  * before mounting Flash on PCB), the Quad Enable bit in the CFR1 volatile is
337b6b23833STakahiro Kuwano  * also set during Flash power-up.
338b6b23833STakahiro Kuwano  *
339b6b23833STakahiro Kuwano  * Return: 0 on success, -errno otherwise.
340b6b23833STakahiro Kuwano  */
cypress_nor_quad_enable_volatile(struct spi_nor * nor)341b6b23833STakahiro Kuwano static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
342b6b23833STakahiro Kuwano {
343f24d423aSTakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
344f24d423aSTakahiro Kuwano 	u64 addr;
345f24d423aSTakahiro Kuwano 	u8 i;
346b6b23833STakahiro Kuwano 	int ret;
347b6b23833STakahiro Kuwano 
348f24d423aSTakahiro Kuwano 	for (i = 0; i < params->n_dice; i++) {
349f24d423aSTakahiro Kuwano 		addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
350f24d423aSTakahiro Kuwano 		ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
351b6b23833STakahiro Kuwano 		if (ret)
352b6b23833STakahiro Kuwano 			return ret;
353b6b23833STakahiro Kuwano 	}
354b6b23833STakahiro Kuwano 
355b6b23833STakahiro Kuwano 	return 0;
356b6b23833STakahiro Kuwano }
357b6b23833STakahiro Kuwano 
358b6b23833STakahiro Kuwano /**
359c87c9b11STakahiro Kuwano  * cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
360c87c9b11STakahiro Kuwano  *                                            (3 or 4-byte) by querying status
361c87c9b11STakahiro Kuwano  *                                            register 1 (SR1).
362c87c9b11STakahiro Kuwano  * @nor:		pointer to a 'struct spi_nor'
363c87c9b11STakahiro Kuwano  * @addr_mode:		ponter to a buffer where we return the determined
364c87c9b11STakahiro Kuwano  *			address mode.
365c87c9b11STakahiro Kuwano  *
366c87c9b11STakahiro Kuwano  * This function tries to determine current address mode by comparing SR1 value
367c87c9b11STakahiro Kuwano  * from RDSR1(no address), RDAR(3-byte address), and RDAR(4-byte address).
368c87c9b11STakahiro Kuwano  *
369c87c9b11STakahiro Kuwano  * Return: 0 on success, -errno otherwise.
370c87c9b11STakahiro Kuwano  */
cypress_nor_determine_addr_mode_by_sr1(struct spi_nor * nor,u8 * addr_mode)371c87c9b11STakahiro Kuwano static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor,
372c87c9b11STakahiro Kuwano 						  u8 *addr_mode)
373c87c9b11STakahiro Kuwano {
374c87c9b11STakahiro Kuwano 	struct spi_mem_op op =
375c87c9b11STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(3, SPINOR_REG_CYPRESS_STR1V, 0,
376c87c9b11STakahiro Kuwano 					  nor->bouncebuf);
377c87c9b11STakahiro Kuwano 	bool is3byte, is4byte;
378c87c9b11STakahiro Kuwano 	int ret;
379c87c9b11STakahiro Kuwano 
380c87c9b11STakahiro Kuwano 	ret = spi_nor_read_sr(nor, &nor->bouncebuf[1]);
381c87c9b11STakahiro Kuwano 	if (ret)
382c87c9b11STakahiro Kuwano 		return ret;
383c87c9b11STakahiro Kuwano 
384c87c9b11STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
385c87c9b11STakahiro Kuwano 	if (ret)
386c87c9b11STakahiro Kuwano 		return ret;
387c87c9b11STakahiro Kuwano 
388c87c9b11STakahiro Kuwano 	is3byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
389c87c9b11STakahiro Kuwano 
390c87c9b11STakahiro Kuwano 	op = (struct spi_mem_op)
391c87c9b11STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(4, SPINOR_REG_CYPRESS_STR1V, 0,
392c87c9b11STakahiro Kuwano 					  nor->bouncebuf);
393c87c9b11STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
394c87c9b11STakahiro Kuwano 	if (ret)
395c87c9b11STakahiro Kuwano 		return ret;
396c87c9b11STakahiro Kuwano 
397c87c9b11STakahiro Kuwano 	is4byte = (nor->bouncebuf[0] == nor->bouncebuf[1]);
398c87c9b11STakahiro Kuwano 
399c87c9b11STakahiro Kuwano 	if (is3byte == is4byte)
400c87c9b11STakahiro Kuwano 		return -EIO;
401c87c9b11STakahiro Kuwano 	if (is3byte)
402c87c9b11STakahiro Kuwano 		*addr_mode = 3;
403c87c9b11STakahiro Kuwano 	else
404c87c9b11STakahiro Kuwano 		*addr_mode = 4;
405c87c9b11STakahiro Kuwano 
406c87c9b11STakahiro Kuwano 	return 0;
407c87c9b11STakahiro Kuwano }
408c87c9b11STakahiro Kuwano 
409c87c9b11STakahiro Kuwano /**
410c87c9b11STakahiro Kuwano  * cypress_nor_set_addr_mode_nbytes() - Set the number of address bytes mode of
411c87c9b11STakahiro Kuwano  *                                      current address mode.
412c87c9b11STakahiro Kuwano  * @nor:		pointer to a 'struct spi_nor'
413c87c9b11STakahiro Kuwano  *
414c87c9b11STakahiro Kuwano  * Determine current address mode by reading SR1 with different methods, then
415c87c9b11STakahiro Kuwano  * query CFR2V[7] to confirm. If determination is failed, force enter to 4-byte
416c87c9b11STakahiro Kuwano  * address mode.
417c87c9b11STakahiro Kuwano  *
418c87c9b11STakahiro Kuwano  * Return: 0 on success, -errno otherwise.
419c87c9b11STakahiro Kuwano  */
cypress_nor_set_addr_mode_nbytes(struct spi_nor * nor)420c87c9b11STakahiro Kuwano static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
421c87c9b11STakahiro Kuwano {
42271c8f9cfSArnd Bergmann 	struct spi_mem_op op;
423c87c9b11STakahiro Kuwano 	u8 addr_mode;
424c87c9b11STakahiro Kuwano 	int ret;
425c87c9b11STakahiro Kuwano 
426c87c9b11STakahiro Kuwano 	/*
427c87c9b11STakahiro Kuwano 	 * Read SR1 by RDSR1 and RDAR(3- AND 4-byte addr). Use write enable
428c87c9b11STakahiro Kuwano 	 * that sets bit-1 in SR1.
429c87c9b11STakahiro Kuwano 	 */
430c87c9b11STakahiro Kuwano 	ret = spi_nor_write_enable(nor);
431c87c9b11STakahiro Kuwano 	if (ret)
432c87c9b11STakahiro Kuwano 		return ret;
433c87c9b11STakahiro Kuwano 	ret = cypress_nor_determine_addr_mode_by_sr1(nor, &addr_mode);
434c87c9b11STakahiro Kuwano 	if (ret) {
435c87c9b11STakahiro Kuwano 		ret = spi_nor_set_4byte_addr_mode(nor, true);
436c87c9b11STakahiro Kuwano 		if (ret)
437c87c9b11STakahiro Kuwano 			return ret;
438c87c9b11STakahiro Kuwano 		return spi_nor_write_disable(nor);
439c87c9b11STakahiro Kuwano 	}
440c87c9b11STakahiro Kuwano 	ret = spi_nor_write_disable(nor);
441c87c9b11STakahiro Kuwano 	if (ret)
442c87c9b11STakahiro Kuwano 		return ret;
443c87c9b11STakahiro Kuwano 
444c87c9b11STakahiro Kuwano 	/*
445c87c9b11STakahiro Kuwano 	 * Query CFR2V and make sure no contradiction between determined address
446c87c9b11STakahiro Kuwano 	 * mode and CFR2V[7].
447c87c9b11STakahiro Kuwano 	 */
448c87c9b11STakahiro Kuwano 	op = (struct spi_mem_op)
449c87c9b11STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(addr_mode, SPINOR_REG_CYPRESS_CFR2V,
450c87c9b11STakahiro Kuwano 					  0, nor->bouncebuf);
451c87c9b11STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
452c87c9b11STakahiro Kuwano 	if (ret)
453c87c9b11STakahiro Kuwano 		return ret;
454c87c9b11STakahiro Kuwano 
455c87c9b11STakahiro Kuwano 	if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR2_ADRBYT) {
456c87c9b11STakahiro Kuwano 		if (addr_mode != 4)
457c87c9b11STakahiro Kuwano 			return spi_nor_set_4byte_addr_mode(nor, true);
458c87c9b11STakahiro Kuwano 	} else {
459c87c9b11STakahiro Kuwano 		if (addr_mode != 3)
460c87c9b11STakahiro Kuwano 			return spi_nor_set_4byte_addr_mode(nor, true);
461c87c9b11STakahiro Kuwano 	}
462c87c9b11STakahiro Kuwano 
463c87c9b11STakahiro Kuwano 	nor->params->addr_nbytes = addr_mode;
464c87c9b11STakahiro Kuwano 	nor->params->addr_mode_nbytes = addr_mode;
465c87c9b11STakahiro Kuwano 
466c87c9b11STakahiro Kuwano 	return 0;
467c87c9b11STakahiro Kuwano }
468c87c9b11STakahiro Kuwano 
469aa517a29STudor Ambarus /**
470aa517a29STudor Ambarus  * cypress_nor_get_page_size() - Get flash page size configuration.
471aa517a29STudor Ambarus  * @nor:	pointer to a 'struct spi_nor'
472aa517a29STudor Ambarus  *
473aa517a29STudor Ambarus  * The BFPT table advertises a 512B or 256B page size depending on part but the
474aa517a29STudor Ambarus  * page size is actually configurable (with the default being 256B). Read from
475aa517a29STudor Ambarus  * CFR3V[4] and set the correct size.
476aa517a29STudor Ambarus  *
477aa517a29STudor Ambarus  * Return: 0 on success, -errno otherwise.
478aa517a29STudor Ambarus  */
cypress_nor_get_page_size(struct spi_nor * nor)479aa517a29STudor Ambarus static int cypress_nor_get_page_size(struct spi_nor *nor)
4806c01ae11STakahiro Kuwano {
4816c01ae11STakahiro Kuwano 	struct spi_mem_op op =
4826c01ae11STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
4836c01ae11STakahiro Kuwano 					  0, 0, nor->bouncebuf);
4846c01ae11STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
4856c01ae11STakahiro Kuwano 	int ret;
4866c01ae11STakahiro Kuwano 	u8 i;
4876c01ae11STakahiro Kuwano 
4886c01ae11STakahiro Kuwano 	/*
4896c01ae11STakahiro Kuwano 	 * Use the minimum common page size configuration. Programming 256-byte
4906c01ae11STakahiro Kuwano 	 * under 512-byte page size configuration is safe.
4916c01ae11STakahiro Kuwano 	 */
4926c01ae11STakahiro Kuwano 	params->page_size = 256;
4936c01ae11STakahiro Kuwano 	for (i = 0; i < params->n_dice; i++) {
4946c01ae11STakahiro Kuwano 		op.addr.val = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR3;
4956c01ae11STakahiro Kuwano 
4966c01ae11STakahiro Kuwano 		ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
4976c01ae11STakahiro Kuwano 		if (ret)
4986c01ae11STakahiro Kuwano 			return ret;
4996c01ae11STakahiro Kuwano 
5006c01ae11STakahiro Kuwano 		if (!(nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ))
5016c01ae11STakahiro Kuwano 			return 0;
5026c01ae11STakahiro Kuwano 	}
5036c01ae11STakahiro Kuwano 
5046c01ae11STakahiro Kuwano 	params->page_size = 512;
5056c01ae11STakahiro Kuwano 
5066c01ae11STakahiro Kuwano 	return 0;
5076c01ae11STakahiro Kuwano }
5086c01ae11STakahiro Kuwano 
cypress_nor_ecc_init(struct spi_nor * nor)5099fd0945fSTakahiro Kuwano static void cypress_nor_ecc_init(struct spi_nor *nor)
5109fd0945fSTakahiro Kuwano {
5119fd0945fSTakahiro Kuwano 	/*
5129fd0945fSTakahiro Kuwano 	 * Programming is supported only in 16-byte ECC data unit granularity.
5139fd0945fSTakahiro Kuwano 	 * Byte-programming, bit-walking, or multiple program operations to the
5149fd0945fSTakahiro Kuwano 	 * same ECC data unit without an erase are not allowed.
5159fd0945fSTakahiro Kuwano 	 */
5169fd0945fSTakahiro Kuwano 	nor->params->writesize = 16;
5179fd0945fSTakahiro Kuwano 	nor->flags |= SNOR_F_ECC;
5189fd0945fSTakahiro Kuwano }
5199fd0945fSTakahiro Kuwano 
520b6b23833STakahiro Kuwano static int
s25fs256t_post_bfpt_fixup(struct spi_nor * nor,const struct sfdp_parameter_header * bfpt_header,const struct sfdp_bfpt * bfpt)5216afcc840STakahiro Kuwano s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
5226afcc840STakahiro Kuwano 			  const struct sfdp_parameter_header *bfpt_header,
5236afcc840STakahiro Kuwano 			  const struct sfdp_bfpt *bfpt)
5246afcc840STakahiro Kuwano {
52571c8f9cfSArnd Bergmann 	struct spi_mem_op op;
5266afcc840STakahiro Kuwano 	int ret;
5276afcc840STakahiro Kuwano 
528c87c9b11STakahiro Kuwano 	ret = cypress_nor_set_addr_mode_nbytes(nor);
529c87c9b11STakahiro Kuwano 	if (ret)
530c87c9b11STakahiro Kuwano 		return ret;
5316afcc840STakahiro Kuwano 
5326afcc840STakahiro Kuwano 	/* Read Architecture Configuration Register (ARCFN) */
5336afcc840STakahiro Kuwano 	op = (struct spi_mem_op)
5346afcc840STakahiro Kuwano 		CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
5356afcc840STakahiro Kuwano 					  SPINOR_REG_CYPRESS_ARCFN, 1,
5366afcc840STakahiro Kuwano 					  nor->bouncebuf);
5376afcc840STakahiro Kuwano 	ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
5386afcc840STakahiro Kuwano 	if (ret)
5396afcc840STakahiro Kuwano 		return ret;
5406afcc840STakahiro Kuwano 
5416afcc840STakahiro Kuwano 	/* ARCFN value must be 0 if uniform sector is selected  */
5426afcc840STakahiro Kuwano 	if (nor->bouncebuf[0])
5436afcc840STakahiro Kuwano 		return -ENODEV;
5446afcc840STakahiro Kuwano 
545aa517a29STudor Ambarus 	return 0;
5466afcc840STakahiro Kuwano }
5476afcc840STakahiro Kuwano 
s25fs256t_post_sfdp_fixup(struct spi_nor * nor)548e570f787STudor Ambarus static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
5496afcc840STakahiro Kuwano {
5506afcc840STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
5516afcc840STakahiro Kuwano 
552aa517a29STudor Ambarus 	/*
553aa517a29STudor Ambarus 	 * S25FS256T does not define the SCCR map, but we would like to use the
554aa517a29STudor Ambarus 	 * same code base for both single and multi chip package devices, thus
555aa517a29STudor Ambarus 	 * set the vreg_offset and n_dice to be able to do so.
556aa517a29STudor Ambarus 	 */
557aa517a29STudor Ambarus 	params->vreg_offset = devm_kmalloc(nor->dev, sizeof(u32), GFP_KERNEL);
558aa517a29STudor Ambarus 	if (!params->vreg_offset)
559aa517a29STudor Ambarus 		return -ENOMEM;
560aa517a29STudor Ambarus 
561aa517a29STudor Ambarus 	params->vreg_offset[0] = SPINOR_REG_CYPRESS_VREG;
562aa517a29STudor Ambarus 	params->n_dice = 1;
563aa517a29STudor Ambarus 
5646afcc840STakahiro Kuwano 	/* PP_1_1_4_4B is supported but missing in 4BAIT. */
5656afcc840STakahiro Kuwano 	params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
5666afcc840STakahiro Kuwano 	spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
5676afcc840STakahiro Kuwano 				SPINOR_OP_PP_1_1_4_4B,
5686afcc840STakahiro Kuwano 				SNOR_PROTO_1_1_4);
569e570f787STudor Ambarus 
570aa517a29STudor Ambarus 	return cypress_nor_get_page_size(nor);
5716afcc840STakahiro Kuwano }
5726afcc840STakahiro Kuwano 
s25fs256t_late_init(struct spi_nor * nor)573d534fd97STakahiro Kuwano static int s25fs256t_late_init(struct spi_nor *nor)
5746afcc840STakahiro Kuwano {
575a9180c29STakahiro Kuwano 	cypress_nor_ecc_init(nor);
576d534fd97STakahiro Kuwano 
577d534fd97STakahiro Kuwano 	return 0;
5786afcc840STakahiro Kuwano }
5796afcc840STakahiro Kuwano 
5806afcc840STakahiro Kuwano static struct spi_nor_fixups s25fs256t_fixups = {
5816afcc840STakahiro Kuwano 	.post_bfpt = s25fs256t_post_bfpt_fixup,
5826afcc840STakahiro Kuwano 	.post_sfdp = s25fs256t_post_sfdp_fixup,
5836afcc840STakahiro Kuwano 	.late_init = s25fs256t_late_init,
5846afcc840STakahiro Kuwano };
5856afcc840STakahiro Kuwano 
5866afcc840STakahiro Kuwano static int
s25hx_t_post_bfpt_fixup(struct spi_nor * nor,const struct sfdp_parameter_header * bfpt_header,const struct sfdp_bfpt * bfpt)587b6b23833STakahiro Kuwano s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
588b6b23833STakahiro Kuwano 			const struct sfdp_parameter_header *bfpt_header,
589b6b23833STakahiro Kuwano 			const struct sfdp_bfpt *bfpt)
590b6b23833STakahiro Kuwano {
591c87c9b11STakahiro Kuwano 	int ret;
592c87c9b11STakahiro Kuwano 
593c87c9b11STakahiro Kuwano 	ret = cypress_nor_set_addr_mode_nbytes(nor);
594c87c9b11STakahiro Kuwano 	if (ret)
595c87c9b11STakahiro Kuwano 		return ret;
596c87c9b11STakahiro Kuwano 
597b6b23833STakahiro Kuwano 	/* Replace Quad Enable with volatile version */
598b6b23833STakahiro Kuwano 	nor->params->quad_enable = cypress_nor_quad_enable_volatile;
599b6b23833STakahiro Kuwano 
6006c01ae11STakahiro Kuwano 	return 0;
601b6b23833STakahiro Kuwano }
602b6b23833STakahiro Kuwano 
s25hx_t_post_sfdp_fixup(struct spi_nor * nor)603e570f787STudor Ambarus static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
604b6b23833STakahiro Kuwano {
605aa517a29STudor Ambarus 	struct spi_nor_flash_parameter *params = nor->params;
606aa517a29STudor Ambarus 	struct spi_nor_erase_type *erase_type = params->erase_map.erase_type;
607b6b23833STakahiro Kuwano 	unsigned int i;
608b6b23833STakahiro Kuwano 
609aa517a29STudor Ambarus 	if (!params->n_dice || !params->vreg_offset) {
610aa517a29STudor Ambarus 		dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
611aa517a29STudor Ambarus 			__func__);
612aa517a29STudor Ambarus 		return -EOPNOTSUPP;
613aa517a29STudor Ambarus 	}
614aa517a29STudor Ambarus 
615aa517a29STudor Ambarus 	/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
616aa517a29STudor Ambarus 	if (params->size == SZ_256M)
617aa517a29STudor Ambarus 		params->n_dice = 2;
618aa517a29STudor Ambarus 
619b6b23833STakahiro Kuwano 	/*
620b6b23833STakahiro Kuwano 	 * In some parts, 3byte erase opcodes are advertised by 4BAIT.
621b6b23833STakahiro Kuwano 	 * Convert them to 4byte erase opcodes.
622b6b23833STakahiro Kuwano 	 */
623b6b23833STakahiro Kuwano 	for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) {
624b6b23833STakahiro Kuwano 		switch (erase_type[i].opcode) {
625b6b23833STakahiro Kuwano 		case SPINOR_OP_SE:
626b6b23833STakahiro Kuwano 			erase_type[i].opcode = SPINOR_OP_SE_4B;
627b6b23833STakahiro Kuwano 			break;
628b6b23833STakahiro Kuwano 		case SPINOR_OP_BE_4K:
629b6b23833STakahiro Kuwano 			erase_type[i].opcode = SPINOR_OP_BE_4K_4B;
630b6b23833STakahiro Kuwano 			break;
631b6b23833STakahiro Kuwano 		default:
632b6b23833STakahiro Kuwano 			break;
633b6b23833STakahiro Kuwano 		}
634b6b23833STakahiro Kuwano 	}
635e570f787STudor Ambarus 
6366c01ae11STakahiro Kuwano 	return cypress_nor_get_page_size(nor);
637b6b23833STakahiro Kuwano }
638b6b23833STakahiro Kuwano 
s25hx_t_late_init(struct spi_nor * nor)639d534fd97STakahiro Kuwano static int s25hx_t_late_init(struct spi_nor *nor)
640b6b23833STakahiro Kuwano {
64191f3c430STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
64291f3c430STakahiro Kuwano 
643b6b23833STakahiro Kuwano 	/* Fast Read 4B requires mode cycles */
64491f3c430STakahiro Kuwano 	params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
64591f3c430STakahiro Kuwano 	params->ready = cypress_nor_sr_ready_and_clear;
646b6b23833STakahiro Kuwano 	cypress_nor_ecc_init(nor);
647b6b23833STakahiro Kuwano 
648d534fd97STakahiro Kuwano 	return 0;
649b6b23833STakahiro Kuwano }
650b6b23833STakahiro Kuwano 
651b6b23833STakahiro Kuwano static struct spi_nor_fixups s25hx_t_fixups = {
652b6b23833STakahiro Kuwano 	.post_bfpt = s25hx_t_post_bfpt_fixup,
653b6b23833STakahiro Kuwano 	.post_sfdp = s25hx_t_post_sfdp_fixup,
654b6b23833STakahiro Kuwano 	.late_init = s25hx_t_late_init,
655b6b23833STakahiro Kuwano };
656b6b23833STakahiro Kuwano 
657a6b50aa1STakahiro Kuwano /**
658d4996700STudor Ambarus  * cypress_nor_set_octal_dtr() - Enable or disable octal DTR on Cypress flashes.
659c3266af1SPratyush Yadav  * @nor:		pointer to a 'struct spi_nor'
660c3266af1SPratyush Yadav  * @enable:              whether to enable or disable Octal DTR
661c3266af1SPratyush Yadav  *
662c3266af1SPratyush Yadav  * This also sets the memory access latency cycles to 24 to allow the flash to
663c3266af1SPratyush Yadav  * run at up to 200MHz.
664c3266af1SPratyush Yadav  *
665c3266af1SPratyush Yadav  * Return: 0 on success, -errno otherwise.
666c3266af1SPratyush Yadav  */
cypress_nor_set_octal_dtr(struct spi_nor * nor,bool enable)667d4996700STudor Ambarus static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
668c3266af1SPratyush Yadav {
66927ff0d34STudor Ambarus 	return enable ? cypress_nor_octal_dtr_en(nor) :
67027ff0d34STudor Ambarus 			cypress_nor_octal_dtr_dis(nor);
671c3266af1SPratyush Yadav }
672c3266af1SPratyush Yadav 
s28hx_t_post_sfdp_fixup(struct spi_nor * nor)673e570f787STudor Ambarus static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
674c3266af1SPratyush Yadav {
67568a86d18STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
676aa517a29STudor Ambarus 
677aa517a29STudor Ambarus 	if (!params->n_dice || !params->vreg_offset) {
678aa517a29STudor Ambarus 		dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
679aa517a29STudor Ambarus 			__func__);
680aa517a29STudor Ambarus 		return -EOPNOTSUPP;
681aa517a29STudor Ambarus 	}
682aa517a29STudor Ambarus 
683aa517a29STudor Ambarus 	/* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
684aa517a29STudor Ambarus 	if (params->size == SZ_256M)
685aa517a29STudor Ambarus 		params->n_dice = 2;
686aa517a29STudor Ambarus 
687c3266af1SPratyush Yadav 	/*
688c3266af1SPratyush Yadav 	 * On older versions of the flash the xSPI Profile 1.0 table has the
689c3266af1SPratyush Yadav 	 * 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
690c3266af1SPratyush Yadav 	 */
69168a86d18STakahiro Kuwano 	if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
69268a86d18STakahiro Kuwano 		params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
693c3266af1SPratyush Yadav 			SPINOR_OP_CYPRESS_RD_FAST;
694c3266af1SPratyush Yadav 
695c3266af1SPratyush Yadav 	/* This flash is also missing the 4-byte Page Program opcode bit. */
69668a86d18STakahiro Kuwano 	spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
697c3266af1SPratyush Yadav 				SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
698c3266af1SPratyush Yadav 	/*
699c3266af1SPratyush Yadav 	 * Since xSPI Page Program opcode is backward compatible with
700c3266af1SPratyush Yadav 	 * Legacy SPI, use Legacy SPI opcode there as well.
701c3266af1SPratyush Yadav 	 */
70268a86d18STakahiro Kuwano 	spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
703c3266af1SPratyush Yadav 				SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
704c3266af1SPratyush Yadav 
705c3266af1SPratyush Yadav 	/*
706c3266af1SPratyush Yadav 	 * The xSPI Profile 1.0 table advertises the number of additional
707c3266af1SPratyush Yadav 	 * address bytes needed for Read Status Register command as 0 but the
708c3266af1SPratyush Yadav 	 * actual value for that is 4.
709c3266af1SPratyush Yadav 	 */
71068a86d18STakahiro Kuwano 	params->rdsr_addr_nbytes = 4;
711e570f787STudor Ambarus 
7126c01ae11STakahiro Kuwano 	return cypress_nor_get_page_size(nor);
713c3266af1SPratyush Yadav }
714c3266af1SPratyush Yadav 
s28hx_t_post_bfpt_fixup(struct spi_nor * nor,const struct sfdp_parameter_header * bfpt_header,const struct sfdp_bfpt * bfpt)71506051322STakahiro Kuwano static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
716c3266af1SPratyush Yadav 				   const struct sfdp_parameter_header *bfpt_header,
717a580293aSTudor Ambarus 				   const struct sfdp_bfpt *bfpt)
718c3266af1SPratyush Yadav {
719abfac0f3STudor Ambarus 	return cypress_nor_set_addr_mode_nbytes(nor);
720c3266af1SPratyush Yadav }
721c3266af1SPratyush Yadav 
s28hx_t_late_init(struct spi_nor * nor)722d534fd97STakahiro Kuwano static int s28hx_t_late_init(struct spi_nor *nor)
723db391efeSTakahiro Kuwano {
724362f786eSTakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
725362f786eSTakahiro Kuwano 
726362f786eSTakahiro Kuwano 	params->set_octal_dtr = cypress_nor_set_octal_dtr;
727463d7cfdSTakahiro Kuwano 	params->ready = cypress_nor_sr_ready_and_clear;
7289fd0945fSTakahiro Kuwano 	cypress_nor_ecc_init(nor);
729d534fd97STakahiro Kuwano 
730d534fd97STakahiro Kuwano 	return 0;
731db391efeSTakahiro Kuwano }
732db391efeSTakahiro Kuwano 
73306051322STakahiro Kuwano static const struct spi_nor_fixups s28hx_t_fixups = {
73406051322STakahiro Kuwano 	.post_sfdp = s28hx_t_post_sfdp_fixup,
73506051322STakahiro Kuwano 	.post_bfpt = s28hx_t_post_bfpt_fixup,
73606051322STakahiro Kuwano 	.late_init = s28hx_t_late_init,
737c3266af1SPratyush Yadav };
738c3266af1SPratyush Yadav 
7395587fa48SSergei Shtylyov static int
s25fs_s_nor_post_bfpt_fixups(struct spi_nor * nor,const struct sfdp_parameter_header * bfpt_header,const struct sfdp_bfpt * bfpt)740fedd0cbfSMichael Walle s25fs_s_nor_post_bfpt_fixups(struct spi_nor *nor,
7415587fa48SSergei Shtylyov 			     const struct sfdp_parameter_header *bfpt_header,
742a580293aSTudor Ambarus 			     const struct sfdp_bfpt *bfpt)
7435587fa48SSergei Shtylyov {
7445587fa48SSergei Shtylyov 	/*
7455587fa48SSergei Shtylyov 	 * The S25FS-S chip family reports 512-byte pages in BFPT but
7465587fa48SSergei Shtylyov 	 * in reality the write buffer still wraps at the safe default
7475587fa48SSergei Shtylyov 	 * of 256 bytes.  Overwrite the page size advertised by BFPT
7485587fa48SSergei Shtylyov 	 * to get the writes working.
7495587fa48SSergei Shtylyov 	 */
750a580293aSTudor Ambarus 	nor->params->page_size = 256;
7515587fa48SSergei Shtylyov 
7525587fa48SSergei Shtylyov 	return 0;
7535587fa48SSergei Shtylyov }
7545587fa48SSergei Shtylyov 
755fedd0cbfSMichael Walle static const struct spi_nor_fixups s25fs_s_nor_fixups = {
756fedd0cbfSMichael Walle 	.post_bfpt = s25fs_s_nor_post_bfpt_fixups,
7575587fa48SSergei Shtylyov };
7585587fa48SSergei Shtylyov 
759fedd0cbfSMichael Walle static const struct flash_info spansion_nor_parts[] = {
7600173c32aSBoris Brezillon 	/* Spansion/Cypress -- single (large) sector size only, at least
7610173c32aSBoris Brezillon 	 * for the chips listed here (without boot sectors).
7620173c32aSBoris Brezillon 	 */
763ec1c0e99STudor Ambarus 	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64)
764ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
765ec1c0e99STudor Ambarus 	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128)
766ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
767ec1c0e99STudor Ambarus 	{ "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64)
768ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
76951c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
77051c55506SMichael Walle 	},
77151c55506SMichael Walle 	{ "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256)
77251c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
77351c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
77451c55506SMichael Walle 	},
77551c55506SMichael Walle 	{ "s25fl256s0", INFO6(0x010219, 0x4d0080, 256 * 1024, 128)
77651c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_SKIP_SFDP | SPI_NOR_DUAL_READ |
77751c55506SMichael Walle 			      SPI_NOR_QUAD_READ)
77851c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
77951c55506SMichael Walle 	},
78051c55506SMichael Walle 	{ "s25fl256s1", INFO6(0x010219, 0x4d0180, 64 * 1024, 512)
78151c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
78251c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
78351c55506SMichael Walle 	},
78451c55506SMichael Walle 	{ "s25fl512s",  INFO6(0x010220, 0x4d0080, 256 * 1024, 256)
78551c55506SMichael Walle 		FLAGS(SPI_NOR_HAS_LOCK)
78651c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
78751c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
78851c55506SMichael Walle 	},
78951c55506SMichael Walle 	{ "s25fs128s1", INFO6(0x012018, 0x4d0181, 64 * 1024, 256)
79051c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
79151c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
792fedd0cbfSMichael Walle 		.fixups = &s25fs_s_nor_fixups, },
793ec1c0e99STudor Ambarus 	{ "s25fs256s0", INFO6(0x010219, 0x4d0081, 256 * 1024, 128)
794ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
79551c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
79651c55506SMichael Walle 	},
79751c55506SMichael Walle 	{ "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512)
79851c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
79951c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
80051c55506SMichael Walle 	},
80151c55506SMichael Walle 	{ "s25fs512s",  INFO6(0x010220, 0x4d0081, 256 * 1024, 256)
80251c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
80351c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
804fedd0cbfSMichael Walle 		.fixups = &s25fs_s_nor_fixups, },
805ec1c0e99STudor Ambarus 	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64) },
806ec1c0e99STudor Ambarus 	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256) },
807ec1c0e99STudor Ambarus 	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64)
80851c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
80951c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
81051c55506SMichael Walle 	},
811ec1c0e99STudor Ambarus 	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256)
81251c55506SMichael Walle 		NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
81351c55506SMichael Walle 		MFR_FLAGS(USE_CLSR)
81451c55506SMichael Walle 	},
815ec1c0e99STudor Ambarus 	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8) },
816ec1c0e99STudor Ambarus 	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16) },
817ec1c0e99STudor Ambarus 	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32) },
818ec1c0e99STudor Ambarus 	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64) },
819ec1c0e99STudor Ambarus 	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128) },
820ec1c0e99STudor Ambarus 	{ "s25fl004k",  INFO(0xef4013,      0,  64 * 1024,   8)
821ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
822ec1c0e99STudor Ambarus 			      SPI_NOR_QUAD_READ) },
823ec1c0e99STudor Ambarus 	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16)
824ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
825ec1c0e99STudor Ambarus 			      SPI_NOR_QUAD_READ) },
826ec1c0e99STudor Ambarus 	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32)
827ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
828ec1c0e99STudor Ambarus 			      SPI_NOR_QUAD_READ) },
829ec1c0e99STudor Ambarus 	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128)
830ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
831ec1c0e99STudor Ambarus 			      SPI_NOR_QUAD_READ) },
832ec1c0e99STudor Ambarus 	{ "s25fl116k",  INFO(0x014015,      0,  64 * 1024,  32)
833ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
834ec1c0e99STudor Ambarus 			      SPI_NOR_QUAD_READ) },
835ec1c0e99STudor Ambarus 	{ "s25fl132k",  INFO(0x014016,      0,  64 * 1024,  64)
836ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K) },
837ec1c0e99STudor Ambarus 	{ "s25fl164k",  INFO(0x014017,      0,  64 * 1024, 128)
838ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K) },
839ec1c0e99STudor Ambarus 	{ "s25fl204k",  INFO(0x014013,      0,  64 * 1024,   8)
840ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
841ec1c0e99STudor Ambarus 	{ "s25fl208k",  INFO(0x014014,      0,  64 * 1024,  16)
842ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
843ec1c0e99STudor Ambarus 	{ "s25fl064l",  INFO(0x016017,      0,  64 * 1024, 128)
844ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
845ec1c0e99STudor Ambarus 		FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
846ec1c0e99STudor Ambarus 	{ "s25fl128l",  INFO(0x016018,      0,  64 * 1024, 256)
847ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
848ec1c0e99STudor Ambarus 		FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
849ec1c0e99STudor Ambarus 	{ "s25fl256l",  INFO(0x016019,      0,  64 * 1024, 512)
850ec1c0e99STudor Ambarus 		NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
851ec1c0e99STudor Ambarus 		FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
8526afcc840STakahiro Kuwano 	{ "s25fs256t",  INFO6(0x342b19, 0x0f0890, 0, 0)
8536afcc840STakahiro Kuwano 		PARSE_SFDP
854d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
8556afcc840STakahiro Kuwano 		.fixups = &s25fs256t_fixups },
85639133e5fSTudor Ambarus 	{ "s25hl512t",  INFO6(0x342a1a, 0x0f0390, 0, 0)
857b6b23833STakahiro Kuwano 		PARSE_SFDP
858d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
859b6b23833STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
86039133e5fSTudor Ambarus 	{ "s25hl01gt",  INFO6(0x342a1b, 0x0f0390, 0, 0)
861b6b23833STakahiro Kuwano 		PARSE_SFDP
862d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
863b6b23833STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
864df6def86STakahiro Kuwano 	{ "s25hl02gt",  INFO6(0x342a1c, 0x0f0090, 0, 0)
865df6def86STakahiro Kuwano 		PARSE_SFDP
866d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
867df6def86STakahiro Kuwano 		FLAGS(NO_CHIP_ERASE)
868df6def86STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
86939133e5fSTudor Ambarus 	{ "s25hs512t",  INFO6(0x342b1a, 0x0f0390, 0, 0)
870b6b23833STakahiro Kuwano 		PARSE_SFDP
871d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
872b6b23833STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
87339133e5fSTudor Ambarus 	{ "s25hs01gt",  INFO6(0x342b1b, 0x0f0390, 0, 0)
874b6b23833STakahiro Kuwano 		PARSE_SFDP
875d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
876b6b23833STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
877df6def86STakahiro Kuwano 	{ "s25hs02gt",  INFO6(0x342b1c, 0x0f0090, 0, 0)
878df6def86STakahiro Kuwano 		PARSE_SFDP
879d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
880df6def86STakahiro Kuwano 		FLAGS(NO_CHIP_ERASE)
881df6def86STakahiro Kuwano 		.fixups = &s25hx_t_fixups },
882ec1c0e99STudor Ambarus 	{ "cy15x104q",  INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
883ec1c0e99STudor Ambarus 		FLAGS(SPI_NOR_NO_ERASE) },
88439133e5fSTudor Ambarus 	{ "s28hl512t",   INFO(0x345a1a,      0, 0, 0)
885aff1fa41STakahiro Kuwano 		PARSE_SFDP
886d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
887aff1fa41STakahiro Kuwano 		.fixups = &s28hx_t_fixups,
888aff1fa41STakahiro Kuwano 	},
88939133e5fSTudor Ambarus 	{ "s28hl01gt",   INFO(0x345a1b,      0, 0, 0)
890aff1fa41STakahiro Kuwano 		PARSE_SFDP
891d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
892aff1fa41STakahiro Kuwano 		.fixups = &s28hx_t_fixups,
893aff1fa41STakahiro Kuwano 	},
89439133e5fSTudor Ambarus 	{ "s28hs512t",   INFO(0x345b1a,      0, 0, 0)
895db391efeSTakahiro Kuwano 		PARSE_SFDP
896d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
89706051322STakahiro Kuwano 		.fixups = &s28hx_t_fixups,
898c3266af1SPratyush Yadav 	},
89939133e5fSTudor Ambarus 	{ "s28hs01gt",   INFO(0x345b1b,      0, 0, 0)
900aff1fa41STakahiro Kuwano 		PARSE_SFDP
901d534fd97STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
902aff1fa41STakahiro Kuwano 		.fixups = &s28hx_t_fixups,
903aff1fa41STakahiro Kuwano 	},
90468a86d18STakahiro Kuwano 	{ "s28hs02gt",   INFO(0x345b1c,      0, 0, 0)
90568a86d18STakahiro Kuwano 		PARSE_SFDP
90668a86d18STakahiro Kuwano 		MFR_FLAGS(USE_CLPEF)
907837d5181SMichael Walle 		.fixups = &s28hx_t_fixups,
908c0abb861STudor Ambarus 	},
909837d5181SMichael Walle };
910837d5181SMichael Walle 
911837d5181SMichael Walle /**
912e8fd3b4bSMichael Walle  * spansion_nor_sr_ready_and_clear() - Query the Status Register to see if the
913e8fd3b4bSMichael Walle  * flash is ready for new commands and clear it if there are any errors.
914837d5181SMichael Walle  * @nor:	pointer to 'struct spi_nor'.
915837d5181SMichael Walle  *
916837d5181SMichael Walle  * Return: 1 if ready, 0 if not ready, -errno on errors.
917837d5181SMichael Walle  */
spansion_nor_sr_ready_and_clear(struct spi_nor * nor)918e8fd3b4bSMichael Walle static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
919837d5181SMichael Walle {
920837d5181SMichael Walle 	int ret;
921837d5181SMichael Walle 
922837d5181SMichael Walle 	ret = spi_nor_read_sr(nor, nor->bouncebuf);
923837d5181SMichael Walle 	if (ret)
924837d5181SMichael Walle 		return ret;
925837d5181SMichael Walle 
926837d5181SMichael Walle 	if (nor->bouncebuf[0] & (SR_E_ERR | SR_P_ERR)) {
927837d5181SMichael Walle 		if (nor->bouncebuf[0] & SR_E_ERR)
928837d5181SMichael Walle 			dev_err(nor->dev, "Erase Error occurred\n");
929837d5181SMichael Walle 		else
930837d5181SMichael Walle 			dev_err(nor->dev, "Programming Error occurred\n");
931837d5181SMichael Walle 
932e8fd3b4bSMichael Walle 		spansion_nor_clear_sr(nor);
933837d5181SMichael Walle 
934837d5181SMichael Walle 		/*
935837d5181SMichael Walle 		 * WEL bit remains set to one when an erase or page program
936837d5181SMichael Walle 		 * error occurs. Issue a Write Disable command to protect
937837d5181SMichael Walle 		 * against inadvertent writes that can possibly corrupt the
938837d5181SMichael Walle 		 * contents of the memory.
939837d5181SMichael Walle 		 */
940837d5181SMichael Walle 		ret = spi_nor_write_disable(nor);
941837d5181SMichael Walle 		if (ret)
942837d5181SMichael Walle 			return ret;
943837d5181SMichael Walle 
944837d5181SMichael Walle 		return -EIO;
945837d5181SMichael Walle 	}
946837d5181SMichael Walle 
947837d5181SMichael Walle 	return !(nor->bouncebuf[0] & SR_WIP);
948837d5181SMichael Walle }
949837d5181SMichael Walle 
spansion_nor_late_init(struct spi_nor * nor)950d534fd97STakahiro Kuwano static int spansion_nor_late_init(struct spi_nor *nor)
9510173c32aSBoris Brezillon {
952d534fd97STakahiro Kuwano 	struct spi_nor_flash_parameter *params = nor->params;
953d534fd97STakahiro Kuwano 	struct spansion_nor_params *priv_params;
954d534fd97STakahiro Kuwano 	u8 mfr_flags = nor->info->mfr_flags;
955d534fd97STakahiro Kuwano 
956d534fd97STakahiro Kuwano 	if (params->size > SZ_16M) {
9570173c32aSBoris Brezillon 		nor->flags |= SNOR_F_4B_OPCODES;
9580173c32aSBoris Brezillon 		/* No small sector erase for 4-byte command set */
9590173c32aSBoris Brezillon 		nor->erase_opcode = SPINOR_OP_SE;
9600173c32aSBoris Brezillon 		nor->mtd.erasesize = nor->info->sector_size;
9610173c32aSBoris Brezillon 	}
962837d5181SMichael Walle 
963d534fd97STakahiro Kuwano 	if (mfr_flags & (USE_CLSR | USE_CLPEF)) {
964d534fd97STakahiro Kuwano 		priv_params = devm_kmalloc(nor->dev, sizeof(*priv_params),
965d534fd97STakahiro Kuwano 					   GFP_KERNEL);
966d534fd97STakahiro Kuwano 		if (!priv_params)
967d534fd97STakahiro Kuwano 			return -ENOMEM;
968d534fd97STakahiro Kuwano 
969d534fd97STakahiro Kuwano 		if (mfr_flags & USE_CLSR)
970d534fd97STakahiro Kuwano 			priv_params->clsr = SPINOR_OP_CLSR;
971d534fd97STakahiro Kuwano 		else if (mfr_flags & USE_CLPEF)
972d534fd97STakahiro Kuwano 			priv_params->clsr = SPINOR_OP_CLPEF;
973d534fd97STakahiro Kuwano 
974d534fd97STakahiro Kuwano 		params->priv = priv_params;
975d534fd97STakahiro Kuwano 		params->ready = spansion_nor_sr_ready_and_clear;
976d534fd97STakahiro Kuwano 	}
977d534fd97STakahiro Kuwano 
978d534fd97STakahiro Kuwano 	return 0;
9796235ff04SMichael Walle }
9800173c32aSBoris Brezillon 
981fedd0cbfSMichael Walle static const struct spi_nor_fixups spansion_nor_fixups = {
982fedd0cbfSMichael Walle 	.late_init = spansion_nor_late_init,
9830173c32aSBoris Brezillon };
9840173c32aSBoris Brezillon 
9850173c32aSBoris Brezillon const struct spi_nor_manufacturer spi_nor_spansion = {
9860173c32aSBoris Brezillon 	.name = "spansion",
987fedd0cbfSMichael Walle 	.parts = spansion_nor_parts,
988fedd0cbfSMichael Walle 	.nparts = ARRAY_SIZE(spansion_nor_parts),
989fedd0cbfSMichael Walle 	.fixups = &spansion_nor_fixups,
9900173c32aSBoris Brezillon };
991