summaryrefslogtreecommitdiff
path: root/drivers/mtd/spi-nor/spansion.c
diff options
context:
space:
mode:
authorTakahiro Kuwano <Takahiro.Kuwano@infineon.com>2023-07-26 10:52:47 +0300
committerTudor Ambarus <tudor.ambarus@linaro.org>2023-07-26 12:39:10 +0300
commitd534fd9787d5925d9637752410e3ea92ca7f4cfa (patch)
treef660f9c009f55019557a27fc3ab7a76c10d3fb09 /drivers/mtd/spi-nor/spansion.c
parentabfac0f3a457dab837fc74e47f00d829976fb0a6 (diff)
downloadlinux-d534fd9787d5925d9637752410e3ea92ca7f4cfa.tar.xz
mtd: spi-nor: spansion: use CLPEF as an alternative to CLSR
Infineon S28Hx (SEMPER Octal) and S25FS256T (SEMPER Nano) support Clear Program and Erase Failure Flags (CLPEF, 82h) instead of CLSR(30h). Introduce a new mfr_flag together with the infrastructure to allow manufacturer private data in the core. With this we remove the need to have if checks in the code at runtime and instead set the correct opcodes at probe time. S25Hx (SEMPER QSPI) supports CLSR but it may be disabled by CFR3x[2] while CLPEF is always available. Therefore, the mfr_flag is also applied to S25Hx for safety. Signed-off-by: Takahiro Kuwano <Takahiro.Kuwano@infineon.com> Link: https://lore.kernel.org/r/20230726075257.12985-2-tudor.ambarus@linaro.org Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
Diffstat (limited to 'drivers/mtd/spi-nor/spansion.c')
-rw-r--r--drivers/mtd/spi-nor/spansion.c72
1 files changed, 58 insertions, 14 deletions
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 314667d4b8a8..6b2532ed053c 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -4,14 +4,17 @@
* Copyright (C) 2014, Freescale Semiconductor, Inc.
*/
+#include <linux/device.h>
#include <linux/mtd/spi-nor.h>
#include "core.h"
/* flash_info mfr_flag. Used to clear sticky prorietary SR bits. */
#define USE_CLSR BIT(0)
+#define USE_CLPEF BIT(1)
#define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
+#define SPINOR_OP_CLPEF 0x82 /* Clear program/erase failure flags */
#define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
#define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
#define SPINOR_REG_CYPRESS_VREG 0x00800000
@@ -57,22 +60,32 @@
SPI_MEM_OP_DUMMY(ndummy, 0), \
SPI_MEM_OP_DATA_IN(1, buf, 0))
-#define SPANSION_CLSR_OP \
- SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_CLSR, 0), \
+#define SPANSION_OP(opcode) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 0), \
SPI_MEM_OP_NO_ADDR, \
SPI_MEM_OP_NO_DUMMY, \
SPI_MEM_OP_NO_DATA)
/**
+ * struct spansion_nor_params - Spansion private parameters.
+ * @clsr: Clear Status Register or Clear Program and Erase Failure Flag
+ * opcode.
+ */
+struct spansion_nor_params {
+ u8 clsr;
+};
+
+/**
* spansion_nor_clear_sr() - Clear the Status Register.
* @nor: pointer to 'struct spi_nor'.
*/
static void spansion_nor_clear_sr(struct spi_nor *nor)
{
+ const struct spansion_nor_params *priv_params = nor->params->priv;
int ret;
if (nor->spimem) {
- struct spi_mem_op op = SPANSION_CLSR_OP;
+ struct spi_mem_op op = SPANSION_OP(priv_params->clsr);
spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
@@ -528,9 +541,11 @@ static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
return 0;
}
-static void s25fs256t_late_init(struct spi_nor *nor)
+static int s25fs256t_late_init(struct spi_nor *nor)
{
cypress_nor_ecc_init(nor);
+
+ return 0;
}
static struct spi_nor_fixups s25fs256t_fixups = {
@@ -586,7 +601,7 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
return cypress_nor_get_page_size(nor);
}
-static void s25hx_t_late_init(struct spi_nor *nor)
+static int s25hx_t_late_init(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
@@ -598,6 +613,8 @@ static void s25hx_t_late_init(struct spi_nor *nor)
/* Replace ready() with multi die version */
if (params->n_dice)
params->ready = cypress_nor_sr_ready_and_clear;
+
+ return 0;
}
static struct spi_nor_fixups s25hx_t_fixups = {
@@ -659,10 +676,12 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
return cypress_nor_set_addr_mode_nbytes(nor);
}
-static void s28hx_t_late_init(struct spi_nor *nor)
+static int s28hx_t_late_init(struct spi_nor *nor)
{
nor->params->set_octal_dtr = cypress_nor_set_octal_dtr;
cypress_nor_ecc_init(nor);
+
+ return 0;
}
static const struct spi_nor_fixups s28hx_t_fixups = {
@@ -786,47 +805,54 @@ static const struct flash_info spansion_nor_parts[] = {
FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
{ "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s25fs256t_fixups },
{ "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512)
PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
FLAGS(NO_CHIP_ERASE)
.fixups = &s25hx_t_fixups },
{ "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512)
PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s25hx_t_fixups },
{ "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
FLAGS(NO_CHIP_ERASE)
.fixups = &s25hx_t_fixups },
{ "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
FLAGS(SPI_NOR_NO_ERASE) },
{ "s28hl512t", INFO(0x345a1a, 0, 256 * 1024, 256)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
{ "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512)
PARSE_SFDP
+ MFR_FLAGS(USE_CLPEF)
.fixups = &s28hx_t_fixups,
},
};
@@ -870,17 +896,35 @@ static int spansion_nor_sr_ready_and_clear(struct spi_nor *nor)
return !(nor->bouncebuf[0] & SR_WIP);
}
-static void spansion_nor_late_init(struct spi_nor *nor)
+static int spansion_nor_late_init(struct spi_nor *nor)
{
- if (nor->params->size > SZ_16M) {
+ struct spi_nor_flash_parameter *params = nor->params;
+ struct spansion_nor_params *priv_params;
+ u8 mfr_flags = nor->info->mfr_flags;
+
+ if (params->size > SZ_16M) {
nor->flags |= SNOR_F_4B_OPCODES;
/* No small sector erase for 4-byte command set */
nor->erase_opcode = SPINOR_OP_SE;
nor->mtd.erasesize = nor->info->sector_size;
}
- if (nor->info->mfr_flags & USE_CLSR)
- nor->params->ready = spansion_nor_sr_ready_and_clear;
+ if (mfr_flags & (USE_CLSR | USE_CLPEF)) {
+ priv_params = devm_kmalloc(nor->dev, sizeof(*priv_params),
+ GFP_KERNEL);
+ if (!priv_params)
+ return -ENOMEM;
+
+ if (mfr_flags & USE_CLSR)
+ priv_params->clsr = SPINOR_OP_CLSR;
+ else if (mfr_flags & USE_CLPEF)
+ priv_params->clsr = SPINOR_OP_CLPEF;
+
+ params->priv = priv_params;
+ params->ready = spansion_nor_sr_ready_and_clear;
+ }
+
+ return 0;
}
static const struct spi_nor_fixups spansion_nor_fixups = {