Commit 6423207e authored by Serge Semin's avatar Serge Semin Committed by Mark Brown

spi: dw: Add memory operations support

Aside from the synchronous Tx-Rx mode, which has been utilized to create
the normal SPI transfers in the framework of the DW SSI driver, DW SPI
controller supports Tx-only and EEPROM-read modes. The former one just
enables the controller to transmit all the data from the Tx FIFO ignoring
anything retrieved from the MISO lane. The later mode is so called
write-then-read operation: DW SPI controller first pushes out all the data
from the Tx FIFO, after that it'll automatically receive as much data as
has been specified by means of the CTRLR1 register. Both of those modes
can be used to implement the memory operations supported by the SPI-memory
subsystem.

The memory operation implementation is pretty much straightforward, except
a few peculiarities we have had to take into account to make things
working. Since DW SPI controller doesn't provide a way to directly set and
clear the native CS lane level, but instead automatically de-asserts it
when a transfer going on, we have to make sure the Tx FIFO isn't empty
during entire Tx procedure. In addition we also need to read data from the
Rx FIFO as fast as possible to prevent it' overflow with automatically
fetched incoming traffic. The denoted peculiarities get to cause even more
problems if DW SSI controller is equipped with relatively small FIFO and
is connected to a relatively slow system bus (APB) (with respect to the
SPI bus speed). In order to workaround the problems for as much as it's
possible, the memory operation execution procedure collects all the Tx
data into a single buffer and disables the local IRQs to speed the
write-then-optionally-read method up.

Note the provided memory operations are utilized by default only if
a glue driver hasn't provided a custom version of ones and this is not
a DW APB SSI controller with fixed automatic CS toggle functionality.
Co-developed-by: default avatarRamil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: default avatarRamil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: default avatarSerge Semin <Sergey.Semin@baikalelectronics.ru>
Link: https://lore.kernel.org/r/20201007235511.4935-18-Sergey.Semin@baikalelectronics.ruSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent bf64b660
...@@ -235,6 +235,7 @@ config SPI_DAVINCI ...@@ -235,6 +235,7 @@ config SPI_DAVINCI
config SPI_DESIGNWARE config SPI_DESIGNWARE
tristate "DesignWare SPI controller core support" tristate "DesignWare SPI controller core support"
imply SPI_MEM
help help
general driver for SPI controller core from DesignWare general driver for SPI controller core from DesignWare
......
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/irqreturn.h> #include <linux/irqreturn.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/scatterlist.h> #include <linux/scatterlist.h>
#include <linux/spi/spi-mem.h>
/* Register offsets */ /* Register offsets */
#define DW_SPI_CTRLR0 0x00 #define DW_SPI_CTRLR0 0x00
...@@ -78,6 +79,9 @@ ...@@ -78,6 +79,9 @@
*/ */
#define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31) #define DWC_SSI_CTRLR0_KEEMBAY_MST BIT(31)
/* Bit fields in CTRLR1 */
#define SPI_NDF_MASK GENMASK(15, 0)
/* Bit fields in SR, 7 bits */ /* Bit fields in SR, 7 bits */
#define SR_MASK 0x7f /* cover 7 bits */ #define SR_MASK 0x7f /* cover 7 bits */
#define SR_BUSY (1 << 0) #define SR_BUSY (1 << 0)
...@@ -101,6 +105,11 @@ ...@@ -101,6 +105,11 @@
#define SPI_DMA_TDMAE (1 << 1) #define SPI_DMA_TDMAE (1 << 1)
#define SPI_WAIT_RETRIES 5 #define SPI_WAIT_RETRIES 5
#define SPI_BUF_SIZE \
(sizeof_field(struct spi_mem_op, cmd.opcode) + \
sizeof_field(struct spi_mem_op, addr.val) + 256)
#define SPI_GET_BYTE(_val, _idx) \
((_val) >> (BITS_PER_BYTE * (_idx)) & 0xff)
enum dw_ssi_type { enum dw_ssi_type {
SSI_MOTO_SPI = 0, SSI_MOTO_SPI = 0,
...@@ -153,6 +162,7 @@ struct dw_spi { ...@@ -153,6 +162,7 @@ struct dw_spi {
unsigned int tx_len; unsigned int tx_len;
void *rx; void *rx;
unsigned int rx_len; unsigned int rx_len;
u8 buf[SPI_BUF_SIZE];
int dma_mapped; int dma_mapped;
u8 n_bytes; /* current is a 1/2 bytes op */ u8 n_bytes; /* current is a 1/2 bytes op */
irqreturn_t (*transfer_handler)(struct dw_spi *dws); irqreturn_t (*transfer_handler)(struct dw_spi *dws);
...@@ -160,6 +170,9 @@ struct dw_spi { ...@@ -160,6 +170,9 @@ struct dw_spi {
u32 cur_rx_sample_dly; u32 cur_rx_sample_dly;
u32 def_rx_sample_dly_ns; u32 def_rx_sample_dly_ns;
/* Custom memory operations */
struct spi_controller_mem_ops mem_ops;
/* DMA info */ /* DMA info */
struct dma_chan *txchan; struct dma_chan *txchan;
u32 txburst; u32 txburst;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment