From patchwork Tue Apr 15 15:13:37 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 3993751 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id E4D8ABFF02 for ; Tue, 15 Apr 2014 15:17:39 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9DC022022A for ; Tue, 15 Apr 2014 15:17:38 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 62D5420200 for ; Tue, 15 Apr 2014 15:17:37 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wa54w-0008Ck-QU; Tue, 15 Apr 2014 15:15:18 +0000 Received: from perceval.ideasonboard.com ([95.142.166.194]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1Wa54s-0006px-NR for linux-arm-kernel@lists.infradead.org; Tue, 15 Apr 2014 15:15:15 +0000 Received: from avalon.ideasonboard.com (55.138-246-81.adsl-dyn.isp.belgacom.be [81.246.138.55]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id DFAFE35A02; Tue, 15 Apr 2014 17:11:38 +0200 (CEST) From: Laurent Pinchart To: dmaengine@vger.kernel.org Subject: [PATCH 6/6] dma: mmp_pdma: Add support externel DMA requests Date: Tue, 15 Apr 2014 17:13:37 +0200 Message-Id: <1397574817-15559-7-git-send-email-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1397574817-15559-1-git-send-email-laurent.pinchart@ideasonboard.com> References: <1397574817-15559-1-git-send-email-laurent.pinchart@ideasonboard.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140415_081515_157218_39A1CBA9 X-CRM114-Status: GOOD ( 20.74 ) X-Spam-Score: -0.7 (/) Cc: Xiang Wang , linux-arm-kernel@lists.infradead.org, Daniel Mack X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The MMP/PXA DMA engine supports transfer initiation by external chips through DMA request (DREQ) signals. Support them by clearing pending DMA requests for the associated source when starting a channel. The request ID to DREQ index mapping depends on the hardware and is passed through platform data or DT. Cc: devicetree@vger.kernel.org Signed-off-by: Laurent Pinchart --- Documentation/devicetree/bindings/dma/mmp-dma.txt | 2 + drivers/dma/mmp_pdma.c | 96 ++++++++++++++++++++--- include/linux/platform_data/mmp_dma.h | 2 + 3 files changed, 87 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/mmp-dma.txt b/Documentation/devicetree/bindings/dma/mmp-dma.txt index 7a802f6..edb9ff3 100644 --- a/Documentation/devicetree/bindings/dma/mmp-dma.txt +++ b/Documentation/devicetree/bindings/dma/mmp-dma.txt @@ -12,6 +12,8 @@ Required properties: Optional properties: - #dma-channels: Number of DMA channels supported by the controller (defaults to 32 when not specified) +- marvell,dreq: Array of the DMA request IDs corresponding to each of the + external device request (DREQ) lines "marvell,pdma-1.0" Used platforms: pxa25x, pxa27x, pxa3xx, pxa93x, pxa168, pxa910, pxa688. diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 849bf75..4546a1c 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -27,6 +27,7 @@ #define DCSR 0x0000 #define DALGN 0x00a0 +#define DRQSR(n) (0x00e0 + ((n) << 2)) #define DINT 0x00f0 #define DDADR 0x0200 #define DSADR 0x0204 @@ -50,6 +51,9 @@ #define DCSR_CMPST BIT(10) /* The Descriptor Compare Status */ #define DCSR_EORINTR BIT(9) /* The end of Receive */ +#define DRQSR_CLR BIT(8) /* Clear Pending Requests */ +#define DRQSR_REQPEND 0x1f /* Requests Pending */ + #define DRCMR(n) ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2)) #define DRCMR_MAPVLD BIT(7) /* Map Valid (read / write) */ #define DRCMR_CHLNUM 0x1f /* mask for Channel Number (read / write) */ @@ -108,6 +112,7 @@ struct mmp_pdma_chan { u32 dcmd; u32 drcmr; u32 dev_addr; + int drq; /* list for desc */ spinlock_t desc_lock; /* Descriptor list lock */ @@ -127,6 +132,8 @@ struct mmp_pdma_phy { struct mmp_pdma_device { int dma_channels; + unsigned int num_dreq; + const u32 *dreq; void __iomem *base; struct device *dev; struct dma_device device; @@ -167,6 +174,9 @@ static void enable_chan(struct mmp_pdma_phy *phy) dalgn &= ~(1 << phy->idx); writel(dalgn, phy->base + DALGN); + if (phy->vchan->drq != -1) + writel(DRQSR_CLR, phy->base + DRQSR(phy->vchan->drq)); + reg = (phy->idx << 2) + DCSR; writel(readl(phy->base + reg) | DCSR_RUN, phy->base + reg); } @@ -685,6 +695,22 @@ fail: return NULL; } +static void mmp_pdma_set_drcmr(struct mmp_pdma_chan *chan, unsigned int drmcr) +{ + struct mmp_pdma_device *pdev = to_mmp_pdma_dev(cchan->chan.device); + unsigned int i; + + chan->drcmr = drmcr; + chan->drq = -1; + + for (i = 0; i < pdev->num_dreq; ++i) { + if (pdev->dreq[i] == drmcr) { + chan->drq = i; + break; + } + } +} + static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, unsigned long arg) { @@ -745,7 +771,7 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd, * be removed. */ if (cfg->slave_id) - chan->drcmr = cfg->slave_id; + mmp_pdma_set_drcmr(chan, cfg->slave_id); break; default: return -ENOSYS; @@ -909,16 +935,64 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec, if (!chan) return NULL; - to_mmp_pdma_chan(chan)->drcmr = dma_spec->args[0]; + mmp_pdma_set_drcmr(to_mmp_pdma_chan(chan), dma_spec->args[0]); return chan; } +static int mmap_pdma_parse_platform_data(struct mmp_pdma_device *pdev) +{ + struct device_node *np = pdev->dev->of_node; + struct property *prop; + + /* Default values: 32 channels, no external DREQ. */ + pdev->dma_channels = 32; + pdev->num_dreq = 0; + + if (!IS_ENABLED(CONFIG_OF) || !np) { + struct mmp_dma_platdata *pdata = dev_get_platdata(pdev->dev); + + if (!pdata) + return 0; + + if (pdata->dma_channels) + pdev->dma_channels = pdata->dma_channels; + if (pdata->num_dreq) { + pdev->num_dreq = pdata->num_dreq; + pdev->dreq = pdata->dreq; + } + + return 0; + } + + of_property_read_u32(np, "#dma-channels", &pdev->dma_channels); + + prop = of_find_property(np, "marvell,dreq"); + if (prop) { + unsigned int num_dreq = prop->length / sizeof(unsigned long); + u32 *dreq; + + dreq = devm_kcalloc(pdev->dev, num_dreq, sizeof(*pdreq), + GFP_KERNEL); + if (dreq == NULL) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "marvell,dreq", dreq, + num_dreq); + if (ret < 0) + return ret; + + pdev->num_dreq = num_dreq; + pdev->dreq = dreq; + } + + return 0; +} + static int mmp_pdma_probe(struct platform_device *op) { struct mmp_pdma_device *pdev; const struct of_device_id *of_id; - struct mmp_dma_platdata *pdata = dev_get_platdata(&op->dev); struct resource *iores; int i, ret, irq = 0; int dma_channels = 0, irq_num = 0; @@ -936,15 +1010,11 @@ static int mmp_pdma_probe(struct platform_device *op) if (IS_ERR(pdev->base)) return PTR_ERR(pdev->base); - of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev); - if (of_id) - of_property_read_u32(pdev->dev->of_node, "#dma-channels", - &dma_channels); - else if (pdata && pdata->dma_channels) - dma_channels = pdata->dma_channels; - else - dma_channels = 32; /* default 32 channel */ - pdev->dma_channels = dma_channels; + ret = mmp_pdma_parse_platform_data(pdev); + if (ret < 0) + return ret; + + dma_channels = pdev->dma_channels; for (i = 0; i < dma_channels; i++) { if (platform_get_irq(op, i) > 0) @@ -1038,7 +1108,7 @@ bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param) if (chan->device->dev->driver != &mmp_pdma_driver.driver) return false; - c->drcmr = *(unsigned int *)param; + mmp_pdma_set_drcmr(c, *(unsigned int *)param); return true; } diff --git a/include/linux/platform_data/mmp_dma.h b/include/linux/platform_data/mmp_dma.h index 2a330ec..32595b8 100644 --- a/include/linux/platform_data/mmp_dma.h +++ b/include/linux/platform_data/mmp_dma.h @@ -14,6 +14,8 @@ struct mmp_dma_platdata { int dma_channels; + unsigned int num_dreq; + const u32 *dreq; }; #endif /* MMP_DMA_H */