All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
@ 2020-03-30 15:45 Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 01/17] spi: spi-mem: allow specifying whether an op is DTR or not Pratyush Yadav
                   ` (18 more replies)
  0 siblings, 19 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Hi,

This series adds support for octal DTR flashes in the spi-nor framework,
and then adds hooks for the Cypress Semper flash which is an xSPI
compliant Octal DTR flash.

The Cadence QSPI controller driver is also updated to run in Octal DTR
mode.

Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
u-boot-ti/next.

This series depends on [0].

[0] cf. <20200224071051.19331-1-p.yadav@ti.com>
[0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html

Changes in v3:
- Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
  tripping up controllers.
- Use op->data.nbytes as a measure of whether the data phase exists or
  not. This fixes data buswidth not being updadted for SR and FSR reads
  because they keep data buffer as NULL when calling spi_nor_setup_op().
- Add support for Micron mt35xu512aba to run in Octal DTR mode.

Pratyush Yadav (17):
  spi: spi-mem: allow specifying whether an op is DTR or not
  spi: spi-mem: allow specifying a command's extension
  spi: cadence-qspi: Do not calibrate when device tree sets read delay
  spi: cadence-qspi: Add support for octal DTR flashes
  mtd: spi-nor-core: Add a ->setup() hook
  mtd: spi-nor-core: Move SFDP related declarations to top
  mtd: spi-nor-core: Introduce flash-specific fixup hooks
  mtd: spi-nor-core: Rework hwcaps selection
  mtd: spi-nor-core: Add support for DTR protocol
  mtd: spi-nor-core: Get command opcode extension type from BFPT
  mtd: spi-nor-core: Parse xSPI Profile 1.0 table
  mtd: spi-nor-core: Prepare Read SR and FSR for Octal DTR mode
  mtd: spi-nor-core: Enable octal DTR mode when possible
  mtd: spi-nor-core: Perform a Soft Reset on shutdown
  mtd: spi-nor-core: Perform a Soft Reset on boot
  mtd: spi-nor-core: Add support for Cypress Semper flash
  mtd: spi-nor-core: Allow using Micron mt35xu512aba in Octal DTR mode

 drivers/mtd/spi/Kconfig        |   11 +
 drivers/mtd/spi/sf_internal.h  |   13 +
 drivers/mtd/spi/sf_probe.c     |    9 +
 drivers/mtd/spi/spi-nor-core.c | 1273 +++++++++++++++++++++++++-------
 drivers/mtd/spi/spi-nor-ids.c  |    3 +-
 drivers/mtd/spi/spi-nor-tiny.c |   22 -
 drivers/spi/cadence_qspi.c     |   87 ++-
 drivers/spi/cadence_qspi.h     |   15 +-
 drivers/spi/cadence_qspi_apb.c |  286 ++++++-
 drivers/spi/spi-mem.c          |    3 +
 include/linux/mtd/spi-nor.h    |  271 +++++--
 include/spi-mem.h              |   16 +-
 12 files changed, 1619 insertions(+), 390 deletions(-)

--
2.25.0

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 01/17] spi: spi-mem: allow specifying whether an op is DTR or not
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 02/17] spi: spi-mem: allow specifying a command's extension Pratyush Yadav
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Each phase is given a separate 'dtr' field so mixed protocols like
4S-4D-4D can be supported.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/spi/spi-mem.c | 3 +++
 include/spi-mem.h     | 8 ++++++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c
index e900c997bd..5db6a612a0 100644
--- a/drivers/spi/spi-mem.c
+++ b/drivers/spi/spi-mem.c
@@ -158,6 +158,9 @@ bool spi_mem_default_supports_op(struct spi_slave *slave,
 				   op->data.dir == SPI_MEM_DATA_OUT))
 		return false;
 
+	if (op->cmd.dtr || op->addr.dtr || op->dummy.dtr || op->data.dtr)
+		return false;
+
 	return true;
 }
 EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
diff --git a/include/spi-mem.h b/include/spi-mem.h
index 36814efa86..fc39d08c3c 100644
--- a/include/spi-mem.h
+++ b/include/spi-mem.h
@@ -72,6 +72,7 @@ enum spi_mem_data_dir {
  * struct spi_mem_op - describes a SPI memory operation
  * @cmd.buswidth: number of IO lines used to transmit the command
  * @cmd.opcode: operation opcode
+ * @cmd.dtr: whether the command opcode should be sent in DTR mode or not
  * @addr.nbytes: number of address bytes to send. Can be zero if the operation
  *		 does not need to send an address
  * @addr.buswidth: number of IO lines used to transmit the address cycles
@@ -79,10 +80,13 @@ enum spi_mem_data_dir {
  *	      Note that only @addr.nbytes are taken into account in this
  *	      address value, so users should make sure the value fits in the
  *	      assigned number of bytes.
+ * @addr.dtr: whether the address should be sent in DTR mode or not
  * @dummy.nbytes: number of dummy bytes to send after an opcode or address. Can
  *		  be zero if the operation does not require dummy bytes
  * @dummy.buswidth: number of IO lanes used to transmit the dummy bytes
+ * @dummy.dtr: whether the dummy bytes should be sent in DTR mode or not
  * @data.buswidth: number of IO lanes used to send/receive the data
+ * @data.dtr: whether the data should be sent in DTR mode or not
  * @data.dir: direction of the transfer
  * @data.buf.in: input buffer
  * @data.buf.out: output buffer
@@ -91,21 +95,25 @@ struct spi_mem_op {
 	struct {
 		u8 buswidth;
 		u8 opcode;
+		u8 dtr : 1;
 	} cmd;
 
 	struct {
 		u8 nbytes;
 		u8 buswidth;
+		u8 dtr : 1;
 		u64 val;
 	} addr;
 
 	struct {
 		u8 nbytes;
 		u8 buswidth;
+		u8 dtr : 1;
 	} dummy;
 
 	struct {
 		u8 buswidth;
+		u8 dtr : 1;
 		enum spi_mem_data_dir dir;
 		unsigned int nbytes;
 		/* buf.{in,out} must be DMA-able. */
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 02/17] spi: spi-mem: allow specifying a command's extension
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 01/17] spi: spi-mem: allow specifying whether an op is DTR or not Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 03/17] spi: cadence-qspi: Do not calibrate when device tree sets read delay Pratyush Yadav
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

In xSPI mode, flashes expect 2-byte opcodes. The second byte is called
the "command extension". There can be 3 types of extensions in xSPI:
repeat, invert, and hex. When the extension type is "repeat", the same
opcode is sent twice. When it is "invert", the second byte is the
inverse of the opcode. When it is "hex" an additional opcode byte based
is sent with the command whose value can be anything.

So, make opcode a 16-bit value and add a 'nbytes', similar to how
multiple address widths are handled.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 include/spi-mem.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/include/spi-mem.h b/include/spi-mem.h
index fc39d08c3c..c55b98fe3e 100644
--- a/include/spi-mem.h
+++ b/include/spi-mem.h
@@ -70,6 +70,8 @@ enum spi_mem_data_dir {
 
 /**
  * struct spi_mem_op - describes a SPI memory operation
+ * @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
+ *		sent MSB-first.
  * @cmd.buswidth: number of IO lines used to transmit the command
  * @cmd.opcode: operation opcode
  * @cmd.dtr: whether the command opcode should be sent in DTR mode or not
@@ -93,9 +95,10 @@ enum spi_mem_data_dir {
  */
 struct spi_mem_op {
 	struct {
+		u8 nbytes;
 		u8 buswidth;
-		u8 opcode;
 		u8 dtr : 1;
+		u16 opcode;
 	} cmd;
 
 	struct {
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 03/17] spi: cadence-qspi: Do not calibrate when device tree sets read delay
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 01/17] spi: spi-mem: allow specifying whether an op is DTR or not Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 02/17] spi: spi-mem: allow specifying a command's extension Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 04/17] spi: cadence-qspi: Add support for octal DTR flashes Pratyush Yadav
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

If the device tree provides a read delay value, use that directly and do
not perform the calibration procedure.

This allows the device tree to over-ride the read delay value in cases
where the read delay value obtained via calibration is incorrect. One
such example is the Cypress Semper flash. It needs a read delay of 4 in
octal DTR mode. But since the calibration procedure is run before the
flash is switched in octal DTR mode, it yields a read delay of 2. A
value of 4 works for both octal DTR and legacy modes.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/spi/cadence_qspi.c | 26 +++++++++++++++++++++-----
 drivers/spi/cadence_qspi.h |  1 +
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 994a5948f1..d29e1a917a 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -140,12 +140,20 @@ static int cadence_spi_set_speed(struct udevice *bus, uint hz)
 	cadence_qspi_apb_controller_disable(priv->regbase);
 
 	/*
-	 * Calibration required for different current SCLK speed, requested
-	 * SCLK speed or chip select
+	 * If the device tree already provides a read delay value, use that
+	 * instead of calibrating.
 	 */
-	if (priv->previous_hz != hz ||
-	    priv->qspi_calibrated_hz != hz ||
-	    priv->qspi_calibrated_cs != spi_chip_select(bus)) {
+	if (plat->read_delay >= 0) {
+		cadence_spi_write_speed(bus, hz);
+		cadence_qspi_apb_readdata_capture(priv->regbase, 1,
+						  plat->read_delay);
+	} else if (priv->previous_hz != hz ||
+		   priv->qspi_calibrated_hz != hz ||
+		   priv->qspi_calibrated_cs != spi_chip_select(bus)) {
+		/*
+		 * Calibration required for different current SCLK speed,
+		 * requested SCLK speed or chip select
+		 */
 		err = spi_calibration(bus, hz);
 		if (err)
 			return err;
@@ -319,6 +327,14 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
 						 255);
 	plat->tchsh_ns = ofnode_read_u32_default(subnode, "cdns,tchsh-ns", 20);
 	plat->tslch_ns = ofnode_read_u32_default(subnode, "cdns,tslch-ns", 20);
+	/*
+	 * Read delay should be an unsigned value but we use a signed integer
+	 * so that negative values can indicate that the device tree did not
+	 * specify any signed values and we need to perform the calibration
+	 * sequence to find it out.
+	 */
+	plat->read_delay = ofnode_read_s32_default(subnode, "cdns,read-delay",
+						   -1);
 
 	debug("%s: regbase=%p ahbbase=%p max-frequency=%d page-size=%d\n",
 	      __func__, plat->regbase, plat->ahbbase, plat->max_hz,
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index ae459c74a1..9dff2fdced 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -26,6 +26,7 @@ struct cadence_spi_platdata {
 	u32		trigger_address;
 	fdt_addr_t	ahbsize;
 	bool		use_dac_mode;
+	int		read_delay;
 
 	/* Flash parameters */
 	u32		page_size;
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 04/17] spi: cadence-qspi: Add support for octal DTR flashes
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (2 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 03/17] spi: cadence-qspi: Do not calibrate when device tree sets read delay Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 05/17] mtd: spi-nor-core: Add a ->setup() hook Pratyush Yadav
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Set up opcode extension and enable/disable DTR mode based on whether the
command is DTR or not.

xSPI flashes can have a 4-byte dummy address associated with some
commands like the Read Status Register command in octal DTR mode. Since
the flash does not support sending the dummy address, we can not use
automatic write completion polling in DTR mode. Further, no write
completion polling makes it impossible to use DAC mode for DTR writes.
In that mode, the controller does not know beforehand how long a write
will be and so it can de-assert Chip Select (CS#) at any time. Once CS#
is de-assert, the flash will go into burning phase. But since the
controller does not do write completion polling, it does not know when
the flash is busy and might send in writes while the flash is not ready.

So, disable write completion polling and make writes go through indirect
mode for DTR writes and let spi-mem take care of polling the SR.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/spi/cadence_qspi.c     |  61 ++++++-
 drivers/spi/cadence_qspi.h     |  14 +-
 drivers/spi/cadence_qspi_apb.c | 286 ++++++++++++++++++++++++++++++---
 include/spi-mem.h              |   3 +
 4 files changed, 338 insertions(+), 26 deletions(-)

diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index d29e1a917a..87391ec892 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -40,20 +40,22 @@ static int cadence_spi_write_speed(struct udevice *bus, uint hz)
 	return 0;
 }
 
-static int cadence_spi_read_id(void *reg_base, u8 len, u8 *idcode)
+static int cadence_spi_read_id(struct cadence_spi_platdata *plat, u8 len,
+			       u8 *idcode)
 {
 	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(0x9F, 1),
 					  SPI_MEM_OP_NO_ADDR,
 					  SPI_MEM_OP_NO_DUMMY,
 					  SPI_MEM_OP_DATA_IN(len, idcode, 1));
 
-	return cadence_qspi_apb_command_read(reg_base, &op);
+	return cadence_qspi_apb_command_read(plat, &op);
 }
 
 /* Calibration sequence to determine the read data capture delay register */
 static int spi_calibration(struct udevice *bus, uint hz)
 {
 	struct cadence_spi_priv *priv = dev_get_priv(bus);
+	struct cadence_spi_platdata *plat = bus->platdata;
 	void *base = priv->regbase;
 	unsigned int idcode = 0, temp = 0;
 	int err = 0, i, range_lo = -1, range_hi = -1;
@@ -68,7 +70,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
 	cadence_qspi_apb_controller_enable(base);
 
 	/* read the ID which will be our golden value */
-	err = cadence_spi_read_id(base, 3, (u8 *)&idcode);
+	err = cadence_spi_read_id(plat, 3, (u8 *)&idcode);
 	if (err) {
 		puts("SF: Calibration failed (read)\n");
 		return err;
@@ -87,7 +89,7 @@ static int spi_calibration(struct udevice *bus, uint hz)
 		cadence_qspi_apb_controller_enable(base);
 
 		/* issue a RDID to get the ID value */
-		err = cadence_spi_read_id(base, 3, (u8 *)&temp);
+		err = cadence_spi_read_id(plat, 3, (u8 *)&temp);
 		if (err) {
 			puts("SF: Calibration failed (read)\n");
 			return err;
@@ -266,10 +268,14 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
 
 	switch (mode) {
 	case CQSPI_STIG_READ:
-		err = cadence_qspi_apb_command_read(base, op);
+		err = cadence_qspi_apb_command_read_setup(plat, op);
+		if (!err)
+			err = cadence_qspi_apb_command_read(plat, op);
 		break;
 	case CQSPI_STIG_WRITE:
-		err = cadence_qspi_apb_command_write(base, op);
+		err = cadence_qspi_apb_command_write_setup(plat, op);
+		if (!err)
+			err = cadence_qspi_apb_command_write(plat, op);
 		break;
 	case CQSPI_READ:
 		err = cadence_qspi_apb_read_setup(plat, op);
@@ -289,6 +295,48 @@ static int cadence_spi_mem_exec_op(struct spi_slave *spi,
 	return err;
 }
 
+static bool cadence_spi_mem_supports_op(struct spi_slave *slave,
+					const struct spi_mem_op *op)
+{
+	bool all_true, all_false;
+	u8 buswidths[4];
+	int i;
+
+	all_true = op->cmd.dtr && op->addr.dtr && op->dummy.dtr &&
+		   op->data.dtr;
+	all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr &&
+		    !op->data.dtr;
+
+	/* Mixed DTR modes not supported. */
+	if (!(all_true || all_false))
+		return false;
+
+	/*
+	 * Only buswidths of 1, 2, 4, and 8 are supported. 0 is allowed in case
+	 * that phase does not exist.
+	 */
+	buswidths[0] = op->cmd.buswidth;
+	buswidths[1] = op->addr.buswidth;
+	buswidths[2] = op->dummy.buswidth;
+	buswidths[3] = op->data.buswidth;
+	for (i = 0; i < ARRAY_SIZE(buswidths); i++) {
+		if (!(buswidths[i] == 0 || buswidths[i] == 1 ||
+		      buswidths[i] == 2 || buswidths[i] == 4 ||
+		      buswidths[i] == 8))
+			return false;
+	}
+
+	/*
+	 * The exception to the above is the command phase. A non-existent
+	 * command phase means that it is an XIP command, which we do not
+	 * support.
+	 */
+	if (op->cmd.buswidth == 0)
+		return false;
+
+	return true;
+}
+
 static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
 {
 	struct cadence_spi_platdata *plat = bus->platdata;
@@ -345,6 +393,7 @@ static int cadence_spi_ofdata_to_platdata(struct udevice *bus)
 
 static const struct spi_controller_mem_ops cadence_spi_mem_ops = {
 	.exec_op = cadence_spi_mem_exec_op,
+	.supports_op = cadence_spi_mem_supports_op,
 };
 
 static const struct dm_spi_ops cadence_spi_ops = {
diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h
index 9dff2fdced..2cf63193e9 100644
--- a/drivers/spi/cadence_qspi.h
+++ b/drivers/spi/cadence_qspi.h
@@ -35,6 +35,12 @@ struct cadence_spi_platdata {
 	u32		tsd2d_ns;
 	u32		tchsh_ns;
 	u32		tslch_ns;
+
+	/* Transaction protocol parameters. */
+	u8		inst_width;
+	u8		addr_width;
+	u8		data_width;
+	bool		dtr;
 };
 
 struct cadence_spi_priv {
@@ -58,9 +64,13 @@ void cadence_qspi_apb_controller_enable(void *reg_base_addr);
 void cadence_qspi_apb_controller_disable(void *reg_base_addr);
 void cadence_qspi_apb_dac_mode_enable(void *reg_base);
 
-int cadence_qspi_apb_command_read(void *reg_base_addr,
+int cadence_qspi_apb_command_read_setup(struct cadence_spi_platdata *plat,
+					const struct spi_mem_op *op);
+int cadence_qspi_apb_command_read(struct cadence_spi_platdata *plat,
 				  const struct spi_mem_op *op);
-int cadence_qspi_apb_command_write(void *reg_base_addr,
+int cadence_qspi_apb_command_write_setup(struct cadence_spi_platdata *plat,
+					 const struct spi_mem_op *op);
+int cadence_qspi_apb_command_write(struct cadence_spi_platdata *plat,
 				   const struct spi_mem_op *op);
 
 int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
diff --git a/drivers/spi/cadence_qspi_apb.c b/drivers/spi/cadence_qspi_apb.c
index 0a5af05614..8e0151a2e3 100644
--- a/drivers/spi/cadence_qspi_apb.c
+++ b/drivers/spi/cadence_qspi_apb.c
@@ -48,7 +48,7 @@
 #define CQSPI_STIG_DATA_LEN_MAX			8
 
 #define CQSPI_DUMMY_CLKS_PER_BYTE		8
-#define CQSPI_DUMMY_BYTES_MAX			4
+#define CQSPI_DUMMY_CLKS_MAX			31
 
 /****************************************************************************
  * Controller's configuration and status register (offset from QSPI_BASE)
@@ -62,6 +62,8 @@
 #define	CQSPI_REG_CONFIG_XIP_IMM		BIT(18)
 #define	CQSPI_REG_CONFIG_CHIPSELECT_LSB		10
 #define	CQSPI_REG_CONFIG_BAUD_LSB		19
+#define CQSPI_REG_CONFIG_DTR_PROTO		BIT(24)
+#define CQSPI_REG_CONFIG_DUAL_OPCODE		BIT(30)
 #define	CQSPI_REG_CONFIG_IDLE_LSB		31
 #define	CQSPI_REG_CONFIG_CHIPSELECT_MASK	0xF
 #define	CQSPI_REG_CONFIG_BAUD_MASK		0xF
@@ -80,6 +82,7 @@
 
 #define	CQSPI_REG_WR_INSTR			0x08
 #define	CQSPI_REG_WR_INSTR_OPCODE_LSB		0
+#define CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB	12
 #define	CQSPI_REG_WR_INSTR_TYPE_DATA_LSB	16
 
 #define	CQSPI_REG_DELAY				0x0C
@@ -117,6 +120,9 @@
 #define	CQSPI_REG_SDRAMLEVEL_RD_MASK		0xFFFF
 #define	CQSPI_REG_SDRAMLEVEL_WR_MASK		0xFFFF
 
+#define CQSPI_REG_WR_COMPLETION_CTRL		0x38
+#define CQSPI_REG_WR_DISABLE_AUTO_POLL		BIT(14)
+
 #define	CQSPI_REG_IRQSTATUS			0x40
 #define	CQSPI_REG_IRQMASK			0x44
 
@@ -163,6 +169,11 @@
 #define	CQSPI_REG_CMDWRITEDATALOWER		0xA8
 #define	CQSPI_REG_CMDWRITEDATAUPPER		0xAC
 
+#define CQSPI_REG_OP_EXT_LOWER			0xE0
+#define CQSPI_REG_OP_EXT_READ_LSB		24
+#define CQSPI_REG_OP_EXT_WRITE_LSB		16
+#define CQSPI_REG_OP_EXT_STIG_LSB		0
+
 #define CQSPI_REG_IS_IDLE(base)					\
 	((readl(base + CQSPI_REG_CONFIG) >>		\
 		CQSPI_REG_CONFIG_IDLE_LSB) & 0x1)
@@ -200,6 +211,75 @@ void cadence_qspi_apb_dac_mode_enable(void *reg_base)
 	writel(reg, reg_base + CQSPI_REG_CONFIG);
 }
 
+static unsigned int cadence_qspi_calc_dummy(const struct spi_mem_op *op,
+					    bool dtr)
+{
+	unsigned int dummy_clk;
+
+	dummy_clk = op->dummy.nbytes * (8 / op->dummy.buswidth);
+	if (dtr)
+		dummy_clk /= 2;
+
+	return dummy_clk;
+}
+
+static u32 cadence_qspi_calc_rdreg(struct cadence_spi_platdata *plat)
+{
+	u32 rdreg = 0;
+
+	rdreg |= plat->inst_width << CQSPI_REG_RD_INSTR_TYPE_INSTR_LSB;
+	rdreg |= plat->addr_width << CQSPI_REG_RD_INSTR_TYPE_ADDR_LSB;
+	rdreg |= plat->data_width << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+
+	return rdreg;
+}
+
+static int cadence_qspi_buswidth_to_inst_type(u8 buswidth)
+{
+	switch (buswidth) {
+	case 0:
+	case 1:
+		return CQSPI_INST_TYPE_SINGLE;
+
+	case 2:
+		return CQSPI_INST_TYPE_DUAL;
+
+	case 4:
+		return CQSPI_INST_TYPE_QUAD;
+
+	case 8:
+		return CQSPI_INST_TYPE_OCTAL;
+
+	default:
+		return -ENOTSUPP;
+	}
+}
+
+static int cadence_qspi_set_protocol(struct cadence_spi_platdata *plat,
+				     const struct spi_mem_op *op)
+{
+	int ret;
+
+	plat->dtr = op->data.dtr && op->cmd.dtr && op->addr.dtr;
+
+	ret = cadence_qspi_buswidth_to_inst_type(op->cmd.buswidth);
+	if (ret < 0)
+		return ret;
+	plat->inst_width = ret;
+
+	ret = cadence_qspi_buswidth_to_inst_type(op->addr.buswidth);
+	if (ret < 0)
+		return ret;
+	plat->addr_width = ret;
+
+	ret = cadence_qspi_buswidth_to_inst_type(op->data.buswidth);
+	if (ret < 0)
+		return ret;
+	plat->data_width = ret;
+
+	return 0;
+}
+
 /* Return 1 if idle, otherwise return 0 (busy). */
 static unsigned int cadence_qspi_wait_idle(void *reg_base)
 {
@@ -431,21 +511,109 @@ static int cadence_qspi_apb_exec_flash_cmd(void *reg_base,
 	return 0;
 }
 
+static int cadence_qspi_setup_opcode_ext(struct cadence_spi_platdata *plat,
+					 const struct spi_mem_op *op,
+					 unsigned int shift)
+{
+	unsigned int reg;
+	u8 ext;
+
+	if (op->cmd.nbytes != 2)
+		return -EINVAL;
+
+	/* Opcode extension is the LSB. */
+	ext = op->cmd.opcode & 0xff;
+
+	reg = readl(plat->regbase + CQSPI_REG_OP_EXT_LOWER);
+	reg &= ~(0xff << shift);
+	reg |= ext << shift;
+	writel(reg, plat->regbase + CQSPI_REG_OP_EXT_LOWER);
+
+	return 0;
+}
+
+static int cadence_qspi_enable_dtr(struct cadence_spi_platdata *plat,
+				   const struct spi_mem_op *op,
+				   unsigned int shift,
+				   bool enable)
+{
+	unsigned int reg;
+	int ret;
+
+	reg = readl(plat->regbase + CQSPI_REG_CONFIG);
+
+	if (enable) {
+		reg |= CQSPI_REG_CONFIG_DTR_PROTO;
+		reg |= CQSPI_REG_CONFIG_DUAL_OPCODE;
+
+		/* Set up command opcode extension. */
+		ret = cadence_qspi_setup_opcode_ext(plat, op, shift);
+		if (ret)
+			return ret;
+	} else {
+		reg &= ~CQSPI_REG_CONFIG_DTR_PROTO;
+		reg &= ~CQSPI_REG_CONFIG_DUAL_OPCODE;
+	}
+
+	writel(reg, plat->regbase + CQSPI_REG_CONFIG);
+
+	return 0;
+}
+
+int cadence_qspi_apb_command_read_setup(struct cadence_spi_platdata *plat,
+					const struct spi_mem_op *op)
+{
+	int ret;
+	unsigned int reg;
+
+	ret = cadence_qspi_set_protocol(plat, op);
+	if (ret)
+		return ret;
+
+	ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB,
+				      plat->dtr);
+	if (ret)
+		return ret;
+
+	reg = cadence_qspi_calc_rdreg(plat);
+	writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+
+	return 0;
+}
+
 /* For command RDID, RDSR. */
-int cadence_qspi_apb_command_read(void *reg_base, const struct spi_mem_op *op)
+int cadence_qspi_apb_command_read(struct cadence_spi_platdata *plat,
+				  const struct spi_mem_op *op)
 {
+	void *reg_base = plat->regbase;
 	unsigned int reg;
 	unsigned int read_len;
 	int status;
 	unsigned int rxlen = op->data.nbytes;
 	void *rxbuf = op->data.buf.in;
+	unsigned int dummy_clk;
+	u8 opcode;
 
 	if (rxlen > CQSPI_STIG_DATA_LEN_MAX || !rxbuf) {
 		printf("QSPI: Invalid input arguments rxlen %u\n", rxlen);
 		return -EINVAL;
 	}
 
-	reg = op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+	if (plat->dtr)
+		opcode = op->cmd.opcode >> 8;
+	else
+		opcode = op->cmd.opcode;
+
+	reg = opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+
+	/* Set up dummy cycles. */
+	dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr);
+	if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+		return -ENOTSUPP;
+
+	if (dummy_clk)
+		reg |= (dummy_clk & CQSPI_REG_CMDCTRL_DUMMY_MASK)
+		     << CQSPI_REG_CMDCTRL_DUMMY_LSB;
 
 	reg |= (0x1 << CQSPI_REG_CMDCTRL_RD_EN_LSB);
 
@@ -472,15 +640,39 @@ int cadence_qspi_apb_command_read(void *reg_base, const struct spi_mem_op *op)
 	return 0;
 }
 
+int cadence_qspi_apb_command_write_setup(struct cadence_spi_platdata *plat,
+					 const struct spi_mem_op *op)
+{
+	int ret;
+	unsigned int reg;
+
+	ret = cadence_qspi_set_protocol(plat, op);
+	if (ret)
+		return ret;
+
+	ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_STIG_LSB,
+				      plat->dtr);
+	if (ret)
+		return ret;
+
+	reg = cadence_qspi_calc_rdreg(plat);
+	writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+
+	return 0;
+}
+
 /* For commands: WRSR, WREN, WRDI, CHIP_ERASE, BE, etc. */
-int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
+int cadence_qspi_apb_command_write(struct cadence_spi_platdata *plat,
+				   const struct spi_mem_op *op)
 {
 	unsigned int reg = 0;
 	unsigned int wr_data;
 	unsigned int wr_len;
 	unsigned int txlen = op->data.nbytes;
 	const void *txbuf = op->data.buf.out;
+	void *reg_base = plat->regbase;
 	u32 addr;
+	u8 opcode;
 
 	/* Reorder address to SPI bus order if only transferring address */
 	if (!txlen) {
@@ -496,7 +688,12 @@ int cadence_qspi_apb_command_write(void *reg_base, const struct spi_mem_op *op)
 		return -EINVAL;
 	}
 
-	reg |= op->cmd.opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
+	if (plat->dtr)
+		opcode = op->cmd.opcode >> 8;
+	else
+		opcode = op->cmd.opcode;
+
+	reg |= opcode << CQSPI_REG_CMDCTRL_OPCODE_LSB;
 
 	if (txlen) {
 		/* writing data = yes */
@@ -530,29 +727,39 @@ int cadence_qspi_apb_read_setup(struct cadence_spi_platdata *plat,
 	unsigned int rd_reg;
 	unsigned int dummy_clk;
 	unsigned int dummy_bytes = op->dummy.nbytes;
+	int ret;
+	u8 opcode;
+
+	ret = cadence_qspi_set_protocol(plat, op);
+	if (ret)
+		return ret;
+
+	ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_READ_LSB,
+				      plat->dtr);
+	if (ret)
+		return ret;
 
 	/* Setup the indirect trigger address */
 	writel(plat->trigger_address,
 	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
 	/* Configure the opcode */
-	rd_reg = op->cmd.opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+	if (plat->dtr)
+		opcode = op->cmd.opcode >> 8;
+	else
+		opcode = op->cmd.opcode;
 
-	if (op->data.buswidth == 8)
-		/* Instruction and address at DQ0, data at DQ0-7. */
-		rd_reg |= CQSPI_INST_TYPE_OCTAL << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
-	else if (op->data.buswidth == 4)
-		/* Instruction and address at DQ0, data at DQ0-3. */
-		rd_reg |= CQSPI_INST_TYPE_QUAD << CQSPI_REG_RD_INSTR_TYPE_DATA_LSB;
+	rd_reg = opcode << CQSPI_REG_RD_INSTR_OPCODE_LSB;
+	rd_reg |= cadence_qspi_calc_rdreg(plat);
 
 	writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTRDSTARTADDR);
 
 	if (dummy_bytes) {
-		if (dummy_bytes > CQSPI_DUMMY_BYTES_MAX)
-			dummy_bytes = CQSPI_DUMMY_BYTES_MAX;
-
 		/* Convert to clock cycles. */
-		dummy_clk = dummy_bytes * CQSPI_DUMMY_CLKS_PER_BYTE;
+		dummy_clk = cadence_qspi_calc_dummy(op, plat->dtr);
+
+		if (dummy_clk > CQSPI_DUMMY_CLKS_MAX)
+			return -ENOTSUPP;
 
 		if (dummy_clk)
 			rd_reg |= (dummy_clk & CQSPI_REG_RD_INSTR_DUMMY_MASK)
@@ -679,17 +886,52 @@ int cadence_qspi_apb_write_setup(struct cadence_spi_platdata *plat,
 				 const struct spi_mem_op *op)
 {
 	unsigned int reg;
+	int ret;
+	u8 opcode;
+
+	ret = cadence_qspi_set_protocol(plat, op);
+	if (ret)
+		return ret;
+
+	ret = cadence_qspi_enable_dtr(plat, op, CQSPI_REG_OP_EXT_WRITE_LSB,
+				      plat->dtr);
+	if (ret)
+		return ret;
 
 	/* Setup the indirect trigger address */
 	writel(plat->trigger_address,
 	       plat->regbase + CQSPI_REG_INDIRECTTRIGGER);
 
 	/* Configure the opcode */
-	reg = op->cmd.opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+	if (plat->dtr)
+		opcode = op->cmd.opcode >> 8;
+	else
+		opcode = op->cmd.opcode;
+
+	reg = opcode << CQSPI_REG_WR_INSTR_OPCODE_LSB;
+	reg |= plat->data_width << CQSPI_REG_WR_INSTR_TYPE_DATA_LSB;
+	reg |= plat->addr_width << CQSPI_REG_WR_INSTR_TYPE_ADDR_LSB;
 	writel(reg, plat->regbase + CQSPI_REG_WR_INSTR);
 
+	reg = cadence_qspi_calc_rdreg(plat);
+	writel(reg, plat->regbase + CQSPI_REG_RD_INSTR);
+
 	writel(op->addr.val, plat->regbase + CQSPI_REG_INDIRECTWRSTARTADDR);
 
+	if (plat->dtr) {
+		/*
+		 * Some flashes like the cypress Semper flash expect a 4-byte
+		 * dummy address with the Read SR command in DTR mode, but this
+		 * controller does not support sending address with the Read SR
+		 * command. So, disable write completion polling on the
+		 * controller's side. spi-nor will take care of polling the
+		 * status register.
+		 */
+		reg = readl(plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
+		reg |= CQSPI_REG_WR_DISABLE_AUTO_POLL;
+		writel(reg, plat->regbase + CQSPI_REG_WR_COMPLETION_CTRL);
+	}
+
 	reg = readl(plat->regbase + CQSPI_REG_SIZE);
 	reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
 	reg |= (op->addr.nbytes - 1);
@@ -778,7 +1020,15 @@ int cadence_qspi_apb_write_execute(struct cadence_spi_platdata *plat,
 	const void *buf = op->data.buf.out;
 	size_t len = op->data.nbytes;
 
-	if (plat->use_dac_mode && (to + len < plat->ahbsize)) {
+	/*
+	 * Some flashes like the Cypress Semper flash expect a dummy 4-byte
+	 * address (all 0s) with the read status register command in DTR mode.
+	 * But this controller does not support sending dummy address bytes to
+	 * the flash when it is polling the write completion register in DTR
+	 * mode. So, we can not use direct mode when in DTR mode for writing
+	 * data.
+	 */
+	if (!plat->dtr && plat->use_dac_mode && (to + len < plat->ahbsize)) {
 		memcpy_toio(plat->ahbbase + to, buf, len);
 		if (!cadence_qspi_wait_idle(plat->regbase))
 			return -EIO;
diff --git a/include/spi-mem.h b/include/spi-mem.h
index c55b98fe3e..1e2310c742 100644
--- a/include/spi-mem.h
+++ b/include/spi-mem.h
@@ -250,6 +250,9 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op);
 
 bool spi_mem_supports_op(struct spi_slave *slave, const struct spi_mem_op *op);
 
+bool spi_mem_default_supports_op(struct spi_slave *slave,
+				 const struct spi_mem_op *op);
+
 int spi_mem_exec_op(struct spi_slave *slave, const struct spi_mem_op *op);
 
 #ifndef __UBOOT__
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 05/17] mtd: spi-nor-core: Add a ->setup() hook
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (3 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 04/17] spi: cadence-qspi: Add support for octal DTR flashes Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 06/17] mtd: spi-nor-core: Move SFDP related declarations to top Pratyush Yadav
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

nor->setup() can be used by flashes to configure settings in case they
have any peculiarities that can't be easily expressed by the generic
spi-nor framework. This includes things like different opcodes, dummy
cycles, page size, uniform/non-uniform sector sizes, etc.

Move related declarations to avoid forward declarations.

Inspired by the Linux kernel's setup() hook.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c |  84 +++------------
 drivers/mtd/spi/spi-nor-tiny.c |  22 ----
 include/linux/mtd/spi-nor.h    | 192 ++++++++++++++++++++++-----------
 3 files changed, 147 insertions(+), 151 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 7b6ad495ac..7b85754e2b 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -1441,71 +1441,6 @@ static int spansion_no_read_cr_quad_enable(struct spi_nor *nor)
 #endif /* CONFIG_SPI_FLASH_SFDP_SUPPORT */
 #endif /* CONFIG_SPI_FLASH_SPANSION */
 
-struct spi_nor_read_command {
-	u8			num_mode_clocks;
-	u8			num_wait_states;
-	u8			opcode;
-	enum spi_nor_protocol	proto;
-};
-
-struct spi_nor_pp_command {
-	u8			opcode;
-	enum spi_nor_protocol	proto;
-};
-
-enum spi_nor_read_command_index {
-	SNOR_CMD_READ,
-	SNOR_CMD_READ_FAST,
-	SNOR_CMD_READ_1_1_1_DTR,
-
-	/* Dual SPI */
-	SNOR_CMD_READ_1_1_2,
-	SNOR_CMD_READ_1_2_2,
-	SNOR_CMD_READ_2_2_2,
-	SNOR_CMD_READ_1_2_2_DTR,
-
-	/* Quad SPI */
-	SNOR_CMD_READ_1_1_4,
-	SNOR_CMD_READ_1_4_4,
-	SNOR_CMD_READ_4_4_4,
-	SNOR_CMD_READ_1_4_4_DTR,
-
-	/* Octo SPI */
-	SNOR_CMD_READ_1_1_8,
-	SNOR_CMD_READ_1_8_8,
-	SNOR_CMD_READ_8_8_8,
-	SNOR_CMD_READ_1_8_8_DTR,
-
-	SNOR_CMD_READ_MAX
-};
-
-enum spi_nor_pp_command_index {
-	SNOR_CMD_PP,
-
-	/* Quad SPI */
-	SNOR_CMD_PP_1_1_4,
-	SNOR_CMD_PP_1_4_4,
-	SNOR_CMD_PP_4_4_4,
-
-	/* Octo SPI */
-	SNOR_CMD_PP_1_1_8,
-	SNOR_CMD_PP_1_8_8,
-	SNOR_CMD_PP_8_8_8,
-
-	SNOR_CMD_PP_MAX
-};
-
-struct spi_nor_flash_parameter {
-	u64				size;
-	u32				page_size;
-
-	struct spi_nor_hwcaps		hwcaps;
-	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
-	struct spi_nor_pp_command	page_programs[SNOR_CMD_PP_MAX];
-
-	int (*quad_enable)(struct spi_nor *nor);
-};
-
 static void
 spi_nor_set_read_settings(struct spi_nor_read_command *read,
 			  u8 num_mode_clocks,
@@ -2363,9 +2298,10 @@ static int spi_nor_select_erase(struct spi_nor *nor,
 	return 0;
 }
 
-static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
-			 const struct spi_nor_flash_parameter *params,
-			 const struct spi_nor_hwcaps *hwcaps)
+static int spi_nor_default_setup(struct spi_nor *nor,
+				 const struct flash_info *info,
+				 const struct spi_nor_flash_parameter *params,
+				 const struct spi_nor_hwcaps *hwcaps)
 {
 	u32 ignored_mask, shared_mask;
 	bool enable_quad_io;
@@ -2424,6 +2360,16 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
 	return 0;
 }
 
+static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
+			 const struct spi_nor_flash_parameter *params,
+			 const struct spi_nor_hwcaps *hwcaps)
+{
+	if (!nor->setup)
+		return 0;
+
+	return nor->setup(nor, info, params, hwcaps);
+}
+
 static int spi_nor_init(struct spi_nor *nor)
 {
 	int err;
@@ -2489,6 +2435,8 @@ int spi_nor_scan(struct spi_nor *nor)
 	nor->read_reg = spi_nor_read_reg;
 	nor->write_reg = spi_nor_write_reg;
 
+	nor->setup = spi_nor_default_setup;
+
 	if (spi->mode & SPI_RX_OCTAL) {
 		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
 
diff --git a/drivers/mtd/spi/spi-nor-tiny.c b/drivers/mtd/spi/spi-nor-tiny.c
index ccc0ab07af..b76b7ca60a 100644
--- a/drivers/mtd/spi/spi-nor-tiny.c
+++ b/drivers/mtd/spi/spi-nor-tiny.c
@@ -543,28 +543,6 @@ static int spansion_read_cr_quad_enable(struct spi_nor *nor)
 }
 #endif /* CONFIG_SPI_FLASH_SPANSION */
 
-struct spi_nor_read_command {
-	u8			num_mode_clocks;
-	u8			num_wait_states;
-	u8			opcode;
-	enum spi_nor_protocol	proto;
-};
-
-enum spi_nor_read_command_index {
-	SNOR_CMD_READ,
-	SNOR_CMD_READ_FAST,
-
-	/* Quad SPI */
-	SNOR_CMD_READ_1_1_4,
-
-	SNOR_CMD_READ_MAX
-};
-
-struct spi_nor_flash_parameter {
-	struct spi_nor_hwcaps		hwcaps;
-	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
-};
-
 static void
 spi_nor_set_read_settings(struct spi_nor_read_command *read,
 			  u8 num_mode_clocks,
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index ec144a08d8..eb5d2794f3 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -248,6 +248,134 @@ enum spi_nor_option_flags {
 	SNOR_F_BROKEN_RESET	= BIT(6),
 };
 
+struct spi_nor;
+
+/**
+ * struct spi_nor_hwcaps - Structure for describing the hardware capabilies
+ * supported by the SPI controller (bus master).
+ * @mask:		the bitmask listing all the supported hw capabilies
+ */
+struct spi_nor_hwcaps {
+	u32	mask;
+};
+
+/*
+ *(Fast) Read capabilities.
+ * MUST be ordered by priority: the higher bit position, the higher priority.
+ * As a matter of performances, it is relevant to use Octo SPI protocols first,
+ * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
+ * (Slow) Read.
+ */
+#define SNOR_HWCAPS_READ_MASK		GENMASK(14, 0)
+#define SNOR_HWCAPS_READ		BIT(0)
+#define SNOR_HWCAPS_READ_FAST		BIT(1)
+#define SNOR_HWCAPS_READ_1_1_1_DTR	BIT(2)
+
+#define SNOR_HWCAPS_READ_DUAL		GENMASK(6, 3)
+#define SNOR_HWCAPS_READ_1_1_2		BIT(3)
+#define SNOR_HWCAPS_READ_1_2_2		BIT(4)
+#define SNOR_HWCAPS_READ_2_2_2		BIT(5)
+#define SNOR_HWCAPS_READ_1_2_2_DTR	BIT(6)
+
+#define SNOR_HWCAPS_READ_QUAD		GENMASK(10, 7)
+#define SNOR_HWCAPS_READ_1_1_4		BIT(7)
+#define SNOR_HWCAPS_READ_1_4_4		BIT(8)
+#define SNOR_HWCAPS_READ_4_4_4		BIT(9)
+#define SNOR_HWCAPS_READ_1_4_4_DTR	BIT(10)
+
+#define SNOR_HWCPAS_READ_OCTO		GENMASK(14, 11)
+#define SNOR_HWCAPS_READ_1_1_8		BIT(11)
+#define SNOR_HWCAPS_READ_1_8_8		BIT(12)
+#define SNOR_HWCAPS_READ_8_8_8		BIT(13)
+#define SNOR_HWCAPS_READ_1_8_8_DTR	BIT(14)
+
+/*
+ * Page Program capabilities.
+ * MUST be ordered by priority: the higher bit position, the higher priority.
+ * Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the
+ * legacy SPI 1-1-1 protocol.
+ * Note that Dual Page Programs are not supported because there is no existing
+ * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
+ * implements such commands.
+ */
+#define SNOR_HWCAPS_PP_MASK	GENMASK(22, 16)
+#define SNOR_HWCAPS_PP		BIT(16)
+
+#define SNOR_HWCAPS_PP_QUAD	GENMASK(19, 17)
+#define SNOR_HWCAPS_PP_1_1_4	BIT(17)
+#define SNOR_HWCAPS_PP_1_4_4	BIT(18)
+#define SNOR_HWCAPS_PP_4_4_4	BIT(19)
+
+#define SNOR_HWCAPS_PP_OCTO	GENMASK(22, 20)
+#define SNOR_HWCAPS_PP_1_1_8	BIT(20)
+#define SNOR_HWCAPS_PP_1_8_8	BIT(21)
+#define SNOR_HWCAPS_PP_8_8_8	BIT(22)
+
+struct spi_nor_read_command {
+	u8			num_mode_clocks;
+	u8			num_wait_states;
+	u8			opcode;
+	enum spi_nor_protocol	proto;
+};
+
+struct spi_nor_pp_command {
+	u8			opcode;
+	enum spi_nor_protocol	proto;
+};
+
+enum spi_nor_read_command_index {
+	SNOR_CMD_READ,
+	SNOR_CMD_READ_FAST,
+	SNOR_CMD_READ_1_1_1_DTR,
+
+	/* Dual SPI */
+	SNOR_CMD_READ_1_1_2,
+	SNOR_CMD_READ_1_2_2,
+	SNOR_CMD_READ_2_2_2,
+	SNOR_CMD_READ_1_2_2_DTR,
+
+	/* Quad SPI */
+	SNOR_CMD_READ_1_1_4,
+	SNOR_CMD_READ_1_4_4,
+	SNOR_CMD_READ_4_4_4,
+	SNOR_CMD_READ_1_4_4_DTR,
+
+	/* Octo SPI */
+	SNOR_CMD_READ_1_1_8,
+	SNOR_CMD_READ_1_8_8,
+	SNOR_CMD_READ_8_8_8,
+	SNOR_CMD_READ_1_8_8_DTR,
+
+	SNOR_CMD_READ_MAX
+};
+
+enum spi_nor_pp_command_index {
+	SNOR_CMD_PP,
+
+	/* Quad SPI */
+	SNOR_CMD_PP_1_1_4,
+	SNOR_CMD_PP_1_4_4,
+	SNOR_CMD_PP_4_4_4,
+
+	/* Octo SPI */
+	SNOR_CMD_PP_1_1_8,
+	SNOR_CMD_PP_1_8_8,
+	SNOR_CMD_PP_8_8_8,
+
+	SNOR_CMD_PP_MAX
+};
+
+struct spi_nor_flash_parameter {
+	u64				size;
+	u32				page_size;
+
+	struct spi_nor_hwcaps		hwcaps;
+	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
+	struct spi_nor_pp_command	page_programs[SNOR_CMD_PP_MAX];
+
+	int (*quad_enable)(struct spi_nor *nor);
+};
+
 /**
  * struct flash_info - Forward declaration of a structure used internally by
  *		       spi_nor_scan()
@@ -327,6 +455,9 @@ struct spi_nor {
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
 
+	int (*setup)(struct spi_nor *nor, const struct flash_info *info,
+		     const struct spi_nor_flash_parameter *params,
+		     const struct spi_nor_hwcaps *hwcaps);
 	int (*prepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	void (*unprepare)(struct spi_nor *nor, enum spi_nor_ops ops);
 	int (*read_reg)(struct spi_nor *nor, u8 opcode, u8 *buf, int len);
@@ -363,67 +494,6 @@ device_node *spi_nor_get_flash_node(struct spi_nor *nor)
 	return mtd_get_of_node(&nor->mtd);
 }
 
-/**
- * struct spi_nor_hwcaps - Structure for describing the hardware capabilies
- * supported by the SPI controller (bus master).
- * @mask:		the bitmask listing all the supported hw capabilies
- */
-struct spi_nor_hwcaps {
-	u32	mask;
-};
-
-/*
- *(Fast) Read capabilities.
- * MUST be ordered by priority: the higher bit position, the higher priority.
- * As a matter of performances, it is relevant to use Octo SPI protocols first,
- * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
- * (Slow) Read.
- */
-#define SNOR_HWCAPS_READ_MASK		GENMASK(14, 0)
-#define SNOR_HWCAPS_READ		BIT(0)
-#define SNOR_HWCAPS_READ_FAST		BIT(1)
-#define SNOR_HWCAPS_READ_1_1_1_DTR	BIT(2)
-
-#define SNOR_HWCAPS_READ_DUAL		GENMASK(6, 3)
-#define SNOR_HWCAPS_READ_1_1_2		BIT(3)
-#define SNOR_HWCAPS_READ_1_2_2		BIT(4)
-#define SNOR_HWCAPS_READ_2_2_2		BIT(5)
-#define SNOR_HWCAPS_READ_1_2_2_DTR	BIT(6)
-
-#define SNOR_HWCAPS_READ_QUAD		GENMASK(10, 7)
-#define SNOR_HWCAPS_READ_1_1_4		BIT(7)
-#define SNOR_HWCAPS_READ_1_4_4		BIT(8)
-#define SNOR_HWCAPS_READ_4_4_4		BIT(9)
-#define SNOR_HWCAPS_READ_1_4_4_DTR	BIT(10)
-
-#define SNOR_HWCPAS_READ_OCTO		GENMASK(14, 11)
-#define SNOR_HWCAPS_READ_1_1_8		BIT(11)
-#define SNOR_HWCAPS_READ_1_8_8		BIT(12)
-#define SNOR_HWCAPS_READ_8_8_8		BIT(13)
-#define SNOR_HWCAPS_READ_1_8_8_DTR	BIT(14)
-
-/*
- * Page Program capabilities.
- * MUST be ordered by priority: the higher bit position, the higher priority.
- * Like (Fast) Read capabilities, Octo/Quad SPI protocols are preferred to the
- * legacy SPI 1-1-1 protocol.
- * Note that Dual Page Programs are not supported because there is no existing
- * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
- * implements such commands.
- */
-#define SNOR_HWCAPS_PP_MASK	GENMASK(22, 16)
-#define SNOR_HWCAPS_PP		BIT(16)
-
-#define SNOR_HWCAPS_PP_QUAD	GENMASK(19, 17)
-#define SNOR_HWCAPS_PP_1_1_4	BIT(17)
-#define SNOR_HWCAPS_PP_1_4_4	BIT(18)
-#define SNOR_HWCAPS_PP_4_4_4	BIT(19)
-
-#define SNOR_HWCAPS_PP_OCTO	GENMASK(22, 20)
-#define SNOR_HWCAPS_PP_1_1_8	BIT(20)
-#define SNOR_HWCAPS_PP_1_8_8	BIT(21)
-#define SNOR_HWCAPS_PP_8_8_8	BIT(22)
-
 /**
  * spi_nor_scan() - scan the SPI NOR
  * @nor:	the spi_nor structure
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 06/17] mtd: spi-nor-core: Move SFDP related declarations to top
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (4 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 05/17] mtd: spi-nor-core: Add a ->setup() hook Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 07/17] mtd: spi-nor-core: Introduce flash-specific fixup hooks Pratyush Yadav
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

These structures will be used in a later commit inside another structure
definition. Also take the declarations out of the ifdef since they won't
affect the final binary anyway and will be used in a later commit.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 224 ++++++++++++++++-----------------
 1 file changed, 112 insertions(+), 112 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 7b85754e2b..8923935de0 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -36,6 +36,118 @@
 
 #define DEFAULT_READY_WAIT_JIFFIES		(40UL * HZ)
 
+struct sfdp_parameter_header {
+	u8		id_lsb;
+	u8		minor;
+	u8		major;
+	u8		length; /* in double words */
+	u8		parameter_table_pointer[3]; /* byte address */
+	u8		id_msb;
+};
+
+#define SFDP_PARAM_HEADER_ID(p)	(((p)->id_msb << 8) | (p)->id_lsb)
+#define SFDP_PARAM_HEADER_PTP(p) \
+	(((p)->parameter_table_pointer[2] << 16) | \
+	 ((p)->parameter_table_pointer[1] <<  8) | \
+	 ((p)->parameter_table_pointer[0] <<  0))
+
+#define SFDP_BFPT_ID		0xff00	/* Basic Flash Parameter Table */
+#define SFDP_SECTOR_MAP_ID	0xff81	/* Sector Map Table */
+#define SFDP_SST_ID		0x01bf	/* Manufacturer specific Table */
+
+#define SFDP_SIGNATURE		0x50444653U
+#define SFDP_JESD216_MAJOR	1
+#define SFDP_JESD216_MINOR	0
+#define SFDP_JESD216A_MINOR	5
+#define SFDP_JESD216B_MINOR	6
+
+struct sfdp_header {
+	u32		signature; /* Ox50444653U <=> "SFDP" */
+	u8		minor;
+	u8		major;
+	u8		nph; /* 0-base number of parameter headers */
+	u8		unused;
+
+	/* Basic Flash Parameter Table. */
+	struct sfdp_parameter_header	bfpt_header;
+};
+
+/* Basic Flash Parameter Table */
+
+/*
+ * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
+ * They are indexed from 1 but C arrays are indexed from 0.
+ */
+#define BFPT_DWORD(i)		((i) - 1)
+#define BFPT_DWORD_MAX		16
+
+/* The first version of JESB216 defined only 9 DWORDs. */
+#define BFPT_DWORD_MAX_JESD216			9
+
+/* 1st DWORD. */
+#define BFPT_DWORD1_FAST_READ_1_1_2		BIT(16)
+#define BFPT_DWORD1_ADDRESS_BYTES_MASK		GENMASK(18, 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY	(0x0UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4	(0x1UL << 17)
+#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY	(0x2UL << 17)
+#define BFPT_DWORD1_DTR				BIT(19)
+#define BFPT_DWORD1_FAST_READ_1_2_2		BIT(20)
+#define BFPT_DWORD1_FAST_READ_1_4_4		BIT(21)
+#define BFPT_DWORD1_FAST_READ_1_1_4		BIT(22)
+
+/* 5th DWORD. */
+#define BFPT_DWORD5_FAST_READ_2_2_2		BIT(0)
+#define BFPT_DWORD5_FAST_READ_4_4_4		BIT(4)
+
+/* 11th DWORD. */
+#define BFPT_DWORD11_PAGE_SIZE_SHIFT		4
+#define BFPT_DWORD11_PAGE_SIZE_MASK		GENMASK(7, 4)
+
+/* 15th DWORD. */
+
+/*
+ * (from JESD216 rev B)
+ * Quad Enable Requirements (QER):
+ * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
+ *         reads based on instruction. DQ3/HOLD# functions are hold during
+ *         instruction phase.
+ * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         Writing only one byte to the status register has the side-effect of
+ *         clearing status register 2, including the QE bit. The 100b code is
+ *         used if writing one byte to the status register does not modify
+ *         status register 2.
+ * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
+ *         one data byte where bit 6 is one.
+ *         [...]
+ * - 011b: QE is bit 7 of status register 2. It is set via Write status
+ *         register 2 instruction 3Eh with one data byte where bit 7 is one.
+ *         [...]
+ *         The status register 2 is read using instruction 3Fh.
+ * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ *         In contrast to the 001b code, writing one byte to the status
+ *         register does not modify status register 2.
+ * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
+ *         Read Status instruction 05h. Status register2 is read using
+ *         instruction 35h. QE is set via Writ Status instruction 01h with
+ *         two data bytes where bit 1 of the second byte is one.
+ *         [...]
+ */
+#define BFPT_DWORD15_QER_MASK			GENMASK(22, 20)
+#define BFPT_DWORD15_QER_NONE			(0x0UL << 20) /* Micron */
+#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY		(0x1UL << 20)
+#define BFPT_DWORD15_QER_SR1_BIT6		(0x2UL << 20) /* Macronix */
+#define BFPT_DWORD15_QER_SR2_BIT7		(0x3UL << 20)
+#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD		(0x4UL << 20)
+#define BFPT_DWORD15_QER_SR2_BIT1		(0x5UL << 20) /* Spansion */
+
+struct sfdp_bfpt {
+	u32	dwords[BFPT_DWORD_MAX];
+};
+
 static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
 		*op, void *buf)
 {
@@ -1518,118 +1630,6 @@ read_err:
 	return ret;
 }
 
-struct sfdp_parameter_header {
-	u8		id_lsb;
-	u8		minor;
-	u8		major;
-	u8		length; /* in double words */
-	u8		parameter_table_pointer[3]; /* byte address */
-	u8		id_msb;
-};
-
-#define SFDP_PARAM_HEADER_ID(p)	(((p)->id_msb << 8) | (p)->id_lsb)
-#define SFDP_PARAM_HEADER_PTP(p) \
-	(((p)->parameter_table_pointer[2] << 16) | \
-	 ((p)->parameter_table_pointer[1] <<  8) | \
-	 ((p)->parameter_table_pointer[0] <<  0))
-
-#define SFDP_BFPT_ID		0xff00	/* Basic Flash Parameter Table */
-#define SFDP_SECTOR_MAP_ID	0xff81	/* Sector Map Table */
-#define SFDP_SST_ID		0x01bf	/* Manufacturer specific Table */
-
-#define SFDP_SIGNATURE		0x50444653U
-#define SFDP_JESD216_MAJOR	1
-#define SFDP_JESD216_MINOR	0
-#define SFDP_JESD216A_MINOR	5
-#define SFDP_JESD216B_MINOR	6
-
-struct sfdp_header {
-	u32		signature; /* Ox50444653U <=> "SFDP" */
-	u8		minor;
-	u8		major;
-	u8		nph; /* 0-base number of parameter headers */
-	u8		unused;
-
-	/* Basic Flash Parameter Table. */
-	struct sfdp_parameter_header	bfpt_header;
-};
-
-/* Basic Flash Parameter Table */
-
-/*
- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
- * They are indexed from 1 but C arrays are indexed from 0.
- */
-#define BFPT_DWORD(i)		((i) - 1)
-#define BFPT_DWORD_MAX		16
-
-/* The first version of JESB216 defined only 9 DWORDs. */
-#define BFPT_DWORD_MAX_JESD216			9
-
-/* 1st DWORD. */
-#define BFPT_DWORD1_FAST_READ_1_1_2		BIT(16)
-#define BFPT_DWORD1_ADDRESS_BYTES_MASK		GENMASK(18, 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_3_ONLY	(0x0UL << 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_3_OR_4	(0x1UL << 17)
-#define BFPT_DWORD1_ADDRESS_BYTES_4_ONLY	(0x2UL << 17)
-#define BFPT_DWORD1_DTR				BIT(19)
-#define BFPT_DWORD1_FAST_READ_1_2_2		BIT(20)
-#define BFPT_DWORD1_FAST_READ_1_4_4		BIT(21)
-#define BFPT_DWORD1_FAST_READ_1_1_4		BIT(22)
-
-/* 5th DWORD. */
-#define BFPT_DWORD5_FAST_READ_2_2_2		BIT(0)
-#define BFPT_DWORD5_FAST_READ_4_4_4		BIT(4)
-
-/* 11th DWORD. */
-#define BFPT_DWORD11_PAGE_SIZE_SHIFT		4
-#define BFPT_DWORD11_PAGE_SIZE_MASK		GENMASK(7, 4)
-
-/* 15th DWORD. */
-
-/*
- * (from JESD216 rev B)
- * Quad Enable Requirements (QER):
- * - 000b: Device does not have a QE bit. Device detects 1-1-4 and 1-4-4
- *         reads based on instruction. DQ3/HOLD# functions are hold during
- *         instruction phase.
- * - 001b: QE is bit 1 of status register 2. It is set via Write Status with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
- *         Writing only one byte to the status register has the side-effect of
- *         clearing status register 2, including the QE bit. The 100b code is
- *         used if writing one byte to the status register does not modify
- *         status register 2.
- * - 010b: QE is bit 6 of status register 1. It is set via Write Status with
- *         one data byte where bit 6 is one.
- *         [...]
- * - 011b: QE is bit 7 of status register 2. It is set via Write status
- *         register 2 instruction 3Eh with one data byte where bit 7 is one.
- *         [...]
- *         The status register 2 is read using instruction 3Fh.
- * - 100b: QE is bit 1 of status register 2. It is set via Write Status with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
- *         In contrast to the 001b code, writing one byte to the status
- *         register does not modify status register 2.
- * - 101b: QE is bit 1 of status register 2. Status register 1 is read using
- *         Read Status instruction 05h. Status register2 is read using
- *         instruction 35h. QE is set via Writ Status instruction 01h with
- *         two data bytes where bit 1 of the second byte is one.
- *         [...]
- */
-#define BFPT_DWORD15_QER_MASK			GENMASK(22, 20)
-#define BFPT_DWORD15_QER_NONE			(0x0UL << 20) /* Micron */
-#define BFPT_DWORD15_QER_SR2_BIT1_BUGGY		(0x1UL << 20)
-#define BFPT_DWORD15_QER_SR1_BIT6		(0x2UL << 20) /* Macronix */
-#define BFPT_DWORD15_QER_SR2_BIT7		(0x3UL << 20)
-#define BFPT_DWORD15_QER_SR2_BIT1_NO_RD		(0x4UL << 20)
-#define BFPT_DWORD15_QER_SR2_BIT1		(0x5UL << 20) /* Spansion */
-
-struct sfdp_bfpt {
-	u32	dwords[BFPT_DWORD_MAX];
-};
-
 /* Fast Read settings. */
 
 static void
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 07/17] mtd: spi-nor-core: Introduce flash-specific fixup hooks
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (5 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 06/17] mtd: spi-nor-core: Move SFDP related declarations to top Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 08/17] mtd: spi-nor-core: Rework hwcaps selection Pratyush Yadav
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Sometimes the information in a flash's SFDP tables is wrong. Sometimes
some information just can't be expressed in the SFDP table. So,
introduce the fixup hooks to allow tailoring settings for a specific
flash.

Three hooks are added: default_init, post_sfdp, and post_bfpt. These
allow tweaking the flash settings at different point in the probe
sequence. Since the hooks reside in nor->info, set that value just
before the call to spi_nor_init_params().

The hooks and at what points they are executed mimics Linux's spi-nor
framework.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/sf_internal.h  |  3 ++
 drivers/mtd/spi/spi-nor-core.c | 69 +++++++++++++++++++++++++++++++++-
 2 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 940b2e4c9e..d689b673ce 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -67,6 +67,9 @@ struct flash_info {
 #define USE_CLSR		BIT(14)	/* use CLSR command */
 #define SPI_NOR_HAS_SST26LOCK	BIT(15)	/* Flash supports lock/unlock via BPR */
 #define SPI_NOR_OCTAL_READ      BIT(16) /* Flash supports Octal Read */
+
+	/* Part specific fixup hooks. */
+	const struct spi_nor_fixups *fixups;
 };
 
 extern const struct flash_info spi_nor_ids[];
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 8923935de0..88b19978ed 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -148,6 +148,31 @@ struct sfdp_bfpt {
 	u32	dwords[BFPT_DWORD_MAX];
 };
 
+/**
+ * struct spi_nor_fixups - SPI NOR fixup hooks
+ * @default_init: called after default flash parameters init. Used to tweak
+ *                flash parameters when information provided by the flash_info
+ *                table is incomplete or wrong.
+ * @post_bfpt: called after the BFPT table has been parsed
+ * @post_sfdp: called after SFDP has been parsed (is also called for SPI NORs
+ *             that do not support RDSFDP). Typically used to tweak various
+ *             parameters that could not be extracted by other means (i.e.
+ *             when information provided by the SFDP/flash_info tables are
+ *             incomplete or wrong).
+ *
+ * Those hooks can be used to tweak the SPI NOR configuration when the SFDP
+ * table is broken or not available.
+ */
+struct spi_nor_fixups {
+	void (*default_init)(struct spi_nor *nor);
+	int (*post_bfpt)(struct spi_nor *nor,
+			 const struct sfdp_parameter_header *bfpt_header,
+			 const struct sfdp_bfpt *bfpt,
+			 struct spi_nor_flash_parameter *params);
+	void (*post_sfdp)(struct spi_nor *nor,
+			  struct spi_nor_flash_parameter *params);
+};
+
 static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
 		*op, void *buf)
 {
@@ -1741,6 +1766,19 @@ static const struct sfdp_bfpt_erase sfdp_bfpt_erases[] = {
 
 static int spi_nor_hwcaps_read2cmd(u32 hwcaps);
 
+static int
+spi_nor_post_bfpt_fixups(struct spi_nor *nor,
+			 const struct sfdp_parameter_header *bfpt_header,
+			 const struct sfdp_bfpt *bfpt,
+			 struct spi_nor_flash_parameter *params)
+{
+	if (nor->info->fixups && nor->info->fixups->post_bfpt)
+		return nor->info->fixups->post_bfpt(nor, bfpt_header, bfpt,
+						    params);
+
+	return 0;
+}
+
 /**
  * spi_nor_parse_bfpt() - read and parse the Basic Flash Parameter Table.
  * @nor:		pointer to a 'struct spi_nor'
@@ -1912,7 +1950,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 		return -EINVAL;
 	}
 
-	return 0;
+	return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
 }
 
 /**
@@ -2072,6 +2110,29 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 }
 #endif /* SPI_FLASH_SFDP_SUPPORT */
 
+/**
+ * spi_nor_post_sfdp_fixups() - Updates the flash's parameters and settings
+ * after SFDP has been parsed (is also called for SPI NORs that do not
+ * support RDSFDP).
+ * @nor:	pointer to a 'struct spi_nor'
+ *
+ * Typically used to tweak various parameters that could not be extracted by
+ * other means (i.e. when information provided by the SFDP/flash_info tables
+ * are incomplete or wrong).
+ */
+static void spi_nor_post_sfdp_fixups(struct spi_nor *nor,
+				     struct spi_nor_flash_parameter *params)
+{
+	if (nor->info->fixups && nor->info->fixups->post_sfdp)
+		nor->info->fixups->post_sfdp(nor, params);
+}
+
+static void spi_nor_default_init_fixups(struct spi_nor *nor)
+{
+	if (nor->info->fixups && nor->info->fixups->default_init)
+		nor->info->fixups->default_init(nor);
+}
+
 static int spi_nor_init_params(struct spi_nor *nor,
 			       const struct flash_info *info,
 			       struct spi_nor_flash_parameter *params)
@@ -2150,6 +2211,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
 		}
 	}
 
+	spi_nor_default_init_fixups(nor);
+
 	/* Override the parameters with data read from SFDP tables. */
 	nor->addr_width = 0;
 	nor->mtd.erasesize = 0;
@@ -2166,6 +2229,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
 		}
 	}
 
+	spi_nor_post_sfdp_fixups(nor, params);
+
 	return 0;
 }
 
@@ -2461,6 +2526,7 @@ int spi_nor_scan(struct spi_nor *nor)
 	info = spi_nor_read_id(nor);
 	if (IS_ERR_OR_NULL(info))
 		return -ENOENT;
+	nor->info = info;
 	/* Parse the Serial Flash Discoverable Parameters table. */
 	ret = spi_nor_init_params(nor, info, &params);
 	if (ret)
@@ -2565,7 +2631,6 @@ int spi_nor_scan(struct spi_nor *nor)
 	}
 
 	/* Send all the required SPI flash commands to initialize device */
-	nor->info = info;
 	ret = spi_nor_init(nor);
 	if (ret)
 		return ret;
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 08/17] mtd: spi-nor-core: Rework hwcaps selection
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (6 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 07/17] mtd: spi-nor-core: Introduce flash-specific fixup hooks Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 09/17] mtd: spi-nor-core: Add support for DTR protocol Pratyush Yadav
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

The spi-mem layer provides a spi_mem_supports_op() function to check
whether a specific operation is supported by the controller or not.
This is much more accurate than the hwcaps selection logic based on
SPI_{RX,TX}_ flags.

Rework the hwcaps selection logic to use spi_mem_supports_op() when
nor->spimem != NULL.

Based on the Linux commit c76f5089796a (mtd: spi-nor: Rework hwcaps
selection for the spi-mem case, 2019-08-06)

Based-on-patch-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 168 +++++++++++++++++++++++++--------
 include/linux/mtd/spi-nor.h    |  14 +++
 2 files changed, 144 insertions(+), 38 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 88b19978ed..f324d3c483 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2285,6 +2285,124 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
 				  ARRAY_SIZE(hwcaps_pp2cmd));
 }
 
+/**
+ * spi_nor_check_op - check if the operation is supported by controller
+ * @nor:        pointer to a 'struct spi_nor'
+ * @op:         pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_op(struct spi_nor *nor,
+			    struct spi_mem_op *op)
+{
+	/*
+	 * First test with 4 address bytes. The opcode itself might be a 3B
+	 * addressing opcode but we don't care, because SPI controller
+	 * implementation should not check the opcode, but just the sequence.
+	 */
+	op->addr.nbytes = 4;
+	if (!spi_mem_supports_op(nor->spi, op)) {
+		if (nor->mtd.size > SZ_16M)
+			return -ENOTSUPP;
+
+		/* If flash size <= 16MB, 3 address bytes are sufficient */
+		op->addr.nbytes = 3;
+		if (!spi_mem_supports_op(nor->spi, op))
+			return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+/**
+ * spi_nor_check_readop - check if the read op is supported by controller
+ * @nor:         pointer to a 'struct spi_nor'
+ * @read:        pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_readop(struct spi_nor *nor,
+				const struct spi_nor_read_command *read)
+{
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(read->opcode, 1),
+					  SPI_MEM_OP_ADDR(3, 0, 1),
+					  SPI_MEM_OP_DUMMY(0, 1),
+					  SPI_MEM_OP_DATA_IN(0, NULL, 1));
+
+	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(read->proto);
+	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(read->proto);
+	op.data.buswidth = spi_nor_get_protocol_data_nbits(read->proto);
+	op.dummy.buswidth = op.addr.buswidth;
+	op.dummy.nbytes = (read->num_mode_clocks + read->num_wait_states) *
+			  op.dummy.buswidth / 8;
+
+	return spi_nor_check_op(nor, &op);
+}
+
+/**
+ * spi_nor_check_pp - check if the page program op is supported by controller
+ * @nor:         pointer to a 'struct spi_nor'
+ * @pp:          pointer to op template to be checked
+ *
+ * Returns 0 if operation is supported, -ENOTSUPP otherwise.
+ */
+static int spi_nor_check_pp(struct spi_nor *nor,
+			    const struct spi_nor_pp_command *pp)
+{
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(pp->opcode, 1),
+					  SPI_MEM_OP_ADDR(3, 0, 1),
+					  SPI_MEM_OP_NO_DUMMY,
+					  SPI_MEM_OP_DATA_OUT(0, NULL, 1));
+
+	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(pp->proto);
+	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(pp->proto);
+	op.data.buswidth = spi_nor_get_protocol_data_nbits(pp->proto);
+
+	return spi_nor_check_op(nor, &op);
+}
+
+/**
+ * spi_nor_adjust_hwcaps - Find optimal Read/Write protocol based on SPI
+ *                         controller capabilities
+ * @nor:        pointer to a 'struct spi_nor'
+ * @params:     pointer to the 'struct spi_nor_flash_parameter'
+ *              representing SPI NOR flash capabilities
+ * @hwcaps:     pointer to resulting capabilities after adjusting
+ *              according to controller and flash's capability
+ */
+static void
+spi_nor_adjust_hwcaps(struct spi_nor *nor,
+		      const struct spi_nor_flash_parameter *params,
+		      u32 *hwcaps)
+{
+	unsigned int cap;
+
+	/* DTR modes are not supported yet, mask them all. */
+	*hwcaps &= ~SNOR_HWCAPS_DTR;
+
+	/* X-X-X modes are not supported yet, mask them all. */
+	*hwcaps &= ~SNOR_HWCAPS_X_X_X;
+
+	for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
+		int rdidx, ppidx;
+
+		if (!(*hwcaps & BIT(cap)))
+			continue;
+
+		rdidx = spi_nor_hwcaps_read2cmd(BIT(cap));
+		if (rdidx >= 0 &&
+		    spi_nor_check_readop(nor, &params->reads[rdidx]))
+			*hwcaps &= ~BIT(cap);
+
+		ppidx = spi_nor_hwcaps_pp2cmd(BIT(cap));
+		if (ppidx < 0)
+			continue;
+
+		if (spi_nor_check_pp(nor, &params->page_programs[ppidx]))
+			*hwcaps &= ~BIT(cap);
+	}
+}
+
 static int spi_nor_select_read(struct spi_nor *nor,
 			       const struct spi_nor_flash_parameter *params,
 			       u32 shared_hwcaps)
@@ -2368,7 +2486,7 @@ static int spi_nor_default_setup(struct spi_nor *nor,
 				 const struct spi_nor_flash_parameter *params,
 				 const struct spi_nor_hwcaps *hwcaps)
 {
-	u32 ignored_mask, shared_mask;
+	u32 shared_mask;
 	bool enable_quad_io;
 	int err;
 
@@ -2378,17 +2496,12 @@ static int spi_nor_default_setup(struct spi_nor *nor,
 	 */
 	shared_mask = hwcaps->mask & params->hwcaps.mask;
 
-	/* SPI n-n-n protocols are not supported yet. */
-	ignored_mask = (SNOR_HWCAPS_READ_2_2_2 |
-			SNOR_HWCAPS_READ_4_4_4 |
-			SNOR_HWCAPS_READ_8_8_8 |
-			SNOR_HWCAPS_PP_4_4_4 |
-			SNOR_HWCAPS_PP_8_8_8);
-	if (shared_mask & ignored_mask) {
-		dev_dbg(nor->dev,
-			"SPI n-n-n protocols are not supported yet.\n");
-		shared_mask &= ~ignored_mask;
-	}
+	/*
+	 * When called from spi_nor_probe(), all caps are set and we need to
+	 * discard some of them based on what the SPI controller actually
+	 * supports (using spi_mem_supports_op()).
+	 */
+	spi_nor_adjust_hwcaps(nor, params, &shared_mask);
 
 	/* Select the (Fast) Read command. */
 	err = spi_nor_select_read(nor, params, shared_mask);
@@ -2483,12 +2596,12 @@ int spi_nor_scan(struct spi_nor *nor)
 	struct spi_nor_flash_parameter params;
 	const struct flash_info *info = NULL;
 	struct mtd_info *mtd = &nor->mtd;
-	struct spi_nor_hwcaps hwcaps = {
-		.mask = SNOR_HWCAPS_READ |
-			SNOR_HWCAPS_READ_FAST |
-			SNOR_HWCAPS_PP,
-	};
 	struct spi_slave *spi = nor->spi;
+	/*
+	 * Enable all caps by default. The core will mask them after
+	 * checking what's really supported using spi_mem_supports_op().
+	 */
+	const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_ALL };
 	int ret;
 
 	/* Reset SPI protocol for all commands. */
@@ -2502,27 +2615,6 @@ int spi_nor_scan(struct spi_nor *nor)
 
 	nor->setup = spi_nor_default_setup;
 
-	if (spi->mode & SPI_RX_OCTAL) {
-		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_8;
-
-		if (spi->mode & SPI_TX_OCTAL)
-			hwcaps.mask |= (SNOR_HWCAPS_READ_1_8_8 |
-					SNOR_HWCAPS_PP_1_1_8 |
-					SNOR_HWCAPS_PP_1_8_8);
-	} else if (spi->mode & SPI_RX_QUAD) {
-		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;
-
-		if (spi->mode & SPI_TX_QUAD)
-			hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 |
-					SNOR_HWCAPS_PP_1_1_4 |
-					SNOR_HWCAPS_PP_1_4_4);
-	} else if (spi->mode & SPI_RX_DUAL) {
-		hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2;
-
-		if (spi->mode & SPI_TX_DUAL)
-			hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2;
-	}
-
 	info = spi_nor_read_id(nor);
 	if (IS_ERR_OR_NULL(info))
 		return -ENOENT;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index eb5d2794f3..4a11999eeb 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -311,6 +311,20 @@ struct spi_nor_hwcaps {
 #define SNOR_HWCAPS_PP_1_8_8	BIT(21)
 #define SNOR_HWCAPS_PP_8_8_8	BIT(22)
 
+#define SNOR_HWCAPS_X_X_X	(SNOR_HWCAPS_READ_2_2_2 |	\
+				 SNOR_HWCAPS_READ_4_4_4 |	\
+				 SNOR_HWCAPS_READ_8_8_8 |	\
+				 SNOR_HWCAPS_PP_4_4_4 |		\
+				 SNOR_HWCAPS_PP_8_8_8)
+
+#define SNOR_HWCAPS_DTR		(SNOR_HWCAPS_READ_1_1_1_DTR |	\
+				 SNOR_HWCAPS_READ_1_2_2_DTR |	\
+				 SNOR_HWCAPS_READ_1_4_4_DTR |	\
+				 SNOR_HWCAPS_READ_1_8_8_DTR)
+
+#define SNOR_HWCAPS_ALL		(SNOR_HWCAPS_READ_MASK |	\
+				 SNOR_HWCAPS_PP_MASK)
+
 struct spi_nor_read_command {
 	u8			num_mode_clocks;
 	u8			num_wait_states;
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 09/17] mtd: spi-nor-core: Add support for DTR protocol
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (7 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 08/17] mtd: spi-nor-core: Rework hwcaps selection Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT Pratyush Yadav
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Double Transfer Rate (DTR) is SPI protocol in which data is transferred
on each clock edge as opposed to on each clock cycle. Make
framework-level changes to allow supporting flashes in DTR mode.

Right now, mixed DTR modes are not supported. So, for example a mode
like 4S-4D-4D will not work. All phases need to be either DTR or STR.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/sf_internal.h  |   1 +
 drivers/mtd/spi/spi-nor-core.c | 114 ++++++++++++++++++++++++++++-----
 include/linux/mtd/spi-nor.h    |  53 ++++++++++-----
 3 files changed, 136 insertions(+), 32 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index d689b673ce..5780c81287 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -67,6 +67,7 @@ struct flash_info {
 #define USE_CLSR		BIT(14)	/* use CLSR command */
 #define SPI_NOR_HAS_SST26LOCK	BIT(15)	/* Flash supports lock/unlock via BPR */
 #define SPI_NOR_OCTAL_READ      BIT(16) /* Flash supports Octal Read */
+#define SPI_NOR_OCTAL_DTR_READ	BIT(17)	/* Flash supports Octal DTR Read */
 
 	/* Part specific fixup hooks. */
 	const struct spi_nor_fixups *fixups;
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index f324d3c483..d3f05e1ded 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -173,6 +173,76 @@ struct spi_nor_fixups {
 			  struct spi_nor_flash_parameter *params);
 };
 
+/**
+ * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
+ *			   extension type.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @op:			pointer to the 'struct spi_mem_op' whose properties
+ *			need to be initialized.
+ *
+ * Right now, only "repeat" and "invert" are supported.
+ *
+ * Return: The opcode extension.
+ */
+static u8 spi_nor_get_cmd_ext(const struct spi_nor *nor,
+			      const struct spi_mem_op *op)
+{
+	switch (nor->cmd_ext_type) {
+	case SPI_NOR_EXT_INVERT:
+		return ~op->cmd.opcode;
+
+	case SPI_NOR_EXT_REPEAT:
+		return op->cmd.opcode;
+
+	default:
+		dev_err(nor->dev, "Unknown command extension type\n");
+		return 0;
+	}
+}
+
+/**
+ * spi_nor_setup_op() - Set up common properties of a spi-mem op.
+ * @nor:		pointer to a 'struct spi_nor'
+ * @op:			pointer to the 'struct spi_mem_op' whose properties
+ *			need to be initialized.
+ * @proto:		the protocol from which the properties need to be set.
+ */
+static void spi_nor_setup_op(const struct spi_nor *nor,
+			     struct spi_mem_op *op,
+			     const enum spi_nor_protocol proto)
+{
+	u8 ext;
+
+	op->cmd.buswidth = spi_nor_get_protocol_inst_nbits(proto);
+
+	if (op->addr.nbytes)
+		op->addr.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+	if (op->dummy.nbytes)
+		op->dummy.buswidth = spi_nor_get_protocol_addr_nbits(proto);
+
+	if (op->data.nbytes)
+		op->data.buswidth = spi_nor_get_protocol_data_nbits(proto);
+
+	if (spi_nor_protocol_is_dtr(proto)) {
+		/*
+		 * spi-mem supports mixed DTR modes, but right now we can only
+		 * have all phases either DTR or STR. IOW, spi-mem can have
+		 * something like 4S-4D-4D, but spi-nor can't. So, set all 4
+		 * phases to either DTR or STR.
+		 */
+		op->cmd.dtr = op->addr.dtr = op->dummy.dtr =
+			op->data.dtr = true;
+
+		/* 2 bytes per clock cycle in DTR mode. */
+		op->dummy.nbytes *= 2;
+
+		ext = spi_nor_get_cmd_ext(nor, op);
+		op->cmd.opcode = (op->cmd.opcode << 8) | ext;
+		op->cmd.nbytes = 2;
+	}
+}
+
 static int spi_nor_read_write_reg(struct spi_nor *nor, struct spi_mem_op
 		*op, void *buf)
 {
@@ -191,6 +261,8 @@ static int spi_nor_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 					  SPI_MEM_OP_DATA_IN(len, NULL, 1));
 	int ret;
 
+	spi_nor_setup_op(nor, &op, nor->reg_proto);
+
 	ret = spi_nor_read_write_reg(nor, &op, val);
 	if (ret < 0)
 		dev_dbg(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
@@ -206,6 +278,8 @@ static int spi_nor_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
 					  SPI_MEM_OP_NO_DUMMY,
 					  SPI_MEM_OP_DATA_OUT(len, NULL, 1));
 
+	spi_nor_setup_op(nor, &op, nor->reg_proto);
+
 	return spi_nor_read_write_reg(nor, &op, buf);
 }
 
@@ -220,14 +294,12 @@ static ssize_t spi_nor_read_data(struct spi_nor *nor, loff_t from, size_t len,
 	size_t remaining = len;
 	int ret;
 
-	/* get transfer protocols. */
-	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
-	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
-	op.dummy.buswidth = op.addr.buswidth;
-	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+	spi_nor_setup_op(nor, &op, nor->read_proto);
 
 	/* convert the dummy cycles to the number of bytes */
 	op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+	if (spi_nor_protocol_is_dtr(nor->read_proto))
+		op.dummy.nbytes *= 2;
 
 	while (remaining) {
 		op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
@@ -257,14 +329,11 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
 				   SPI_MEM_OP_DATA_OUT(len, buf, 1));
 	int ret;
 
-	/* get transfer protocols. */
-	op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
-	op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
-	op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
-
 	if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
 		op.addr.nbytes = 0;
 
+	spi_nor_setup_op(nor, &op, nor->write_proto);
+
 	ret = spi_mem_adjust_op_size(nor->spi, &op);
 	if (ret)
 		return ret;
@@ -666,6 +735,8 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr)
 			   SPI_MEM_OP_NO_DUMMY,
 			   SPI_MEM_OP_NO_DATA);
 
+	spi_nor_setup_op(nor, &op, nor->write_proto);
+
 	if (nor->erase)
 		return nor->erase(nor, addr);
 
@@ -2183,6 +2254,13 @@ static int spi_nor_init_params(struct spi_nor *nor,
 	spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP],
 				SPINOR_OP_PP, 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(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+				SPINOR_OP_PP, SNOR_PROTO_8_8_8_DTR);
+
 	if (info->flags & SPI_NOR_QUAD_READ) {
 		params->hwcaps.mask |= SNOR_HWCAPS_PP_1_1_4;
 		spi_nor_set_pp_settings(&params->page_programs[SNOR_CMD_PP_1_1_4],
@@ -2216,7 +2294,8 @@ static int spi_nor_init_params(struct spi_nor *nor,
 	/* Override the parameters with data read from SFDP tables. */
 	nor->addr_width = 0;
 	nor->mtd.erasesize = 0;
-	if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)) &&
+	if ((info->flags & (SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
+	     SPI_NOR_OCTAL_DTR_READ)) &&
 	    !(info->flags & SPI_NOR_SKIP_SFDP)) {
 		struct spi_nor_flash_parameter sfdp_params;
 
@@ -2263,6 +2342,7 @@ static int spi_nor_hwcaps_read2cmd(u32 hwcaps)
 		{ SNOR_HWCAPS_READ_1_8_8,	SNOR_CMD_READ_1_8_8 },
 		{ SNOR_HWCAPS_READ_8_8_8,	SNOR_CMD_READ_8_8_8 },
 		{ SNOR_HWCAPS_READ_1_8_8_DTR,	SNOR_CMD_READ_1_8_8_DTR },
+		{ SNOR_HWCAPS_READ_8_8_8_DTR,	SNOR_CMD_READ_8_8_8_DTR },
 	};
 
 	return spi_nor_hwcaps2cmd(hwcaps, hwcaps_read2cmd,
@@ -2279,6 +2359,7 @@ static int spi_nor_hwcaps_pp2cmd(u32 hwcaps)
 		{ SNOR_HWCAPS_PP_1_1_8,		SNOR_CMD_PP_1_1_8 },
 		{ SNOR_HWCAPS_PP_1_8_8,		SNOR_CMD_PP_1_8_8 },
 		{ SNOR_HWCAPS_PP_8_8_8,		SNOR_CMD_PP_8_8_8 },
+		{ SNOR_HWCAPS_PP_8_8_8_DTR,	SNOR_CMD_PP_8_8_8_DTR },
 	};
 
 	return spi_nor_hwcaps2cmd(hwcaps, hwcaps_pp2cmd,
@@ -2377,11 +2458,8 @@ spi_nor_adjust_hwcaps(struct spi_nor *nor,
 {
 	unsigned int cap;
 
-	/* DTR modes are not supported yet, mask them all. */
-	*hwcaps &= ~SNOR_HWCAPS_DTR;
-
-	/* X-X-X modes are not supported yet, mask them all. */
-	*hwcaps &= ~SNOR_HWCAPS_X_X_X;
+	/* Some modes are not supported yet. Mask them. */
+	*hwcaps &= ~SNOR_HWCAPS_UNSUPP;
 
 	for (cap = 0; cap < sizeof(*hwcaps) * BITS_PER_BYTE; cap++) {
 		int rdidx, ppidx;
@@ -2574,6 +2652,7 @@ static int spi_nor_init(struct spi_nor *nor)
 	}
 
 	if (nor->addr_width == 4 &&
+	    !(nor->info->flags & SPI_NOR_OCTAL_DTR_READ) &&
 	    (JEDEC_MFR(nor->info) != SNOR_MFR_SPANSION) &&
 	    !(nor->info->flags & SPI_NOR_4B_OPCODES)) {
 		/*
@@ -2696,6 +2775,9 @@ int spi_nor_scan(struct spi_nor *nor)
 
 	if (nor->addr_width) {
 		/* already configured from SFDP */
+	} else if (spi_nor_protocol_is_dtr(nor->read_proto)) {
+		 /* Always use 4-byte addresses in DTR mode. */
+		nor->addr_width = 4;
 	} else if (info->addr_width) {
 		nor->addr_width = info->addr_width;
 	} else if (mtd->size > SZ_16M) {
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4a11999eeb..155aa4331a 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -199,6 +199,7 @@ enum spi_nor_protocol {
 	SNOR_PROTO_1_2_2_DTR = SNOR_PROTO_DTR(1, 2, 2),
 	SNOR_PROTO_1_4_4_DTR = SNOR_PROTO_DTR(1, 4, 4),
 	SNOR_PROTO_1_8_8_DTR = SNOR_PROTO_DTR(1, 8, 8),
+	SNOR_PROTO_8_8_8_DTR = SNOR_PROTO_DTR(8, 8, 8),
 };
 
 static inline bool spi_nor_protocol_is_dtr(enum spi_nor_protocol proto)
@@ -266,7 +267,7 @@ struct spi_nor_hwcaps {
  * then Quad SPI protocols before Dual SPI protocols, Fast Read and lastly
  * (Slow) Read.
  */
-#define SNOR_HWCAPS_READ_MASK		GENMASK(14, 0)
+#define SNOR_HWCAPS_READ_MASK		GENMASK(15, 0)
 #define SNOR_HWCAPS_READ		BIT(0)
 #define SNOR_HWCAPS_READ_FAST		BIT(1)
 #define SNOR_HWCAPS_READ_1_1_1_DTR	BIT(2)
@@ -283,11 +284,12 @@ struct spi_nor_hwcaps {
 #define SNOR_HWCAPS_READ_4_4_4		BIT(9)
 #define SNOR_HWCAPS_READ_1_4_4_DTR	BIT(10)
 
-#define SNOR_HWCPAS_READ_OCTO		GENMASK(14, 11)
+#define SNOR_HWCPAS_READ_OCTO		GENMASK(15, 11)
 #define SNOR_HWCAPS_READ_1_1_8		BIT(11)
 #define SNOR_HWCAPS_READ_1_8_8		BIT(12)
 #define SNOR_HWCAPS_READ_8_8_8		BIT(13)
 #define SNOR_HWCAPS_READ_1_8_8_DTR	BIT(14)
+#define SNOR_HWCAPS_READ_8_8_8_DTR	BIT(15)
 
 /*
  * Page Program capabilities.
@@ -298,24 +300,23 @@ struct spi_nor_hwcaps {
  * JEDEC/SFDP standard to define them. Also at this moment no SPI flash memory
  * implements such commands.
  */
-#define SNOR_HWCAPS_PP_MASK	GENMASK(22, 16)
-#define SNOR_HWCAPS_PP		BIT(16)
+#define SNOR_HWCAPS_PP_MASK		GENMASK(23, 16)
+#define SNOR_HWCAPS_PP			BIT(16)
 
-#define SNOR_HWCAPS_PP_QUAD	GENMASK(19, 17)
-#define SNOR_HWCAPS_PP_1_1_4	BIT(17)
-#define SNOR_HWCAPS_PP_1_4_4	BIT(18)
-#define SNOR_HWCAPS_PP_4_4_4	BIT(19)
+#define SNOR_HWCAPS_PP_QUAD		GENMASK(19, 17)
+#define SNOR_HWCAPS_PP_1_1_4		BIT(17)
+#define SNOR_HWCAPS_PP_1_4_4		BIT(18)
+#define SNOR_HWCAPS_PP_4_4_4		BIT(19)
 
-#define SNOR_HWCAPS_PP_OCTO	GENMASK(22, 20)
-#define SNOR_HWCAPS_PP_1_1_8	BIT(20)
-#define SNOR_HWCAPS_PP_1_8_8	BIT(21)
-#define SNOR_HWCAPS_PP_8_8_8	BIT(22)
+#define SNOR_HWCAPS_PP_OCTO		GENMASK(23, 20)
+#define SNOR_HWCAPS_PP_1_1_8		BIT(20)
+#define SNOR_HWCAPS_PP_1_8_8		BIT(21)
+#define SNOR_HWCAPS_PP_8_8_8		BIT(22)
+#define SNOR_HWCAPS_PP_8_8_8_DTR	BIT(23)
 
-#define SNOR_HWCAPS_X_X_X	(SNOR_HWCAPS_READ_2_2_2 |	\
+#define SNOR_HWCAPS_UNSUPP	(SNOR_HWCAPS_READ_2_2_2 |	\
 				 SNOR_HWCAPS_READ_4_4_4 |	\
-				 SNOR_HWCAPS_READ_8_8_8 |	\
-				 SNOR_HWCAPS_PP_4_4_4 |		\
-				 SNOR_HWCAPS_PP_8_8_8)
+				 SNOR_HWCAPS_PP_4_4_4)
 
 #define SNOR_HWCAPS_DTR		(SNOR_HWCAPS_READ_1_1_1_DTR |	\
 				 SNOR_HWCAPS_READ_1_2_2_DTR |	\
@@ -359,6 +360,7 @@ enum spi_nor_read_command_index {
 	SNOR_CMD_READ_1_8_8,
 	SNOR_CMD_READ_8_8_8,
 	SNOR_CMD_READ_1_8_8_DTR,
+	SNOR_CMD_READ_8_8_8_DTR,
 
 	SNOR_CMD_READ_MAX
 };
@@ -375,6 +377,7 @@ enum spi_nor_pp_command_index {
 	SNOR_CMD_PP_1_1_8,
 	SNOR_CMD_PP_1_8_8,
 	SNOR_CMD_PP_8_8_8,
+	SNOR_CMD_PP_8_8_8_DTR,
 
 	SNOR_CMD_PP_MAX
 };
@@ -390,6 +393,22 @@ struct spi_nor_flash_parameter {
 	int (*quad_enable)(struct spi_nor *nor);
 };
 
+/**
+ * enum spi_nor_cmd_ext - describes the command opcode extension in DTR mode
+ * @SPI_MEM_NOR_NONE: no extension. This is the default, and is used in Legacy
+ *		      SPI mode
+ * @SPI_MEM_NOR_REPEAT: the extension is same as the opcode
+ * @SPI_MEM_NOR_INVERT: the extension is the bitwise inverse of the opcode
+ * @SPI_MEM_NOR_HEX: the extension is any hex value. The command and opcode
+ *		     combine to form a 16-bit opcode.
+ */
+enum spi_nor_cmd_ext {
+	SPI_NOR_EXT_NONE = 0,
+	SPI_NOR_EXT_REPEAT,
+	SPI_NOR_EXT_INVERT,
+	SPI_NOR_EXT_HEX,
+};
+
 /**
  * struct flash_info - Forward declaration of a structure used internally by
  *		       spi_nor_scan()
@@ -427,6 +446,7 @@ struct flash_info;
  * @write_proto:	the SPI protocol for write operations
  * @reg_proto		the SPI protocol for read_reg/write_reg/erase operations
  * @cmd_buf:		used by the write_reg
+ * @cmd_ext_type:	the command opcode extension for DTR mode.
  * @prepare:		[OPTIONAL] do some preparations for the
  *			read/write/erase/lock/unlock operations
  * @unprepare:		[OPTIONAL] do some post work after the
@@ -468,6 +488,7 @@ struct spi_nor {
 	bool			sst_write_second;
 	u32			flags;
 	u8			cmd_buf[SPI_NOR_MAX_CMD_SIZE];
+	enum spi_nor_cmd_ext	cmd_ext_type;
 
 	int (*setup)(struct spi_nor *nor, const struct flash_info *info,
 		     const struct spi_nor_flash_parameter *params,
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (8 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 09/17] mtd: spi-nor-core: Add support for DTR protocol Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-05-18 14:31   ` Pragnesh Patel
  2020-03-30 15:45 ` [PATCH v3 11/17] mtd: spi-nor-core: Parse xSPI Profile 1.0 table Pratyush Yadav
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Some devices in DTR mode expect an extra command byte called the
extension. The extension can either be same as the opcode, bitwise
inverse of the opcode, or another additional byte forming a 16-byte
opcode. Get the extension type from the BFPT. For now, only flashes with
"repeat" and "inverse" extensions are supported.

As of JESD216D.01, BFPT is 20 DWORDs, so update the table size to
reflect that.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index d3f05e1ded..684a8c3216 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -75,11 +75,11 @@ struct sfdp_header {
 /* Basic Flash Parameter Table */
 
 /*
- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
+ * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
  * They are indexed from 1 but C arrays are indexed from 0.
  */
 #define BFPT_DWORD(i)		((i) - 1)
-#define BFPT_DWORD_MAX		16
+#define BFPT_DWORD_MAX		20
 
 /* The first version of JESB216 defined only 9 DWORDs. */
 #define BFPT_DWORD_MAX_JESD216			9
@@ -144,6 +144,12 @@ struct sfdp_header {
 #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD		(0x4UL << 20)
 #define BFPT_DWORD15_QER_SR2_BIT1		(0x5UL << 20) /* Spansion */
 
+#define BFPT_DWORD18_CMD_EXT_MASK		GENMASK(30, 29)
+#define BFPT_DWORD18_CMD_EXT_REP		(0x0UL << 29) /* Repeat */
+#define BFPT_DWORD18_CMD_EXT_INV		(0x1UL << 29) /* Invert */
+#define BFPT_DWORD18_CMD_EXT_RES		(0x2UL << 29) /* Reserved */
+#define BFPT_DWORD18_CMD_EXT_16B		(0x3UL << 29) /* 16-bit opcode */
+
 struct sfdp_bfpt {
 	u32	dwords[BFPT_DWORD_MAX];
 };
@@ -2021,6 +2027,24 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 		return -EINVAL;
 	}
 
+	/* 8D-8D-8D command extension. */
+	switch (bfpt.dwords[BFPT_DWORD(18)] & BFPT_DWORD18_CMD_EXT_MASK) {
+	case BFPT_DWORD18_CMD_EXT_REP:
+		nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+		break;
+
+	case BFPT_DWORD18_CMD_EXT_INV:
+		nor->cmd_ext_type = SPI_NOR_EXT_INVERT;
+		break;
+
+	case BFPT_DWORD18_CMD_EXT_RES:
+		return -EINVAL;
+
+	case BFPT_DWORD18_CMD_EXT_16B:
+		dev_err(nor->dev, "16-bit opcodes not supported\n");
+		return -ENOTSUPP;
+	}
+
 	return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
 }
 
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 11/17] mtd: spi-nor-core: Parse xSPI Profile 1.0 table
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (9 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 12/17] mtd: spi-nor-core: Prepare Read SR and FSR for Octal DTR mode Pratyush Yadav
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

This table is indication that the flash is xSPI compliant and hence
supports octal DTR mode. Extract information like the fast read opcode,
the number of dummy cycles needed for a Read Status Register command,
and the number of address bytes needed for a Read Status Register
command.

The default dummy cycles for a fast octal DTR read are set to 20. Since
there is no simple way of determining the dummy cycles needed for the
fast read command, flashes that use a different value should update it
in their flash-specific hooks.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 81 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    |  7 +++
 2 files changed, 88 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 684a8c3216..ab9bdee43b 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -17,6 +17,7 @@
 #include <linux/log2.h>
 #include <linux/math64.h>
 #include <linux/sizes.h>
+#include <linux/bitfield.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/spi-nor.h>
@@ -54,6 +55,7 @@ struct sfdp_parameter_header {
 #define SFDP_BFPT_ID		0xff00	/* Basic Flash Parameter Table */
 #define SFDP_SECTOR_MAP_ID	0xff81	/* Sector Map Table */
 #define SFDP_SST_ID		0x01bf	/* Manufacturer specific Table */
+#define SFDP_PROFILE1_ID	0xff05	/* xSPI Profile 1.0 Table */
 
 #define SFDP_SIGNATURE		0x50444653U
 #define SFDP_JESD216_MAJOR	1
@@ -150,6 +152,11 @@ struct sfdp_header {
 #define BFPT_DWORD18_CMD_EXT_RES		(0x2UL << 29) /* Reserved */
 #define BFPT_DWORD18_CMD_EXT_16B		(0x3UL << 29) /* 16-bit opcode */
 
+/* xSPI Profile 1.0 table (from JESD216D.01). */
+#define PROFILE1_DWORD1_RD_FAST_CMD		GENMASK(15, 8)
+#define PROFILE1_DWORD1_RDSR_DUMMY		BIT(28)
+#define PROFILE1_DWORD1_RDSR_ADDR_BYTES		BIT(29)
+
 struct sfdp_bfpt {
 	u32	dwords[BFPT_DWORD_MAX];
 };
@@ -2048,6 +2055,74 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 	return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);
 }
 
+/**
+ * spi_nor_parse_profile1() - parse the xSPI Profile 1.0 table
+ * @nor:		pointer to a 'struct spi_nor'
+ * @param_header:	pointer to the 'struct sfdp_parameter_header' describing
+ *			the 4-Byte Address Instruction Table length and version.
+ * @params:		pointer to the 'struct spi_nor_flash_parameter' to be.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_parse_profile1(struct spi_nor *nor,
+				  const struct sfdp_parameter_header *profile1_header,
+				  struct spi_nor_flash_parameter *params)
+{
+	u32 *table, opcode, addr;
+	size_t len;
+	int ret, i;
+
+	len = profile1_header->length * sizeof(*table);
+	table = kmalloc(len, GFP_KERNEL);
+	if (!table)
+		return -ENOMEM;
+
+	addr = SFDP_PARAM_HEADER_PTP(profile1_header);
+	ret = spi_nor_read_sfdp(nor, addr, len, table);
+	if (ret)
+		goto out;
+
+	/* Fix endianness of the table DWORDs. */
+	for (i = 0; i < profile1_header->length; i++)
+		table[i] = le32_to_cpu(table[i]);
+
+	/* Get 8D-8D-8D fast read opcode and dummy cycles. */
+	opcode = FIELD_GET(PROFILE1_DWORD1_RD_FAST_CMD, table[0]);
+
+	/*
+	 * Update the fast read settings. We set the default dummy cycles to 20
+	 * here. Flashes can change this value if they need to when enabling
+	 * octal mode.
+	 */
+	params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+	spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+				  0, 20, opcode,
+				  SNOR_PROTO_8_8_8_DTR);
+
+	/*
+	 * Since the flash supports xSPI DTR reads, it should also support DTR
+	 * Page Program opcodes.
+	 */
+	params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+	/*
+	 * Set the Read Status Register dummy cycles and dummy address bytes.
+	 */
+	if (table[0] & PROFILE1_DWORD1_RDSR_DUMMY)
+		params->rdsr_dummy = 8;
+	else
+		params->rdsr_dummy = 4;
+
+	if (table[0] & PROFILE1_DWORD1_RDSR_ADDR_BYTES)
+		params->rdsr_addr_nbytes = 4;
+	else
+		params->rdsr_addr_nbytes = 0;
+
+out:
+	kfree(table);
+	return ret;
+}
+
 /**
  * spi_nor_parse_microchip_sfdp() - parse the Microchip manufacturer specific
  * SFDP table.
@@ -2176,6 +2251,10 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 			err = spi_nor_parse_microchip_sfdp(nor, param_header);
 			break;
 
+		case SFDP_PROFILE1_ID:
+			err = spi_nor_parse_profile1(nor, param_header, params);
+			break;
+
 		default:
 			break;
 		}
@@ -2833,6 +2912,8 @@ int spi_nor_scan(struct spi_nor *nor)
 	if (ret)
 		return ret;
 
+	nor->rdsr_dummy = params.rdsr_dummy;
+	nor->rdsr_addr_nbytes = params.rdsr_addr_nbytes;
 	nor->name = mtd->name;
 	nor->size = mtd->size;
 	nor->erase_size = mtd->erasesize;
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 155aa4331a..4b3b81ce67 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -385,6 +385,8 @@ enum spi_nor_pp_command_index {
 struct spi_nor_flash_parameter {
 	u64				size;
 	u32				page_size;
+	u8				rdsr_dummy;
+	u8				rdsr_addr_nbytes;
 
 	struct spi_nor_hwcaps		hwcaps;
 	struct spi_nor_read_command	reads[SNOR_CMD_READ_MAX];
@@ -437,6 +439,9 @@ struct flash_info;
  * @read_opcode:	the read opcode
  * @read_dummy:		the dummy needed by the read operation
  * @program_opcode:	the program opcode
+ * @rdsr_dummy		dummy cycles needed for Read Status Register command.
+ * @rdsr_addr_nbytes:	dummy address bytes needed for Read Status Register
+ *			command.
  * @bank_read_cmd:	Bank read cmd
  * @bank_write_cmd:	Bank write cmd
  * @bank_curr:		Current flash bank
@@ -477,6 +482,8 @@ struct spi_nor {
 	u8			read_opcode;
 	u8			read_dummy;
 	u8			program_opcode;
+	u8			rdsr_dummy;
+	u8			rdsr_addr_nbytes;
 #ifdef CONFIG_SPI_FLASH_BAR
 	u8			bank_read_cmd;
 	u8			bank_write_cmd;
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 12/17] mtd: spi-nor-core: Prepare Read SR and FSR for Octal DTR mode
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (10 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 11/17] mtd: spi-nor-core: Parse xSPI Profile 1.0 table Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 13/17] mtd: spi-nor-core: Enable octal DTR mode when possible Pratyush Yadav
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

The xSPI Profile 1.0 table specifies how many dummy cycles and address
bytes are needed for the Read Status Register command in Octal DTR mode.
Use that information to send the correct Read SR command.

Some controllers might have trouble reading just 1 byte in DTR mode. So,
when we are in DTR mode read 2 bytes and discard the second. This shows
no side effects with the two flashes I tested: Micron mt35xu512aba and
Cypress s28hs512t.

Update Read FSR to mimic Read SR because they share the same
characteristics.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 43 +++++++++++++++++++++++++++++-----
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index ab9bdee43b..9361b5c121 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -367,15 +367,30 @@ static ssize_t spi_nor_write_data(struct spi_nor *nor, loff_t to, size_t len,
 static int read_sr(struct spi_nor *nor)
 {
 	int ret;
-	u8 val;
+	u8 val[2];
+	u8 addr_nbytes = nor->rdsr_addr_nbytes;
+	u8 dummy = nor->rdsr_dummy;
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDSR, 1),
+					  SPI_MEM_OP_ADDR(addr_nbytes, 0, 1),
+					  SPI_MEM_OP_DUMMY(dummy, 1),
+					  SPI_MEM_OP_DATA_IN(1, NULL, 1));
+
+	spi_nor_setup_op(nor, &op, nor->reg_proto);
 
-	ret = nor->read_reg(nor, SPINOR_OP_RDSR, &val, 1);
+	/*
+	 * We don't want to read only one byte in DTR mode. So, read 2 and then
+	 * discard the second byte.
+	 */
+	if (spi_nor_protocol_is_dtr(nor->reg_proto))
+		op.data.nbytes = 2;
+
+	ret = spi_nor_read_write_reg(nor, &op, val);
 	if (ret < 0) {
 		pr_debug("error %d reading SR\n", (int)ret);
 		return ret;
 	}
 
-	return val;
+	return *val;
 }
 
 /*
@@ -386,15 +401,31 @@ static int read_sr(struct spi_nor *nor)
 static int read_fsr(struct spi_nor *nor)
 {
 	int ret;
-	u8 val;
+	u8 val[2];
+	u8 addr_nbytes = nor->rdsr_addr_nbytes;
+	u8 dummy = nor->rdsr_dummy;
 
-	ret = nor->read_reg(nor, SPINOR_OP_RDFSR, &val, 1);
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RDFSR, 1),
+					  SPI_MEM_OP_ADDR(addr_nbytes, 0, 1),
+					  SPI_MEM_OP_DUMMY(dummy, 1),
+					  SPI_MEM_OP_DATA_IN(1, NULL, 1));
+
+	spi_nor_setup_op(nor, &op, nor->reg_proto);
+
+	/*
+	 * We don't want to read only one byte in DTR mode. So, read 2 and then
+	 * discard the second byte.
+	 */
+	if (spi_nor_protocol_is_dtr(nor->reg_proto))
+		op.data.nbytes = 2;
+
+	ret = spi_nor_read_write_reg(nor, &op, val);
 	if (ret < 0) {
 		pr_debug("error %d reading FSR\n", ret);
 		return ret;
 	}
 
-	return val;
+	return *val;
 }
 
 /*
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 13/17] mtd: spi-nor-core: Enable octal DTR mode when possible
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (11 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 12/17] mtd: spi-nor-core: Prepare Read SR and FSR for Octal DTR mode Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown Pratyush Yadav
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Allow flashes to specify a hook to enable octal DTR mode. Use this hook
whenever possible to get optimal transfer speeds.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/spi-nor-core.c | 31 +++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    |  2 ++
 2 files changed, 33 insertions(+)

diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 9361b5c121..5b995cda3f 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2760,10 +2760,41 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
 	return nor->setup(nor, info, params, hwcaps);
 }
 
+/** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
+ * @nor:                 pointer to a 'struct spi_nor'
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_octal_dtr_enable(struct spi_nor *nor)
+{
+	int ret;
+
+	if (!nor->octal_dtr_enable)
+		return 0;
+
+	if (!(spi_nor_get_protocol_width(nor->read_proto) == 8 ||
+	      spi_nor_get_protocol_width(nor->write_proto) == 8))
+		return 0;
+
+	ret = nor->octal_dtr_enable(nor);
+	if (ret)
+		return ret;
+
+	nor->reg_proto = SNOR_PROTO_8_8_8_DTR;
+
+	return 0;
+}
+
 static int spi_nor_init(struct spi_nor *nor)
 {
 	int err;
 
+	err = spi_nor_octal_dtr_enable(nor);
+	if (err) {
+		dev_dbg(nor->dev, "Octal DTR mode not supported\n");
+		return err;
+	}
+
 	/*
 	 * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up
 	 * with the software protection bits set
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 4b3b81ce67..defd0d2d3d 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -468,6 +468,7 @@ struct flash_info;
  * @flash_is_locked:	[FLASH-SPECIFIC] check if a region of the SPI NOR is
  * @quad_enable:	[FLASH-SPECIFIC] enables SPI NOR quad mode
  *			completely locked
+ * @octal_dtr_enable:	[FLASH-SPECIFIC] enables SPI NOR octal DTR mode.
  * @priv:		the private data
  */
 struct spi_nor {
@@ -515,6 +516,7 @@ struct spi_nor {
 	int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 	int (*flash_is_locked)(struct spi_nor *nor, loff_t ofs, uint64_t len);
 	int (*quad_enable)(struct spi_nor *nor);
+	int (*octal_dtr_enable)(struct spi_nor *nor);
 
 	void *priv;
 /* Compatibility for spi_flash, remove once sf layer is merged with mtd */
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (12 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 13/17] mtd: spi-nor-core: Enable octal DTR mode when possible Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-05-13  6:44   ` Jagan Teki
  2020-03-30 15:45 ` [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot Pratyush Yadav
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

On probe, the SPI NOR core will put a flash in 8D-8D-8D mode if it
supports it. But Linux as of now expects to get the flash in 1S-1S-1S
mode. Handing the flash to Linux in Octal DTR mode means the kernel will
fail to detect the flash.

So, we need to reset to Power-on-Reset (POR) state before handing off
the flash. A Software Reset command can be used to do this. Since the
command is optional, flashes have to specify they support it by using
the flag 'SPI_NOR_SOFT_RESET'.

One limitation of the soft reset is that it will restore state from
non-volatile registers in some flashes. This means that if the flash was
set to 8D mode in a non-volatile configuration, a soft reset won't help.
This commit assumes that we don't set any non-volatile bits anywhere,
and the flash doesn't have any non-volatile Octal DTR mode
configuration.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/sf_internal.h  |  1 +
 drivers/mtd/spi/sf_probe.c     |  9 +++++
 drivers/mtd/spi/spi-nor-core.c | 66 ++++++++++++++++++++++++++++++++++
 include/linux/mtd/spi-nor.h    | 11 ++++++
 4 files changed, 87 insertions(+)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 5780c81287..37e6657490 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -68,6 +68,7 @@ struct flash_info {
 #define SPI_NOR_HAS_SST26LOCK	BIT(15)	/* Flash supports lock/unlock via BPR */
 #define SPI_NOR_OCTAL_READ      BIT(16) /* Flash supports Octal Read */
 #define SPI_NOR_OCTAL_DTR_READ	BIT(17)	/* Flash supports Octal DTR Read */
+#define SPI_NOR_SOFT_RESET	BIT(18)	/* Flash supports soft reset command */
 
 	/* Part specific fixup hooks. */
 	const struct spi_nor_fixups *fixups;
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index 72b6ee702d..90bd3196c2 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -152,6 +152,14 @@ int spi_flash_std_probe(struct udevice *dev)
 
 static int spi_flash_std_remove(struct udevice *dev)
 {
+	struct spi_flash *flash;
+	int ret;
+
+	flash = dev_get_uclass_priv(dev);
+	ret = spi_nor_remove(flash);
+	if (ret)
+		return ret;
+
 #if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
 	spi_flash_mtd_unregister();
 #endif
@@ -178,6 +186,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
 	.remove		= spi_flash_std_remove,
 	.priv_auto_alloc_size = sizeof(struct spi_flash),
 	.ops		= &spi_flash_std_ops,
+	.flags		= DM_FLAG_OS_PREPARE,
 };
 
 #endif /* CONFIG_DM_SPI_FLASH */
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 5b995cda3f..52b3775035 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -186,6 +186,8 @@ struct spi_nor_fixups {
 			  struct spi_nor_flash_parameter *params);
 };
 
+#define SPI_NOR_SRST_SLEEP_LEN			200
+
 /**
  * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
  *			   extension type.
@@ -2835,6 +2837,67 @@ static int spi_nor_init(struct spi_nor *nor)
 	return 0;
 }
 
+/**
+ * spi_nor_soft_reset() - perform the JEDEC Software Reset sequence
+ * @nor:	the spi_nor structure
+ *
+ * This function can be used to switch from Octal DTR mode to legacy mode on a
+ * flash that supports it. The soft reset is executed in Octal DTR mode.
+ *
+ * Return: 0 for success, -errno for failure.
+ */
+static int spi_nor_soft_reset(struct spi_nor *nor)
+{
+	struct spi_mem_op op;
+	int ret;
+	enum spi_nor_cmd_ext ext;
+
+	ext = nor->cmd_ext_type;
+	nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+
+	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 8),
+			SPI_MEM_OP_NO_DUMMY,
+			SPI_MEM_OP_NO_ADDR,
+			SPI_MEM_OP_NO_DATA);
+	spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_warn(nor->dev, "Software reset enable failed: %d\n", ret);
+		goto out;
+	}
+
+	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 8),
+			SPI_MEM_OP_NO_DUMMY,
+			SPI_MEM_OP_NO_ADDR,
+			SPI_MEM_OP_NO_DATA);
+	spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_warn(nor->dev, "Software reset failed: %d\n", ret);
+		goto out;
+	}
+
+	/*
+	 * Software Reset is not instant, and the delay varies from flash to
+	 * flash. Looking at a few flashes, most range somewhere below 100
+	 * microseconds. So, wait for 200ms just to be sure.
+	 */
+	udelay(SPI_NOR_SRST_SLEEP_LEN);
+
+out:
+	nor->cmd_ext_type = ext;
+	return ret;
+}
+
+int spi_nor_remove(struct spi_nor *nor)
+{
+	if (nor->info->flags & SPI_NOR_OCTAL_DTR_READ &&
+	    nor->flags & SNOR_F_SOFT_RESET)
+		return spi_nor_soft_reset(nor);
+
+	return 0;
+}
+
 int spi_nor_scan(struct spi_nor *nor)
 {
 	struct spi_nor_flash_parameter params;
@@ -2917,6 +2980,9 @@ int spi_nor_scan(struct spi_nor *nor)
 	if (info->flags & USE_CLSR)
 		nor->flags |= SNOR_F_USE_CLSR;
 
+	if (info->flags & SPI_NOR_SOFT_RESET)
+		nor->flags |= SNOR_F_SOFT_RESET;
+
 	if (info->flags & SPI_NOR_NO_ERASE)
 		mtd->flags |= MTD_NO_ERASE;
 
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index defd0d2d3d..58992f02b4 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -66,6 +66,8 @@
 #define SPINOR_OP_CLFSR		0x50	/* Clear flag status register */
 #define SPINOR_OP_RDEAR		0xc8	/* Read Extended Address Register */
 #define SPINOR_OP_WREAR		0xc5	/* Write Extended Address Register */
+#define SPINOR_OP_SRSTEN	0x66	/* Software Reset Enable */
+#define SPINOR_OP_SRST		0x99	/* Software Reset */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
 #define SPINOR_OP_READ_4B	0x13	/* Read data bytes (low frequency) */
@@ -247,6 +249,7 @@ enum spi_nor_option_flags {
 	SNOR_F_READY_XSR_RDY	= BIT(4),
 	SNOR_F_USE_CLSR		= BIT(5),
 	SNOR_F_BROKEN_RESET	= BIT(6),
+	SNOR_F_SOFT_RESET	= BIT(7),
 };
 
 struct spi_nor;
@@ -550,4 +553,12 @@ device_node *spi_nor_get_flash_node(struct spi_nor *nor)
  */
 int spi_nor_scan(struct spi_nor *nor);
 
+/**
+ * spi_nor_remove() - perform cleanup before booting to the next stage
+ * @nor:	the spi_nor structure
+ *
+ * Return: 0 for success, -errno for failure.
+ */
+int spi_nor_remove(struct spi_nor *nor);
+
 #endif
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (13 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-05-13  6:47   ` Jagan Teki
  2020-03-30 15:45 ` [PATCH v3 16/17] mtd: spi-nor-core: Add support for Cypress Semper flash Pratyush Yadav
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
difficult to detect the mode the flash is in. One option is to read SFDP
in all modes and see which one gives the correct "SFDP" signature, but
not all flashes support SFDP in 8D-8D-8D mode.

Further, even if you detect the mode of the flash via SFDP, you still
have the problem of actually reading the ID. The Read ID command is not
standardized across flash vendors. Flashes can have different dummy
cycles needed for reading the ID. Some flashes even expect a 4-byte
dummy address with the Read ID command. All this information cannot be
obtained from the SFDP table.

So, perform a Software Reset sequence before reading the ID and
initializing the flash. A Soft Reset will bring back the flash in its
default protocol mode assuming no non-volatile configuration was set.
This will let us detect the flash even if ROM hands it to us in Octal
DTR mode.

To accommodate cases where there is more than one flash on a board, and
only one of them needs a soft reset, failure to reset is not made fatal,
and we still try to read ID if possible.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/Kconfig        | 11 +++++++++++
 drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
 2 files changed, 38 insertions(+)

diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
index 018e8c597e..38d509c568 100644
--- a/drivers/mtd/spi/Kconfig
+++ b/drivers/mtd/spi/Kconfig
@@ -88,6 +88,17 @@ config SPI_FLASH_SFDP_SUPPORT
 	 SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
 	 tables as per JESD216 standard.
 
+config SPI_FLASH_SOFT_RESET
+	bool "Software Reset support for SPI NOR flashes"
+	help
+	 Enable support for xSPI Software Reset. It will be used to switch
+	 from Octal DTR mode to legacy mode to allow detecting flashes that
+	 are handed to us in Octal DTR mode. It is expected that if the config
+	 is enabled the flash supports the Soft Reset sequence and is booted in
+	 Octal DTR mode. Do not enable this config on flashes that are not
+	 supposed to be handed to U-Boot in Octal DTR mode, even if they _do_
+	 support the Soft Reset sequence.
+
 config SPI_FLASH_BAR
 	bool "SPI flash Bank/Extended address register support"
 	help
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 52b3775035..3af2c6afa9 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
 
 	nor->setup = spi_nor_default_setup;
 
+#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
+	/*
+	 * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
+	 * is difficult to detect the mode the flash is in. One option is to
+	 * read SFDP in all modes and see which one gives the correct "SFDP"
+	 * signature, but not all flashes support SFDP in 8D-8D-8D mode.
+	 *
+	 * Further, even if you detect the mode of the flash via SFDP, you
+	 * still have the problem of actually reading the ID. The Read ID
+	 * command is not standardized across flash vendors. Flashes can have
+	 * different dummy cycles needed for reading the ID. Some flashes even
+	 * expect a 4-byte dummy address with the Read ID command. All this
+	 * information cannot be obtained from the SFDP table.
+	 *
+	 * So, perform a Software Reset sequence before reading the ID and
+	 * initializing the flash. A Soft Reset will bring back the flash in
+	 * its default protocol mode assuming no non-volatile configuration was
+	 * set. This will let us detect the flash even if ROM hands it to us in
+	 * Octal DTR mode.
+	 *
+	 * To accommodate cases where there is more than one flash on a board,
+	 * and only one of them needs a soft reset, failure to reset is not
+	 * made fatal, and we still try to read ID if possible.
+	 */
+	spi_nor_soft_reset(nor);
+#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
+
 	info = spi_nor_read_id(nor);
 	if (IS_ERR_OR_NULL(info))
 		return -ENOENT;
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 16/17] mtd: spi-nor-core: Add support for Cypress Semper flash
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (14 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-03-30 15:45 ` [PATCH v3 17/17] mtd: spi-nor-core: Allow using Micron mt35xu512aba in Octal DTR mode Pratyush Yadav
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

The Cypress Semper flash is an xSPI compliant octal DTR flash. Add
support for using it in octal DTR mode.

The flash by default boots in a hybrid sector mode. Switch to uniform
sector mode on boot. Use the default 20 dummy cycles for a read fast
command.

The SFDP programming on some older versions of the flash was incorrect.
Fixes for that are included in the fixup hooks.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/sf_internal.h  |   4 +
 drivers/mtd/spi/spi-nor-core.c | 194 +++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi-nor-ids.c  |   1 +
 include/linux/mtd/spi-nor.h    |  14 +++
 4 files changed, 213 insertions(+)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index 37e6657490..d017c857d0 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -76,6 +76,10 @@ struct flash_info {
 
 extern const struct flash_info spi_nor_ids[];
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+extern struct spi_nor_fixups s28hs512t_fixups;
+#endif
+
 #define JEDEC_MFR(info)	((info)->id[0])
 #define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2]))
 
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index 3af2c6afa9..f6f72f8a32 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2762,6 +2762,200 @@ static int spi_nor_setup(struct spi_nor *nor, const struct flash_info *info,
 	return nor->setup(nor, info, params, hwcaps);
 }
 
+#ifdef CONFIG_SPI_FLASH_SPANSION
+/**
+ * spi_nor_cypress_octal_enable() - Enable octal DTR mode on Cypress flashes.
+ * @nor:		pointer to a 'struct spi_nor'
+ *
+ * This also sets the memory access latency cycles to 20, which is the default
+ * in the spi-nor framework.
+ *
+ * Return: 0 on success, -errno otherwise.
+ */
+static int spi_nor_cypress_octal_enable(struct spi_nor *nor)
+{
+	struct spi_mem_op op;
+	u8 buf;
+	u8 addr_width = 3;
+	int ret;
+
+	/* Use 20 dummy cycles for memory array reads. */
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_8_20;
+	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+			SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR2V, 1),
+			SPI_MEM_OP_NO_DUMMY,
+			SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_warn(nor->dev,
+			 "failed to set default memory latency value: %d\n",
+			 ret);
+		return ret;
+	}
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	nor->read_dummy = 20;
+
+	/* Set the octal and DTR enable bits. */
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN;
+	op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+			SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR5V, 1),
+			SPI_MEM_OP_NO_DUMMY,
+			SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_warn(nor->dev, "Failed to enable octal DTR mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int s28hs512t_setup(struct spi_nor *nor, const struct flash_info *info,
+			   const struct spi_nor_flash_parameter *params,
+			   const struct spi_nor_hwcaps *hwcaps)
+{
+	struct spi_mem_op op;
+	u8 buf;
+	u8 addr_width = 3;
+	int ret;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	/*
+	 * This Cypress flash also supports hybrid sector sizes. Make sure
+	 * uniform sector mode is selected. This is done by setting the bit
+	 * CFR3N[3].
+	 */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+			   SPI_MEM_OP_ADDR(addr_width,
+					   SPINOR_REG_CYPRESS_CFR3V, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_IN(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret)
+		return ret;
+
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	/* Set the uniform sector mode bit. */
+	buf |= SPINOR_REG_CYPRESS_CFR3N_UNISECT;
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1),
+			   SPI_MEM_OP_ADDR(addr_width,
+					   SPINOR_REG_CYPRESS_CFR3N, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_err(nor->dev, "Failed to change to uniform sector mode\n");
+		return ret;
+	}
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	return spi_nor_default_setup(nor, info, params, hwcaps);
+}
+
+static void s28hs512t_default_init(struct spi_nor *nor)
+{
+	nor->octal_dtr_enable = spi_nor_cypress_octal_enable;
+	nor->setup = s28hs512t_setup;
+}
+
+static void s28hs512t_post_sfdp_fixup(struct spi_nor *nor,
+				      struct spi_nor_flash_parameter *params)
+{
+	/*
+	 * 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 (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(&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(&params->page_programs[SNOR_CMD_PP_8_8_8_DTR],
+				SPINOR_OP_PP_4B, SNOR_PROTO_8_8_8_DTR);
+
+	/*
+	 * The xSPI Profile 1.0 table advertises the number of additional
+	 * address bytes needed for Read Status Register command as 0 but the
+	 * actual value for that is 4.
+	 */
+	params->rdsr_addr_nbytes = 4;
+}
+
+static int s28hs512t_post_bfpt_fixup(struct spi_nor *nor,
+				     const struct sfdp_parameter_header *bfpt_header,
+				     const struct sfdp_bfpt *bfpt,
+				     struct spi_nor_flash_parameter *params)
+{
+	struct spi_mem_op op;
+	u8 buf;
+	u8 addr_width = 3;
+	int ret;
+
+	/*
+	 * The BFPT table advertises a 512B page size but the page size is
+	 * actually configurable (with the default being 256B). Read from
+	 * CFR3V[4] and set the correct size.
+	 */
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_RD_ANY_REG, 1),
+			   SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_CYPRESS_CFR3V, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_IN(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret)
+		return ret;
+
+	if (buf & SPINOR_REG_CYPRESS_CFR3V_PGSZ)
+		params->page_size = 512;
+	else
+		params->page_size = 256;
+
+	/*
+	 * The BFPT advertises that it supports 4k erases, and the datasheet
+	 * says the same. But 4k erases did not work when testing. So, use 256k
+	 * erases for now.
+	 */
+	nor->erase_opcode = SPINOR_OP_SE_4B;
+	nor->mtd.erasesize = 0x40000;
+
+	return 0;
+}
+
+struct spi_nor_fixups s28hs512t_fixups = {
+	.default_init = s28hs512t_default_init,
+	.post_sfdp = s28hs512t_post_sfdp_fixup,
+	.post_bfpt = s28hs512t_post_bfpt_fixup,
+};
+#endif /* CONFIG_SPI_FLASH_SPANSION */
+
 /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
  * @nor:                 pointer to a 'struct spi_nor'
  *
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 973b6f86c9..33e6915c16 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -211,6 +211,7 @@ const struct flash_info spi_nor_ids[] = {
 	{ INFO("s25fl208k",  0x014014,      0,  64 * 1024,  16, SECT_4K | SPI_NOR_DUAL_READ) },
 	{ INFO("s25fl064l",  0x016017,      0,  64 * 1024, 128, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
 	{ INFO("s25fl128l",  0x016018,      0,  64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) },
+	{ INFO("s28hs512t",  0x345b1a,      0, 256 * 1024, 256, SPI_NOR_OCTAL_DTR_READ | SPI_NOR_SOFT_RESET) .fixups = &s28hs512t_fixups },
 #endif
 #ifdef CONFIG_SPI_FLASH_SST		/* SST */
 	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index 58992f02b4..fcb7f7aa20 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -156,6 +156,20 @@
 /* Status Register 2 bits. */
 #define SR2_QUAD_EN_BIT7	BIT(7)
 
+/* For Cypress flash. */
+#define SPINOR_OP_RD_ANY_REG			0x65	/* Read any register */
+#define SPINOR_OP_WR_ANY_REG			0x71	/* Write any register */
+#define SPINOR_REG_CYPRESS_CFR2V		0x00800003
+#define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_8_20	0x8
+#define SPINOR_REG_CYPRESS_CFR3N		0x00000004
+#define SPINOR_REG_CYPRESS_CFR3V		0x00800004
+#define SPINOR_REG_CYPRESS_CFR3V_PGSZ		BIT(4) /* Page size. */
+#define SPINOR_REG_CYPRESS_CFR3N_UNISECT	BIT(3) /* Uniform sector mode */
+#define SPINOR_REG_CYPRESS_CFR4V		0x00800005
+#define SPINOR_REG_CYPRESS_CFR5V		0x00800006
+#define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN	0x3
+#define SPINOR_OP_CYPRESS_RD_FAST		0xee
+
 /* Supported SPI protocols */
 #define SNOR_PROTO_INST_MASK	GENMASK(23, 16)
 #define SNOR_PROTO_INST_SHIFT	16
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 17/17] mtd: spi-nor-core: Allow using Micron mt35xu512aba in Octal DTR mode
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (15 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 16/17] mtd: spi-nor-core: Add support for Cypress Semper flash Pratyush Yadav
@ 2020-03-30 15:45 ` Pratyush Yadav
  2020-04-21  7:49 ` [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
  2020-05-12 16:43 ` Jagan Teki
  18 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-03-30 15:45 UTC (permalink / raw)
  To: u-boot

Since this flash doesn't have a Profile 1.0 table, the Octal DTR
capabilities are enabled in the post SFDP fixup, along with the 8D-8D-8D
fast read settings.

Enable Octal DTR mode with 20 dummy cycles to allow running at the
maximum supported frequency of 200Mhz.

The flash supports the soft reset sequence. So, add the flag in the
flash's info.

Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
---
 drivers/mtd/spi/sf_internal.h  |  4 ++
 drivers/mtd/spi/spi-nor-core.c | 87 ++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/spi-nor-ids.c  |  2 +-
 include/linux/mtd/spi-nor.h    | 10 +++-
 4 files changed, 100 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
index d017c857d0..6a6b743dfe 100644
--- a/drivers/mtd/spi/sf_internal.h
+++ b/drivers/mtd/spi/sf_internal.h
@@ -80,6 +80,10 @@ extern const struct flash_info spi_nor_ids[];
 extern struct spi_nor_fixups s28hs512t_fixups;
 #endif
 
+#ifdef CONFIG_SPI_FLASH_STMICRO
+extern struct spi_nor_fixups mt35xu512aba_fixups;
+#endif
+
 #define JEDEC_MFR(info)	((info)->id[0])
 #define JEDEC_ID(info)		(((info)->id[1]) << 8 | ((info)->id[2]))
 
diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
index f6f72f8a32..3711ba6e23 100644
--- a/drivers/mtd/spi/spi-nor-core.c
+++ b/drivers/mtd/spi/spi-nor-core.c
@@ -2956,6 +2956,93 @@ struct spi_nor_fixups s28hs512t_fixups = {
 };
 #endif /* CONFIG_SPI_FLASH_SPANSION */
 
+#ifdef CONFIG_SPI_FLASH_STMICRO
+static int spi_nor_micron_octal_dtr_enable(struct spi_nor *nor)
+{
+	struct spi_mem_op op;
+	u8 buf;
+	u8 addr_width = 3;
+	int ret;
+
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = SPINOR_MT_DTR_NO_DQS;
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+			   SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR0V, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret) {
+		dev_err(nor->dev, "Failed to enable octal DTR mode\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mt35xu512aba_setup(struct spi_nor *nor,
+			      const struct flash_info *info,
+			      const struct spi_nor_flash_parameter *params,
+			      const struct spi_nor_hwcaps *hwcaps)
+{
+	struct spi_mem_op op;
+	u8 buf;
+	u8 addr_width = 3;
+	int ret;
+
+	/* Set dummy cycles for Fast Read to the default of 20. */
+	ret = write_enable(nor);
+	if (ret)
+		return ret;
+
+	buf = 20;
+	op = (struct spi_mem_op)
+		SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1),
+			   SPI_MEM_OP_ADDR(addr_width, SPINOR_REG_MT_CFR1V, 1),
+			   SPI_MEM_OP_NO_DUMMY,
+			   SPI_MEM_OP_DATA_OUT(1, &buf, 1));
+	ret = spi_mem_exec_op(nor->spi, &op);
+	if (ret)
+		return ret;
+
+	ret = spi_nor_wait_till_ready(nor);
+	if (ret)
+		return ret;
+
+	return spi_nor_default_setup(nor, info, params, hwcaps);
+}
+
+static void mt35xu512aba_default_init(struct spi_nor *nor)
+{
+	nor->octal_dtr_enable = spi_nor_micron_octal_dtr_enable;
+	nor->setup = mt35xu512aba_setup;
+}
+
+static void mt35xu512aba_post_sfdp_fixup(struct spi_nor *nor,
+					 struct spi_nor_flash_parameter *params)
+{
+	/* Set the Fast Read settings. */
+	params->hwcaps.mask |= SNOR_HWCAPS_READ_8_8_8_DTR;
+	spi_nor_set_read_settings(&params->reads[SNOR_CMD_READ_8_8_8_DTR],
+				  0, 20, SPINOR_OP_MT_DTR_RD,
+				  SNOR_PROTO_8_8_8_DTR);
+
+	params->hwcaps.mask |= SNOR_HWCAPS_PP_8_8_8_DTR;
+
+	nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
+	params->rdsr_dummy = 8;
+	params->rdsr_addr_nbytes = 0;
+}
+
+struct spi_nor_fixups mt35xu512aba_fixups = {
+	.default_init = mt35xu512aba_default_init,
+	.post_sfdp = mt35xu512aba_post_sfdp_fixup,
+};
+#endif /* CONFIG_SPI_FLASH_STMICRO */
+
 /** spi_nor_octal_dtr_enable() - enable Octal DTR I/O if needed
  * @nor:                 pointer to a 'struct spi_nor'
  *
diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 33e6915c16..2f9498eced 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -182,7 +182,7 @@ const struct flash_info spi_nor_ids[] = {
 	{ INFO("n25q00",      0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("n25q00a",     0x20bb21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
 	{ INFO("mt25qu02g",   0x20bb22, 0, 64 * 1024, 4096, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ | NO_CHIP_ERASE) },
-	{ INFO("mt35xu512aba", 0x2c5b1a, 0,  128 * 1024,  512, USE_FSR | SPI_NOR_4B_OPCODES) },
+	{ INFO("mt35xu512aba", 0x2c5b1a, 0,  128 * 1024,  512,  USE_FSR | SPI_NOR_4B_OPCODES | SPI_NOR_OCTAL_DTR_READ | SPI_NOR_SOFT_RESET) .fixups = &mt35xu512aba_fixups },
 	{ INFO("mt35xu02g",  0x2c5b1c, 0, 128 * 1024,  2048, USE_FSR | SPI_NOR_4B_OPCODES) },
 #endif
 #ifdef CONFIG_SPI_FLASH_SPANSION	/* SPANSION */
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index fcb7f7aa20..d59d217842 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -123,8 +123,14 @@
 #define SPINOR_OP_CLSR		0x30	/* Clear status register 1 */
 
 /* Used for Micron flashes only. */
-#define SPINOR_OP_RD_EVCR      0x65    /* Read EVCR register */
-#define SPINOR_OP_WD_EVCR      0x61    /* Write EVCR register */
+#define SPINOR_OP_RD_EVCR	0x65	/* Read EVCR register */
+#define SPINOR_OP_WD_EVCR	0x61	/* Write EVCR register */
+#define SPINOR_OP_MT_DTR_RD	0xfd	/* Fast Read opcode in DTR mode */
+#define SPINOR_OP_MT_RD_ANY_REG	0x85	/* Read volatile register */
+#define SPINOR_OP_MT_WR_ANY_REG	0x81	/* Write volatile register */
+#define SPINOR_REG_MT_CFR0V	0x00	/* For setting octal DTR mode */
+#define SPINOR_REG_MT_CFR1V	0x01	/* For setting dummy cycles */
+#define SPINOR_MT_DTR_NO_DQS	0xc7	/* Enable Octal DTR without DQS. */
 
 /* Status Register bits. */
 #define SR_WIP			BIT(0)	/* Write in progress */
-- 
2.25.0

^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (16 preceding siblings ...)
  2020-03-30 15:45 ` [PATCH v3 17/17] mtd: spi-nor-core: Allow using Micron mt35xu512aba in Octal DTR mode Pratyush Yadav
@ 2020-04-21  7:49 ` Pratyush Yadav
  2020-04-21  8:09   ` Jagan Teki
  2020-05-05  7:58   ` Vignesh Raghavendra
  2020-05-12 16:43 ` Jagan Teki
  18 siblings, 2 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-04-21  7:49 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 30/03/20 09:15PM, Pratyush Yadav wrote:
> Hi,
> 
> This series adds support for octal DTR flashes in the spi-nor framework,
> and then adds hooks for the Cypress Semper flash which is an xSPI
> compliant Octal DTR flash.
> 
> The Cadence QSPI controller driver is also updated to run in Octal DTR
> mode.
> 
> Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
> u-boot-ti/next.
> 
> This series depends on [0].
> 
> [0] cf. <20200224071051.19331-1-p.yadav@ti.com>
> [0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html
> 
> Changes in v3:
> - Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
>   tripping up controllers.
> - Use op->data.nbytes as a measure of whether the data phase exists or
>   not. This fixes data buswidth not being updadted for SR and FSR reads
>   because they keep data buffer as NULL when calling spi_nor_setup_op().
> - Add support for Micron mt35xu512aba to run in Octal DTR mode.

Any comments on the series? If not, please pull it in.

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
  2020-04-21  7:49 ` [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
@ 2020-04-21  8:09   ` Jagan Teki
  2020-05-05  7:58   ` Vignesh Raghavendra
  1 sibling, 0 replies; 33+ messages in thread
From: Jagan Teki @ 2020-04-21  8:09 UTC (permalink / raw)
  To: u-boot

On Tue, Apr 21, 2020 at 1:19 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> Hi Jagan,
>
> On 30/03/20 09:15PM, Pratyush Yadav wrote:
> > Hi,
> >
> > This series adds support for octal DTR flashes in the spi-nor framework,
> > and then adds hooks for the Cypress Semper flash which is an xSPI
> > compliant Octal DTR flash.
> >
> > The Cadence QSPI controller driver is also updated to run in Octal DTR
> > mode.
> >
> > Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
> > u-boot-ti/next.
> >
> > This series depends on [0].
> >
> > [0] cf. <20200224071051.19331-1-p.yadav@ti.com>
> > [0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html
> >
> > Changes in v3:
> > - Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
> >   tripping up controllers.
> > - Use op->data.nbytes as a measure of whether the data phase exists or
> >   not. This fixes data buswidth not being updadted for SR and FSR reads
> >   because they keep data buffer as NULL when calling spi_nor_setup_op().
> > - Add support for Micron mt35xu512aba to run in Octal DTR mode.
>
> Any comments on the series? If not, please pull it in.

I hardly looked at the code, and will comment as soon as possible.

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
  2020-04-21  7:49 ` [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
  2020-04-21  8:09   ` Jagan Teki
@ 2020-05-05  7:58   ` Vignesh Raghavendra
  1 sibling, 0 replies; 33+ messages in thread
From: Vignesh Raghavendra @ 2020-05-05  7:58 UTC (permalink / raw)
  To: u-boot



On 21/04/20 1:19 pm, Pratyush Yadav wrote:
> Hi Jagan,
> 
> On 30/03/20 09:15PM, Pratyush Yadav wrote:
>> Hi,
>>
>> This series adds support for octal DTR flashes in the spi-nor framework,
>> and then adds hooks for the Cypress Semper flash which is an xSPI
>> compliant Octal DTR flash.
>>
>> The Cadence QSPI controller driver is also updated to run in Octal DTR
>> mode.
>>
>> Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
>> u-boot-ti/next.
>>
>> This series depends on [0].
>>
>> [0] cf. <20200224071051.19331-1-p.yadav@ti.com>
>> [0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html
>>
>> Changes in v3:
>> - Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
>>   tripping up controllers.
>> - Use op->data.nbytes as a measure of whether the data phase exists or
>>   not. This fixes data buswidth not being updadted for SR and FSR reads
>>   because they keep data buffer as NULL when calling spi_nor_setup_op().
>> - Add support for Micron mt35xu512aba to run in Octal DTR mode.
> 
> Any comments on the series? If not, please pull it in.
> 


Reviewed-by: Vignesh Raghavendra <vigneshr@ti.com>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
  2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
                   ` (17 preceding siblings ...)
  2020-04-21  7:49 ` [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
@ 2020-05-12 16:43 ` Jagan Teki
  2020-05-12 18:23   ` Pratyush Yadav
  18 siblings, 1 reply; 33+ messages in thread
From: Jagan Teki @ 2020-05-12 16:43 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 30, 2020 at 9:15 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> Hi,
>
> This series adds support for octal DTR flashes in the spi-nor framework,
> and then adds hooks for the Cypress Semper flash which is an xSPI
> compliant Octal DTR flash.
>
> The Cadence QSPI controller driver is also updated to run in Octal DTR
> mode.
>
> Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
> u-boot-ti/next.
>
> This series depends on [0].
>
> [0] cf. <20200224071051.19331-1-p.yadav@ti.com>
> [0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html
>
> Changes in v3:
> - Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
>   tripping up controllers.
> - Use op->data.nbytes as a measure of whether the data phase exists or
>   not. This fixes data buswidth not being updadted for SR and FSR reads
>   because they keep data buffer as NULL when calling spi_nor_setup_op().
> - Add support for Micron mt35xu512aba to run in Octal DTR mode.

Do you have foot-print statistics for these changes? if yes can mark it here.

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support
  2020-05-12 16:43 ` Jagan Teki
@ 2020-05-12 18:23   ` Pratyush Yadav
  0 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-12 18:23 UTC (permalink / raw)
  To: u-boot

On 12/05/20 10:13PM, Jagan Teki wrote:
> On Mon, Mar 30, 2020 at 9:15 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> >
> > Hi,
> >
> > This series adds support for octal DTR flashes in the spi-nor framework,
> > and then adds hooks for the Cypress Semper flash which is an xSPI
> > compliant Octal DTR flash.
> >
> > The Cadence QSPI controller driver is also updated to run in Octal DTR
> > mode.
> >
> > Tested on TI J721e EVM with 1-bit ECC on the Cypress flash on top of
> > u-boot-ti/next.
> >
> > This series depends on [0].
> >
> > [0] cf. <20200224071051.19331-1-p.yadav@ti.com>
> > [0] https://lists.denx.de/pipermail/u-boot/2020-February/401192.html
> >
> > Changes in v3:
> > - Read 2 bytes in Octal DTR mode when reading SR and FSR to avoid
> >   tripping up controllers.
> > - Use op->data.nbytes as a measure of whether the data phase exists or
> >   not. This fixes data buswidth not being updadted for SR and FSR reads
> >   because they keep data buffer as NULL when calling spi_nor_setup_op().
> > - Add support for Micron mt35xu512aba to run in Octal DTR mode.
> 
> Do you have foot-print statistics for these changes? if yes can mark it here.

Do you mean binary size difference?

With these changes, the U-Boot binary is 830308 bytes. Without them it 
is 825260 bytes. That is a 5048 byte increase.

With these changes, the SPL binary weighs in at 605312 bytes. Without 
them it is 600488 bytes. That is a 4824 byte increase.

This is with both the Spansion and STMicro configs enabled. When I 
disable them I get the follwing data.

U-Boot:
With: 822644
Without: 819688
Difference: 2956

SPL:
With: 599218
Without: 596192
Difference: 3026
 

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown
  2020-03-30 15:45 ` [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown Pratyush Yadav
@ 2020-05-13  6:44   ` Jagan Teki
  2020-05-19 15:09     ` Pratyush Yadav
  0 siblings, 1 reply; 33+ messages in thread
From: Jagan Teki @ 2020-05-13  6:44 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> On probe, the SPI NOR core will put a flash in 8D-8D-8D mode if it
> supports it. But Linux as of now expects to get the flash in 1S-1S-1S
> mode. Handing the flash to Linux in Octal DTR mode means the kernel will
> fail to detect the flash.
>
> So, we need to reset to Power-on-Reset (POR) state before handing off
> the flash. A Software Reset command can be used to do this. Since the
> command is optional, flashes have to specify they support it by using
> the flag 'SPI_NOR_SOFT_RESET'.
>
> One limitation of the soft reset is that it will restore state from
> non-volatile registers in some flashes. This means that if the flash was
> set to 8D mode in a non-volatile configuration, a soft reset won't help.
> This commit assumes that we don't set any non-volatile bits anywhere,
> and the flash doesn't have any non-volatile Octal DTR mode
> configuration.

Is this common for all 8D supported flash devices?

>
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> ---
>  drivers/mtd/spi/sf_internal.h  |  1 +
>  drivers/mtd/spi/sf_probe.c     |  9 +++++
>  drivers/mtd/spi/spi-nor-core.c | 66 ++++++++++++++++++++++++++++++++++
>  include/linux/mtd/spi-nor.h    | 11 ++++++
>  4 files changed, 87 insertions(+)
>
> diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> index 5780c81287..37e6657490 100644
> --- a/drivers/mtd/spi/sf_internal.h
> +++ b/drivers/mtd/spi/sf_internal.h
> @@ -68,6 +68,7 @@ struct flash_info {
>  #define SPI_NOR_HAS_SST26LOCK  BIT(15) /* Flash supports lock/unlock via BPR */
>  #define SPI_NOR_OCTAL_READ      BIT(16) /* Flash supports Octal Read */
>  #define SPI_NOR_OCTAL_DTR_READ BIT(17) /* Flash supports Octal DTR Read */
> +#define SPI_NOR_SOFT_RESET     BIT(18) /* Flash supports soft reset command */
>
>         /* Part specific fixup hooks. */
>         const struct spi_nor_fixups *fixups;
> diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
> index 72b6ee702d..90bd3196c2 100644
> --- a/drivers/mtd/spi/sf_probe.c
> +++ b/drivers/mtd/spi/sf_probe.c
> @@ -152,6 +152,14 @@ int spi_flash_std_probe(struct udevice *dev)
>
>  static int spi_flash_std_remove(struct udevice *dev)
>  {
> +       struct spi_flash *flash;
> +       int ret;
> +
> +       flash = dev_get_uclass_priv(dev);
> +       ret = spi_nor_remove(flash);
> +       if (ret)
> +               return ret;
> +
>  #if CONFIG_IS_ENABLED(SPI_FLASH_MTD)
>         spi_flash_mtd_unregister();
>  #endif
> @@ -178,6 +186,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
>         .remove         = spi_flash_std_remove,
>         .priv_auto_alloc_size = sizeof(struct spi_flash),
>         .ops            = &spi_flash_std_ops,
> +       .flags          = DM_FLAG_OS_PREPARE,
>  };
>
>  #endif /* CONFIG_DM_SPI_FLASH */
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 5b995cda3f..52b3775035 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -186,6 +186,8 @@ struct spi_nor_fixups {
>                           struct spi_nor_flash_parameter *params);
>  };
>
> +#define SPI_NOR_SRST_SLEEP_LEN                 200
> +
>  /**
>   * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
>   *                        extension type.
> @@ -2835,6 +2837,67 @@ static int spi_nor_init(struct spi_nor *nor)
>         return 0;
>  }
>
> +/**
> + * spi_nor_soft_reset() - perform the JEDEC Software Reset sequence
> + * @nor:       the spi_nor structure
> + *
> + * This function can be used to switch from Octal DTR mode to legacy mode on a
> + * flash that supports it. The soft reset is executed in Octal DTR mode.
> + *
> + * Return: 0 for success, -errno for failure.
> + */
> +static int spi_nor_soft_reset(struct spi_nor *nor)
> +{
> +       struct spi_mem_op op;
> +       int ret;
> +       enum spi_nor_cmd_ext ext;
> +
> +       ext = nor->cmd_ext_type;
> +       nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
> +
> +       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 8),
> +                       SPI_MEM_OP_NO_DUMMY,
> +                       SPI_MEM_OP_NO_ADDR,
> +                       SPI_MEM_OP_NO_DATA);
> +       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
> +       ret = spi_mem_exec_op(nor->spi, &op);
> +       if (ret) {
> +               dev_warn(nor->dev, "Software reset enable failed: %d\n", ret);
> +               goto out;
> +       }
> +
> +       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 8),
> +                       SPI_MEM_OP_NO_DUMMY,
> +                       SPI_MEM_OP_NO_ADDR,
> +                       SPI_MEM_OP_NO_DATA);
> +       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
> +       ret = spi_mem_exec_op(nor->spi, &op);
> +       if (ret) {
> +               dev_warn(nor->dev, "Software reset failed: %d\n", ret);
> +               goto out;
> +       }
> +
> +       /*
> +        * Software Reset is not instant, and the delay varies from flash to
> +        * flash. Looking at a few flashes, most range somewhere below 100
> +        * microseconds. So, wait for 200ms just to be sure.
> +        */
> +       udelay(SPI_NOR_SRST_SLEEP_LEN);

Any reference for this delay? I mean datasheet?

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-03-30 15:45 ` [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot Pratyush Yadav
@ 2020-05-13  6:47   ` Jagan Teki
  2020-05-13  8:54     ` Pratyush Yadav
  0 siblings, 1 reply; 33+ messages in thread
From: Jagan Teki @ 2020-05-13  6:47 UTC (permalink / raw)
  To: u-boot

On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> difficult to detect the mode the flash is in. One option is to read SFDP
> in all modes and see which one gives the correct "SFDP" signature, but
> not all flashes support SFDP in 8D-8D-8D mode.
>
> Further, even if you detect the mode of the flash via SFDP, you still
> have the problem of actually reading the ID. The Read ID command is not
> standardized across flash vendors. Flashes can have different dummy
> cycles needed for reading the ID. Some flashes even expect a 4-byte
> dummy address with the Read ID command. All this information cannot be
> obtained from the SFDP table.
>
> So, perform a Software Reset sequence before reading the ID and
> initializing the flash. A Soft Reset will bring back the flash in its
> default protocol mode assuming no non-volatile configuration was set.
> This will let us detect the flash even if ROM hands it to us in Octal
> DTR mode.
>
> To accommodate cases where there is more than one flash on a board, and
> only one of them needs a soft reset, failure to reset is not made fatal,
> and we still try to read ID if possible.
>
> Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> ---
>  drivers/mtd/spi/Kconfig        | 11 +++++++++++
>  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
>  2 files changed, 38 insertions(+)
>
> diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
> index 018e8c597e..38d509c568 100644
> --- a/drivers/mtd/spi/Kconfig
> +++ b/drivers/mtd/spi/Kconfig
> @@ -88,6 +88,17 @@ config SPI_FLASH_SFDP_SUPPORT
>          SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
>          tables as per JESD216 standard.
>
> +config SPI_FLASH_SOFT_RESET
> +       bool "Software Reset support for SPI NOR flashes"
> +       help
> +        Enable support for xSPI Software Reset. It will be used to switch
> +        from Octal DTR mode to legacy mode to allow detecting flashes that
> +        are handed to us in Octal DTR mode. It is expected that if the config
> +        is enabled the flash supports the Soft Reset sequence and is booted in
> +        Octal DTR mode. Do not enable this config on flashes that are not
> +        supposed to be handed to U-Boot in Octal DTR mode, even if they _do_
> +        support the Soft Reset sequence.
> +
>  config SPI_FLASH_BAR
>         bool "SPI flash Bank/Extended address register support"
>         help
> diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> index 52b3775035..3af2c6afa9 100644
> --- a/drivers/mtd/spi/spi-nor-core.c
> +++ b/drivers/mtd/spi/spi-nor-core.c
> @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
>
>         nor->setup = spi_nor_default_setup;
>
> +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> +       /*
> +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> +        * is difficult to detect the mode the flash is in. One option is to
> +        * read SFDP in all modes and see which one gives the correct "SFDP"
> +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> +        *
> +        * Further, even if you detect the mode of the flash via SFDP, you
> +        * still have the problem of actually reading the ID. The Read ID
> +        * command is not standardized across flash vendors. Flashes can have
> +        * different dummy cycles needed for reading the ID. Some flashes even
> +        * expect a 4-byte dummy address with the Read ID command. All this
> +        * information cannot be obtained from the SFDP table.
> +        *
> +        * So, perform a Software Reset sequence before reading the ID and
> +        * initializing the flash. A Soft Reset will bring back the flash in
> +        * its default protocol mode assuming no non-volatile configuration was
> +        * set. This will let us detect the flash even if ROM hands it to us in
> +        * Octal DTR mode.
> +        *
> +        * To accommodate cases where there is more than one flash on a board,
> +        * and only one of them needs a soft reset, failure to reset is not
> +        * made fatal, and we still try to read ID if possible.
> +        */
> +       spi_nor_soft_reset(nor);
> +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */

Does it specific to a particular flash chip? I believe add flash chip
fixups would make more sense instead of having it like this.

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-05-13  6:47   ` Jagan Teki
@ 2020-05-13  8:54     ` Pratyush Yadav
  2020-05-13  9:56       ` Jagan Teki
  0 siblings, 1 reply; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-13  8:54 UTC (permalink / raw)
  To: u-boot

On 13/05/20 12:17PM, Jagan Teki wrote:
> On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> >
> > When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> > difficult to detect the mode the flash is in. One option is to read SFDP
> > in all modes and see which one gives the correct "SFDP" signature, but
> > not all flashes support SFDP in 8D-8D-8D mode.
> >
> > Further, even if you detect the mode of the flash via SFDP, you still
> > have the problem of actually reading the ID. The Read ID command is not
> > standardized across flash vendors. Flashes can have different dummy
> > cycles needed for reading the ID. Some flashes even expect a 4-byte
> > dummy address with the Read ID command. All this information cannot be
> > obtained from the SFDP table.
> >
> > So, perform a Software Reset sequence before reading the ID and
> > initializing the flash. A Soft Reset will bring back the flash in its
> > default protocol mode assuming no non-volatile configuration was set.
> > This will let us detect the flash even if ROM hands it to us in Octal
> > DTR mode.
> >
> > To accommodate cases where there is more than one flash on a board, and
> > only one of them needs a soft reset, failure to reset is not made fatal,
> > and we still try to read ID if possible.
> >
> > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > ---
> >  drivers/mtd/spi/Kconfig        | 11 +++++++++++
> >  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
> >  2 files changed, 38 insertions(+)
> >
> > diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
> > index 018e8c597e..38d509c568 100644
> > --- a/drivers/mtd/spi/Kconfig
> > +++ b/drivers/mtd/spi/Kconfig
> > @@ -88,6 +88,17 @@ config SPI_FLASH_SFDP_SUPPORT
> >          SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
> >          tables as per JESD216 standard.
> >
> > +config SPI_FLASH_SOFT_RESET
> > +       bool "Software Reset support for SPI NOR flashes"
> > +       help
> > +        Enable support for xSPI Software Reset. It will be used to switch
> > +        from Octal DTR mode to legacy mode to allow detecting flashes that
> > +        are handed to us in Octal DTR mode. It is expected that if the config
> > +        is enabled the flash supports the Soft Reset sequence and is booted in
> > +        Octal DTR mode. Do not enable this config on flashes that are not
> > +        supposed to be handed to U-Boot in Octal DTR mode, even if they _do_
> > +        support the Soft Reset sequence.
> > +
> >  config SPI_FLASH_BAR
> >         bool "SPI flash Bank/Extended address register support"
> >         help
> > diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> > index 52b3775035..3af2c6afa9 100644
> > --- a/drivers/mtd/spi/spi-nor-core.c
> > +++ b/drivers/mtd/spi/spi-nor-core.c
> > @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
> >
> >         nor->setup = spi_nor_default_setup;
> >
> > +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> > +       /*
> > +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> > +        * is difficult to detect the mode the flash is in. One option is to
> > +        * read SFDP in all modes and see which one gives the correct "SFDP"
> > +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> > +        *
> > +        * Further, even if you detect the mode of the flash via SFDP, you
> > +        * still have the problem of actually reading the ID. The Read ID
> > +        * command is not standardized across flash vendors. Flashes can have
> > +        * different dummy cycles needed for reading the ID. Some flashes even
> > +        * expect a 4-byte dummy address with the Read ID command. All this
> > +        * information cannot be obtained from the SFDP table.
> > +        *
> > +        * So, perform a Software Reset sequence before reading the ID and
> > +        * initializing the flash. A Soft Reset will bring back the flash in
> > +        * its default protocol mode assuming no non-volatile configuration was
> > +        * set. This will let us detect the flash even if ROM hands it to us in
> > +        * Octal DTR mode.
> > +        *
> > +        * To accommodate cases where there is more than one flash on a board,
> > +        * and only one of them needs a soft reset, failure to reset is not
> > +        * made fatal, and we still try to read ID if possible.
> > +        */
> > +       spi_nor_soft_reset(nor);
> > +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
> 
> Does it specific to a particular flash chip? I believe add flash chip
> fixups would make more sense instead of having it like this.

To run a flash fixup, we need to know which flash it is. But if ROM 
hands us the flash in 8D mode, we can't reliably detect the ID of the 
flash since the Read ID command differs from one flash to another. For 
example, on the Cypress S28 flash family, the Read ID command in 8D mode  
expects 4 dummy address bytes and 3 dummy cycles. But on the Micron 
MT35XU flashes, Read ID in 8D needs 0 address bytes and 8 dummy cycles.

This works around the issue by issuing a soft reset command so even if 
the flash is in 8D mode, it gets switched back to 1S mode so we can 
detect it.

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-05-13  8:54     ` Pratyush Yadav
@ 2020-05-13  9:56       ` Jagan Teki
  2020-05-13 11:04         ` Pratyush Yadav
  0 siblings, 1 reply; 33+ messages in thread
From: Jagan Teki @ 2020-05-13  9:56 UTC (permalink / raw)
  To: u-boot

On Wed, May 13, 2020 at 2:24 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> On 13/05/20 12:17PM, Jagan Teki wrote:
> > On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > >
> > > When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> > > difficult to detect the mode the flash is in. One option is to read SFDP
> > > in all modes and see which one gives the correct "SFDP" signature, but
> > > not all flashes support SFDP in 8D-8D-8D mode.
> > >
> > > Further, even if you detect the mode of the flash via SFDP, you still
> > > have the problem of actually reading the ID. The Read ID command is not
> > > standardized across flash vendors. Flashes can have different dummy
> > > cycles needed for reading the ID. Some flashes even expect a 4-byte
> > > dummy address with the Read ID command. All this information cannot be
> > > obtained from the SFDP table.
> > >
> > > So, perform a Software Reset sequence before reading the ID and
> > > initializing the flash. A Soft Reset will bring back the flash in its
> > > default protocol mode assuming no non-volatile configuration was set.
> > > This will let us detect the flash even if ROM hands it to us in Octal
> > > DTR mode.
> > >
> > > To accommodate cases where there is more than one flash on a board, and
> > > only one of them needs a soft reset, failure to reset is not made fatal,
> > > and we still try to read ID if possible.
> > >
> > > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > > ---
> > >  drivers/mtd/spi/Kconfig        | 11 +++++++++++
> > >  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
> > >  2 files changed, 38 insertions(+)
> > >
> > > diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig
> > > index 018e8c597e..38d509c568 100644
> > > --- a/drivers/mtd/spi/Kconfig
> > > +++ b/drivers/mtd/spi/Kconfig
> > > @@ -88,6 +88,17 @@ config SPI_FLASH_SFDP_SUPPORT
> > >          SPI NOR flashes using Serial Flash Discoverable Parameters (SFDP)
> > >          tables as per JESD216 standard.
> > >
> > > +config SPI_FLASH_SOFT_RESET
> > > +       bool "Software Reset support for SPI NOR flashes"
> > > +       help
> > > +        Enable support for xSPI Software Reset. It will be used to switch
> > > +        from Octal DTR mode to legacy mode to allow detecting flashes that
> > > +        are handed to us in Octal DTR mode. It is expected that if the config
> > > +        is enabled the flash supports the Soft Reset sequence and is booted in
> > > +        Octal DTR mode. Do not enable this config on flashes that are not
> > > +        supposed to be handed to U-Boot in Octal DTR mode, even if they _do_
> > > +        support the Soft Reset sequence.
> > > +
> > >  config SPI_FLASH_BAR
> > >         bool "SPI flash Bank/Extended address register support"
> > >         help
> > > diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> > > index 52b3775035..3af2c6afa9 100644
> > > --- a/drivers/mtd/spi/spi-nor-core.c
> > > +++ b/drivers/mtd/spi/spi-nor-core.c
> > > @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
> > >
> > >         nor->setup = spi_nor_default_setup;
> > >
> > > +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> > > +       /*
> > > +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> > > +        * is difficult to detect the mode the flash is in. One option is to
> > > +        * read SFDP in all modes and see which one gives the correct "SFDP"
> > > +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> > > +        *
> > > +        * Further, even if you detect the mode of the flash via SFDP, you
> > > +        * still have the problem of actually reading the ID. The Read ID
> > > +        * command is not standardized across flash vendors. Flashes can have
> > > +        * different dummy cycles needed for reading the ID. Some flashes even
> > > +        * expect a 4-byte dummy address with the Read ID command. All this
> > > +        * information cannot be obtained from the SFDP table.
> > > +        *
> > > +        * So, perform a Software Reset sequence before reading the ID and
> > > +        * initializing the flash. A Soft Reset will bring back the flash in
> > > +        * its default protocol mode assuming no non-volatile configuration was
> > > +        * set. This will let us detect the flash even if ROM hands it to us in
> > > +        * Octal DTR mode.
> > > +        *
> > > +        * To accommodate cases where there is more than one flash on a board,
> > > +        * and only one of them needs a soft reset, failure to reset is not
> > > +        * made fatal, and we still try to read ID if possible.
> > > +        */
> > > +       spi_nor_soft_reset(nor);
> > > +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
> >
> > Does it specific to a particular flash chip? I believe add flash chip
> > fixups would make more sense instead of having it like this.
>
> To run a flash fixup, we need to know which flash it is. But if ROM
> hands us the flash in 8D mode, we can't reliably detect the ID of the
> flash since the Read ID command differs from one flash to another. For
> example, on the Cypress S28 flash family, the Read ID command in 8D mode
> expects 4 dummy address bytes and 3 dummy cycles. But on the Micron
> MT35XU flashes, Read ID in 8D needs 0 address bytes and 8 dummy cycles.
>
> This works around the issue by issuing a soft reset command so even if
> the flash is in 8D mode, it gets switched back to 1S mode so we can
> detect it.

I got this from the commit message, thanks. Point I'm trying to
understand here about can't we detect soft reset of associate flash
via some bits in SFDP? if yes then we can dynamically process the soft
reset on associated flash like quad enable does?

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-05-13  9:56       ` Jagan Teki
@ 2020-05-13 11:04         ` Pratyush Yadav
  2020-05-15  7:42           ` Jagan Teki
  0 siblings, 1 reply; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-13 11:04 UTC (permalink / raw)
  To: u-boot

On 13/05/20 03:26PM, Jagan Teki wrote:
> On Wed, May 13, 2020 at 2:24 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> >
> > On 13/05/20 12:17PM, Jagan Teki wrote:
> > > On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > > >
> > > > When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> > > > difficult to detect the mode the flash is in. One option is to read SFDP
> > > > in all modes and see which one gives the correct "SFDP" signature, but
> > > > not all flashes support SFDP in 8D-8D-8D mode.
> > > >
> > > > Further, even if you detect the mode of the flash via SFDP, you still
> > > > have the problem of actually reading the ID. The Read ID command is not
> > > > standardized across flash vendors. Flashes can have different dummy
> > > > cycles needed for reading the ID. Some flashes even expect a 4-byte
> > > > dummy address with the Read ID command. All this information cannot be
> > > > obtained from the SFDP table.
> > > >
> > > > So, perform a Software Reset sequence before reading the ID and
> > > > initializing the flash. A Soft Reset will bring back the flash in its
> > > > default protocol mode assuming no non-volatile configuration was set.
> > > > This will let us detect the flash even if ROM hands it to us in Octal
> > > > DTR mode.
> > > >
> > > > To accommodate cases where there is more than one flash on a board, and
> > > > only one of them needs a soft reset, failure to reset is not made fatal,
> > > > and we still try to read ID if possible.
> > > >
> > > > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > > > ---
> > > >  drivers/mtd/spi/Kconfig        | 11 +++++++++++
> > > >  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
> > > >  2 files changed, 38 insertions(+)
> > > >
> > > > diff --git a/drivers/mtd/spi/spi-nor-core.c 
> > > > b/drivers/mtd/spi/spi-nor-core.c
> > > > index 52b3775035..3af2c6afa9 100644
> > > > --- a/drivers/mtd/spi/spi-nor-core.c
> > > > +++ b/drivers/mtd/spi/spi-nor-core.c
> > > > @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
> > > >
> > > >         nor->setup = spi_nor_default_setup;
> > > >
> > > > +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> > > > +       /*
> > > > +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> > > > +        * is difficult to detect the mode the flash is in. One option is to
> > > > +        * read SFDP in all modes and see which one gives the correct "SFDP"
> > > > +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> > > > +        *
> > > > +        * Further, even if you detect the mode of the flash via SFDP, you
> > > > +        * still have the problem of actually reading the ID. The Read ID
> > > > +        * command is not standardized across flash vendors. Flashes can have
> > > > +        * different dummy cycles needed for reading the ID. Some flashes even
> > > > +        * expect a 4-byte dummy address with the Read ID command. All this
> > > > +        * information cannot be obtained from the SFDP table.
> > > > +        *
> > > > +        * So, perform a Software Reset sequence before reading the ID and
> > > > +        * initializing the flash. A Soft Reset will bring back the flash in
> > > > +        * its default protocol mode assuming no non-volatile configuration was
> > > > +        * set. This will let us detect the flash even if ROM hands it to us in
> > > > +        * Octal DTR mode.
> > > > +        *
> > > > +        * To accommodate cases where there is more than one flash on a board,
> > > > +        * and only one of them needs a soft reset, failure to reset is not
> > > > +        * made fatal, and we still try to read ID if possible.
> > > > +        */
> > > > +       spi_nor_soft_reset(nor);
> > > > +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
> > >
> > > Does it specific to a particular flash chip? I believe add flash chip
> > > fixups would make more sense instead of having it like this.
> >
> > To run a flash fixup, we need to know which flash it is. But if ROM
> > hands us the flash in 8D mode, we can't reliably detect the ID of the
> > flash since the Read ID command differs from one flash to another. For
> > example, on the Cypress S28 flash family, the Read ID command in 8D mode
> > expects 4 dummy address bytes and 3 dummy cycles. But on the Micron
> > MT35XU flashes, Read ID in 8D needs 0 address bytes and 8 dummy cycles.
> >
> > This works around the issue by issuing a soft reset command so even if
> > the flash is in 8D mode, it gets switched back to 1S mode so we can
> > detect it.
> 
> I got this from the commit message, thanks. Point I'm trying to
> understand here about can't we detect soft reset of associate flash
> via some bits in SFDP? if yes then we can dynamically process the soft
> reset on associated flash like quad enable does?

If the device supports the Read SFDP command in 8D mode (it is optional 
as per JESD251), then we can detect soft reset support via BFPT DWORD 16 
bits 13:8.

If we go that path, we would need to take the below steps before we can 
proceed with the probe:

- Issue Read SFDP in 8D mode and see if we get the "SFDP" signature 
  correctly. If we don't, exit.

- Read BFPT in 8D mode, and see if Soft Reset is supported.

- If it is, issue a soft reset and go on as usual. If it isn't, error 
  out, and the probe fails.

The problem is, I'm not sure if controllers will be okay doing this on a 
flash that is in 1S mode. Say the controller expects the DQS line to 
toggle when the flash is sending data. Now, we tell the controller we 
will read 16 bytes (SFDP header), but since the flash is in 1S mode, it 
sees some other command and might not send out any data at all. In this 
case, will the controller hang, waiting forever for the flash to toggle 
DQS?

FWIW, the controller on our board (Cadence QSPI) doesn't hang. But I'm 
not sure how other controllers would react. That's why I went with the 
more minimal option. The soft reset sequence doesn't expect to receive 
any data. It only sends it.

If you think no contoller will trip over this, then I don't mind 
discovering Soft Reset capability via BFPT.

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-05-13 11:04         ` Pratyush Yadav
@ 2020-05-15  7:42           ` Jagan Teki
  2020-05-19 15:33             ` Pratyush Yadav
  0 siblings, 1 reply; 33+ messages in thread
From: Jagan Teki @ 2020-05-15  7:42 UTC (permalink / raw)
  To: u-boot

On Wed, May 13, 2020 at 4:34 PM Pratyush Yadav <p.yadav@ti.com> wrote:
>
> On 13/05/20 03:26PM, Jagan Teki wrote:
> > On Wed, May 13, 2020 at 2:24 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > >
> > > On 13/05/20 12:17PM, Jagan Teki wrote:
> > > > On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > > > >
> > > > > When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> > > > > difficult to detect the mode the flash is in. One option is to read SFDP
> > > > > in all modes and see which one gives the correct "SFDP" signature, but
> > > > > not all flashes support SFDP in 8D-8D-8D mode.
> > > > >
> > > > > Further, even if you detect the mode of the flash via SFDP, you still
> > > > > have the problem of actually reading the ID. The Read ID command is not
> > > > > standardized across flash vendors. Flashes can have different dummy
> > > > > cycles needed for reading the ID. Some flashes even expect a 4-byte
> > > > > dummy address with the Read ID command. All this information cannot be
> > > > > obtained from the SFDP table.
> > > > >
> > > > > So, perform a Software Reset sequence before reading the ID and
> > > > > initializing the flash. A Soft Reset will bring back the flash in its
> > > > > default protocol mode assuming no non-volatile configuration was set.
> > > > > This will let us detect the flash even if ROM hands it to us in Octal
> > > > > DTR mode.
> > > > >
> > > > > To accommodate cases where there is more than one flash on a board, and
> > > > > only one of them needs a soft reset, failure to reset is not made fatal,
> > > > > and we still try to read ID if possible.
> > > > >
> > > > > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > > > > ---
> > > > >  drivers/mtd/spi/Kconfig        | 11 +++++++++++
> > > > >  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
> > > > >  2 files changed, 38 insertions(+)
> > > > >
> > > > > diff --git a/drivers/mtd/spi/spi-nor-core.c
> > > > > b/drivers/mtd/spi/spi-nor-core.c
> > > > > index 52b3775035..3af2c6afa9 100644
> > > > > --- a/drivers/mtd/spi/spi-nor-core.c
> > > > > +++ b/drivers/mtd/spi/spi-nor-core.c
> > > > > @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
> > > > >
> > > > >         nor->setup = spi_nor_default_setup;
> > > > >
> > > > > +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> > > > > +       /*
> > > > > +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> > > > > +        * is difficult to detect the mode the flash is in. One option is to
> > > > > +        * read SFDP in all modes and see which one gives the correct "SFDP"
> > > > > +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> > > > > +        *
> > > > > +        * Further, even if you detect the mode of the flash via SFDP, you
> > > > > +        * still have the problem of actually reading the ID. The Read ID
> > > > > +        * command is not standardized across flash vendors. Flashes can have
> > > > > +        * different dummy cycles needed for reading the ID. Some flashes even
> > > > > +        * expect a 4-byte dummy address with the Read ID command. All this
> > > > > +        * information cannot be obtained from the SFDP table.
> > > > > +        *
> > > > > +        * So, perform a Software Reset sequence before reading the ID and
> > > > > +        * initializing the flash. A Soft Reset will bring back the flash in
> > > > > +        * its default protocol mode assuming no non-volatile configuration was
> > > > > +        * set. This will let us detect the flash even if ROM hands it to us in
> > > > > +        * Octal DTR mode.
> > > > > +        *
> > > > > +        * To accommodate cases where there is more than one flash on a board,
> > > > > +        * and only one of them needs a soft reset, failure to reset is not
> > > > > +        * made fatal, and we still try to read ID if possible.
> > > > > +        */
> > > > > +       spi_nor_soft_reset(nor);
> > > > > +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
> > > >
> > > > Does it specific to a particular flash chip? I believe add flash chip
> > > > fixups would make more sense instead of having it like this.
> > >
> > > To run a flash fixup, we need to know which flash it is. But if ROM
> > > hands us the flash in 8D mode, we can't reliably detect the ID of the
> > > flash since the Read ID command differs from one flash to another. For
> > > example, on the Cypress S28 flash family, the Read ID command in 8D mode
> > > expects 4 dummy address bytes and 3 dummy cycles. But on the Micron
> > > MT35XU flashes, Read ID in 8D needs 0 address bytes and 8 dummy cycles.
> > >
> > > This works around the issue by issuing a soft reset command so even if
> > > the flash is in 8D mode, it gets switched back to 1S mode so we can
> > > detect it.
> >
> > I got this from the commit message, thanks. Point I'm trying to
> > understand here about can't we detect soft reset of associate flash
> > via some bits in SFDP? if yes then we can dynamically process the soft
> > reset on associated flash like quad enable does?
>
> If the device supports the Read SFDP command in 8D mode (it is optional
> as per JESD251), then we can detect soft reset support via BFPT DWORD 16
> bits 13:8.
>
> If we go that path, we would need to take the below steps before we can
> proceed with the probe:
>
> - Issue Read SFDP in 8D mode and see if we get the "SFDP" signature
>   correctly. If we don't, exit.
>
> - Read BFPT in 8D mode, and see if Soft Reset is supported.
>
> - If it is, issue a soft reset and go on as usual. If it isn't, error
>   out, and the probe fails.
>
> The problem is, I'm not sure if controllers will be okay doing this on a
> flash that is in 1S mode. Say the controller expects the DQS line to
> toggle when the flash is sending data. Now, we tell the controller we
> will read 16 bytes (SFDP header), but since the flash is in 1S mode, it
> sees some other command and might not send out any data at all. In this
> case, will the controller hang, waiting forever for the flash to toggle
> DQS?
>
> FWIW, the controller on our board (Cadence QSPI) doesn't hang. But I'm
> not sure how other controllers would react. That's why I went with the
> more minimal option. The soft reset sequence doesn't expect to receive
> any data. It only sends it.

So, we never sure if another controller (other than cadence) can
guarantee to toggle the DQS? Can't the flash wait till to controller
to toggle? I would like to see how this implemented in Linux, is it
under progress or done in similar way?

Jagan.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT
  2020-03-30 15:45 ` [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT Pratyush Yadav
@ 2020-05-18 14:31   ` Pragnesh Patel
  2020-05-18 18:33     ` Pratyush Yadav
  0 siblings, 1 reply; 33+ messages in thread
From: Pragnesh Patel @ 2020-05-18 14:31 UTC (permalink / raw)
  To: u-boot

Hi Pratyush,

>-----Original Message-----
>From: U-Boot <u-boot-bounces@lists.denx.de> On Behalf Of Pratyush Yadav
>Sent: 30 March 2020 21:16
>To: Jagan Teki <jagan@amarulasolutions.com>; Vignesh Raghavendra
><vigneshr@ti.com>
>Cc: Pratyush Yadav <p.yadav@ti.com>; u-boot at lists.denx.de; Sekhar Nori
><nsekhar@ti.com>
>Subject: [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension
>type from BFPT
>
>[External Email] Do not click links or attachments unless you recognize the
>sender and know the content is safe
>
>Some devices in DTR mode expect an extra command byte called the
>extension. The extension can either be same as the opcode, bitwise inverse of
>the opcode, or another additional byte forming a 16-byte opcode. Get the
>extension type from the BFPT. For now, only flashes with "repeat" and
>"inverse" extensions are supported.
>
>As of JESD216D.01, BFPT is 20 DWORDs, so update the table size to reflect
>that.
>
>Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
>---
> drivers/mtd/spi/spi-nor-core.c | 28 ++++++++++++++++++++++++++--
> 1 file changed, 26 insertions(+), 2 deletions(-)
>
>diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
>index d3f05e1ded..684a8c3216 100644
>--- a/drivers/mtd/spi/spi-nor-core.c
>+++ b/drivers/mtd/spi/spi-nor-core.c
>@@ -75,11 +75,11 @@ struct sfdp_header {
> /* Basic Flash Parameter Table */
>
> /*
>- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
>+ * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
>  * They are indexed from 1 but C arrays are indexed from 0.
>  */
> #define BFPT_DWORD(i)          ((i) - 1)
>-#define BFPT_DWORD_MAX         16
>+#define BFPT_DWORD_MAX         20

If we will change this according to rev D then you should also consider other revisions (rev B) because
below condition will return 0 for revisions lower than rev D.

static int spi_nor_parse_bfpt() {
......
	1943         /* Stop here if not JESD216 rev A or later. */
	1944         if (bfpt_header->length < BFPT_DWORD_MAX)
	1945                 return 0;
.....
}

For flashes which does not support rev D will return from here.

>
> /* The first version of JESB216 defined only 9 DWORDs. */
> #define BFPT_DWORD_MAX_JESD216                 9
>@@ -144,6 +144,12 @@ struct sfdp_header {
> #define BFPT_DWORD15_QER_SR2_BIT1_NO_RD                (0x4UL << 20)
> #define BFPT_DWORD15_QER_SR2_BIT1              (0x5UL << 20) /* Spansion */
>
>+#define BFPT_DWORD18_CMD_EXT_MASK              GENMASK(30, 29)
>+#define BFPT_DWORD18_CMD_EXT_REP               (0x0UL << 29) /* Repeat */
>+#define BFPT_DWORD18_CMD_EXT_INV               (0x1UL << 29) /* Invert */
>+#define BFPT_DWORD18_CMD_EXT_RES               (0x2UL << 29) /* Reserved
>*/
>+#define BFPT_DWORD18_CMD_EXT_16B               (0x3UL << 29) /* 16-bit
>opcode */
>+
> struct sfdp_bfpt {
>        u32     dwords[BFPT_DWORD_MAX];
> };
>@@ -2021,6 +2027,24 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
>                return -EINVAL;
>        }
>
>+       /* 8D-8D-8D command extension. */
>+       switch (bfpt.dwords[BFPT_DWORD(18)] &
>BFPT_DWORD18_CMD_EXT_MASK) {
>+       case BFPT_DWORD18_CMD_EXT_REP:
>+               nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
>+               break;
>+
>+       case BFPT_DWORD18_CMD_EXT_INV:
>+               nor->cmd_ext_type = SPI_NOR_EXT_INVERT;
>+               break;
>+
>+       case BFPT_DWORD18_CMD_EXT_RES:
>+               return -EINVAL;
>+
>+       case BFPT_DWORD18_CMD_EXT_16B:
>+               dev_err(nor->dev, "16-bit opcodes not supported\n");
>+               return -ENOTSUPP;
>+       }
>+
>        return spi_nor_post_bfpt_fixups(nor, bfpt_header, &bfpt, params);  }
>
>--
>2.25.0

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT
  2020-05-18 14:31   ` Pragnesh Patel
@ 2020-05-18 18:33     ` Pratyush Yadav
  0 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-18 18:33 UTC (permalink / raw)
  To: u-boot

Hi Pragnesh,

On 18/05/20 02:31PM, Pragnesh Patel wrote:
> Hi Pratyush,
> 
> >-----Original Message-----
> >From: U-Boot <u-boot-bounces@lists.denx.de> On Behalf Of Pratyush Yadav
> >Sent: 30 March 2020 21:16
> >To: Jagan Teki <jagan@amarulasolutions.com>; Vignesh Raghavendra
> ><vigneshr@ti.com>
> >Cc: Pratyush Yadav <p.yadav@ti.com>; u-boot at lists.denx.de; Sekhar Nori
> ><nsekhar@ti.com>
> >Subject: [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension
> >type from BFPT
> >
> >[External Email] Do not click links or attachments unless you recognize the
> >sender and know the content is safe
> >
> >Some devices in DTR mode expect an extra command byte called the
> >extension. The extension can either be same as the opcode, bitwise inverse of
> >the opcode, or another additional byte forming a 16-byte opcode. Get the
> >extension type from the BFPT. For now, only flashes with "repeat" and
> >"inverse" extensions are supported.
> >
> >As of JESD216D.01, BFPT is 20 DWORDs, so update the table size to reflect
> >that.
> >
> >Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> >---
> > drivers/mtd/spi/spi-nor-core.c | 28 ++++++++++++++++++++++++++--
> > 1 file changed, 26 insertions(+), 2 deletions(-)
> >
> >diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> >index d3f05e1ded..684a8c3216 100644
> >--- a/drivers/mtd/spi/spi-nor-core.c
> >+++ b/drivers/mtd/spi/spi-nor-core.c
> >@@ -75,11 +75,11 @@ struct sfdp_header {
> > /* Basic Flash Parameter Table */
> >
> > /*
> >- * JESD216 rev B defines a Basic Flash Parameter Table of 16 DWORDs.
> >+ * JESD216 rev D defines a Basic Flash Parameter Table of 20 DWORDs.
> >  * They are indexed from 1 but C arrays are indexed from 0.
> >  */
> > #define BFPT_DWORD(i)          ((i) - 1)
> >-#define BFPT_DWORD_MAX         16
> >+#define BFPT_DWORD_MAX         20
> 
> If we will change this according to rev D then you should also consider other revisions (rev B) because
> below condition will return 0 for revisions lower than rev D.
> 
> static int spi_nor_parse_bfpt() {
> ......
> 	1943         /* Stop here if not JESD216 rev A or later. */
> 	1944         if (bfpt_header->length < BFPT_DWORD_MAX)
> 	1945                 return 0;
> .....
> }
> 
> For flashes which does not support rev D will return from here.

Will fix in the next version. Thanks.
 

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown
  2020-05-13  6:44   ` Jagan Teki
@ 2020-05-19 15:09     ` Pratyush Yadav
  0 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-19 15:09 UTC (permalink / raw)
  To: u-boot

Hi Jagan,

On 13/05/20 12:14PM, Jagan Teki wrote:
> On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> >
> > On probe, the SPI NOR core will put a flash in 8D-8D-8D mode if it
> > supports it. But Linux as of now expects to get the flash in 1S-1S-1S
> > mode. Handing the flash to Linux in Octal DTR mode means the kernel will
> > fail to detect the flash.
> >
> > So, we need to reset to Power-on-Reset (POR) state before handing off
> > the flash. A Software Reset command can be used to do this. Since the
> > command is optional, flashes have to specify they support it by using
> > the flag 'SPI_NOR_SOFT_RESET'.
> >
> > One limitation of the soft reset is that it will restore state from
> > non-volatile registers in some flashes. This means that if the flash was
> > set to 8D mode in a non-volatile configuration, a soft reset won't help.
> > This commit assumes that we don't set any non-volatile bits anywhere,
> > and the flash doesn't have any non-volatile Octal DTR mode
> > configuration.
> 
> Is this common for all 8D supported flash devices?

The standard allows a flash to restore state from non-volatile 
registers, but doesn't mandates it.

I looked at a few flashes (like the Cypress S28 and Micron MT35XU 
flashes which this series adds support for), and all of them restored 
state from non-volatile registers. I'm not aware of any flash that 
restores state to factory defaults ignoring its non-volatile 
configuration, but I haven't looked at all the datasheets out there to 
make a definitive claim.
 
> >
> > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > ---
> >  drivers/mtd/spi/sf_internal.h  |  1 +
> >  drivers/mtd/spi/sf_probe.c     |  9 +++++
> >  drivers/mtd/spi/spi-nor-core.c | 66 ++++++++++++++++++++++++++++++++++
> >  include/linux/mtd/spi-nor.h    | 11 ++++++
> >  4 files changed, 87 insertions(+)
> >
> > diff --git a/drivers/mtd/spi/sf_internal.h b/drivers/mtd/spi/sf_internal.h
> > index 5780c81287..37e6657490 100644
> > --- a/drivers/mtd/spi/sf_internal.h
> > +++ b/drivers/mtd/spi/sf_internal.h
> > @@ -178,6 +186,7 @@ U_BOOT_DRIVER(spi_flash_std) = {
> >         .remove         = spi_flash_std_remove,
> >         .priv_auto_alloc_size = sizeof(struct spi_flash),
> >         .ops            = &spi_flash_std_ops,
> > +       .flags          = DM_FLAG_OS_PREPARE,
> >  };
> >
> >  #endif /* CONFIG_DM_SPI_FLASH */
> > diff --git a/drivers/mtd/spi/spi-nor-core.c b/drivers/mtd/spi/spi-nor-core.c
> > index 5b995cda3f..52b3775035 100644
> > --- a/drivers/mtd/spi/spi-nor-core.c
> > +++ b/drivers/mtd/spi/spi-nor-core.c
> > @@ -186,6 +186,8 @@ struct spi_nor_fixups {
> >                           struct spi_nor_flash_parameter *params);
> >  };
> >
> > +#define SPI_NOR_SRST_SLEEP_LEN                 200
> > +
> >  /**
> >   * spi_nor_get_cmd_ext() - Get the command opcode extension based on the
> >   *                        extension type.
> > @@ -2835,6 +2837,67 @@ static int spi_nor_init(struct spi_nor *nor)
> >         return 0;
> >  }
> >
> > +/**
> > + * spi_nor_soft_reset() - perform the JEDEC Software Reset sequence
> > + * @nor:       the spi_nor structure
> > + *
> > + * This function can be used to switch from Octal DTR mode to legacy mode on a
> > + * flash that supports it. The soft reset is executed in Octal DTR mode.
> > + *
> > + * Return: 0 for success, -errno for failure.
> > + */
> > +static int spi_nor_soft_reset(struct spi_nor *nor)
> > +{
> > +       struct spi_mem_op op;
> > +       int ret;
> > +       enum spi_nor_cmd_ext ext;
> > +
> > +       ext = nor->cmd_ext_type;
> > +       nor->cmd_ext_type = SPI_NOR_EXT_REPEAT;
> > +
> > +       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRSTEN, 8),
> > +                       SPI_MEM_OP_NO_DUMMY,
> > +                       SPI_MEM_OP_NO_ADDR,
> > +                       SPI_MEM_OP_NO_DATA);
> > +       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
> > +       ret = spi_mem_exec_op(nor->spi, &op);
> > +       if (ret) {
> > +               dev_warn(nor->dev, "Software reset enable failed: %d\n", ret);
> > +               goto out;
> > +       }
> > +
> > +       op = (struct spi_mem_op)SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_SRST, 8),
> > +                       SPI_MEM_OP_NO_DUMMY,
> > +                       SPI_MEM_OP_NO_ADDR,
> > +                       SPI_MEM_OP_NO_DATA);
> > +       spi_nor_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR);
> > +       ret = spi_mem_exec_op(nor->spi, &op);
> > +       if (ret) {
> > +               dev_warn(nor->dev, "Software reset failed: %d\n", ret);
> > +               goto out;
> > +       }
> > +
> > +       /*
> > +        * Software Reset is not instant, and the delay varies from flash to
> > +        * flash. Looking at a few flashes, most range somewhere below 100
> > +        * microseconds. So, wait for 200ms just to be sure.
> > +        */
> > +       udelay(SPI_NOR_SRST_SLEEP_LEN);
> 
> Any reference for this delay? I mean datasheet?

Unfortunately, the timings for the two flashes this series adds support 
for are not public. But as examples, you can look at n25q (90 ns), mt25q 
(40 ns), (20 ns) w25q (30 us).

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot
  2020-05-15  7:42           ` Jagan Teki
@ 2020-05-19 15:33             ` Pratyush Yadav
  0 siblings, 0 replies; 33+ messages in thread
From: Pratyush Yadav @ 2020-05-19 15:33 UTC (permalink / raw)
  To: u-boot

On 15/05/20 01:12PM, Jagan Teki wrote:
> On Wed, May 13, 2020 at 4:34 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> >
> > On 13/05/20 03:26PM, Jagan Teki wrote:
> > > On Wed, May 13, 2020 at 2:24 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > > >
> > > > On 13/05/20 12:17PM, Jagan Teki wrote:
> > > > > On Mon, Mar 30, 2020 at 9:16 PM Pratyush Yadav <p.yadav@ti.com> wrote:
> > > > > >
> > > > > > When the flash is handed to us in a stateful mode like 8D-8D-8D, it is
> > > > > > difficult to detect the mode the flash is in. One option is to read SFDP
> > > > > > in all modes and see which one gives the correct "SFDP" signature, but
> > > > > > not all flashes support SFDP in 8D-8D-8D mode.
> > > > > >
> > > > > > Further, even if you detect the mode of the flash via SFDP, you still
> > > > > > have the problem of actually reading the ID. The Read ID command is not
> > > > > > standardized across flash vendors. Flashes can have different dummy
> > > > > > cycles needed for reading the ID. Some flashes even expect a 4-byte
> > > > > > dummy address with the Read ID command. All this information cannot be
> > > > > > obtained from the SFDP table.
> > > > > >
> > > > > > So, perform a Software Reset sequence before reading the ID and
> > > > > > initializing the flash. A Soft Reset will bring back the flash in its
> > > > > > default protocol mode assuming no non-volatile configuration was set.
> > > > > > This will let us detect the flash even if ROM hands it to us in Octal
> > > > > > DTR mode.
> > > > > >
> > > > > > To accommodate cases where there is more than one flash on a board, and
> > > > > > only one of them needs a soft reset, failure to reset is not made fatal,
> > > > > > and we still try to read ID if possible.
> > > > > >
> > > > > > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
> > > > > > ---
> > > > > >  drivers/mtd/spi/Kconfig        | 11 +++++++++++
> > > > > >  drivers/mtd/spi/spi-nor-core.c | 27 +++++++++++++++++++++++++++
> > > > > >  2 files changed, 38 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/mtd/spi/spi-nor-core.c
> > > > > > b/drivers/mtd/spi/spi-nor-core.c
> > > > > > index 52b3775035..3af2c6afa9 100644
> > > > > > --- a/drivers/mtd/spi/spi-nor-core.c
> > > > > > +++ b/drivers/mtd/spi/spi-nor-core.c
> > > > > > @@ -2922,6 +2922,33 @@ int spi_nor_scan(struct spi_nor *nor)
> > > > > >
> > > > > >         nor->setup = spi_nor_default_setup;
> > > > > >
> > > > > > +#if defined(CONFIG_SPI_FLASH_SOFT_RESET)
> > > > > > +       /*
> > > > > > +        * When the flash is handed to us in a stateful mode like 8D-8D-8D, it
> > > > > > +        * is difficult to detect the mode the flash is in. One option is to
> > > > > > +        * read SFDP in all modes and see which one gives the correct "SFDP"
> > > > > > +        * signature, but not all flashes support SFDP in 8D-8D-8D mode.
> > > > > > +        *
> > > > > > +        * Further, even if you detect the mode of the flash via SFDP, you
> > > > > > +        * still have the problem of actually reading the ID. The Read ID
> > > > > > +        * command is not standardized across flash vendors. Flashes can have
> > > > > > +        * different dummy cycles needed for reading the ID. Some flashes even
> > > > > > +        * expect a 4-byte dummy address with the Read ID command. All this
> > > > > > +        * information cannot be obtained from the SFDP table.
> > > > > > +        *
> > > > > > +        * So, perform a Software Reset sequence before reading the ID and
> > > > > > +        * initializing the flash. A Soft Reset will bring back the flash in
> > > > > > +        * its default protocol mode assuming no non-volatile configuration was
> > > > > > +        * set. This will let us detect the flash even if ROM hands it to us in
> > > > > > +        * Octal DTR mode.
> > > > > > +        *
> > > > > > +        * To accommodate cases where there is more than one flash on a board,
> > > > > > +        * and only one of them needs a soft reset, failure to reset is not
> > > > > > +        * made fatal, and we still try to read ID if possible.
> > > > > > +        */
> > > > > > +       spi_nor_soft_reset(nor);
> > > > > > +#endif /* CONFIG_SPI_FLASH_SOFT_RESET */
> > > > >
> > > > > Does it specific to a particular flash chip? I believe add flash chip
> > > > > fixups would make more sense instead of having it like this.
> > > >
> > > > To run a flash fixup, we need to know which flash it is. But if ROM
> > > > hands us the flash in 8D mode, we can't reliably detect the ID of the
> > > > flash since the Read ID command differs from one flash to another. For
> > > > example, on the Cypress S28 flash family, the Read ID command in 8D mode
> > > > expects 4 dummy address bytes and 3 dummy cycles. But on the Micron
> > > > MT35XU flashes, Read ID in 8D needs 0 address bytes and 8 dummy cycles.
> > > >
> > > > This works around the issue by issuing a soft reset command so even if
> > > > the flash is in 8D mode, it gets switched back to 1S mode so we can
> > > > detect it.
> > >
> > > I got this from the commit message, thanks. Point I'm trying to
> > > understand here about can't we detect soft reset of associate flash
> > > via some bits in SFDP? if yes then we can dynamically process the soft
> > > reset on associated flash like quad enable does?
> >
> > If the device supports the Read SFDP command in 8D mode (it is optional
> > as per JESD251), then we can detect soft reset support via BFPT DWORD 16
> > bits 13:8.
> >
> > If we go that path, we would need to take the below steps before we can
> > proceed with the probe:
> >
> > - Issue Read SFDP in 8D mode and see if we get the "SFDP" signature
> >   correctly. If we don't, exit.
> >
> > - Read BFPT in 8D mode, and see if Soft Reset is supported.
> >
> > - If it is, issue a soft reset and go on as usual. If it isn't, error
> >   out, and the probe fails.
> >
> > The problem is, I'm not sure if controllers will be okay doing this on a
> > flash that is in 1S mode. Say the controller expects the DQS line to
> > toggle when the flash is sending data. Now, we tell the controller we
> > will read 16 bytes (SFDP header), but since the flash is in 1S mode, it
> > sees some other command and might not send out any data at all. In this
> > case, will the controller hang, waiting forever for the flash to toggle
> > DQS?
> >
> > FWIW, the controller on our board (Cadence QSPI) doesn't hang. But I'm
> > not sure how other controllers would react. That's why I went with the
> > more minimal option. The soft reset sequence doesn't expect to receive
> > any data. It only sends it.
> 
> So, we never sure if another controller (other than cadence) can
> guarantee to toggle the DQS? Can't the flash wait till to controller
> to toggle? I would like to see how this implemented in Linux, is it
> under progress or done in similar way?

DQS is just an example of something that can go wrong. The point I'm 
trying to make here is that since we don't know what state the flash is 
in, we might be issuing it commands in a different mode. Something like 
that can go wrong in many places, so we want to do as little as 
possible. That is why I hid this behind a config so people who don't 
need this don't have to bother with the trouble.

The soft reset sequence sends out 2 bytes and that's it. Detecting it 
via SFDP involves reading SFDP in 8D mode. It is much more complicated, 
and so much more can go wrong.

We are trying to solve an impossible problem here: cleanly handling 
flashes booting in stateful mode (I wrote about it here [0]). IMHO we 
should be trying to get away with as little as we can.

Linux's stance on this problem is that "bootloaders should hand us the 
flash in 1S mode. We don't want to deal with this problem as of now." 
Someone somewhere has to do this. Right now, that burden falls on the 
bootloader.
 
[0] https://lore.kernel.org/linux-mtd/20200228093658.zc3uifqg4zruokq3 at ti.com/

-- 
Regards,
Pratyush Yadav
Texas Instruments India

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2020-05-19 15:33 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-30 15:45 [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 01/17] spi: spi-mem: allow specifying whether an op is DTR or not Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 02/17] spi: spi-mem: allow specifying a command's extension Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 03/17] spi: cadence-qspi: Do not calibrate when device tree sets read delay Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 04/17] spi: cadence-qspi: Add support for octal DTR flashes Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 05/17] mtd: spi-nor-core: Add a ->setup() hook Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 06/17] mtd: spi-nor-core: Move SFDP related declarations to top Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 07/17] mtd: spi-nor-core: Introduce flash-specific fixup hooks Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 08/17] mtd: spi-nor-core: Rework hwcaps selection Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 09/17] mtd: spi-nor-core: Add support for DTR protocol Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 10/17] mtd: spi-nor-core: Get command opcode extension type from BFPT Pratyush Yadav
2020-05-18 14:31   ` Pragnesh Patel
2020-05-18 18:33     ` Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 11/17] mtd: spi-nor-core: Parse xSPI Profile 1.0 table Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 12/17] mtd: spi-nor-core: Prepare Read SR and FSR for Octal DTR mode Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 13/17] mtd: spi-nor-core: Enable octal DTR mode when possible Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 14/17] mtd: spi-nor-core: Perform a Soft Reset on shutdown Pratyush Yadav
2020-05-13  6:44   ` Jagan Teki
2020-05-19 15:09     ` Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 15/17] mtd: spi-nor-core: Perform a Soft Reset on boot Pratyush Yadav
2020-05-13  6:47   ` Jagan Teki
2020-05-13  8:54     ` Pratyush Yadav
2020-05-13  9:56       ` Jagan Teki
2020-05-13 11:04         ` Pratyush Yadav
2020-05-15  7:42           ` Jagan Teki
2020-05-19 15:33             ` Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 16/17] mtd: spi-nor-core: Add support for Cypress Semper flash Pratyush Yadav
2020-03-30 15:45 ` [PATCH v3 17/17] mtd: spi-nor-core: Allow using Micron mt35xu512aba in Octal DTR mode Pratyush Yadav
2020-04-21  7:49 ` [PATCH v3 00/17] mtd: spi-nor-core: add xSPI Octal DTR support Pratyush Yadav
2020-04-21  8:09   ` Jagan Teki
2020-05-05  7:58   ` Vignesh Raghavendra
2020-05-12 16:43 ` Jagan Teki
2020-05-12 18:23   ` Pratyush Yadav

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.