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(¶ms->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(¶ms->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(¶ms->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