devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Shawn Lin <shawn.lin@rock-chips.com>
To: "Doug Anderson" <dianders@chromium.org>,
	"Heiko Stübner" <heiko@sntech.de>
Cc: shawn.lin@rock-chips.com, Jaehoon Chung <jh80.chung@samsung.com>,
	Ulf Hansson <ulf.hansson@linaro.org>,
	Vineet.Gupta1@synopsys.com, Wei Xu <xuwei5@hisilicon.com>,
	Joachim Eastwood <manabian@gmail.com>,
	Alexey Brodkin <abrodkin@synopsys.com>,
	Kukjin Kim <kgene@kernel.org>,
	Krzysztof Kozlowski <k.kozlowski@samsung.com>,
	Russell King <linux@arm.linux.org.uk>,
	Zhangfei Gao <zhangfei.gao@linaro.org>,
	Jun Nie <jun.nie@linaro.org>, Ralf Baechle <ralf@linux-mips.org>,
	Govindraj Raja <govindraj.raja@imgtec.com>,
	Arnd Bergmann <arnd@arndb.de>,
	linux-samsung-soc <linux-samsung-soc@vger.kernel.org>,
	linux-mips@linux-mips.org,
	"linux-mmc@vger.kernel.org" <linux-mmc@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"open list:ARM/Rockchip SoC..."
	<linux-rockchip@lists.infradead.org>,
	"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>linux
Subject: Re: [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support
Date: Mon, 17 Aug 2015 14:27:47 +0800	[thread overview]
Message-ID: <55D17EE3.2040700@rock-chips.com> (raw)
In-Reply-To: <CAD=FV=W1dzqoJuJtJsD5TPKmSBpUbBcifGz654o9x8J1rX6-GQ@mail.gmail.com>

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

在 2015/8/17 5:10, Doug Anderson 写道:
> Heiko,
>
> On Fri, Aug 14, 2015 at 3:13 PM, Heiko Stübner <heiko@sntech.de> wrote:
>> Hi Shawn,
>>
>> Am Freitag, 14. August 2015, 16:34:35 schrieb Shawn Lin:
>>> DesignWare MMC Controller can supports two types of DMA
>>> mode: external dma and internal dma. We get a RK312x platform
>>> integrated dw_mmc and ARM pl330 dma controller. This patch add
>>> edmac ops to support these platforms. I've tested it on RK312x
>>> platform with edmac mode and RK3288 platform with idmac mode.
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
>>
>> judging by your "from", I guess you're running this on some older Rockchip soc
>> without the idma? Because I tried testing this on a Radxa Rock, but only got
>> failures, from the start (failed to read card status register). In PIO mode
>> everything works again.
>>
>>
>> I guess I overlooked just some tiny detail, but to me the dma channel ids seem
>> correct after all. Maybe you have any hints what I'm doing wrong?
>
> If I were a guessing man (which I'm not), I'd guess that perhaps
> you're running into troubles with our friend the PL330.
>
> There appear to be strange issues with the PL330 on Rockchip SoCs.  I
> was only peripherally involved with them, but I know at least about
> some of the patches in our tree, like:
>

Thanks, Doug, that's the root cause. PL330 on Rockchip Socs need your 
patches, and we might need another patch to limit pl330 burst_len to 
16(Hmm...seems another quirks for rockchip but not on your tree);

Hi Heiko,
I just get a Radxa Rock luckily and test my patch based on 
http://radxa.com/Rock/Linux_Mainline. Yes, it can't work.

If you test my patchset on Rockchip platform, pls apply pl330 patch from 
my tree based on kernel 4.2-RC3. AND, temporary hack dw_mmc to limit 
pl330 burst_len to 16.
This is a dmaengine or pl330 problem(I guest it should be upstreamed 
later?), but my patchset is for *generic* dw_mmc to support emdac, so 
other platforms should never need the hack of pl330.

pl330.patch is for pl330 changes
r3xxx.patch is for pl330 quirks

AND pls limit burst_len to 16 for BROKRN pl330 of rockchips.
static int dw_mci_edmac_start_dma(
...
+        u32 burst_limit = 0;
+        u32 mburst;
+        u32 idx, rx_wmark, tx_wmark;

...
         /* Match burst msize with external dma config */
         fifoth_val = mci_readl(host, FIFOTH);
-	cfg.dst_maxburst = mszs[(fifoth_val >> 28) & 0x7];
-	cfg.src_maxburst = cfg.dst_maxburst;
+	/* HACK for BROKEN pl330 */
+       mburst = mszs[(fifoth_val >> 28) & 0x7];
+       burst_limit = 16;
+       if (mburst > burst_limit) {
+               mburst = burst_limit;
+               idx = (ilog2(mburst) > 0) ? (ilog2(mburst) - 1) : 0;
+               rx_wmark = mszs[idx] - 1;
+               tx_wmark = (host->fifo_depth) / 2;
+               fifoth_val = SDMMC_SET_FIFOTH(idx, rx_wmark, tx_wmark);
+               mci_writel(host, FIFOTH, fifoth_val);
+       }
+	cfg.dst_maxburst = mburst;
+       cfg.src_maxburst = cfg.dst_maxburst;


> https://chromium-review.googlesource.com/237607
> FROMLIST: DMA: pl330: support burst mode for dev-to-mem and mem-to-dev transmit
>
> https://chromium-review.googlesource.com/237393
> CHROMIUM: dmaengine: pl330: support quirks for some broken
>
> https://chromium-review.googlesource.com/237396
> CHROMIUM: dmaengine: pl330: add quirk for broken no flushp
>
> https://chromium-review.googlesource.com/237394
> CHROMIUM: ARM: dts: rockchip: Add broken-no-flushp into rk3288.dtsi
>
> https://chromium-review.googlesource.com/242063
> CHROMIUM: ASoC: rockchip_i2s: modify DMA max burst to 1
>
>
>


-- 
Shawn Lin

[-- Attachment #2: pl330.patch --]
[-- Type: text/plain, Size: 7954 bytes --]

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index ecab4ea..b2a950c 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -34,6 +34,14 @@
 #define PL330_MAX_IRQS		32
 #define PL330_MAX_PERI		32
 
+#define PL330_QUIRK_BROKEN_NO_FLUSHP BIT(0)
+
+enum pl330_cond {
+	SINGLE,
+	BURST,
+	ALWAYS,
+};
+
 enum pl330_cachectrl {
 	CCTRL0,		/* Noncacheable and nonbufferable */
 	CCTRL1,		/* Bufferable only */
@@ -344,12 +352,6 @@ enum pl330_dst {
 	DST,
 };
 
-enum pl330_cond {
-	SINGLE,
-	BURST,
-	ALWAYS,
-};
-
 struct dma_pl330_desc;
 
 struct _pl330_req {
@@ -488,6 +490,17 @@ struct pl330_dmac {
 	/* Peripheral channels connected to this DMAC */
 	unsigned int num_peripherals;
 	struct dma_pl330_chan *peripherals; /* keep at end */
+	int quirks;
+};
+
+static struct pl330_of_quirks {
+	char *quirk;
+	int id;
+} of_quirks[] = {
+	{
+		.quirk = "broken-no-flushp",
+		.id = PL330_QUIRK_BROKEN_NO_FLUSHP,
+	}
 };
 
 struct dma_pl330_desc {
@@ -1137,47 +1150,64 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
 	return off;
 }
 
-static inline int _ldst_devtomem(unsigned dry_run, u8 buf[],
+static inline int _ldst_devtomem(struct pl330_dmac *pi,unsigned dry_run, u8 buf[],
 		const struct _xfer_spec *pxs, int cyc)
 {
 	int off = 0;
+	enum pl330_cond cond;
+
+	if (pi->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)
+		cond = BURST;
+	else
+		cond = (pxs->desc->rqcfg.brst_len == 1) ? SINGLE : BURST;
 
 	while (cyc--) {
-		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
-		off += _emit_LDP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
+		off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
+		off += _emit_LDP(dry_run, &buf[off], cond, pxs->desc->peri);
 		off += _emit_ST(dry_run, &buf[off], ALWAYS);
-		off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+
+		if (!(pi->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))
+			off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
 	}
 
 	return off;
 }
 
-static inline int _ldst_memtodev(unsigned dry_run, u8 buf[],
+static inline int _ldst_memtodev(struct pl330_dmac *pi, unsigned dry_run, u8 buf[],
 		const struct _xfer_spec *pxs, int cyc)
 {
 	int off = 0;
+	enum pl330_cond cond;
+
+	if (pi->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)
+		cond = BURST;
+	else
+		cond = (pxs->desc->rqcfg.brst_len == 1) ? SINGLE : BURST;
+
 
 	while (cyc--) {
-		off += _emit_WFP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
+		off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
 		off += _emit_LD(dry_run, &buf[off], ALWAYS);
-		off += _emit_STP(dry_run, &buf[off], SINGLE, pxs->desc->peri);
-		off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
+		off += _emit_STP(dry_run, &buf[off], cond, pxs->desc->peri);
+
+		if (!(pi->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP))		
+			off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri);
 	}
 
 	return off;
 }
 
-static int _bursts(unsigned dry_run, u8 buf[],
+static int _bursts(struct pl330_dmac *pi,unsigned dry_run, u8 buf[],
 		const struct _xfer_spec *pxs, int cyc)
 {
 	int off = 0;
 
 	switch (pxs->desc->rqtype) {
 	case DMA_MEM_TO_DEV:
-		off += _ldst_memtodev(dry_run, &buf[off], pxs, cyc);
+		off += _ldst_memtodev(pi, dry_run, &buf[off], pxs, cyc);
 		break;
 	case DMA_DEV_TO_MEM:
-		off += _ldst_devtomem(dry_run, &buf[off], pxs, cyc);
+		off += _ldst_devtomem(pi, dry_run, &buf[off], pxs, cyc);
 		break;
 	case DMA_MEM_TO_MEM:
 		off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
@@ -1191,7 +1221,7 @@ static int _bursts(unsigned dry_run, u8 buf[],
 }
 
 /* Returns bytes consumed and updates bursts */
-static inline int _loop(unsigned dry_run, u8 buf[],
+static inline int _loop(struct pl330_dmac *pi, unsigned dry_run, u8 buf[],
 		unsigned long *bursts, const struct _xfer_spec *pxs)
 {
 	int cyc, cycmax, szlp, szlpend, szbrst, off;
@@ -1214,7 +1244,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
 	}
 
 	szlp = _emit_LP(1, buf, 0, 0);
-	szbrst = _bursts(1, buf, pxs, 1);
+	szbrst = _bursts(pi, 1, buf, pxs, 1);
 
 	lpend.cond = ALWAYS;
 	lpend.forever = false;
@@ -1246,7 +1276,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
 	off += _emit_LP(dry_run, &buf[off], 1, lcnt1);
 	ljmp1 = off;
 
-	off += _bursts(dry_run, &buf[off], pxs, cyc);
+	off += _bursts(pi, dry_run, &buf[off], pxs, cyc);
 
 	lpend.cond = ALWAYS;
 	lpend.forever = false;
@@ -1269,7 +1299,7 @@ static inline int _loop(unsigned dry_run, u8 buf[],
 	return off;
 }
 
-static inline int _setup_loops(unsigned dry_run, u8 buf[],
+static inline int _setup_loops(struct pl330_dmac *pi, unsigned dry_run, u8 buf[],
 		const struct _xfer_spec *pxs)
 {
 	struct pl330_xfer *x = &pxs->desc->px;
@@ -1279,14 +1309,14 @@ static inline int _setup_loops(unsigned dry_run, u8 buf[],
 
 	while (bursts) {
 		c = bursts;
-		off += _loop(dry_run, &buf[off], &c, pxs);
+		off += _loop(pi, dry_run, &buf[off], &c, pxs);
 		bursts -= c;
 	}
 
 	return off;
 }
 
-static inline int _setup_xfer(unsigned dry_run, u8 buf[],
+static inline int _setup_xfer(struct pl330_dmac *pi,unsigned dry_run, u8 buf[],
 		const struct _xfer_spec *pxs)
 {
 	struct pl330_xfer *x = &pxs->desc->px;
@@ -1298,7 +1328,7 @@ static inline int _setup_xfer(unsigned dry_run, u8 buf[],
 	off += _emit_MOV(dry_run, &buf[off], DAR, x->dst_addr);
 
 	/* Setup Loop(s) */
-	off += _setup_loops(dry_run, &buf[off], pxs);
+	off += _setup_loops(pi, dry_run, &buf[off], pxs);
 
 	return off;
 }
@@ -1307,7 +1337,7 @@ static inline int _setup_xfer(unsigned dry_run, u8 buf[],
  * A req is a sequence of one or more xfer units.
  * Returns the number of bytes taken to setup the MC for the req.
  */
-static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
+static int _setup_req(struct pl330_dmac *pi,unsigned dry_run, struct pl330_thread *thrd,
 		unsigned index, struct _xfer_spec *pxs)
 {
 	struct _pl330_req *req = &thrd->req[index];
@@ -1325,7 +1355,7 @@ static int _setup_req(unsigned dry_run, struct pl330_thread *thrd,
 	if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr)))
 		return -EINVAL;
 
-	off += _setup_xfer(dry_run, &buf[off], pxs);
+	off += _setup_xfer(pi, dry_run, &buf[off], pxs);
 
 	/* DMASEV peripheral/event */
 	off += _emit_SEV(dry_run, &buf[off], thrd->ev);
@@ -1419,7 +1449,7 @@ static int pl330_submit_req(struct pl330_thread *thrd,
 	xs.desc = desc;
 
 	/* First dry run to check if req is acceptable */
-	ret = _setup_req(1, thrd, idx, &xs);
+	ret = _setup_req(pl330, 1, thrd, idx, &xs);
 	if (ret < 0)
 		goto xfer_exit;
 
@@ -1433,7 +1463,7 @@ static int pl330_submit_req(struct pl330_thread *thrd,
 	/* Hook the request */
 	thrd->lstenq = idx;
 	thrd->req[idx].desc = desc;
-	_setup_req(0, thrd, idx, &xs);
+	_setup_req(pl330, 0, thrd, idx, &xs);
 
 	ret = 0;
 
@@ -2557,7 +2587,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
 
 		desc->rqtype = direction;
 		desc->rqcfg.brst_size = pch->burst_sz;
-		desc->rqcfg.brst_len = 1;
+		desc->rqcfg.brst_len = pch->burst_len;
 		desc->bytes_requested = period_len;
 		fill_px(&desc->px, dst, src, period_len);
 
@@ -2702,7 +2732,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		}
 
 		desc->rqcfg.brst_size = pch->burst_sz;
-		desc->rqcfg.brst_len = 1;
+		desc->rqcfg.brst_len = pch->burst_len;
 		desc->rqtype = direction;
 		desc->bytes_requested = sg_dma_len(sg);
 	}
@@ -2778,6 +2808,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 	struct resource *res;
 	int i, ret, irq;
 	int num_chan;
+	struct device_node *np = adev->dev.of_node;
 
 	pdat = dev_get_platdata(&adev->dev);
 
@@ -2797,6 +2828,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
 	pl330->mcbufsz = pdat ? pdat->mcbuf_sz : 0;
 
+	/* get quirk */
+	for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
+		if (of_property_read_bool(np, of_quirks[i].quirk))
+			pl330->quirks |= of_quirks[i].id;
+
 	res = &adev->res;
 	pl330->base = devm_ioremap_resource(&adev->dev, res);
 	if (IS_ERR(pl330->base))

[-- Attachment #3: rk3xxxx.patch --]
[-- Type: text/plain, Size: 426 bytes --]

diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index a2ae9f3..fb5b4ec 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -94,6 +94,7 @@
 
 		dmac2: dma-controller@20078000 {
 			compatible = "arm,pl330", "arm,primecell";
+			broken-no-flushp;
 			reg = <0x20078000 0x4000>;
 			interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>,
 				     <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;

  reply	other threads:[~2015-08-17  6:27 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-14  8:33 [RFC PATCH v5 0/9] Add external dma support for Synopsys MSHC Shawn Lin
2015-08-14  8:34 ` [RFC PATCH v5 1/9] mmc: dw_mmc: Add external dma interface support Shawn Lin
2015-08-14 22:13   ` Heiko Stübner
2015-08-16 21:10     ` Doug Anderson
2015-08-17  6:27       ` Shawn Lin [this message]
2015-08-17  1:11     ` Shawn Lin
2015-08-14  8:34 ` [RFC PATCH v5 2/9] Documentation: synopsys-dw-mshc: add bindings for idmac and edmac Shawn Lin
2015-08-14  8:35 ` [RFC PATCH v5 3/9] mips: pistachio_defconfig: remove CONFIG_MMC_DW_IDMAC Shawn Lin
     [not found] ` <1439541232-30100-1-git-send-email-shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
2015-08-14  8:35   ` [RFC PATCH v5 4/9] arc: axs10x_defconfig: " Shawn Lin
2015-08-14  8:35 ` [RFC PATCH v5 5/9] arm: exynos_defconfig: " Shawn Lin
2015-08-14  8:35 ` [RFC PATCH v5 6/9] arm: hisi_defconfig: " Shawn Lin
2015-08-14  8:36 ` [RFC PATCH v5 7/9] arm: lpc18xx_defconfig: " Shawn Lin
2015-08-14  8:36 ` [RFC PATCH v5 8/9] arm: multi_v7_defconfig: " Shawn Lin
2015-08-14  8:36 ` [RFC PATCH v5 9/9] arm: zx_defconfig: " Shawn Lin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55D17EE3.2040700@rock-chips.com \
    --to=shawn.lin@rock-chips.com \
    --cc=Vineet.Gupta1@synopsys.com \
    --cc=abrodkin@synopsys.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=dianders@chromium.org \
    --cc=govindraj.raja@imgtec.com \
    --cc=heiko@sntech.de \
    --cc=jh80.chung@samsung.com \
    --cc=jun.nie@linaro.org \
    --cc=k.kozlowski@samsung.com \
    --cc=kgene@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mips@linux-mips.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=linux@arm.linux.org.uk \
    --cc=manabian@gmail.com \
    --cc=ralf@linux-mips.org \
    --cc=ulf.hansson@linaro.org \
    --cc=xuwei5@hisilicon.com \
    --cc=zhangfei.gao@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).