summaryrefslogtreecommitdiff
path: root/drivers/mtd/spi-nor/spansion.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/spi-nor/spansion.c')
-rw-r--r--drivers/mtd/spi-nor/spansion.c750
1 files changed, 510 insertions, 240 deletions
diff --git a/drivers/mtd/spi-nor/spansion.c b/drivers/mtd/spi-nor/spansion.c
index 15f9a80c10b9..8498c7003d88 100644
--- a/drivers/mtd/spi-nor/spansion.c
+++ b/drivers/mtd/spi-nor/spansion.c
@@ -4,14 +4,21 @@
* Copyright (C) 2014, Freescale Semiconductor, Inc.
*/
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/errno.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_CYPRESS_EX4B 0xB8 /* Exit 4-byte address mode */
+#define SPINOR_OP_CYPRESS_DIE_ERASE 0x61 /* Chip (die) erase */
#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
@@ -19,21 +26,16 @@
#define SPINOR_REG_CYPRESS_STR1V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_STR1)
#define SPINOR_REG_CYPRESS_CFR1 0x2
-#define SPINOR_REG_CYPRESS_CFR1V \
- (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR1)
#define SPINOR_REG_CYPRESS_CFR1_QUAD_EN BIT(1) /* Quad Enable */
#define SPINOR_REG_CYPRESS_CFR2 0x3
#define SPINOR_REG_CYPRESS_CFR2V \
(SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR2)
+#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK GENMASK(3, 0)
#define SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24 0xb
#define SPINOR_REG_CYPRESS_CFR2_ADRBYT BIT(7)
#define SPINOR_REG_CYPRESS_CFR3 0x4
-#define SPINOR_REG_CYPRESS_CFR3V \
- (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR3)
#define SPINOR_REG_CYPRESS_CFR3_PGSZ BIT(4) /* Page size. */
#define SPINOR_REG_CYPRESS_CFR5 0x6
-#define SPINOR_REG_CYPRESS_CFR5V \
- (SPINOR_REG_CYPRESS_VREG + SPINOR_REG_CYPRESS_CFR5)
#define SPINOR_REG_CYPRESS_CFR5_BIT6 BIT(6)
#define SPINOR_REG_CYPRESS_CFR5_DDR BIT(1)
#define SPINOR_REG_CYPRESS_CFR5_OPI BIT(0)
@@ -57,22 +59,39 @@
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 CYPRESS_NOR_EN4B_EX4B_OP(enable) \
+ SPI_MEM_OP(SPI_MEM_OP_CMD(enable ? SPINOR_OP_EN4B : \
+ SPINOR_OP_CYPRESS_EX4B, 0), \
+ SPI_MEM_OP_NO_ADDR, \
+ SPI_MEM_OP_NO_DUMMY, \
+ SPI_MEM_OP_NO_DATA)
+
+#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);
@@ -88,11 +107,18 @@ static void spansion_nor_clear_sr(struct spi_nor *nor)
static int cypress_nor_sr_ready_and_clear_reg(struct spi_nor *nor, u64 addr)
{
+ struct spi_nor_flash_parameter *params = nor->params;
struct spi_mem_op op =
- CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes, addr,
+ CYPRESS_NOR_RD_ANY_REG_OP(params->addr_mode_nbytes, addr,
0, nor->bouncebuf);
int ret;
+ if (nor->reg_proto == SNOR_PROTO_8_8_8_DTR) {
+ op.addr.nbytes = nor->addr_nbytes;
+ op.dummy.nbytes = params->rdsr_dummy;
+ op.data.nbytes = 2;
+ }
+
ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
if (ret)
return ret;
@@ -141,18 +167,26 @@ static int cypress_nor_sr_ready_and_clear(struct spi_nor *nor)
return 1;
}
-static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
+static int cypress_nor_set_memlat(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
int ret;
u8 addr_mode_nbytes = nor->params->addr_mode_nbytes;
+ op = (struct spi_mem_op)
+ CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, addr, 0, buf);
+
+ ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
+ if (ret)
+ return ret;
+
/* Use 24 dummy cycles for memory array reads. */
- *buf = SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24;
+ *buf &= ~SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK;
+ *buf |= FIELD_PREP(SPINOR_REG_CYPRESS_CFR2_MEMLAT_MASK,
+ SPINOR_REG_CYPRESS_CFR2_MEMLAT_11_24);
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
- SPINOR_REG_CYPRESS_CFR2V, 1, buf);
+ CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, addr, 1, buf);
ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
if (ret)
@@ -160,15 +194,41 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
nor->read_dummy = 24;
+ return 0;
+}
+
+static int cypress_nor_set_octal_dtr_bits(struct spi_nor *nor, u64 addr)
+{
+ struct spi_mem_op op;
+ u8 *buf = nor->bouncebuf;
+
/* Set the octal and DTR enable bits. */
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_EN;
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes,
- SPINOR_REG_CYPRESS_CFR5V, 1, buf);
+ CYPRESS_NOR_WR_ANY_REG_OP(nor->params->addr_mode_nbytes,
+ addr, 1, buf);
- ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
- if (ret)
- return ret;
+ return spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto);
+}
+
+static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
+{
+ const struct spi_nor_flash_parameter *params = nor->params;
+ u8 *buf = nor->bouncebuf;
+ u64 addr;
+ int i, ret;
+
+ for (i = 0; i < params->n_dice; i++) {
+ addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR2;
+ ret = cypress_nor_set_memlat(nor, addr);
+ if (ret)
+ return ret;
+
+ addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
+ ret = cypress_nor_set_octal_dtr_bits(nor, addr);
+ if (ret)
+ return ret;
+ }
/* Read flash ID to make sure the switch was successful. */
ret = spi_nor_read_id(nor, nor->addr_nbytes, 3, buf,
@@ -178,17 +238,16 @@ static int cypress_nor_octal_dtr_en(struct spi_nor *nor)
return ret;
}
- if (memcmp(buf, nor->info->id, nor->info->id_len))
+ if (memcmp(buf, nor->info->id->bytes, nor->info->id->len))
return -EINVAL;
return 0;
}
-static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
+static int cypress_nor_set_single_spi_bits(struct spi_nor *nor, u64 addr)
{
struct spi_mem_op op;
u8 *buf = nor->bouncebuf;
- int ret;
/*
* The register is 1-byte wide, but 1-byte transactions are not allowed
@@ -198,11 +257,23 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
buf[0] = SPINOR_REG_CYPRESS_CFR5_OCT_DTR_DS;
buf[1] = 0;
op = (struct spi_mem_op)
- CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes,
- SPINOR_REG_CYPRESS_CFR5V, 2, buf);
- ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
- if (ret)
- return ret;
+ CYPRESS_NOR_WR_ANY_REG_OP(nor->addr_nbytes, addr, 2, buf);
+ return spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR);
+}
+
+static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
+{
+ const struct spi_nor_flash_parameter *params = nor->params;
+ u8 *buf = nor->bouncebuf;
+ u64 addr;
+ int i, ret;
+
+ for (i = 0; i < params->n_dice; i++) {
+ addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR5;
+ ret = cypress_nor_set_single_spi_bits(nor, addr);
+ if (ret)
+ return ret;
+ }
/* Read flash ID to make sure the switch was successful. */
ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1);
@@ -211,7 +282,7 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
return ret;
}
- if (memcmp(buf, nor->info->id, nor->info->id_len))
+ if (memcmp(buf, nor->info->id->bytes, nor->info->id->len))
return -EINVAL;
return 0;
@@ -283,10 +354,6 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
u8 i;
int ret;
- if (!params->n_dice)
- return cypress_nor_quad_enable_volatile_reg(nor,
- SPINOR_REG_CYPRESS_CFR1V);
-
for (i = 0; i < params->n_dice; i++) {
addr = params->vreg_offset[i] + SPINOR_REG_CYPRESS_CFR1;
ret = cypress_nor_quad_enable_volatile_reg(nor, addr);
@@ -297,6 +364,20 @@ static int cypress_nor_quad_enable_volatile(struct spi_nor *nor)
return 0;
}
+static int cypress_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable)
+{
+ int ret;
+ struct spi_mem_op op = CYPRESS_NOR_EN4B_EX4B_OP(enable);
+
+ spi_nor_spimem_setup_op(nor, &op, nor->reg_proto);
+
+ ret = spi_mem_exec_op(nor->spimem, &op);
+ if (ret)
+ dev_dbg(nor->dev, "error %d setting 4-byte mode\n", ret);
+
+ return ret;
+}
+
/**
* cypress_nor_determine_addr_mode_by_sr1() - Determine current address mode
* (3 or 4-byte) by querying status
@@ -408,28 +489,17 @@ static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
return 0;
}
-static int cypress_nor_get_page_size_single_chip(struct spi_nor *nor)
-{
- struct spi_mem_op op =
- CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
- SPINOR_REG_CYPRESS_CFR3V, 0,
- nor->bouncebuf);
- int ret;
-
- ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto);
- if (ret)
- return ret;
-
- if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR3_PGSZ)
- nor->params->page_size = 512;
- else
- nor->params->page_size = 256;
-
- return 0;
-}
-
-
-static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
+/**
+ * cypress_nor_get_page_size() - Get flash page size configuration.
+ * @nor: pointer to a 'struct spi_nor'
+ *
+ * The BFPT table advertises a 512B or 256B page size depending on part but the
+ * page size is actually configurable (with the default being 256B). Read from
+ * CFR3V[4] and set the correct size.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int cypress_nor_get_page_size(struct spi_nor *nor)
{
struct spi_mem_op op =
CYPRESS_NOR_RD_ANY_REG_OP(nor->params->addr_mode_nbytes,
@@ -459,23 +529,6 @@ static int cypress_nor_get_page_size_mcp(struct spi_nor *nor)
return 0;
}
-/**
- * cypress_nor_get_page_size() - Get flash page size configuration.
- * @nor: pointer to a 'struct spi_nor'
- *
- * The BFPT table advertises a 512B or 256B page size depending on part but the
- * page size is actually configurable (with the default being 256B). Read from
- * CFR3V[4] and set the correct size.
- *
- * Return: 0 on success, -errno otherwise.
- */
-static int cypress_nor_get_page_size(struct spi_nor *nor)
-{
- if (nor->params->n_dice)
- return cypress_nor_get_page_size_mcp(nor);
- return cypress_nor_get_page_size_single_chip(nor);
-}
-
static void cypress_nor_ecc_init(struct spi_nor *nor)
{
/*
@@ -495,6 +548,9 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
struct spi_mem_op op;
int ret;
+ /* Assign 4-byte address mode method that is not determined in BFPT */
+ nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
+
ret = cypress_nor_set_addr_mode_nbytes(nor);
if (ret)
return ret;
@@ -512,28 +568,42 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
if (nor->bouncebuf[0])
return -ENODEV;
- return cypress_nor_get_page_size(nor);
+ return 0;
}
static int s25fs256t_post_sfdp_fixup(struct spi_nor *nor)
{
struct spi_nor_flash_parameter *params = nor->params;
+ /*
+ * S25FS256T does not define the SCCR map, but we would like to use the
+ * same code base for both single and multi chip package devices, thus
+ * set the vreg_offset and n_dice to be able to do so.
+ */
+ params->vreg_offset = devm_kmalloc(nor->dev, sizeof(u32), GFP_KERNEL);
+ if (!params->vreg_offset)
+ return -ENOMEM;
+
+ params->vreg_offset[0] = SPINOR_REG_CYPRESS_VREG;
+ params->n_dice = 1;
+
/* PP_1_1_4_4B is supported but missing in 4BAIT. */
params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
SPINOR_OP_PP_1_1_4_4B,
SNOR_PROTO_1_1_4);
- return 0;
+ return cypress_nor_get_page_size(nor);
}
-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 = {
+static const struct spi_nor_fixups s25fs256t_fixups = {
.post_bfpt = s25fs256t_post_bfpt_fixup,
.post_sfdp = s25fs256t_post_sfdp_fixup,
.late_init = s25fs256t_late_init,
@@ -546,6 +616,9 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
{
int ret;
+ /* Assign 4-byte address mode method that is not determined in BFPT */
+ nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
+
ret = cypress_nor_set_addr_mode_nbytes(nor);
if (ret)
return ret;
@@ -558,10 +631,20 @@ s25hx_t_post_bfpt_fixup(struct spi_nor *nor,
static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
{
- struct spi_nor_erase_type *erase_type =
- nor->params->erase_map.erase_type;
+ struct spi_nor_flash_parameter *params = nor->params;
+ struct spi_nor_erase_type *erase_type = params->erase_map.erase_type;
unsigned int i;
+ if (!params->n_dice || !params->vreg_offset) {
+ dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
+ __func__);
+ return -EOPNOTSUPP;
+ }
+
+ /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
+ if (params->size == SZ_256M)
+ params->n_dice = 2;
+
/*
* In some parts, 3byte erase opcodes are advertised by 4BAIT.
* Convert them to 4byte erase opcodes.
@@ -579,35 +662,30 @@ static int s25hx_t_post_sfdp_fixup(struct spi_nor *nor)
}
}
- /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
- if (nor->params->size == SZ_256M)
- nor->params->n_dice = 2;
-
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;
/* Fast Read 4B requires mode cycles */
params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8;
-
+ params->ready = cypress_nor_sr_ready_and_clear;
cypress_nor_ecc_init(nor);
- /* Replace ready() with multi die version */
- if (params->n_dice)
- params->ready = cypress_nor_sr_ready_and_clear;
+ params->die_erase_opcode = SPINOR_OP_CYPRESS_DIE_ERASE;
+ return 0;
}
-static struct spi_nor_fixups s25hx_t_fixups = {
+static const struct spi_nor_fixups s25hx_t_fixups = {
.post_bfpt = s25hx_t_post_bfpt_fixup,
.post_sfdp = s25hx_t_post_sfdp_fixup,
.late_init = s25hx_t_late_init,
};
/**
- * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
+ * cypress_nor_set_octal_dtr() - Enable or disable octal DTR on Cypress flashes.
* @nor: pointer to a 'struct spi_nor'
* @enable: whether to enable or disable Octal DTR
*
@@ -616,7 +694,7 @@ static struct spi_nor_fixups s25hx_t_fixups = {
*
* Return: 0 on success, -errno otherwise.
*/
-static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
+static int cypress_nor_set_octal_dtr(struct spi_nor *nor, bool enable)
{
return enable ? cypress_nor_octal_dtr_en(nor) :
cypress_nor_octal_dtr_dis(nor);
@@ -624,22 +702,34 @@ static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable)
static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
{
+ struct spi_nor_flash_parameter *params = nor->params;
+
+ if (!params->n_dice || !params->vreg_offset) {
+ dev_err(nor->dev, "%s failed. The volatile register offset could not be retrieved from SFDP.\n",
+ __func__);
+ return -EOPNOTSUPP;
+ }
+
+ /* The 2 Gb parts duplicate info and advertise 4 dice instead of 2. */
+ if (params->size == SZ_256M)
+ params->n_dice = 2;
+
/*
* On older versions of the flash the xSPI Profile 1.0 table has the
* 8D-8D-8D Fast Read opcode as 0x00. But it actually should be 0xEE.
*/
- if (nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
- nor->params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
+ if (params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode == 0)
+ params->reads[SNOR_CMD_READ_8_8_8_DTR].opcode =
SPINOR_OP_CYPRESS_RD_FAST;
/* This flash is also missing the 4-byte Page Program opcode bit. */
- spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP],
+ spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
SPINOR_OP_PP_4B, SNOR_PROTO_1_1_1);
/*
* Since xSPI Page Program opcode is backward compatible with
* Legacy SPI, use Legacy SPI opcode there as well.
*/
- spi_nor_set_pp_settings(&nor->params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+ spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
/*
@@ -647,7 +737,7 @@ static int s28hx_t_post_sfdp_fixup(struct spi_nor *nor)
* address bytes needed for Read Status Register command as 0 but the
* actual value for that is 4.
*/
- nor->params->rdsr_addr_nbytes = 4;
+ params->rdsr_addr_nbytes = 4;
return cypress_nor_get_page_size(nor);
}
@@ -656,19 +746,21 @@ static int s28hx_t_post_bfpt_fixup(struct spi_nor *nor,
const struct sfdp_parameter_header *bfpt_header,
const struct sfdp_bfpt *bfpt)
{
- int ret;
+ /* Assign 4-byte address mode method that is not determined in BFPT */
+ nor->params->set_4byte_addr_mode = cypress_nor_set_4byte_addr_mode;
- ret = cypress_nor_set_addr_mode_nbytes(nor);
- if (ret)
- return ret;
-
- return 0;
+ 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->octal_dtr_enable = cypress_nor_octal_dtr_enable;
+ struct spi_nor_flash_parameter *params = nor->params;
+
+ params->set_octal_dtr = cypress_nor_set_octal_dtr;
+ params->ready = cypress_nor_sr_ready_and_clear;
cypress_nor_ecc_init(nor);
+
+ return 0;
}
static const struct spi_nor_fixups s28hx_t_fixups = {
@@ -693,148 +785,307 @@ s25fs_s_nor_post_bfpt_fixups(struct spi_nor *nor,
return 0;
}
+static void s25fs_s_nor_smpt_read_dummy(const struct spi_nor *nor,
+ u8 *read_dummy)
+{
+ /*
+ * The configuration detection dwords in S25FS-S SMPT has 65h as
+ * command instruction and 'variable' as configuration detection command
+ * latency. Set 8 dummy cycles as it is factory default for 65h (read
+ * any register) op.
+ */
+ *read_dummy = 8;
+}
+
+static void s25fs_s_nor_smpt_map_id_dummy(const struct spi_nor *nor, u8 *map_id)
+{
+ /*
+ * The S25FS512S chip supports:
+ * - Hybrid sector option which has physical set of eight 4-KB sectors
+ * and one 224-KB sector at the top or bottom of address space with
+ * all remaining sectors of 256-KB
+ * - Uniform sector option which has uniform 256-KB sectors
+ *
+ * On the other hand, the datasheet rev.O Table 71 on page 153 JEDEC
+ * Sector Map Parameter Dword-6 Config. Detect-3 does use CR3NV[1] to
+ * discern 64-KB(CR3NV[1]=0) and 256-KB(CR3NV[1]=1) uniform sectors
+ * device configuration. And in section 7.5.5.1 Configuration Register 3
+ * Non-volatile (CR3NV) page 61, the CR3NV[1] is RFU Reserved for Future
+ * Use and set to 0, which means 64-KB uniform. Since the device does
+ * not support 64-KB uniform sectors in any configuration, parsing SMPT
+ * table cannot find a valid sector map entry and fails. Fix this up by
+ * setting SMPT by overwriting the CR3NV[1] value to 1, as the table
+ * expects.
+ */
+ if (nor->params->size == SZ_64M)
+ *map_id |= BIT(0);
+}
+
static const struct spi_nor_fixups s25fs_s_nor_fixups = {
.post_bfpt = s25fs_s_nor_post_bfpt_fixups,
+ .smpt_read_dummy = s25fs_s_nor_smpt_read_dummy,
+ .smpt_map_id = s25fs_s_nor_smpt_map_id_dummy,
};
static const struct flash_info spansion_nor_parts[] = {
- /* Spansion/Cypress -- single (large) sector size only, at least
- * for the chips listed here (without boot sectors).
- */
- { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
- { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
- { "s25fl128s0", INFO6(0x012018, 0x4d0080, 256 * 1024, 64)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fl128s1", INFO6(0x012018, 0x4d0180, 64 * 1024, 256)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fl256s0", INFO6(0x010219, 0x4d0080, 256 * 1024, 128)
- NO_SFDP_FLAGS(SPI_NOR_SKIP_SFDP | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fl256s1", INFO6(0x010219, 0x4d0180, 64 * 1024, 512)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fl512s", INFO6(0x010220, 0x4d0080, 256 * 1024, 256)
- FLAGS(SPI_NOR_HAS_LOCK)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fs128s1", INFO6(0x012018, 0x4d0181, 64 * 1024, 256)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25fs_s_nor_fixups, },
- { "s25fs256s0", INFO6(0x010219, 0x4d0081, 256 * 1024, 128)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fs256s1", INFO6(0x010219, 0x4d0181, 64 * 1024, 512)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fs512s", INFO6(0x010220, 0x4d0081, 256 * 1024, 256)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25fs_s_nor_fixups, },
- { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64) },
- { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256) },
- { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256)
- NO_SFDP_FLAGS(SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- MFR_FLAGS(USE_CLSR)
- },
- { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8) },
- { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16) },
- { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32) },
- { "s25sl032a", INFO(0x010215, 0, 64 * 1024, 64) },
- { "s25sl064a", INFO(0x010216, 0, 64 * 1024, 128) },
- { "s25fl004k", INFO(0xef4013, 0, 64 * 1024, 8)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
- { "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
- { "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
- { "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
- { "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
- SPI_NOR_QUAD_READ) },
- { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64)
- NO_SFDP_FLAGS(SECT_4K) },
- { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128)
- NO_SFDP_FLAGS(SECT_4K) },
- { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
- { "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
- { "s25fl064l", INFO(0x016017, 0, 64 * 1024, 128)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
- { "s25fl128l", INFO(0x016018, 0, 64 * 1024, 256)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
- { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
- NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
- FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
- { "s25fs256t", INFO6(0x342b19, 0x0f0890, 0, 0)
- PARSE_SFDP
- .fixups = &s25fs256t_fixups },
- { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256)
- PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25hx_t_fixups },
- { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512)
- PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25hx_t_fixups },
- { "s25hl02gt", INFO6(0x342a1c, 0x0f0090, 0, 0)
- PARSE_SFDP
- FLAGS(NO_CHIP_ERASE)
- .fixups = &s25hx_t_fixups },
- { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256)
- PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25hx_t_fixups },
- { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512)
- PARSE_SFDP
- MFR_FLAGS(USE_CLSR)
- .fixups = &s25hx_t_fixups },
- { "s25hs02gt", INFO6(0x342b1c, 0x0f0090, 0, 0)
- PARSE_SFDP
- 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
+ {
+ .id = SNOR_ID(0x01, 0x02, 0x12),
+ .name = "s25sl004a",
+ .size = SZ_512K,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x13),
+ .name = "s25sl008a",
+ .size = SZ_1M,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x14),
+ .name = "s25sl016a",
+ .size = SZ_2M,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x15, 0x4d, 0x00),
+ .name = "s25sl032p",
+ .size = SZ_4M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x15),
+ .name = "s25sl032a",
+ .size = SZ_4M,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x16, 0x4d, 0x00),
+ .name = "s25sl064p",
+ .size = SZ_8M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x16),
+ .name = "s25sl064a",
+ .size = SZ_8M,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x19, 0x4d, 0x00, 0x80),
+ .name = "s25fl256s0",
+ .size = SZ_32M,
+ .sector_size = SZ_256K,
+ .no_sfdp_flags = SPI_NOR_SKIP_SFDP | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x19, 0x4d, 0x00, 0x81),
+ .name = "s25fs256s0",
+ .size = SZ_32M,
+ .sector_size = SZ_256K,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x19, 0x4d, 0x01, 0x80),
+ .name = "s25fl256s1",
+ .size = SZ_32M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x19, 0x4d, 0x01, 0x81),
+ .name = "s25fs256s1",
+ .size = SZ_32M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x20, 0x4d, 0x00, 0x80),
+ .name = "s25fl512s",
+ .size = SZ_64M,
+ .sector_size = SZ_256K,
+ .flags = SPI_NOR_HAS_LOCK,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x02, 0x20, 0x4d, 0x00, 0x81),
+ .name = "s25fs512s",
+ .size = SZ_64M,
+ .sector_size = SZ_256K,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ .fixups = &s25fs_s_nor_fixups,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x03, 0x00),
+ .name = "s25sl12800",
+ .size = SZ_16M,
+ .sector_size = SZ_256K,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x03, 0x01),
+ .name = "s25sl12801",
+ .size = SZ_16M,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x4d, 0x00, 0x80),
+ .name = "s25fl128s0",
+ .size = SZ_16M,
+ .sector_size = SZ_256K,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x4d, 0x00),
+ .name = "s25fl129p0",
+ .size = SZ_16M,
+ .sector_size = SZ_256K,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x4d, 0x01, 0x80),
+ .name = "s25fl128s1",
+ .size = SZ_16M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x4d, 0x01, 0x81),
+ .name = "s25fs128s1",
+ .size = SZ_16M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ .fixups = &s25fs_s_nor_fixups,
+ }, {
+ .id = SNOR_ID(0x01, 0x20, 0x18, 0x4d, 0x01),
+ .name = "s25fl129p1",
+ .size = SZ_16M,
+ .no_sfdp_flags = SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .mfr_flags = USE_CLSR,
+ }, {
+ .id = SNOR_ID(0x01, 0x40, 0x13),
+ .name = "s25fl204k",
+ .size = SZ_512K,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ,
+ }, {
+ .id = SNOR_ID(0x01, 0x40, 0x14),
+ .name = "s25fl208k",
+ .size = SZ_1M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ,
+ }, {
+ .id = SNOR_ID(0x01, 0x40, 0x15),
+ .name = "s25fl116k",
+ .size = SZ_2M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0x01, 0x40, 0x16),
+ .name = "s25fl132k",
+ .size = SZ_4M,
+ .no_sfdp_flags = SECT_4K,
+ }, {
+ .id = SNOR_ID(0x01, 0x40, 0x17),
+ .name = "s25fl164k",
+ .size = SZ_8M,
+ .no_sfdp_flags = SECT_4K,
+ }, {
+ .id = SNOR_ID(0x01, 0x60, 0x17),
+ .name = "s25fl064l",
+ .size = SZ_8M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .fixup_flags = SPI_NOR_4B_OPCODES,
+ }, {
+ .id = SNOR_ID(0x01, 0x60, 0x18),
+ .name = "s25fl128l",
+ .size = SZ_16M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .fixup_flags = SPI_NOR_4B_OPCODES,
+ }, {
+ .id = SNOR_ID(0x01, 0x60, 0x19),
+ .name = "s25fl256l",
+ .size = SZ_32M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ .fixup_flags = SPI_NOR_4B_OPCODES,
+ }, {
+ .id = SNOR_ID(0x04, 0x2c, 0xc2, 0x7f, 0x7f, 0x7f),
+ .name = "cy15x104q",
+ .size = SZ_512K,
+ .sector_size = SZ_512K,
+ .flags = SPI_NOR_NO_ERASE,
+ }, {
+ .id = SNOR_ID(0x34, 0x2a, 0x1a, 0x0f, 0x03, 0x90),
+ .name = "s25hl512t",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2a, 0x1b, 0x0f, 0x03, 0x90),
+ .name = "s25hl01gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2a, 0x1c, 0x0f, 0x00, 0x90),
+ .name = "s25hl02gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2b, 0x19, 0x0f, 0x08, 0x90),
+ .name = "s25fs256t",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25fs256t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2b, 0x1a, 0x0f, 0x03, 0x90),
+ .name = "s25hs512t",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2b, 0x1b, 0x0f, 0x03, 0x90),
+ .name = "s25hs01gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ .id = SNOR_ID(0x34, 0x2b, 0x1c, 0x0f, 0x00, 0x90),
+ .name = "s25hs02gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s25hx_t_fixups
+ }, {
+ /* S28HL256T */
+ .id = SNOR_ID(0x34, 0x5a, 0x19),
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s28hx_t_fixups,
+ }, {
+ .id = SNOR_ID(0x34, 0x5a, 0x1a),
+ .name = "s28hl512t",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s28hx_t_fixups,
+ }, {
+ .id = SNOR_ID(0x34, 0x5a, 0x1b),
+ .name = "s28hl01gt",
+ .mfr_flags = USE_CLPEF,
.fixups = &s28hx_t_fixups,
- },
- { "s28hl01gt", INFO(0x345a1b, 0, 256 * 1024, 512)
- PARSE_SFDP
+ }, {
+ /* S28HL02GT */
+ .id = SNOR_ID(0x34, 0x5a, 0x1c),
+ .mfr_flags = USE_CLPEF,
.fixups = &s28hx_t_fixups,
- },
- { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
- PARSE_SFDP
+ }, {
+ .id = SNOR_ID(0x34, 0x5b, 0x19),
+ .mfr_flags = USE_CLPEF,
.fixups = &s28hx_t_fixups,
- },
- { "s28hs01gt", INFO(0x345b1b, 0, 256 * 1024, 512)
- PARSE_SFDP
+ }, {
+ .id = SNOR_ID(0x34, 0x5b, 0x1a),
+ .name = "s28hs512t",
+ .mfr_flags = USE_CLPEF,
.fixups = &s28hx_t_fixups,
- },
+ }, {
+ .id = SNOR_ID(0x34, 0x5b, 0x1b),
+ .name = "s28hs01gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s28hx_t_fixups,
+ }, {
+ .id = SNOR_ID(0x34, 0x5b, 0x1c),
+ .name = "s28hs02gt",
+ .mfr_flags = USE_CLPEF,
+ .fixups = &s28hx_t_fixups,
+ }, {
+ .id = SNOR_ID(0xef, 0x40, 0x13),
+ .name = "s25fl004k",
+ .size = SZ_512K,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0xef, 0x40, 0x14),
+ .name = "s25fl008k",
+ .size = SZ_1M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0xef, 0x40, 0x15),
+ .name = "s25fl016k",
+ .size = SZ_2M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }, {
+ .id = SNOR_ID(0xef, 0x40, 0x17),
+ .name = "s25fl064k",
+ .size = SZ_8M,
+ .no_sfdp_flags = SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ,
+ }
};
/**
@@ -876,17 +1127,36 @@ 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;
+ nor->mtd.erasesize = nor->info->sector_size ?:
+ SPI_NOR_DEFAULT_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 = {