All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wenyou Yang <wenyou.yang@microchip.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 1/8] spi: add support of SPI flash commands
Date: Tue, 25 Jul 2017 15:00:55 +0800	[thread overview]
Message-ID: <20170725070102.1344-2-wenyou.yang@microchip.com> (raw)
In-Reply-To: <20170725070102.1344-1-wenyou.yang@microchip.com>

From: Cyrille Pitchen <cyrille.pitchen@atmel.com>

This patch introduces 'struct spi_flash_command' and functions
spi_is_flash_command_supported() / spi_exec_flash_command().

The 'struct spi_flash_command' describes all the relevant parameters to
execute any SPI flash command:
- the instruction op code
- the number of bytes used to send the address: 0, 3 or 4 bytes
- the number of mode and wait-state clock cycles, also called dummy cycles
- the number and values of data bytes to be sent or received
- the SPI x-y-z protocol [1]
- the flash command type [2]

[1] SPI x-y-z protocol:
- x is the number of I/O lines used to send the instruction op code.
- y is the number of I/O lines used during address, mode and wait-state
  clock cycles.
- z is the number of I/O lines used to send or received data.

[2] Flash command type:
The flash command type is provided to differenciate "memory"
read/write/erase operations from "flash internal register" read/write
operations. Indeed some SPI controller drivers handle those command type
in different ways.
However SPI controller drivers should not check the value of the
instruction op code to guess the actual kind of flash command to perform.
Many instruction op codes are SPI flash manufacturer specific and only
drivers/mtd/spi/spi_flash.c should have the knowledge of all of them.

Besides, more and more QSPI controllers, like those of TI and Candence,
have special way to support (Fast) Read operations using some
"memory like" area mapped into the system bus. Hence, if those drivers
choose to override the default implementation of
spi_is_flash_command_supported() so that their own functions return true
only for a "memory read" flash command type, then spi_exec_flash_command()
might be used to implement the read from the "memory like" area mapped
into the system bus.
It means that spi_exec_flash_command() could be used to supersede the
actual flash->memory_map mechanism; spi_is_flash_command_supported() /
spi_exec_flash_command() being more generic and covering more use cases.

For instance, the Atmel QSPI hardware controller uses its "memory like"
area mapped ino the system to perform not only (Fast) Read operations but
actually all other types of flash commands. Hence the regular SPI API
based on the spi_xfer() function is not suited to support the Atmel QSPI
controller.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
---

Changes in v3: None
Changes in v2: None

 drivers/spi/spi-uclass.c |  40 +++++++++++
 drivers/spi/spi.c        |  13 ++++
 include/spi.h            | 168 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 221 insertions(+)

diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index e06a603ab1..5de4510363 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -91,6 +91,30 @@ int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
+bool dm_spi_is_flash_command_supported(struct udevice *dev,
+				       const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->is_flash_command_supported)
+		return ops->is_flash_command_supported(dev, cmd);
+
+	return false;
+}
+
+int dm_spi_exec_flash_command(struct udevice *dev,
+			      const struct spi_flash_command *cmd)
+{
+	struct udevice *bus = dev->parent;
+	struct dm_spi_ops *ops = spi_get_ops(bus);
+
+	if (ops->exec_flash_command)
+		return ops->exec_flash_command(dev, cmd);
+
+	return -EINVAL;
+}
+
 int spi_claim_bus(struct spi_slave *slave)
 {
 	return dm_spi_claim_bus(slave->dev);
@@ -107,6 +131,18 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
 	return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
 }
 
+bool spi_is_flash_command_supported(struct spi_slave *slave,
+				    const struct spi_flash_command *cmd)
+{
+	return dm_spi_is_flash_command_supported(slave->dev, cmd);
+}
+
+int spi_exec_flash_command(struct spi_slave *slave,
+			   const struct spi_flash_command *cmd)
+{
+	return dm_spi_exec_flash_command(slave->dev, cmd);
+}
+
 #if !CONFIG_IS_ENABLED(OF_PLATDATA)
 static int spi_child_post_bind(struct udevice *dev)
 {
@@ -144,6 +180,10 @@ static int spi_post_probe(struct udevice *bus)
 		ops->set_mode += gd->reloc_off;
 	if (ops->cs_info)
 		ops->cs_info += gd->reloc_off;
+	if (ops->is_flash_command_supported)
+		ops->is_flash_command_supported += gd->reloc_off;
+	if (ops->exec_flash_command)
+		ops->exec_flash_command += gd->reloc_off;
 #endif
 
 	return 0;
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 7d81fbd7f8..e47acdc9e4 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -5,6 +5,7 @@
  */
 
 #include <common.h>
+#include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
 #include <spi.h>
@@ -58,3 +59,15 @@ struct spi_slave *spi_base_setup_slave_fdt(const void *blob, int busnum,
 	return spi_setup_slave(busnum, cs, max_hz, mode);
 }
 #endif
+
+__weak bool spi_is_flash_command_supported(struct spi_slave *slave,
+					   const struct spi_flash_command *cmd)
+{
+	return false;
+}
+
+__weak int spi_exec_flash_command(struct spi_slave *slave,
+				  const struct spi_flash_command *cmd)
+{
+	return -EINVAL;
+}
diff --git a/include/spi.h b/include/spi.h
index 8c4b882c54..a090266b52 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -10,6 +10,8 @@
 #ifndef _SPI_H_
 #define _SPI_H_
 
+#include <linux/string.h> /* memset() */
+
 /* SPI mode flags */
 #define SPI_CPHA	BIT(0)			/* clock phase */
 #define SPI_CPOL	BIT(1)			/* clock polarity */
@@ -64,6 +66,116 @@ struct dm_spi_slave_platdata {
 #endif /* CONFIG_DM_SPI */
 
 /**
+ * enum spi_flash_protocol - SPI flash command protocol
+ */
+#define SPI_FPROTO_INST_SHIFT	16
+#define SPI_FPROTO_INST_MASK	GENMASK(23, 16)
+#define SPI_FPROTO_INST(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_INST_SHIFT) &	\
+	 SPI_FPROTO_INST_MASK)
+
+#define SPI_FPROTO_ADDR_SHIFT	8
+#define SPI_FPROTO_ADDR_MASK	GENMASK(15, 8)
+#define SPI_FPROTO_ADDR(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_ADDR_SHIFT) &	\
+	 SPI_FPROTO_ADDR_MASK)
+
+#define SPI_FPROTO_DATA_SHIFT	0
+#define SPI_FPROTO_DATA_MASK	GENMASK(7, 0)
+#define SPI_FPROTO_DATA(nbits)					\
+	((((unsigned long)(nbits)) << SPI_FPROTO_DATA_SHIFT) &	\
+	 SPI_FPROTO_DATA_MASK)
+
+#define SPI_FPROTO(inst_nbits, addr_nbits, data_nbits)	\
+	(SPI_FPROTO_INST(inst_nbits) |			\
+	 SPI_FPROTO_ADDR(addr_nbits) |			\
+	 SPI_FPROTO_DATA(data_nbits))
+
+enum spi_flash_protocol {
+	SPI_FPROTO_1_1_1 = SPI_FPROTO(1, 1, 1),
+	SPI_FPROTO_1_1_2 = SPI_FPROTO(1, 1, 2),
+	SPI_FPROTO_1_1_4 = SPI_FPROTO(1, 1, 4),
+	SPI_FPROTO_1_2_2 = SPI_FPROTO(1, 2, 2),
+	SPI_FPROTO_1_4_4 = SPI_FPROTO(1, 4, 4),
+	SPI_FPROTO_2_2_2 = SPI_FPROTO(2, 2, 2),
+	SPI_FPROTO_4_4_4 = SPI_FPROTO(4, 4, 4),
+};
+
+static inline
+u8 spi_flash_protocol_get_inst_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_INST_MASK)) >>
+		SPI_FPROTO_INST_SHIFT;
+}
+
+static inline
+u8 spi_flash_protocol_get_addr_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_ADDR_MASK)) >>
+		SPI_FPROTO_ADDR_SHIFT;
+}
+
+static inline
+u8 spi_flash_protocol_get_data_nbits(enum spi_flash_protocol proto)
+{
+	return ((unsigned long)(proto & SPI_FPROTO_DATA_MASK)) >>
+		SPI_FPROTO_DATA_SHIFT;
+}
+
+/**
+ * struct spi_flash_command - SPI flash command structure
+ *
+ * @instr:		Opcode sent to the SPI slave during instr clock cycles.
+ * @mode:		Value sent to the SPI slave during mode clock cycles.
+ * @num_mode_cycles:	Number of mode clock cycles.
+ * @num_wait_states:	Number of wait-state clock cycles.
+ * @addr_len:		Number of bytes sent during address clock cycles:
+ *			should be 0, 3, or 4.
+ * @addr:		Value sent to the SPI slave during address clock cycles.
+ * @data_len:		Number of bytes to be sent during data clock cycles.
+ * @tx_data:		Data sent to the SPI slave during data clock cycles.
+ * @rx_data:		Data read from the SPI slave during data clock cycles.
+ */
+struct spi_flash_command {
+	enum spi_flash_protocol proto;
+	u8 flags;
+#define SPI_FCMD_TYPE		GENMASK(2, 0)
+#define SPI_FCMD_READ		(0x0U << 0)
+#define SPI_FCMD_WRITE		(0x1U << 0)
+#define SPI_FCMD_ERASE		(0x2U << 0)
+#define SPI_FCMD_READ_REG	(0x3U << 0)
+#define SPI_FCMD_WRITE_REG	(0x4U << 0)
+
+	u8 inst;
+	u8 mode;
+	u8 num_mode_cycles;
+	u8 num_wait_states;
+	u8 addr_len;
+	u32 addr;
+	size_t data_len;
+	const void *tx_data;
+	void *rx_data;
+};
+
+/**
+ * Initialize a 'struct spi_flash_command'.
+ *
+ * @cmd:		Pointer to the 'struct spi_flash_command' to initialize.
+ * @instr:		Instruction opcode.
+ * @addr_len:		Number of address bytes.
+ */
+static inline void
+spi_flash_command_init(struct spi_flash_command *cmd,
+		       u8 inst, u8 addr_len, u8 flags)
+{
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->proto = SPI_FPROTO_1_1_1;
+	cmd->inst = inst;
+	cmd->addr_len = addr_len;
+	cmd->flags = flags;
+}
+
+/**
  * struct spi_slave - Representation of a SPI slave
  *
  * For driver model this is the per-child data used by the SPI bus. It can
@@ -252,6 +364,24 @@ int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen);
 int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
 		void *din, unsigned long flags);
 
+/**
+ * Check whether the given SPI flash command is supported
+ *
+ * @slave:	The SPI slave
+ * @cmd:	The SPI flash command to check.
+ */
+bool spi_is_flash_command_supported(struct spi_slave *slave,
+				    const struct spi_flash_command *cmd);
+
+/**
+ * Execute SPI flash command
+ *
+ * @slave:	The SPI slave which will execute the give SPI flash command.
+ * @cmd:	The SPI flash command to execute.
+ */
+int spi_exec_flash_command(struct spi_slave *slave,
+			   const struct spi_flash_command *cmd);
+
 /* Copy memory mapped data */
 void spi_flash_copy_mmap(void *data, void *offset, size_t len);
 
@@ -464,6 +594,26 @@ struct dm_spi_ops {
 	 *	   is invalid, other -ve value on error
 	 */
 	int (*cs_info)(struct udevice *bus, uint cs, struct spi_cs_info *info);
+
+	/**
+	 * Check whether the given SPI flash command is supported.
+	 *
+	 * @bus:	The SPI bus
+	 * @cmd:	The SPI flash command to check.
+	 * @return:	true if supported, false otherwise
+	 */
+	bool (*is_flash_command_supported)(struct udevice *bus,
+					   const struct spi_flash_command *cmd);
+
+	/**
+	 * Execute a SPI flash command
+	 *
+	 * @bus:	The SPI bus
+	 * @cmd:	The SPI flash command to execute.
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*exec_flash_command)(struct udevice *bus,
+				  const struct spi_flash_command *cmd);
 };
 
 struct dm_spi_emul_ops {
@@ -651,6 +801,24 @@ void dm_spi_release_bus(struct udevice *dev);
 int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
 		const void *dout, void *din, unsigned long flags);
 
+/**
+ * Check whether the given SPI flash command is supported.
+ *
+ * @dev:	The SPI slave device
+ * @cmd:	The SPI flash command
+ */
+bool dm_spi_is_flash_command_supported(struct udevice *dev,
+				       const struct spi_flash_command *cmd);
+
+/**
+ * Execute the given SPI flash command.
+ *
+ * @dev:	The SPI slave device
+ * @cmd:	The SPI flash command
+ */
+int dm_spi_exec_flash_command(struct udevice *dev,
+			      const struct spi_flash_command *cmd);
+
 /* Access the operations for a SPI device */
 #define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
 #define spi_emul_get_ops(dev)	((struct dm_spi_emul_ops *)(dev)->driver->ops)
-- 
2.13.0

  reply	other threads:[~2017-07-25  7:00 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-25  7:00 [U-Boot] [PATCH v3 0/8] sf: improve support of (Q)SPI flash memories Wenyou Yang
2017-07-25  7:00 ` Wenyou Yang [this message]
2017-08-30 13:50   ` [U-Boot] [PATCH v3 1/8] spi: add support of SPI flash commands Jagan Teki
2017-09-01  0:10     ` Wenyou.Yang at microchip.com
2017-07-25  7:00 ` [U-Boot] [PATCH v3 2/8] sf: describe all SPI flash commands with 'struct spi_flash_command' Wenyou Yang
2017-08-30 14:03   ` Jagan Teki
2017-07-25  7:00 ` [U-Boot] [PATCH v3 3/8] sf: select the relevant SPI flash protocol for read and write commands Wenyou Yang
2017-07-25  7:00 ` [U-Boot] [PATCH v3 4/8] sf: differentiate Page Program 1-1-4 and 1-4-4 Wenyou Yang
2017-07-25  7:00 ` [U-Boot] [PATCH v3 5/8] sf: add 'addr_len' member to 'struct spi_flash' Wenyou Yang
2017-07-25  7:01 ` [U-Boot] [PATCH v3 6/8] sf: add new option to support SPI flash above 16MiB Wenyou Yang
2017-07-25  7:01 ` [U-Boot] [PATCH v3 7/8] sf: add support to Microchip SST26 QSPI memories Wenyou Yang
2017-07-25  7:01 ` [U-Boot] [PATCH v3 8/8] sf: add driver for Atmel QSPI controller Wenyou Yang
2017-08-30 13:58   ` Jagan Teki
2017-07-31  7:29 ` [U-Boot] [PATCH v3 0/8] sf: improve support of (Q)SPI flash memories Yang, Wenyou
2017-08-11  1:02 ` Yang, Wenyou
2017-08-11  5:14   ` Jagan Teki
2017-08-25  1:17 ` Yang, Wenyou
2017-08-25 16:07   ` Jagan Teki
2017-08-25 16:13     ` Marek Vasut
2017-08-25 16:28       ` Jagan Teki
2017-08-25 16:45         ` Marek Vasut
2017-08-25 23:05           ` Bin Meng
2017-08-26  6:14             ` Jagan Teki
2017-08-26  8:36               ` Marek Vasut
2017-08-26 19:12                 ` Tom Rini
2017-08-26  6:34 ` Jagan Teki
2017-08-30  1:58   ` Yang, Wenyou
2017-08-30  6:33     ` Jagan Teki
2017-08-30  3:25   ` Yang, Wenyou
2017-08-30  3:43     ` Bin Meng
2017-08-30  5:27       ` Yang, Wenyou
2017-08-30  5:41         ` Bin Meng
2017-08-30  5:51           ` Yang, Wenyou
2017-08-30  6:30           ` Jagan Teki
2017-08-30  7:47             ` Bin Meng
2017-08-30 13:25               ` Jagan Teki

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20170725070102.1344-2-wenyou.yang@microchip.com \
    --to=wenyou.yang@microchip.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

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

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