[U-Boot] [PATCH 16/18] sf: fix support of Micron memories
Cyrille Pitchen
cyrille.pitchen at atmel.com
Tue Mar 15 19:12:38 CET 2016
This patch provides support of Micron QSPI memories.
Signed-off-by: Cyrille Pitchen <cyrille.pitchen at atmel.com>
---
drivers/mtd/spi/Makefile | 1 +
drivers/mtd/spi/sf_internal.h | 24 +++++
drivers/mtd/spi/sf_micron.c | 222 ++++++++++++++++++++++++++++++++++++++++++
drivers/mtd/spi/spi_flash.c | 13 +--
4 files changed, 251 insertions(+), 9 deletions(-)
create mode 100644 drivers/mtd/spi/sf_micron.c
diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index c665836f9560..90266d619ddf 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_SPL_SPI_BOOT) += fsl_espi_spl.o
endif
obj-$(CONFIG_SPI_FLASH) += sf_probe.o spi_flash.o sf_params.o sf.o
+obj-$(CONFIG_SPI_FLASH_STMICRO) += sf_micron.o
obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o
obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o
obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o
diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index a98c011218ce..afee8b69ca6b 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -142,6 +142,24 @@ enum spi_nor_option_flags {
# define CMD_SST_AAI_WP 0xAD /* Auto Address Incr Word Program */
#endif
+/* Micron specific */
+#ifdef CONFIG_SPI_FLASH_STMICRO
+
+/* Volatile Configuration Register (VCR) */
+#define CMD_MICRON_WR_VCR 0x81
+#define CMD_MICRON_RD_VCR 0x85
+#define MICRON_VCR_XIP BIT(3)
+#define MICRON_VCR_DUMMIES 0xf0
+#define MICRON_VCR_DUMMIES_(x) (((x) << 4) & MICRON_VCR_DUMMIES)
+
+/* Enhanced Volatile Configuraiton Register (EVCR) */
+#define CMD_MICRON_WR_EVCR 0x61
+#define CMD_MICRON_RD_EVCR 0x65
+#define MICRON_EVCR_QUAD_DIS BIT(7)
+#define MICRON_EVCR_DUAL_DIS BIT(6)
+#endif
+
+
/**
* struct spi_flash_params - SPI/QSPI flash device params structure
*
@@ -264,6 +282,12 @@ int spi_flash_mtd_register(struct spi_flash *flash);
void spi_flash_mtd_unregister(void);
#endif
+#ifdef CONFIG_SPI_FLASH_STMICRO
+int spi_flash_setup_micron(struct spi_flash *flash,
+ const struct spi_flash_params *params,
+ int best_match);
+#endif
+
/**
* spi_flash_scan - scan the SPI FLASH
* @flash: the spi flash structure
diff --git a/drivers/mtd/spi/sf_micron.c b/drivers/mtd/spi/sf_micron.c
new file mode 100644
index 000000000000..b399b6ff52fe
--- /dev/null
+++ b/drivers/mtd/spi/sf_micron.c
@@ -0,0 +1,222 @@
+/*
+ * Micron SPI NOR flash support
+ *
+ * Copyright (C) 2016 Cyrille Pitchen <cyrille.pitchen at atmel.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "sf_internal.h"
+
+static int spi_flash_micron_set_dummy_cycles(struct spi_flash *flash,
+ u8 num_dummy_cycles)
+{
+ u8 vcr, mask, value;
+ int ret;
+
+ /* Set the number of dummy cycles and disable XIP */
+ mask = (MICRON_VCR_DUMMIES | MICRON_VCR_XIP);
+ value = MICRON_VCR_DUMMIES_(num_dummy_cycles) | MICRON_VCR_XIP;
+
+ /* Check current VCR value */
+ ret = spi_flash_read_reg(flash, CMD_MICRON_RD_VCR, 1, &vcr);
+ if (ret)
+ goto end;
+
+ if ((vcr & mask) == value)
+ goto end;
+
+ /* VCR update is needed */
+ vcr = (vcr & ~mask) | value;
+ ret = spi_flash_update_reg(flash, CMD_MICRON_WR_VCR, 1, &vcr);
+ if (ret)
+ goto end;
+
+ /* Verify update */
+ ret = spi_flash_read_reg(flash, CMD_MICRON_RD_VCR, 1, &vcr);
+ if (ret)
+ goto end;
+
+ if ((vcr & mask) != value)
+ ret = -EIO;
+
+end:
+ if (ret)
+ printf("SF: failed to set the dummy cycles on Micron memory!\n");
+
+ return ret;
+}
+
+static int spi_flash_micron_set_protocol(struct spi_flash *flash,
+ enum spi_flash_protocol proto,
+ u8 mask, u8 value)
+{
+ u8 evcr;
+ int ret;
+
+ /* Check current EVCR value */
+ ret = spi_flash_read_reg(flash, CMD_MICRON_RD_EVCR, 1, &evcr);
+ if (ret)
+ goto end;
+
+ if ((evcr & mask) == value)
+ goto end;
+
+ /* EVCR update is needed */
+ ret = spi_flash_cmd_write_enable(flash);
+ if (ret)
+ goto end;
+
+ evcr = (evcr & ~mask) | value;
+ ret = spi_flash_write_reg(flash, CMD_MICRON_WR_EVCR, 1, &evcr);
+ if (ret)
+ goto end;
+
+ /*
+ * Don't forget to update the protocol HERE otherwise next commands
+ * will fail.
+ */
+ flash->reg_proto = proto;
+
+ /* Wait for ready status */
+ ret = spi_flash_wait_ready(flash);
+ if (ret)
+ goto end;
+
+ /* Verify update */
+ ret = spi_flash_read_reg(flash, CMD_MICRON_RD_EVCR, 1, &evcr);
+ if (ret)
+ goto end;
+
+ if ((evcr & mask) != value)
+ ret = -EIO;
+
+end:
+ if (ret) {
+ printf("SF: failed to set I/O mode on Micron memory!\n");
+ return ret;
+ }
+
+ flash->read_proto = proto;
+ flash->write_proto = proto;
+ flash->erase_proto = proto;
+ return 0;
+}
+
+static inline int spi_flash_micron_set_ext_spi_mode(struct spi_flash *flash)
+{
+ enum spi_flash_protocol proto = SPI_FLASH_PROTO_1_1_1;
+ u8 mask = (MICRON_EVCR_QUAD_DIS | MICRON_EVCR_DUAL_DIS);
+ u8 value = mask;
+
+ return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+static inline int spi_flash_micron_set_dual_mode(struct spi_flash *flash)
+{
+ enum spi_flash_protocol proto = SPI_FLASH_PROTO_2_2_2;
+ u8 mask = (MICRON_EVCR_QUAD_DIS | MICRON_EVCR_DUAL_DIS);
+ u8 value = MICRON_EVCR_QUAD_DIS;
+
+ return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+static inline int spi_flash_micron_set_quad_mode(struct spi_flash *flash)
+{
+ enum spi_flash_protocol proto = SPI_FLASH_PROTO_4_4_4;
+ u8 mask = MICRON_EVCR_QUAD_DIS;
+ u8 value = 0;
+
+ return spi_flash_micron_set_protocol(flash, proto, mask, value);
+}
+
+int spi_flash_setup_micron(struct spi_flash *flash,
+ const struct spi_flash_params *params,
+ int best_match)
+{
+ u16 read_cmd = best_match ? (1 << (best_match - 1)) : ARRAY_FAST;
+ u8 dummy_cycles = (read_cmd == ARRAY_SLOW) ? 0 : 8;
+ int ret = 0;
+
+ /* Configure (Fast) Read operations */
+ switch (read_cmd) {
+ case QUAD_CMD_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_4_4_4)
+ ret = spi_flash_micron_set_quad_mode(flash);
+ flash->read_cmd = CMD_READ_QUAD_IO_FAST;
+ break;
+
+ case QUAD_IO_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+ ret = spi_flash_micron_set_ext_spi_mode(flash);
+ flash->read_proto = SPI_FLASH_PROTO_1_4_4;
+ flash->read_cmd = CMD_READ_QUAD_IO_FAST;
+ break;
+
+ case QUAD_OUTPUT_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+ ret = spi_flash_micron_set_ext_spi_mode(flash);
+ flash->read_proto = SPI_FLASH_PROTO_1_1_4;
+ flash->read_cmd = CMD_READ_QUAD_OUTPUT_FAST;
+ break;
+
+ case DUAL_CMD_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_2_2_2)
+ ret = spi_flash_micron_set_dual_mode(flash);
+ flash->read_cmd = CMD_READ_DUAL_IO_FAST;
+ break;
+
+ case DUAL_IO_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+ ret = spi_flash_micron_set_ext_spi_mode(flash);
+ flash->read_proto = SPI_FLASH_PROTO_1_2_2;
+ flash->read_cmd = CMD_READ_DUAL_IO_FAST;
+ break;
+
+ case DUAL_OUTPUT_FAST:
+ if (flash->reg_proto != SPI_FLASH_PROTO_1_1_1)
+ ret = spi_flash_micron_set_ext_spi_mode(flash);
+ flash->read_proto = SPI_FLASH_PROTO_1_1_2;
+ flash->read_cmd = CMD_READ_DUAL_OUTPUT_FAST;
+ break;
+
+ case ARRAY_FAST:
+ flash->read_proto = SPI_FLASH_PROTO_1_1_1;
+ flash->read_cmd = CMD_READ_ARRAY_FAST;
+ break;
+
+ case ARRAY_SLOW:
+ flash->read_proto = SPI_FLASH_PROTO_1_1_1;
+ flash->read_cmd = CMD_READ_ARRAY_SLOW;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ /* Configure Page Program operations */
+ if (flash->write_proto == SPI_FLASH_PROTO_4_4_4 ||
+ flash->write_proto == SPI_FLASH_PROTO_2_2_2) {
+ flash->write_cmd = CMD_PAGE_PROGRAM;
+ } else if ((flash->spi->mode & SPI_TX_QUAD) &&
+ (params->flags & WR_QPP)) {
+ flash->write_cmd = CMD_QUAD_PAGE_PROGRAM;
+ flash->write_proto = SPI_FLASH_PROTO_1_1_4;
+ } else {
+ flash->write_cmd = CMD_PAGE_PROGRAM;
+ flash->write_proto = SPI_FLASH_PROTO_1_1_1;
+ }
+
+ /* Set number of dummy cycles for Fast Read operations */
+ if (params->e_rd_cmd & (QUAD_CMD_FAST | DUAL_CMD_FAST))
+ ret = spi_flash_micron_set_dummy_cycles(flash, dummy_cycles);
+ return ret ? : spi_flash_set_dummy_byte(flash, dummy_cycles);
+}
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 50250491d228..922afc811a0b 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -1022,11 +1022,6 @@ static int set_quad_mode(struct spi_flash *flash, u8 idcode0)
case SPI_FLASH_CFI_MFR_WINBOND:
return spansion_quad_enable(flash);
#endif
-#ifdef CONFIG_SPI_FLASH_STMICRO
- case SPI_FLASH_CFI_MFR_STMICRO:
- debug("SF: QEB is volatile for %02x flash\n", idcode0);
- return 0;
-#endif
default:
printf("SF: Need set QEB func for %02x flash\n", idcode0);
return -1;
@@ -1113,10 +1108,10 @@ static int spi_flash_setup(struct spi_flash *flash,
* manufacturer.
*/
switch (params->jedec >> 16) {
- /*
- * TODO: Manufacturer dedicated setup will be added HERE by
- * further patches.
- */
+#ifdef CONFIG_SPI_FLASH_STMICRO
+ case SPI_FLASH_CFI_MFR_STMICRO:
+ return spi_flash_setup_micron(flash, params, match);
+#endif
default:
return spi_flash_setup_deprecated(flash, params, match);
--
1.8.2.2
More information about the U-Boot
mailing list