|
|
@@ -0,0 +1,179 @@
|
|
|
+From 556351f14e74db4cd3ddde386457edce7bf0b27f Mon Sep 17 00:00:00 2001
|
|
|
+From: Vignesh R <[email protected]>
|
|
|
+Date: Fri, 11 Dec 2015 09:39:56 +0530
|
|
|
+Subject: [PATCH] spi: introduce accelerated read support for spi flash devices
|
|
|
+
|
|
|
+In addition to providing direct access to SPI bus, some spi controller
|
|
|
+hardwares (like ti-qspi) provide special port (like memory mapped port)
|
|
|
+that are optimized to improve SPI flash read performance.
|
|
|
+This means the controller can automatically send the SPI signals
|
|
|
+required to read data from the SPI flash device.
|
|
|
+For this, SPI controller needs to know flash specific information like
|
|
|
+read command to use, dummy bytes and address width.
|
|
|
+
|
|
|
+Introduce spi_flash_read() interface to support accelerated read
|
|
|
+over SPI flash devices. SPI master drivers can implement this callback to
|
|
|
+support interfaces such as memory mapped read etc. m25p80 flash driver
|
|
|
+and other flash drivers can call this make use of such interfaces. The
|
|
|
+interface should only be used with SPI flashes and cannot be used with
|
|
|
+other SPI devices.
|
|
|
+
|
|
|
+Signed-off-by: Vignesh R <[email protected]>
|
|
|
+Signed-off-by: Mark Brown <[email protected]>
|
|
|
+---
|
|
|
+
|
|
|
+--- a/drivers/spi/spi.c
|
|
|
++++ b/drivers/spi/spi.c
|
|
|
+@@ -1135,6 +1135,7 @@ static void __spi_pump_messages(struct s
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
++ mutex_lock(&master->bus_lock_mutex);
|
|
|
+ trace_spi_message_start(master->cur_msg);
|
|
|
+
|
|
|
+ if (master->prepare_message) {
|
|
|
+@@ -1144,6 +1145,7 @@ static void __spi_pump_messages(struct s
|
|
|
+ "failed to prepare message: %d\n", ret);
|
|
|
+ master->cur_msg->status = ret;
|
|
|
+ spi_finalize_current_message(master);
|
|
|
++ mutex_unlock(&master->bus_lock_mutex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ master->cur_msg_prepared = true;
|
|
|
+@@ -1153,6 +1155,7 @@ static void __spi_pump_messages(struct s
|
|
|
+ if (ret) {
|
|
|
+ master->cur_msg->status = ret;
|
|
|
+ spi_finalize_current_message(master);
|
|
|
++ mutex_unlock(&master->bus_lock_mutex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -1160,8 +1163,10 @@ static void __spi_pump_messages(struct s
|
|
|
+ if (ret) {
|
|
|
+ dev_err(&master->dev,
|
|
|
+ "failed to transfer one message from queue\n");
|
|
|
++ mutex_unlock(&master->bus_lock_mutex);
|
|
|
+ return;
|
|
|
+ }
|
|
|
++ mutex_unlock(&master->bus_lock_mutex);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+@@ -2329,6 +2334,46 @@ int spi_async_locked(struct spi_device *
|
|
|
+ EXPORT_SYMBOL_GPL(spi_async_locked);
|
|
|
+
|
|
|
+
|
|
|
++int spi_flash_read(struct spi_device *spi,
|
|
|
++ struct spi_flash_read_message *msg)
|
|
|
++
|
|
|
++{
|
|
|
++ struct spi_master *master = spi->master;
|
|
|
++ int ret;
|
|
|
++
|
|
|
++ if ((msg->opcode_nbits == SPI_NBITS_DUAL ||
|
|
|
++ msg->addr_nbits == SPI_NBITS_DUAL) &&
|
|
|
++ !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD)))
|
|
|
++ return -EINVAL;
|
|
|
++ if ((msg->opcode_nbits == SPI_NBITS_QUAD ||
|
|
|
++ msg->addr_nbits == SPI_NBITS_QUAD) &&
|
|
|
++ !(spi->mode & SPI_TX_QUAD))
|
|
|
++ return -EINVAL;
|
|
|
++ if (msg->data_nbits == SPI_NBITS_DUAL &&
|
|
|
++ !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD)))
|
|
|
++ return -EINVAL;
|
|
|
++ if (msg->data_nbits == SPI_NBITS_QUAD &&
|
|
|
++ !(spi->mode & SPI_RX_QUAD))
|
|
|
++ return -EINVAL;
|
|
|
++
|
|
|
++ if (master->auto_runtime_pm) {
|
|
|
++ ret = pm_runtime_get_sync(master->dev.parent);
|
|
|
++ if (ret < 0) {
|
|
|
++ dev_err(&master->dev, "Failed to power device: %d\n",
|
|
|
++ ret);
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ mutex_lock(&master->bus_lock_mutex);
|
|
|
++ ret = master->spi_flash_read(spi, msg);
|
|
|
++ mutex_unlock(&master->bus_lock_mutex);
|
|
|
++ if (master->auto_runtime_pm)
|
|
|
++ pm_runtime_put(master->dev.parent);
|
|
|
++
|
|
|
++ return ret;
|
|
|
++}
|
|
|
++EXPORT_SYMBOL_GPL(spi_flash_read);
|
|
|
++
|
|
|
+ /*-------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+ /* Utility methods for SPI master protocol drivers, layered on
|
|
|
+--- a/include/linux/spi/spi.h
|
|
|
++++ b/include/linux/spi/spi.h
|
|
|
+@@ -25,6 +25,7 @@
|
|
|
+ struct dma_chan;
|
|
|
+ struct spi_master;
|
|
|
+ struct spi_transfer;
|
|
|
++struct spi_flash_read_message;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * INTERFACES between SPI master-side drivers and SPI infrastructure.
|
|
|
+@@ -361,6 +362,8 @@ static inline void spi_unregister_driver
|
|
|
+ * @handle_err: the subsystem calls the driver to handle an error that occurs
|
|
|
+ * in the generic implementation of transfer_one_message().
|
|
|
+ * @unprepare_message: undo any work done by prepare_message().
|
|
|
++ * @spi_flash_read: to support spi-controller hardwares that provide
|
|
|
++ * accelerated interface to read from flash devices.
|
|
|
+ * @cs_gpios: Array of GPIOs to use as chip select lines; one per CS
|
|
|
+ * number. Any individual value may be -ENOENT for CS lines that
|
|
|
+ * are not GPIOs (driven by the SPI controller itself).
|
|
|
+@@ -507,6 +510,8 @@ struct spi_master {
|
|
|
+ struct spi_message *message);
|
|
|
+ int (*unprepare_message)(struct spi_master *master,
|
|
|
+ struct spi_message *message);
|
|
|
++ int (*spi_flash_read)(struct spi_device *spi,
|
|
|
++ struct spi_flash_read_message *msg);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * These hooks are for drivers that use a generic implementation
|
|
|
+@@ -999,6 +1004,42 @@ static inline ssize_t spi_w8r16be(struct
|
|
|
+ return be16_to_cpu(result);
|
|
|
+ }
|
|
|
+
|
|
|
++/**
|
|
|
++ * struct spi_flash_read_message - flash specific information for
|
|
|
++ * spi-masters that provide accelerated flash read interfaces
|
|
|
++ * @buf: buffer to read data
|
|
|
++ * @from: offset within the flash from where data is to be read
|
|
|
++ * @len: length of data to be read
|
|
|
++ * @retlen: actual length of data read
|
|
|
++ * @read_opcode: read_opcode to be used to communicate with flash
|
|
|
++ * @addr_width: number of address bytes
|
|
|
++ * @dummy_bytes: number of dummy bytes
|
|
|
++ * @opcode_nbits: number of lines to send opcode
|
|
|
++ * @addr_nbits: number of lines to send address
|
|
|
++ * @data_nbits: number of lines for data
|
|
|
++ */
|
|
|
++struct spi_flash_read_message {
|
|
|
++ void *buf;
|
|
|
++ loff_t from;
|
|
|
++ size_t len;
|
|
|
++ size_t retlen;
|
|
|
++ u8 read_opcode;
|
|
|
++ u8 addr_width;
|
|
|
++ u8 dummy_bytes;
|
|
|
++ u8 opcode_nbits;
|
|
|
++ u8 addr_nbits;
|
|
|
++ u8 data_nbits;
|
|
|
++};
|
|
|
++
|
|
|
++/* SPI core interface for flash read support */
|
|
|
++static inline bool spi_flash_read_supported(struct spi_device *spi)
|
|
|
++{
|
|
|
++ return spi->master->spi_flash_read ? true : false;
|
|
|
++}
|
|
|
++
|
|
|
++int spi_flash_read(struct spi_device *spi,
|
|
|
++ struct spi_flash_read_message *msg);
|
|
|
++
|
|
|
+ /*---------------------------------------------------------------------------*/
|
|
|
+
|
|
|
+ /*
|