* [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
* 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 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 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 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
* [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
* 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 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
* [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
* 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 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
* [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
* 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 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 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 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
* [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
* 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
* [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 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-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 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