@@ -900,27 +900,110 @@ write_err:
return ret;
}
-static int macronix_quad_enable(struct spi_nor *nor)
+static int macronix_set_qpi_mode(struct spi_nor *nor, bool enable)
{
- int ret, val;
+ int sr, mask, qpi_bit;
+
+ mask = SR_QUAD_EN_MX;
+ qpi_bit = (enable) ? SR_QUAD_EN_MX : 0;
+
+ sr = read_sr(nor);
+ if ((sr & mask) == qpi_bit)
+ return 0;
- val = read_sr(nor);
write_enable(nor);
+ write_sr(nor, (sr & ~mask) | qpi_bit);
- write_sr(nor, val | SR_QUAD_EN_MX);
+ /* Set the reg protocol now before accessing any other register. */
+ nor->reg_proto = (enable) ? SPI_PROTO_4_4_4 : SPI_PROTO_1_1_1;
- if (spi_nor_wait_till_ready(nor))
+ if (spi_nor_wait_till_ready(nor)) {
+ dev_err(nor->dev, "Failed to %s the QPI mode.\n",
+ enable ? "enable" : "disable");
return 1;
+ }
- ret = read_sr(nor);
- if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
- dev_err(nor->dev, "Macronix Quad bit not set\n");
+ sr = read_sr(nor);
+ if (!(sr > 0 && ((sr & mask) != qpi_bit))) {
+ dev_err(nor->dev, "Macronix Quad bit was not %s.\n",
+ enable ? "set" : "cleared");
return -EINVAL;
}
return 0;
}
+static int macronix_set_quad_io(struct spi_nor *nor)
+{
+ /* Enable the QPI mode if not done yet. */
+ if (macronix_set_qpi_mode(nor, true))
+ return -EINVAL;
+
+ /* Use SPI 4-4-4 protocol for all commands. */
+ nor->read_proto = SPI_PROTO_4_4_4;
+ nor->write_proto = SPI_PROTO_4_4_4;
+ nor->erase_proto = SPI_PROTO_4_4_4;
+
+ /*
+ * The Fast Read Quad Output 1-1-4 command (0x6b) command is not
+ * supported in QPI mode, use the Fast Read Quad I/O 1-4-4 (0xeb)
+ * instead.
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_4_4;
+
+ return 0;
+}
+
+static int macronix_set_quad_output(struct spi_nor *nor)
+{
+ /* Disable the QPI mode if not done yet. */
+ if (macronix_set_qpi_mode(nor, false))
+ return -EINVAL;
+
+ /* Use the Fast Read Quad Output 1-1-4 command. */
+ nor->read_proto = SPI_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+ return 0;
+}
+
+static int macronix_set_dual_io(struct spi_nor *nor)
+{
+ /* Disable the QPI mode if not done yet. */
+ if (macronix_set_qpi_mode(nor, false))
+ return -EINVAL;
+
+ /* Use the Fast Read Dual I/O 1-2-2 command. */
+ nor->read_proto = SPI_PROTO_1_2_2;
+ nor->read_opcode = SPINOR_OP_READ_1_2_2;
+
+ return 0;
+}
+
+static int macronix_set_dual_output(struct spi_nor *nor)
+{
+ /* Disable the QPI mode if not done yet. */
+ if (macronix_set_qpi_mode(nor, false))
+ return -EINVAL;
+
+ /* Use the Fast Read Dual Output 1-1-2 command. */
+ nor->read_proto = SPI_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+ return 0;
+}
+
+static int macronix_set_single(struct spi_nor *nor)
+{
+ /* Disable the QPI mode if not done yet. */
+ if (macronix_set_qpi_mode(nor, false))
+ return -EINVAL;
+
+ nor->read_proto = SPI_PROTO_1_1_1;
+
+ return 0;
+}
+
/*
* Write status Register and configuration register with 2 bytes
* The first byte will be written to the status register, while the
@@ -935,96 +1018,416 @@ static int write_sr_cr(struct spi_nor *nor, u16 val)
return nor->write_reg(nor, SPINOR_OP_WRSR, nor->cmd_buf, 2);
}
-static int spansion_quad_enable(struct spi_nor *nor)
+static int spansion_write_cr(struct spi_nor *nor, bool quad_mode, u8 lc)
{
- int ret;
- int quad_en = CR_QUAD_EN_SPAN << 8;
+ int cr, mask, value;
- write_enable(nor);
+ mask = CR_QUAD_EN_SPAN | CR_LC_MASK;
+ value = (lc << 6) & CR_LC_MASK;
+ if (quad_mode)
+ value |= CR_QUAD_EN_SPAN;
- ret = write_sr_cr(nor, quad_en);
- if (ret < 0) {
+ /* Read the control register */
+ cr = read_cr(nor);
+ if (cr < 0) {
+ dev_err(nor->dev,
+ "error while reading configuration register\n");
+ return -EINVAL;
+ }
+
+ /* Check whether the Quad bit and the Latency Code need to be updated */
+ if ((cr & mask) == value)
+ return 0;
+
+ /* Update the configuration register. */
+ cr = (cr & ~mask) | value;
+ write_enable(nor);
+ if (write_sr_cr(nor, cr << 8) < 0) {
dev_err(nor->dev,
"error while writing configuration register\n");
return -EINVAL;
}
/* read back and check it */
- ret = read_cr(nor);
- if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
- dev_err(nor->dev, "Spansion Quad bit not set\n");
+ cr = read_cr(nor);
+ if (!(cr > 0 && ((cr & mask) == value))) {
+ dev_err(nor->dev,
+ "error while updating configuration register\n");
return -EINVAL;
}
return 0;
}
-static int micron_quad_enable(struct spi_nor *nor)
+static int spansion_set_quad_output(struct spi_nor *nor)
+{
+ int ret;
+
+ /*
+ * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+ * processing a Fast Read Quad Output 1-1-4 command.
+ */
+ ret = spansion_write_cr(nor, true, 0);
+ if (ret)
+ return ret;
+
+ /* Use the Fast Read Quad Output 1-1-4 command. */
+ nor->read_proto = SPI_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+ return 0;
+}
+
+static int spansion_set_dual_output(struct spi_nor *nor)
+{
+ int ret;
+
+ /*
+ * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+ * processing a Fast Read Dual Output 1-1-2 command.
+ */
+ ret = spansion_write_cr(nor, false, 0);
+ if (ret)
+ return ret;
+
+ /* Use the Fast Read Dual Output 1-1-2 command. */
+ nor->read_proto = SPI_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+ return 0;
+}
+
+static int spansion_set_single(struct spi_nor *nor)
{
int ret;
- u8 val;
- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+ /*
+ * Set the Latency Code to 0 so the memory expects 8 dummy cycles when
+ * processing a Fast Read 1-1-1 command. The Latency Code is not
+ * relevant for Read command since no dummy cycle is expected.
+ */
+ ret = spansion_write_cr(nor, false, 0);
+ if (ret)
+ return ret;
+
+ nor->read_proto = SPI_PROTO_1_1_1;
+
+ return 0;
+}
+
+static int micron_set_dummy_cycles(struct spi_nor *nor, u8 num_dummy_cycles)
+{
+ u8 vcr, val, mask;
+ int ret;
+
+ mask = GENMASK(7, 4);
+ val = (num_dummy_cycles << 4) & mask;
+
+ /* Read the Volatile Configuration Register (VCR). */
+ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
if (ret < 0) {
- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+ dev_err(nor->dev, "error while reading VCR register\n");
return ret;
}
+ /* Check whether we need to update the number of dummy cycles. */
+ if ((vcr & mask) == val)
+ return 0;
+
+ /* Update the number of dummy into the VCR. */
write_enable(nor);
+ vcr = (vcr & ~mask) | val;
+ ret = nor->write_reg(nor, SPINOR_OP_WR_VCR, &vcr, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while writing VCR register\n");
+ return ret;
+ }
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
- /* set EVCR, enable quad I/O */
- nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
- ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1);
+ /* Read VCR and check it. */
+ ret = nor->read_reg(nor, SPINOR_OP_RD_VCR, &vcr, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while reading VCR\n");
+ return ret;
+ }
+ if ((vcr & mask) != val) {
+ dev_err(nor->dev, "Micron VCR dummy cycles not updated\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int micron_set_protocol(struct spi_nor *nor, u8 val,
+ enum spi_protocol proto)
+{
+ u8 evcr, mask;
+ int ret;
+
+ mask = EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON;
+
+ /* Read the Exhanced Volatile Configuration Register (EVCR). */
+ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while reading EVCR register\n");
+ return ret;
+ }
+
+ /* Check whether we need to update the protocol bits. */
+ if ((evcr & mask) == val)
+ return 0;
+
+ /* Set EVCR protocol bits. */
+ write_enable(nor);
+ evcr = (evcr & ~mask) | val;
+ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, &evcr, 1);
if (ret < 0) {
dev_err(nor->dev, "error while writing EVCR register\n");
return ret;
}
+ /* Switch reg protocol now before accessing any other registers. */
+ nor->reg_proto = proto;
+
ret = spi_nor_wait_till_ready(nor);
if (ret)
return ret;
- /* read EVCR and check it */
- ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+ /* Read EVCR and check it. */
+ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &evcr, 1);
if (ret < 0) {
- dev_err(nor->dev, "error %d reading EVCR\n", ret);
+ dev_err(nor->dev, "error while reading EVCR\n");
return ret;
}
- if (val & EVCR_QUAD_EN_MICRON) {
- dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+ if ((evcr & mask) != val) {
+ dev_err(nor->dev, "Micron EVCR protocol bits not updated\n");
return -EINVAL;
}
return 0;
}
-static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info)
+static inline int micron_set_extended_spi_protocol(struct spi_nor *nor)
{
- int status;
+ int ret;
+ /* Set both the Quad and Dual bits to select the Extended SPI mode */
+ ret = micron_set_protocol(nor,
+ EVCR_QUAD_EN_MICRON | EVCR_DUAL_EN_MICRON,
+ SPI_PROTO_1_1_1);
+ if (ret) {
+ dev_err(nor->dev, "Failed to set Micron Extended SPI mode\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int micron_set_quad_io(struct spi_nor *nor)
+{
+ int ret;
+
+ /* Clear at least the Quad bit to enable quad mode */
+ ret = micron_set_protocol(nor,
+ EVCR_DUAL_EN_MICRON,
+ SPI_PROTO_4_4_4);
+ if (ret) {
+ dev_err(nor->dev, "Failed to set Micron Quad mode\n");
+ return ret;
+ }
+
+ /* Force the number of dummy cycles to 8 */
+ ret = micron_set_dummy_cycles(nor, 8);
+ if (ret)
+ return ret;
+
+ /* Use SPI 4-4-4 protocol for all commands. */
+ nor->read_proto = SPI_PROTO_4_4_4;
+ nor->write_proto = SPI_PROTO_4_4_4;
+ nor->erase_proto = SPI_PROTO_4_4_4;
+
+ /*
+ * The Fast Read Quad Output 1-1-4 command (0x6b) is processed with
+ * SPI 4-4-4 protocol.
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+ return 0;
+}
+
+static int micron_set_quad_output(struct spi_nor *nor)
+{
+ int ret;
+
+ ret = micron_set_extended_spi_protocol(nor);
+ if (ret)
+ return ret;
+
+ /* Force the number of dummy cycles to 8 */
+ ret = micron_set_dummy_cycles(nor, 8);
+ if (ret)
+ return ret;
+
+ /* Use the Fast Read Quad Output 1-1-4 command. */
+ nor->read_proto = SPI_PROTO_1_1_4;
+ nor->read_opcode = SPINOR_OP_READ_1_1_4;
+
+ return 0;
+}
+
+static int micron_set_dual_io(struct spi_nor *nor)
+{
+ int ret;
+
+ /* Clear Dual bit but keep Quad bit set to enable dual mode */
+ ret = micron_set_protocol(nor,
+ EVCR_QUAD_EN_MICRON,
+ SPI_PROTO_2_2_2);
+ if (ret) {
+ dev_err(nor->dev, "Failed to set Micron Dual mode\n");
+ return ret;
+ }
+
+ /* Force the number of dummy cycles to 8 */
+ ret = micron_set_dummy_cycles(nor, 8);
+ if (ret)
+ return ret;
+
+ /* Use SPI 2-2-2 protocol for all commands. */
+ nor->read_proto = SPI_PROTO_2_2_2;
+ nor->write_proto = SPI_PROTO_2_2_2;
+ nor->erase_proto = SPI_PROTO_2_2_2;
+
+ /*
+ * The Fast Read Dual Output 1-1-2 command (0x3b) is processed with
+ * SPI 2-2-2 protocol.
+ */
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+ return 0;
+}
+
+static int micron_set_dual_output(struct spi_nor *nor)
+{
+ int ret;
+
+ ret = micron_set_extended_spi_protocol(nor);
+ if (ret)
+ return ret;
+
+ /* Force the number of dummy cycles to 8 */
+ ret = micron_set_dummy_cycles(nor, 8);
+ if (ret)
+ return ret;
+
+ /* Use the Fast Read Dual Output 1-1-4 command. */
+ nor->read_proto = SPI_PROTO_1_1_2;
+ nor->read_opcode = SPINOR_OP_READ_1_1_2;
+
+ return 0;
+}
+
+static int micron_set_single(struct spi_nor *nor)
+{
+ int ret;
+
+ ret = micron_set_extended_spi_protocol(nor);
+ if (ret)
+ return ret;
+
+ /* Force the number of dummy cycles to 8 (Fast Read only) */
+ ret = micron_set_dummy_cycles(nor, 8);
+ if (ret)
+ return ret;
+
+ nor->read_proto = SPI_PROTO_1_1_1;
+
+ return 0;
+}
+
+static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info,
+ u16 mode)
+{
switch (JEDEC_MFR(info)) {
case CFI_MFR_MACRONIX:
- status = macronix_quad_enable(nor);
- if (status) {
- dev_err(nor->dev, "Macronix quad-read not enabled\n");
- return -EINVAL;
- }
- return status;
+ if (mode & SPI_TX_QUAD)
+ return macronix_set_quad_io(nor);
+ return macronix_set_quad_output(nor);
+
case CFI_MFR_ST:
- status = micron_quad_enable(nor);
- if (status) {
- dev_err(nor->dev, "Micron quad-read not enabled\n");
- return -EINVAL;
- }
- return status;
+ if (mode & SPI_TX_QUAD)
+ return micron_set_quad_io(nor);
+ return micron_set_quad_output(nor);
+
+ case CFI_MFR_AMD:
+ /*
+ * Don't use the Fast Read Quad I/O (0xeb / 0xec) commands as
+ * their number of dummy cycles is not a multiple of 8. Some
+ * SPI controllers, especially those relying on the m25p80
+ * driver, expect the number of dummy cycles to be a multiple
+ * of 8.
+ */
+ return spansion_set_quad_output(nor);
+
default:
- status = spansion_quad_enable(nor);
- if (status) {
- dev_err(nor->dev, "Spansion quad-read not enabled\n");
- return -EINVAL;
- }
- return status;
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int set_dual_mode(struct spi_nor *nor, const struct flash_info *info,
+ u16 mode)
+{
+ switch (JEDEC_MFR(info)) {
+ case CFI_MFR_MACRONIX:
+ if (mode & SPI_TX_DUAL)
+ return macronix_set_dual_io(nor);
+ return macronix_set_dual_output(nor);
+
+ case CFI_MFR_ST:
+ if (mode & SPI_TX_DUAL)
+ return micron_set_dual_io(nor);
+ return micron_set_dual_output(nor);
+
+ case CFI_MFR_AMD:
+ /*
+ * Don't use the Fast Read Dual I/O (0xbb / 0xbc) commands as
+ * their number of dummy cycles is not a multiple of 8. Some
+ * SPI controllers, especially those relying on the m25p80
+ * driver, expect the number of dummy cycles to be a multiple
+ * of 8.
+ */
+ return spansion_set_dual_output(nor);
+
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int set_single_mode(struct spi_nor *nor, const struct flash_info *info,
+ u16 mode)
+{
+ switch (JEDEC_MFR(info)) {
+ case CFI_MFR_MACRONIX:
+ return macronix_set_single(nor);
+
+ case CFI_MFR_ST:
+ return micron_set_single(nor);
+
+ case CFI_MFR_AMD:
+ return spansion_set_single(nor);
+
+ default:
+ break;
}
+
+ return -EINVAL;
}
static int spi_nor_check(struct spi_nor *nor)
@@ -1170,39 +1573,38 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, u16 mode)
if (info->flags & SPI_NOR_NO_FR)
nor->flash_read = SPI_NOR_NORMAL;
+ /* Default commands */
+ nor->program_opcode = SPINOR_OP_PP;
+ if (nor->flash_read == SPI_NOR_NORMAL)
+ nor->read_opcode = SPINOR_OP_READ;
+ else
+ nor->read_opcode = SPINOR_OP_READ_FAST;
+
/* Quad/Dual-read mode takes precedence over fast/normal */
if (mode & SPI_RX_QUAD && info->flags & SPI_NOR_QUAD_READ) {
- ret = set_quad_mode(nor, info);
+ /* At least SPI 1-1-4 should be supported */
+ ret = set_quad_mode(nor, info, mode);
if (ret) {
dev_err(dev, "quad mode not supported\n");
return ret;
}
nor->flash_read = SPI_NOR_QUAD;
} else if (mode & SPI_RX_DUAL && info->flags & SPI_NOR_DUAL_READ) {
+ /* At lest SPI 1-1-2 should be supported */
+ ret = set_dual_mode(nor, info, mode);
+ if (ret) {
+ dev_err(dev, "dual mode not supported\n");
+ return ret;
+ }
nor->flash_read = SPI_NOR_DUAL;
+ } else if (info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) {
+ ret = set_single_mode(nor, info, mode);
+ if (ret) {
+ dev_err(dev, "failed to switch back to single mode\n");
+ return ret;
+ }
}
- /* Default commands */
- switch (nor->flash_read) {
- case SPI_NOR_QUAD:
- nor->read_opcode = SPINOR_OP_READ_1_1_4;
- break;
- case SPI_NOR_DUAL:
- nor->read_opcode = SPINOR_OP_READ_1_1_2;
- break;
- case SPI_NOR_FAST:
- nor->read_opcode = SPINOR_OP_READ_FAST;
- break;
- case SPI_NOR_NORMAL:
- nor->read_opcode = SPINOR_OP_READ;
- break;
- default:
- dev_err(dev, "No Read opcode defined\n");
- return -EINVAL;
- }
-
- nor->program_opcode = SPINOR_OP_PP;
-
if (info->addr_width)
nor->addr_width = info->addr_width;
else if (mtd->size > 0x1000000) {
@@ -24,8 +24,10 @@
#define SPINOR_OP_WRSR 0x01 /* Write status register 1 byte */
#define SPINOR_OP_READ 0x03 /* Read data bytes (low frequency) */
#define SPINOR_OP_READ_FAST 0x0b /* Read data bytes (high frequency) */
-#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual SPI) */
-#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad SPI) */
+#define SPINOR_OP_READ_1_1_2 0x3b /* Read data bytes (Dual Output SPI) */
+#define SPINOR_OP_READ_1_2_2 0xbb /* Read data bytes (Dual I/O SPI) */
+#define SPINOR_OP_READ_1_1_4 0x6b /* Read data bytes (Quad Out SPI) */
+#define SPINOR_OP_READ_1_4_4 0xeb /* Read data bytes (Quad I/O SPI) */
#define SPINOR_OP_PP 0x02 /* Page program (up to 256 bytes) */
#define SPINOR_OP_BE_4K 0x20 /* Erase 4KiB block */
#define SPINOR_OP_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */
@@ -58,6 +60,8 @@
/* Used for Micron flashes only. */
#define SPINOR_OP_MIO_RDID 0xaf /* Multiple I/O Read JEDEC ID */
+#define SPINOR_OP_RD_VCR 0x85 /* Read VCR register */
+#define SPINOR_OP_WR_VCR 0x81 /* Write VCR register */
#define SPINOR_OP_RD_EVCR 0x65 /* Read EVCR register */
#define SPINOR_OP_WD_EVCR 0x61 /* Write EVCR register */
@@ -74,12 +78,14 @@
/* Enhanced Volatile Configuration Register bits */
#define EVCR_QUAD_EN_MICRON 0x80 /* Micron Quad I/O */
+#define EVCR_DUAL_EN_MICRON 0x40 /* Micron Dual I/O */
/* Flag Status Register bits */
#define FSR_READY 0x80
/* Configuration Register bits. */
#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */
+#define CR_LC_MASK 0xc0 /* Spansion Latency Code */
enum read_mode {
SPI_NOR_NORMAL = 0,
Micron: Once their Quad SPI protocol enabled, Micron spi-nor memories expect all commands to use the SPI 4-4-4 protocol. Also when the Dual SPI protocol is enabled, all commands must use the SPI 2-2-2 protocol. Macronix: When the QPI mode is enabled, all commands must use the SPI 4-4-4 protocol. If the QPI mode is disabled, the Fast Read Dual Output (0x3b) command uses the SPI 1-1-2 protocol whereas other commands use the SPI 1-1-1 protocol. Spansion: When Quad I/O operations are enabled, the Fast Read Quad Output (0x6b / 0x6c) commands use the SPI 1-1-4 protocol. Also when using the Fast Read Dual Output (0x3b / 0x3c) commands, the SPI 1-1-2 protocol must be used. Other commands use the SPI 1-1-1 protocol. Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com> --- drivers/mtd/spi-nor/spi-nor.c | 544 ++++++++++++++++++++++++++++++++++++------ include/linux/mtd/spi-nor.h | 10 +- 2 files changed, 481 insertions(+), 73 deletions(-)