All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
@ 2020-09-20 11:28 Serge Semin
  2020-09-20 11:28 ` [PATCH 01/30] spi: dw: Discard IRQ threshold macro Serge Semin
                   ` (31 more replies)
  0 siblings, 32 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Originally I intended to merge a dedicated Baikal-T1 System Boot SPI
Controller driver into the kernel and leave the DW APB SSI driver
untouched. But after a long discussion (see the link at the bottom of the
letter) Mark and Andy persuaded me to integrate what we developed there
into the DW APB SSI core driver to be useful for another controllers,
which may have got the same peculiarities/problems as ours:
- No IRQ.
- No DMA.
- No GPIO CS, so a native CS is utilized.
- small Tx/Rx FIFO depth.
- Automatic CS assertion/de-assertion.
- Slow system bus.
All of them have been fixed in the framework of this patchset in some
extent at least for the SPI memory operations. As I expected it wasn't
that easy and the integration took that many patches as you can see from
the subject. Though some of them are mere cleanups or weakly related with
the subject fixes, but we just couldn't leave the code as is at some
places since we were working with the DW APB SSI driver anyway. Here is
what we did to fix the original DW APB SSI driver, to make it less messy.

First two patches are just cleanups to simplify the DW APB SSI device
initialization a bit. We suggest to discard the IRQ threshold macro as
unused and use a ternary operator to initialize the set_cs callback
instead of assigning-and-updating it.

Then we've discovered that the n_bytes field of the driver private data is
used by the DW APB SSI IRQ handler, which requires it to be initialized
before the SMP memory barrier and to be visible from another CPUs. Speaking
about the SMP memory barrier. Having one right after the shared resources
initialization is enough and there is no point in using the spin-lock to
protect the Tx/Rx buffer pointers. The protection functionality is
redundant there by the driver design. (Though I have a doubt whether the
SMP memory barrier is also required there because the normal IO-methods
like readl/writel implies a full memory barrier. So any memory operations
performed before them are supposed to be seen by devices and another CPUs.
See the patch log for details of my concern.)

Thirdly we've found out that there is some confusion in the IRQs
masking/unmasking/clearing in the SPI-transfer procedure. Multiple interrupts
are unmasked on the SPI-transfer initialization, but just TXEI is only
masked back on completion. Similarly IRQ status isn't cleared on the
controller reset, which actually makes the reset being not full and errors
prone in the controller probe procedure.

Another very important optimization is using the IO-relaxed accessors in
the dw_read_io_reg()/dw_write_io_reg() methods. Since the Tx/Rx FIFO data
registers are the most frequently accessible controller resource, using
relaxed accessors there will significantly improve the data read/write
performance. At least on Baikal-T1 SoC such modification opens up a way to
have the DW APB SSI controller working with higher SPI bus speeds, than
without it.

Fifthly we've made an effort to cleanup the code using the SPI-device
private data - chip_data. We suggest to remove the chip type from there
since it isn't used and isn't implemented right anyway. Then instead of
having a bus speed, clock divider, transfer mode preserved there, and
recalculating the CR0 fields of the SPI-device-specific phase, polarity
and frame format each time the SPI transfer is requested, we can save it
in the chip_data instance. By doing so we'll make that structure finally
used as it was supposed to by design (see the spi-fsl-dspi.c, spi-pl022.c,
spi-pxa2xx.c drivers for examples).

Sixthly instead of having the SPI-transfer specific CR0-update callback,
we suggest to implement the DW APB SSI controller capabilities approach.
By doing so we can now inject the vendor-specific peculiarities in
different parts of the DW APB SSI core driver (which is required to
implement both SPI-transfers and the SPI memory operations). This will
also make the code less confusing like defining a callback in the core
driver, setting it up in the glue layer, then calling it from the core
driver again. Seeing the small capabilities implementation embedded
in-situ is more readable than tracking the callbacks assignments. This
will concern the CS-override, Keembay master setup, DW SSI-specific CR0
registers layout capabilities.

Seventhly since there are going to be two types of the transfers
implemented in the DW APB SSI core driver, we need a common method to set
the controller configuration like, Tx/Rx-mode, bus speed, data frame size
and number of data frames to read in case of the memory operations. So we
just detached the corresponding code from the SPI-transfer-one method and
made it to be a part of the new dw_spi_update_config() function, which is
former update_cr0(). Note that the new method will be also useful for the
glue drivers, which due to the hardware design need to create their own
memory operations (for instance, for the dirmap-operations provided in the
Baikal-T System Boot SPI controller driver).

Eighthly it is the data IO procedure and IRQ-based SPI-transfer
implementation refactoring. The former one will look much simpler if the
buffers initial pointers and the buffers length data utilized instead of
the Tx/Rx buffers start and end pointers. The later one currently lacks of
valid execution at the final stage of the SPI-transfer. So if there is no
data left to send, but there is still data which needs to be received, the
Tx FIFO Empty IRQ will constantly happen until all of the requested
inbound data is received. So we suggest to fix that by taking the Rx FIFO
Empty IRQ into account.

Ninthly it's potentially errors prone to enable the DW APB SSI interrupts
before enabling the chip. It specifically concerns a case if for some
reason the DW APB SSI IRQs handler is executed before the controller is
enabled. That will cause a part of the outbound data loss. So we suggest
to reverse the order.

Tenthly in order to be able to pre-initialize the Tx FIFO with data and
only the start the SPI memory operations we need to have any CS
de-activated. We'll fulfil that requirement by explicitly clearing the CS
on the SPI transfer completion and at the explicit controller reset.

Then seeing all the currently available and potentially being created
types of the SPI transfers need to perform the DW APB SSI controller
status register check and the errors handler procedure, we've created a
common method for all of them.

Eleventhly if before we've mostly had a series of fixups, cleanups and
refactorings, here we've finally come to the new functionality
implementation. It concerns the poll-based transfer (as Baikal-T1 System
Boot SPI controller lacks a dedicated IRQ lane connected) and the SPI
memory operations implementation. If the former feature is pretty much
straightforward (see the patch log for details), the later one is a bit
tricky. It's based on the EEPROM-read (write-then-read) and the Tx-only
modes of the DW APB SSI controller, which as performing the automatic data
read and write let's us to implement the faster IO procedure than using
the Tx-Rx-mode-based approach. Having the memory-operations implemented
that way is the best thing we can currently do to provide the errors-less
SPI transfers to SPI devices with native CS attached.

Note the approach utilized here to develop the SPI memory operations can
be also used to create the "automatic CS toggle problem"-free(ish) SPI
transfers (combine SPI-message transfers into two buffers, disable
interrupts, push-pull the combined data). But we don't provide a solution
in the framework of this patchset. It is a matter of a dedicated one,
which we currently don't intend to spend our time on.

Finally at the closure of the this patchset you'll find patches, which
provide the Baikal-T1-specific DW APB SSI controllers support. The SoC has
got three SPI controllers. Two of them are pretty much normal DW APB SSI
interfaces: with IRQ, DMA, FIFOs of 64 words depth, 4x CSs. But the third
one as being a part of the Baikal-T1 System Boot Controller has got a very
limited resources: no IRQ, no DMA, only a single native chip-select and
Tx/Rx FIFOs with just 8 words depth available. In order to provide a
transparent initial boot code execution the System Boot SPI Controller is
also utilized by an vendor-specific IP-block, which exposes an SPI flash
memory direct mapping interface. Please see the corresponding patch for
details.

Link: https://lore.kernel.org/linux-spi/20200508093621.31619-1-Sergey.Semin@baikalelectronics.ru/

[1] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt,
    Section "KERNEL I/O BARRIER EFFECTS"

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Lars Povlsen <lars.povlsen@microchip.com>
Cc: wuxu.wu <wuxu.wu@huawei.com>
Cc: Feng Tang <feng.tang@intel.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: linux-spi@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Serge Semin (30):
  spi: dw: Discard IRQ threshold macro
  spi: dw: Use ternary op to init set_cs callback
  spi: dw: Initialize n_bytes before the memory barrier
  Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent
    concurrent calls
  spi: dw: Clear IRQ status on DW SPI controller reset
  spi: dw: Disable all IRQs when controller is unused
  spi: dw: Use relaxed IO-methods to access FIFOs
  spi: dw: Discard DW SSI chip type storages
  spi: dw: Convert CS-override to DW SPI capabilities
  spi: dw: Add KeemBay Master capability
  spi: dw: Add DWC SSI capability
  spi: dw: Detach SPI device specific CR0 config method
  spi: dw: Update SPI bus speed in a config function
  spi: dw: Simplify the SPI bus speed config procedure
  spi: dw: Update Rx sample delay in the config function
  spi: dw: Add DW SPI controller config structure
  spi: dw: Refactor data IO procedure
  spi: dw: Refactor IRQ-based SPI transfer procedure
  spi: dw: Perform IRQ setup in a dedicated function
  spi: dw: Unmask IRQs after enabling the chip
  spi: dw: Discard chip enabling on DMA setup error
  spi: dw: De-assert chip-select on reset
  spi: dw: Explicitly de-assert CS on SPI transfer completion
  spi: dw: Move num-of retries parameter to the header file
  spi: dw: Add generic DW SSI status-check method
  spi: dw: Add memory operations support
  spi: dw: Introduce max mem-ops SPI bus frequency setting
  spi: dw: Add poll-based SPI transfers support
  dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers
  spi: dw: Add Baikal-T1 SPI Controller glue driver

 .../bindings/spi/snps,dw-apb-ssi.yaml         |  33 +-
 drivers/spi/Kconfig                           |  29 +
 drivers/spi/Makefile                          |   1 +
 drivers/spi/spi-dw-bt1.c                      | 339 +++++++++
 drivers/spi/spi-dw-core.c                     | 642 ++++++++++++++----
 drivers/spi/spi-dw-dma.c                      |  16 +-
 drivers/spi/spi-dw-mmio.c                     |  36 +-
 drivers/spi/spi-dw.h                          |  85 ++-
 8 files changed, 960 insertions(+), 221 deletions(-)
 create mode 100644 drivers/spi/spi-dw-bt1.c

-- 
2.27.0


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

* [PATCH 01/30] spi: dw: Discard IRQ threshold macro
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback Serge Semin
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The macro has been unused since a half of FIFO length was defined to be a
marker of the IRQ. Let's remove it definition.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw.h | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 90dfd21622d6..51bab30b9f85 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -92,9 +92,6 @@
 #define SPI_DMA_RDMAE			(1 << 0)
 #define SPI_DMA_TDMAE			(1 << 1)
 
-/* TX RX interrupt level threshold, max can be 256 */
-#define SPI_INT_THRESHOLD		32
-
 enum dw_ssi_type {
 	SSI_MOTO_SPI = 0,
 	SSI_TI_SSP,
-- 
2.27.0


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

* [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
  2020-09-20 11:28 ` [PATCH 01/30] spi: dw: Discard IRQ threshold macro Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-29 13:11   ` Mark Brown
  2020-09-20 11:28 ` [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier Serge Semin
                   ` (29 subsequent siblings)
  31 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Simplify the dw_spi_add_host() method a bit by replacing the set_cs
callback overwrite procedure with direct setting the callback if a custom
version of one is specified.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 55afdcee7d2b..8b3ce5a0378a 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -482,7 +482,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	master->num_chipselect = dws->num_cs;
 	master->setup = dw_spi_setup;
 	master->cleanup = dw_spi_cleanup;
-	master->set_cs = dw_spi_set_cs;
+	master->set_cs = dws->set_cs ?: dw_spi_set_cs;
 	master->transfer_one = dw_spi_transfer_one;
 	master->handle_err = dw_spi_handle_err;
 	master->max_speed_hz = dws->max_freq;
@@ -491,9 +491,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	master->flags = SPI_MASTER_GPIO_SS;
 	master->auto_runtime_pm = true;
 
-	if (dws->set_cs)
-		master->set_cs = dws->set_cs;
-
 	/* Get default rx sample delay */
 	device_property_read_u32(dev, "rx-sample-delay-ns",
 				 &dws->def_rx_sample_dly_ns);
-- 
2.27.0


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

* [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
  2020-09-20 11:28 ` [PATCH 01/30] spi: dw: Discard IRQ threshold macro Serge Semin
  2020-09-20 11:28 ` [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-29 13:12   ` Mark Brown
  2020-09-20 11:28 ` [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls Serge Semin
                   ` (28 subsequent siblings)
  31 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Since n_bytes field of the DW SPI private data is also utilized by the
IRQ handler, we need to make sure it' initialization is done before the
memory barrier.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 8b3ce5a0378a..1af74362461d 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -299,6 +299,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	dws->dma_mapped = 0;
 	spin_lock_irqsave(&dws->buf_lock, flags);
+	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
 	dws->tx = (void *)transfer->tx_buf;
 	dws->tx_end = dws->tx + transfer->len;
 	dws->rx = transfer->rx_buf;
@@ -323,7 +324,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	}
 
 	transfer->effective_speed_hz = dws->max_freq / chip->clk_div;
-	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
 
 	cr0 = dws->update_cr0(master, spi, transfer);
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
-- 
2.27.0


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

* [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (2 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-29 13:28   ` Mark Brown
  2020-09-20 11:28 ` [PATCH 05/30] spi: dw: Clear IRQ status on DW SPI controller reset Serge Semin
                   ` (27 subsequent siblings)
  31 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

There is no point in having the commit 19b61392c5a8 ("spi: spi-dw: Add
lock protect dw_spi rx/tx to prevent concurrent calls") applied. The
commit author made an assumption that the problem with the rx data
mismatch was due to the lack of the data protection. While most likely it
was caused by the lack of the memory barrier. So having the
commit bfda044533b2 ("spi: dw: use "smp_mb()" to avoid sending spi data
error") applied would be enough to fix the problem.

Indeed the spin unlock operation makes sure each memory operation issued
before the release will be completed before it's completed. In other words
it works as an implicit one way memory barrier. So having both smp_mb()
and the spin_unlock_irqrestore() here is just redundant. One of them would
be enough. It's better to leave the smp_mb() since the Tx/Rx buffers
consistency is provided by the data transfer algorithm implementation:
first we initialize the buffers pointers, then make sure the assignments
are visible by the other CPUs by calling the smp_mb(), only after that
enable the interrupt, which handler uses the buffers.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Folks. I have also a doubt whether the SMP memory barrier is required there
because the normal IO-methods like readl/writel imply a full memory barrier. So
any memory operation performed before them are supposed to be seen by devices
and another CPUs [1]. So most likely there could have been a problem with those
IOs implementation on the subject platform or a spurious interrupt could
have been raised during the data initialization. What do you think?
Am I missing something?

[1] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt,
    Section "KERNEL I/O BARRIER EFFECTS"
---
 drivers/spi/spi-dw-core.c | 14 ++------------
 drivers/spi/spi-dw.h      |  1 -
 2 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 1af74362461d..18411f5b9954 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -142,11 +142,9 @@ static inline u32 rx_max(struct dw_spi *dws)
 
 static void dw_writer(struct dw_spi *dws)
 {
-	u32 max;
+	u32 max = tx_max(dws);
 	u16 txw = 0;
 
-	spin_lock(&dws->buf_lock);
-	max = tx_max(dws);
 	while (max--) {
 		/* Set the tx word if the transfer's original "tx" is not null */
 		if (dws->tx_end - dws->len) {
@@ -158,16 +156,13 @@ static void dw_writer(struct dw_spi *dws)
 		dw_write_io_reg(dws, DW_SPI_DR, txw);
 		dws->tx += dws->n_bytes;
 	}
-	spin_unlock(&dws->buf_lock);
 }
 
 static void dw_reader(struct dw_spi *dws)
 {
-	u32 max;
+	u32 max = rx_max(dws);
 	u16 rxw;
 
-	spin_lock(&dws->buf_lock);
-	max = rx_max(dws);
 	while (max--) {
 		rxw = dw_read_io_reg(dws, DW_SPI_DR);
 		/* Care rx only if the transfer's original "rx" is not null */
@@ -179,7 +174,6 @@ static void dw_reader(struct dw_spi *dws)
 		}
 		dws->rx += dws->n_bytes;
 	}
-	spin_unlock(&dws->buf_lock);
 }
 
 static void int_error_stop(struct dw_spi *dws, const char *msg)
@@ -291,21 +285,18 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 {
 	struct dw_spi *dws = spi_controller_get_devdata(master);
 	struct chip_data *chip = spi_get_ctldata(spi);
-	unsigned long flags;
 	u8 imask = 0;
 	u16 txlevel = 0;
 	u32 cr0;
 	int ret;
 
 	dws->dma_mapped = 0;
-	spin_lock_irqsave(&dws->buf_lock, flags);
 	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
 	dws->tx = (void *)transfer->tx_buf;
 	dws->tx_end = dws->tx + transfer->len;
 	dws->rx = transfer->rx_buf;
 	dws->rx_end = dws->rx + transfer->len;
 	dws->len = transfer->len;
-	spin_unlock_irqrestore(&dws->buf_lock, flags);
 
 	/* Ensure dw->rx and dw->rx_end are visible */
 	smp_mb();
@@ -464,7 +455,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	dws->master = master;
 	dws->type = SSI_MOTO_SPI;
 	dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
-	spin_lock_init(&dws->buf_lock);
 
 	spi_controller_set_devdata(master, dws);
 
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 51bab30b9f85..1ab704d1ebd8 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -131,7 +131,6 @@ struct dw_spi {
 	size_t			len;
 	void			*tx;
 	void			*tx_end;
-	spinlock_t		buf_lock;
 	void			*rx;
 	void			*rx_end;
 	int			dma_mapped;
-- 
2.27.0


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

* [PATCH 05/30] spi: dw: Clear IRQ status on DW SPI controller reset
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (3 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 06/30] spi: dw: Disable all IRQs when controller is unused Serge Semin
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

It turns out the IRQ status isn't cleared after switching the controller
off and getting it back on, which may cause raising false error interrupts
if controller has been unsuccessfully used by, for instance, a bootloader
before the driver is loaded. Let's explicitly clear the interrupts status
in the dedicated controller reset method.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 1ab704d1ebd8..ff77f39047ce 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -229,14 +229,15 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
 }
 
 /*
- * This does disable the SPI controller, interrupts, and re-enable the
- * controller back. Transmit and receive FIFO buffers are cleared when the
- * device is disabled.
+ * This disables the SPI controller, interrupts, clears the interrupts status,
+ * and re-enable the controller back. Transmit and receive FIFO buffers are
+ * cleared when the device is disabled.
  */
 static inline void spi_reset_chip(struct dw_spi *dws)
 {
 	spi_enable_chip(dws, 0);
 	spi_mask_intr(dws, 0xff);
+	dw_readl(dws, DW_SPI_ICR);
 	spi_enable_chip(dws, 1);
 }
 
-- 
2.27.0


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

* [PATCH 06/30] spi: dw: Disable all IRQs when controller is unused
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (4 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 05/30] spi: dw: Clear IRQ status on DW SPI controller reset Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 07/30] spi: dw: Use relaxed IO-methods to access FIFOs Serge Semin
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

It's a good practice to disable all IRQs if a device is fully unused. In
our case it is supposed to be done before requesting the IRQ and after the
last byte of an SPI transfer is received. In the former case it's required
to prevent the IRQ handler invocation before the driver data is fully
initialized (which may happen if the IRQs status has been left uncleared
before the device is probed). So we just moved the spi_hw_init() method
invocation to the earlier stage before requesting the IRQ. In the later
case there is just no point in having any of the IRQs enabled between SPI
transfers and when there is no SPI message currently being processed.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 18411f5b9954..be94ed5bb896 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -198,7 +198,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 
 	dw_reader(dws);
 	if (dws->rx_end == dws->rx) {
-		spi_mask_intr(dws, SPI_INT_TXEI);
+		spi_mask_intr(dws, 0xff);
 		spi_finalize_current_transfer(dws->master);
 		return IRQ_HANDLED;
 	}
@@ -222,7 +222,7 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	if (!master->cur_msg) {
-		spi_mask_intr(dws, SPI_INT_TXEI);
+		spi_mask_intr(dws, 0xff);
 		return IRQ_HANDLED;
 	}
 
@@ -458,6 +458,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 
 	spi_controller_set_devdata(master, dws);
 
+	/* Basic HW init */
+	spi_hw_init(dev, dws);
+
 	ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
 			  master);
 	if (ret < 0) {
@@ -485,9 +488,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	device_property_read_u32(dev, "rx-sample-delay-ns",
 				 &dws->def_rx_sample_dly_ns);
 
-	/* Basic HW init */
-	spi_hw_init(dev, dws);
-
 	if (dws->dma_ops && dws->dma_ops->dma_init) {
 		ret = dws->dma_ops->dma_init(dev, dws);
 		if (ret) {
-- 
2.27.0


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

* [PATCH 07/30] spi: dw: Use relaxed IO-methods to access FIFOs
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (5 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 06/30] spi: dw: Disable all IRQs when controller is unused Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 08/30] spi: dw: Discard DW SSI chip type storages Serge Semin
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

In accordance with [1] the relaxed methods are guaranteed to be ordered
with respect to other accesses from the same CPU thread to the same
peripheral.  This is what we need during the data read/write from/to the
controller FIFOs being executed within a single IRQ handler or a kernel
task.

Such optimization shall significantly speed the data reader and writer up.
For instance, the relaxed IO-accessors utilization on Baikal-T1 lets the
driver to support the SPI memory operations with bus frequency three-fold
faster than if normal IO-accessors would be used.

[1] "LINUX KERNEL MEMORY BARRIERS", Documentation/memory-barriers.txt,
    Section "KERNEL I/O BARRIER EFFECTS"

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw.h | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index ff77f39047ce..063fa1b1352d 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -161,29 +161,19 @@ static inline u32 dw_readl(struct dw_spi *dws, u32 offset)
 	return __raw_readl(dws->regs + offset);
 }
 
-static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
-{
-	return __raw_readw(dws->regs + offset);
-}
-
 static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
 {
 	__raw_writel(val, dws->regs + offset);
 }
 
-static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
-{
-	__raw_writew(val, dws->regs + offset);
-}
-
 static inline u32 dw_read_io_reg(struct dw_spi *dws, u32 offset)
 {
 	switch (dws->reg_io_width) {
 	case 2:
-		return dw_readw(dws, offset);
+		return readw_relaxed(dws->regs + offset);
 	case 4:
 	default:
-		return dw_readl(dws, offset);
+		return readl_relaxed(dws->regs + offset);
 	}
 }
 
@@ -191,11 +181,11 @@ static inline void dw_write_io_reg(struct dw_spi *dws, u32 offset, u32 val)
 {
 	switch (dws->reg_io_width) {
 	case 2:
-		dw_writew(dws, offset, val);
+		writew_relaxed(val, dws->regs + offset);
 		break;
 	case 4:
 	default:
-		dw_writel(dws, offset, val);
+		writel_relaxed(val, dws->regs + offset);
 		break;
 	}
 }
-- 
2.27.0


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

* [PATCH 08/30] spi: dw: Discard DW SSI chip type storages
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (6 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 07/30] spi: dw: Use relaxed IO-methods to access FIFOs Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 09/30] spi: dw: Convert CS-override to DW SPI capabilities Serge Semin
                   ` (23 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Keeping SPI peripheral devices type is pointless since first it hasn't
been functionally utilized by any of the client drivers/code and second it
won't work for Microwire type at the very least. Moreover there is no
point in setting up the type by means of the chip-data in the modern
kernel. The peripheral devices with specific interface type need to be
detected in order to activate the corresponding frame format. It most
likely will require some peripheral device specific DT property or
whatever to find out the interface protocol. So let's remove the serial
interface type fields from the DW APB SSI controller and the SPI
peripheral device private data.

Note we'll preserve the explicit SSI_MOTO_SPI interface type setting up to
signify the only currently supported interface protocol.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 6 ++----
 drivers/spi/spi-dw.h      | 1 -
 2 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index be94ed5bb896..dd9574f9fafc 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -23,7 +23,6 @@
 /* Slave spi_dev related */
 struct chip_data {
 	u8 tmode;		/* TR/TO/RO/EEPROM */
-	u8 type;		/* SPI/SSP/MicroWire */
 
 	u16 clk_div;		/* baud rate divider */
 	u32 speed_hz;		/* baud rate */
@@ -238,7 +237,7 @@ u32 dw_spi_update_cr0(struct spi_controller *master, struct spi_device *spi,
 
 	/* Default SPI mode is SCPOL = 0, SCPH = 0 */
 	cr0 = (transfer->bits_per_word - 1)
-		| (chip->type << SPI_FRF_OFFSET)
+		| (SSI_MOTO_SPI << SPI_FRF_OFFSET)
 		| ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) |
 		   (((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET) |
 		   (((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET))
@@ -260,7 +259,7 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
 	cr0 = (transfer->bits_per_word - 1);
 
 	/* CTRLR0[ 7: 6] Frame Format */
-	cr0 |= chip->type << DWC_SSI_CTRLR0_FRF_OFFSET;
+	cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
 
 	/*
 	 * SPI mode (SCPOL|SCPH)
@@ -453,7 +452,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 		return -ENOMEM;
 
 	dws->master = master;
-	dws->type = SSI_MOTO_SPI;
 	dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
 
 	spi_controller_set_devdata(master, dws);
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 063fa1b1352d..4420b4d29bac 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -111,7 +111,6 @@ struct dw_spi_dma_ops {
 
 struct dw_spi {
 	struct spi_controller	*master;
-	enum dw_ssi_type	type;
 
 	void __iomem		*regs;
 	unsigned long		paddr;
-- 
2.27.0


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

* [PATCH 09/30] spi: dw: Convert CS-override to DW SPI capabilities
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (7 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 08/30] spi: dw: Discard DW SSI chip type storages Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 10/30] spi: dw: Add KeemBay Master capability Serge Semin
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

There are several vendor-specific versions of the DW SPI controllers,
each of which may have some peculiarities with respect to the original
IP-core. Seeing it has already caused adding flags and a callback into the
DW SPI private data, let's introduce a generic capabilities interface to
tune the generic DW SPI controller driver up in accordance with the
particular controller specifics. It's done by converting a simple
Alpine-specific CS-override capability into the DW SPI controller
capability activated by setting the DW_SPI_CAP_CS_OVERRIDE flag.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 4 ++--
 drivers/spi/spi-dw-mmio.c | 2 +-
 drivers/spi/spi-dw.h      | 7 ++++++-
 3 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index dd9574f9fafc..78e5af8ed173 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -104,7 +104,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
 	 */
 	if (cs_high == enable)
 		dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
-	else if (dws->cs_override)
+	else if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
 		dw_writel(dws, DW_SPI_SER, 0);
 }
 EXPORT_SYMBOL_GPL(dw_spi_set_cs);
@@ -435,7 +435,7 @@ static void spi_hw_init(struct device *dev, struct dw_spi *dws)
 	}
 
 	/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
-	if (dws->cs_override)
+	if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
 		dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
 }
 
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 18772c0c9220..7111cb7ca23b 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -204,7 +204,7 @@ static int dw_spi_mscc_sparx5_init(struct platform_device *pdev,
 static int dw_spi_alpine_init(struct platform_device *pdev,
 			      struct dw_spi_mmio *dwsmmio)
 {
-	dwsmmio->dws.cs_override = 1;
+	dwsmmio->dws.caps = DW_SPI_CAP_CS_OVERRIDE;
 
 	/* Register hook to configure CTRLR0 */
 	dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 4420b4d29bac..4c748b2853a8 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -2,6 +2,7 @@
 #ifndef DW_SPI_HEADER_H
 #define DW_SPI_HEADER_H
 
+#include <linux/bits.h>
 #include <linux/completion.h>
 #include <linux/debugfs.h>
 #include <linux/irqreturn.h>
@@ -98,6 +99,9 @@ enum dw_ssi_type {
 	SSI_NS_MICROWIRE,
 };
 
+/* DW SPI capabilities */
+#define DW_SPI_CAP_CS_OVERRIDE		BIT(0)
+
 struct dw_spi;
 struct dw_spi_dma_ops {
 	int (*dma_init)(struct device *dev, struct dw_spi *dws);
@@ -118,7 +122,8 @@ struct dw_spi {
 	u32			fifo_len;	/* depth of the FIFO buffer */
 	u32			max_freq;	/* max bus freq supported */
 
-	int			cs_override;
+	u32			caps;		/* DW SPI capabilities */
+
 	u32			reg_io_width;	/* DR I/O width in bytes */
 	u16			bus_num;
 	u16			num_cs;		/* supported slave numbers */
-- 
2.27.0


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

* [PATCH 10/30] spi: dw: Add KeemBay Master capability
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (8 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 09/30] spi: dw: Convert CS-override to DW SPI capabilities Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 11/30] spi: dw: Add DWC SSI capability Serge Semin
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

In a further commit we'll have to get rid of the update_cr0() callback and
define a DW SSI capability instead. Since Keem Bay master/slave
functionality is controller by the CTRL0 register bitfield, we need to
first move the master mode selection into the internal corresponding
update_cr0 method, which would be activated by means of the dedicated
DW_SPI_CAP_KEEMBAY_MST capability setup.

Note this will be also useful if the driver will be ever altered to
support the DW SPI slave interface.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c |  4 ++++
 drivers/spi/spi-dw-mmio.c | 20 +++-----------------
 drivers/spi/spi-dw.h      |  8 ++++++++
 3 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 78e5af8ed173..8f9737640ec1 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -252,6 +252,7 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
 			     struct spi_device *spi,
 			     struct spi_transfer *transfer)
 {
+	struct dw_spi *dws = spi_controller_get_devdata(master);
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u32 cr0;
 
@@ -275,6 +276,9 @@ u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
 	/* CTRLR0[13] Shift Register Loop */
 	cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
 
+	if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
+		cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
+
 	return cr0;
 }
 EXPORT_SYMBOL_GPL(dw_spi_update_cr0_v1_01a);
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index 7111cb7ca23b..c0d351fde782 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -48,13 +48,6 @@ struct dw_spi_mmio {
 #define SPARX5_FORCE_ENA			0xa4
 #define SPARX5_FORCE_VAL			0xa8
 
-/*
- * For Keem Bay, CTRLR0[31] is used to select controller mode.
- * 0: SSI is slave
- * 1: SSI is master
- */
-#define KEEMBAY_CTRLR0_SSIC_IS_MST		BIT(31)
-
 struct dw_spi_mscc {
 	struct regmap       *syscon;
 	void __iomem        *spi_mst; /* Not sparx5 */
@@ -234,20 +227,13 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
 	return 0;
 }
 
-static u32 dw_spi_update_cr0_keembay(struct spi_controller *master,
-				     struct spi_device *spi,
-				     struct spi_transfer *transfer)
-{
-	u32 cr0 = dw_spi_update_cr0_v1_01a(master, spi, transfer);
-
-	return cr0 | KEEMBAY_CTRLR0_SSIC_IS_MST;
-}
-
 static int dw_spi_keembay_init(struct platform_device *pdev,
 			       struct dw_spi_mmio *dwsmmio)
 {
+	dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
+
 	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0_keembay;
+	dwsmmio->dws.update_cr0 = dw_spi_update_cr0_v1_01a;
 
 	return 0;
 }
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 4c748b2853a8..da9b543322c9 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -71,6 +71,13 @@
 #define DWC_SSI_CTRLR0_FRF_OFFSET	6
 #define DWC_SSI_CTRLR0_DFS_OFFSET	0
 
+/*
+ * For Keem Bay, CTRLR0[31] is used to select controller mode.
+ * 0: SSI is slave
+ * 1: SSI is master
+ */
+#define DWC_SSI_CTRLR0_KEEMBAY_MST	BIT(31)
+
 /* Bit fields in SR, 7 bits */
 #define SR_MASK				0x7f		/* cover 7 bits */
 #define SR_BUSY				(1 << 0)
@@ -101,6 +108,7 @@ enum dw_ssi_type {
 
 /* DW SPI capabilities */
 #define DW_SPI_CAP_CS_OVERRIDE		BIT(0)
+#define DW_SPI_CAP_KEEMBAY_MST		BIT(1)
 
 struct dw_spi;
 struct dw_spi_dma_ops {
-- 
2.27.0


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

* [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (9 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 10/30] spi: dw: Add KeemBay Master capability Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-29 13:52   ` Mark Brown
  2020-09-20 11:28 ` [PATCH 12/30] spi: dw: Detach SPI device specific CR0 config method Serge Semin
                   ` (20 subsequent siblings)
  31 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Currently DWC SSI core is supported by means of setting up the
core-specific update_cr0() callback. It isn't suitable for multiple
reasons. First of all having exported several methods doing the same thing
but for different chips makes the code harder to maintain. Secondly the
spi-dw-core driver exports the methods, then the spi-dw-mmio driver sets
the private data callback with one of them so to be called by the core
driver again. That makes the code logic too complicated. Thirdly using
callbacks for just updating the CR0 register is problematic, since in case
if the register needed to be updated from different parts of the code,
we'd have to create another callback (for instance the SPI device-specific
parameters don't need to be calculated each time the SPI transfer is
submitted, so it's better to pre-calculate the CR0 data at the SPI-device
setup stage).

So keeping all the above in mind let's discard the update_cr0() callbacks,
define a generic and static dw_spi_update_cr0() method and create the
DW_SPI_CAP_DWC_SSI capability, which when enabled would activate the
alternative CR0 register layout.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 69 ++++++++++++---------------------------
 drivers/spi/spi-dw-mmio.c | 20 ++----------
 drivers/spi/spi-dw.h      |  9 +----
 3 files changed, 23 insertions(+), 75 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 8f9737640ec1..c21641a485ce 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -228,60 +228,33 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 	return dws->transfer_handler(dws);
 }
 
-/* Configure CTRLR0 for DW_apb_ssi */
-u32 dw_spi_update_cr0(struct spi_controller *master, struct spi_device *spi,
-		      struct spi_transfer *transfer)
+static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
+			      struct spi_transfer *transfer)
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u32 cr0;
 
-	/* Default SPI mode is SCPOL = 0, SCPH = 0 */
-	cr0 = (transfer->bits_per_word - 1)
-		| (SSI_MOTO_SPI << SPI_FRF_OFFSET)
-		| ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) |
-		   (((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET) |
-		   (((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET))
-		| (chip->tmode << SPI_TMOD_OFFSET);
-
-	return cr0;
-}
-EXPORT_SYMBOL_GPL(dw_spi_update_cr0);
-
-/* Configure CTRLR0 for DWC_ssi */
-u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
-			     struct spi_device *spi,
-			     struct spi_transfer *transfer)
-{
-	struct dw_spi *dws = spi_controller_get_devdata(master);
-	struct chip_data *chip = spi_get_ctldata(spi);
-	u32 cr0;
-
-	/* CTRLR0[ 4: 0] Data Frame Size */
 	cr0 = (transfer->bits_per_word - 1);
 
-	/* CTRLR0[ 7: 6] Frame Format */
-	cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
-
-	/*
-	 * SPI mode (SCPOL|SCPH)
-	 * CTRLR0[ 8] Serial Clock Phase
-	 * CTRLR0[ 9] Serial Clock Polarity
-	 */
-	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
-	cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
-
-	/* CTRLR0[11:10] Transfer Mode */
-	cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
-
-	/* CTRLR0[13] Shift Register Loop */
-	cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
-
-	if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
-		cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
+	if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
+		cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET;
+		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET;
+		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET;
+		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET;
+		cr0 |= chip->tmode << SPI_TMOD_OFFSET;
+	} else {
+		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
+		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
+		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
+		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
+		cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
+
+		if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
+			cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
+	}
 
-	return cr0;
+	dw_writel(dws, DW_SPI_CTRLR0, cr0);
 }
-EXPORT_SYMBOL_GPL(dw_spi_update_cr0_v1_01a);
 
 static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
@@ -290,7 +263,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u8 imask = 0;
 	u16 txlevel = 0;
-	u32 cr0;
 	int ret;
 
 	dws->dma_mapped = 0;
@@ -319,8 +291,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	transfer->effective_speed_hz = dws->max_freq / chip->clk_div;
 
-	cr0 = dws->update_cr0(master, spi, transfer);
-	dw_writel(dws, DW_SPI_CTRLR0, cr0);
+	dw_spi_update_cr0(dws, spi, transfer);
 
 	/* Check if current transfer is a DMA transaction */
 	if (master->can_dma && master->can_dma(master, spi, transfer))
diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c
index c0d351fde782..d0cc5bf4fa4e 100644
--- a/drivers/spi/spi-dw-mmio.c
+++ b/drivers/spi/spi-dw-mmio.c
@@ -110,9 +110,6 @@ static int dw_spi_mscc_init(struct platform_device *pdev,
 	dwsmmio->dws.set_cs = dw_spi_mscc_set_cs;
 	dwsmmio->priv = dwsmscc;
 
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
-
 	return 0;
 }
 
@@ -188,9 +185,6 @@ static int dw_spi_mscc_sparx5_init(struct platform_device *pdev,
 	dwsmmio->dws.set_cs = dw_spi_sparx5_set_cs;
 	dwsmmio->priv = dwsmscc;
 
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
-
 	return 0;
 }
 
@@ -199,18 +193,12 @@ static int dw_spi_alpine_init(struct platform_device *pdev,
 {
 	dwsmmio->dws.caps = DW_SPI_CAP_CS_OVERRIDE;
 
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
-
 	return 0;
 }
 
 static int dw_spi_dw_apb_init(struct platform_device *pdev,
 			      struct dw_spi_mmio *dwsmmio)
 {
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0;
-
 	dw_spi_dma_setup_generic(&dwsmmio->dws);
 
 	return 0;
@@ -219,8 +207,7 @@ static int dw_spi_dw_apb_init(struct platform_device *pdev,
 static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
 			       struct dw_spi_mmio *dwsmmio)
 {
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0_v1_01a;
+	dwsmmio->dws.caps = DW_SPI_CAP_DWC_SSI;
 
 	dw_spi_dma_setup_generic(&dwsmmio->dws);
 
@@ -230,10 +217,7 @@ static int dw_spi_dwc_ssi_init(struct platform_device *pdev,
 static int dw_spi_keembay_init(struct platform_device *pdev,
 			       struct dw_spi_mmio *dwsmmio)
 {
-	dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST;
-
-	/* Register hook to configure CTRLR0 */
-	dwsmmio->dws.update_cr0 = dw_spi_update_cr0_v1_01a;
+	dwsmmio->dws.caps = DW_SPI_CAP_KEEMBAY_MST | DW_SPI_CAP_DWC_SSI;
 
 	return 0;
 }
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index da9b543322c9..c02351cf2f99 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -109,6 +109,7 @@ enum dw_ssi_type {
 /* DW SPI capabilities */
 #define DW_SPI_CAP_CS_OVERRIDE		BIT(0)
 #define DW_SPI_CAP_KEEMBAY_MST		BIT(1)
+#define DW_SPI_CAP_DWC_SSI		BIT(2)
 
 struct dw_spi;
 struct dw_spi_dma_ops {
@@ -136,8 +137,6 @@ struct dw_spi {
 	u16			bus_num;
 	u16			num_cs;		/* supported slave numbers */
 	void (*set_cs)(struct spi_device *spi, bool enable);
-	u32 (*update_cr0)(struct spi_controller *master, struct spi_device *spi,
-			  struct spi_transfer *transfer);
 
 	/* Current message transfer state info */
 	size_t			len;
@@ -254,12 +253,6 @@ extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
 extern void dw_spi_remove_host(struct dw_spi *dws);
 extern int dw_spi_suspend_host(struct dw_spi *dws);
 extern int dw_spi_resume_host(struct dw_spi *dws);
-extern u32 dw_spi_update_cr0(struct spi_controller *master,
-			     struct spi_device *spi,
-			     struct spi_transfer *transfer);
-extern u32 dw_spi_update_cr0_v1_01a(struct spi_controller *master,
-				    struct spi_device *spi,
-				    struct spi_transfer *transfer);
 
 #ifdef CONFIG_SPI_DW_DMA
 
-- 
2.27.0


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

* [PATCH 12/30] spi: dw: Detach SPI device specific CR0 config method
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (10 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 11/30] spi: dw: Add DWC SSI capability Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 13/30] spi: dw: Update SPI bus speed in a config function Serge Semin
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Indeed there is no point in detecting the SPI peripheral device parameters
and initializing the CR0 register fields each time an SPI transfer is
executed. Instead let's define a dedicated CR0 chip-data member, which
will be initialized in accordance with the SPI device settings at the
moment of setting it up.

By doing so we'll finally make the SPI device chip_data serving as it's
supposed to - to preserve the SPI device specific DW SPI configuration.
See spi-fsl-dspi.c, spi-pl022.c, spi-pxa2xx.c drivers for example of the
way the chip data is utilized.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index c21641a485ce..a9644351d75f 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -27,6 +27,7 @@ struct chip_data {
 	u16 clk_div;		/* baud rate divider */
 	u32 speed_hz;		/* baud rate */
 
+	u32 cr0;
 	u32 rx_sample_dly;	/* RX sample delay */
 };
 
@@ -228,31 +229,41 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
 	return dws->transfer_handler(dws);
 }
 
-static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
-			      struct spi_transfer *transfer)
+static u32 dw_spi_get_cr0(struct dw_spi *dws, struct spi_device *spi)
 {
-	struct chip_data *chip = spi_get_ctldata(spi);
-	u32 cr0;
-
-	cr0 = (transfer->bits_per_word - 1);
+	u32 cr0 = 0;
 
 	if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
 		cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET;
 		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET;
 		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET;
 		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET;
-		cr0 |= chip->tmode << SPI_TMOD_OFFSET;
 	} else {
 		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
 		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
 		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
 		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
-		cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
 
 		if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
 			cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
 	}
 
+	return cr0;
+}
+
+static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
+			      struct spi_transfer *transfer)
+{
+	struct chip_data *chip = spi_get_ctldata(spi);
+	u32 cr0 = chip->cr0;
+
+	cr0 |= (transfer->bits_per_word - 1);
+
+	if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
+		cr0 |= chip->tmode << SPI_TMOD_OFFSET;
+	else
+		cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
+
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
 }
 
@@ -350,6 +361,7 @@ static void dw_spi_handle_err(struct spi_controller *master,
 /* This may be called twice for each spi dev */
 static int dw_spi_setup(struct spi_device *spi)
 {
+	struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
 	struct chip_data *chip;
 
 	/* Only alloc on first setup */
@@ -373,6 +385,13 @@ static int dw_spi_setup(struct spi_device *spi)
 							dws->max_freq);
 	}
 
+	/*
+	 * Update CR0 data each time the setup callback is invoked since
+	 * the device parameters could have been changed, for instance, by
+	 * the MMC SPI driver or something else.
+	 */
+	chip->cr0 = dw_spi_get_cr0(dws, spi);
+
 	chip->tmode = SPI_TMOD_TR;
 
 	return 0;
-- 
2.27.0


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

* [PATCH 13/30] spi: dw: Update SPI bus speed in a config function
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (11 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 12/30] spi: dw: Detach SPI device specific CR0 config method Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 14/30] spi: dw: Simplify the SPI bus speed config procedure Serge Semin
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The SPI bus speed update functionality will be useful in another parts of
the driver too (like to implement the SPI memory operations and from the
DW SPI glue layers). Let's move it to the update_cr0() method then and
since the later is now updating not only the CTRLR0 register alter its
prototype to have a generic function name not related to CR0.

Leave the too long line with the chip->clk_div setting as is for now,
since it's going to be changed later anyway.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index a9644351d75f..0b80a16d9872 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -251,8 +251,8 @@ static u32 dw_spi_get_cr0(struct dw_spi *dws, struct spi_device *spi)
 	return cr0;
 }
 
-static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
-			      struct spi_transfer *transfer)
+static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
+				 struct spi_transfer *transfer)
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u32 cr0 = chip->cr0;
@@ -265,6 +265,17 @@ static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
 		cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
 
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
+
+	/* Handle per transfer options for bpw and speed */
+	if (transfer->speed_hz != dws->current_freq) {
+		if (transfer->speed_hz != chip->speed_hz) {
+			/* clk_div doesn't support odd number */
+			chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
+			chip->speed_hz = transfer->speed_hz;
+		}
+		dws->current_freq = transfer->speed_hz;
+		spi_set_clk(dws, chip->clk_div);
+	}
 }
 
 static int dw_spi_transfer_one(struct spi_controller *master,
@@ -289,21 +300,10 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	spi_enable_chip(dws, 0);
 
-	/* Handle per transfer options for bpw and speed */
-	if (transfer->speed_hz != dws->current_freq) {
-		if (transfer->speed_hz != chip->speed_hz) {
-			/* clk_div doesn't support odd number */
-			chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
-			chip->speed_hz = transfer->speed_hz;
-		}
-		dws->current_freq = transfer->speed_hz;
-		spi_set_clk(dws, chip->clk_div);
-	}
+	dw_spi_update_config(dws, spi, transfer);
 
 	transfer->effective_speed_hz = dws->max_freq / chip->clk_div;
 
-	dw_spi_update_cr0(dws, spi, transfer);
-
 	/* Check if current transfer is a DMA transaction */
 	if (master->can_dma && master->can_dma(master, spi, transfer))
 		dws->dma_mapped = master->cur_msg_mapped;
-- 
2.27.0


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

* [PATCH 14/30] spi: dw: Simplify the SPI bus speed config procedure
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (12 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 13/30] spi: dw: Update SPI bus speed in a config function Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:28 ` [PATCH 15/30] spi: dw: Update Rx sample delay in the config function Serge Semin
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The code currently responsible for the SPI communication speed setting up
is a bit messy. Most likely for some historical reason the bus frequency
is saved in the peripheral chip private data. It's pointless now since the
custom communication speed is a SPI-transfer-specific thing and only if
there is no SPI transfer data specified (like during the SPI memory
operations) it can be taken from the SPI device structure. But even in the
later case there is no point in having the clock divider and the SPI bus
frequency saved in the chip data, because the controller can be used for
both SPI-transfer-based and SPI-transfer-less communications. From
software point of view keeping the current clock divider in an SPI-device
specific storage may give a small performance gain (to avoid sometimes a
round-up division), but in comparison to the total SPI transfer time it
just doesn't worth saving a few CPU cycles in comparison to the total SPI
transfer time while having the harder to read code. The only optimization,
which could worth preserving in the code is to avoid unnecessary DW SPI
controller registers update if it's possible. So to speak let's simplify
the SPI communication speed update procedure by removing the clock-related
fields from the peripheral chip data and update the DW SPI clock divider
only if it's really changed. The later change is reached by keeping the
effective SPI bus speed in the internal DW SPI private data.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 0b80a16d9872..92138a6ada12 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -24,9 +24,6 @@
 struct chip_data {
 	u8 tmode;		/* TR/TO/RO/EEPROM */
 
-	u16 clk_div;		/* baud rate divider */
-	u32 speed_hz;		/* baud rate */
-
 	u32 cr0;
 	u32 rx_sample_dly;	/* RX sample delay */
 };
@@ -256,6 +253,8 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u32 cr0 = chip->cr0;
+	u32 speed_hz;
+	u16 clk_div;
 
 	cr0 |= (transfer->bits_per_word - 1);
 
@@ -266,15 +265,13 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
 
-	/* Handle per transfer options for bpw and speed */
-	if (transfer->speed_hz != dws->current_freq) {
-		if (transfer->speed_hz != chip->speed_hz) {
-			/* clk_div doesn't support odd number */
-			chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
-			chip->speed_hz = transfer->speed_hz;
-		}
-		dws->current_freq = transfer->speed_hz;
-		spi_set_clk(dws, chip->clk_div);
+	/* Note DW APB SSI clock divider doesn't support odd numbers */
+	clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
+	speed_hz = dws->max_freq / clk_div;
+
+	if (dws->current_freq != speed_hz) {
+		spi_set_clk(dws, clk_div);
+		dws->current_freq = speed_hz;
 	}
 }
 
@@ -302,7 +299,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	dw_spi_update_config(dws, spi, transfer);
 
-	transfer->effective_speed_hz = dws->max_freq / chip->clk_div;
+	transfer->effective_speed_hz = dws->current_freq;
 
 	/* Check if current transfer is a DMA transaction */
 	if (master->can_dma && master->can_dma(master, spi, transfer))
-- 
2.27.0


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

* [PATCH 15/30] spi: dw: Update Rx sample delay in the config function
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (13 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 14/30] spi: dw: Simplify the SPI bus speed config procedure Serge Semin
@ 2020-09-20 11:28 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 16/30] spi: dw: Add DW SPI controller config structure Serge Semin
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:28 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Rx sample delay can be SPI device specific, and should be synchronously
initialized with the rest of the communication and peripheral device
related controller setups. So let's move the Rx-sample delay setup into
the DW APB SSI configuration update method.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 92138a6ada12..f00fc4828480 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -273,13 +273,18 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 		spi_set_clk(dws, clk_div);
 		dws->current_freq = speed_hz;
 	}
+
+	/* Update RX sample delay if required */
+	if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
+		dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
+		dws->cur_rx_sample_dly = chip->rx_sample_dly;
+	}
 }
 
 static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
 {
 	struct dw_spi *dws = spi_controller_get_devdata(master);
-	struct chip_data *chip = spi_get_ctldata(spi);
 	u8 imask = 0;
 	u16 txlevel = 0;
 	int ret;
@@ -305,12 +310,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	if (master->can_dma && master->can_dma(master, spi, transfer))
 		dws->dma_mapped = master->cur_msg_mapped;
 
-	/* Update RX sample delay if required */
-	if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
-		dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
-		dws->cur_rx_sample_dly = chip->rx_sample_dly;
-	}
-
 	/* For poll mode just disable all interrupts */
 	spi_mask_intr(dws, 0xff);
 
-- 
2.27.0


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

* [PATCH 16/30] spi: dw: Add DW SPI controller config structure
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (14 preceding siblings ...)
  2020-09-20 11:28 ` [PATCH 15/30] spi: dw: Update Rx sample delay in the config function Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 17/30] spi: dw: Refactor data IO procedure Serge Semin
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

DW APB SSI controller can be used by the two SPI core interfaces:
traditional SPI transfers and SPI memory operations. The controller needs
to be accordingly configured at runtime when the corresponding operations
are executed. In order to do that for the both interfaces from a single
function we introduce a new data wrapper for the transfer mode, data
width, number of data frames (for the automatic data transfer) and the bus
frequency. It will be used by the update_config() method to tune the DW
APB SSI up.

The update_config() method is made exported to be used not only by the DW
SPI core driver, but by the glue layer drivers too. This will be required
in a coming further commit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 29 +++++++++++++++++------------
 drivers/spi/spi-dw.h      | 10 ++++++++++
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index f00fc4828480..9102685c1523 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -20,10 +20,8 @@
 #include <linux/debugfs.h>
 #endif
 
-/* Slave spi_dev related */
+/* Slave spi_device related */
 struct chip_data {
-	u8 tmode;		/* TR/TO/RO/EEPROM */
-
 	u32 cr0;
 	u32 rx_sample_dly;	/* RX sample delay */
 };
@@ -248,25 +246,28 @@ static u32 dw_spi_get_cr0(struct dw_spi *dws, struct spi_device *spi)
 	return cr0;
 }
 
-static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
-				 struct spi_transfer *transfer)
+void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
+			  struct dw_spi_cfg *cfg)
 {
 	struct chip_data *chip = spi_get_ctldata(spi);
 	u32 cr0 = chip->cr0;
 	u32 speed_hz;
 	u16 clk_div;
 
-	cr0 |= (transfer->bits_per_word - 1);
+	cr0 |= (cfg->dfs - 1);
 
 	if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
-		cr0 |= chip->tmode << SPI_TMOD_OFFSET;
+		cr0 |= cfg->tmode << SPI_TMOD_OFFSET;
 	else
-		cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
+		cr0 |= cfg->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
 
 	dw_writel(dws, DW_SPI_CTRLR0, cr0);
 
+	if (cfg->tmode == SPI_TMOD_EPROMREAD || cfg->tmode == SPI_TMOD_RO)
+		dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
+
 	/* Note DW APB SSI clock divider doesn't support odd numbers */
-	clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe;
+	clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe;
 	speed_hz = dws->max_freq / clk_div;
 
 	if (dws->current_freq != speed_hz) {
@@ -280,11 +281,17 @@ static void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 		dws->cur_rx_sample_dly = chip->rx_sample_dly;
 	}
 }
+EXPORT_SYMBOL_GPL(dw_spi_update_config);
 
 static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
 {
 	struct dw_spi *dws = spi_controller_get_devdata(master);
+	struct dw_spi_cfg cfg = {
+		.tmode = SPI_TMOD_TR,
+		.dfs = transfer->bits_per_word,
+		.freq = transfer->speed_hz,
+	};
 	u8 imask = 0;
 	u16 txlevel = 0;
 	int ret;
@@ -302,7 +309,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	spi_enable_chip(dws, 0);
 
-	dw_spi_update_config(dws, spi, transfer);
+	dw_spi_update_config(dws, spi, &cfg);
 
 	transfer->effective_speed_hz = dws->current_freq;
 
@@ -388,8 +395,6 @@ static int dw_spi_setup(struct spi_device *spi)
 	 */
 	chip->cr0 = dw_spi_get_cr0(dws, spi);
 
-	chip->tmode = SPI_TMOD_TR;
-
 	return 0;
 }
 
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index c02351cf2f99..2a2346438564 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -111,6 +111,14 @@ enum dw_ssi_type {
 #define DW_SPI_CAP_KEEMBAY_MST		BIT(1)
 #define DW_SPI_CAP_DWC_SSI		BIT(2)
 
+/* Slave spi_transfer/spi_mem_op related */
+struct dw_spi_cfg {
+	u8 tmode;
+	u8 dfs;
+	u32 ndf;
+	u32 freq;
+};
+
 struct dw_spi;
 struct dw_spi_dma_ops {
 	int (*dma_init)(struct device *dev, struct dw_spi *dws);
@@ -249,6 +257,8 @@ static inline void spi_shutdown_chip(struct dw_spi *dws)
 }
 
 extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
+extern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
+				 struct dw_spi_cfg *cfg);
 extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
 extern void dw_spi_remove_host(struct dw_spi *dws);
 extern int dw_spi_suspend_host(struct dw_spi *dws);
-- 
2.27.0


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

* [PATCH 17/30] spi: dw: Refactor data IO procedure
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (15 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 16/30] spi: dw: Add DW SPI controller config structure Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 18/30] spi: dw: Refactor IRQ-based SPI transfer procedure Serge Semin
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The Tx and Rx data write/read procedure can be significantly simplified by
using Tx/Rx transfer lengths instead of the end pointers. By having the
Tx/Rx data leftover lengths (in the number of transfer words) we can get
rid of all subtraction and division operations utilized here and there in
the tx_max(), rx_max(), dw_writer() and dw_reader() methods. Such
modification will not only give us the more optimized IO procedures, but
will make the data IO methods much more readable than before.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 37 +++++++++++++++++--------------------
 drivers/spi/spi-dw.h      |  5 ++---
 2 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 9102685c1523..84c1fdfd6e52 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -108,9 +108,8 @@ EXPORT_SYMBOL_GPL(dw_spi_set_cs);
 /* Return the max entries we can fill into tx fifo */
 static inline u32 tx_max(struct dw_spi *dws)
 {
-	u32 tx_left, tx_room, rxtx_gap;
+	u32 tx_room, rxtx_gap;
 
-	tx_left = (dws->tx_end - dws->tx) / dws->n_bytes;
 	tx_room = dws->fifo_len - dw_readl(dws, DW_SPI_TXFLR);
 
 	/*
@@ -121,18 +120,15 @@ static inline u32 tx_max(struct dw_spi *dws)
 	 * shift registers. So a control from sw point of
 	 * view is taken.
 	 */
-	rxtx_gap =  ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx))
-			/ dws->n_bytes;
+	rxtx_gap = dws->fifo_len - (dws->rx_len - dws->tx_len);
 
-	return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap));
+	return min3((u32)dws->tx_len, tx_room, rxtx_gap);
 }
 
 /* Return the max entries we should read out of rx fifo */
 static inline u32 rx_max(struct dw_spi *dws)
 {
-	u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
-
-	return min_t(u32, rx_left, dw_readl(dws, DW_SPI_RXFLR));
+	return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR));
 }
 
 static void dw_writer(struct dw_spi *dws)
@@ -141,15 +137,16 @@ static void dw_writer(struct dw_spi *dws)
 	u16 txw = 0;
 
 	while (max--) {
-		/* Set the tx word if the transfer's original "tx" is not null */
-		if (dws->tx_end - dws->len) {
+		if (dws->tx) {
 			if (dws->n_bytes == 1)
 				txw = *(u8 *)(dws->tx);
 			else
 				txw = *(u16 *)(dws->tx);
+
+			dws->tx += dws->n_bytes;
 		}
 		dw_write_io_reg(dws, DW_SPI_DR, txw);
-		dws->tx += dws->n_bytes;
+		--dws->tx_len;
 	}
 }
 
@@ -160,14 +157,15 @@ static void dw_reader(struct dw_spi *dws)
 
 	while (max--) {
 		rxw = dw_read_io_reg(dws, DW_SPI_DR);
-		/* Care rx only if the transfer's original "rx" is not null */
-		if (dws->rx_end - dws->len) {
+		if (dws->rx) {
 			if (dws->n_bytes == 1)
 				*(u8 *)(dws->rx) = rxw;
 			else
 				*(u16 *)(dws->rx) = rxw;
+
+			dws->rx += dws->n_bytes;
 		}
-		dws->rx += dws->n_bytes;
+		--dws->rx_len;
 	}
 }
 
@@ -192,7 +190,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 	}
 
 	dw_reader(dws);
-	if (dws->rx_end == dws->rx) {
+	if (!dws->rx_len) {
 		spi_mask_intr(dws, 0xff);
 		spi_finalize_current_transfer(dws->master);
 		return IRQ_HANDLED;
@@ -299,12 +297,11 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	dws->dma_mapped = 0;
 	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
 	dws->tx = (void *)transfer->tx_buf;
-	dws->tx_end = dws->tx + transfer->len;
+	dws->tx_len = transfer->len / dws->n_bytes;
 	dws->rx = transfer->rx_buf;
-	dws->rx_end = dws->rx + transfer->len;
-	dws->len = transfer->len;
+	dws->rx_len = dws->tx_len;
 
-	/* Ensure dw->rx and dw->rx_end are visible */
+	/* Ensure the data above is visible for all CPUs */
 	smp_mb();
 
 	spi_enable_chip(dws, 0);
@@ -331,7 +328,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 			return ret;
 		}
 	} else {
-		txlevel = min_t(u16, dws->fifo_len / 2, dws->len / dws->n_bytes);
+		txlevel = min_t(u16, dws->fifo_len / 2, dws->tx_len);
 		dw_writel(dws, DW_SPI_TXFTLR, txlevel);
 
 		/* Set the interrupt mask */
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 2a2346438564..cfc9f63acde4 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -147,11 +147,10 @@ struct dw_spi {
 	void (*set_cs)(struct spi_device *spi, bool enable);
 
 	/* Current message transfer state info */
-	size_t			len;
 	void			*tx;
-	void			*tx_end;
+	unsigned int		tx_len;
 	void			*rx;
-	void			*rx_end;
+	unsigned int		rx_len;
 	int			dma_mapped;
 	u8			n_bytes;	/* current is a 1/2 bytes op */
 	irqreturn_t		(*transfer_handler)(struct dw_spi *dws);
-- 
2.27.0


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

* [PATCH 18/30] spi: dw: Refactor IRQ-based SPI transfer procedure
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (16 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 17/30] spi: dw: Refactor data IO procedure Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 19/30] spi: dw: Perform IRQ setup in a dedicated function Serge Semin
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

Current IRQ-based SPI transfer execution procedure doesn't work well at
the final stage of the execution. If all the Tx data is sent out (written
to the Tx FIFO) but there is some data left to receive, the Tx FIFO Empty
IRQ will constantly happen until all of the requested inbound data is
received. Though for a short period of time, but it will make the system
less responsive. In order to fix that let's refactor the SPI transfer
execution procedure by taking the Rx FIFO Full IRQ into account. We'll read
and write SPI transfer data each time the IRQ happens as before. If all
the outbound data is sent out, we'll disable the Tx FIFO Empty IRQ. If
there is still some data to receive, we'll adjust the Rx FIFO Threshold
level, so the next IRQ would be raised at the moment of all incoming data
being available in the Rx FIFO.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 33 ++++++++++++++++++++++++---------
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 84c1fdfd6e52..682463b2f68b 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -189,17 +189,30 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
 		return IRQ_HANDLED;
 	}
 
+	/*
+	 * Read data from the Rx FIFO every time we've got a chance executing
+	 * this method. If there is nothing left to receive, terminate the
+	 * procedure. Otherwise adjust the Rx FIFO Threshold level if it's a
+	 * final stage of the transfer. By doing so we'll get the next IRQ
+	 * right when the leftover incoming data is received.
+	 */
 	dw_reader(dws);
 	if (!dws->rx_len) {
 		spi_mask_intr(dws, 0xff);
 		spi_finalize_current_transfer(dws->master);
-		return IRQ_HANDLED;
+	} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
+		dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
 	}
+
+	/*
+	 * Send data out if Tx FIFO Empty IRQ is received. The IRQ will be
+	 * disabled after the data transmission is finished so not to
+	 * have the TXE IRQ flood at the final stage of the transfer.
+	 */
 	if (irq_status & SPI_INT_TXEI) {
-		spi_mask_intr(dws, SPI_INT_TXEI);
 		dw_writer(dws);
-		/* Enable TX irq always, it will be disabled when RX finished */
-		spi_umask_intr(dws, SPI_INT_TXEI);
+		if (!dws->tx_len)
+			spi_mask_intr(dws, SPI_INT_TXEI);
 	}
 
 	return IRQ_HANDLED;
@@ -317,10 +330,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	/* For poll mode just disable all interrupts */
 	spi_mask_intr(dws, 0xff);
 
-	/*
-	 * Interrupt mode
-	 * we only need set the TXEI IRQ, as TX/RX always happen syncronizely
-	 */
 	if (dws->dma_mapped) {
 		ret = dws->dma_ops->dma_setup(dws, transfer);
 		if (ret < 0) {
@@ -328,12 +337,18 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 			return ret;
 		}
 	} else {
+		/*
+		 * Originally Tx and Rx data lengths match. Rx FIFO Threshold level
+		 * will be adjusted at the final stage of the IRQ-based SPI transfer
+		 * execution so not to lose the leftover of the incoming data.
+		 */
 		txlevel = min_t(u16, dws->fifo_len / 2, dws->tx_len);
 		dw_writel(dws, DW_SPI_TXFTLR, txlevel);
+		dw_writel(dws, DW_SPI_RXFTLR, txlevel - 1);
 
 		/* Set the interrupt mask */
 		imask |= SPI_INT_TXEI | SPI_INT_TXOI |
-			 SPI_INT_RXUI | SPI_INT_RXOI;
+			 SPI_INT_RXUI | SPI_INT_RXOI | SPI_INT_RXFI;
 		spi_umask_intr(dws, imask);
 
 		dws->transfer_handler = interrupt_transfer;
-- 
2.27.0


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

* [PATCH 19/30] spi: dw: Perform IRQ setup in a dedicated function
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (17 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 18/30] spi: dw: Refactor IRQ-based SPI transfer procedure Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 20/30] spi: dw: Unmask IRQs after enabling the chip Serge Semin
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

In order to make the transfer_one() callback method more readable and
for unification with the DMA-based transfer, let's detach the IRQ setup
procedure into a dedicated function. While at it rename the IRQ-based
transfer handler function to be dw_spi-prefixe and looking more like the
DMA-related one.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 41 ++++++++++++++++++++++-----------------
 1 file changed, 23 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 682463b2f68b..08bc53b9de88 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -178,7 +178,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
 	spi_finalize_current_transfer(dws->master);
 }
 
-static irqreturn_t interrupt_transfer(struct dw_spi *dws)
+static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
 {
 	u16 irq_status = dw_readl(dws, DW_SPI_ISR);
 
@@ -294,6 +294,27 @@ void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 }
 EXPORT_SYMBOL_GPL(dw_spi_update_config);
 
+static void dw_spi_irq_setup(struct dw_spi *dws)
+{
+	u16 level;
+	u8 imask;
+
+	/*
+	 * Originally Tx and Rx data lengths match. Rx FIFO Threshold level
+	 * will be adjusted at the final stage of the IRQ-based SPI transfer
+	 * execution so not to lose the leftover of the incoming data.
+	 */
+	level = min_t(u16, dws->fifo_len / 2, dws->tx_len);
+	dw_writel(dws, DW_SPI_TXFTLR, level);
+	dw_writel(dws, DW_SPI_RXFTLR, level - 1);
+
+	imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI |
+		SPI_INT_RXFI;
+	spi_umask_intr(dws, imask);
+
+	dws->transfer_handler = dw_spi_transfer_handler;
+}
+
 static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
 {
@@ -303,8 +324,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 		.dfs = transfer->bits_per_word,
 		.freq = transfer->speed_hz,
 	};
-	u8 imask = 0;
-	u16 txlevel = 0;
 	int ret;
 
 	dws->dma_mapped = 0;
@@ -337,21 +356,7 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 			return ret;
 		}
 	} else {
-		/*
-		 * Originally Tx and Rx data lengths match. Rx FIFO Threshold level
-		 * will be adjusted at the final stage of the IRQ-based SPI transfer
-		 * execution so not to lose the leftover of the incoming data.
-		 */
-		txlevel = min_t(u16, dws->fifo_len / 2, dws->tx_len);
-		dw_writel(dws, DW_SPI_TXFTLR, txlevel);
-		dw_writel(dws, DW_SPI_RXFTLR, txlevel - 1);
-
-		/* Set the interrupt mask */
-		imask |= SPI_INT_TXEI | SPI_INT_TXOI |
-			 SPI_INT_RXUI | SPI_INT_RXOI | SPI_INT_RXFI;
-		spi_umask_intr(dws, imask);
-
-		dws->transfer_handler = interrupt_transfer;
+		dw_spi_irq_setup(dws);
 	}
 
 	spi_enable_chip(dws, 1);
-- 
2.27.0


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

* [PATCH 20/30] spi: dw: Unmask IRQs after enabling the chip
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (18 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 19/30] spi: dw: Perform IRQ setup in a dedicated function Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 21/30] spi: dw: Discard chip enabling on DMA setup error Serge Semin
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

It's theoretically erroneous to enable IRQ before the chip is turned on.
If IRQ handler gets executed before the chip is enabled, then any data
written to the Tx FIFO will be just ignored.

I say "theoretically" because we haven't noticed any problem with that,
but let's fix it anyway just in case...

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 08bc53b9de88..8dbe11c1821c 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -355,8 +355,6 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 			spi_enable_chip(dws, 1);
 			return ret;
 		}
-	} else {
-		dw_spi_irq_setup(dws);
 	}
 
 	spi_enable_chip(dws, 1);
@@ -364,6 +362,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 	if (dws->dma_mapped)
 		return dws->dma_ops->dma_transfer(dws, transfer);
 
+	dw_spi_irq_setup(dws);
+
 	return 1;
 }
 
-- 
2.27.0


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

* [PATCH 21/30] spi: dw: Discard chip enabling on DMA setup error
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (19 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 20/30] spi: dw: Unmask IRQs after enabling the chip Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 22/30] spi: dw: De-assert chip-select on reset Serge Semin
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

It's pointless to enable the chip back if the DMA setup procedure fails,
since we'll disable it on the next transfer anyway. For the same reason We
don't do that in case of a failure detected in any other methods called
from the transfer_one() method.

While at it consider any non-zero value returned from the dma_setup
callback to be erroneous as it's supposed to be in the kernel.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 8dbe11c1821c..65db4dd3ea8a 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -351,10 +351,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	if (dws->dma_mapped) {
 		ret = dws->dma_ops->dma_setup(dws, transfer);
-		if (ret < 0) {
-			spi_enable_chip(dws, 1);
+		if (ret)
 			return ret;
-		}
 	}
 
 	spi_enable_chip(dws, 1);
-- 
2.27.0


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

* [PATCH 22/30] spi: dw: De-assert chip-select on reset
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (20 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 21/30] spi: dw: Discard chip enabling on DMA setup error Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 23/30] spi: dw: Explicitly de-assert CS on SPI transfer completion Serge Semin
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

SPI memory operations implementation will require to have the CS register
cleared before executing the operation in order not to have the
transmission automatically started prior the Tx FIFO is pre-initialized.
Let's clear the register then on explicit controller reset to fulfil the
requirements in case of an error or having the CS left set by a bootloader
or another software.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw.h | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index cfc9f63acde4..eb1d46983319 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -237,15 +237,16 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
 }
 
 /*
- * This disables the SPI controller, interrupts, clears the interrupts status,
- * and re-enable the controller back. Transmit and receive FIFO buffers are
- * cleared when the device is disabled.
+ * This disables the SPI controller, interrupts, clears the interrupts status
+ * and CS, then re-enables the controller back. Transmit and receive FIFO
+ * buffers are cleared when the device is disabled.
  */
 static inline void spi_reset_chip(struct dw_spi *dws)
 {
 	spi_enable_chip(dws, 0);
 	spi_mask_intr(dws, 0xff);
 	dw_readl(dws, DW_SPI_ICR);
+	dw_writel(dws, DW_SPI_SER, 0);
 	spi_enable_chip(dws, 1);
 }
 
-- 
2.27.0


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

* [PATCH 23/30] spi: dw: Explicitly de-assert CS on SPI transfer completion
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (21 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 22/30] spi: dw: De-assert chip-select on reset Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 24/30] spi: dw: Move num-of retries parameter to the header file Serge Semin
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

By design of the currently available native set_cs callback, the CS
de-assertion will be done only if it's required by the corresponding
controller capability. But in order to pre-fill the Tx FIFO buffer with
data during the SPI memory ops execution the SER register needs to be left
cleared before that. We'll also need a way to explicitly set and clear the
corresponding CS bit at a certain moment of the operation. Let's alter
the set_cs function then to also de-activate the CS, when it's required.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 65db4dd3ea8a..7a25ea6f4af6 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -100,7 +100,7 @@ void dw_spi_set_cs(struct spi_device *spi, bool enable)
 	 */
 	if (cs_high == enable)
 		dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
-	else if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
+	else
 		dw_writel(dws, DW_SPI_SER, 0);
 }
 EXPORT_SYMBOL_GPL(dw_spi_set_cs);
-- 
2.27.0


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

* [PATCH 24/30] spi: dw: Move num-of retries parameter to the header file
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (22 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 23/30] spi: dw: Explicitly de-assert CS on SPI transfer completion Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 25/30] spi: dw: Add generic DW SSI status-check method Serge Semin
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The parameter will be needed for another wait-done method being added in
the framework of the SPI memory operation modification in a further
commit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-dma.c | 5 ++---
 drivers/spi/spi-dw.h     | 2 ++
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index bb390ff67d1d..9db119dc5554 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -17,7 +17,6 @@
 
 #include "spi-dw.h"
 
-#define WAIT_RETRIES	5
 #define RX_BUSY		0
 #define RX_BURST_LEVEL	16
 #define TX_BUSY		1
@@ -208,7 +207,7 @@ static inline bool dw_spi_dma_tx_busy(struct dw_spi *dws)
 static int dw_spi_dma_wait_tx_done(struct dw_spi *dws,
 				   struct spi_transfer *xfer)
 {
-	int retry = WAIT_RETRIES;
+	int retry = SPI_WAIT_RETRIES;
 	struct spi_delay delay;
 	u32 nents;
 
@@ -283,7 +282,7 @@ static inline bool dw_spi_dma_rx_busy(struct dw_spi *dws)
 
 static int dw_spi_dma_wait_rx_done(struct dw_spi *dws)
 {
-	int retry = WAIT_RETRIES;
+	int retry = SPI_WAIT_RETRIES;
 	struct spi_delay delay;
 	unsigned long ns, us;
 	u32 nents;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index eb1d46983319..946065201c9c 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -100,6 +100,8 @@
 #define SPI_DMA_RDMAE			(1 << 0)
 #define SPI_DMA_TDMAE			(1 << 1)
 
+#define SPI_WAIT_RETRIES		5
+
 enum dw_ssi_type {
 	SSI_MOTO_SPI = 0,
 	SSI_TI_SSP,
-- 
2.27.0


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

* [PATCH 25/30] spi: dw: Add generic DW SSI status-check method
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (23 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 24/30] spi: dw: Move num-of retries parameter to the header file Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 26/30] spi: dw: Add memory operations support Serge Semin
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

The DW SSI errors handling method can be generically implemented for all
types of the transfers: IRQ, DMA and poll-based ones. It will be a
function which checks the overflow/underflow error flags and resets the
controller if any of them is set. In the framework of this commit we make
use of the new method to detect the errors in the IRQ- and DMA-based SPI
transfer execution procedures.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 43 +++++++++++++++++++++++++++++++--------
 drivers/spi/spi-dw-dma.c  | 11 ++--------
 drivers/spi/spi-dw.h      |  1 +
 3 files changed, 37 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 7a25ea6f4af6..77d61ded9256 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -169,23 +169,48 @@ static void dw_reader(struct dw_spi *dws)
 	}
 }
 
-static void int_error_stop(struct dw_spi *dws, const char *msg)
+int dw_spi_check_status(struct dw_spi *dws, bool raw)
 {
-	spi_reset_chip(dws);
+	u32 irq_status;
+	int ret = 0;
+
+	if (raw)
+		irq_status = dw_readl(dws, DW_SPI_RISR);
+	else
+		irq_status = dw_readl(dws, DW_SPI_ISR);
+
+	if (irq_status & SPI_INT_RXOI) {
+		dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
+		ret = -EIO;
+	}
+
+	if (irq_status & SPI_INT_RXUI) {
+		dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
+		ret = -EIO;
+	}
 
-	dev_err(&dws->master->dev, "%s\n", msg);
-	dws->master->cur_msg->status = -EIO;
-	spi_finalize_current_transfer(dws->master);
+	if (irq_status & SPI_INT_TXOI) {
+		dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
+		ret = -EIO;
+	}
+
+	/* Generically handle the erroneous situation */
+	if (ret) {
+		spi_reset_chip(dws);
+		if (dws->master->cur_msg)
+			dws->master->cur_msg->status = ret;
+	}
+
+	return ret;
 }
+EXPORT_SYMBOL_GPL(dw_spi_check_status);
 
 static irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
 {
 	u16 irq_status = dw_readl(dws, DW_SPI_ISR);
 
-	/* Error handling */
-	if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
-		dw_readl(dws, DW_SPI_ICR);
-		int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
+	if (dw_spi_check_status(dws, false)) {
+		spi_finalize_current_transfer(dws->master);
 		return IRQ_HANDLED;
 	}
 
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index 9db119dc5554..1969b09b4f5e 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -144,17 +144,10 @@ static void dw_spi_dma_exit(struct dw_spi *dws)
 
 static irqreturn_t dw_spi_dma_transfer_handler(struct dw_spi *dws)
 {
-	u16 irq_status = dw_readl(dws, DW_SPI_ISR);
+	dw_spi_check_status(dws, false);
 
-	if (!irq_status)
-		return IRQ_NONE;
-
-	dw_readl(dws, DW_SPI_ICR);
-	spi_reset_chip(dws);
-
-	dev_err(&dws->master->dev, "%s: FIFO overrun/underrun\n", __func__);
-	dws->master->cur_msg->status = -EIO;
 	complete(&dws->dma_completion);
+
 	return IRQ_HANDLED;
 }
 
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 946065201c9c..5eb98ece2f2a 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -261,6 +261,7 @@ static inline void spi_shutdown_chip(struct dw_spi *dws)
 extern void dw_spi_set_cs(struct spi_device *spi, bool enable);
 extern void dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
 				 struct dw_spi_cfg *cfg);
+extern int dw_spi_check_status(struct dw_spi *dws, bool raw);
 extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
 extern void dw_spi_remove_host(struct dw_spi *dws);
 extern int dw_spi_suspend_host(struct dw_spi *dws);
-- 
2.27.0


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

* [PATCH 26/30] spi: dw: Add memory operations support
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (24 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 25/30] spi: dw: Add generic DW SSI status-check method Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 27/30] spi: dw: Introduce max mem-ops SPI bus frequency setting Serge Semin
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

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: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/Kconfig       |   1 +
 drivers/spi/spi-dw-core.c | 300 ++++++++++++++++++++++++++++++++++++++
 drivers/spi/spi-dw.h      |  13 ++
 3 files changed, 314 insertions(+)

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index c6ea760ea5f0..1f70bb1e7fa9 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -235,6 +235,7 @@ config SPI_DAVINCI
 
 config SPI_DESIGNWARE
 	tristate "DesignWare SPI controller core support"
+	imply SPI_MEM
 	help
 	  general driver for SPI controller core from DesignWare
 
diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 77d61ded9256..ca22f427d82d 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -8,10 +8,13 @@
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/preempt.h>
 #include <linux/highmem.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/string.h>
 #include <linux/of.h>
 
 #include "spi-dw.h"
@@ -401,6 +404,300 @@ static void dw_spi_handle_err(struct spi_controller *master,
 	spi_reset_chip(dws);
 }
 
+static int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
+{
+	if (op->data.dir == SPI_MEM_DATA_IN)
+		op->data.nbytes = clamp_val(op->data.nbytes, 0, SPI_NDF_MASK + 1);
+
+	return 0;
+}
+
+static bool dw_spi_supports_mem_op(struct spi_mem *mem,
+				   const struct spi_mem_op *op)
+{
+	if (op->data.buswidth > 1 || op->addr.buswidth > 1 ||
+	    op->dummy.buswidth > 1 || op->cmd.buswidth > 1)
+		return false;
+
+	return spi_mem_default_supports_op(mem, op);
+}
+
+static int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
+{
+	unsigned int i, j, len;
+	u8 *out;
+
+	/*
+	 * Calculate the total length of the EEPROM command transfer and
+	 * either use the pre-allocated buffer or create a temporary one.
+	 */
+	len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
+	if (op->data.dir == SPI_MEM_DATA_OUT)
+		len += op->data.nbytes;
+
+	if (len <= SPI_BUF_SIZE) {
+		out = dws->buf;
+	} else {
+		out = kzalloc(len, GFP_KERNEL);
+		if (!out)
+			return -ENOMEM;
+	}
+
+	/*
+	 * Collect the operation code, address and dummy bytes into the single
+	 * buffer. If it's a transfer with data to be sent, also copy it into the
+	 * single buffer in order to speed the data transmission up.
+	 */
+	for (i = 0; i < op->cmd.nbytes; ++i)
+		out[i] = SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1);
+	for (j = 0; j < op->addr.nbytes; ++i, ++j)
+		out[i] = SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1);
+	for (j = 0; j < op->dummy.nbytes; ++i, ++j)
+		out[i] = 0x0;
+
+	if (op->data.dir == SPI_MEM_DATA_OUT)
+		memcpy(&out[i], op->data.buf.out, op->data.nbytes);
+
+	dws->n_bytes = 1;
+	dws->tx = out;
+	dws->tx_len = len;
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		dws->rx = op->data.buf.in;
+		dws->rx_len = op->data.nbytes;
+	} else {
+		dws->rx = NULL;
+		dws->rx_len = 0;
+	}
+
+	return 0;
+}
+
+static void dw_spi_free_mem_buf(struct dw_spi *dws)
+{
+	if (dws->tx != dws->buf)
+		kfree(dws->tx);
+}
+
+static int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
+{
+	u32 room, entries, sts;
+	unsigned int len;
+	u8 *buf;
+
+	/*
+	 * At initial stage we just pre-fill the Tx FIFO in with no rush,
+	 * since native CS hasn't been enabled yet and the automatic data
+	 * transmission won't start til we do that.
+	 */
+	len = min(dws->fifo_len, dws->tx_len);
+	buf = dws->tx;
+	while (len--)
+		dw_write_io_reg(dws, DW_SPI_DR, *buf++);
+
+	/*
+	 * After setting any bit in the SER register the transmission will
+	 * start automatically. We have to keep up with that procedure
+	 * otherwise the CS de-assertion will happen whereupon the memory
+	 * operation will be pre-terminated.
+	 */
+	len = dws->tx_len - ((void *)buf - dws->tx);
+	dw_spi_set_cs(spi, false);
+	while (len) {
+		entries = readl_relaxed(dws->regs + DW_SPI_TXFLR);
+		if (!entries) {
+			dev_err(&dws->master->dev, "CS de-assertion on Tx\n");
+			return -EIO;
+		}
+		room = min(dws->fifo_len - entries, len);
+		for (; room; --room, --len)
+			dw_write_io_reg(dws, DW_SPI_DR, *buf++);
+	}
+
+	/*
+	 * Data fetching will start automatically if the EEPROM-read mode is
+	 * activated. We have to keep up with the incoming data pace to
+	 * prevent the Rx FIFO overflow causing the inbound data loss.
+	 */
+	len = dws->rx_len;
+	buf = dws->rx;
+	while (len) {
+		entries = readl_relaxed(dws->regs + DW_SPI_RXFLR);
+		if (!entries) {
+			sts = readl_relaxed(dws->regs + DW_SPI_RISR);
+			if (sts & SPI_INT_RXOI) {
+				dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
+				return -EIO;
+			}
+			continue;
+		}
+		entries = min(entries, len);
+		for (; entries; --entries, --len)
+			*buf++ = dw_read_io_reg(dws, DW_SPI_DR);
+	}
+
+	return 0;
+}
+
+static inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
+{
+	return dw_readl(dws, DW_SPI_SR) & SR_BUSY;
+}
+
+static int dw_spi_wait_mem_op_done(struct dw_spi *dws)
+{
+	int retry = SPI_WAIT_RETRIES;
+	struct spi_delay delay;
+	unsigned long ns, us;
+	u32 nents;
+
+	nents = dw_readl(dws, DW_SPI_TXFLR);
+	ns = NSEC_PER_SEC / dws->current_freq * nents;
+	ns *= dws->n_bytes * BITS_PER_BYTE;
+	if (ns <= NSEC_PER_USEC) {
+		delay.unit = SPI_DELAY_UNIT_NSECS;
+		delay.value = ns;
+	} else {
+		us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
+		delay.unit = SPI_DELAY_UNIT_USECS;
+		delay.value = clamp_val(us, 0, USHRT_MAX);
+	}
+
+	while (dw_spi_ctlr_busy(dws) && retry--)
+		spi_delay_exec(&delay, NULL);
+
+	if (retry < 0) {
+		dev_err(&dws->master->dev, "Mem op hanged up\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi)
+{
+	spi_enable_chip(dws, 0);
+	dw_spi_set_cs(spi, true);
+	spi_enable_chip(dws, 1);
+}
+
+/*
+ * The SPI memory operation implementation below is the best choice for the
+ * devices, which are selected by the native chip-select lane. It's
+ * specifically developed to workaround the problem with automatic chip-select
+ * lane toggle when there is no data in the Tx FIFO buffer. Luckily the current
+ * SPI-mem core calls exec_op() callback only if the GPIO-based CS is
+ * unavailable.
+ */
+static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
+{
+	struct dw_spi *dws = spi_controller_get_devdata(mem->spi->controller);
+	struct dw_spi_cfg cfg;
+	unsigned long flags;
+	int ret;
+
+	/*
+	 * Collect the outbound data into a single buffer to speed the
+	 * transmission up at least on the initial stage.
+	 */
+	ret = dw_spi_init_mem_buf(dws, op);
+	if (ret)
+		return ret;
+
+	/*
+	 * DW SPI EEPROM-read mode is required only for the SPI memory Data-IN
+	 * operation. Transmit-only mode is suitable for the rest of them.
+	 */
+	cfg.dfs = 8;
+	cfg.freq = mem->spi->max_speed_hz;
+	if (op->data.dir == SPI_MEM_DATA_IN) {
+		cfg.tmode = SPI_TMOD_EPROMREAD;
+		cfg.ndf = op->data.nbytes;
+	} else {
+		cfg.tmode = SPI_TMOD_TO;
+	}
+
+	spi_enable_chip(dws, 0);
+
+	dw_spi_update_config(dws, mem->spi, &cfg);
+
+	spi_mask_intr(dws, 0xff);
+
+	spi_enable_chip(dws, 1);
+
+	/*
+	 * DW APB SSI controller has very nasty peculiarities. First originally
+	 * (without any vendor-specific modifications) it doesn't provide a
+	 * direct way to set and clear the native chip-select signal. Instead
+	 * the controller de-asserts the CS lane if Tx FIFO isn't empty and a
+	 * transmission is going on, and automatically asserts it back to the
+	 * high level if the Tx FIFO doesn't have anything to be pushed out.
+	 * Due to that a multi-tasking or heavy IRQs activity might be fatal,
+	 * since the transfer procedure preemption may cause the Tx FIFO
+	 * getting empty and sudden CS assertion, which in the middle of the
+	 * transfer will most likely cause the data loss. Secondly the
+	 * EEPROM-read or Read-only DW SPI transfer modes imply the incoming
+	 * data being automatically pulled in into the Rx FIFO. So if the
+	 * driver software is late in fetching the data from the FIFO before
+	 * it's overflown, new incoming data will be lost. In order to make
+	 * sure the executed memory operations are CS-atomic and to prevent the
+	 * Rx FIFO overflow we have to disable the local interrupts so to block
+	 * any preemption during the subsequent IO operations.
+	 *
+	 * Note. At some circumstances disabling IRQs may not help to prevent
+	 * the problems described above. The CS de-assertion and Rx FIFO
+	 * overflow may still happen due to the relatively slow system bus, so
+	 * the write-then-read algo implemented here just won't keep up with an
+	 * SPI bus data transfer. Such situation is highly platform specific
+	 * and is supposed to be fixed by manual restricting the SPI bus
+	 * frequency using the dws->max_mem_freq parameter.
+	 */
+	local_irq_save(flags);
+	preempt_disable();
+
+	ret = dw_spi_write_then_read(dws, mem->spi);
+
+	local_irq_restore(flags);
+	preempt_enable();
+
+	/*
+	 * Wait for the operation being finished and check the controller
+	 * status only if there hasn't been any run-time error detected. In the
+	 * former case it's just pointless. In the later one to prevent an
+	 * additional error message printing since any hw error flag being set
+	 * would be due to an error detected on the data transfer.
+	 */
+	if (!ret) {
+		ret = dw_spi_wait_mem_op_done(dws);
+		if (!ret)
+			ret = dw_spi_check_status(dws, true);
+	}
+
+	dw_spi_stop_mem_op(dws, mem->spi);
+
+	dw_spi_free_mem_buf(dws);
+
+	return ret;
+}
+
+/*
+ * Initialize the default memory operations if a glue layer hasn't specified
+ * custom ones. Direct mapping operations will be preserved anyway since DW SPI
+ * controller doesn't have an embedded dirmap interface. Note the memory
+ * operations implemented in this driver is the best choice only for the DW APB
+ * SSI controller with standard native CS functionality. If a hardware vendor
+ * has fixed the automatic CS assertion/de-assertion peculiarity, then it will
+ * be safer to use the normal SPI-messages-based transfers implementation.
+ */
+static void dw_spi_init_mem_ops(struct dw_spi *dws)
+{
+	if (!dws->mem_ops.exec_op && !(dws->caps & DW_SPI_CAP_CS_OVERRIDE) &&
+	    !dws->set_cs) {
+		dws->mem_ops.adjust_op_size = dw_spi_adjust_mem_op_size;
+		dws->mem_ops.supports_op = dw_spi_supports_mem_op;
+		dws->mem_ops.exec_op = dw_spi_exec_mem_op;
+	}
+}
+
 /* This may be called twice for each spi dev */
 static int dw_spi_setup(struct spi_device *spi)
 {
@@ -501,6 +798,8 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 		goto err_free_master;
 	}
 
+	dw_spi_init_mem_ops(dws);
+
 	master->use_gpio_descriptors = true;
 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
 	master->bits_per_word_mask =  SPI_BPW_RANGE_MASK(4, 16);
@@ -511,6 +810,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	master->set_cs = dws->set_cs ?: dw_spi_set_cs;
 	master->transfer_one = dw_spi_transfer_one;
 	master->handle_err = dw_spi_handle_err;
+	master->mem_ops = &dws->mem_ops;
 	master->max_speed_hz = dws->max_freq;
 	master->dev.of_node = dev->of_node;
 	master->dev.fwnode = dev->fwnode;
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 5eb98ece2f2a..4b08fe34a85d 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -8,6 +8,7 @@
 #include <linux/irqreturn.h>
 #include <linux/io.h>
 #include <linux/scatterlist.h>
+#include <linux/spi/spi-mem.h>
 
 /* Register offsets */
 #define DW_SPI_CTRLR0			0x00
@@ -78,6 +79,9 @@
  */
 #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 */
 #define SR_MASK				0x7f		/* cover 7 bits */
 #define SR_BUSY				(1 << 0)
@@ -101,6 +105,11 @@
 #define SPI_DMA_TDMAE			(1 << 1)
 
 #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 {
 	SSI_MOTO_SPI = 0,
@@ -153,6 +162,7 @@ struct dw_spi {
 	unsigned int		tx_len;
 	void			*rx;
 	unsigned int		rx_len;
+	u8			buf[SPI_BUF_SIZE];
 	int			dma_mapped;
 	u8			n_bytes;	/* current is a 1/2 bytes op */
 	irqreturn_t		(*transfer_handler)(struct dw_spi *dws);
@@ -160,6 +170,9 @@ struct dw_spi {
 	u32			cur_rx_sample_dly;
 	u32			def_rx_sample_dly_ns;
 
+	/* Custom memory operations */
+	struct spi_controller_mem_ops mem_ops;
+
 	/* DMA info */
 	struct dma_chan		*txchan;
 	u32			txburst;
-- 
2.27.0


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

* [PATCH 27/30] spi: dw: Introduce max mem-ops SPI bus frequency setting
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (25 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 26/30] spi: dw: Add memory operations support Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 28/30] spi: dw: Add poll-based SPI transfers support Serge Semin
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

In some circumstances the current implementation of the SPI memory
operations may occasionally fail even though they are executed in the
atomic context. This may happen if the system bus is relatively slow in
comparison to the SPI bus frequency, or there is a concurrent access to
it, which makes the MMIO-operations occasionally stalling before
push-pulling data from the DW APB SPI FIFOs. These two problems we've
discovered on the Baikal-T1 SoC. In order to fix them we have no choice
but to set an artificial limitation on the SPI bus speed.

Note currently this limitation will be only applicable for the memory
operations, since the standard SPI core interface is implemented with an
assumption that there is no problem with the automatic CS toggling.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 4 +++-
 drivers/spi/spi-dw.h      | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index ca22f427d82d..7b901226fd38 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -608,7 +608,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
 	 * operation. Transmit-only mode is suitable for the rest of them.
 	 */
 	cfg.dfs = 8;
-	cfg.freq = mem->spi->max_speed_hz;
+	cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
 	if (op->data.dir == SPI_MEM_DATA_IN) {
 		cfg.tmode = SPI_TMOD_EPROMREAD;
 		cfg.ndf = op->data.nbytes;
@@ -695,6 +695,8 @@ static void dw_spi_init_mem_ops(struct dw_spi *dws)
 		dws->mem_ops.adjust_op_size = dw_spi_adjust_mem_op_size;
 		dws->mem_ops.supports_op = dw_spi_supports_mem_op;
 		dws->mem_ops.exec_op = dw_spi_exec_mem_op;
+		if (!dws->max_mem_freq)
+			dws->max_mem_freq = dws->max_freq;
 	}
 }
 
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 4b08fe34a85d..dc5781236cc6 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -148,6 +148,7 @@ struct dw_spi {
 	unsigned long		paddr;
 	int			irq;
 	u32			fifo_len;	/* depth of the FIFO buffer */
+	u32			max_mem_freq;	/* max mem-ops bus freq */
 	u32			max_freq;	/* max bus freq supported */
 
 	u32			caps;		/* DW SPI capabilities */
-- 
2.27.0


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

* [PATCH 28/30] spi: dw: Add poll-based SPI transfers support
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (26 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 27/30] spi: dw: Introduce max mem-ops SPI bus frequency setting Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-20 11:29 ` [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers Serge Semin
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, Rob Herring, linux-spi,
	devicetree, linux-kernel

A functionality of the poll-based transfer has been removed by
commit 1ceb09717e98 ("spi: dw: remove cs_control and poll_mode members
from chip_data") with a justification that "there is no user of one
anymore". It turns out one of our DW APB SSI core is synthesized with no
IRQ line attached and the only possible way of using it is to implement a
poll-based SPI transfer procedure. So we have to get the removed
functionality back, but with some alterations described below.

First of all the poll-based transfer is activated only if the DW SPI
controller doesn't have an IRQ line attached and the Linux IRQ number is
initialized with the IRQ_NOTCONNECTED value. Secondly the transfer
procedure is now executed with a delay performed between writer and reader
methods. The delay value is calculated based on the number of data words
expected to be received on the current iteration. Finally the errors
status is checked on each iteration.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/spi-dw-core.c | 40 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-dw-core.c b/drivers/spi/spi-dw-core.c
index 7b901226fd38..cd01225a0f81 100644
--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -343,6 +343,42 @@ static void dw_spi_irq_setup(struct dw_spi *dws)
 	dws->transfer_handler = dw_spi_transfer_handler;
 }
 
+/*
+ * The iterative procedure of the poll-based transfer is simple: write as much
+ * as possible to the Tx FIFO, wait until the pending to receive data is ready
+ * to be read, read it from the Rx FIFO and check whether the performed
+ * procedure has been successful.
+ *
+ * Note this method the same way as the IRQ-based transfer won't work well for
+ * the SPI devices connected to the controller with native CS due to the
+ * automatic CS assertion/de-assertion.
+ */
+static int dw_spi_poll_transfer(struct dw_spi *dws,
+				struct spi_transfer *transfer)
+{
+	struct spi_delay delay;
+	u16 nbits;
+	int ret;
+
+	delay.unit = SPI_DELAY_UNIT_SCK;
+	nbits = dws->n_bytes * BITS_PER_BYTE;
+
+	do {
+		dw_writer(dws);
+
+		delay.value = nbits * (dws->rx_len - dws->tx_len);
+		spi_delay_exec(&delay, transfer);
+
+		dw_reader(dws);
+
+		ret = dw_spi_check_status(dws, true);
+		if (ret)
+			return ret;
+	} while (dws->rx_len);
+
+	return 0;
+}
+
 static int dw_spi_transfer_one(struct spi_controller *master,
 		struct spi_device *spi, struct spi_transfer *transfer)
 {
@@ -387,6 +423,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,
 
 	if (dws->dma_mapped)
 		return dws->dma_ops->dma_transfer(dws, transfer);
+	else if (dws->irq == IRQ_NOTCONNECTED)
+		return dw_spi_poll_transfer(dws, transfer);
 
 	dw_spi_irq_setup(dws);
 
@@ -795,7 +833,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 
 	ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
 			  master);
-	if (ret < 0) {
+	if (ret < 0 && ret != -ENOTCONN) {
 		dev_err(dev, "can not get IRQ\n");
 		goto err_free_master;
 	}
-- 
2.27.0


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

* [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (27 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 28/30] spi: dw: Add poll-based SPI transfers support Serge Semin
@ 2020-09-20 11:29 ` Serge Semin
  2020-09-29 16:58   ` Rob Herring
  2020-09-20 11:41 ` [PATCH 30/30] spi: dw: Add Baikal-T1 SPI Controller glue driver Serge Semin
                   ` (2 subsequent siblings)
  31 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:29 UTC (permalink / raw)
  To: Mark Brown, Rob Herring
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Ramil Zaripov,
	Pavel Parkhomenko, Andy Shevchenko, Andy Shevchenko,
	Lars Povlsen, wuxu . wu, Feng Tang, linux-spi, devicetree,
	linux-kernel

These controllers are based on the DW APB SSI IP-core and embedded into
the SoC, so two of them are equipped with IRQ, DMA, 64 words FIFOs and 4
native CS, while another one as being utilized by the Baikal-T1 System
Boot Controller has got a very limited resources: no IRQ, no DMA, only a
single native chip-select and just 8 bytes Tx/Rx FIFOs available. That's
why we have to mark the IRQ to be optional for the later interface.

The SPI controller embedded into the Baikal-T1 System Boot Controller can
be also used to directly access an external SPI flash by means of a
dedicated FSM. The corresponding MMIO region availability is switchable by
the embedded multiplexor, which phandle can be specified in the dts node.

* We added a new example to test out the non-standard Baikal-T1 System
Boot SPI Controller DT binding.

Co-developed-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../bindings/spi/snps,dw-apb-ssi.yaml         | 33 +++++++++++++++++--
 1 file changed, 31 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
index c62cbe79f00d..d6ae35777dac 100644
--- a/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
+++ b/Documentation/devicetree/bindings/spi/snps,dw-apb-ssi.yaml
@@ -22,6 +22,21 @@ allOf:
       properties:
         reg:
           minItems: 2
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - baikal,bt1-sys-ssi
+    then:
+      properties:
+        mux-controls:
+          maxItems: 1
+      required:
+        - mux-controls
+    else:
+      required:
+        - interrupts
 
 properties:
   compatible:
@@ -44,12 +59,16 @@ properties:
           - const: snps,dw-apb-ssi
       - description: Intel Keem Bay SPI Controller
         const: intel,keembay-ssi
+      - description: Baikal-T1 SPI Controller
+        const: baikal,bt1-ssi
+      - description: Baikal-T1 System Boot SPI Controller
+        const: baikal,bt1-sys-ssi
 
   reg:
     minItems: 1
     items:
       - description: DW APB SSI controller memory mapped registers
-      - description: SPI MST region map
+      - description: SPI MST region map or directly mapped SPI ROM
 
   interrupts:
     maxItems: 1
@@ -114,7 +133,6 @@ required:
   - reg
   - "#address-cells"
   - "#size-cells"
-  - interrupts
   - clocks
 
 examples:
@@ -130,4 +148,15 @@ examples:
       cs-gpios = <&gpio0 13 0>,
                  <&gpio0 14 0>;
     };
+  - |
+    spi@1f040100 {
+      compatible = "baikal,bt1-sys-ssi";
+      reg = <0x1f040100 0x900>,
+            <0x1c000000 0x1000000>;
+      #address-cells = <1>;
+      #size-cells = <0>;
+      mux-controls = <&boot_mux>;
+      clocks = <&ccu_sys>;
+      clock-names = "ssi_clk";
+    };
 ...
-- 
2.27.0


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

* [PATCH 30/30] spi: dw: Add Baikal-T1 SPI Controller glue driver
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (28 preceding siblings ...)
  2020-09-20 11:29 ` [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers Serge Semin
@ 2020-09-20 11:41 ` Serge Semin
  2020-09-29 14:43 ` [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Mark Brown
  2020-09-29 16:23 ` Mark Brown
  31 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-20 11:41 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

Baikal-T1 is equipped with three DW APB SSI-based MMIO SPI controllers.
Two of them are pretty much normal: with IRQ, DMA, FIFOs of 64 words
depth, 4x CSs, but the third one as being a part of the Baikal-T1 System
Boot Controller has got a very limited resources: no IRQ, no DMA, only a
single native chip-select and Tx/Rx FIFO with just 8 words depth
available. In order to provide a transparent initial boot code execution
the Boot SPI controller is also utilized by an vendor-specific IP-block,
which exposes an SPI flash direct mapping interface. Since both direct
mapping and SPI controller normal utilization are mutual exclusive only
one of these interfaces can be used to access an external SPI slave
device. That's why a dedicated mux is embedded into the System Boot
Controller. All of that is taken into account in the Baikal-T1-specific DW
APB SSI glue driver implemented by means of the DW SPI core module.

Co-developed-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/spi/Kconfig      |  28 ++++
 drivers/spi/Makefile     |   1 +
 drivers/spi/spi-dw-bt1.c | 339 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 368 insertions(+)
 create mode 100644 drivers/spi/spi-dw-bt1.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 1f70bb1e7fa9..415d57b2057f 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -252,6 +252,34 @@ config SPI_DW_MMIO
 	tristate "Memory-mapped io interface driver for DW SPI core"
 	depends on HAS_IOMEM
 
+config SPI_DW_BT1
+	tristate "Baikal-T1 SPI driver for DW SPI core"
+	depends on MIPS_BAIKAL_T1 || COMPILE_TEST
+	help
+	  Baikal-T1 SoC is equipped with three DW APB SSI-based MMIO SPI
+	  controllers. Two of them are pretty much normal: with IRQ, DMA,
+	  FIFOs of 64 words depth, 4x CSs, but the third one as being a
+	  part of the Baikal-T1 System Boot Controller has got a very
+	  limited resources: no IRQ, no DMA, only a single native
+	  chip-select and Tx/Rx FIFO with just 8 words depth available.
+	  The later one is normally connected to an external SPI-nor flash
+	  of 128Mb (in general can be of bigger size).
+
+config SPI_DW_BT1_DIRMAP
+	bool "Directly mapped Baikal-T1 Boot SPI flash support"
+	depends on SPI_DW_BT1
+	select MULTIPLEXER
+	select MUX_MMIO
+	help
+	  Directly mapped SPI flash memory is an interface specific to the
+	  Baikal-T1 System Boot Controller. It is a 16MB MMIO region, which
+	  can be used to access a peripheral memory device just by
+	  reading/writing data from/to it. Note that the system APB bus
+	  will stall during each IO from/to the dirmap region until the
+	  operation is finished. So try not to use it concurrently with
+	  time-critical tasks (like the SPI memory operations implemented
+	  in this driver).
+
 endif
 
 config SPI_DLN2
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index cf955ea803cd..21dc75842aca 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_DLN2)			+= spi-dln2.o
 obj-$(CONFIG_SPI_DESIGNWARE)		+= spi-dw.o
 spi-dw-y				:= spi-dw-core.o
 spi-dw-$(CONFIG_SPI_DW_DMA)		+= spi-dw-dma.o
+obj-$(CONFIG_SPI_DW_BT1)		+= spi-dw-bt1.o
 obj-$(CONFIG_SPI_DW_MMIO)		+= spi-dw-mmio.o
 obj-$(CONFIG_SPI_DW_PCI)		+= spi-dw-pci.o
 obj-$(CONFIG_SPI_EFM32)			+= spi-efm32.o
diff --git a/drivers/spi/spi-dw-bt1.c b/drivers/spi/spi-dw-bt1.c
new file mode 100644
index 000000000000..f382dfad7842
--- /dev/null
+++ b/drivers/spi/spi-dw-bt1.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
+//
+// Authors:
+//   Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
+//   Serge Semin <Sergey.Semin@baikalelectronics.ru>
+//
+// Baikal-T1 DW APB SPI and System Boot SPI driver
+//
+
+#include <linux/clk.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mux/consumer.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/spi-mem.h>
+#include <linux/spi/spi.h>
+
+#include "spi-dw.h"
+
+#define BT1_BOOT_DIRMAP		0
+#define BT1_BOOT_REGS		1
+
+struct dw_spi_bt1 {
+	struct dw_spi		dws;
+	struct clk		*clk;
+	struct mux_control	*mux;
+
+#ifdef CONFIG_SPI_DW_BT1_DIRMAP
+	void __iomem		*map;
+	resource_size_t		map_len;
+#endif
+};
+#define to_dw_spi_bt1(_ctlr) \
+	container_of(spi_controller_get_devdata(_ctlr), struct dw_spi_bt1, dws)
+
+typedef int (*dw_spi_bt1_init_cb)(struct platform_device *pdev,
+				    struct dw_spi_bt1 *dwsbt1);
+
+#ifdef CONFIG_SPI_DW_BT1_DIRMAP
+
+static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+	struct dw_spi_bt1 *dwsbt1 = to_dw_spi_bt1(desc->mem->spi->controller);
+
+	if (!dwsbt1->map ||
+	    !dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl))
+		return -EOPNOTSUPP;
+
+	/*
+	 * Make sure the requested region doesn't go out of the physically
+	 * mapped flash memory bounds and the operation is read-only.
+	 */
+	if (desc->info.offset + desc->info.length > dwsbt1->map_len ||
+	    desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+/*
+ * Directly mapped SPI memory region is only accessible in the dword chunks.
+ * That's why we have to create a dedicated read-method to copy data from there
+ * to the passed buffer.
+ */
+static void dw_spi_bt1_dirmap_copy_from_map(void *to, void __iomem *from, size_t len)
+{
+	size_t shift, chunk;
+	u32 data;
+
+	/*
+	 * We split the copying up into the next three stages: unaligned head,
+	 * aligned body, unaligned tail.
+	 */
+	shift = (size_t)from & 0x3;
+	if (shift) {
+		chunk = min_t(size_t, 4 - shift, len);
+		data = readl_relaxed(from - shift);
+		memcpy(to, &data + shift, chunk);
+		from += chunk;
+		to += chunk;
+		len -= chunk;
+	}
+
+	while (len >= 4) {
+		data = readl_relaxed(from);
+		memcpy(to, &data, 4);
+		from += 4;
+		to += 4;
+		len -= 4;
+	}
+
+	if (len) {
+		data = readl_relaxed(from);
+		memcpy(to, &data, len);
+	}
+}
+
+static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,
+				      u64 offs, size_t len, void *buf)
+{
+	struct dw_spi_bt1 *dwsbt1 = to_dw_spi_bt1(desc->mem->spi->controller);
+	struct dw_spi *dws = &dwsbt1->dws;
+	struct spi_mem *mem = desc->mem;
+	struct dw_spi_cfg cfg;
+	int ret;
+
+	/*
+	 * Make sure the requested operation length is valid. Truncate the
+	 * length if it's greater than the length of the MMIO region.
+	 */
+	if (offs >= dwsbt1->map_len || !len)
+		return 0;
+
+	len = min_t(size_t, len, dwsbt1->map_len - offs);
+
+	/* Collect the controller configuration required by the operation */
+	cfg.tmode = SPI_TMOD_EPROMREAD;
+	cfg.dfs = 8;
+	cfg.ndf = 4;
+	cfg.freq = mem->spi->max_speed_hz;
+
+	/* Make sure the corresponding CS is de-asserted on transmission */
+	dw_spi_set_cs(mem->spi, false);
+
+	spi_enable_chip(dws, 0);
+
+	dw_spi_update_config(dws, mem->spi, &cfg);
+
+	spi_umask_intr(dws, SPI_INT_RXFI);
+
+	spi_enable_chip(dws, 1);
+
+	/*
+	 * Enable the transparent mode of the System Boot Controller.
+	 * The SPI core IO should have been locked before calling this method
+	 * so noone would be touching the controller' registers during the
+	 * dirmap operation.
+	 */
+	ret = mux_control_select(dwsbt1->mux, BT1_BOOT_DIRMAP);
+	if (ret)
+		return ret;
+
+	dw_spi_bt1_dirmap_copy_from_map(buf, dwsbt1->map + offs, len);
+
+	mux_control_deselect(dwsbt1->mux);
+
+	dw_spi_set_cs(mem->spi, true);
+
+	ret = dw_spi_check_status(dws, true);
+
+	return ret ?: len;
+}
+
+#endif /* CONFIG_SPI_DW_BT1_DIRMAP */
+
+static int dw_spi_bt1_std_init(struct platform_device *pdev,
+			       struct dw_spi_bt1 *dwsbt1)
+{
+	struct dw_spi *dws = &dwsbt1->dws;
+
+	dws->irq = platform_get_irq(pdev, 0);
+	if (dws->irq < 0)
+		return dws->irq;
+
+	dws->num_cs = 4;
+
+	/*
+	 * Baikal-T1 Normal SPI Controllers don't always keep up with full SPI
+	 * bus speed especially when it comes to the concurrent access to the
+	 * APB bus resources. Thus we have no choice but to set a constraint on
+	 * the SPI bus frequency for the memory operations which require to
+	 * read/write data as fast as possible.
+	 */
+	dws->max_mem_freq = 20000000U;
+
+	dw_spi_dma_setup_generic(dws);
+
+	return 0;
+}
+
+static int dw_spi_bt1_sys_init(struct platform_device *pdev,
+			       struct dw_spi_bt1 *dwsbt1)
+{
+	struct resource *mem __maybe_unused;
+	struct dw_spi *dws = &dwsbt1->dws;
+
+	/*
+	 * Baikal-T1 System Boot Controller is equipped with a mux, which
+	 * switches between the directly mapped SPI flash access mode and
+	 * IO access to the DW APB SSI registers. Note the mux controller
+	 * must be setup to preserve the registers being accessible by default
+	 * (on idle-state).
+	 */
+	dwsbt1->mux = devm_mux_control_get(&pdev->dev, NULL);
+	if (IS_ERR(dwsbt1->mux))
+		return PTR_ERR(dwsbt1->mux);
+
+	/*
+	 * Directly mapped SPI flash memory is a 16MB MMIO region, which can be
+	 * used to access a peripheral memory device just by reading/writing
+	 * data from/to it. Note the system APB bus will stall during each IO
+	 * from/to the dirmap region until the operation is finished. So don't
+	 * use it concurrently with time-critical tasks (like the SPI memory
+	 * operations implemented in the DW APB SSI driver).
+	 */
+#ifdef CONFIG_SPI_DW_BT1_DIRMAP
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (mem) {
+		dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem);
+		if (!IS_ERR(dwsbt1->map)) {
+			dwsbt1->map_len = (mem->end - mem->start + 1);
+			dws->mem_ops.dirmap_create = dw_spi_bt1_dirmap_create;
+			dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;
+		} else {
+			dwsbt1->map = NULL;
+		}
+	}
+#endif /* CONFIG_SPI_DW_BT1_DIRMAP */
+
+	/*
+	 * There is no IRQ, no DMA and just one CS available on the System Boot
+	 * SPI controller.
+	 */
+	dws->irq = IRQ_NOTCONNECTED;
+	dws->num_cs = 1;
+
+	/*
+	 * Baikal-T1 System Boot SPI Controller doesn't keep up with the full
+	 * SPI bus speed due to relatively slow APB bus and races for it'
+	 * resources from different CPUs. The situation is worsen by a small
+	 * FIFOs depth (just 8 words). It works better in a single CPU mode
+	 * though, but still tends to be not fast enough at low CPU
+	 * frequencies.
+	 */
+	if (num_possible_cpus() > 1)
+		dws->max_mem_freq = 10000000U;
+	else
+		dws->max_mem_freq = 20000000U;
+
+	return 0;
+}
+
+static int dw_spi_bt1_probe(struct platform_device *pdev)
+{
+	dw_spi_bt1_init_cb init_func;
+	struct dw_spi_bt1 *dwsbt1;
+	struct resource *mem;
+	struct dw_spi *dws;
+	int ret;
+
+	dwsbt1 = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_bt1), GFP_KERNEL);
+	if (!dwsbt1)
+		return -ENOMEM;
+
+	dws = &dwsbt1->dws;
+
+	dws->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
+	if (IS_ERR(dws->regs))
+		return PTR_ERR(dws->regs);
+
+	dws->paddr = mem->start;
+
+	dwsbt1->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(dwsbt1->clk))
+		return PTR_ERR(dwsbt1->clk);
+
+	ret = clk_prepare_enable(dwsbt1->clk);
+	if (ret)
+		return ret;
+
+	dws->bus_num = pdev->id;
+	dws->reg_io_width = 4;
+	dws->max_freq = clk_get_rate(dwsbt1->clk);
+	if (!dws->max_freq)
+		goto err_disable_clk;
+
+	init_func = device_get_match_data(&pdev->dev);
+	ret = init_func(pdev, dwsbt1);
+	if (ret)
+		goto err_disable_clk;
+
+	pm_runtime_enable(&pdev->dev);
+
+	ret = dw_spi_add_host(&pdev->dev, dws);
+	if (ret)
+		goto err_disable_clk;
+
+	platform_set_drvdata(pdev, dwsbt1);
+
+	return 0;
+
+err_disable_clk:
+	clk_disable_unprepare(dwsbt1->clk);
+
+	return ret;
+}
+
+static int dw_spi_bt1_remove(struct platform_device *pdev)
+{
+	struct dw_spi_bt1 *dwsbt1 = platform_get_drvdata(pdev);
+
+	dw_spi_remove_host(&dwsbt1->dws);
+
+	pm_runtime_disable(&pdev->dev);
+
+	clk_disable_unprepare(dwsbt1->clk);
+
+	return 0;
+}
+
+static const struct of_device_id dw_spi_bt1_of_match[] = {
+	{ .compatible = "baikal,bt1-ssi", .data = dw_spi_bt1_std_init},
+	{ .compatible = "baikal,bt1-sys-ssi", .data = dw_spi_bt1_sys_init},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match);
+
+static struct platform_driver dw_spi_bt1_driver = {
+	.probe	= dw_spi_bt1_probe,
+	.remove	= dw_spi_bt1_remove,
+	.driver	= {
+		.name		= "bt1-sys-ssi",
+		.of_match_table	= dw_spi_bt1_of_match,
+	},
+};
+module_platform_driver(dw_spi_bt1_driver);
+
+MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");
+MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");
+MODULE_LICENSE("GPL v2");
-- 
2.27.0


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

* Re: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-20 11:28 ` [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback Serge Semin
@ 2020-09-29 13:11   ` Mark Brown
  2020-09-29 21:55     ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-29 13:11 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 450 bytes --]

On Sun, Sep 20, 2020 at 02:28:46PM +0300, Serge Semin wrote:
> Simplify the dw_spi_add_host() method a bit by replacing the set_cs
> callback overwrite procedure with direct setting the callback if a custom
> version of one is specified.

> -	master->set_cs = dw_spi_set_cs;
> +	master->set_cs = dws->set_cs ?: dw_spi_set_cs;

> -	if (dws->set_cs)
> -		master->set_cs = dws->set_cs;

This doesn't look like a win for legibility or comprehensibility.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier
  2020-09-20 11:28 ` [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier Serge Semin
@ 2020-09-29 13:12   ` Mark Brown
  2020-09-29 22:05     ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-29 13:12 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 299 bytes --]

On Sun, Sep 20, 2020 at 02:28:47PM +0300, Serge Semin wrote:
> Since n_bytes field of the DW SPI private data is also utilized by the
> IRQ handler, we need to make sure it' initialization is done before the
> memory barrier.

This looks like a fix so should have been before any cosmetic cleanups.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
  2020-09-20 11:28 ` [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls Serge Semin
@ 2020-09-29 13:28   ` Mark Brown
  2020-09-29 22:08     ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-29 13:28 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 605 bytes --]

On Sun, Sep 20, 2020 at 02:28:48PM +0300, Serge Semin wrote:
> There is no point in having the commit 19b61392c5a8 ("spi: spi-dw: Add
> lock protect dw_spi rx/tx to prevent concurrent calls") applied. The
> commit author made an assumption that the problem with the rx data

Please submit patches using subject lines reflecting the style for the
subsystem, this makes it easier for people to identify relevant patches.
Look at what existing commits in the area you're changing are doing and
make sure your subject lines visually resemble what they're doing.
There's no need to resubmit to fix this alone.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-20 11:28 ` [PATCH 11/30] spi: dw: Add DWC SSI capability Serge Semin
@ 2020-09-29 13:52   ` Mark Brown
  2020-09-29 22:17     ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-29 13:52 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 607 bytes --]

On Sun, Sep 20, 2020 at 02:28:55PM +0300, Serge Semin wrote:

> -	/*
> -	 * SPI mode (SCPOL|SCPH)
> -	 * CTRLR0[ 8] Serial Clock Phase
> -	 * CTRLR0[ 9] Serial Clock Polarity
> -	 */
> -	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> -	cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;

> +		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
> +		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> +		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;

The new code seems less well commented than the old code here.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (29 preceding siblings ...)
  2020-09-20 11:41 ` [PATCH 30/30] spi: dw: Add Baikal-T1 SPI Controller glue driver Serge Semin
@ 2020-09-29 14:43 ` Mark Brown
  2020-09-29 22:43   ` Serge Semin
  2020-09-29 16:23 ` Mark Brown
  31 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-29 14:43 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1110 bytes --]

On Sun, Sep 20, 2020 at 02:28:44PM +0300, Serge Semin wrote:

> First two patches are just cleanups to simplify the DW APB SSI device
> initialization a bit. We suggest to discard the IRQ threshold macro as
> unused and use a ternary operator to initialize the set_cs callback
> instead of assigning-and-updating it.

> Then we've discovered that the n_bytes field of the driver private data is
> used by the DW APB SSI IRQ handler, which requires it to be initialized

This is a *huge* patch series which is a bit unweildy to review
(especially given the other 10+ patch series you sent at the same time),
once you start getting over 10 patches it's time to pay attention to
series length and the fact that you're outlining a bunch of tangentially
related areas which could have been split out easily enough.  It is much
better to send smaller sets of patches at once, or if you're sending a
lot then to split them into smaller serieses.  This will tend to make
the review more approachable which will in turn tend to make things go
faster, people are much more likely to put off going through a huge
series.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
                   ` (30 preceding siblings ...)
  2020-09-29 14:43 ` [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Mark Brown
@ 2020-09-29 16:23 ` Mark Brown
  31 siblings, 0 replies; 52+ messages in thread
From: Mark Brown @ 2020-09-29 16:23 UTC (permalink / raw)
  To: Serge Semin
  Cc: Pavel Parkhomenko, Ramil Zaripov, Feng Tang, Andy Shevchenko,
	Alexey Malahov, Andy Shevchenko, linux-kernel, linux-spi,
	Rob Herring, Lars Povlsen, devicetree, Serge Semin, wuxu . wu

On Sun, 20 Sep 2020 14:28:44 +0300, Serge Semin wrote:
> Originally I intended to merge a dedicated Baikal-T1 System Boot SPI
> Controller driver into the kernel and leave the DW APB SSI driver
> untouched. But after a long discussion (see the link at the bottom of the
> letter) Mark and Andy persuaded me to integrate what we developed there
> into the DW APB SSI core driver to be useful for another controllers,
> which may have got the same peculiarities/problems as ours:
> - No IRQ.
> - No DMA.
> - No GPIO CS, so a native CS is utilized.
> - small Tx/Rx FIFO depth.
> - Automatic CS assertion/de-assertion.
> - Slow system bus.
> All of them have been fixed in the framework of this patchset in some
> extent at least for the SPI memory operations. As I expected it wasn't
> that easy and the integration took that many patches as you can see from
> the subject. Though some of them are mere cleanups or weakly related with
> the subject fixes, but we just couldn't leave the code as is at some
> places since we were working with the DW APB SSI driver anyway. Here is
> what we did to fix the original DW APB SSI driver, to make it less messy.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-next

Thanks!

[1/9] spi: dw: Discard IRQ threshold macro
      commit: 07918df724f2fed02327e3cbfe58a5d5568b2cc2
[2/9] spi: dw: Initialize n_bytes before the memory barrier
      commit: 8225c1c9a073c323f68833d136fcf94fbc75a275
[3/9] spi: spi-dw: Remove extraneous locking
      commit: 0b6bfad4cee4a3d5c49e01fa00284db4b676360e
[4/9] spi: dw: Clear IRQ status on DW SPI controller reset
      commit: a128f6ecd56a32e559889145003425b0c7d406e3
[5/9] spi: dw: Disable all IRQs when controller is unused
      commit: a1d5aa6f7f97b15e8fd917169239088823471741
[6/9] spi: dw: Use relaxed IO-methods to access FIFOs
      commit: 7e31cea7d1e0f4b683dc45c21530cd3ee82559b4
[7/9] spi: dw: Discard DW SSI chip type storages
      commit: 675e7c9d71cedee3988b554c47971be77e72d2db
[8/9] spi: dw: Convert CS-override to DW SPI capabilities
      commit: cc760f3143f53ea8387cd76cffc43bdc89db9df4
[9/9] spi: dw: Add KeemBay Master capability
      commit: ffb7ca54c95b4c76ad8a9aa1b2b16d61df2a7139

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

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

* Re: [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers
  2020-09-20 11:29 ` [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers Serge Semin
@ 2020-09-29 16:58   ` Rob Herring
  0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring @ 2020-09-29 16:58 UTC (permalink / raw)
  To: Serge Semin
  Cc: Lars Povlsen, Alexey Malahov, wuxu . wu, Rob Herring,
	Andy Shevchenko, Serge Semin, devicetree, Ramil Zaripov,
	linux-spi, Feng Tang, Pavel Parkhomenko, Mark Brown,
	linux-kernel, Andy Shevchenko

On Sun, 20 Sep 2020 14:29:13 +0300, Serge Semin wrote:
> These controllers are based on the DW APB SSI IP-core and embedded into
> the SoC, so two of them are equipped with IRQ, DMA, 64 words FIFOs and 4
> native CS, while another one as being utilized by the Baikal-T1 System
> Boot Controller has got a very limited resources: no IRQ, no DMA, only a
> single native chip-select and just 8 bytes Tx/Rx FIFOs available. That's
> why we have to mark the IRQ to be optional for the later interface.
> 
> The SPI controller embedded into the Baikal-T1 System Boot Controller can
> be also used to directly access an external SPI flash by means of a
> dedicated FSM. The corresponding MMIO region availability is switchable by
> the embedded multiplexor, which phandle can be specified in the dts node.
> 
> * We added a new example to test out the non-standard Baikal-T1 System
> Boot SPI Controller DT binding.
> 
> Co-developed-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Signed-off-by: Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../bindings/spi/snps,dw-apb-ssi.yaml         | 33 +++++++++++++++++--
>  1 file changed, 31 insertions(+), 2 deletions(-)
> 

Reviewed-by: Rob Herring <robh@kernel.org>

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

* Re: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-29 13:11   ` Mark Brown
@ 2020-09-29 21:55     ` Serge Semin
  2020-09-30 14:57       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-29 21:55 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Tue, Sep 29, 2020 at 02:11:53PM +0100, Mark Brown wrote:
> On Sun, Sep 20, 2020 at 02:28:46PM +0300, Serge Semin wrote:
> > Simplify the dw_spi_add_host() method a bit by replacing the set_cs
> > callback overwrite procedure with direct setting the callback if a custom
> > version of one is specified.
> 
> > -	master->set_cs = dw_spi_set_cs;
> > +	master->set_cs = dws->set_cs ?: dw_spi_set_cs;
> 
> > -	if (dws->set_cs)
> > -		master->set_cs = dws->set_cs;
> 

> This doesn't look like a win for legibility or comprehensibility.

Assigning a default value and redefining it way later doesn't look legible
either, because in that case you'd need to keep in mind, that some callback has
already been set. Moreover it does one redundant assignment. That's why I
decided to implement the setting up by means of the ternary op.

If you don't like the ternary op, then we could use an explicit if-else
statement here. But I'd insist on implementing the assignment in a one
place of the function instead of having it partly perform here and partly there.
Like this:

--- a/drivers/spi/spi-dw-core.c
+++ b/drivers/spi/spi-dw-core.c
@@ -477,7 +477,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
 	master->num_chipselect = dws->num_cs;
 	master->setup = dw_spi_setup;
 	master->cleanup = dw_spi_cleanup;
-	master->set_cs = dw_spi_set_cs;
+	if (dws->set_cs)
+		master->set_cs = dws->set_cs;
+	else
+		master->set_cs = dw_spi_set_cs;
 	master->transfer_one = dw_spi_transfer_one;
 	master->handle_err = dw_spi_handle_err;
 	master->max_speed_hz = dws->max_freq;

Personally I prefer the ternary op in such situations. The operator provides an
elegant small well known solution for the default-assignments. I don't see it
as non-legible or incomprehensible. (I don't really understand why you and
Andy don't like the operator that much =))

-Sergey

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

* Re: [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier
  2020-09-29 13:12   ` Mark Brown
@ 2020-09-29 22:05     ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-29 22:05 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Tue, Sep 29, 2020 at 02:12:25PM +0100, Mark Brown wrote:
> On Sun, Sep 20, 2020 at 02:28:47PM +0300, Serge Semin wrote:
> > Since n_bytes field of the DW SPI private data is also utilized by the
> > IRQ handler, we need to make sure it' initialization is done before the
> > memory barrier.
> 

> This looks like a fix so should have been before any cosmetic cleanups.

Ah, sorry about that. I had that in mind, but have just forgotten to move it
to the series head.

-Sergey

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

* Re: [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls
  2020-09-29 13:28   ` Mark Brown
@ 2020-09-29 22:08     ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-29 22:08 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Tue, Sep 29, 2020 at 02:28:11PM +0100, Mark Brown wrote:
> On Sun, Sep 20, 2020 at 02:28:48PM +0300, Serge Semin wrote:
> > There is no point in having the commit 19b61392c5a8 ("spi: spi-dw: Add
> > lock protect dw_spi rx/tx to prevent concurrent calls") applied. The
> > commit author made an assumption that the problem with the rx data
> 

> Please submit patches using subject lines reflecting the style for the
> subsystem, this makes it easier for people to identify relevant patches.
> Look at what existing commits in the area you're changing are doing and
> make sure your subject lines visually resemble what they're doing.
> There's no need to resubmit to fix this alone.

Ok. Thank you for pointing that out. I'll do like you said next time on a
patch reversion.

-Sergey

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

* Re: [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-29 13:52   ` Mark Brown
@ 2020-09-29 22:17     ` Serge Semin
  2020-09-30 15:03       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-29 22:17 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Tue, Sep 29, 2020 at 02:52:33PM +0100, Mark Brown wrote:
> On Sun, Sep 20, 2020 at 02:28:55PM +0300, Serge Semin wrote:
> 
> > -	/*
> > -	 * SPI mode (SCPOL|SCPH)
> > -	 * CTRLR0[ 8] Serial Clock Phase
> > -	 * CTRLR0[ 9] Serial Clock Polarity
> > -	 */
> > -	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> > -	cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
> 

> > +		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
> > +		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> > +		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
> 
> The new code seems less well commented than the old code here.

You are right. The comments are omitted. The thing is that they are absolutely
redundant here, for the same reason they haven't been added to the standard
update_cr0() method. Both the DWC SSI-capable and standard DW APB SSI-specific
part of the code do the same thing: setup the CTRLR0 fields, which are described
by the macro definitions. So there is no need to duplicate that information in
the comments, moreover seeing it can be inferred from the code.

-Sergey

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-29 14:43 ` [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Mark Brown
@ 2020-09-29 22:43   ` Serge Semin
  2020-09-30 11:04     ` Mark Brown
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-29 22:43 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

Hi Mark

On Tue, Sep 29, 2020 at 03:43:51PM +0100, Mark Brown wrote:
> On Sun, Sep 20, 2020 at 02:28:44PM +0300, Serge Semin wrote:
> 
> > First two patches are just cleanups to simplify the DW APB SSI device
> > initialization a bit. We suggest to discard the IRQ threshold macro as
> > unused and use a ternary operator to initialize the set_cs callback
> > instead of assigning-and-updating it.
> 
> > Then we've discovered that the n_bytes field of the driver private data is
> > used by the DW APB SSI IRQ handler, which requires it to be initialized
> 

> This is a *huge* patch series which is a bit unweildy to review
> (especially given the other 10+ patch series you sent at the same time),

Yeah, sorry about the bulky series. If most of the changes have been more
complicated than that, less inter-dependent and less directed to having the code
prepared for the main alterations I would have definitely split them up in
different series. But the biggest part of the patchset is just a preparation
before adding the mem-ops, poll-based transfers and Baikal-T1 SPI support. So
having them submitted without the main part of the patchset would be just weird.

The other 10+ patches were sent months ago. I've just resent them with minor
alterations to get more attention.) Anyway since they concern an absolutely
different functionality (DW APB SSI DMA driver) of course I've delivered them in
the framework of the different patchset.

> once you start getting over 10 patches it's time to pay attention to
> series length and the fact that you're outlining a bunch of tangentially
> related areas which could have been split out easily enough.  It is much
> better to send smaller sets of patches at once, or if you're sending a
> lot then to split them into smaller serieses.  This will tend to make
> the review more approachable which will in turn tend to make things go
> faster, people are much more likely to put off going through a huge
> series.

I see you have already merged in the first nine patches. So would you like me
to split the rest of them up into two series or it would be ok to resend (if
required) them as one series seeing it's not that bulky anymore?

-Sergey

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-29 22:43   ` Serge Semin
@ 2020-09-30 11:04     ` Mark Brown
  2020-09-30 13:11       ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-30 11:04 UTC (permalink / raw)
  To: Serge Semin
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1546 bytes --]

On Wed, Sep 30, 2020 at 01:43:03AM +0300, Serge Semin wrote:
> On Tue, Sep 29, 2020 at 03:43:51PM +0100, Mark Brown wrote:

> > This is a *huge* patch series which is a bit unweildy to review
> > (especially given the other 10+ patch series you sent at the same time),

> Yeah, sorry about the bulky series. If most of the changes have been more
> complicated than that, less inter-dependent and less directed to having the code
> prepared for the main alterations I would have definitely split them up in
> different series. But the biggest part of the patchset is just a preparation
> before adding the mem-ops, poll-based transfers and Baikal-T1 SPI support. So
> having them submitted without the main part of the patchset would be just weird.

One option with things like this is to just not send everything at once
- even when split into multiple series it's a huge bulk of patches in an
inbox.  Unless the patches are obviously from their subjects repetitive
people probably aren't getting far enough in to look at the actual
patches or even their sizes before deciding it looks like a lot of work
and putting things off for later.

> I see you have already merged in the first nine patches. So would you like me
> to split the rest of them up into two series or it would be ok to resend (if
> required) them as one series seeing it's not that bulky anymore?

Not all of the first 9, IIRC I skipped one I had comments on.  If they
can be split that would probably be helpful, if there are dependencies
then it's not going to buy too much.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-30 11:04     ` Mark Brown
@ 2020-09-30 13:11       ` Serge Semin
  2020-09-30 14:43         ` Mark Brown
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-30 13:11 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Wed, Sep 30, 2020 at 12:04:04PM +0100, Mark Brown wrote:
> On Wed, Sep 30, 2020 at 01:43:03AM +0300, Serge Semin wrote:
> > On Tue, Sep 29, 2020 at 03:43:51PM +0100, Mark Brown wrote:
> 
> > > This is a *huge* patch series which is a bit unweildy to review
> > > (especially given the other 10+ patch series you sent at the same time),
> 
> > Yeah, sorry about the bulky series. If most of the changes have been more
> > complicated than that, less inter-dependent and less directed to having the code
> > prepared for the main alterations I would have definitely split them up in
> > different series. But the biggest part of the patchset is just a preparation
> > before adding the mem-ops, poll-based transfers and Baikal-T1 SPI support. So
> > having them submitted without the main part of the patchset would be just weird.
> 
> One option with things like this is to just not send everything at once
> - even when split into multiple series it's a huge bulk of patches in an
> inbox.  Unless the patches are obviously from their subjects repetitive
> people probably aren't getting far enough in to look at the actual
> patches or even their sizes before deciding it looks like a lot of work
> and putting things off for later.
> 
> > I see you have already merged in the first nine patches. So would you like me
> > to split the rest of them up into two series or it would be ok to resend (if
> > required) them as one series seeing it's not that bulky anymore?
> 

> Not all of the first 9, IIRC I skipped one I had comments on.

Yes, you skipped one and I've already given you my response on your comment
about it: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
So have I responded to your comment on another patch:
[PATCH 11/30] spi: dw: Add DWC SSI capability .

I will need a response from you about them to go further with this patchset.

> If they
> can be split that would probably be helpful, if there are dependencies
> then it's not going to buy too much.

Well, all later patches depend on the changes introduced in the previous ones in
one way or another. So in any case that will be an incremental series of patchsets
otherwise they most likely won't get applied cleanly on the driver source code.
For now we have got 21 patch left to review:
I) First two ones you've given your comments on and are mostly related to the
patches you have already merged in.
1. 688c17cad5c2 spi: dw: Use ternary op to init set_cs callback
2. 17d0b3abc03d spi: dw: Add DWC SSI capability

II) Refactor the DW APB SSI controller config procedure.
3. 6a436c824961 spi: dw: Detach SPI device specific CR0 config method
4. 47614d60e44c spi: dw: Update SPI bus speed in a config function
5. df64a4961801 spi: dw: Simplify the SPI bus speed config procedure
6. 1a583b130bab spi: dw: Update Rx sample delay in the config function
7. 9f205a8939a2 spi: dw: Add DW SPI controller config structure

III) Refactor IRQ-based SPI transfer procedure.
8. d4fa973a3f7c spi: dw: Refactor data IO procedure
9. d998b98e3d93 spi: dw: Refactor IRQ-based SPI transfer procedure
10. 7fc419af6e67 spi: dw: Perform IRQ setup in a dedicated function
11. d3dfd997379a spi: dw: Unmask IRQs after enabling the chip
12. 6ecf589320f3 spi: dw: Discard chip enabling on DMA setup error

IV) Final preparation before adding the memory operations.
13. 84a03fad452c spi: dw: De-assert chip-select on reset
14. dd0212eb5738 spi: dw: Explicitly de-assert CS on SPI transfer completion
15. d1eea0f556cf spi: dw: Move num-of retries parameter to the header file
16. 3e70e5a6c1d9 spi: dw: Add generic DW SSI status-check method

v) Introduce memory and poll-based operations.
17. 52d733f30464 spi: dw: Add memory operations support
18. c2f45eb3d662 spi: dw: Introduce max mem-ops SPI bus frequency setting
19. ccf08869b6bd spi: dw: Add poll-based SPI transfers support

vI) Add Baikal-T1 glue-driver
20. a536c408f7aa dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers
21. 791e68755ead spi: dw: Add Baikal-T1 SPI Controller glue driver

If you want I can resend the series split up as I described above. Alternatively
I can collect I) - III) into a one patchset and IV) - VI) into another one.
So to speak I'll do in whatever scenario you prefer. Just tell me which one is
more suitable for you to review.

In anyway we need to settle the issues regarding the first two patches. Please give
me your answers on the comments I've left there in response to your comments.)

-Sergey

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

* Re: [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support
  2020-09-30 13:11       ` Serge Semin
@ 2020-09-30 14:43         ` Mark Brown
  0 siblings, 0 replies; 52+ messages in thread
From: Mark Brown @ 2020-09-30 14:43 UTC (permalink / raw)
  To: Serge Semin
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 584 bytes --]

On Wed, Sep 30, 2020 at 04:11:15PM +0300, Serge Semin wrote:
> On Wed, Sep 30, 2020 at 12:04:04PM +0100, Mark Brown wrote:

> > Not all of the first 9, IIRC I skipped one I had comments on.

> Yes, you skipped one and I've already given you my response on your comment
> about it: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
> So have I responded to your comment on another patch:
> [PATCH 11/30] spi: dw: Add DWC SSI capability .

> I will need a response from you about them to go further with this patchset.

I'm not sure I saw any concrete questions with those?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-29 21:55     ` Serge Semin
@ 2020-09-30 14:57       ` Serge Semin
  2020-09-30 15:01         ` Mark Brown
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-30 14:57 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

Mark,
A concrete question is below the main text.)

On Wed, Sep 30, 2020 at 12:55:55AM +0300, Serge Semin wrote:
> On Tue, Sep 29, 2020 at 02:11:53PM +0100, Mark Brown wrote:
> > On Sun, Sep 20, 2020 at 02:28:46PM +0300, Serge Semin wrote:
> > > Simplify the dw_spi_add_host() method a bit by replacing the set_cs
> > > callback overwrite procedure with direct setting the callback if a custom
> > > version of one is specified.
> > 
> > > -	master->set_cs = dw_spi_set_cs;
> > > +	master->set_cs = dws->set_cs ?: dw_spi_set_cs;
> > 
> > > -	if (dws->set_cs)
> > > -		master->set_cs = dws->set_cs;
> > 
> 

> > This doesn't look like a win for legibility or comprehensibility.
> 
> Assigning a default value and redefining it way later doesn't look legible
> either, because in that case you'd need to keep in mind, that some callback has
> already been set. Moreover it does one redundant assignment. That's why I
> decided to implement the setting up by means of the ternary op.
> 
> If you don't like the ternary op, then we could use an explicit if-else
> statement here. But I'd insist on implementing the assignment in a one
> place of the function instead of having it partly perform here and partly there.
> Like this:
> 
> --- a/drivers/spi/spi-dw-core.c
> +++ b/drivers/spi/spi-dw-core.c
> @@ -477,7 +477,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
>  	master->num_chipselect = dws->num_cs;
>  	master->setup = dw_spi_setup;
>  	master->cleanup = dw_spi_cleanup;
> -	master->set_cs = dw_spi_set_cs;
> +	if (dws->set_cs)
> +		master->set_cs = dws->set_cs;
> +	else
> +		master->set_cs = dw_spi_set_cs;
>  	master->transfer_one = dw_spi_transfer_one;
>  	master->handle_err = dw_spi_handle_err;
>  	master->max_speed_hz = dws->max_freq;
> 
> Personally I prefer the ternary op in such situations. The operator provides an
> elegant small well known solution for the default-assignments. I don't see it
> as non-legible or incomprehensible. (I don't really understand why you and
> Andy don't like the operator that much =))
> 
> -Sergey

Judging by having your comment on this patch you obviously didn't like the
ternary operator used to assign a default value to the set_cs callback. So I
suggested a solution, which may suit you. What do you think about it? Agree,
disagree, insist on leaving this part of the code along, etc.

-Sergey

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

* Re: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-30 14:57       ` Serge Semin
@ 2020-09-30 15:01         ` Mark Brown
  2020-09-30 15:07           ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-30 15:01 UTC (permalink / raw)
  To: Serge Semin
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 553 bytes --]

On Wed, Sep 30, 2020 at 05:57:59PM +0300, Serge Semin wrote:
> On Wed, Sep 30, 2020 at 12:55:55AM +0300, Serge Semin wrote:

> > +	if (dws->set_cs)
> > +		master->set_cs = dws->set_cs;
> > +	else
> > +		master->set_cs = dw_spi_set_cs;

> Judging by having your comment on this patch you obviously didn't like the
> ternary operator used to assign a default value to the set_cs callback. So I
> suggested a solution, which may suit you. What do you think about it? Agree,
> disagree, insist on leaving this part of the code along, etc.

That looks fine.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-29 22:17     ` Serge Semin
@ 2020-09-30 15:03       ` Serge Semin
  2020-09-30 15:41         ` Mark Brown
  0 siblings, 1 reply; 52+ messages in thread
From: Serge Semin @ 2020-09-30 15:03 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

Mark,
A concrete question is below of my previous comment.

On Wed, Sep 30, 2020 at 01:17:37AM +0300, Serge Semin wrote:
> On Tue, Sep 29, 2020 at 02:52:33PM +0100, Mark Brown wrote:
> > On Sun, Sep 20, 2020 at 02:28:55PM +0300, Serge Semin wrote:
> > 
> > > -	/*
> > > -	 * SPI mode (SCPOL|SCPH)
> > > -	 * CTRLR0[ 8] Serial Clock Phase
> > > -	 * CTRLR0[ 9] Serial Clock Polarity
> > > -	 */
> > > -	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> > > -	cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
> > 
> 
> > > +		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
> > > +		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> > > +		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
> > 
> > The new code seems less well commented than the old code here.
> 
> You are right. The comments are omitted. The thing is that they are absolutely
> redundant here, for the same reason they haven't been added to the standard
> update_cr0() method. Both the DWC SSI-capable and standard DW APB SSI-specific
> part of the code do the same thing: setup the CTRLR0 fields, which are described
> by the macro definitions. So there is no need to duplicate that information in
> the comments, moreover seeing it can be inferred from the code.
> 
> -Sergey

My response to your comment was that those in-code comments have been absolutely
redundant. So I just removed them, since I was touching that part of the driver
anyway. If you are agree with me having that done here, then please, accept the
patch the way it is. If you disagree, or have any other though, please give me
your answer, why.

-Sergey

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

* Re: [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback
  2020-09-30 15:01         ` Mark Brown
@ 2020-09-30 15:07           ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-30 15:07 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Wed, Sep 30, 2020 at 04:01:17PM +0100, Mark Brown wrote:
> On Wed, Sep 30, 2020 at 05:57:59PM +0300, Serge Semin wrote:
> > On Wed, Sep 30, 2020 at 12:55:55AM +0300, Serge Semin wrote:
> 
> > > +	if (dws->set_cs)
> > > +		master->set_cs = dws->set_cs;
> > > +	else
> > > +		master->set_cs = dw_spi_set_cs;
> 

> > Judging by having your comment on this patch you obviously didn't like the
> > ternary operator used to assign a default value to the set_cs callback. So I
> > suggested a solution, which may suit you. What do you think about it? Agree,
> > disagree, insist on leaving this part of the code along, etc.
> 
> That looks fine.

Ok. I'll implement it in the next patchset version.

-Sergey

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

* Re: [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-30 15:03       ` Serge Semin
@ 2020-09-30 15:41         ` Mark Brown
  2020-09-30 15:53           ` Serge Semin
  0 siblings, 1 reply; 52+ messages in thread
From: Mark Brown @ 2020-09-30 15:41 UTC (permalink / raw)
  To: Serge Semin
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 665 bytes --]

On Wed, Sep 30, 2020 at 06:03:12PM +0300, Serge Semin wrote:
> On Wed, Sep 30, 2020 at 01:17:37AM +0300, Serge Semin wrote:

> > > > -	/*
> > > > -	 * SPI mode (SCPOL|SCPH)
> > > > -	 * CTRLR0[ 8] Serial Clock Phase
> > > > -	 * CTRLR0[ 9] Serial Clock Polarity
> > > > -	 */
> > > > -	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;

> anyway. If you are agree with me having that done here, then please, accept the
> patch the way it is. If you disagree, or have any other though, please give me
> your answer, why.

Those comments did seem to help mitigate the wall of acronym soup issue
that the code has, it seems a shame to drop them.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

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

* Re: [PATCH 11/30] spi: dw: Add DWC SSI capability
  2020-09-30 15:41         ` Mark Brown
@ 2020-09-30 15:53           ` Serge Semin
  0 siblings, 0 replies; 52+ messages in thread
From: Serge Semin @ 2020-09-30 15:53 UTC (permalink / raw)
  To: Mark Brown
  Cc: Alexey Malahov, Ramil Zaripov, Pavel Parkhomenko,
	Andy Shevchenko, Andy Shevchenko, Lars Povlsen, wuxu . wu,
	Feng Tang, Rob Herring, linux-spi, devicetree, linux-kernel

On Wed, Sep 30, 2020 at 04:41:49PM +0100, Mark Brown wrote:
> On Wed, Sep 30, 2020 at 06:03:12PM +0300, Serge Semin wrote:
> > On Wed, Sep 30, 2020 at 01:17:37AM +0300, Serge Semin wrote:
> 
> > > > > -	/*
> > > > > -	 * SPI mode (SCPOL|SCPH)
> > > > > -	 * CTRLR0[ 8] Serial Clock Phase
> > > > > -	 * CTRLR0[ 9] Serial Clock Polarity
> > > > > -	 */
> > > > > -	cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
> 
> > anyway. If you are agree with me having that done here, then please, accept the
> > patch the way it is. If you disagree, or have any other though, please give me
> > your answer, why.
> 
> Those comments did seem to help mitigate the wall of acronym soup issue
> that the code has, it seems a shame to drop them.

I see your point, but still don't think that those comment give much help like you
said, because the mode->register mapping can be easily derived from the macro
naming and values.

Anyway since you insist on having the comments left here, I'll get them back and
add the similar ones for the standard DW-APB-SSI version of the controller so
the code would look coherent.

-Sergey

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

end of thread, other threads:[~2020-09-30 15:54 UTC | newest]

Thread overview: 52+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-20 11:28 [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Serge Semin
2020-09-20 11:28 ` [PATCH 01/30] spi: dw: Discard IRQ threshold macro Serge Semin
2020-09-20 11:28 ` [PATCH 02/30] spi: dw: Use ternary op to init set_cs callback Serge Semin
2020-09-29 13:11   ` Mark Brown
2020-09-29 21:55     ` Serge Semin
2020-09-30 14:57       ` Serge Semin
2020-09-30 15:01         ` Mark Brown
2020-09-30 15:07           ` Serge Semin
2020-09-20 11:28 ` [PATCH 03/30] spi: dw: Initialize n_bytes before the memory barrier Serge Semin
2020-09-29 13:12   ` Mark Brown
2020-09-29 22:05     ` Serge Semin
2020-09-20 11:28 ` [PATCH 04/30] Revert: spi: spi-dw: Add lock protect dw_spi rx/tx to prevent concurrent calls Serge Semin
2020-09-29 13:28   ` Mark Brown
2020-09-29 22:08     ` Serge Semin
2020-09-20 11:28 ` [PATCH 05/30] spi: dw: Clear IRQ status on DW SPI controller reset Serge Semin
2020-09-20 11:28 ` [PATCH 06/30] spi: dw: Disable all IRQs when controller is unused Serge Semin
2020-09-20 11:28 ` [PATCH 07/30] spi: dw: Use relaxed IO-methods to access FIFOs Serge Semin
2020-09-20 11:28 ` [PATCH 08/30] spi: dw: Discard DW SSI chip type storages Serge Semin
2020-09-20 11:28 ` [PATCH 09/30] spi: dw: Convert CS-override to DW SPI capabilities Serge Semin
2020-09-20 11:28 ` [PATCH 10/30] spi: dw: Add KeemBay Master capability Serge Semin
2020-09-20 11:28 ` [PATCH 11/30] spi: dw: Add DWC SSI capability Serge Semin
2020-09-29 13:52   ` Mark Brown
2020-09-29 22:17     ` Serge Semin
2020-09-30 15:03       ` Serge Semin
2020-09-30 15:41         ` Mark Brown
2020-09-30 15:53           ` Serge Semin
2020-09-20 11:28 ` [PATCH 12/30] spi: dw: Detach SPI device specific CR0 config method Serge Semin
2020-09-20 11:28 ` [PATCH 13/30] spi: dw: Update SPI bus speed in a config function Serge Semin
2020-09-20 11:28 ` [PATCH 14/30] spi: dw: Simplify the SPI bus speed config procedure Serge Semin
2020-09-20 11:28 ` [PATCH 15/30] spi: dw: Update Rx sample delay in the config function Serge Semin
2020-09-20 11:29 ` [PATCH 16/30] spi: dw: Add DW SPI controller config structure Serge Semin
2020-09-20 11:29 ` [PATCH 17/30] spi: dw: Refactor data IO procedure Serge Semin
2020-09-20 11:29 ` [PATCH 18/30] spi: dw: Refactor IRQ-based SPI transfer procedure Serge Semin
2020-09-20 11:29 ` [PATCH 19/30] spi: dw: Perform IRQ setup in a dedicated function Serge Semin
2020-09-20 11:29 ` [PATCH 20/30] spi: dw: Unmask IRQs after enabling the chip Serge Semin
2020-09-20 11:29 ` [PATCH 21/30] spi: dw: Discard chip enabling on DMA setup error Serge Semin
2020-09-20 11:29 ` [PATCH 22/30] spi: dw: De-assert chip-select on reset Serge Semin
2020-09-20 11:29 ` [PATCH 23/30] spi: dw: Explicitly de-assert CS on SPI transfer completion Serge Semin
2020-09-20 11:29 ` [PATCH 24/30] spi: dw: Move num-of retries parameter to the header file Serge Semin
2020-09-20 11:29 ` [PATCH 25/30] spi: dw: Add generic DW SSI status-check method Serge Semin
2020-09-20 11:29 ` [PATCH 26/30] spi: dw: Add memory operations support Serge Semin
2020-09-20 11:29 ` [PATCH 27/30] spi: dw: Introduce max mem-ops SPI bus frequency setting Serge Semin
2020-09-20 11:29 ` [PATCH 28/30] spi: dw: Add poll-based SPI transfers support Serge Semin
2020-09-20 11:29 ` [PATCH 29/30] dt-bindings: spi: dw: Add Baikal-T1 SPI Controllers Serge Semin
2020-09-29 16:58   ` Rob Herring
2020-09-20 11:41 ` [PATCH 30/30] spi: dw: Add Baikal-T1 SPI Controller glue driver Serge Semin
2020-09-29 14:43 ` [PATCH 00/30] spi: dw: Add full Baikal-T1 SPI Controllers support Mark Brown
2020-09-29 22:43   ` Serge Semin
2020-09-30 11:04     ` Mark Brown
2020-09-30 13:11       ` Serge Semin
2020-09-30 14:43         ` Mark Brown
2020-09-29 16:23 ` Mark Brown

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.