From 72ef08bf651a9fab3b315b8e6d57d19926c77e4d Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Tue, 10 Apr 2018 18:02:16 -0700 Subject: [PATCH 01/32] dmaengine: dmatest: Remove use of VLAs There's an ongoing effort to remove VLAs from the kernel (https://lkml.org/lkml/2018/3/7/621) to eventually turn on -Wvla. The test already pre-allocates some buffers with kmalloc so turn the two VLAs in to pre-allocated kmalloc buffers. Signed-off-by: Laura Abbott Reviewed-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index b9339524d5bd..aa1712beb0cc 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -468,6 +468,8 @@ static int dmatest_func(void *data) unsigned long long total_len = 0; u8 align = 0; bool is_memset = false; + dma_addr_t *srcs; + dma_addr_t *dma_pq; set_freezable(); @@ -551,6 +553,14 @@ static int dmatest_func(void *data) set_user_nice(current, 10); + srcs = kcalloc(src_cnt, sizeof(dma_addr_t), GFP_KERNEL); + if (!srcs) + goto err_dstbuf; + + dma_pq = kcalloc(dst_cnt, sizeof(dma_addr_t), GFP_KERNEL); + if (!dma_pq) + goto err_srcs_array; + /* * src and dst buffers are freed by ourselves below */ @@ -561,7 +571,6 @@ static int dmatest_func(void *data) && !(params->iterations && total_tests >= params->iterations)) { struct dma_async_tx_descriptor *tx = NULL; struct dmaengine_unmap_data *um; - dma_addr_t srcs[src_cnt]; dma_addr_t *dsts; unsigned int src_off, dst_off, len; @@ -676,8 +685,6 @@ static int dmatest_func(void *data) srcs, src_cnt, len, flags); else if (thread->type == DMA_PQ) { - dma_addr_t dma_pq[dst_cnt]; - for (i = 0; i < dst_cnt; i++) dma_pq[i] = dsts[i] + dst_off; tx = dev->device_prep_dma_pq(chan, dma_pq, srcs, @@ -779,6 +786,9 @@ static int dmatest_func(void *data) runtime = ktime_to_us(ktime); ret = 0; + kfree(dma_pq); +err_srcs_array: + kfree(srcs); err_dstbuf: for (i = 0; thread->udsts[i]; i++) kfree(thread->udsts[i]); From 6af6c3710759d875a5abafd7900e2a5f62a7c095 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 16:05:39 +0200 Subject: [PATCH 02/32] dmaengine: qcom: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Reviewed-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 3 +-- drivers/dma/qcom/hidma_mgmt_sys.c | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 963cc5228d05..43d4b00b8138 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -616,8 +616,7 @@ static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg) static ssize_t hidma_show_values(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct hidma_dev *mdev = platform_get_drvdata(pdev); + struct hidma_dev *mdev = dev_get_drvdata(dev); buf[0] = 0; diff --git a/drivers/dma/qcom/hidma_mgmt_sys.c b/drivers/dma/qcom/hidma_mgmt_sys.c index d61f1068a34b..cbb89eafd844 100644 --- a/drivers/dma/qcom/hidma_mgmt_sys.c +++ b/drivers/dma/qcom/hidma_mgmt_sys.c @@ -107,8 +107,7 @@ static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = { static ssize_t show_values(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev); + struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev); unsigned int i; buf[0] = 0; @@ -125,8 +124,7 @@ static ssize_t show_values(struct device *dev, struct device_attribute *attr, static ssize_t set_values(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev); + struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev); unsigned long tmp; unsigned int i; int rc; From 83ff13235fb3e9c10401f457df27f67bf3b389af Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 19 Apr 2018 16:05:38 +0200 Subject: [PATCH 03/32] dmaengine: dw: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Acked-by: Viresh Kumar Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index bc31fe802061..f62dd0944908 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -293,8 +293,7 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); static int dw_suspend_late(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = dev_get_drvdata(dev); dw_dma_disable(chip); clk_disable_unprepare(chip->clk); @@ -304,8 +303,7 @@ static int dw_suspend_late(struct device *dev) static int dw_resume_early(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct dw_dma_chip *chip = platform_get_drvdata(pdev); + struct dw_dma_chip *chip = dev_get_drvdata(dev); int ret; ret = clk_prepare_enable(chip->clk); From 6ae7abe370d14c62e5ae70e3f5909d31a44a560b Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Thu, 19 Apr 2018 11:20:32 -0400 Subject: [PATCH 04/32] MAINTAINERS: add maintainer for Qualcomm HIDMA drivers drivers/dma/qcom directory is being shared by multiple QCOM dmaengine drivers. Separate ownership by filenames. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0a1410d5a621..2110ad09b93d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11657,6 +11657,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rkuo/linux-hexagon-kernel.g S: Supported F: arch/hexagon/ +QUALCOMM HIDMA DRIVER +M: Sinan Kaya +L: linux-arm-kernel@lists.infradead.org +L: linux-arm-msm@vger.kernel.org +L: dmaengine@vger.kernel.org +S: Supported +F: drivers/dma/qcom/hidma* + QUALCOMM IOMMU M: Rob Clark L: iommu@lists.linux-foundation.org From 5c4a74a4144a6c394fd7ca4760f779129075d636 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:09 +0200 Subject: [PATCH 05/32] dmaengine: at_hdmac: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index a861b5b4d443..75f38d19fcbe 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -2041,8 +2041,7 @@ static void at_dma_shutdown(struct platform_device *pdev) static int at_dma_prepare(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_dma *atdma = platform_get_drvdata(pdev); + struct at_dma *atdma = dev_get_drvdata(dev); struct dma_chan *chan, *_chan; list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, @@ -2076,8 +2075,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan) static int at_dma_suspend_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_dma *atdma = platform_get_drvdata(pdev); + struct at_dma *atdma = dev_get_drvdata(dev); struct dma_chan *chan, *_chan; /* preserve data */ @@ -2118,8 +2116,7 @@ static void atc_resume_cyclic(struct at_dma_chan *atchan) static int at_dma_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_dma *atdma = platform_get_drvdata(pdev); + struct at_dma *atdma = dev_get_drvdata(dev); struct dma_chan *chan, *_chan; /* bring back DMA controller */ From ede2b295033f52c35acc089db76b71cd7f4bf243 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:10 +0200 Subject: [PATCH 06/32] dmaengine: at_xdmac: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 94236ec9d410..4bf72561667c 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1833,8 +1833,7 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan) #ifdef CONFIG_PM static int atmel_xdmac_prepare(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_xdmac *atxdmac = platform_get_drvdata(pdev); + struct at_xdmac *atxdmac = dev_get_drvdata(dev); struct dma_chan *chan, *_chan; list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { @@ -1853,8 +1852,7 @@ static int atmel_xdmac_prepare(struct device *dev) #ifdef CONFIG_PM_SLEEP static int atmel_xdmac_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_xdmac *atxdmac = platform_get_drvdata(pdev); + struct at_xdmac *atxdmac = dev_get_drvdata(dev); struct dma_chan *chan, *_chan; list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { @@ -1878,8 +1876,7 @@ static int atmel_xdmac_suspend(struct device *dev) static int atmel_xdmac_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct at_xdmac *atxdmac = platform_get_drvdata(pdev); + struct at_xdmac *atxdmac = dev_get_drvdata(dev); struct at_xdmac_chan *atchan; struct dma_chan *chan, *_chan; int i; From 03bf2793f3637f7c3cb7acbe40f15f4da333f2e1 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:11 +0200 Subject: [PATCH 07/32] dmaengine: fsldma: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/fsldma.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 3eaece888e75..1117b5123a6f 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -1328,8 +1328,7 @@ static int fsldma_of_remove(struct platform_device *op) #ifdef CONFIG_PM static int fsldma_suspend_late(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct fsldma_device *fdev = platform_get_drvdata(pdev); + struct fsldma_device *fdev = dev_get_drvdata(dev); struct fsldma_chan *chan; int i; @@ -1360,8 +1359,7 @@ out: static int fsldma_resume_early(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct fsldma_device *fdev = platform_get_drvdata(pdev); + struct fsldma_device *fdev = dev_get_drvdata(dev); struct fsldma_chan *chan; u32 mode; int i; From b7d69799af675e1c13ea470ef942450216b2c9b6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:12 +0200 Subject: [PATCH 08/32] dmaengine: idma64: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/idma64.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c index 1953e57505f4..e5c911200bdb 100644 --- a/drivers/dma/idma64.c +++ b/drivers/dma/idma64.c @@ -670,8 +670,7 @@ static int idma64_platform_remove(struct platform_device *pdev) static int idma64_pm_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct idma64_chip *chip = platform_get_drvdata(pdev); + struct idma64_chip *chip = dev_get_drvdata(dev); idma64_off(chip->idma64); return 0; @@ -679,8 +678,7 @@ static int idma64_pm_suspend(struct device *dev) static int idma64_pm_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct idma64_chip *chip = platform_get_drvdata(pdev); + struct idma64_chip *chip = dev_get_drvdata(dev); idma64_on(chip->idma64); return 0; From be34c218210298ddd2f00a583ded480115bb270a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:13 +0200 Subject: [PATCH 09/32] dmaengine: ste_dma40: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index c2b089af0420..1bc149af990e 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2889,8 +2889,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, #ifdef CONFIG_PM_SLEEP static int dma40_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct d40_base *base = platform_get_drvdata(pdev); + struct d40_base *base = dev_get_drvdata(dev); int ret; ret = pm_runtime_force_suspend(dev); @@ -2904,8 +2903,7 @@ static int dma40_suspend(struct device *dev) static int dma40_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct d40_base *base = platform_get_drvdata(pdev); + struct d40_base *base = dev_get_drvdata(dev); int ret = 0; if (base->lcpa_regulator) { @@ -2970,8 +2968,7 @@ static void d40_save_restore_registers(struct d40_base *base, bool save) static int dma40_runtime_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct d40_base *base = platform_get_drvdata(pdev); + struct d40_base *base = dev_get_drvdata(dev); d40_save_restore_registers(base, true); @@ -2985,8 +2982,7 @@ static int dma40_runtime_suspend(struct device *dev) static int dma40_runtime_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct d40_base *base = platform_get_drvdata(pdev); + struct d40_base *base = dev_get_drvdata(dev); d40_save_restore_registers(base, false); From a8afcfeb013f95a3339eafd690f41af6657a6113 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 22 Apr 2018 11:14:14 +0200 Subject: [PATCH 10/32] dmaengine: txx9dmac: simplify getting .drvdata We should get drvdata from struct device directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Vinod Koul --- drivers/dma/txx9dmac.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c index 4d8c7b9078fd..eb45af71d3a3 100644 --- a/drivers/dma/txx9dmac.c +++ b/drivers/dma/txx9dmac.c @@ -1244,8 +1244,7 @@ static void txx9dmac_shutdown(struct platform_device *pdev) static int txx9dmac_suspend_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); + struct txx9dmac_dev *ddev = dev_get_drvdata(dev); txx9dmac_off(ddev); return 0; @@ -1253,9 +1252,8 @@ static int txx9dmac_suspend_noirq(struct device *dev) static int txx9dmac_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); - struct txx9dmac_platform_data *pdata = dev_get_platdata(&pdev->dev); + struct txx9dmac_dev *ddev = dev_get_drvdata(dev); + struct txx9dmac_platform_data *pdata = dev_get_platdata(dev); u32 mcr; mcr = TXX9_DMA_MCR_MSTEN | MCR_LE; From ee6de9ac527f0630d496303df3f270678128e6c6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Fri, 13 Apr 2018 15:52:12 +0200 Subject: [PATCH 11/32] dmaengine: stm32-mdma: align TLEN and buffer length on burst Both buffer Transfer Length (TLEN if any) and transfer size have to be aligned on burst size (burst beats*bus width). Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index daa1602eb9f5..4c7634ca62a7 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -410,13 +410,10 @@ static enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr, static u32 stm32_mdma_get_best_burst(u32 buf_len, u32 tlen, u32 max_burst, enum dma_slave_buswidth width) { - u32 best_burst = max_burst; - u32 burst_len = best_burst * width; + u32 best_burst; - while ((burst_len > 0) && (tlen % burst_len)) { - best_burst = best_burst >> 1; - burst_len = best_burst * width; - } + best_burst = min((u32)1 << __ffs(tlen | buf_len), + max_burst * width) / width; return (best_burst > 0) ? best_burst : 1; } From bbb5a4e1e772c878783c2d59b97ac3b358d4a0a6 Mon Sep 17 00:00:00 2001 From: Pierre-Yves MORDRET Date: Fri, 13 Apr 2018 15:52:13 +0200 Subject: [PATCH 12/32] dmaengine: stm32-mdma: Fix incomplete Hw descriptors allocator Only 1 Hw Descriptor is allocated. Loop over required Hw descriptor for proper allocation. Signed-off-by: Pierre-Yves MORDRET Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 89 +++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 4c7634ca62a7..1ac775f93d9e 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -252,13 +252,17 @@ struct stm32_mdma_hwdesc { u32 cmdr; } __aligned(64); +struct stm32_mdma_desc_node { + struct stm32_mdma_hwdesc *hwdesc; + dma_addr_t hwdesc_phys; +}; + struct stm32_mdma_desc { struct virt_dma_desc vdesc; u32 ccr; - struct stm32_mdma_hwdesc *hwdesc; - dma_addr_t hwdesc_phys; bool cyclic; u32 count; + struct stm32_mdma_desc_node node[]; }; struct stm32_mdma_chan { @@ -344,30 +348,42 @@ static struct stm32_mdma_desc *stm32_mdma_alloc_desc( struct stm32_mdma_chan *chan, u32 count) { struct stm32_mdma_desc *desc; + int i; - desc = kzalloc(sizeof(*desc), GFP_NOWAIT); + desc = kzalloc(offsetof(typeof(*desc), node[count]), GFP_NOWAIT); if (!desc) return NULL; - desc->hwdesc = dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, - &desc->hwdesc_phys); - if (!desc->hwdesc) { - dev_err(chan2dev(chan), "Failed to allocate descriptor\n"); - kfree(desc); - return NULL; + for (i = 0; i < count; i++) { + desc->node[i].hwdesc = + dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, + &desc->node[i].hwdesc_phys); + if (!desc->node[i].hwdesc) + goto err; } desc->count = count; return desc; + +err: + dev_err(chan2dev(chan), "Failed to allocate descriptor\n"); + while (--i >= 0) + dma_pool_free(chan->desc_pool, desc->node[i].hwdesc, + desc->node[i].hwdesc_phys); + kfree(desc); + return NULL; } static void stm32_mdma_desc_free(struct virt_dma_desc *vdesc) { struct stm32_mdma_desc *desc = to_stm32_mdma_desc(vdesc); struct stm32_mdma_chan *chan = to_stm32_mdma_chan(vdesc->tx.chan); + int i; - dma_pool_free(chan->desc_pool, desc->hwdesc, desc->hwdesc_phys); + for (i = 0; i < desc->count; i++) + dma_pool_free(chan->desc_pool, desc->node[i].hwdesc, + desc->node[i].hwdesc_phys); kfree(desc); } @@ -666,18 +682,18 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, } static void stm32_mdma_dump_hwdesc(struct stm32_mdma_chan *chan, - struct stm32_mdma_hwdesc *hwdesc) + struct stm32_mdma_desc_node *node) { - dev_dbg(chan2dev(chan), "hwdesc: 0x%p\n", hwdesc); - dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n", hwdesc->ctcr); - dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n", hwdesc->cbndtr); - dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n", hwdesc->csar); - dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n", hwdesc->cdar); - dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n", hwdesc->cbrur); - dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n", hwdesc->clar); - dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n", hwdesc->ctbr); - dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n", hwdesc->cmar); - dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n\n", hwdesc->cmdr); + dev_dbg(chan2dev(chan), "hwdesc: %pad\n", &node->hwdesc_phys); + dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n", node->hwdesc->ctcr); + dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n", node->hwdesc->cbndtr); + dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n", node->hwdesc->csar); + dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n", node->hwdesc->cdar); + dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n", node->hwdesc->cbrur); + dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n", node->hwdesc->clar); + dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n", node->hwdesc->ctbr); + dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n", node->hwdesc->cmar); + dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n\n", node->hwdesc->cmdr); } static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, @@ -691,7 +707,7 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, struct stm32_mdma_hwdesc *hwdesc; u32 next = count + 1; - hwdesc = &desc->hwdesc[count]; + hwdesc = desc->node[count].hwdesc; hwdesc->ctcr = ctcr; hwdesc->cbndtr &= ~(STM32_MDMA_CBNDTR_BRC_MK | STM32_MDMA_CBNDTR_BRDUM | @@ -701,19 +717,20 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, hwdesc->csar = src_addr; hwdesc->cdar = dst_addr; hwdesc->cbrur = 0; - hwdesc->clar = desc->hwdesc_phys + next * sizeof(*hwdesc); hwdesc->ctbr = ctbr; hwdesc->cmar = config->mask_addr; hwdesc->cmdr = config->mask_data; if (is_last) { if (is_cyclic) - hwdesc->clar = desc->hwdesc_phys; + hwdesc->clar = desc->node[0].hwdesc_phys; else hwdesc->clar = 0; + } else { + hwdesc->clar = desc->node[next].hwdesc_phys; } - stm32_mdma_dump_hwdesc(chan, hwdesc); + stm32_mdma_dump_hwdesc(chan, &desc->node[count]); } static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan, @@ -777,7 +794,7 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, { struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); struct stm32_mdma_desc *desc; - int ret; + int i, ret; /* * Once DMA is in setup cyclic mode the channel we cannot assign this @@ -803,7 +820,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); xfer_setup_err: - dma_pool_free(chan->desc_pool, &desc->hwdesc, desc->hwdesc_phys); + for (i = 0; i < desc->count; i++) + dma_pool_free(chan->desc_pool, desc->node[i].hwdesc, + desc->node[i].hwdesc_phys); kfree(desc); return NULL; } @@ -892,7 +911,9 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); xfer_setup_err: - dma_pool_free(chan->desc_pool, &desc->hwdesc, desc->hwdesc_phys); + for (i = 0; i < desc->count; i++) + dma_pool_free(chan->desc_pool, desc->node[i].hwdesc, + desc->node[i].hwdesc_phys); kfree(desc); return NULL; } @@ -1006,7 +1027,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src, ctcr |= STM32_MDMA_CTCR_PKE; /* Prepare hardware descriptor */ - hwdesc = desc->hwdesc; + hwdesc = desc->node[0].hwdesc; hwdesc->ctcr = ctcr; hwdesc->cbndtr = cbndtr; hwdesc->csar = src; @@ -1017,7 +1038,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src, hwdesc->cmar = 0; hwdesc->cmdr = 0; - stm32_mdma_dump_hwdesc(chan, hwdesc); + stm32_mdma_dump_hwdesc(chan, &desc->node[0]); } else { /* Setup a LLI transfer */ ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_LINKED_LIST) | @@ -1117,7 +1138,7 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan) } chan->desc = to_stm32_mdma_desc(vdesc); - hwdesc = chan->desc->hwdesc; + hwdesc = chan->desc->node[0].hwdesc; chan->curr_hwdesc = 0; stm32_mdma_write(dmadev, STM32_MDMA_CCR(id), chan->desc->ccr); @@ -1195,7 +1216,7 @@ static int stm32_mdma_resume(struct dma_chan *c) unsigned long flags; u32 status, reg; - hwdesc = &chan->desc->hwdesc[chan->curr_hwdesc]; + hwdesc = chan->desc->node[chan->curr_hwdesc].hwdesc; spin_lock_irqsave(&chan->vchan.lock, flags); @@ -1265,13 +1286,13 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, u32 curr_hwdesc) { struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); + struct stm32_mdma_hwdesc *hwdesc = desc->node[0].hwdesc; u32 cbndtr, residue, modulo, burst_size; int i; residue = 0; for (i = curr_hwdesc + 1; i < desc->count; i++) { - struct stm32_mdma_hwdesc *hwdesc = &desc->hwdesc[i]; - + hwdesc = desc->node[i].hwdesc; residue += STM32_MDMA_CBNDTR_BNDT(hwdesc->cbndtr); } cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); From 0ef9944d2e05bedc6e388fe215edd4c1bed192bc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 20 Apr 2018 15:28:28 +0200 Subject: [PATCH 13/32] dmaengine: shdmac: Change platform check to CONFIG_ARCH_RENESAS Since commit 9b5ba0df4ea4f940 ("ARM: shmobile: Introduce ARCH_RENESAS") is CONFIG_ARCH_RENESAS a more appropriate platform check than the legacy CONFIG_ARCH_SHMOBILE, hence use the former. Renesas SuperH SH-Mobile SoCs are still covered by the CONFIG_CPU_SH4 check, just like before support for Renesas ARM SoCs was added. Instead of blindly changing all the #ifdefs, switch the main code block in sh_dmae_probe() to IS_ENABLED(), as this allows to remove all the remaining #ifdefs. This will allow to drop ARCH_SHMOBILE on ARM in the near future. Signed-off-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Vinod Koul --- drivers/dma/sh/shdmac.c | 54 ++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c index c94ffab0d25c..04a74e0a95b7 100644 --- a/drivers/dma/sh/shdmac.c +++ b/drivers/dma/sh/shdmac.c @@ -443,7 +443,6 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev) return ret; } -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) static irqreturn_t sh_dmae_err(int irq, void *data) { struct sh_dmae_device *shdev = data; @@ -454,7 +453,6 @@ static irqreturn_t sh_dmae_err(int irq, void *data) sh_dmae_reset(shdev); return IRQ_HANDLED; } -#endif static bool sh_dmae_desc_completed(struct shdma_chan *schan, struct shdma_desc *sdesc) @@ -686,11 +684,8 @@ static int sh_dmae_probe(struct platform_device *pdev) const struct sh_dmae_pdata *pdata; unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {}; int chan_irq[SH_DMAE_MAX_CHANNELS]; -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) unsigned long irqflags = 0; - int errirq; -#endif - int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0; + int err, errirq, i, irq_cnt = 0, irqres = 0, irq_cap = 0; struct sh_dmae_device *shdev; struct dma_device *dma_dev; struct resource *chan, *dmars, *errirq_res, *chanirq_res; @@ -792,33 +787,32 @@ static int sh_dmae_probe(struct platform_device *pdev) if (err) goto rst_err; -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) - chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + if (IS_ENABLED(CONFIG_CPU_SH4) || IS_ENABLED(CONFIG_ARCH_RENESAS)) { + chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); - if (!chanirq_res) + if (!chanirq_res) + chanirq_res = errirq_res; + else + irqres++; + + if (chanirq_res == errirq_res || + (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE) + irqflags = IRQF_SHARED; + + errirq = errirq_res->start; + + err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, + irqflags, "DMAC Address Error", shdev); + if (err) { + dev_err(&pdev->dev, + "DMA failed requesting irq #%d, error %d\n", + errirq, err); + goto eirq_err; + } + } else { chanirq_res = errirq_res; - else - irqres++; - - if (chanirq_res == errirq_res || - (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE) - irqflags = IRQF_SHARED; - - errirq = errirq_res->start; - - err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags, - "DMAC Address Error", shdev); - if (err) { - dev_err(&pdev->dev, - "DMA failed requesting irq #%d, error %d\n", - errirq, err); - goto eirq_err; } -#else - chanirq_res = errirq_res; -#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */ - if (chanirq_res->start == chanirq_res->end && !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { /* Special case - all multiplexed */ @@ -884,9 +878,7 @@ edmadevreg: chan_probe_err: sh_dmae_chan_remove(shdev); -#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) eirq_err: -#endif rst_err: spin_lock_irq(&sh_dmae_lock); list_del_rcu(&shdev->node); From d88b1397c674178e595319fab4a3cd434c915639 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 25 Apr 2018 11:45:03 +0300 Subject: [PATCH 14/32] dmaengine: ti: New directory for Texas Instruments DMA drivers Collect the Texas Instruments DMA drivers under drivers/dma/ti/ Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 31 +--------------- drivers/dma/Makefile | 5 +-- drivers/dma/ti/Kconfig | 37 +++++++++++++++++++ drivers/dma/ti/Makefile | 5 +++ drivers/dma/{ => ti}/cppi41.c | 2 +- .../{ti-dma-crossbar.c => ti/dma-crossbar.c} | 0 drivers/dma/{ => ti}/edma.c | 4 +- drivers/dma/{ => ti}/omap-dma.c | 2 +- 8 files changed, 49 insertions(+), 37 deletions(-) create mode 100644 drivers/dma/ti/Kconfig create mode 100644 drivers/dma/ti/Makefile rename drivers/dma/{ => ti}/cppi41.c (99%) rename drivers/dma/{ti-dma-crossbar.c => ti/dma-crossbar.c} (100%) rename drivers/dma/{ => ti}/edma.c (99%) rename drivers/dma/{ => ti}/omap-dma.c (99%) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 6d61cd023633..ca1680afa20a 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -151,13 +151,6 @@ config DMA_JZ4780 If you have a board based on such a SoC and wish to use DMA for devices which can use the DMA controller, say Y or M here. -config DMA_OMAP - tristate "OMAP DMA support" - depends on ARCH_OMAP || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_DMA_CROSSBAR if (SOC_DRA7XX || COMPILE_TEST) - config DMA_SA11X0 tristate "SA-11x0 DMA support" depends on ARCH_SA1100 || COMPILE_TEST @@ -574,28 +567,6 @@ config TIMB_DMA help Enable support for the Timberdale FPGA DMA engine. -config TI_CPPI41 - tristate "CPPI 4.1 DMA support" - depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX) - select DMA_ENGINE - help - The Communications Port Programming Interface (CPPI) 4.1 DMA engine - is currently used by the USB driver on AM335x and DA8xx platforms. - -config TI_DMA_CROSSBAR - bool - -config TI_EDMA - bool "TI EDMA support" - depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_DMA_CROSSBAR if (ARCH_OMAP || COMPILE_TEST) - default n - help - Enable support for the TI EDMA controller. This DMA - engine is found on TI DaVinci and AM33xx parts. - config XGENE_DMA tristate "APM X-Gene DMA support" depends on ARCH_XGENE || COMPILE_TEST @@ -653,6 +624,8 @@ source "drivers/dma/hsu/Kconfig" source "drivers/dma/sh/Kconfig" +source "drivers/dma/ti/Kconfig" + # clients comment "DMA Clients" depends on DMA_ENGINE diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 0f62a4d49aab..203a99d68315 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o -obj-$(CONFIG_DMA_OMAP) += omap-dma.o obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o @@ -69,13 +68,11 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o obj-$(CONFIG_TIMB_DMA) += timb_dma.o -obj-$(CONFIG_TI_CPPI41) += cppi41.o -obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o -obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx_dma.o obj-$(CONFIG_ST_FDMA) += st_fdma.o obj-y += mediatek/ obj-y += qcom/ +obj-y += ti/ obj-y += xilinx/ diff --git a/drivers/dma/ti/Kconfig b/drivers/dma/ti/Kconfig new file mode 100644 index 000000000000..e5e74e1361dc --- /dev/null +++ b/drivers/dma/ti/Kconfig @@ -0,0 +1,37 @@ +# +# Texas Instruments DMA drivers +# + +config TI_CPPI41 + tristate "Texas Instruments CPPI 4.1 DMA support" + depends on (ARCH_OMAP || ARCH_DAVINCI_DA8XX) + select DMA_ENGINE + help + The Communications Port Programming Interface (CPPI) 4.1 DMA engine + is currently used by the USB driver on AM335x and DA8xx platforms. + +config TI_EDMA + tristate "Texas Instruments EDMA support" + depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + select TI_DMA_CROSSBAR if (ARCH_OMAP || COMPILE_TEST) + default y + help + Enable support for the TI EDMA (Enhanced DMA) controller. This DMA + engine is found on TI DaVinci, AM33xx, AM43xx, DRA7xx and Keystone 2 + parts. + +config DMA_OMAP + tristate "Texas Instruments sDMA (omap-dma) support" + depends on ARCH_OMAP || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + select TI_DMA_CROSSBAR if (SOC_DRA7XX || COMPILE_TEST) + default y + help + Enable support for the TI sDMA (System DMA or DMA4) controller. This + DMA engine is found on OMAP and DRA7xx parts. + +config TI_DMA_CROSSBAR + bool diff --git a/drivers/dma/ti/Makefile b/drivers/dma/ti/Makefile new file mode 100644 index 000000000000..113e59ec9c32 --- /dev/null +++ b/drivers/dma/ti/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_TI_CPPI41) += cppi41.o +obj-$(CONFIG_TI_EDMA) += edma.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o +obj-$(CONFIG_TI_DMA_CROSSBAR) += dma-crossbar.o diff --git a/drivers/dma/cppi41.c b/drivers/dma/ti/cppi41.c similarity index 99% rename from drivers/dma/cppi41.c rename to drivers/dma/ti/cppi41.c index d9bee65a18a4..1497da367710 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/ti/cppi41.c @@ -11,7 +11,7 @@ #include #include #include -#include "dmaengine.h" +#include "../dmaengine.h" #define DESC_TYPE 27 #define DESC_TYPE_HOST 0x10 diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti/dma-crossbar.c similarity index 100% rename from drivers/dma/ti-dma-crossbar.c rename to drivers/dma/ti/dma-crossbar.c diff --git a/drivers/dma/edma.c b/drivers/dma/ti/edma.c similarity index 99% rename from drivers/dma/edma.c rename to drivers/dma/ti/edma.c index 85ea92fcea54..93a5cbf13319 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/ti/edma.c @@ -33,8 +33,8 @@ #include -#include "dmaengine.h" -#include "virt-dma.h" +#include "../dmaengine.h" +#include "../virt-dma.h" /* Offsets matching "struct edmacc_param" */ #define PARM_OPT 0x00 diff --git a/drivers/dma/omap-dma.c b/drivers/dma/ti/omap-dma.c similarity index 99% rename from drivers/dma/omap-dma.c rename to drivers/dma/ti/omap-dma.c index d21c19822feb..b73fb51fbc81 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/ti/omap-dma.c @@ -21,7 +21,7 @@ #include #include -#include "virt-dma.h" +#include "../virt-dma.h" #define OMAP_SDMA_REQUESTS 127 #define OMAP_SDMA_CHANNELS 32 From 6b1d255ecde522ac961226b22321f417c62b2435 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Thu, 19 Apr 2018 10:00:46 +0800 Subject: [PATCH 15/32] dmaengine: sprd: Define the DMA transfer step type Define the DMA transfer step type to make code more readable. Signed-off-by: Eric Long Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index b106e8a60af6..dcfa4179bf9e 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -116,6 +116,13 @@ #define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0 #define SPRD_DMA_TRSF_STEP_MASK GENMASK(15, 0) +/* define the DMA transfer step type */ +#define SPRD_DMA_NONE_STEP 0 +#define SPRD_DMA_BYTE_STEP 1 +#define SPRD_DMA_SHORT_STEP 2 +#define SPRD_DMA_WORD_STEP 4 +#define SPRD_DMA_DWORD_STEP 8 + #define SPRD_DMA_SOFTWARE_UID 0 /* @@ -598,16 +605,16 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, if (IS_ALIGNED(len, 4)) { datawidth = 2; - src_step = 4; - des_step = 4; + src_step = SPRD_DMA_WORD_STEP; + des_step = SPRD_DMA_WORD_STEP; } else if (IS_ALIGNED(len, 2)) { datawidth = 1; - src_step = 2; - des_step = 2; + src_step = SPRD_DMA_SHORT_STEP; + des_step = SPRD_DMA_SHORT_STEP; } else { datawidth = 0; - src_step = 1; - des_step = 1; + src_step = SPRD_DMA_BYTE_STEP; + des_step = SPRD_DMA_BYTE_STEP; } fragment_len = SPRD_DMA_MEMCPY_MIN_SIZE; From d7c33cf8ff4e01e12ad854c92512bf76b5291928 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Thu, 19 Apr 2018 10:00:47 +0800 Subject: [PATCH 16/32] dmaengine: sprd: Define the DMA data width type Define the DMA data width type to make code more readable. Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index dcfa4179bf9e..65ff0a583615 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -176,6 +176,14 @@ enum sprd_dma_int_type { SPRD_DMA_CFGERR_INT, }; +/* dma data width values */ +enum sprd_dma_datawidth { + SPRD_DMA_DATAWIDTH_1_BYTE, + SPRD_DMA_DATAWIDTH_2_BYTES, + SPRD_DMA_DATAWIDTH_4_BYTES, + SPRD_DMA_DATAWIDTH_8_BYTES, +}; + /* dma channel hardware configuration */ struct sprd_dma_chn_hw { u32 pause; @@ -604,15 +612,15 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, u32 fix_mode = 0, fix_en = 0; if (IS_ALIGNED(len, 4)) { - datawidth = 2; + datawidth = SPRD_DMA_DATAWIDTH_4_BYTES; src_step = SPRD_DMA_WORD_STEP; des_step = SPRD_DMA_WORD_STEP; } else if (IS_ALIGNED(len, 2)) { - datawidth = 1; + datawidth = SPRD_DMA_DATAWIDTH_2_BYTES; src_step = SPRD_DMA_SHORT_STEP; des_step = SPRD_DMA_SHORT_STEP; } else { - datawidth = 0; + datawidth = SPRD_DMA_DATAWIDTH_1_BYTE; src_step = SPRD_DMA_BYTE_STEP; des_step = SPRD_DMA_BYTE_STEP; } From ab42ddb9eb71b580349b03e4fc5bfcf230422eb8 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Thu, 19 Apr 2018 10:00:48 +0800 Subject: [PATCH 17/32] dmaengine: sprd: Move DMA request mode and interrupt type into head file This patch will move the Spreadtrum DMA request mode and interrupt type into one head file for user to configure. Signed-off-by: Eric Long Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 52 +------------------------------- include/linux/dma/sprd-dma.h | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 51 deletions(-) create mode 100644 include/linux/dma/sprd-dma.h diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 65ff0a583615..ccdeb8f999e5 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -125,57 +126,6 @@ #define SPRD_DMA_SOFTWARE_UID 0 -/* - * enum sprd_dma_req_mode: define the DMA request mode - * @SPRD_DMA_FRAG_REQ: fragment request mode - * @SPRD_DMA_BLK_REQ: block request mode - * @SPRD_DMA_TRANS_REQ: transaction request mode - * @SPRD_DMA_LIST_REQ: link-list request mode - * - * We have 4 types request mode: fragment mode, block mode, transaction mode - * and linklist mode. One transaction can contain several blocks, one block can - * contain several fragments. Link-list mode means we can save several DMA - * configuration into one reserved memory, then DMA can fetch each DMA - * configuration automatically to start transfer. - */ -enum sprd_dma_req_mode { - SPRD_DMA_FRAG_REQ, - SPRD_DMA_BLK_REQ, - SPRD_DMA_TRANS_REQ, - SPRD_DMA_LIST_REQ, -}; - -/* - * enum sprd_dma_int_type: define the DMA interrupt type - * @SPRD_DMA_NO_INT: do not need generate DMA interrupts. - * @SPRD_DMA_FRAG_INT: fragment done interrupt when one fragment request - * is done. - * @SPRD_DMA_BLK_INT: block done interrupt when one block request is done. - * @SPRD_DMA_BLK_FRAG_INT: block and fragment interrupt when one fragment - * or one block request is done. - * @SPRD_DMA_TRANS_INT: tansaction done interrupt when one transaction - * request is done. - * @SPRD_DMA_TRANS_FRAG_INT: transaction and fragment interrupt when one - * transaction request or fragment request is done. - * @SPRD_DMA_TRANS_BLK_INT: transaction and block interrupt when one - * transaction request or block request is done. - * @SPRD_DMA_LIST_INT: link-list done interrupt when one link-list request - * is done. - * @SPRD_DMA_CFGERR_INT: configure error interrupt when configuration is - * incorrect. - */ -enum sprd_dma_int_type { - SPRD_DMA_NO_INT, - SPRD_DMA_FRAG_INT, - SPRD_DMA_BLK_INT, - SPRD_DMA_BLK_FRAG_INT, - SPRD_DMA_TRANS_INT, - SPRD_DMA_TRANS_FRAG_INT, - SPRD_DMA_TRANS_BLK_INT, - SPRD_DMA_LIST_INT, - SPRD_DMA_CFGERR_INT, -}; - /* dma data width values */ enum sprd_dma_datawidth { SPRD_DMA_DATAWIDTH_1_BYTE, diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h new file mode 100644 index 000000000000..c545162e725b --- /dev/null +++ b/include/linux/dma/sprd-dma.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _SPRD_DMA_H_ +#define _SPRD_DMA_H_ + +/* + * enum sprd_dma_req_mode: define the DMA request mode + * @SPRD_DMA_FRAG_REQ: fragment request mode + * @SPRD_DMA_BLK_REQ: block request mode + * @SPRD_DMA_TRANS_REQ: transaction request mode + * @SPRD_DMA_LIST_REQ: link-list request mode + * + * We have 4 types request mode: fragment mode, block mode, transaction mode + * and linklist mode. One transaction can contain several blocks, one block can + * contain several fragments. Link-list mode means we can save several DMA + * configuration into one reserved memory, then DMA can fetch each DMA + * configuration automatically to start transfer. + */ +enum sprd_dma_req_mode { + SPRD_DMA_FRAG_REQ, + SPRD_DMA_BLK_REQ, + SPRD_DMA_TRANS_REQ, + SPRD_DMA_LIST_REQ, +}; + +/* + * enum sprd_dma_int_type: define the DMA interrupt type + * @SPRD_DMA_NO_INT: do not need generate DMA interrupts. + * @SPRD_DMA_FRAG_INT: fragment done interrupt when one fragment request + * is done. + * @SPRD_DMA_BLK_INT: block done interrupt when one block request is done. + * @SPRD_DMA_BLK_FRAG_INT: block and fragment interrupt when one fragment + * or one block request is done. + * @SPRD_DMA_TRANS_INT: tansaction done interrupt when one transaction + * request is done. + * @SPRD_DMA_TRANS_FRAG_INT: transaction and fragment interrupt when one + * transaction request or fragment request is done. + * @SPRD_DMA_TRANS_BLK_INT: transaction and block interrupt when one + * transaction request or block request is done. + * @SPRD_DMA_LIST_INT: link-list done interrupt when one link-list request + * is done. + * @SPRD_DMA_CFGERR_INT: configure error interrupt when configuration is + * incorrect. + */ +enum sprd_dma_int_type { + SPRD_DMA_NO_INT, + SPRD_DMA_FRAG_INT, + SPRD_DMA_BLK_INT, + SPRD_DMA_BLK_FRAG_INT, + SPRD_DMA_TRANS_INT, + SPRD_DMA_TRANS_FRAG_INT, + SPRD_DMA_TRANS_BLK_INT, + SPRD_DMA_LIST_INT, + SPRD_DMA_CFGERR_INT, +}; + +#endif From 9f17b101f938f56c79ac645ea506de106b964ca9 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 24 Apr 2018 10:51:06 +0200 Subject: [PATCH 18/32] dmaengine: rcar-dmac: Document R-Car D3 bindings R8A77995's SYS-DMAC is R-Car Gen3-compatible. Signed-off-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman [simon: rebased] Signed-off-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt index aadfb236d53a..11796d43740a 100644 --- a/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,rcar-dmac.txt @@ -28,6 +28,7 @@ Required Properties: - "renesas,dmac-r8a7796" (R-Car M3-W) - "renesas,dmac-r8a77970" (R-Car V3M) - "renesas,dmac-r8a77980" (R-Car V3H) + - "renesas,dmac-r8a77995" (R-Car D3) - reg: base address and length of the registers block for the DMAC From d317d32b4f9ad68626fb527bde151f025a7bfbb1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 28 Apr 2018 23:03:52 +0100 Subject: [PATCH 19/32] dmaengine: stm32-mdma: fix spelling mistake: "avalaible" -> "available" Trivial fix to spelling mistake in dev_err error message text and make channel plural. Signed-off-by: Colin Ian King Signed-off-by: Vinod Koul --- drivers/dma/stm32-mdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c index 1ac775f93d9e..9dc450b7ace6 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -1521,7 +1521,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, c = dma_get_any_slave_channel(&dmadev->ddev); if (!c) { - dev_err(mdma2dev(dmadev), "No more channel avalaible\n"); + dev_err(mdma2dev(dmadev), "No more channels available\n"); return NULL; } From 9c87572eca7592b996d4c8c51dfd858fd7b1f151 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sat, 28 Apr 2018 12:57:54 -0700 Subject: [PATCH 20/32] dmaengine: axi-dmac: Request IRQ with IRQF_SHARED Request IRQ with IRQF_SHARED flag to enable setups with multiple instances of the core sharing a single IRQ line. This works out since the IRQ handler already checks if there is an actual IRQ pending and returns IRQ_NONE otherwise. Acked-by: Lars-Peter Clausen Signed-off-by: Moritz Fischer Signed-off-by: Vinod Koul --- drivers/dma/dma-axi-dmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c index 2419fe524daa..15b2453d2647 100644 --- a/drivers/dma/dma-axi-dmac.c +++ b/drivers/dma/dma-axi-dmac.c @@ -687,7 +687,7 @@ static int axi_dmac_probe(struct platform_device *pdev) if (ret) goto err_unregister_device; - ret = request_irq(dmac->irq, axi_dmac_interrupt_handler, 0, + ret = request_irq(dmac->irq, axi_dmac_interrupt_handler, IRQF_SHARED, dev_name(&pdev->dev), dmac); if (ret) goto err_unregister_of; From 1d48745b192a7a45bbdd3557b4c039609569ca41 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Wed, 18 Apr 2018 20:31:06 -0400 Subject: [PATCH 21/32] dmaengine: pl330: flush before wait, and add dev burst support. Do DMAFLUSHP _before_ the first DMAWFP to ensure controller and peripheral are in agreement about dma request state before first transfer. Add support for burst transfers to/from peripherals. In the new scheme, the controller does as many burst transfers as it can then transfers the remaining dregs with either single transfers for peripherals, or with a reduced size burst for memory-to-memory transfers. Signed-off-by: Frank Mori Hess Tested-by: Frank Mori Hess Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 211 +++++++++++++++++++++++++++++++++----------- 1 file changed, 160 insertions(+), 51 deletions(-) diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index de1fd59fe136..6237069001c4 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dmaengine.h" #define PL330_MAX_CHAN 8 @@ -1094,51 +1095,96 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], return off; } -static inline int _ldst_devtomem(struct pl330_dmac *pl330, unsigned dry_run, - u8 buf[], const struct _xfer_spec *pxs, - int cyc) +static u32 _emit_load(unsigned int dry_run, u8 buf[], + enum pl330_cond cond, enum dma_transfer_direction direction, + u8 peri) { int off = 0; - enum pl330_cond cond; - if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) - cond = BURST; - else - cond = SINGLE; + switch (direction) { + case DMA_MEM_TO_MEM: + /* fall through */ + case DMA_MEM_TO_DEV: + off += _emit_LD(dry_run, &buf[off], cond); + break; - while (cyc--) { - 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); + case DMA_DEV_TO_MEM: + if (cond == ALWAYS) { + off += _emit_LDP(dry_run, &buf[off], SINGLE, + peri); + off += _emit_LDP(dry_run, &buf[off], BURST, + peri); + } else { + off += _emit_LDP(dry_run, &buf[off], cond, + peri); + } + break; - if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)) - off += _emit_FLUSHP(dry_run, &buf[off], - pxs->desc->peri); + default: + /* this code should be unreachable */ + WARN_ON(1); + break; } return off; } -static inline int _ldst_memtodev(struct pl330_dmac *pl330, - unsigned dry_run, u8 buf[], - const struct _xfer_spec *pxs, int cyc) +static inline u32 _emit_store(unsigned int dry_run, u8 buf[], + enum pl330_cond cond, enum dma_transfer_direction direction, + u8 peri) +{ + int off = 0; + + switch (direction) { + case DMA_MEM_TO_MEM: + /* fall through */ + case DMA_DEV_TO_MEM: + off += _emit_ST(dry_run, &buf[off], cond); + break; + + case DMA_MEM_TO_DEV: + if (cond == ALWAYS) { + off += _emit_STP(dry_run, &buf[off], SINGLE, + peri); + off += _emit_STP(dry_run, &buf[off], BURST, + peri); + } else { + off += _emit_STP(dry_run, &buf[off], cond, + peri); + } + break; + + default: + /* this code should be unreachable */ + WARN_ON(1); + break; + } + + return off; +} + +static inline int _ldst_peripheral(struct pl330_dmac *pl330, + unsigned dry_run, u8 buf[], + const struct _xfer_spec *pxs, int cyc, + enum pl330_cond cond) { int off = 0; - enum pl330_cond cond; if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) cond = BURST; - else - cond = SINGLE; + /* + * do FLUSHP at beginning to clear any stale dma requests before the + * first WFP. + */ + if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)) + off += _emit_FLUSHP(dry_run, &buf[off], pxs->desc->peri); while (cyc--) { 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], cond, pxs->desc->peri); - - if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)) - off += _emit_FLUSHP(dry_run, &buf[off], - pxs->desc->peri); + off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype, + pxs->desc->peri); + off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype, + pxs->desc->peri); } return off; @@ -1148,19 +1194,65 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], const struct _xfer_spec *pxs, int cyc) { int off = 0; + enum pl330_cond cond = BRST_LEN(pxs->ccr) > 1 ? BURST : SINGLE; switch (pxs->desc->rqtype) { case DMA_MEM_TO_DEV: - off += _ldst_memtodev(pl330, dry_run, &buf[off], pxs, cyc); - break; + /* fall through */ case DMA_DEV_TO_MEM: - off += _ldst_devtomem(pl330, dry_run, &buf[off], pxs, cyc); + off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, cyc, + cond); break; + case DMA_MEM_TO_MEM: off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc); break; + default: - off += 0x40000000; /* Scare off the Client */ + /* this code should be unreachable */ + WARN_ON(1); + break; + } + + return off; +} + +/* + * transfer dregs with single transfers to peripheral, or a reduced size burst + * for mem-to-mem. + */ +static int _dregs(struct pl330_dmac *pl330, unsigned int dry_run, u8 buf[], + const struct _xfer_spec *pxs, int transfer_length) +{ + int off = 0; + int dregs_ccr; + + if (transfer_length == 0) + return off; + + switch (pxs->desc->rqtype) { + case DMA_MEM_TO_DEV: + /* fall through */ + case DMA_DEV_TO_MEM: + off += _ldst_peripheral(pl330, dry_run, &buf[off], pxs, + transfer_length, SINGLE); + break; + + case DMA_MEM_TO_MEM: + dregs_ccr = pxs->ccr; + dregs_ccr &= ~((0xf << CC_SRCBRSTLEN_SHFT) | + (0xf << CC_DSTBRSTLEN_SHFT)); + dregs_ccr |= (((transfer_length - 1) & 0xf) << + CC_SRCBRSTLEN_SHFT); + dregs_ccr |= (((transfer_length - 1) & 0xf) << + CC_DSTBRSTLEN_SHFT); + off += _emit_MOV(dry_run, &buf[off], CCR, dregs_ccr); + off += _ldst_memtomem(dry_run, &buf[off], pxs, 1); + break; + + default: + /* this code should be unreachable */ + WARN_ON(1); break; } @@ -1256,6 +1348,8 @@ static inline int _setup_loops(struct pl330_dmac *pl330, struct pl330_xfer *x = &pxs->desc->px; u32 ccr = pxs->ccr; unsigned long c, bursts = BYTE_TO_BURST(x->bytes, ccr); + int num_dregs = (x->bytes - BURST_TO_BYTE(bursts, ccr)) / + BRST_SIZE(ccr); int off = 0; while (bursts) { @@ -1263,6 +1357,7 @@ static inline int _setup_loops(struct pl330_dmac *pl330, off += _loop(pl330, dry_run, &buf[off], &c, pxs); bursts -= c; } + off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs); return off; } @@ -1294,7 +1389,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run, struct _xfer_spec *pxs) { struct _pl330_req *req = &thrd->req[index]; - struct pl330_xfer *x; u8 *buf = req->mc_cpu; int off = 0; @@ -1303,11 +1397,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run, /* DMAMOV CCR, ccr */ off += _emit_MOV(dry_run, &buf[off], CCR, pxs->ccr); - x = &pxs->desc->px; - /* Error if xfer length is not aligned at burst size */ - if (x->bytes % (BRST_SIZE(pxs->ccr) * BRST_LEN(pxs->ccr))) - return -EINVAL; - off += _setup_xfer(pl330, dry_run, &buf[off], pxs); /* DMASEV peripheral/event */ @@ -1365,6 +1454,20 @@ static int pl330_submit_req(struct pl330_thread *thrd, u32 ccr; int ret = 0; + switch (desc->rqtype) { + case DMA_MEM_TO_DEV: + break; + + case DMA_DEV_TO_MEM: + break; + + case DMA_MEM_TO_MEM: + break; + + default: + return -ENOTSUPP; + } + if (pl330->state == DYING || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) { dev_info(thrd->dmac->ddma.dev, "%s:%d\n", @@ -2106,6 +2209,18 @@ static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, return true; } +static int fixup_burst_len(int max_burst_len, int quirks) +{ + if (quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) + return 1; + else if (max_burst_len > PL330_MAX_BURST) + return PL330_MAX_BURST; + else if (max_burst_len < 1) + return 1; + else + return max_burst_len; +} + static int pl330_config(struct dma_chan *chan, struct dma_slave_config *slave_config) { @@ -2117,15 +2232,15 @@ static int pl330_config(struct dma_chan *chan, pch->fifo_addr = slave_config->dst_addr; if (slave_config->dst_addr_width) pch->burst_sz = __ffs(slave_config->dst_addr_width); - if (slave_config->dst_maxburst) - pch->burst_len = slave_config->dst_maxburst; + pch->burst_len = fixup_burst_len(slave_config->dst_maxburst, + pch->dmac->quirks); } else if (slave_config->direction == DMA_DEV_TO_MEM) { if (slave_config->src_addr) pch->fifo_addr = slave_config->src_addr; if (slave_config->src_addr_width) pch->burst_sz = __ffs(slave_config->src_addr_width); - if (slave_config->src_maxburst) - pch->burst_len = slave_config->src_maxburst; + pch->burst_len = fixup_burst_len(slave_config->src_maxburst, + pch->dmac->quirks); } return 0; @@ -2519,14 +2634,8 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) burst_len >>= desc->rqcfg.brst_size; /* src/dst_burst_len can't be more than 16 */ - if (burst_len > 16) - burst_len = 16; - - while (burst_len > 1) { - if (!(len % (burst_len << desc->rqcfg.brst_size))) - break; - burst_len--; - } + if (burst_len > PL330_MAX_BURST) + burst_len = PL330_MAX_BURST; return burst_len; } @@ -2598,7 +2707,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); @@ -2743,7 +2852,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); } From e891e41ee301a57fc74a4a0d4da60fdc9669e50c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 7 May 2018 01:40:34 +0000 Subject: [PATCH 22/32] dmaengine: sprd: Fix potential NULL dereference in sprd_dma_probe() platform_get_resource() may fail and return NULL, so we should better check it's return value to avoid a NULL pointer dereference a bit later in the code. This is detected by Coccinelle semantic patch. @@ expression pdev, res, n, t, e, e1, e2; @@ res = platform_get_resource(pdev, t, n); + if (!res) + return -EINVAL; ... when != res == NULL e = devm_ioremap_nocache(e1, res->start, e2); Fixes: 9b3b8171f7f4 ("dmaengine: sprd: Add Spreadtrum DMA driver") Signed-off-by: Wei Yongjun Reviewed-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index ccdeb8f999e5..dba7a17dee15 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -807,6 +807,8 @@ static int sprd_dma_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -EINVAL; sdev->glb_base = devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res)); if (!sdev->glb_base) From e7f063ae1a31e953bd2460d81697d18408f03641 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Wed, 9 May 2018 11:23:50 +0800 Subject: [PATCH 23/32] dmaengine: sprd: Use devm_ioremap_resource() to map memory Instead of checking the return value of platform_get_resource(), we can use devm_ioremap_resource() which has the NULL pointer check and the memory region requesting. Suggested-by: Lars-Peter Clausen Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index dba7a17dee15..e715d07aa632 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -807,10 +807,7 @@ static int sprd_dma_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; - sdev->glb_base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); + sdev->glb_base = devm_ioremap_resource(&pdev->dev, res); if (!sdev->glb_base) return -ENOMEM; From fd8d26adc9a909c0c099265cb62d5e5ec2a87e7e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 May 2018 11:48:07 +0300 Subject: [PATCH 24/32] dmaengine: sprd: fix an NULL vs IS_ERR() bug We recently cleaned this code up but we need to update the error handling as well. The devm_ioremap_resource() returns error pointers on error, never NULL. Fixes: e7f063ae1a31 ("dmaengine: sprd: Use devm_ioremap_resource() to map memory") Signed-off-by: Dan Carpenter Reviewed-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index e715d07aa632..36df3b096bbc 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -808,8 +808,8 @@ static int sprd_dma_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sdev->glb_base = devm_ioremap_resource(&pdev->dev, res); - if (!sdev->glb_base) - return -ENOMEM; + if (IS_ERR(sdev->glb_base)) + return PTR_ERR(sdev->glb_base); dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask); sdev->total_chns = chn_count; From 5c63de1eaadae5c7941c283e6d5577d8a588159d Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 17 May 2018 10:59:16 +0100 Subject: [PATCH 25/32] dmaengine: qcom: bam_dma: fix invalid assignment warning Building kernel with W=1 throws below invalid assignment warnings. bam_dma.c:676:44: warning: invalid assignment: += bam_dma.c:676:44: left side has type unsigned long bam_dma.c:676:44: right side has type restricted __le16 bam_dma.c:921:41: warning: invalid assignment: += bam_dma.c:921:41: left side has type unsigned long bam_dma.c:921:41: right side has type restricted __le16 Fix them!. Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul --- drivers/dma/qcom/bam_dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index d29275b97e84..4f66d613936d 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -665,7 +665,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, remainder = 0; } - async_desc->length += desc->size; + async_desc->length += le16_to_cpu(desc->size); desc++; } while (remainder > 0); } @@ -910,7 +910,8 @@ static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie, continue; for (i = 0; i < async_desc->num_desc; i++) - residue += async_desc->curr_desc[i].size; + residue += le16_to_cpu( + async_desc->curr_desc[i].size); } } From 9c3655cba0a84bb95c68b0570a060c2bee6ccc2c Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 17 May 2018 10:59:15 +0100 Subject: [PATCH 26/32] dmaengine: qcom: bam_dma: fix some doc warnings. Building kernel with W=1 throws up below warnings: bam_dma.c:459: warning: Function parameter or member 'dir' not described in 'bam_chan_init_hw' bam_dma.c:697: warning: Function parameter or member 'chan' not described in 'bam_dma_terminate_all' bam_dma.c:697: warning: Excess function parameter 'bchan' description in 'bam_dma_terminate_all' bam_dma.c:964: warning: Function parameter or member 'bchan' not described in 'bam_start_dma' Fix these!. Signed-off-by: Srinivas Kandagatla Signed-off-by: Vinod Koul --- drivers/dma/qcom/bam_dma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c index 4f66d613936d..b1628d5db6d7 100644 --- a/drivers/dma/qcom/bam_dma.c +++ b/drivers/dma/qcom/bam_dma.c @@ -451,6 +451,7 @@ static void bam_reset_channel(struct bam_chan *bchan) /** * bam_chan_init_hw - Initialize channel hardware * @bchan: bam channel + * @dir: DMA transfer direction * * This function resets and initializes the BAM channel */ @@ -679,7 +680,7 @@ err_out: /** * bam_dma_terminate_all - terminate all transactions on a channel - * @bchan: bam dma channel + * @chan: bam dma channel * * Dequeues and frees all transactions * No callbacks are done @@ -951,7 +952,7 @@ static void bam_apply_new_config(struct bam_chan *bchan, /** * bam_start_dma - start next transaction - * @bchan - bam dma channel + * @bchan: bam dma channel */ static void bam_start_dma(struct bam_chan *bchan) { From 6fc1d18ec9df502dddb9b4d57420170b3dd73f05 Mon Sep 17 00:00:00 2001 From: Hiroyuki Yokoyama Date: Wed, 16 May 2018 15:06:18 +0200 Subject: [PATCH 27/32] dmaengine: usb-dmac: Document R8A7799{0,5} bindings Renesas R-Car D3 (R8A77995) and E3 (R8A77990) SoCs also have the R-Car gen2/3 compatible DMA controllers, so document the SoC specific binding. Signed-off-by: Hiroyuki Yokoyama [uli: squashed] Signed-off-by: Ulrich Hecht Reviewed-by: Simon Horman Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt index 9dc935e24e55..482e54362d3e 100644 --- a/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt +++ b/Documentation/devicetree/bindings/dma/renesas,usb-dmac.txt @@ -12,6 +12,8 @@ Required Properties: - "renesas,r8a7795-usb-dmac" (R-Car H3) - "renesas,r8a7796-usb-dmac" (R-Car M3-W) - "renesas,r8a77965-usb-dmac" (R-Car M3-N) + - "renesas,r8a77990-usb-dmac" (R-Car E3) + - "renesas,r8a77995-usb-dmac" (R-Car D3) - reg: base address and length of the registers block for the DMAC - interrupts: interrupt specifiers for the DMAC, one for each entry in interrupt-names. From c01faaca10bb3cd00584a1a7bb4f0e9db72c5d24 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 21 May 2018 23:53:30 -0300 Subject: [PATCH 28/32] dmaengine: imx-sdma: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index ccd03c3cedfe..f077992635c2 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1,21 +1,14 @@ -/* - * drivers/dma/imx-sdma.c - * - * This file contains a driver for the Freescale Smart DMA engine - * - * Copyright 2010 Sascha Hauer, Pengutronix - * - * Based on code from Freescale: - * - * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// drivers/dma/imx-sdma.c +// +// This file contains a driver for the Freescale Smart DMA engine +// +// Copyright 2010 Sascha Hauer, Pengutronix +// +// Based on code from Freescale: +// +// Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. #include #include From d9617a3f2bd3d35b93d36ea5c84eaf430f192ecb Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 21 May 2018 23:53:31 -0300 Subject: [PATCH 29/32] dmaengine: mxs-dma: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/mxs-dma.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c index 41d167921fab..ae5182ff0128 100644 --- a/drivers/dma/mxs-dma.c +++ b/drivers/dma/mxs-dma.c @@ -1,12 +1,8 @@ -/* - * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. - * - * Refer to drivers/dma/imx-sdma.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. +// +// Refer to drivers/dma/imx-sdma.c #include #include From ce9c28ca6c6f572c0bb6e7936e8f42cd1595b820 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 21 May 2018 23:53:32 -0300 Subject: [PATCH 30/32] dmaengine: imx-dma: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 715b39ae5a46..75b6ff0415ee 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1,19 +1,13 @@ -/* - * drivers/dma/imx-dma.c - * - * This file contains a driver for the Freescale i.MX DMA engine - * found on i.MX1/21/27 - * - * Copyright 2010 Sascha Hauer, Pengutronix - * Copyright 2012 Javier Martin, Vista Silicon - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ +// SPDX-License-Identifier: GPL-2.0+ +// +// drivers/dma/imx-dma.c +// +// This file contains a driver for the Freescale i.MX DMA engine +// found on i.MX1/21/27 +// +// Copyright 2010 Sascha Hauer, Pengutronix +// Copyright 2012 Javier Martin, Vista Silicon + #include #include #include From 32fa20139ebc1521954b9ccb411e5772411efc87 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Wed, 23 May 2018 17:31:10 +0800 Subject: [PATCH 31/32] dmaengine: sprd: Optimize the sprd_dma_prep_dma_memcpy() This is one preparation patch, we can use default DMA configuration to implement the device_prep_dma_memcpy() interface instead of issuing sprd_dma_config(). We will implement one new sprd_dma_config() function with introducing device_prep_slave_sg() interface in following patch. So we can remove the obsolete sprd_dma_config() firstly. Signed-off-by: Eric Long Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 167 ++++++++++------------------------------- 1 file changed, 39 insertions(+), 128 deletions(-) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 36df3b096bbc..1ca5acd2a4ac 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -552,147 +552,58 @@ static void sprd_dma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&schan->vc.lock, flags); } -static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, - dma_addr_t dest, dma_addr_t src, size_t len) -{ - struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); - struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; - u32 datawidth, src_step, des_step, fragment_len; - u32 block_len, req_mode, irq_mode, transcation_len; - u32 fix_mode = 0, fix_en = 0; - - if (IS_ALIGNED(len, 4)) { - datawidth = SPRD_DMA_DATAWIDTH_4_BYTES; - src_step = SPRD_DMA_WORD_STEP; - des_step = SPRD_DMA_WORD_STEP; - } else if (IS_ALIGNED(len, 2)) { - datawidth = SPRD_DMA_DATAWIDTH_2_BYTES; - src_step = SPRD_DMA_SHORT_STEP; - des_step = SPRD_DMA_SHORT_STEP; - } else { - datawidth = SPRD_DMA_DATAWIDTH_1_BYTE; - src_step = SPRD_DMA_BYTE_STEP; - des_step = SPRD_DMA_BYTE_STEP; - } - - fragment_len = SPRD_DMA_MEMCPY_MIN_SIZE; - if (len <= SPRD_DMA_BLK_LEN_MASK) { - block_len = len; - transcation_len = 0; - req_mode = SPRD_DMA_BLK_REQ; - irq_mode = SPRD_DMA_BLK_INT; - } else { - block_len = SPRD_DMA_MEMCPY_MIN_SIZE; - transcation_len = len; - req_mode = SPRD_DMA_TRANS_REQ; - irq_mode = SPRD_DMA_TRANS_INT; - } - - hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; - hw->wrap_ptr = (u32)((src >> SPRD_DMA_HIGH_ADDR_OFFSET) & - SPRD_DMA_HIGH_ADDR_MASK); - hw->wrap_to = (u32)((dest >> SPRD_DMA_HIGH_ADDR_OFFSET) & - SPRD_DMA_HIGH_ADDR_MASK); - - hw->src_addr = (u32)(src & SPRD_DMA_LOW_ADDR_MASK); - hw->des_addr = (u32)(dest & SPRD_DMA_LOW_ADDR_MASK); - - if ((src_step != 0 && des_step != 0) || (src_step | des_step) == 0) { - fix_en = 0; - } else { - fix_en = 1; - if (src_step) - fix_mode = 1; - else - fix_mode = 0; - } - - hw->frg_len = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET | - datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET | - req_mode << SPRD_DMA_REQ_MODE_OFFSET | - fix_mode << SPRD_DMA_FIX_SEL_OFFSET | - fix_en << SPRD_DMA_FIX_EN_OFFSET | - (fragment_len & SPRD_DMA_FRG_LEN_MASK); - hw->blk_len = block_len & SPRD_DMA_BLK_LEN_MASK; - - hw->intc = SPRD_DMA_CFG_ERR_INT_EN; - - switch (irq_mode) { - case SPRD_DMA_NO_INT: - break; - - case SPRD_DMA_FRAG_INT: - hw->intc |= SPRD_DMA_FRAG_INT_EN; - break; - - case SPRD_DMA_BLK_INT: - hw->intc |= SPRD_DMA_BLK_INT_EN; - break; - - case SPRD_DMA_BLK_FRAG_INT: - hw->intc |= SPRD_DMA_BLK_INT_EN | SPRD_DMA_FRAG_INT_EN; - break; - - case SPRD_DMA_TRANS_INT: - hw->intc |= SPRD_DMA_TRANS_INT_EN; - break; - - case SPRD_DMA_TRANS_FRAG_INT: - hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_FRAG_INT_EN; - break; - - case SPRD_DMA_TRANS_BLK_INT: - hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_BLK_INT_EN; - break; - - case SPRD_DMA_LIST_INT: - hw->intc |= SPRD_DMA_LIST_INT_EN; - break; - - case SPRD_DMA_CFGERR_INT: - hw->intc |= SPRD_DMA_CFG_ERR_INT_EN; - break; - - default: - dev_err(sdev->dma_dev.dev, "invalid irq mode\n"); - return -EINVAL; - } - - if (transcation_len == 0) - hw->trsc_len = block_len & SPRD_DMA_TRSC_LEN_MASK; - else - hw->trsc_len = transcation_len & SPRD_DMA_TRSC_LEN_MASK; - - hw->trsf_step = (des_step & SPRD_DMA_TRSF_STEP_MASK) << - SPRD_DMA_DEST_TRSF_STEP_OFFSET | - (src_step & SPRD_DMA_TRSF_STEP_MASK) << - SPRD_DMA_SRC_TRSF_STEP_OFFSET; - - hw->frg_step = 0; - hw->src_blk_step = 0; - hw->des_blk_step = 0; - hw->src_blk_step = 0; - return 0; -} - static struct dma_async_tx_descriptor * sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) { struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); struct sprd_dma_desc *sdesc; - int ret; + struct sprd_dma_chn_hw *hw; + enum sprd_dma_datawidth datawidth; + u32 step, temp; sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); if (!sdesc) return NULL; - ret = sprd_dma_config(chan, sdesc, dest, src, len); - if (ret) { - kfree(sdesc); - return NULL; + hw = &sdesc->chn_hw; + + hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; + hw->intc = SPRD_DMA_TRANS_INT | SPRD_DMA_CFG_ERR_INT_EN; + hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK; + hw->des_addr = dest & SPRD_DMA_LOW_ADDR_MASK; + hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) & + SPRD_DMA_HIGH_ADDR_MASK; + hw->wrap_to = (dest >> SPRD_DMA_HIGH_ADDR_OFFSET) & + SPRD_DMA_HIGH_ADDR_MASK; + + if (IS_ALIGNED(len, 8)) { + datawidth = SPRD_DMA_DATAWIDTH_8_BYTES; + step = SPRD_DMA_DWORD_STEP; + } else if (IS_ALIGNED(len, 4)) { + datawidth = SPRD_DMA_DATAWIDTH_4_BYTES; + step = SPRD_DMA_WORD_STEP; + } else if (IS_ALIGNED(len, 2)) { + datawidth = SPRD_DMA_DATAWIDTH_2_BYTES; + step = SPRD_DMA_SHORT_STEP; + } else { + datawidth = SPRD_DMA_DATAWIDTH_1_BYTE; + step = SPRD_DMA_BYTE_STEP; } + temp = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET; + temp |= datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET; + temp |= SPRD_DMA_TRANS_REQ << SPRD_DMA_REQ_MODE_OFFSET; + temp |= len & SPRD_DMA_FRG_LEN_MASK; + hw->frg_len = temp; + + hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK; + hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK; + + temp = (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET; + temp |= (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; + hw->trsf_step = temp; + return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); } From ca1b7d3daff43a269fb7a0479055ac5b741638d8 Mon Sep 17 00:00:00 2001 From: Eric Long Date: Wed, 23 May 2018 17:31:11 +0800 Subject: [PATCH 32/32] dmaengine: sprd: Add Spreadtrum DMA configuration This patch adds the 'device_config' and 'device_prep_slave_sg' interfaces for users to configure DMA, as well as adding one 'struct sprd_dma_config' structure to save Spreadtrum DMA configuration for each DMA channel. Signed-off-by: Eric Long Signed-off-by: Baolin Wang Signed-off-by: Vinod Koul --- drivers/dma/sprd-dma.c | 182 +++++++++++++++++++++++++++++++++++ include/linux/dma/sprd-dma.h | 4 + 2 files changed, 186 insertions(+) diff --git a/drivers/dma/sprd-dma.c b/drivers/dma/sprd-dma.c index 1ca5acd2a4ac..ab69f835ea02 100644 --- a/drivers/dma/sprd-dma.c +++ b/drivers/dma/sprd-dma.c @@ -164,6 +164,7 @@ struct sprd_dma_desc { struct sprd_dma_chn { struct virt_dma_chan vc; void __iomem *chn_base; + struct dma_slave_config slave_cfg; u32 chn_num; u32 dev_id; struct sprd_dma_desc *cur_desc; @@ -552,6 +553,129 @@ static void sprd_dma_issue_pending(struct dma_chan *chan) spin_unlock_irqrestore(&schan->vc.lock, flags); } +static int sprd_dma_get_datawidth(enum dma_slave_buswidth buswidth) +{ + switch (buswidth) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + case DMA_SLAVE_BUSWIDTH_2_BYTES: + case DMA_SLAVE_BUSWIDTH_4_BYTES: + case DMA_SLAVE_BUSWIDTH_8_BYTES: + return ffs(buswidth) - 1; + + default: + return -EINVAL; + } +} + +static int sprd_dma_get_step(enum dma_slave_buswidth buswidth) +{ + switch (buswidth) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + case DMA_SLAVE_BUSWIDTH_2_BYTES: + case DMA_SLAVE_BUSWIDTH_4_BYTES: + case DMA_SLAVE_BUSWIDTH_8_BYTES: + return buswidth; + + default: + return -EINVAL; + } +} + +static int sprd_dma_fill_desc(struct dma_chan *chan, + struct sprd_dma_desc *sdesc, + dma_addr_t src, dma_addr_t dst, u32 len, + enum dma_transfer_direction dir, + unsigned long flags, + struct dma_slave_config *slave_cfg) +{ + struct sprd_dma_dev *sdev = to_sprd_dma_dev(chan); + struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct sprd_dma_chn_hw *hw = &sdesc->chn_hw; + u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK; + u32 int_mode = flags & SPRD_DMA_INT_MASK; + int src_datawidth, dst_datawidth, src_step, dst_step; + u32 temp, fix_mode = 0, fix_en = 0; + + if (dir == DMA_MEM_TO_DEV) { + src_step = sprd_dma_get_step(slave_cfg->src_addr_width); + if (src_step < 0) { + dev_err(sdev->dma_dev.dev, "invalid source step\n"); + return src_step; + } + dst_step = SPRD_DMA_NONE_STEP; + } else { + dst_step = sprd_dma_get_step(slave_cfg->dst_addr_width); + if (dst_step < 0) { + dev_err(sdev->dma_dev.dev, "invalid destination step\n"); + return dst_step; + } + src_step = SPRD_DMA_NONE_STEP; + } + + src_datawidth = sprd_dma_get_datawidth(slave_cfg->src_addr_width); + if (src_datawidth < 0) { + dev_err(sdev->dma_dev.dev, "invalid source datawidth\n"); + return src_datawidth; + } + + dst_datawidth = sprd_dma_get_datawidth(slave_cfg->dst_addr_width); + if (dst_datawidth < 0) { + dev_err(sdev->dma_dev.dev, "invalid destination datawidth\n"); + return dst_datawidth; + } + + if (slave_cfg->slave_id) + schan->dev_id = slave_cfg->slave_id; + + hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET; + + /* + * wrap_ptr and wrap_to will save the high 4 bits source address and + * destination address. + */ + hw->wrap_ptr = (src >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK; + hw->wrap_to = (dst >> SPRD_DMA_HIGH_ADDR_OFFSET) & SPRD_DMA_HIGH_ADDR_MASK; + hw->src_addr = src & SPRD_DMA_LOW_ADDR_MASK; + hw->des_addr = dst & SPRD_DMA_LOW_ADDR_MASK; + + /* + * If the src step and dst step both are 0 or both are not 0, that means + * we can not enable the fix mode. If one is 0 and another one is not, + * we can enable the fix mode. + */ + if ((src_step != 0 && dst_step != 0) || (src_step | dst_step) == 0) { + fix_en = 0; + } else { + fix_en = 1; + if (src_step) + fix_mode = 1; + else + fix_mode = 0; + } + + hw->intc = int_mode | SPRD_DMA_CFG_ERR_INT_EN; + + temp = src_datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET; + temp |= dst_datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET; + temp |= req_mode << SPRD_DMA_REQ_MODE_OFFSET; + temp |= fix_mode << SPRD_DMA_FIX_SEL_OFFSET; + temp |= fix_en << SPRD_DMA_FIX_EN_OFFSET; + temp |= slave_cfg->src_maxburst & SPRD_DMA_FRG_LEN_MASK; + hw->frg_len = temp; + + hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK; + hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK; + + temp = (dst_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET; + temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET; + hw->trsf_step = temp; + + hw->frg_step = 0; + hw->src_blk_step = 0; + hw->des_blk_step = 0; + return 0; +} + static struct dma_async_tx_descriptor * sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) @@ -607,6 +731,62 @@ sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); } +static struct dma_async_tx_descriptor * +sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sglen, enum dma_transfer_direction dir, + unsigned long flags, void *context) +{ + struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct dma_slave_config *slave_cfg = &schan->slave_cfg; + dma_addr_t src = 0, dst = 0; + struct sprd_dma_desc *sdesc; + struct scatterlist *sg; + u32 len = 0; + int ret, i; + + /* TODO: now we only support one sg for each DMA configuration. */ + if (!is_slave_direction(dir) || sglen > 1) + return NULL; + + sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT); + if (!sdesc) + return NULL; + + for_each_sg(sgl, sg, sglen, i) { + len = sg_dma_len(sg); + + if (dir == DMA_MEM_TO_DEV) { + src = sg_dma_address(sg); + dst = slave_cfg->dst_addr; + } else { + src = slave_cfg->src_addr; + dst = sg_dma_address(sg); + } + } + + ret = sprd_dma_fill_desc(chan, sdesc, src, dst, len, dir, flags, + slave_cfg); + if (ret) { + kfree(sdesc); + return NULL; + } + + return vchan_tx_prep(&schan->vc, &sdesc->vd, flags); +} + +static int sprd_dma_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); + struct dma_slave_config *slave_cfg = &schan->slave_cfg; + + if (!is_slave_direction(config->direction)) + return -EINVAL; + + memcpy(slave_cfg, config, sizeof(*config)); + return 0; +} + static int sprd_dma_pause(struct dma_chan *chan) { struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); @@ -733,6 +913,8 @@ static int sprd_dma_probe(struct platform_device *pdev) sdev->dma_dev.device_tx_status = sprd_dma_tx_status; sdev->dma_dev.device_issue_pending = sprd_dma_issue_pending; sdev->dma_dev.device_prep_dma_memcpy = sprd_dma_prep_dma_memcpy; + sdev->dma_dev.device_prep_slave_sg = sprd_dma_prep_slave_sg; + sdev->dma_dev.device_config = sprd_dma_slave_config; sdev->dma_dev.device_pause = sprd_dma_pause; sdev->dma_dev.device_resume = sprd_dma_resume; sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all; diff --git a/include/linux/dma/sprd-dma.h b/include/linux/dma/sprd-dma.h index c545162e725b..b0115e340fbc 100644 --- a/include/linux/dma/sprd-dma.h +++ b/include/linux/dma/sprd-dma.h @@ -3,6 +3,10 @@ #ifndef _SPRD_DMA_H_ #define _SPRD_DMA_H_ +#define SPRD_DMA_REQ_SHIFT 16 +#define SPRD_DMA_FLAGS(req_mode, int_type) \ + ((req_mode) << SPRD_DMA_REQ_SHIFT | (int_type)) + /* * enum sprd_dma_req_mode: define the DMA request mode * @SPRD_DMA_FRAG_REQ: fragment request mode