From patchwork Mon Apr 8 06:43:29 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic Desroches X-Patchwork-Id: 2405251 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) by patchwork1.kernel.org (Postfix) with ESMTP id 032203FD1A for ; Mon, 8 Apr 2013 06:44:18 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UP5oE-0005Hv-L9; Mon, 08 Apr 2013 06:44:06 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UP5oB-0000FO-Ky; Mon, 08 Apr 2013 06:44:03 +0000 Received: from eusmtp01.atmel.com ([212.144.249.242]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UP5o0-0000EE-Ez for linux-arm-kernel@lists.infradead.org; Mon, 08 Apr 2013 06:43:54 +0000 Received: from ibiza.corp.atmel.com (10.161.101.13) by eusmtp01.atmel.com (10.161.101.30) with Microsoft SMTP Server id 14.2.318.4; Mon, 8 Apr 2013 08:43:43 +0200 From: To: Subject: [RFC v2 PATCH] at_hdmac: move to generic DMA binding Date: Mon, 8 Apr 2013 08:43:29 +0200 Message-ID: <1365403409-18381-1-git-send-email-ludovic.desroches@atmel.com> X-Mailer: git-send-email 1.7.11.3 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130408_024353_514025_27643616 X-CRM114-Status: GOOD ( 17.82 ) X-Spam-Score: -4.3 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -2.4 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: vinod.koul@intel.com, plagnioj@jcrosoft.com, Ludovic Desroches , nicolas.ferre@atmel.com, arnd@arndb.de 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: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org From: Ludovic Desroches Signed-off-by: Ludovic Desroches --- Hi, Here is a second try to move at_hdmac to generic DMA binding. I have updated bindings according to Arnd comments ie I have removed chunk transfer size. I have added the implementation but I am not very happy with the translation function. I have tried to not break old stuff: slave ask for a channel giving an atslave structure (passed through pdata) as a parameter for the filter function which saves this structure into chan->private. Then chan->private contains the configuration for the channel CFG register which is done when calling device_alloc_chan_resources. If I allocate the atslave structure in the xlate function, where should be the right place to deallocate it? For the moment, I choose to add the atslave structure to the at_dma_chan structure but I am not happy with writing the channel configuration register into the xlate function. I would like to keep the same path as before. Regards Ludovic .../devicetree/bindings/dma/atmel-dma.txt | 27 +++++++- arch/arm/boot/dts/sama5d3.dtsi | 2 + drivers/dma/at_hdmac.c | 71 ++++++++++++++++++++-- drivers/dma/at_hdmac_regs.h | 7 +++ 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/dma/atmel-dma.txt b/Documentation/devicetree/bindings/dma/atmel-dma.txt index 3c046ee..2d6f0f3 100644 --- a/Documentation/devicetree/bindings/dma/atmel-dma.txt +++ b/Documentation/devicetree/bindings/dma/atmel-dma.txt @@ -4,11 +4,34 @@ Required properties: - compatible: Should be "atmel,-dma" - reg: Should contain DMA registers location and length - interrupts: Should contain DMA interrupt +- #dma-cells: Must be <2> -Examples: +Example: -dma@ffffec00 { +dma0: dma@ffffec00 { compatible = "atmel,at91sam9g45-dma"; reg = <0xffffec00 0x200>; interrupts = <21>; + #dma-cells = <2>; +}; + +DMA clients connected to the Atmel DMA controller must use the format +described in the dma.txt file, using a three-cell specifier for each channel. +The three cells in order are: + +1. A phandle pointing to the DMA controller +2. The memory interface (16 most significant bits), the peripheral interface +(16 less significant bits) +3. The peripheral identifier (can be different for tx and rx) + +Example: + +i2c0@i2c@f8010000 { + compatible = "atmel,at91sam9x5-i2c"; + reg = <0xf8010000 0x100>; + interrupts = <9 4 6>; + dmas = <&dma0 1 7>, + <&dma0 1 8>; + dma-names = "tx", "rx" }; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 39b0458..9232143 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -349,6 +349,7 @@ reg = <0xffffe600 0x200>; interrupts = <30 4 0>; #dma-cells = <1>; + #dma-cells = <2>; }; dma1: dma-controller@ffffe800 { @@ -356,6 +357,7 @@ reg = <0xffffe800 0x200>; interrupts = <31 4 0>; #dma-cells = <1>; + #dma-cells = <2>; }; ramc0: ramc@ffffea00 { diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 8415467..ec7f561 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "at_hdmac_regs.h" #include "dmaengine.h" @@ -676,7 +677,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrlb |= ATC_DST_ADDR_MODE_FIXED | ATC_SRC_ADDR_MODE_INCR | ATC_FC_MEM2PER - | ATC_SIF(AT_DMA_MEM_IF) | ATC_DIF(AT_DMA_PER_IF); + | ATC_SIF(atchan->mem_if) | ATC_DIF(atchan->per_if); reg = sconfig->dst_addr; for_each_sg(sgl, sg, sg_len, i) { struct at_desc *desc; @@ -715,7 +716,7 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, ctrlb |= ATC_DST_ADDR_MODE_INCR | ATC_SRC_ADDR_MODE_FIXED | ATC_FC_PER2MEM - | ATC_SIF(AT_DMA_PER_IF) | ATC_DIF(AT_DMA_MEM_IF); + | ATC_SIF(atchan->per_if) | ATC_DIF(atchan->mem_if); reg = sconfig->src_addr; for_each_sg(sgl, sg, sg_len, i) { @@ -821,8 +822,8 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, desc->lli.ctrlb = ATC_DST_ADDR_MODE_FIXED | ATC_SRC_ADDR_MODE_INCR | ATC_FC_MEM2PER - | ATC_SIF(AT_DMA_MEM_IF) - | ATC_DIF(AT_DMA_PER_IF); + | ATC_SIF(atchan->mem_if) + | ATC_DIF(atchan->per_if); break; case DMA_DEV_TO_MEM: @@ -832,8 +833,8 @@ atc_dma_cyclic_fill_desc(struct dma_chan *chan, struct at_desc *desc, desc->lli.ctrlb = ATC_DST_ADDR_MODE_INCR | ATC_SRC_ADDR_MODE_FIXED | ATC_FC_PER2MEM - | ATC_SIF(AT_DMA_PER_IF) - | ATC_DIF(AT_DMA_MEM_IF); + | ATC_SIF(atchan->per_if) + | ATC_DIF(atchan->mem_if); break; default: @@ -1189,6 +1190,55 @@ static void atc_free_chan_resources(struct dma_chan *chan) dev_vdbg(chan2dev(chan), "free_chan_resources: done\n"); } +static bool at_dma_filter(struct dma_chan *chan, void *dma_dev) +{ + if (dma_dev == chan->device->dev) + return true; + else + return false; +} + +static struct dma_chan *at_dma_xlate(struct of_phandle_args *dma_spec, + struct of_dma *of_dma) +{ + struct dma_chan *chan; + struct at_dma_chan *atchan; + struct at_dma_slave *atslave; + dma_cap_mask_t mask; + unsigned int per_id; + struct platform_device *dmac_pdev; + + if (dma_spec->args_count != 2) + return NULL; + + dmac_pdev = of_find_device_by_node(dma_spec->np); + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + chan = dma_request_channel(mask, at_dma_filter, &dmac_pdev->dev); + if (!chan) + return NULL; + + atchan = to_at_dma_chan(chan); + atchan->per_if = dma_spec->args[0] & 0xff; + atchan->mem_if = (dma_spec->args[0] >> 16) & 0xff; + + atslave = &atchan->atslave; + /* + * We can fill both SRC_PER and DST_PER, one of these fields will be + * ignored depending on DMA transfer direction. + */ + per_id = dma_spec->args[1]; + atslave->cfg = ATC_FIFOCFG_HALFFIFO | ATC_DST_H2SEL_HW + | ATC_SRC_H2SEL_HW | ATC_DST_PER(per_id) + | ATC_SRC_PER(per_id); + atslave->dma_dev = &dmac_pdev->dev; + chan->private = atslave; + channel_writel(atchan, CFG, atslave->cfg); + + return chan; +} /*-- Module Management -----------------------------------------------*/ @@ -1389,6 +1439,15 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_async_device_register(&atdma->dma_common); + if (pdev->dev.of_node) { + printk("=== of_dma_controller_register ===\n"); + err = of_dma_controller_register(pdev->dev.of_node, + at_dma_xlate, atdma); + if (err && err != -ENODEV) + dev_err(&pdev->dev, + "could not register of_dma_controller\n"); + } + return 0; err_pool_create: diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 0eb3c13..e3d2f12 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -220,6 +220,8 @@ enum atc_status { * @device: parent device * @ch_regs: memory mapped register base * @mask: channel index in a mask + * @per_if: peripheral interface + * @mem_if: memory interface * @status: transmit status information from irq/prep* functions * to tasklet (use atomic operations) * @tasklet: bottom half to finish transaction work @@ -227,6 +229,8 @@ enum atc_status { * @save_dscr: for cyclic operations, preserve next descriptor address in * the cyclic list on suspend/resume cycle * @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG + * @atslave: hardware configuration for slave transfers which is not passed via + * DMA_SLAVE_CONFIG * @lock: serializes enqueue/dequeue operations to descriptors lists * @active_list: list of descriptors dmaengine is being running on * @queue: list of descriptors ready to be submitted to engine @@ -238,11 +242,14 @@ struct at_dma_chan { struct at_dma *device; void __iomem *ch_regs; u8 mask; + u8 per_if; + u8 mem_if; unsigned long status; struct tasklet_struct tasklet; u32 save_cfg; u32 save_dscr; struct dma_slave_config dma_sconfig; + struct at_dma_slave atslave; spinlock_t lock;