2018-10-31 11:00:45

by Esmil

[permalink] [raw]
Subject: [PATCH v1 00/14] Rockchip SPI cleanup and use interrupts

From: Emil Renner Berthing <[email protected]>

Hi,

I took another look at the rockchip spi driver and ended up
with more cleanups and implementing an interrupt handler
to fill/empty the tx and rx fifos rather than busy-looping.

I have two question though:

The driver sets the SPI_LOOP flag in master->mode_bits,
but never checks if the flag is set on an spi device.
That looks suspicious to me, but I'm not exactly sure what
that flag means, so it might be ok?

The driver registers a master->max_transfer_size function
to always return 0xffff, but also checks each transfer
for xfer->len > 0xffff.
I thought that was redundant, but it turns out I can
trigger it with a simple
dd if=/dev/mtd0 of=/dev/null bs=[something > 0xffff]
Is that a bug or have I just not understood what
master->max_transfer_size is supposed to do?

/Emil

Emil Renner Berthing (14):
spi: rockchip: make spi_enable_chip take bool
spi: rockchip: use designated init for dma config
spi: rockchip: always use SPI mode
spi: rockchip: use atomic_t state
spi: rockchip: disable spi on error
spi: rockchip: read transfer info directly
spi: rockchip: don't store dma channels twice
spi: rockchip: remove master pointer from dev data
spi: rockchip: simplify use_dma logic
spi: rockchip: set min/max speed
spi: rockchip: precompute rx sample delay
spi: rockchip: use irq rather than polling
spi: rockchip: support 4bit words
spi: rockchip: support lsb-first mode

drivers/spi/spi-rockchip.c | 579 +++++++++++++++++--------------------
1 file changed, 264 insertions(+), 315 deletions(-)

--
2.19.1



2018-10-31 10:59:06

by Esmil

[permalink] [raw]
Subject: [PATCH v1 13/14] spi: rockchip: support 4bit words

From: Emil Renner Berthing <[email protected]>

The hardware supports 4, 8 and 16bit spi words,
so add the missing support for 4bit words.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 41 +++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1297f081818d..9e47e81553a1 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -54,6 +54,9 @@

/* Bit fields in CTRLR0 */
#define CR0_DFS_OFFSET 0
+#define CR0_DFS_4BIT 0x0
+#define CR0_DFS_8BIT 0x1
+#define CR0_DFS_16BIT 0x2

#define CR0_CFS_OFFSET 2

@@ -464,15 +467,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
bool use_dma)
{
- u32 dmacr = 0;
-
u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
| CR0_SSD_ONE << CR0_SSD_OFFSET
| CR0_EM_BIG << CR0_EM_OFFSET;
+ u32 cr1;
+ u32 dmacr = 0;

cr0 |= rs->rsd << CR0_RSD_OFFSET;
- cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;

if (xfer->rx_buf && xfer->tx_buf)
@@ -482,6 +484,27 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else if (use_dma)
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

+ switch (xfer->bits_per_word) {
+ case 4:
+ cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len - 1;
+ break;
+ case 8:
+ cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len - 1;
+ break;
+ case 16:
+ cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len / 2 - 1;
+ break;
+ default:
+ /* we only whitelist 4, 8 and 16 bit words in
+ * master->bits_per_word_mask, so this shouldn't
+ * happen
+ */
+ unreachable();
+ }
+
if (use_dma) {
if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
@@ -490,13 +513,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
}

writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
-
- if (rs->n_bytes == 1)
- writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
- else if (rs->n_bytes == 2)
- writel_relaxed((xfer->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
- else
- writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed(cr1, rs->regs + ROCKCHIP_SPI_CTRLR1);

/* unfortunately setting the fifo threshold level to generate an
* interrupt exactly when the fifo is full doesn't seem to work,
@@ -545,7 +562,7 @@ static int rockchip_spi_transfer_one(
return -EINVAL;
}

- rs->n_bytes = xfer->bits_per_word >> 3;
+ rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2;

use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

@@ -667,7 +684,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
master->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
master->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);

--
2.19.1


2018-10-31 10:59:06

by Esmil

[permalink] [raw]
Subject: [PATCH v1 14/14] spi: rockchip: support lsb-first mode

From: Emil Renner Berthing <[email protected]>

Add missing support for lsb-first mode.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 9e47e81553a1..3912526ead66 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -476,6 +476,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs,

cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+ if (spi->mode & SPI_LSB_FIRST)
+ cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;

if (xfer->rx_buf && xfer->tx_buf)
cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
@@ -681,7 +683,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)

master->auto_runtime_pm = true;
master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
--
2.19.1


2018-10-31 10:59:12

by Esmil

[permalink] [raw]
Subject: [PATCH v1 12/14] spi: rockchip: use irq rather than polling

From: Emil Renner Berthing <[email protected]>

Register an interrupt handler to fill/empty the
tx and rx fifos rather than busy-looping.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 155 ++++++++++++++++++++++---------------
1 file changed, 92 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5fe6099ff366..1297f081818d 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -172,6 +172,11 @@ struct rockchip_spi {
dma_addr_t dma_addr_rx;
dma_addr_t dma_addr_tx;

+ const void *tx;
+ void *rx;
+ unsigned int tx_left;
+ unsigned int rx_left;
+
atomic_t state;

/*depth of the FIFO buffer */
@@ -182,11 +187,6 @@ struct rockchip_spi {
u8 n_bytes;
u8 rsd;

- const void *tx;
- const void *tx_end;
- void *rx;
- void *rx_end;
-
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
};

@@ -222,24 +222,6 @@ static u32 get_fifo_len(struct rockchip_spi *rs)
return (fifo == 31) ? 0 : fifo;
}

-static inline u32 tx_max(struct rockchip_spi *rs)
-{
- u32 tx_left, tx_room;
-
- tx_left = (rs->tx_end - rs->tx) / rs->n_bytes;
- tx_room = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
-
- return min(tx_left, tx_room);
-}
-
-static inline u32 rx_max(struct rockchip_spi *rs)
-{
- u32 rx_left = (rs->rx_end - rs->rx) / rs->n_bytes;
- u32 rx_room = (u32)readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
-
- return min(rx_left, rx_room);
-}
-
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
struct spi_master *master = spi->master;
@@ -277,6 +259,9 @@ static void rockchip_spi_handle_err(struct spi_master *master,
*/
spi_enable_chip(rs, false);

+ /* make sure all interrupts are masked */
+ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
+
if (atomic_read(&rs->state) & TXDMA)
dmaengine_terminate_async(master->dma_tx);

@@ -286,14 +271,17 @@ static void rockchip_spi_handle_err(struct spi_master *master,

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
{
- u32 max = tx_max(rs);
- u32 txw = 0;
+ u32 tx_free = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
+ u32 words = min(rs->tx_left, tx_free);
+
+ rs->tx_left -= words;
+ for (; words; words--) {
+ u32 txw;

- while (max--) {
if (rs->n_bytes == 1)
- txw = *(u8 *)(rs->tx);
+ txw = *(u8 *)rs->tx;
else
- txw = *(u16 *)(rs->tx);
+ txw = *(u16 *)rs->tx;

writel_relaxed(txw, rs->regs + ROCKCHIP_SPI_TXDR);
rs->tx += rs->n_bytes;
@@ -302,46 +290,72 @@ static void rockchip_spi_pio_writer(struct rockchip_spi *rs)

static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
{
- u32 max = rx_max(rs);
- u32 rxw;
+ u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
+ u32 rx_left = rs->rx_left - words;
+
+ /* the hardware doesn't allow us to change fifo threshold
+ * level while spi is enabled, so instead make sure to leave
+ * enough words in the rx fifo to get the last interrupt
+ * exactly when all words have been received
+ */
+ if (rx_left) {
+ u32 ftl = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFTLR) + 1;
+
+ if (rx_left < ftl) {
+ rx_left = ftl;
+ words = rs->rx_left - rx_left;
+ }
+ }
+
+ rs->rx_left = rx_left;
+ for (; words; words--) {
+ u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
+
+ if (!rs->rx)
+ continue;

- while (max--) {
- rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
if (rs->n_bytes == 1)
- *(u8 *)(rs->rx) = (u8)rxw;
+ *(u8 *)rs->rx = (u8)rxw;
else
- *(u16 *)(rs->rx) = (u16)rxw;
+ *(u16 *)rs->rx = (u16)rxw;
rs->rx += rs->n_bytes;
}
}

-static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
+static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
{
- int remain = 0;
+ struct spi_master *master = dev_id;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);

- spi_enable_chip(rs, true);
+ if (rs->tx_left)
+ rockchip_spi_pio_writer(rs);

- do {
- if (rs->tx) {
- remain = rs->tx_end - rs->tx;
- rockchip_spi_pio_writer(rs);
- }
+ rockchip_spi_pio_reader(rs);
+ if (!rs->rx_left) {
+ spi_enable_chip(rs, false);
+ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
+ spi_finalize_current_transfer(master);
+ }

- if (rs->rx) {
- remain = rs->rx_end - rs->rx;
- rockchip_spi_pio_reader(rs);
- }
+ return IRQ_HANDLED;
+}

- cpu_relax();
- } while (remain);
+static int rockchip_spi_prepare_irq(struct rockchip_spi *rs,
+ struct spi_transfer *xfer)
+{
+ rs->tx = xfer->tx_buf;
+ rs->rx = xfer->rx_buf;
+ rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0;
+ rs->rx_left = xfer->len / rs->n_bytes;

- /* If tx, wait until the FIFO data completely. */
- if (rs->tx)
- wait_for_idle(rs);
+ writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR);
+ spi_enable_chip(rs, true);

- spi_enable_chip(rs, false);
+ if (rs->tx_left)
+ rockchip_spi_pio_writer(rs);

- return 0;
+ /* 1 means the transfer is in progress */
+ return 1;
}

static void rockchip_spi_dma_rxcb(void *data)
@@ -465,7 +479,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
else if (xfer->rx_buf)
cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET;
- else
+ else if (use_dma)
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

if (use_dma) {
@@ -484,8 +498,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);

- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ /* unfortunately setting the fifo threshold level to generate an
+ * interrupt exactly when the fifo is full doesn't seem to work,
+ * so we need the strict inequality here
+ */
+ if (xfer->len < rs->fifo_len)
+ writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ else
+ writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);

writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
@@ -527,11 +547,6 @@ static int rockchip_spi_transfer_one(

rs->n_bytes = xfer->bits_per_word >> 3;

- rs->tx = xfer->tx_buf;
- rs->tx_end = rs->tx + xfer->len;
- rs->rx = xfer->rx_buf;
- rs->rx_end = rs->rx + xfer->len;
-
use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

rockchip_spi_config(rs, spi, xfer, use_dma);
@@ -539,7 +554,7 @@ static int rockchip_spi_transfer_one(
if (use_dma)
return rockchip_spi_prepare_dma(rs, master, xfer);

- return rockchip_spi_pio_transfer(rs);
+ return rockchip_spi_prepare_irq(rs, xfer);
}

static bool rockchip_spi_can_dma(struct spi_master *master,
@@ -547,8 +562,13 @@ static bool rockchip_spi_can_dma(struct spi_master *master,
struct spi_transfer *xfer)
{
struct rockchip_spi *rs = spi_master_get_devdata(master);
+ unsigned int bytes_per_word = xfer->bits_per_word <= 8 ? 1 : 2;

- return (xfer->len > rs->fifo_len);
+ /* if the numbor of spi words to transfer is less than the fifo
+ * length we can just fill the fifo and wait for a single irq,
+ * so don't bother setting up dma
+ */
+ return xfer->len / bytes_per_word >= rs->fifo_len;
}

static int rockchip_spi_probe(struct platform_device *pdev)
@@ -603,6 +623,15 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto err_disable_spiclk;
+
+ ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL,
+ IRQF_ONESHOT, dev_name(&pdev->dev), master);
+ if (ret)
+ goto err_disable_spiclk;
+
rs->dev = &pdev->dev;
rs->freq = clk_get_rate(rs->spiclk);

--
2.19.1


2018-10-31 10:59:18

by Esmil

[permalink] [raw]
Subject: [PATCH v1 11/14] spi: rockchip: precompute rx sample delay

From: Emil Renner Berthing <[email protected]>

Now that we no longer potentially change spi clock
at runtime we can precompute the rx sample delay
at probe time rather than for each transfer.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index d1b3ba2b1532..5fe6099ff366 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -94,6 +94,7 @@
#define CR0_BHT_8BIT 0x1

#define CR0_RSD_OFFSET 14
+#define CR0_RSD_MAX 0x3

#define CR0_FRF_OFFSET 16
#define CR0_FRF_SPI 0x0
@@ -179,7 +180,7 @@ struct rockchip_spi {
u32 freq;

u8 n_bytes;
- u32 rsd_nsecs;
+ u8 rsd;

const void *tx;
const void *tx_end;
@@ -450,13 +451,13 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
bool use_dma)
{
u32 dmacr = 0;
- int rsd = 0;

u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
| CR0_SSD_ONE << CR0_SSD_OFFSET
| CR0_EM_BIG << CR0_EM_OFFSET;

+ cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;

@@ -474,20 +475,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
dmacr |= RF_DMA_EN;
}

- /* Rx sample delay is expressed in parent clock cycles (max 3) */
- rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->freq >> 8),
- 1000000000 >> 8);
- if (!rsd && rs->rsd_nsecs) {
- pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
- rs->freq, rs->rsd_nsecs);
- } else if (rsd > 3) {
- rsd = 3;
- pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
- rs->freq, rs->rsd_nsecs,
- rsd * 1000000000U / rs->freq);
- }
- cr0 |= rsd << CR0_RSD_OFFSET;
-
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);

if (rs->n_bytes == 1)
@@ -620,8 +607,21 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->freq = clk_get_rate(rs->spiclk);

if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
- &rsd_nsecs))
- rs->rsd_nsecs = rsd_nsecs;
+ &rsd_nsecs)) {
+ /* rx sample delay is expressed in parent clock cycles (max 3) */
+ u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
+ 1000000000 >> 8);
+ if (!rsd) {
+ dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n",
+ rs->freq, rsd_nsecs);
+ } else if (rsd > CR0_RSD_MAX) {
+ rsd = CR0_RSD_MAX;
+ dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
+ rs->freq, rsd_nsecs,
+ CR0_RSD_MAX * 1000000000U / rs->freq);
+ }
+ rs->rsd = rsd;
+ }

rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {
--
2.19.1


2018-10-31 10:59:25

by Esmil

[permalink] [raw]
Subject: [PATCH v1 10/14] spi: rockchip: set min/max speed

From: Emil Renner Berthing <[email protected]>

The driver previously checked each transfer if the
requested speed was higher than possible with the
current spi clock rate and raised the clock rate
accordingly.

However, there is no check to see if the spi clock
was actually set that high and no way to dynamically
lower the spi clock rate again.

So it seems any potiential users of this functionality
are better off just setting the spi clock rate at init
using the assigned-clock-rates devicetree property.

Removing this dynamic spi clock rate raising allows
us let the spi framework handle min/max speeds
for us.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 52 +++++++++++++++-----------------------
1 file changed, 20 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index ba60cbcd45c2..d1b3ba2b1532 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -115,6 +115,10 @@
/* Bit fields in SER, 2bit */
#define SER_MASK 0x3

+/* Bit fields in BAUDR */
+#define BAUDR_SCKDV_MIN 2
+#define BAUDR_SCKDV_MAX 65534
+
/* Bit fields in SR, 5bit */
#define SR_MASK 0x1f
#define SR_BUSY (1 << 0)
@@ -147,7 +151,7 @@
#define TXDMA (1 << 1)

/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
-#define MAX_SCLK_OUT 50000000
+#define MAX_SCLK_OUT 50000000U

/*
* SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However,
@@ -171,12 +175,11 @@ struct rockchip_spi {

/*depth of the FIFO buffer */
u32 fifo_len;
- /* max bus freq supported */
- u32 max_freq;
+ /* frequency of spiclk */
+ u32 freq;

u8 n_bytes;
u32 rsd_nsecs;
- u32 speed;

const void *tx;
const void *tx_end;
@@ -191,11 +194,6 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}

-static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
-{
- writel_relaxed(div, rs->regs + ROCKCHIP_SPI_BAUDR);
-}
-
static inline void wait_for_idle(struct rockchip_spi *rs)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
@@ -451,7 +449,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
bool use_dma)
{
- u32 div = 0;
u32 dmacr = 0;
int rsd = 0;

@@ -477,30 +474,17 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
dmacr |= RF_DMA_EN;
}

- if (WARN_ON(rs->speed > MAX_SCLK_OUT))
- rs->speed = MAX_SCLK_OUT;
-
- /* the minimum divisor is 2 */
- if (rs->max_freq < 2 * rs->speed) {
- clk_set_rate(rs->spiclk, 2 * rs->speed);
- rs->max_freq = clk_get_rate(rs->spiclk);
- }
-
- /* div doesn't support odd number */
- div = DIV_ROUND_UP(rs->max_freq, rs->speed);
- div = (div + 1) & 0xfffe;
-
/* Rx sample delay is expressed in parent clock cycles (max 3) */
- rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
+ rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->freq >> 8),
1000000000 >> 8);
if (!rsd && rs->rsd_nsecs) {
pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
- rs->max_freq, rs->rsd_nsecs);
+ rs->freq, rs->rsd_nsecs);
} else if (rsd > 3) {
rsd = 3;
pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
- rs->max_freq, rs->rsd_nsecs,
- rsd * 1000000000U / rs->max_freq);
+ rs->freq, rs->rsd_nsecs,
+ rsd * 1000000000U / rs->freq);
}
cr0 |= rsd << CR0_RSD_OFFSET;

@@ -520,9 +504,12 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);

- spi_set_clk(rs, div);
-
- dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
+ /* the hardware only supports an even clock divisor, so
+ * round divisor = spiclk / speed up to nearest even number
+ * so that the resulting speed is <= the requested speed
+ */
+ writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz),
+ rs->regs + ROCKCHIP_SPI_BAUDR);
}

static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
@@ -551,7 +538,6 @@ static int rockchip_spi_transfer_one(
return -EINVAL;
}

- rs->speed = xfer->speed_hz;
rs->n_bytes = xfer->bits_per_word >> 3;

rs->tx = xfer->tx_buf;
@@ -631,7 +617,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
spi_enable_chip(rs, false);

rs->dev = &pdev->dev;
- rs->max_freq = clk_get_rate(rs->spiclk);
+ rs->freq = clk_get_rate(rs->spiclk);

if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
&rsd_nsecs))
@@ -653,6 +639,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ master->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
+ master->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);

master->set_cs = rockchip_spi_set_cs;
master->transfer_one = rockchip_spi_transfer_one;
--
2.19.1


2018-10-31 10:59:34

by Esmil

[permalink] [raw]
Subject: [PATCH v1 09/14] spi: rockchip: simplify use_dma logic

From: Emil Renner Berthing <[email protected]>

We only need to know if we're using dma when setting
up the transfer, so just use a local variable for
that.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 45a1479c1a29..ba60cbcd45c2 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -184,8 +184,6 @@ struct rockchip_spi {
void *rx_end;

bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
-
- bool use_dma;
};

static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
@@ -450,7 +448,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
}

static void rockchip_spi_config(struct rockchip_spi *rs,
- struct spi_device *spi, struct spi_transfer *xfer)
+ struct spi_device *spi, struct spi_transfer *xfer,
+ bool use_dma)
{
u32 div = 0;
u32 dmacr = 0;
@@ -471,7 +470,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

- if (rs->use_dma) {
+ if (use_dma) {
if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
if (xfer->rx_buf)
@@ -537,6 +536,7 @@ static int rockchip_spi_transfer_one(
struct spi_transfer *xfer)
{
struct rockchip_spi *rs = spi_master_get_devdata(master);
+ bool use_dma;

WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY));
@@ -559,15 +559,11 @@ static int rockchip_spi_transfer_one(
rs->rx = xfer->rx_buf;
rs->rx_end = rs->rx + xfer->len;

- /* we need prepare dma before spi was enabled */
- if (master->can_dma && master->can_dma(master, spi, xfer))
- rs->use_dma = true;
- else
- rs->use_dma = false;
+ use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

- rockchip_spi_config(rs, spi, xfer);
+ rockchip_spi_config(rs, spi, xfer, use_dma);

- if (rs->use_dma)
+ if (use_dma)
return rockchip_spi_prepare_dma(rs, master, xfer);

return rockchip_spi_pio_transfer(rs);
--
2.19.1


2018-10-31 10:59:38

by Esmil

[permalink] [raw]
Subject: [PATCH v1 07/14] spi: rockchip: don't store dma channels twice

From: Emil Renner Berthing <[email protected]>

The spi master (aka spi controller) structure already
has two fields for storing the rx and tx dma channels.
Just use them rather than duplicating them in driver data.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 76 +++++++++++++++++---------------------
1 file changed, 34 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5edc51820d35..f3fe6d4cf6f6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -157,11 +157,6 @@

#define ROCKCHIP_SPI_MAX_CS_NUM 2

-struct rockchip_spi_dma_data {
- struct dma_chan *ch;
- dma_addr_t addr;
-};
-
struct rockchip_spi {
struct device *dev;
struct spi_master *master;
@@ -170,6 +165,8 @@ struct rockchip_spi {
struct clk *apb_pclk;

void __iomem *regs;
+ dma_addr_t dma_addr_rx;
+ dma_addr_t dma_addr_tx;

atomic_t state;

@@ -190,8 +187,6 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
- struct rockchip_spi_dma_data dma_rx;
- struct rockchip_spi_dma_data dma_tx;
};

static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
@@ -287,10 +282,10 @@ static void rockchip_spi_handle_err(struct spi_master *master,
spi_enable_chip(rs, false);

if (atomic_read(&rs->state) & TXDMA)
- dmaengine_terminate_async(rs->dma_tx.ch);
+ dmaengine_terminate_async(master->dma_tx);

if (atomic_read(&rs->state) & RXDMA)
- dmaengine_terminate_async(rs->dma_rx.ch);
+ dmaengine_terminate_async(master->dma_rx);
}

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
@@ -381,7 +376,7 @@ static void rockchip_spi_dma_txcb(void *data)
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
- struct spi_transfer *xfer)
+ struct spi_master *master, struct spi_transfer *xfer)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;

@@ -391,15 +386,15 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (xfer->rx_buf) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
- .src_addr = rs->dma_rx.addr,
+ .src_addr = rs->dma_addr_rx,
.src_addr_width = rs->n_bytes,
.src_maxburst = 1,
};

- dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
+ dmaengine_slave_config(master->dma_rx, &rxconf);

rxdesc = dmaengine_prep_slave_sg(
- rs->dma_rx.ch,
+ master->dma_rx,
xfer->rx_sg.sgl, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc)
@@ -413,20 +408,20 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (xfer->tx_buf) {
struct dma_slave_config txconf = {
.direction = DMA_MEM_TO_DEV,
- .dst_addr = rs->dma_tx.addr,
+ .dst_addr = rs->dma_addr_tx,
.dst_addr_width = rs->n_bytes,
.dst_maxburst = rs->fifo_len / 2,
};

- dmaengine_slave_config(rs->dma_tx.ch, &txconf);
+ dmaengine_slave_config(master->dma_tx, &txconf);

txdesc = dmaengine_prep_slave_sg(
- rs->dma_tx.ch,
+ master->dma_tx,
xfer->tx_sg.sgl, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
- dmaengine_terminate_sync(rs->dma_rx.ch);
+ dmaengine_terminate_sync(master->dma_rx);
return -EINVAL;
}

@@ -438,7 +433,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (rxdesc) {
atomic_or(RXDMA, &rs->state);
dmaengine_submit(rxdesc);
- dma_async_issue_pending(rs->dma_rx.ch);
+ dma_async_issue_pending(master->dma_rx);
}

spi_enable_chip(rs, true);
@@ -446,7 +441,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (txdesc) {
atomic_or(TXDMA, &rs->state);
dmaengine_submit(txdesc);
- dma_async_issue_pending(rs->dma_tx.ch);
+ dma_async_issue_pending(master->dma_tx);
}

/* 1 means the transfer is in progress */
@@ -572,7 +567,7 @@ static int rockchip_spi_transfer_one(
rockchip_spi_config(rs, spi, xfer);

if (rs->use_dma)
- return rockchip_spi_prepare_dma(rs, xfer);
+ return rockchip_spi_prepare_dma(rs, master, xfer);

return rockchip_spi_pio_transfer(rs);
}
@@ -669,34 +664,31 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->handle_err = rockchip_spi_handle_err;
master->flags = SPI_MASTER_GPIO_SS;

- rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
- if (IS_ERR(rs->dma_tx.ch)) {
+ master->dma_tx = dma_request_chan(rs->dev, "tx");
+ if (IS_ERR(master->dma_tx)) {
/* Check tx to see if we need defer probing driver */
- if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
+ if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_disable_pm_runtime;
}
dev_warn(rs->dev, "Failed to request TX DMA channel\n");
- rs->dma_tx.ch = NULL;
+ master->dma_tx = NULL;
}

- rs->dma_rx.ch = dma_request_chan(rs->dev, "rx");
- if (IS_ERR(rs->dma_rx.ch)) {
- if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) {
+ master->dma_rx = dma_request_chan(rs->dev, "rx");
+ if (IS_ERR(master->dma_rx)) {
+ if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_free_dma_tx;
}
dev_warn(rs->dev, "Failed to request RX DMA channel\n");
- rs->dma_rx.ch = NULL;
+ master->dma_rx = NULL;
}

- if (rs->dma_tx.ch && rs->dma_rx.ch) {
- rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
- rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
-
+ if (master->dma_tx && master->dma_rx) {
+ rs->dma_addr_tx = mem->start + ROCKCHIP_SPI_TXDR;
+ rs->dma_addr_rx = mem->start + ROCKCHIP_SPI_RXDR;
master->can_dma = rockchip_spi_can_dma;
- master->dma_tx = rs->dma_tx.ch;
- master->dma_rx = rs->dma_rx.ch;
}

ret = devm_spi_register_master(&pdev->dev, master);
@@ -708,11 +700,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
return 0;

err_free_dma_rx:
- if (rs->dma_rx.ch)
- dma_release_channel(rs->dma_rx.ch);
+ if (master->dma_rx)
+ dma_release_channel(master->dma_rx);
err_free_dma_tx:
- if (rs->dma_tx.ch)
- dma_release_channel(rs->dma_tx.ch);
+ if (master->dma_tx)
+ dma_release_channel(master->dma_tx);
err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
err_disable_spiclk:
@@ -739,10 +731,10 @@ static int rockchip_spi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);

- if (rs->dma_tx.ch)
- dma_release_channel(rs->dma_tx.ch);
- if (rs->dma_rx.ch)
- dma_release_channel(rs->dma_rx.ch);
+ if (master->dma_tx)
+ dma_release_channel(master->dma_tx);
+ if (master->dma_rx)
+ dma_release_channel(master->dma_rx);

spi_master_put(master);

--
2.19.1


2018-10-31 10:59:47

by Esmil

[permalink] [raw]
Subject: [PATCH v1 08/14] spi: rockchip: remove master pointer from dev data

From: Emil Renner Berthing <[email protected]>

In almost all cases we already have a pointer to the
spi master structure where we have the driver data.

The only exceptions are the dma callbacks which are
easily fixed by passing them the master and using
spi_master_get_devdata to retrieve the driver data.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index f3fe6d4cf6f6..45a1479c1a29 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -159,7 +159,6 @@

struct rockchip_spi {
struct device *dev;
- struct spi_master *master;

struct clk *spiclk;
struct clk *apb_pclk;
@@ -350,19 +349,21 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)

static void rockchip_spi_dma_rxcb(void *data)
{
- struct rockchip_spi *rs = data;
+ struct spi_master *master = data;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);
int state = atomic_fetch_andnot(RXDMA, &rs->state);

if (state & TXDMA)
return;

spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
+ spi_finalize_current_transfer(master);
}

static void rockchip_spi_dma_txcb(void *data)
{
- struct rockchip_spi *rs = data;
+ struct spi_master *master = data;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);
int state = atomic_fetch_andnot(TXDMA, &rs->state);

if (state & RXDMA)
@@ -372,7 +373,7 @@ static void rockchip_spi_dma_txcb(void *data)
wait_for_idle(rs);

spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
+ spi_finalize_current_transfer(master);
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
@@ -401,7 +402,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
return -EINVAL;

rxdesc->callback = rockchip_spi_dma_rxcb;
- rxdesc->callback_param = rs;
+ rxdesc->callback_param = master;
}

txdesc = NULL;
@@ -426,7 +427,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
}

txdesc->callback = rockchip_spi_dma_txcb;
- txdesc->callback_param = rs;
+ txdesc->callback_param = master;
}

/* rx must be started before tx due to spi instinct */
@@ -633,7 +634,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

- rs->master = master;
rs->dev = &pdev->dev;
rs->max_freq = clk_get_rate(rs->spiclk);

@@ -746,9 +746,8 @@ static int rockchip_spi_suspend(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
- struct rockchip_spi *rs = spi_master_get_devdata(master);

- ret = spi_master_suspend(rs->master);
+ ret = spi_master_suspend(master);
if (ret < 0)
return ret;

@@ -773,7 +772,7 @@ static int rockchip_spi_resume(struct device *dev)
if (ret < 0)
return ret;

- ret = spi_master_resume(rs->master);
+ ret = spi_master_resume(master);
if (ret < 0) {
clk_disable_unprepare(rs->spiclk);
clk_disable_unprepare(rs->apb_pclk);
--
2.19.1


2018-10-31 10:59:59

by Esmil

[permalink] [raw]
Subject: [PATCH v1 06/14] spi: rockchip: read transfer info directly

From: Emil Renner Berthing <[email protected]>

Just read transfer info directly from the spi device
and transfer structures rather than storing it in
driver data first.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 70 +++++++++++++-------------------------
1 file changed, 24 insertions(+), 46 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5729e6071729..5edc51820d35 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -178,12 +178,8 @@ struct rockchip_spi {
/* max bus freq supported */
u32 max_freq;

- u16 mode;
- u8 tmode;
- u8 bpw;
u8 n_bytes;
u32 rsd_nsecs;
- unsigned len;
u32 speed;

const void *tx;
@@ -194,8 +190,6 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
- struct sg_table tx_sg;
- struct sg_table rx_sg;
struct rockchip_spi_dma_data dma_rx;
struct rockchip_spi_dma_data dma_tx;
};
@@ -282,17 +276,6 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
rs->cs_asserted[spi->chip_select] = cs_asserted;
}

-static int rockchip_spi_prepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct rockchip_spi *rs = spi_master_get_devdata(master);
- struct spi_device *spi = msg->spi;
-
- rs->mode = spi->mode;
-
- return 0;
-}
-
static void rockchip_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
@@ -397,14 +380,15 @@ static void rockchip_spi_dma_txcb(void *data)
spi_finalize_current_transfer(rs->master);
}

-static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
+ struct spi_transfer *xfer)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;

atomic_set(&rs->state, 0);

rxdesc = NULL;
- if (rs->rx) {
+ if (xfer->rx_buf) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
.src_addr = rs->dma_rx.addr,
@@ -416,7 +400,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

rxdesc = dmaengine_prep_slave_sg(
rs->dma_rx.ch,
- rs->rx_sg.sgl, rs->rx_sg.nents,
+ xfer->rx_sg.sgl, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc)
return -EINVAL;
@@ -426,7 +410,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
}

txdesc = NULL;
- if (rs->tx) {
+ if (xfer->tx_buf) {
struct dma_slave_config txconf = {
.direction = DMA_MEM_TO_DEV,
.dst_addr = rs->dma_tx.addr,
@@ -438,7 +422,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

txdesc = dmaengine_prep_slave_sg(
rs->dma_tx.ch,
- rs->tx_sg.sgl, rs->tx_sg.nents,
+ xfer->tx_sg.sgl, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
@@ -469,7 +453,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
return 1;
}

-static void rockchip_spi_config(struct rockchip_spi *rs)
+static void rockchip_spi_config(struct rockchip_spi *rs,
+ struct spi_device *spi, struct spi_transfer *xfer)
{
u32 div = 0;
u32 dmacr = 0;
@@ -481,13 +466,19 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
| CR0_EM_BIG << CR0_EM_OFFSET;

cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
- cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
- cr0 |= (rs->tmode << CR0_XFM_OFFSET);
+ cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+
+ if (xfer->rx_buf && xfer->tx_buf)
+ cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
+ else if (xfer->rx_buf)
+ cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET;
+ else
+ cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

if (rs->use_dma) {
- if (rs->tx)
+ if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
- if (rs->rx)
+ if (xfer->rx_buf)
dmacr |= RF_DMA_EN;
}

@@ -521,11 +512,11 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);

if (rs->n_bytes == 1)
- writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else if (rs->n_bytes == 2)
- writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed((xfer->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else
- writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);

writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
@@ -565,24 +556,12 @@ static int rockchip_spi_transfer_one(
}

rs->speed = xfer->speed_hz;
- rs->bpw = xfer->bits_per_word;
- rs->n_bytes = rs->bpw >> 3;
+ rs->n_bytes = xfer->bits_per_word >> 3;

rs->tx = xfer->tx_buf;
rs->tx_end = rs->tx + xfer->len;
rs->rx = xfer->rx_buf;
rs->rx_end = rs->rx + xfer->len;
- rs->len = xfer->len;
-
- rs->tx_sg = xfer->tx_sg;
- rs->rx_sg = xfer->rx_sg;
-
- if (rs->tx && rs->rx)
- rs->tmode = CR0_XFM_TR;
- else if (rs->tx)
- rs->tmode = CR0_XFM_TO;
- else if (rs->rx)
- rs->tmode = CR0_XFM_RO;

/* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer))
@@ -590,10 +569,10 @@ static int rockchip_spi_transfer_one(
else
rs->use_dma = false;

- rockchip_spi_config(rs);
+ rockchip_spi_config(rs, spi, xfer);

if (rs->use_dma)
- return rockchip_spi_prepare_dma(rs);
+ return rockchip_spi_prepare_dma(rs, xfer);

return rockchip_spi_pio_transfer(rs);
}
@@ -685,7 +664,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);

master->set_cs = rockchip_spi_set_cs;
- master->prepare_message = rockchip_spi_prepare_message;
master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err;
--
2.19.1


2018-10-31 11:00:27

by Esmil

[permalink] [raw]
Subject: [PATCH v1 03/14] spi: rockchip: always use SPI mode

From: Emil Renner Berthing <[email protected]>

The hardware supports 3 different variants of SPI
and there were some code around it, but nothing
to actually set it to anything but "Motorola SPI".
Just drop that code and always use that mode.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 87d1b9837d94..7fac4253075e 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -156,12 +156,6 @@

#define ROCKCHIP_SPI_MAX_CS_NUM 2

-enum rockchip_ssi_type {
- SSI_MOTO_SPI = 0,
- SSI_TI_SSP,
- SSI_NS_MICROWIRE,
-};
-
struct rockchip_spi_dma_data {
struct dma_chan *ch;
dma_addr_t addr;
@@ -179,8 +173,6 @@ struct rockchip_spi {
u32 fifo_len;
/* max bus freq supported */
u32 max_freq;
- /* supported slave numbers */
- enum rockchip_ssi_type type;

u16 mode;
u8 tmode;
@@ -525,14 +517,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
u32 dmacr = 0;
int rsd = 0;

- u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
- | (CR0_SSD_ONE << CR0_SSD_OFFSET)
- | (CR0_EM_BIG << CR0_EM_OFFSET);
+ u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
+ | CR0_BHT_8BIT << CR0_BHT_OFFSET
+ | CR0_SSD_ONE << CR0_SSD_OFFSET
+ | CR0_EM_BIG << CR0_EM_OFFSET;

cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
cr0 |= (rs->tmode << CR0_XFM_OFFSET);
- cr0 |= (rs->type << CR0_FRF_OFFSET);

if (rs->use_dma) {
if (rs->tx)
@@ -709,7 +701,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

- rs->type = SSI_MOTO_SPI;
rs->master = master;
rs->dev = &pdev->dev;
rs->max_freq = clk_get_rate(rs->spiclk);
--
2.19.1


2018-10-31 11:00:37

by Esmil

[permalink] [raw]
Subject: [PATCH v1 01/14] spi: rockchip: make spi_enable_chip take bool

From: Emil Renner Berthing <[email protected]>

The spi_enable_chip function takes a boolean
argument. Change the type to reflect that.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 51ef632bca52..7e54e1a69cc8 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -208,9 +208,9 @@ struct rockchip_spi {
struct rockchip_spi_dma_data dma_tx;
};

-static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
+static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
{
- writel_relaxed((enable ? 1 : 0), rs->regs + ROCKCHIP_SPI_SSIENR);
+ writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}

static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
@@ -339,7 +339,7 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,
{
struct rockchip_spi *rs = spi_master_get_devdata(master);

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

return 0;
}
@@ -379,7 +379,7 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
{
int remain = 0;

- spi_enable_chip(rs, 1);
+ spi_enable_chip(rs, true);

do {
if (rs->tx) {
@@ -399,7 +399,7 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
if (rs->tx)
wait_for_idle(rs);

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

return 0;
}
@@ -413,7 +413,7 @@ static void rockchip_spi_dma_rxcb(void *data)

rs->state &= ~RXBUSY;
if (!(rs->state & TXBUSY)) {
- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);
spi_finalize_current_transfer(rs->master);
}

@@ -432,7 +432,7 @@ static void rockchip_spi_dma_txcb(void *data)

rs->state &= ~TXBUSY;
if (!(rs->state & RXBUSY)) {
- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);
spi_finalize_current_transfer(rs->master);
}

@@ -503,7 +503,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_rx.ch);
}

- spi_enable_chip(rs, 1);
+ spi_enable_chip(rs, true);

if (txdesc) {
spin_lock_irqsave(&rs->lock, flags);
@@ -705,7 +705,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto err_disable_apbclk;
}

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

rs->type = SSI_MOTO_SPI;
rs->master = master;
--
2.19.1


2018-10-31 11:01:35

by Esmil

[permalink] [raw]
Subject: [PATCH v1 05/14] spi: rockchip: disable spi on error

From: Emil Renner Berthing <[email protected]>

Successful transfers leave the spi disabled, so if
we just make sure to disable the spi on error
there should be no need to disable the spi from
master->unprepare_message.

This also flushes the tx and rx fifos,
so no need to do that manually.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 30 +++++-------------------------
1 file changed, 5 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1c813797f963..5729e6071729 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -210,12 +210,6 @@ static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
writel_relaxed(div, rs->regs + ROCKCHIP_SPI_BAUDR);
}

-static inline void flush_fifo(struct rockchip_spi *rs)
-{
- while (readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR))
- readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
-}
-
static inline void wait_for_idle(struct rockchip_spi *rs)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
@@ -304,29 +298,16 @@ static void rockchip_spi_handle_err(struct spi_master *master,
{
struct rockchip_spi *rs = spi_master_get_devdata(master);

- /*
- * For DMA mode, we need terminate DMA channel and flush
- * fifo for the next transfer if DMA thansfer timeout.
- * handle_err() was called by core if transfer failed.
- * Maybe it is reasonable for error handling here.
+ /* stop running spi transfer
+ * this also flushes both rx and tx fifos
*/
+ spi_enable_chip(rs, false);
+
if (atomic_read(&rs->state) & TXDMA)
dmaengine_terminate_async(rs->dma_tx.ch);

- if (atomic_read(&rs->state) & RXDMA) {
+ if (atomic_read(&rs->state) & RXDMA)
dmaengine_terminate_async(rs->dma_rx.ch);
- flush_fifo(rs);
- }
-}
-
-static int rockchip_spi_unprepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct rockchip_spi *rs = spi_master_get_devdata(master);
-
- spi_enable_chip(rs, false);
-
- return 0;
}

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
@@ -705,7 +686,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

master->set_cs = rockchip_spi_set_cs;
master->prepare_message = rockchip_spi_prepare_message;
- master->unprepare_message = rockchip_spi_unprepare_message;
master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err;
--
2.19.1


2018-10-31 11:01:37

by Esmil

[permalink] [raw]
Subject: [PATCH v1 04/14] spi: rockchip: use atomic_t state

From: Emil Renner Berthing <[email protected]>

The state field is currently only used to make sure
only the last of the tx and rx dma callbacks issue
an spi_finalize_current_transfer.
Rather than using a spinlock we can get away
with just turning the state field into an atomic_t.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 75 +++++++++++++-------------------------
1 file changed, 25 insertions(+), 50 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 7fac4253075e..1c813797f963 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -142,8 +142,9 @@
#define RF_DMA_EN (1 << 0)
#define TF_DMA_EN (1 << 1)

-#define RXBUSY (1 << 0)
-#define TXBUSY (1 << 1)
+/* Driver state flags */
+#define RXDMA (1 << 0)
+#define TXDMA (1 << 1)

/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000
@@ -169,6 +170,9 @@ struct rockchip_spi {
struct clk *apb_pclk;

void __iomem *regs;
+
+ atomic_t state;
+
/*depth of the FIFO buffer */
u32 fifo_len;
/* max bus freq supported */
@@ -187,10 +191,6 @@ struct rockchip_spi {
void *rx;
void *rx_end;

- u32 state;
- /* protect state */
- spinlock_t lock;
-
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
@@ -302,28 +302,21 @@ static int rockchip_spi_prepare_message(struct spi_master *master,
static void rockchip_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
- unsigned long flags;
struct rockchip_spi *rs = spi_master_get_devdata(master);

- spin_lock_irqsave(&rs->lock, flags);
-
/*
* For DMA mode, we need terminate DMA channel and flush
* fifo for the next transfer if DMA thansfer timeout.
* handle_err() was called by core if transfer failed.
* Maybe it is reasonable for error handling here.
*/
- if (rs->use_dma) {
- if (rs->state & RXBUSY) {
- dmaengine_terminate_async(rs->dma_rx.ch);
- flush_fifo(rs);
- }
+ if (atomic_read(&rs->state) & TXDMA)
+ dmaengine_terminate_async(rs->dma_tx.ch);

- if (rs->state & TXBUSY)
- dmaengine_terminate_async(rs->dma_tx.ch);
+ if (atomic_read(&rs->state) & RXDMA) {
+ dmaengine_terminate_async(rs->dma_rx.ch);
+ flush_fifo(rs);
}
-
- spin_unlock_irqrestore(&rs->lock, flags);
}

static int rockchip_spi_unprepare_message(struct spi_master *master,
@@ -398,48 +391,36 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)

static void rockchip_spi_dma_rxcb(void *data)
{
- unsigned long flags;
struct rockchip_spi *rs = data;
+ int state = atomic_fetch_andnot(RXDMA, &rs->state);

- spin_lock_irqsave(&rs->lock, flags);
-
- rs->state &= ~RXBUSY;
- if (!(rs->state & TXBUSY)) {
- spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
- }
+ if (state & TXDMA)
+ return;

- spin_unlock_irqrestore(&rs->lock, flags);
+ spi_enable_chip(rs, false);
+ spi_finalize_current_transfer(rs->master);
}

static void rockchip_spi_dma_txcb(void *data)
{
- unsigned long flags;
struct rockchip_spi *rs = data;
+ int state = atomic_fetch_andnot(TXDMA, &rs->state);
+
+ if (state & RXDMA)
+ return;

/* Wait until the FIFO data completely. */
wait_for_idle(rs);

- spin_lock_irqsave(&rs->lock, flags);
-
- rs->state &= ~TXBUSY;
- if (!(rs->state & RXBUSY)) {
- spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
- }
-
- spin_unlock_irqrestore(&rs->lock, flags);
+ spi_enable_chip(rs, false);
+ spi_finalize_current_transfer(rs->master);
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
- unsigned long flags;
struct dma_async_tx_descriptor *rxdesc, *txdesc;

- spin_lock_irqsave(&rs->lock, flags);
- rs->state &= ~RXBUSY;
- rs->state &= ~TXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_set(&rs->state, 0);

rxdesc = NULL;
if (rs->rx) {
@@ -490,9 +471,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

/* rx must be started before tx due to spi instinct */
if (rxdesc) {
- spin_lock_irqsave(&rs->lock, flags);
- rs->state |= RXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_or(RXDMA, &rs->state);
dmaengine_submit(rxdesc);
dma_async_issue_pending(rs->dma_rx.ch);
}
@@ -500,9 +479,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
spi_enable_chip(rs, true);

if (txdesc) {
- spin_lock_irqsave(&rs->lock, flags);
- rs->state |= TXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_or(TXDMA, &rs->state);
dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch);
}
@@ -716,8 +693,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto err_disable_spiclk;
}

- spin_lock_init(&rs->lock);
-
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);

--
2.19.1


2018-10-31 11:01:54

by Esmil

[permalink] [raw]
Subject: [PATCH v1 02/14] spi: rockchip: use designated init for dma config

From: Emil Renner Berthing <[email protected]>

Use C99 designated initializers for dma slave config
structures. This also makes sure uninitialized fields
are zeroed so we don't need an explicit memset.

Signed-off-by: Emil Renner Berthing <[email protected]>
---
drivers/spi/spi-rockchip.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 7e54e1a69cc8..87d1b9837d94 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -442,12 +442,8 @@ static void rockchip_spi_dma_txcb(void *data)
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
unsigned long flags;
- struct dma_slave_config rxconf, txconf;
struct dma_async_tx_descriptor *rxdesc, *txdesc;

- memset(&rxconf, 0, sizeof(rxconf));
- memset(&txconf, 0, sizeof(txconf));
-
spin_lock_irqsave(&rs->lock, flags);
rs->state &= ~RXBUSY;
rs->state &= ~TXBUSY;
@@ -455,10 +451,13 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

rxdesc = NULL;
if (rs->rx) {
- rxconf.direction = DMA_DEV_TO_MEM;
- rxconf.src_addr = rs->dma_rx.addr;
- rxconf.src_addr_width = rs->n_bytes;
- rxconf.src_maxburst = 1;
+ struct dma_slave_config rxconf = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr = rs->dma_rx.addr,
+ .src_addr_width = rs->n_bytes,
+ .src_maxburst = 1,
+ };
+
dmaengine_slave_config(rs->dma_rx.ch, &rxconf);

rxdesc = dmaengine_prep_slave_sg(
@@ -474,10 +473,13 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

txdesc = NULL;
if (rs->tx) {
- txconf.direction = DMA_MEM_TO_DEV;
- txconf.dst_addr = rs->dma_tx.addr;
- txconf.dst_addr_width = rs->n_bytes;
- txconf.dst_maxburst = rs->fifo_len / 2;
+ struct dma_slave_config txconf = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = rs->dma_tx.addr,
+ .dst_addr_width = rs->n_bytes,
+ .dst_maxburst = rs->fifo_len / 2,
+ };
+
dmaengine_slave_config(rs->dma_tx.ch, &txconf);

txdesc = dmaengine_prep_slave_sg(
--
2.19.1


2018-10-31 11:21:15

by Heiko Stuebner

[permalink] [raw]
Subject: Re: [PATCH v1 00/14] Rockchip SPI cleanup and use interrupts

Am Mittwoch, 31. Oktober 2018, 11:56:57 CET schrieb Emil Renner Berthing:
> Emil Renner Berthing (14):
> spi: rockchip: make spi_enable_chip take bool
> spi: rockchip: use designated init for dma config
> spi: rockchip: always use SPI mode
> spi: rockchip: use atomic_t state
> spi: rockchip: disable spi on error
> spi: rockchip: read transfer info directly
> spi: rockchip: don't store dma channels twice
> spi: rockchip: remove master pointer from dev data
> spi: rockchip: simplify use_dma logic
> spi: rockchip: set min/max speed
> spi: rockchip: precompute rx sample delay
> spi: rockchip: use irq rather than polling
> spi: rockchip: support 4bit words
> spi: rockchip: support lsb-first mode

The series, on rk3288 with cros-ec and spi-flash, rk3328 with a spi-flash,
rk3399 with cros-ec and spi-flash:

Tested-by: Heiko Stuebner <[email protected]>




2018-11-05 12:07:15

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: use irq rather than polling" to the spi tree

The patch

spi: rockchip: use irq rather than polling

has been applied to the spi tree at

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

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

From 01b59ce5dac856323a0c13c1d51d99a819f32efe Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:09 +0100
Subject: [PATCH] spi: rockchip: use irq rather than polling

Register an interrupt handler to fill/empty the
tx and rx fifos rather than busy-looping.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 155 ++++++++++++++++++++++---------------
1 file changed, 92 insertions(+), 63 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5fe6099ff366..1297f081818d 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -172,6 +172,11 @@ struct rockchip_spi {
dma_addr_t dma_addr_rx;
dma_addr_t dma_addr_tx;

+ const void *tx;
+ void *rx;
+ unsigned int tx_left;
+ unsigned int rx_left;
+
atomic_t state;

/*depth of the FIFO buffer */
@@ -182,11 +187,6 @@ struct rockchip_spi {
u8 n_bytes;
u8 rsd;

- const void *tx;
- const void *tx_end;
- void *rx;
- void *rx_end;
-
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
};

@@ -222,24 +222,6 @@ static u32 get_fifo_len(struct rockchip_spi *rs)
return (fifo == 31) ? 0 : fifo;
}

-static inline u32 tx_max(struct rockchip_spi *rs)
-{
- u32 tx_left, tx_room;
-
- tx_left = (rs->tx_end - rs->tx) / rs->n_bytes;
- tx_room = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
-
- return min(tx_left, tx_room);
-}
-
-static inline u32 rx_max(struct rockchip_spi *rs)
-{
- u32 rx_left = (rs->rx_end - rs->rx) / rs->n_bytes;
- u32 rx_room = (u32)readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
-
- return min(rx_left, rx_room);
-}
-
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
struct spi_master *master = spi->master;
@@ -277,6 +259,9 @@ static void rockchip_spi_handle_err(struct spi_master *master,
*/
spi_enable_chip(rs, false);

+ /* make sure all interrupts are masked */
+ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
+
if (atomic_read(&rs->state) & TXDMA)
dmaengine_terminate_async(master->dma_tx);

@@ -286,14 +271,17 @@ static void rockchip_spi_handle_err(struct spi_master *master,

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
{
- u32 max = tx_max(rs);
- u32 txw = 0;
+ u32 tx_free = rs->fifo_len - readl_relaxed(rs->regs + ROCKCHIP_SPI_TXFLR);
+ u32 words = min(rs->tx_left, tx_free);
+
+ rs->tx_left -= words;
+ for (; words; words--) {
+ u32 txw;

- while (max--) {
if (rs->n_bytes == 1)
- txw = *(u8 *)(rs->tx);
+ txw = *(u8 *)rs->tx;
else
- txw = *(u16 *)(rs->tx);
+ txw = *(u16 *)rs->tx;

writel_relaxed(txw, rs->regs + ROCKCHIP_SPI_TXDR);
rs->tx += rs->n_bytes;
@@ -302,46 +290,72 @@ static void rockchip_spi_pio_writer(struct rockchip_spi *rs)

static void rockchip_spi_pio_reader(struct rockchip_spi *rs)
{
- u32 max = rx_max(rs);
- u32 rxw;
+ u32 words = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR);
+ u32 rx_left = rs->rx_left - words;
+
+ /* the hardware doesn't allow us to change fifo threshold
+ * level while spi is enabled, so instead make sure to leave
+ * enough words in the rx fifo to get the last interrupt
+ * exactly when all words have been received
+ */
+ if (rx_left) {
+ u32 ftl = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFTLR) + 1;
+
+ if (rx_left < ftl) {
+ rx_left = ftl;
+ words = rs->rx_left - rx_left;
+ }
+ }
+
+ rs->rx_left = rx_left;
+ for (; words; words--) {
+ u32 rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
+
+ if (!rs->rx)
+ continue;

- while (max--) {
- rxw = readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
if (rs->n_bytes == 1)
- *(u8 *)(rs->rx) = (u8)rxw;
+ *(u8 *)rs->rx = (u8)rxw;
else
- *(u16 *)(rs->rx) = (u16)rxw;
+ *(u16 *)rs->rx = (u16)rxw;
rs->rx += rs->n_bytes;
}
}

-static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
+static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)
{
- int remain = 0;
+ struct spi_master *master = dev_id;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);

- spi_enable_chip(rs, true);
+ if (rs->tx_left)
+ rockchip_spi_pio_writer(rs);

- do {
- if (rs->tx) {
- remain = rs->tx_end - rs->tx;
- rockchip_spi_pio_writer(rs);
- }
+ rockchip_spi_pio_reader(rs);
+ if (!rs->rx_left) {
+ spi_enable_chip(rs, false);
+ writel_relaxed(0, rs->regs + ROCKCHIP_SPI_IMR);
+ spi_finalize_current_transfer(master);
+ }

- if (rs->rx) {
- remain = rs->rx_end - rs->rx;
- rockchip_spi_pio_reader(rs);
- }
+ return IRQ_HANDLED;
+}

- cpu_relax();
- } while (remain);
+static int rockchip_spi_prepare_irq(struct rockchip_spi *rs,
+ struct spi_transfer *xfer)
+{
+ rs->tx = xfer->tx_buf;
+ rs->rx = xfer->rx_buf;
+ rs->tx_left = rs->tx ? xfer->len / rs->n_bytes : 0;
+ rs->rx_left = xfer->len / rs->n_bytes;

- /* If tx, wait until the FIFO data completely. */
- if (rs->tx)
- wait_for_idle(rs);
+ writel_relaxed(INT_RF_FULL, rs->regs + ROCKCHIP_SPI_IMR);
+ spi_enable_chip(rs, true);

- spi_enable_chip(rs, false);
+ if (rs->tx_left)
+ rockchip_spi_pio_writer(rs);

- return 0;
+ /* 1 means the transfer is in progress */
+ return 1;
}

static void rockchip_spi_dma_rxcb(void *data)
@@ -465,7 +479,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
else if (xfer->rx_buf)
cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET;
- else
+ else if (use_dma)
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

if (use_dma) {
@@ -484,8 +498,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);

- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
- writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ /* unfortunately setting the fifo threshold level to generate an
+ * interrupt exactly when the fifo is full doesn't seem to work,
+ * so we need the strict inequality here
+ */
+ if (xfer->len < rs->fifo_len)
+ writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
+ else
+ writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);

writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_DMATDLR);
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
@@ -527,11 +547,6 @@ static int rockchip_spi_transfer_one(

rs->n_bytes = xfer->bits_per_word >> 3;

- rs->tx = xfer->tx_buf;
- rs->tx_end = rs->tx + xfer->len;
- rs->rx = xfer->rx_buf;
- rs->rx_end = rs->rx + xfer->len;
-
use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

rockchip_spi_config(rs, spi, xfer, use_dma);
@@ -539,7 +554,7 @@ static int rockchip_spi_transfer_one(
if (use_dma)
return rockchip_spi_prepare_dma(rs, master, xfer);

- return rockchip_spi_pio_transfer(rs);
+ return rockchip_spi_prepare_irq(rs, xfer);
}

static bool rockchip_spi_can_dma(struct spi_master *master,
@@ -547,8 +562,13 @@ static bool rockchip_spi_can_dma(struct spi_master *master,
struct spi_transfer *xfer)
{
struct rockchip_spi *rs = spi_master_get_devdata(master);
+ unsigned int bytes_per_word = xfer->bits_per_word <= 8 ? 1 : 2;

- return (xfer->len > rs->fifo_len);
+ /* if the numbor of spi words to transfer is less than the fifo
+ * length we can just fill the fifo and wait for a single irq,
+ * so don't bother setting up dma
+ */
+ return xfer->len / bytes_per_word >= rs->fifo_len;
}

static int rockchip_spi_probe(struct platform_device *pdev)
@@ -603,6 +623,15 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

+ ret = platform_get_irq(pdev, 0);
+ if (ret < 0)
+ goto err_disable_spiclk;
+
+ ret = devm_request_threaded_irq(&pdev->dev, ret, rockchip_spi_isr, NULL,
+ IRQF_ONESHOT, dev_name(&pdev->dev), master);
+ if (ret)
+ goto err_disable_spiclk;
+
rs->dev = &pdev->dev;
rs->freq = clk_get_rate(rs->spiclk);

--
2.19.0.rc2


2018-11-05 12:07:21

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: set min/max speed" to the spi tree

The patch

spi: rockchip: set min/max speed

has been applied to the spi tree at

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

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

From 420b82f842941a32adf309ca1b193adfc77616b0 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:07 +0100
Subject: [PATCH] spi: rockchip: set min/max speed

The driver previously checked each transfer if the
requested speed was higher than possible with the
current spi clock rate and raised the clock rate
accordingly.

However, there is no check to see if the spi clock
was actually set that high and no way to dynamically
lower the spi clock rate again.

So it seems any potiential users of this functionality
are better off just setting the spi clock rate at init
using the assigned-clock-rates devicetree property.

Removing this dynamic spi clock rate raising allows
us let the spi framework handle min/max speeds
for us.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 52 +++++++++++++++-----------------------
1 file changed, 20 insertions(+), 32 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index ba60cbcd45c2..d1b3ba2b1532 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -115,6 +115,10 @@
/* Bit fields in SER, 2bit */
#define SER_MASK 0x3

+/* Bit fields in BAUDR */
+#define BAUDR_SCKDV_MIN 2
+#define BAUDR_SCKDV_MAX 65534
+
/* Bit fields in SR, 5bit */
#define SR_MASK 0x1f
#define SR_BUSY (1 << 0)
@@ -147,7 +151,7 @@
#define TXDMA (1 << 1)

/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
-#define MAX_SCLK_OUT 50000000
+#define MAX_SCLK_OUT 50000000U

/*
* SPI_CTRLR1 is 16-bits, so we should support lengths of 0xffff + 1. However,
@@ -171,12 +175,11 @@ struct rockchip_spi {

/*depth of the FIFO buffer */
u32 fifo_len;
- /* max bus freq supported */
- u32 max_freq;
+ /* frequency of spiclk */
+ u32 freq;

u8 n_bytes;
u32 rsd_nsecs;
- u32 speed;

const void *tx;
const void *tx_end;
@@ -191,11 +194,6 @@ static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}

-static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
-{
- writel_relaxed(div, rs->regs + ROCKCHIP_SPI_BAUDR);
-}
-
static inline void wait_for_idle(struct rockchip_spi *rs)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
@@ -451,7 +449,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
bool use_dma)
{
- u32 div = 0;
u32 dmacr = 0;
int rsd = 0;

@@ -477,30 +474,17 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
dmacr |= RF_DMA_EN;
}

- if (WARN_ON(rs->speed > MAX_SCLK_OUT))
- rs->speed = MAX_SCLK_OUT;
-
- /* the minimum divisor is 2 */
- if (rs->max_freq < 2 * rs->speed) {
- clk_set_rate(rs->spiclk, 2 * rs->speed);
- rs->max_freq = clk_get_rate(rs->spiclk);
- }
-
- /* div doesn't support odd number */
- div = DIV_ROUND_UP(rs->max_freq, rs->speed);
- div = (div + 1) & 0xfffe;
-
/* Rx sample delay is expressed in parent clock cycles (max 3) */
- rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
+ rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->freq >> 8),
1000000000 >> 8);
if (!rsd && rs->rsd_nsecs) {
pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
- rs->max_freq, rs->rsd_nsecs);
+ rs->freq, rs->rsd_nsecs);
} else if (rsd > 3) {
rsd = 3;
pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
- rs->max_freq, rs->rsd_nsecs,
- rsd * 1000000000U / rs->max_freq);
+ rs->freq, rs->rsd_nsecs,
+ rsd * 1000000000U / rs->freq);
}
cr0 |= rsd << CR0_RSD_OFFSET;

@@ -520,9 +504,12 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR);
writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR);

- spi_set_clk(rs, div);
-
- dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div);
+ /* the hardware only supports an even clock divisor, so
+ * round divisor = spiclk / speed up to nearest even number
+ * so that the resulting speed is <= the requested speed
+ */
+ writel_relaxed(2 * DIV_ROUND_UP(rs->freq, 2 * xfer->speed_hz),
+ rs->regs + ROCKCHIP_SPI_BAUDR);
}

static size_t rockchip_spi_max_transfer_size(struct spi_device *spi)
@@ -551,7 +538,6 @@ static int rockchip_spi_transfer_one(
return -EINVAL;
}

- rs->speed = xfer->speed_hz;
rs->n_bytes = xfer->bits_per_word >> 3;

rs->tx = xfer->tx_buf;
@@ -631,7 +617,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
spi_enable_chip(rs, false);

rs->dev = &pdev->dev;
- rs->max_freq = clk_get_rate(rs->spiclk);
+ rs->freq = clk_get_rate(rs->spiclk);

if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
&rsd_nsecs))
@@ -653,6 +639,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ master->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
+ master->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);

master->set_cs = rockchip_spi_set_cs;
master->transfer_one = rockchip_spi_transfer_one;
--
2.19.0.rc2


2018-11-05 12:07:38

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: precompute rx sample delay" to the spi tree

The patch

spi: rockchip: precompute rx sample delay

has been applied to the spi tree at

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

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

From 74b7efa82b11914c21e30d987ed61d3daa57ff21 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:08 +0100
Subject: [PATCH] spi: rockchip: precompute rx sample delay

Now that we no longer potentially change spi clock
at runtime we can precompute the rx sample delay
at probe time rather than for each transfer.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index d1b3ba2b1532..5fe6099ff366 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -94,6 +94,7 @@
#define CR0_BHT_8BIT 0x1

#define CR0_RSD_OFFSET 14
+#define CR0_RSD_MAX 0x3

#define CR0_FRF_OFFSET 16
#define CR0_FRF_SPI 0x0
@@ -179,7 +180,7 @@ struct rockchip_spi {
u32 freq;

u8 n_bytes;
- u32 rsd_nsecs;
+ u8 rsd;

const void *tx;
const void *tx_end;
@@ -450,13 +451,13 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
bool use_dma)
{
u32 dmacr = 0;
- int rsd = 0;

u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
| CR0_SSD_ONE << CR0_SSD_OFFSET
| CR0_EM_BIG << CR0_EM_OFFSET;

+ cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;

@@ -474,20 +475,6 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
dmacr |= RF_DMA_EN;
}

- /* Rx sample delay is expressed in parent clock cycles (max 3) */
- rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->freq >> 8),
- 1000000000 >> 8);
- if (!rsd && rs->rsd_nsecs) {
- pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
- rs->freq, rs->rsd_nsecs);
- } else if (rsd > 3) {
- rsd = 3;
- pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
- rs->freq, rs->rsd_nsecs,
- rsd * 1000000000U / rs->freq);
- }
- cr0 |= rsd << CR0_RSD_OFFSET;
-
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);

if (rs->n_bytes == 1)
@@ -620,8 +607,21 @@ static int rockchip_spi_probe(struct platform_device *pdev)
rs->freq = clk_get_rate(rs->spiclk);

if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
- &rsd_nsecs))
- rs->rsd_nsecs = rsd_nsecs;
+ &rsd_nsecs)) {
+ /* rx sample delay is expressed in parent clock cycles (max 3) */
+ u32 rsd = DIV_ROUND_CLOSEST(rsd_nsecs * (rs->freq >> 8),
+ 1000000000 >> 8);
+ if (!rsd) {
+ dev_warn(rs->dev, "%u Hz are too slow to express %u ns delay\n",
+ rs->freq, rsd_nsecs);
+ } else if (rsd > CR0_RSD_MAX) {
+ rsd = CR0_RSD_MAX;
+ dev_warn(rs->dev, "%u Hz are too fast to express %u ns delay, clamping at %u ns\n",
+ rs->freq, rsd_nsecs,
+ CR0_RSD_MAX * 1000000000U / rs->freq);
+ }
+ rs->rsd = rsd;
+ }

rs->fifo_len = get_fifo_len(rs);
if (!rs->fifo_len) {
--
2.19.0.rc2


2018-11-05 12:07:41

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: simplify use_dma logic" to the spi tree

The patch

spi: rockchip: simplify use_dma logic

has been applied to the spi tree at

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

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

From eff0275e5253604429aedc42b008c5fcaa6cc597 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:06 +0100
Subject: [PATCH] spi: rockchip: simplify use_dma logic

We only need to know if we're using dma when setting
up the transfer, so just use a local variable for
that.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 45a1479c1a29..ba60cbcd45c2 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -184,8 +184,6 @@ struct rockchip_spi {
void *rx_end;

bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];
-
- bool use_dma;
};

static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
@@ -450,7 +448,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
}

static void rockchip_spi_config(struct rockchip_spi *rs,
- struct spi_device *spi, struct spi_transfer *xfer)
+ struct spi_device *spi, struct spi_transfer *xfer,
+ bool use_dma)
{
u32 div = 0;
u32 dmacr = 0;
@@ -471,7 +470,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

- if (rs->use_dma) {
+ if (use_dma) {
if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
if (xfer->rx_buf)
@@ -537,6 +536,7 @@ static int rockchip_spi_transfer_one(
struct spi_transfer *xfer)
{
struct rockchip_spi *rs = spi_master_get_devdata(master);
+ bool use_dma;

WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) &&
(readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY));
@@ -559,15 +559,11 @@ static int rockchip_spi_transfer_one(
rs->rx = xfer->rx_buf;
rs->rx_end = rs->rx + xfer->len;

- /* we need prepare dma before spi was enabled */
- if (master->can_dma && master->can_dma(master, spi, xfer))
- rs->use_dma = true;
- else
- rs->use_dma = false;
+ use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

- rockchip_spi_config(rs, spi, xfer);
+ rockchip_spi_config(rs, spi, xfer, use_dma);

- if (rs->use_dma)
+ if (use_dma)
return rockchip_spi_prepare_dma(rs, master, xfer);

return rockchip_spi_pio_transfer(rs);
--
2.19.0.rc2


2018-11-05 12:07:44

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: don't store dma channels twice" to the spi tree

The patch

spi: rockchip: don't store dma channels twice

has been applied to the spi tree at

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

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

From eee06a9ee2cd5deaddc5f77ce8f6118c8b82b2a0 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:04 +0100
Subject: [PATCH] spi: rockchip: don't store dma channels twice

The spi master (aka spi controller) structure already
has two fields for storing the rx and tx dma channels.
Just use them rather than duplicating them in driver data.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 76 +++++++++++++++++---------------------
1 file changed, 34 insertions(+), 42 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5edc51820d35..f3fe6d4cf6f6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -157,11 +157,6 @@

#define ROCKCHIP_SPI_MAX_CS_NUM 2

-struct rockchip_spi_dma_data {
- struct dma_chan *ch;
- dma_addr_t addr;
-};
-
struct rockchip_spi {
struct device *dev;
struct spi_master *master;
@@ -170,6 +165,8 @@ struct rockchip_spi {
struct clk *apb_pclk;

void __iomem *regs;
+ dma_addr_t dma_addr_rx;
+ dma_addr_t dma_addr_tx;

atomic_t state;

@@ -190,8 +187,6 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
- struct rockchip_spi_dma_data dma_rx;
- struct rockchip_spi_dma_data dma_tx;
};

static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
@@ -287,10 +282,10 @@ static void rockchip_spi_handle_err(struct spi_master *master,
spi_enable_chip(rs, false);

if (atomic_read(&rs->state) & TXDMA)
- dmaengine_terminate_async(rs->dma_tx.ch);
+ dmaengine_terminate_async(master->dma_tx);

if (atomic_read(&rs->state) & RXDMA)
- dmaengine_terminate_async(rs->dma_rx.ch);
+ dmaengine_terminate_async(master->dma_rx);
}

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
@@ -381,7 +376,7 @@ static void rockchip_spi_dma_txcb(void *data)
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
- struct spi_transfer *xfer)
+ struct spi_master *master, struct spi_transfer *xfer)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;

@@ -391,15 +386,15 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (xfer->rx_buf) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
- .src_addr = rs->dma_rx.addr,
+ .src_addr = rs->dma_addr_rx,
.src_addr_width = rs->n_bytes,
.src_maxburst = 1,
};

- dmaengine_slave_config(rs->dma_rx.ch, &rxconf);
+ dmaengine_slave_config(master->dma_rx, &rxconf);

rxdesc = dmaengine_prep_slave_sg(
- rs->dma_rx.ch,
+ master->dma_rx,
xfer->rx_sg.sgl, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc)
@@ -413,20 +408,20 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (xfer->tx_buf) {
struct dma_slave_config txconf = {
.direction = DMA_MEM_TO_DEV,
- .dst_addr = rs->dma_tx.addr,
+ .dst_addr = rs->dma_addr_tx,
.dst_addr_width = rs->n_bytes,
.dst_maxburst = rs->fifo_len / 2,
};

- dmaengine_slave_config(rs->dma_tx.ch, &txconf);
+ dmaengine_slave_config(master->dma_tx, &txconf);

txdesc = dmaengine_prep_slave_sg(
- rs->dma_tx.ch,
+ master->dma_tx,
xfer->tx_sg.sgl, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
- dmaengine_terminate_sync(rs->dma_rx.ch);
+ dmaengine_terminate_sync(master->dma_rx);
return -EINVAL;
}

@@ -438,7 +433,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (rxdesc) {
atomic_or(RXDMA, &rs->state);
dmaengine_submit(rxdesc);
- dma_async_issue_pending(rs->dma_rx.ch);
+ dma_async_issue_pending(master->dma_rx);
}

spi_enable_chip(rs, true);
@@ -446,7 +441,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
if (txdesc) {
atomic_or(TXDMA, &rs->state);
dmaengine_submit(txdesc);
- dma_async_issue_pending(rs->dma_tx.ch);
+ dma_async_issue_pending(master->dma_tx);
}

/* 1 means the transfer is in progress */
@@ -572,7 +567,7 @@ static int rockchip_spi_transfer_one(
rockchip_spi_config(rs, spi, xfer);

if (rs->use_dma)
- return rockchip_spi_prepare_dma(rs, xfer);
+ return rockchip_spi_prepare_dma(rs, master, xfer);

return rockchip_spi_pio_transfer(rs);
}
@@ -669,34 +664,31 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->handle_err = rockchip_spi_handle_err;
master->flags = SPI_MASTER_GPIO_SS;

- rs->dma_tx.ch = dma_request_chan(rs->dev, "tx");
- if (IS_ERR(rs->dma_tx.ch)) {
+ master->dma_tx = dma_request_chan(rs->dev, "tx");
+ if (IS_ERR(master->dma_tx)) {
/* Check tx to see if we need defer probing driver */
- if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
+ if (PTR_ERR(master->dma_tx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_disable_pm_runtime;
}
dev_warn(rs->dev, "Failed to request TX DMA channel\n");
- rs->dma_tx.ch = NULL;
+ master->dma_tx = NULL;
}

- rs->dma_rx.ch = dma_request_chan(rs->dev, "rx");
- if (IS_ERR(rs->dma_rx.ch)) {
- if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) {
+ master->dma_rx = dma_request_chan(rs->dev, "rx");
+ if (IS_ERR(master->dma_rx)) {
+ if (PTR_ERR(master->dma_rx) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto err_free_dma_tx;
}
dev_warn(rs->dev, "Failed to request RX DMA channel\n");
- rs->dma_rx.ch = NULL;
+ master->dma_rx = NULL;
}

- if (rs->dma_tx.ch && rs->dma_rx.ch) {
- rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR);
- rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR);
-
+ if (master->dma_tx && master->dma_rx) {
+ rs->dma_addr_tx = mem->start + ROCKCHIP_SPI_TXDR;
+ rs->dma_addr_rx = mem->start + ROCKCHIP_SPI_RXDR;
master->can_dma = rockchip_spi_can_dma;
- master->dma_tx = rs->dma_tx.ch;
- master->dma_rx = rs->dma_rx.ch;
}

ret = devm_spi_register_master(&pdev->dev, master);
@@ -708,11 +700,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
return 0;

err_free_dma_rx:
- if (rs->dma_rx.ch)
- dma_release_channel(rs->dma_rx.ch);
+ if (master->dma_rx)
+ dma_release_channel(master->dma_rx);
err_free_dma_tx:
- if (rs->dma_tx.ch)
- dma_release_channel(rs->dma_tx.ch);
+ if (master->dma_tx)
+ dma_release_channel(master->dma_tx);
err_disable_pm_runtime:
pm_runtime_disable(&pdev->dev);
err_disable_spiclk:
@@ -739,10 +731,10 @@ static int rockchip_spi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);

- if (rs->dma_tx.ch)
- dma_release_channel(rs->dma_tx.ch);
- if (rs->dma_rx.ch)
- dma_release_channel(rs->dma_rx.ch);
+ if (master->dma_tx)
+ dma_release_channel(master->dma_tx);
+ if (master->dma_rx)
+ dma_release_channel(master->dma_rx);

spi_master_put(master);

--
2.19.0.rc2


2018-11-05 12:07:52

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: read transfer info directly" to the spi tree

The patch

spi: rockchip: read transfer info directly

has been applied to the spi tree at

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

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

From fc1ad8ee33480bdf0493b54907b74538bf9b75b8 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:03 +0100
Subject: [PATCH] spi: rockchip: read transfer info directly

Just read transfer info directly from the spi device
and transfer structures rather than storing it in
driver data first.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 70 +++++++++++++-------------------------
1 file changed, 24 insertions(+), 46 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 5729e6071729..5edc51820d35 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -178,12 +178,8 @@ struct rockchip_spi {
/* max bus freq supported */
u32 max_freq;

- u16 mode;
- u8 tmode;
- u8 bpw;
u8 n_bytes;
u32 rsd_nsecs;
- unsigned len;
u32 speed;

const void *tx;
@@ -194,8 +190,6 @@ struct rockchip_spi {
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
- struct sg_table tx_sg;
- struct sg_table rx_sg;
struct rockchip_spi_dma_data dma_rx;
struct rockchip_spi_dma_data dma_tx;
};
@@ -282,17 +276,6 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
rs->cs_asserted[spi->chip_select] = cs_asserted;
}

-static int rockchip_spi_prepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct rockchip_spi *rs = spi_master_get_devdata(master);
- struct spi_device *spi = msg->spi;
-
- rs->mode = spi->mode;
-
- return 0;
-}
-
static void rockchip_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
@@ -397,14 +380,15 @@ static void rockchip_spi_dma_txcb(void *data)
spi_finalize_current_transfer(rs->master);
}

-static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
+static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
+ struct spi_transfer *xfer)
{
struct dma_async_tx_descriptor *rxdesc, *txdesc;

atomic_set(&rs->state, 0);

rxdesc = NULL;
- if (rs->rx) {
+ if (xfer->rx_buf) {
struct dma_slave_config rxconf = {
.direction = DMA_DEV_TO_MEM,
.src_addr = rs->dma_rx.addr,
@@ -416,7 +400,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

rxdesc = dmaengine_prep_slave_sg(
rs->dma_rx.ch,
- rs->rx_sg.sgl, rs->rx_sg.nents,
+ xfer->rx_sg.sgl, xfer->rx_sg.nents,
DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!rxdesc)
return -EINVAL;
@@ -426,7 +410,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
}

txdesc = NULL;
- if (rs->tx) {
+ if (xfer->tx_buf) {
struct dma_slave_config txconf = {
.direction = DMA_MEM_TO_DEV,
.dst_addr = rs->dma_tx.addr,
@@ -438,7 +422,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

txdesc = dmaengine_prep_slave_sg(
rs->dma_tx.ch,
- rs->tx_sg.sgl, rs->tx_sg.nents,
+ xfer->tx_sg.sgl, xfer->tx_sg.nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!txdesc) {
if (rxdesc)
@@ -469,7 +453,8 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
return 1;
}

-static void rockchip_spi_config(struct rockchip_spi *rs)
+static void rockchip_spi_config(struct rockchip_spi *rs,
+ struct spi_device *spi, struct spi_transfer *xfer)
{
u32 div = 0;
u32 dmacr = 0;
@@ -481,13 +466,19 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
| CR0_EM_BIG << CR0_EM_OFFSET;

cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
- cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
- cr0 |= (rs->tmode << CR0_XFM_OFFSET);
+ cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+
+ if (xfer->rx_buf && xfer->tx_buf)
+ cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
+ else if (xfer->rx_buf)
+ cr0 |= CR0_XFM_RO << CR0_XFM_OFFSET;
+ else
+ cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

if (rs->use_dma) {
- if (rs->tx)
+ if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
- if (rs->rx)
+ if (xfer->rx_buf)
dmacr |= RF_DMA_EN;
}

@@ -521,11 +512,11 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);

if (rs->n_bytes == 1)
- writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else if (rs->n_bytes == 2)
- writel_relaxed((rs->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed((xfer->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
else
- writel_relaxed((rs->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);

writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR);
writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR);
@@ -565,24 +556,12 @@ static int rockchip_spi_transfer_one(
}

rs->speed = xfer->speed_hz;
- rs->bpw = xfer->bits_per_word;
- rs->n_bytes = rs->bpw >> 3;
+ rs->n_bytes = xfer->bits_per_word >> 3;

rs->tx = xfer->tx_buf;
rs->tx_end = rs->tx + xfer->len;
rs->rx = xfer->rx_buf;
rs->rx_end = rs->rx + xfer->len;
- rs->len = xfer->len;
-
- rs->tx_sg = xfer->tx_sg;
- rs->rx_sg = xfer->rx_sg;
-
- if (rs->tx && rs->rx)
- rs->tmode = CR0_XFM_TR;
- else if (rs->tx)
- rs->tmode = CR0_XFM_TO;
- else if (rs->rx)
- rs->tmode = CR0_XFM_RO;

/* we need prepare dma before spi was enabled */
if (master->can_dma && master->can_dma(master, spi, xfer))
@@ -590,10 +569,10 @@ static int rockchip_spi_transfer_one(
else
rs->use_dma = false;

- rockchip_spi_config(rs);
+ rockchip_spi_config(rs, spi, xfer);

if (rs->use_dma)
- return rockchip_spi_prepare_dma(rs);
+ return rockchip_spi_prepare_dma(rs, xfer);

return rockchip_spi_pio_transfer(rs);
}
@@ -685,7 +664,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);

master->set_cs = rockchip_spi_set_cs;
- master->prepare_message = rockchip_spi_prepare_message;
master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err;
--
2.19.0.rc2


2018-11-05 12:07:56

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: use atomic_t state" to the spi tree

The patch

spi: rockchip: use atomic_t state

has been applied to the spi tree at

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

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

From fab3e4871f623c8f86e8a0e00749f1480ffa08db Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:01 +0100
Subject: [PATCH] spi: rockchip: use atomic_t state

The state field is currently only used to make sure
only the last of the tx and rx dma callbacks issue
an spi_finalize_current_transfer.
Rather than using a spinlock we can get away
with just turning the state field into an atomic_t.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 75 +++++++++++++-------------------------
1 file changed, 25 insertions(+), 50 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 7fac4253075e..1c813797f963 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -142,8 +142,9 @@
#define RF_DMA_EN (1 << 0)
#define TF_DMA_EN (1 << 1)

-#define RXBUSY (1 << 0)
-#define TXBUSY (1 << 1)
+/* Driver state flags */
+#define RXDMA (1 << 0)
+#define TXDMA (1 << 1)

/* sclk_out: spi master internal logic in rk3x can support 50Mhz */
#define MAX_SCLK_OUT 50000000
@@ -169,6 +170,9 @@ struct rockchip_spi {
struct clk *apb_pclk;

void __iomem *regs;
+
+ atomic_t state;
+
/*depth of the FIFO buffer */
u32 fifo_len;
/* max bus freq supported */
@@ -187,10 +191,6 @@ struct rockchip_spi {
void *rx;
void *rx_end;

- u32 state;
- /* protect state */
- spinlock_t lock;
-
bool cs_asserted[ROCKCHIP_SPI_MAX_CS_NUM];

bool use_dma;
@@ -302,28 +302,21 @@ static int rockchip_spi_prepare_message(struct spi_master *master,
static void rockchip_spi_handle_err(struct spi_master *master,
struct spi_message *msg)
{
- unsigned long flags;
struct rockchip_spi *rs = spi_master_get_devdata(master);

- spin_lock_irqsave(&rs->lock, flags);
-
/*
* For DMA mode, we need terminate DMA channel and flush
* fifo for the next transfer if DMA thansfer timeout.
* handle_err() was called by core if transfer failed.
* Maybe it is reasonable for error handling here.
*/
- if (rs->use_dma) {
- if (rs->state & RXBUSY) {
- dmaengine_terminate_async(rs->dma_rx.ch);
- flush_fifo(rs);
- }
+ if (atomic_read(&rs->state) & TXDMA)
+ dmaengine_terminate_async(rs->dma_tx.ch);

- if (rs->state & TXBUSY)
- dmaengine_terminate_async(rs->dma_tx.ch);
+ if (atomic_read(&rs->state) & RXDMA) {
+ dmaengine_terminate_async(rs->dma_rx.ch);
+ flush_fifo(rs);
}
-
- spin_unlock_irqrestore(&rs->lock, flags);
}

static int rockchip_spi_unprepare_message(struct spi_master *master,
@@ -398,48 +391,36 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)

static void rockchip_spi_dma_rxcb(void *data)
{
- unsigned long flags;
struct rockchip_spi *rs = data;
+ int state = atomic_fetch_andnot(RXDMA, &rs->state);

- spin_lock_irqsave(&rs->lock, flags);
-
- rs->state &= ~RXBUSY;
- if (!(rs->state & TXBUSY)) {
- spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
- }
+ if (state & TXDMA)
+ return;

- spin_unlock_irqrestore(&rs->lock, flags);
+ spi_enable_chip(rs, false);
+ spi_finalize_current_transfer(rs->master);
}

static void rockchip_spi_dma_txcb(void *data)
{
- unsigned long flags;
struct rockchip_spi *rs = data;
+ int state = atomic_fetch_andnot(TXDMA, &rs->state);
+
+ if (state & RXDMA)
+ return;

/* Wait until the FIFO data completely. */
wait_for_idle(rs);

- spin_lock_irqsave(&rs->lock, flags);
-
- rs->state &= ~TXBUSY;
- if (!(rs->state & RXBUSY)) {
- spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
- }
-
- spin_unlock_irqrestore(&rs->lock, flags);
+ spi_enable_chip(rs, false);
+ spi_finalize_current_transfer(rs->master);
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
- unsigned long flags;
struct dma_async_tx_descriptor *rxdesc, *txdesc;

- spin_lock_irqsave(&rs->lock, flags);
- rs->state &= ~RXBUSY;
- rs->state &= ~TXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_set(&rs->state, 0);

rxdesc = NULL;
if (rs->rx) {
@@ -490,9 +471,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

/* rx must be started before tx due to spi instinct */
if (rxdesc) {
- spin_lock_irqsave(&rs->lock, flags);
- rs->state |= RXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_or(RXDMA, &rs->state);
dmaengine_submit(rxdesc);
dma_async_issue_pending(rs->dma_rx.ch);
}
@@ -500,9 +479,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
spi_enable_chip(rs, true);

if (txdesc) {
- spin_lock_irqsave(&rs->lock, flags);
- rs->state |= TXBUSY;
- spin_unlock_irqrestore(&rs->lock, flags);
+ atomic_or(TXDMA, &rs->state);
dmaengine_submit(txdesc);
dma_async_issue_pending(rs->dma_tx.ch);
}
@@ -716,8 +693,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto err_disable_spiclk;
}

- spin_lock_init(&rs->lock);
-
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);

--
2.19.0.rc2


2018-11-05 12:08:01

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: always use SPI mode" to the spi tree

The patch

spi: rockchip: always use SPI mode

has been applied to the spi tree at

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

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

From 2410d6a3c3070e205169a1a741aa78898e30a642 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:00 +0100
Subject: [PATCH] spi: rockchip: always use SPI mode

The hardware supports 3 different variants of SPI
and there were some code around it, but nothing
to actually set it to anything but "Motorola SPI".
Just drop that code and always use that mode.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 17 ++++-------------
1 file changed, 4 insertions(+), 13 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 87d1b9837d94..7fac4253075e 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -156,12 +156,6 @@

#define ROCKCHIP_SPI_MAX_CS_NUM 2

-enum rockchip_ssi_type {
- SSI_MOTO_SPI = 0,
- SSI_TI_SSP,
- SSI_NS_MICROWIRE,
-};
-
struct rockchip_spi_dma_data {
struct dma_chan *ch;
dma_addr_t addr;
@@ -179,8 +173,6 @@ struct rockchip_spi {
u32 fifo_len;
/* max bus freq supported */
u32 max_freq;
- /* supported slave numbers */
- enum rockchip_ssi_type type;

u16 mode;
u8 tmode;
@@ -525,14 +517,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
u32 dmacr = 0;
int rsd = 0;

- u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
- | (CR0_SSD_ONE << CR0_SSD_OFFSET)
- | (CR0_EM_BIG << CR0_EM_OFFSET);
+ u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
+ | CR0_BHT_8BIT << CR0_BHT_OFFSET
+ | CR0_SSD_ONE << CR0_SSD_OFFSET
+ | CR0_EM_BIG << CR0_EM_OFFSET;

cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
cr0 |= (rs->tmode << CR0_XFM_OFFSET);
- cr0 |= (rs->type << CR0_FRF_OFFSET);

if (rs->use_dma) {
if (rs->tx)
@@ -709,7 +701,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

- rs->type = SSI_MOTO_SPI;
rs->master = master;
rs->dev = &pdev->dev;
rs->max_freq = clk_get_rate(rs->spiclk);
--
2.19.0.rc2


2018-11-05 12:08:04

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: make spi_enable_chip take bool" to the spi tree

The patch

spi: rockchip: make spi_enable_chip take bool

has been applied to the spi tree at

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

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

From 30688e4e670d21126aa596df4523940e2f8d24de Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:56:58 +0100
Subject: [PATCH] spi: rockchip: make spi_enable_chip take bool

The spi_enable_chip function takes a boolean
argument. Change the type to reflect that.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 51ef632bca52..7e54e1a69cc8 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -208,9 +208,9 @@ struct rockchip_spi {
struct rockchip_spi_dma_data dma_tx;
};

-static inline void spi_enable_chip(struct rockchip_spi *rs, int enable)
+static inline void spi_enable_chip(struct rockchip_spi *rs, bool enable)
{
- writel_relaxed((enable ? 1 : 0), rs->regs + ROCKCHIP_SPI_SSIENR);
+ writel_relaxed((enable ? 1U : 0U), rs->regs + ROCKCHIP_SPI_SSIENR);
}

static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
@@ -339,7 +339,7 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,
{
struct rockchip_spi *rs = spi_master_get_devdata(master);

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

return 0;
}
@@ -379,7 +379,7 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
{
int remain = 0;

- spi_enable_chip(rs, 1);
+ spi_enable_chip(rs, true);

do {
if (rs->tx) {
@@ -399,7 +399,7 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)
if (rs->tx)
wait_for_idle(rs);

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

return 0;
}
@@ -413,7 +413,7 @@ static void rockchip_spi_dma_rxcb(void *data)

rs->state &= ~RXBUSY;
if (!(rs->state & TXBUSY)) {
- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);
spi_finalize_current_transfer(rs->master);
}

@@ -432,7 +432,7 @@ static void rockchip_spi_dma_txcb(void *data)

rs->state &= ~TXBUSY;
if (!(rs->state & RXBUSY)) {
- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);
spi_finalize_current_transfer(rs->master);
}

@@ -503,7 +503,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_rx.ch);
}

- spi_enable_chip(rs, 1);
+ spi_enable_chip(rs, true);

if (txdesc) {
spin_lock_irqsave(&rs->lock, flags);
@@ -705,7 +705,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
goto err_disable_apbclk;
}

- spi_enable_chip(rs, 0);
+ spi_enable_chip(rs, false);

rs->type = SSI_MOTO_SPI;
rs->master = master;
--
2.19.0.rc2


2018-11-05 12:08:27

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: disable spi on error" to the spi tree

The patch

spi: rockchip: disable spi on error

has been applied to the spi tree at

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

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

From ce386100d99976442093ff57b5b24a9562c6cc27 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:02 +0100
Subject: [PATCH] spi: rockchip: disable spi on error

Successful transfers leave the spi disabled, so if
we just make sure to disable the spi on error
there should be no need to disable the spi from
master->unprepare_message.

This also flushes the tx and rx fifos,
so no need to do that manually.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 30 +++++-------------------------
1 file changed, 5 insertions(+), 25 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1c813797f963..5729e6071729 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -210,12 +210,6 @@ static inline void spi_set_clk(struct rockchip_spi *rs, u16 div)
writel_relaxed(div, rs->regs + ROCKCHIP_SPI_BAUDR);
}

-static inline void flush_fifo(struct rockchip_spi *rs)
-{
- while (readl_relaxed(rs->regs + ROCKCHIP_SPI_RXFLR))
- readl_relaxed(rs->regs + ROCKCHIP_SPI_RXDR);
-}
-
static inline void wait_for_idle(struct rockchip_spi *rs)
{
unsigned long timeout = jiffies + msecs_to_jiffies(5);
@@ -304,29 +298,16 @@ static void rockchip_spi_handle_err(struct spi_master *master,
{
struct rockchip_spi *rs = spi_master_get_devdata(master);

- /*
- * For DMA mode, we need terminate DMA channel and flush
- * fifo for the next transfer if DMA thansfer timeout.
- * handle_err() was called by core if transfer failed.
- * Maybe it is reasonable for error handling here.
+ /* stop running spi transfer
+ * this also flushes both rx and tx fifos
*/
+ spi_enable_chip(rs, false);
+
if (atomic_read(&rs->state) & TXDMA)
dmaengine_terminate_async(rs->dma_tx.ch);

- if (atomic_read(&rs->state) & RXDMA) {
+ if (atomic_read(&rs->state) & RXDMA)
dmaengine_terminate_async(rs->dma_rx.ch);
- flush_fifo(rs);
- }
-}
-
-static int rockchip_spi_unprepare_message(struct spi_master *master,
- struct spi_message *msg)
-{
- struct rockchip_spi *rs = spi_master_get_devdata(master);
-
- spi_enable_chip(rs, false);
-
- return 0;
}

static void rockchip_spi_pio_writer(struct rockchip_spi *rs)
@@ -705,7 +686,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

master->set_cs = rockchip_spi_set_cs;
master->prepare_message = rockchip_spi_prepare_message;
- master->unprepare_message = rockchip_spi_unprepare_message;
master->transfer_one = rockchip_spi_transfer_one;
master->max_transfer_size = rockchip_spi_max_transfer_size;
master->handle_err = rockchip_spi_handle_err;
--
2.19.0.rc2


2018-11-05 12:08:28

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: support 4bit words" to the spi tree

The patch

spi: rockchip: support 4bit words

has been applied to the spi tree at

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

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

From 65498c6ae2414a1425aa6c4231e79e2998afec05 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:10 +0100
Subject: [PATCH] spi: rockchip: support 4bit words

The hardware supports 4, 8 and 16bit spi words,
so add the missing support for 4bit words.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 41 +++++++++++++++++++++++++++-----------
1 file changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 1297f081818d..9e47e81553a1 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -54,6 +54,9 @@

/* Bit fields in CTRLR0 */
#define CR0_DFS_OFFSET 0
+#define CR0_DFS_4BIT 0x0
+#define CR0_DFS_8BIT 0x1
+#define CR0_DFS_16BIT 0x2

#define CR0_CFS_OFFSET 2

@@ -464,15 +467,14 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
struct spi_device *spi, struct spi_transfer *xfer,
bool use_dma)
{
- u32 dmacr = 0;
-
u32 cr0 = CR0_FRF_SPI << CR0_FRF_OFFSET
| CR0_BHT_8BIT << CR0_BHT_OFFSET
| CR0_SSD_ONE << CR0_SSD_OFFSET
| CR0_EM_BIG << CR0_EM_OFFSET;
+ u32 cr1;
+ u32 dmacr = 0;

cr0 |= rs->rsd << CR0_RSD_OFFSET;
- cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;

if (xfer->rx_buf && xfer->tx_buf)
@@ -482,6 +484,27 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
else if (use_dma)
cr0 |= CR0_XFM_TO << CR0_XFM_OFFSET;

+ switch (xfer->bits_per_word) {
+ case 4:
+ cr0 |= CR0_DFS_4BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len - 1;
+ break;
+ case 8:
+ cr0 |= CR0_DFS_8BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len - 1;
+ break;
+ case 16:
+ cr0 |= CR0_DFS_16BIT << CR0_DFS_OFFSET;
+ cr1 = xfer->len / 2 - 1;
+ break;
+ default:
+ /* we only whitelist 4, 8 and 16 bit words in
+ * master->bits_per_word_mask, so this shouldn't
+ * happen
+ */
+ unreachable();
+ }
+
if (use_dma) {
if (xfer->tx_buf)
dmacr |= TF_DMA_EN;
@@ -490,13 +513,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs,
}

writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
-
- if (rs->n_bytes == 1)
- writel_relaxed(xfer->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
- else if (rs->n_bytes == 2)
- writel_relaxed((xfer->len / 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
- else
- writel_relaxed((xfer->len * 2) - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
+ writel_relaxed(cr1, rs->regs + ROCKCHIP_SPI_CTRLR1);

/* unfortunately setting the fifo threshold level to generate an
* interrupt exactly when the fifo is full doesn't seem to work,
@@ -545,7 +562,7 @@ static int rockchip_spi_transfer_one(
return -EINVAL;
}

- rs->n_bytes = xfer->bits_per_word >> 3;
+ rs->n_bytes = xfer->bits_per_word <= 8 ? 1 : 2;

use_dma = master->can_dma ? master->can_dma(master, spi, xfer) : false;

@@ -667,7 +684,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
- master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
+ master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
master->min_speed_hz = rs->freq / BAUDR_SCKDV_MAX;
master->max_speed_hz = min(rs->freq / BAUDR_SCKDV_MIN, MAX_SCLK_OUT);

--
2.19.0.rc2


2018-11-05 12:08:59

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: support lsb-first mode" to the spi tree

The patch

spi: rockchip: support lsb-first mode

has been applied to the spi tree at

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

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

From 04290192f7ebe892828f69ac57c4684e25da378d Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:11 +0100
Subject: [PATCH] spi: rockchip: support lsb-first mode

Add missing support for lsb-first mode.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 9e47e81553a1..3912526ead66 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -476,6 +476,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs,

cr0 |= rs->rsd << CR0_RSD_OFFSET;
cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET;
+ if (spi->mode & SPI_LSB_FIRST)
+ cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET;

if (xfer->rx_buf && xfer->tx_buf)
cr0 |= CR0_XFM_TR << CR0_XFM_OFFSET;
@@ -681,7 +683,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)

master->auto_runtime_pm = true;
master->bus_num = pdev->id;
- master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP | SPI_LSB_FIRST;
master->num_chipselect = ROCKCHIP_SPI_MAX_CS_NUM;
master->dev.of_node = pdev->dev.of_node;
master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8) | SPI_BPW_MASK(4);
--
2.19.0.rc2


2018-11-05 12:09:17

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: use designated init for dma config" to the spi tree

The patch

spi: rockchip: use designated init for dma config

has been applied to the spi tree at

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

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

From 31bcb57be12fd815a9051f07d64334809b8cb472 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:56:59 +0100
Subject: [PATCH] spi: rockchip: use designated init for dma config

Use C99 designated initializers for dma slave config
structures. This also makes sure uninitialized fields
are zeroed so we don't need an explicit memset.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 26 ++++++++++++++------------
1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 7e54e1a69cc8..87d1b9837d94 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -442,12 +442,8 @@ static void rockchip_spi_dma_txcb(void *data)
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
unsigned long flags;
- struct dma_slave_config rxconf, txconf;
struct dma_async_tx_descriptor *rxdesc, *txdesc;

- memset(&rxconf, 0, sizeof(rxconf));
- memset(&txconf, 0, sizeof(txconf));
-
spin_lock_irqsave(&rs->lock, flags);
rs->state &= ~RXBUSY;
rs->state &= ~TXBUSY;
@@ -455,10 +451,13 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

rxdesc = NULL;
if (rs->rx) {
- rxconf.direction = DMA_DEV_TO_MEM;
- rxconf.src_addr = rs->dma_rx.addr;
- rxconf.src_addr_width = rs->n_bytes;
- rxconf.src_maxburst = 1;
+ struct dma_slave_config rxconf = {
+ .direction = DMA_DEV_TO_MEM,
+ .src_addr = rs->dma_rx.addr,
+ .src_addr_width = rs->n_bytes,
+ .src_maxburst = 1,
+ };
+
dmaengine_slave_config(rs->dma_rx.ch, &rxconf);

rxdesc = dmaengine_prep_slave_sg(
@@ -474,10 +473,13 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)

txdesc = NULL;
if (rs->tx) {
- txconf.direction = DMA_MEM_TO_DEV;
- txconf.dst_addr = rs->dma_tx.addr;
- txconf.dst_addr_width = rs->n_bytes;
- txconf.dst_maxburst = rs->fifo_len / 2;
+ struct dma_slave_config txconf = {
+ .direction = DMA_MEM_TO_DEV,
+ .dst_addr = rs->dma_tx.addr,
+ .dst_addr_width = rs->n_bytes,
+ .dst_maxburst = rs->fifo_len / 2,
+ };
+
dmaengine_slave_config(rs->dma_tx.ch, &txconf);

txdesc = dmaengine_prep_slave_sg(
--
2.19.0.rc2


2018-11-05 12:09:53

by Mark Brown

[permalink] [raw]
Subject: Applied "spi: rockchip: remove master pointer from dev data" to the spi tree

The patch

spi: rockchip: remove master pointer from dev data

has been applied to the spi tree at

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

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

From d790c342e689ea77a5cf72d5b993299911ee5276 Mon Sep 17 00:00:00 2001
From: Emil Renner Berthing <[email protected]>
Date: Wed, 31 Oct 2018 11:57:05 +0100
Subject: [PATCH] spi: rockchip: remove master pointer from dev data

In almost all cases we already have a pointer to the
spi master structure where we have the driver data.

The only exceptions are the dma callbacks which are
easily fixed by passing them the master and using
spi_master_get_devdata to retrieve the driver data.

Signed-off-by: Emil Renner Berthing <[email protected]>
Tested-by: Heiko Stuebner <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-rockchip.c | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index f3fe6d4cf6f6..45a1479c1a29 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -159,7 +159,6 @@

struct rockchip_spi {
struct device *dev;
- struct spi_master *master;

struct clk *spiclk;
struct clk *apb_pclk;
@@ -350,19 +349,21 @@ static int rockchip_spi_pio_transfer(struct rockchip_spi *rs)

static void rockchip_spi_dma_rxcb(void *data)
{
- struct rockchip_spi *rs = data;
+ struct spi_master *master = data;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);
int state = atomic_fetch_andnot(RXDMA, &rs->state);

if (state & TXDMA)
return;

spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
+ spi_finalize_current_transfer(master);
}

static void rockchip_spi_dma_txcb(void *data)
{
- struct rockchip_spi *rs = data;
+ struct spi_master *master = data;
+ struct rockchip_spi *rs = spi_master_get_devdata(master);
int state = atomic_fetch_andnot(TXDMA, &rs->state);

if (state & RXDMA)
@@ -372,7 +373,7 @@ static void rockchip_spi_dma_txcb(void *data)
wait_for_idle(rs);

spi_enable_chip(rs, false);
- spi_finalize_current_transfer(rs->master);
+ spi_finalize_current_transfer(master);
}

static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
@@ -401,7 +402,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
return -EINVAL;

rxdesc->callback = rockchip_spi_dma_rxcb;
- rxdesc->callback_param = rs;
+ rxdesc->callback_param = master;
}

txdesc = NULL;
@@ -426,7 +427,7 @@ static int rockchip_spi_prepare_dma(struct rockchip_spi *rs,
}

txdesc->callback = rockchip_spi_dma_txcb;
- txdesc->callback_param = rs;
+ txdesc->callback_param = master;
}

/* rx must be started before tx due to spi instinct */
@@ -633,7 +634,6 @@ static int rockchip_spi_probe(struct platform_device *pdev)

spi_enable_chip(rs, false);

- rs->master = master;
rs->dev = &pdev->dev;
rs->max_freq = clk_get_rate(rs->spiclk);

@@ -746,9 +746,8 @@ static int rockchip_spi_suspend(struct device *dev)
{
int ret;
struct spi_master *master = dev_get_drvdata(dev);
- struct rockchip_spi *rs = spi_master_get_devdata(master);

- ret = spi_master_suspend(rs->master);
+ ret = spi_master_suspend(master);
if (ret < 0)
return ret;

@@ -773,7 +772,7 @@ static int rockchip_spi_resume(struct device *dev)
if (ret < 0)
return ret;

- ret = spi_master_resume(rs->master);
+ ret = spi_master_resume(master);
if (ret < 0) {
clk_disable_unprepare(rs->spiclk);
clk_disable_unprepare(rs->apb_pclk);
--
2.19.0.rc2