From patchwork Fri Sep 2 00:44:33 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "boojin.kim" X-Patchwork-Id: 1121442 Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p828YriK006688 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Fri, 2 Sep 2011 08:35:14 GMT Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QzPCR-0008HQ-I1; Fri, 02 Sep 2011 08:34:08 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1QzPCQ-0003td-AD; Fri, 02 Sep 2011 08:34:06 +0000 Received: from ganesha.gnumonks.org ([2001:780:45:1d:2e0:81ff:fe28:898a]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1QzP9A-0002sX-Vz for linux-arm-kernel@lists.infradead.org; Fri, 02 Sep 2011 08:30:58 +0000 Received: from uucp by ganesha.gnumonks.org with local-bsmtp (Exim 4.72) (envelope-from ) id 1QzP8z-0007ju-As; Fri, 02 Sep 2011 10:30:33 +0200 Received: from [12.23.102.153] (helo=sunrise.dsn.sec.samsung.com) by jackpot.kr.gnumonks.org with esmtp (Exim 4.69) (envelope-from ) id 1QzH6g-0004nd-PX; Fri, 02 Sep 2011 08:55:38 +0900 From: Boojin Kim To: linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org Subject: [PATCH v8 05/16] DMA: PL330: Add DMA_CYCLIC capability Date: Fri, 2 Sep 2011 09:44:33 +0900 Message-Id: <1314924284-25554-6-git-send-email-boojin.kim@samsung.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1314924284-25554-1-git-send-email-boojin.kim@samsung.com> References: <1314924284-25554-1-git-send-email-boojin.kim@samsung.com> X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110902_043045_414634_4C8B59D5 X-CRM114-Status: GOOD ( 19.10 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- Cc: Kukjin Kim , Russell King , Boojin Kim , Vinod Koul , Linus Walleij , Jassi Brar , Grant Likely , Mark Brown , Dan Williams X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter2.kernel.org [140.211.167.43]); Fri, 02 Sep 2011 08:35:14 +0000 (UTC) This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver activated with it reuses the dma requests that were submitted through tx_submit(). Signed-off-by: Boojin Kim Acked-by: Linus Walleij Acked-by: Vinod Koul Cc: Dan Williams Signed-off-by: Kukjin Kim --- drivers/dma/pl330.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 83 insertions(+), 1 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 59943ec..621134f 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -75,6 +75,9 @@ struct dma_pl330_chan { int burst_sz; /* the peripheral fifo width */ int burst_len; /* the number of burst */ dma_addr_t fifo_addr; + + /* for cyclic capability */ + bool cyclic; }; struct dma_pl330_dmac { @@ -161,6 +164,31 @@ static inline void free_desc_list(struct list_head *list) spin_unlock_irqrestore(&pdmac->pool_lock, flags); } +static inline void handle_cyclic_desc_list(struct list_head *list) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch; + unsigned long flags; + + if (list_empty(list)) + return; + + list_for_each_entry(desc, list, node) { + dma_async_tx_callback callback; + + /* Change status to reload it */ + desc->status = PREP; + pch = desc->pchan; + callback = desc->txd.callback; + if (callback) + callback(desc->txd.callback_param); + } + + spin_lock_irqsave(&pch->lock, flags); + list_splice_tail_init(list, &pch->work_list); + spin_unlock_irqrestore(&pch->lock, flags); +} + static inline void fill_queue(struct dma_pl330_chan *pch) { struct dma_pl330_desc *desc; @@ -214,7 +242,10 @@ static void pl330_tasklet(unsigned long data) spin_unlock_irqrestore(&pch->lock, flags); - free_desc_list(&list); + if (pch->cyclic) + handle_cyclic_desc_list(&list); + else + free_desc_list(&list); } static void dma_pl330_rqcb(void *token, enum pl330_op_err err) @@ -245,6 +276,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) spin_lock_irqsave(&pch->lock, flags); pch->completed = chan->cookie = 1; + pch->cyclic = false; pch->pl330_chid = pl330_request_channel(&pdmac->pif); if (!pch->pl330_chid) { @@ -324,6 +356,9 @@ static void pl330_free_chan_resources(struct dma_chan *chan) pl330_release_channel(pch->pl330_chid); pch->pl330_chid = NULL; + if (pch->cyclic) + list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); + spin_unlock_irqrestore(&pch->lock, flags); } @@ -560,6 +595,51 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) return burst_len; } +static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( + struct dma_chan *chan, dma_addr_t dma_addr, size_t len, + size_t period_len, enum dma_data_direction direction) +{ + struct dma_pl330_desc *desc; + struct dma_pl330_chan *pch = to_pchan(chan); + dma_addr_t dst; + dma_addr_t src; + + desc = pl330_get_desc(pch); + if (!desc) { + dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n", + __func__, __LINE__); + return NULL; + } + + switch (direction) { + case DMA_TO_DEVICE: + desc->rqcfg.src_inc = 1; + desc->rqcfg.dst_inc = 0; + src = dma_addr; + dst = pch->fifo_addr; + break; + case DMA_FROM_DEVICE: + desc->rqcfg.src_inc = 0; + desc->rqcfg.dst_inc = 1; + src = pch->fifo_addr; + dst = dma_addr; + break; + default: + dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n", + __func__, __LINE__); + return NULL; + } + + desc->rqcfg.brst_size = pch->burst_sz; + desc->rqcfg.brst_len = 1; + + pch->cyclic = true; + + fill_px(&desc->px, dst, src, period_len); + + return &desc->txd; +} + static struct dma_async_tx_descriptor * pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, size_t len, unsigned long flags) @@ -791,6 +871,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) case MEMTODEV: case DEVTOMEM: dma_cap_set(DMA_SLAVE, pd->cap_mask); + dma_cap_set(DMA_CYCLIC, pd->cap_mask); break; default: dev_err(&adev->dev, "DEVTODEV Not Supported\n"); @@ -819,6 +900,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id) pd->device_alloc_chan_resources = pl330_alloc_chan_resources; pd->device_free_chan_resources = pl330_free_chan_resources; pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy; + pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic; pd->device_tx_status = pl330_tx_status; pd->device_prep_slave_sg = pl330_prep_slave_sg; pd->device_control = pl330_control;