All of lore.kernel.org
 help / color / mirror / Atom feed
From: Cyrille Pitchen <cyrille.pitchen@atmel.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 16/18] sf: fix support of Micron memories
Date: Tue, 15 Mar 2016 19:12:38 +0100	[thread overview]
Message-ID: <be87afa9fa67149baf5753864d11b82125ea8c18.1458063638.git.cyrille.pitchen@atmel.com> (raw)
In-Reply-To: <cover.1458063638.git.cyrille.pitchen@atmel.com>

This patch provides support of Micron QSPI memories.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@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@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

  parent reply	other threads:[~2016-03-15 18:12 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-15 18:12 [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 01/18] Revert "sf: Fix quad bit set for micron devices" Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 02/18] sf: call spi_claim_bus() and spi_release_bus() only once per read, write or erase Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 03/18] sf: replace spi_flash_read_common() calls by spi_flash_cmd_read() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 04/18] sf: remove spi_flash_write_common() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 05/18] sf: export spi_flash_wait_ready() function Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 06/18] sf: share erase generic algorithm Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 07/18] sf: share write " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 08/18] sf: share read " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 09/18] sf: add hooks to handle register read and write operations Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 10/18] sf: move support of SST flash into generic spi_flash_write_alg() Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 11/18] sf: fix selection of supported READ commands for QSPI memories Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 12/18] sf: fix detection of QSPI memories when they boot in Quad or Dual mode Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 13/18] sf: add helper function to set the number of dummy bytes Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 14/18] sf: add 4byte address opcodes Cyrille Pitchen
2016-03-21  8:58   ` [U-Boot] [PATCH 14/18 v2] " Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 15/18] sf: prepare next fixes to support of QSPI memories by manufacturer Cyrille Pitchen
2016-03-15 18:12 ` Cyrille Pitchen [this message]
2016-03-15 18:12 ` [U-Boot] [PATCH 17/18] ARM: at91: clock: add function to get QSPI clocks Cyrille Pitchen
2016-03-15 18:12 ` [U-Boot] [PATCH 18/18] sf: add driver for Atmel QSPI controller Cyrille Pitchen
2016-03-15 18:21 ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Jagan Teki
2016-03-15 19:17   ` Marek Vasut
2016-03-16 13:30   ` Cyrille Pitchen
2016-03-16 14:14     ` Jagan Teki
2016-03-16 16:23       ` Albert ARIBAUD
2016-03-16 16:34         ` Jagan Teki
2016-03-17  7:30           ` Albert ARIBAUD
2016-03-16 16:30       ` Cyrille Pitchen
2016-03-16 16:41         ` [U-Boot] [PATCH 1/4] rework board config files Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 2/4] sama5d2_xplained: add support of QSPI controllers Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 3/4] dts: add dts file for Atmel sama5d2 xplained board Cyrille Pitchen
2016-03-16 16:41           ` [U-Boot] [PATCH 4/4] sf: fix sf probe Cyrille Pitchen
2016-03-18 13:48       ` [U-Boot] [PATCH 00/18] sf: fix support of QSPI memories and controllers Stefan Roese
2016-03-18 15:18         ` Cyrille Pitchen
2016-03-21  9:07           ` Jagan Teki
2016-03-21 13:13             ` Cyrille Pitchen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=be87afa9fa67149baf5753864d11b82125ea8c18.1458063638.git.cyrille.pitchen@atmel.com \
    --to=cyrille.pitchen@atmel.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.