diff mbox

[U-Boot,11/18] sf: fix selection of supported READ commands for QSPI memories

Message ID d9bf08f21ddc01fcd3fbdcc98ac8645d59478675.1458063638.git.cyrille.pitchen@atmel.com
State Deferred
Delegated to: Jagannadha Sutradharudu Teki
Headers show

Commit Message

Cyrille Pitchen March 15, 2016, 6:12 p.m. UTC
It looks odd to compute a logical AND between the e_rd_cmd field of
struct spi_flash_params and the mode_rx field of struct spi_slave.

Indeed, these two fields don't use the same range of values.
mode_rx is limited to SPI_RX_{SLOW, FAST, DUAL, QUAD}. Even completed
with the SPI_TX_{DUAL, QUAD} flags from the mode field, this is not
enough to find out whether the SPI controller driver supports
Fast Read 4-4-4 (Micron, Macronix, Winbond) commands.
With only the SPI_RX_QUAD and the SPI_TX_QUAD, how to make the
difference between Fast Read 1-4-4 and Fast Read 4-4-4 ?

On the other hand, the e_rd_cmd field already provides a more accurate
knowledge of the Fast Read commands supported by the SPI flash memory.

Then this patch provides a safe convertion from mode_rx + mode values
into e_rd_cmd values to be used by the sf_probe.c driver: this driver
never try using the Fast Read 4-4-4 command.
Other drivers will provide an exhaustive list of supported Fast Read
commands.

Hence a more accurate op code is chosen according to both the SPI flash
memory and the SPI controller capabilities.

Please note that we cannot simply extend the SPI_TX_* and SPI_RX_* flags
of the struct spi_slave since they are set according DT properties
shared with Linux: spi-tx-bus-width and spi-rx-bus-width.

These two DT properties don't allow us to make the difference between
the SPI 1-4-4 and SPI 4-4-4 protocols.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
---
 drivers/mtd/spi/sf_internal.h | 14 +++++++++++---
 drivers/mtd/spi/sf_params.c   | 32 ++++++++++++++++----------------
 drivers/mtd/spi/sf_probe.c    | 19 ++++++++++++++++++-
 drivers/mtd/spi/spi_flash.c   |  9 ++++++---
 4 files changed, 51 insertions(+), 23 deletions(-)
diff mbox

Patch

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index c5966fb37ac8..8b8521369e4e 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -29,12 +29,19 @@  enum spi_read_cmds {
 	QUAD_OUTPUT_FAST	= BIT(3),
 	DUAL_IO_FAST		= BIT(4),
 	QUAD_IO_FAST		= BIT(5),
+	DUAL_CMD_FAST		= BIT(6),
+	QUAD_CMD_FAST		= BIT(7),
 };
 
 /* Normal - Extended - Full command set */
 #define RD_NORM		(ARRAY_SLOW | ARRAY_FAST)
-#define RD_EXTN		(RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
-#define RD_FULL		(RD_EXTN | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+#define RD_EXTN		(RD_NORM | DUAL_OUTPUT_FAST)
+#define RD_DUAL		(RD_NORM | DUAL_OUTPUT_FAST | DUAL_IO_FAST)
+#define RD_DCMD		(RD_DUAL | DUAL_CMD_FAST)
+#define RD_QUAD		(RD_NORM | QUAD_OUTPUT_FAST | QUAD_IO_FAST)
+#define RD_QCMD		(RD_QUAD | QUAD_CMD_FAST)
+#define RD_FULL		(RD_DUAL | RD_QUAD)
+#define RD_FCMD		(RD_DCMD | RD_QCMD)
 
 /* sf param flags */
 enum {
@@ -240,6 +247,7 @@  void spi_flash_mtd_unregister(void);
 /**
  * spi_flash_scan - scan the SPI FLASH
  * @flash:	the spi flash structure
+ * @e_rd_cmd:	Enum list for read commands supported by the SPI controller
  *
  * The drivers can use this fuction to scan the SPI FLASH.
  * In the scanning, it will try to get all the necessary information to
@@ -247,6 +255,6 @@  void spi_flash_mtd_unregister(void);
  *
  * Return: 0 for success, others for failure.
  */
-int spi_flash_scan(struct spi_flash *flash);
+int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd);
 
 #endif /* _SF_INTERNAL_H_ */
diff --git a/drivers/mtd/spi/sf_params.c b/drivers/mtd/spi/sf_params.c
index 4f37e33eb068..d3103dbc8742 100644
--- a/drivers/mtd/spi/sf_params.c
+++ b/drivers/mtd/spi/sf_params.c
@@ -47,10 +47,10 @@  const struct spi_flash_params spi_flash_params_table[] = {
 	{"MX25L1605D",	   0xc22015, 0x0,	64 * 1024,    32, RD_NORM,			  0},
 	{"MX25L3205D",	   0xc22016, 0x0,	64 * 1024,    64, RD_NORM,			  0},
 	{"MX25L6405D",	   0xc22017, 0x0,	64 * 1024,   128, RD_NORM,			  0},
-	{"MX25L12805",	   0xc22018, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"MX25L25635F",	   0xc22019, 0x0,	64 * 1024,   512, RD_FULL,		     WR_QPP},
-	{"MX25L51235F",	   0xc2201a, 0x0,	64 * 1024,  1024, RD_FULL,		     WR_QPP},
-	{"MX25L12855E",	   0xc22618, 0x0,	64 * 1024,   256, RD_FULL,		     WR_QPP},
+	{"MX25L12805",	   0xc22018, 0x0,	64 * 1024,   256, RD_QCMD,		     WR_QPP},
+	{"MX25L25635F",	   0xc22019, 0x0,	64 * 1024,   512, RD_QCMD,		     WR_QPP},
+	{"MX25L51235F",	   0xc2201a, 0x0,	64 * 1024,  1024, RD_QCMD,		     WR_QPP},
+	{"MX25L12855E",	   0xc22618, 0x0,	64 * 1024,   256, RD_QCMD,		     WR_QPP},
 #endif
 #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
 	{"S25FL008A",	   0x010213, 0x0,	64 * 1024,    16, RD_NORM,			  0},
@@ -83,18 +83,18 @@  const struct spi_flash_params spi_flash_params_table[] = {
 	{"M25P64",	   0x202017, 0x0,       64 * 1024,   128, RD_NORM,			  0},
 	{"M25P128",	   0x202018, 0x0,      256 * 1024,    64, RD_NORM,			  0},
 	{"M25PX64",	   0x207117, 0x0,       64 * 1024,   128, RD_NORM,		    SECT_4K},
-	{"N25Q32",	   0x20ba16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q32A",	   0x20bb16, 0x0,       64 * 1024,    64, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q64",	   0x20ba17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q64A",	   0x20bb17, 0x0,       64 * 1024,   128, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q128",	   0x20ba18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"N25Q128A",	   0x20bb18, 0x0,       64 * 1024,   256, RD_FULL,		     WR_QPP},
-	{"N25Q256",	   0x20ba19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q256A",	   0x20bb19, 0x0,       64 * 1024,   512, RD_FULL,	   WR_QPP | SECT_4K},
-	{"N25Q512",	   0x20ba20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q512A",	   0x20bb20, 0x0,       64 * 1024,  1024, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q1024",	   0x20ba21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
-	{"N25Q1024A",	   0x20bb21, 0x0,       64 * 1024,  2048, RD_FULL, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q32",	   0x20ba16, 0x0,       64 * 1024,    64, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q32A",	   0x20bb16, 0x0,       64 * 1024,    64, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q64",	   0x20ba17, 0x0,       64 * 1024,   128, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q64A",	   0x20bb17, 0x0,       64 * 1024,   128, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q128",	   0x20ba18, 0x0,       64 * 1024,   256, RD_FCMD,		     WR_QPP},
+	{"N25Q128A",	   0x20bb18, 0x0,       64 * 1024,   256, RD_FCMD,		     WR_QPP},
+	{"N25Q256",	   0x20ba19, 0x0,       64 * 1024,   512, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q256A",	   0x20bb19, 0x0,       64 * 1024,   512, RD_FCMD,	   WR_QPP | SECT_4K},
+	{"N25Q512",	   0x20ba20, 0x0,       64 * 1024,  1024, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q512A",	   0x20bb20, 0x0,       64 * 1024,  1024, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q1024",	   0x20ba21, 0x0,       64 * 1024,  2048, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
+	{"N25Q1024A",	   0x20bb21, 0x0,       64 * 1024,  2048, RD_FCMD, WR_QPP | E_FSR | SECT_4K},
 #endif
 #ifdef CONFIG_SPI_FLASH_SST		/* SST */
 	{"SST25VF040B",	   0xbf258d, 0x0,	64 * 1024,     8, RD_NORM,          SECT_4K | SST_WR},
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 837535fdb7a5..8a0345bc1994 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -26,6 +26,7 @@ 
 static int spi_flash_probe_slave(struct spi_flash *flash)
 {
 	struct spi_slave *spi = flash->spi;
+	u8 mode_rx, e_rd_cmd;
 	int ret;
 
 	/* Setup spi_slave */
@@ -34,6 +35,22 @@  static int spi_flash_probe_slave(struct spi_flash *flash)
 		return -ENODEV;
 	}
 
+	/* Convert SPI mode_rx and mode to SPI flash read commands */
+	mode_rx = spi->mode_rx;
+	if (mode_rx & SPI_RX_QUAD) {
+		e_rd_cmd = RD_NORM | QUAD_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_QUAD)
+			e_rd_cmd |= QUAD_IO_FAST;
+	} else if (mode_rx & SPI_RX_DUAL) {
+		e_rd_cmd = RD_NORM | DUAL_OUTPUT_FAST;
+		if (spi->mode & SPI_TX_DUAL)
+			e_rd_cmd |= DUAL_IO_FAST;
+	} else if ((mode_rx & (SPI_RX_SLOW | SPI_RX_FAST)) == SPI_RX_SLOW) {
+		e_rd_cmd = ARRAY_SLOW;
+	} else {
+		e_rd_cmd = RD_NORM;
+	}
+
 	/* Claim spi bus */
 	ret = spi_claim_bus(spi);
 	if (ret) {
@@ -41,7 +58,7 @@  static int spi_flash_probe_slave(struct spi_flash *flash)
 		return ret;
 	}
 
-	ret = spi_flash_scan(flash);
+	ret = spi_flash_scan(flash, e_rd_cmd);
 	if (ret)
 		goto err_read_id;
 
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c
index 7f5341a87c07..5ba148bd3626 100644
--- a/drivers/mtd/spi/spi_flash.c
+++ b/drivers/mtd/spi/spi_flash.c
@@ -987,7 +987,7 @@  int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash)
 }
 #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
-int spi_flash_scan(struct spi_flash *flash)
+int spi_flash_scan(struct spi_flash *flash, u8 e_rd_cmd)
 {
 	struct spi_slave *spi = flash->spi;
 	const struct spi_flash_params *params;
@@ -1000,7 +1000,10 @@  int spi_flash_scan(struct spi_flash *flash)
 		CMD_READ_DUAL_OUTPUT_FAST,
 		CMD_READ_QUAD_OUTPUT_FAST,
 		CMD_READ_DUAL_IO_FAST,
-		CMD_READ_QUAD_IO_FAST };
+		CMD_READ_QUAD_IO_FAST,
+		CMD_READ_DUAL_IO_FAST,	/* same op code as for DUAL_IO_FAST */
+		CMD_READ_QUAD_IO_FAST,	/* same op code as for QUAD_IO_FAST */
+	};
 
 	/* Assign spi_flash ops */
 #ifndef CONFIG_DM_SPI_FLASH
@@ -1115,7 +1118,7 @@  int spi_flash_scan(struct spi_flash *flash)
 	flash->sector_size = flash->erase_size;
 
 	/* Look for the fastest read cmd */
-	cmd = fls(params->e_rd_cmd & spi->mode_rx);
+	cmd = fls(params->e_rd_cmd & e_rd_cmd);
 	if (cmd) {
 		cmd = spi_read_cmds_array[cmd - 1];
 		flash->read_cmd = cmd;