aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVladimir Barinov <vladimir.barinov@cogentembedded.com>2017-12-10 23:51:43 +0300
committerVladimir Barinov <vladimir.barinov@cogentembedded.com>2017-12-10 23:51:43 +0300
commit157552575a14a71b923821641551c98df94055f3 (patch)
tree2003978701637f51726844b154226ece01d40856
parent47bbe76d08109fb77ced2ce98ec734cb7740792e (diff)
DMAC fixes
- Backport RCAR DMAC fixes from upstream - Reeneable DMA for SCIF0 on R8A7797
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch4
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0080-dmaengine-rcar-dmac-ensure-CHCR-DE-bit-is-actually-0.patch87
-rw-r--r--meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0081-dmaengine-rcar-dmac-use-TCRB-instead-of-TCR-for-resi.patch108
3 files changed, 197 insertions, 2 deletions
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
index 68570b3..d6726a3 100644
--- a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0018-arm64-renesas-r8a7797-Add-Renesas-R8A7797-SoC-suppor.patch
@@ -696,8 +696,8 @@ index 0000000..6eaa5ba
+ <&scif_clk>; /* RMSTPCR2/bit7:SCIF0 */
+ /*clock-names = "fck", "sck", "brg_int", "scif_clk"; */
+ clock-names = "fck";
-+// dmas = <&dmac1 0x51>, <&dmac1 0x50>;
-+// dma-names = "tx", "rx";
++ dmas = <&dmac1 0x51>, <&dmac1 0x50>;
++ dma-names = "tx", "rx";
+ power-domains = <&sysc R8A7797_PD_ALWAYS_ON>;
+ status = "disabled";
+ };
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0080-dmaengine-rcar-dmac-ensure-CHCR-DE-bit-is-actually-0.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0080-dmaengine-rcar-dmac-ensure-CHCR-DE-bit-is-actually-0.patch
new file mode 100644
index 0000000..e1597ea
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0080-dmaengine-rcar-dmac-ensure-CHCR-DE-bit-is-actually-0.patch
@@ -0,0 +1,87 @@
+From a8d46a7f5d17ca9cbe9e9c7d1d23dc6ea437e141 Mon Sep 17 00:00:00 2001
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Date: Fri, 17 Nov 2017 11:00:28 +0900
+Subject: [PATCH 1/2] dmaengine: rcar-dmac: ensure CHCR DE bit is actually 0
+ after clearing
+
+DMAC reads data from source device, and buffered it until transferable
+size for sink device. Because of this behavior, DMAC is including
+buffered data .
+
+Now, CHCR DE bit is controlling DMA transfer enable/disable.
+
+If DE bit was cleared during data transferring, or during buffering,
+it will flush buffered data if source device was peripheral device
+(The buffered data will be removed if source device was memory).
+Because of this behavior, driver should ensure that DE bit is actually
+0 after clearing.
+
+This patch adds new rcar_dmac_chcr_de_barrier() and call it after CHCR
+register access.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
+Tested-by: Ryo Kodama <ryo.kodama.vz@renesas.com>
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+---
+ drivers/dma/sh/rcar-dmac.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
+index 2b2c7db..c99fd0f 100644
+--- a/drivers/dma/sh/rcar-dmac.c
++++ b/drivers/dma/sh/rcar-dmac.c
+@@ -10,6 +10,7 @@
+ * published by the Free Software Foundation.
+ */
+
++#include <linux/delay.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/dmaengine.h>
+ #include <linux/interrupt.h>
+@@ -741,6 +742,24 @@ static int rcar_dmac_fill_hwdesc(struct rcar_dmac_chan *chan,
+ /* -----------------------------------------------------------------------------
+ * Stop and reset
+ */
++static void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan)
++{
++ u32 chcr;
++ unsigned int i;
++
++ /*
++ * Ensure that the setting of the DE bit is actually 0 after
++ * clearing it.
++ */
++ for (i = 0; i < 1024; i++) {
++ chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
++ if (!(chcr & RCAR_DMACHCR_DE))
++ return;
++ udelay(1);
++ }
++
++ dev_err(chan->chan.device->dev, "CHCR DE check error\n");
++}
+
+ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
+ {
+@@ -749,6 +768,7 @@ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
+ chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
+ RCAR_DMACHCR_TE | RCAR_DMACHCR_DE);
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
++ rcar_dmac_chcr_de_barrier(chan);
+ }
+
+ static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
+@@ -1481,6 +1501,8 @@ static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
+ if (chcr & RCAR_DMACHCR_TE)
+ mask |= RCAR_DMACHCR_DE;
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
++ if (mask & RCAR_DMACHCR_DE)
++ rcar_dmac_chcr_de_barrier(chan);
+
+ if (chcr & RCAR_DMACHCR_DSE)
+ ret |= rcar_dmac_isr_desc_stage_end(chan);
+--
+1.9.1
+
diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0081-dmaengine-rcar-dmac-use-TCRB-instead-of-TCR-for-resi.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0081-dmaengine-rcar-dmac-use-TCRB-instead-of-TCR-for-resi.patch
new file mode 100644
index 0000000..c9bfdfb
--- /dev/null
+++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0081-dmaengine-rcar-dmac-use-TCRB-instead-of-TCR-for-resi.patch
@@ -0,0 +1,108 @@
+From 73a47bd0da668c99f04e9076f2b02101a5b2749b Mon Sep 17 00:00:00 2001
+From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Date: Fri, 17 Nov 2017 02:09:32 +0000
+Subject: [PATCH 2/2] dmaengine: rcar-dmac: use TCRB instead of TCR for residue
+
+SYS/RT/Audio DMAC includes independent data buffers for reading
+and writing. Therefore, the read transfer counter and write transfer
+counter have different values.
+TCR indicates read counter, and TCRB indicates write counter.
+The relationship is like below.
+
+ TCR TCRB
+ [SOURCE] -> [DMAC] -> [SINK]
+
+In the MEM_TO_DEV direction, what really matters is how much data has
+been written to the device. If the DMA is interrupted between read and
+write, then, the data doesn't end up in the destination, so shouldn't
+be counted. TCRB is thus the register we should use in this cases.
+
+In the DEV_TO_MEM direction, the situation is more complex. Both the
+read and write side are important. What matters from a data consumer
+point of view is how much data has been written to memory.
+On the other hand, if the transfer is interrupted between read and
+write, we'll end up losing data. It can also be important to report.
+
+In the MEM_TO_MEM direction, what matters is of course how much data
+has been written to memory from data consumer point of view.
+Here, because read and write have independent data buffers, it will
+take a while for TCR and TCRB to become equal. Thus we should check
+TCRB in this case, too.
+
+Thus, all cases we should check TCRB instead of TCR.
+
+Without this patch, Sound Capture has noise after PulseAudio support
+(= 07b7acb51d2 ("ASoC: rsnd: update pointer more accurate")), because
+the recorder will use wrong residue counter which indicates transferred
+from sound device, but in reality the data was not yet put to memory
+and recorder will record it.
+
+However, because DMAC is buffering data until it can be transferable
+size, TCRB might not be updated.
+For example, if consumer doesn't know how much data can be received,
+it requests enough size to DMAC. But in reality, it might receive very
+few data. In such case, DMAC just buffered it until transferable size,
+and no TCRB updated.
+
+In such case, this buffered data will be transferred if CHCR::DE bit was
+cleared, and this is happen if rcar_dmac_chan_halt(). In other word, it
+happen when consumer called dmaengine_terminate_all().
+
+Because of this behavior, it need to flush buffered data when it returns
+"residue" (= dmaengine_tx_status()).
+Otherwise, consumer might calculate wrong things if it called
+dmaengine_tx_status() and dmaengine_terminate_all() consecutively.
+
+Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+Tested-by: Hiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
+Tested-by: Ryo Kodama <ryo.kodama.vz@renesas.com>
+Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+---
+ drivers/dma/sh/rcar-dmac.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
+index c99fd0f..3bbd11d 100644
+--- a/drivers/dma/sh/rcar-dmac.c
++++ b/drivers/dma/sh/rcar-dmac.c
+@@ -761,6 +761,23 @@ static void rcar_dmac_chcr_de_barrier(struct rcar_dmac_chan *chan)
+ dev_err(chan->chan.device->dev, "CHCR DE check error\n");
+ }
+
++static void rcar_dmac_sync_tcr(struct rcar_dmac_chan *chan)
++{
++ u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
++
++ if (!(chcr & RCAR_DMACHCR_DE))
++ return;
++
++ /* set DE=0 and flush remaining data */
++ rcar_dmac_chan_write(chan, RCAR_DMACHCR, (chcr & ~RCAR_DMACHCR_DE));
++
++ /* make sure all remaining data was flushed */
++ rcar_dmac_chcr_de_barrier(chan);
++
++ /* back DE */
++ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
++}
++
+ static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
+ {
+ u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+@@ -1329,8 +1346,11 @@ static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
+ residue += chunk->size;
+ }
+
++ if (desc->direction == DMA_DEV_TO_MEM)
++ rcar_dmac_sync_tcr(chan);
++
+ /* Add the residue for the current chunk. */
+- residue += rcar_dmac_chan_read(chan, RCAR_DMATCR) << desc->xfer_shift;
++ residue += rcar_dmac_chan_read(chan, RCAR_DMATCRB) << desc->xfer_shift;
+
+ return residue;
+ }
+--
+1.9.1
+