Commit 2996148a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'dmaengine-4.18-rc1' of git://git.infradead.org/users/vkoul/slave-dma

Pull dmaengine updates from Vinod Koul:

 - updates to sprd, bam_dma, stm drivers

 - remove VLAs in dmatest

 - move TI drivers to their own subdir

 - switch to SPDX tags for ima/mxs dma drivers

 - simplify getting .drvdata on bunch of drivers by Wolfram Sang

* tag 'dmaengine-4.18-rc1' of git://git.infradead.org/users/vkoul/slave-dma: (32 commits)
  dmaengine: sprd: Add Spreadtrum DMA configuration
  dmaengine: sprd: Optimize the sprd_dma_prep_dma_memcpy()
  dmaengine: imx-dma: Switch to SPDX identifier
  dmaengine: mxs-dma: Switch to SPDX identifier
  dmaengine: imx-sdma: Switch to SPDX identifier
  dmaengine: usb-dmac: Document R8A7799{0,5} bindings
  dmaengine: qcom: bam_dma: fix some doc warnings.
  dmaengine: qcom: bam_dma: fix invalid assignment warning
  dmaengine: sprd: fix an NULL vs IS_ERR() bug
  dmaengine: sprd: Use devm_ioremap_resource() to map memory
  dmaengine: sprd: Fix potential NULL dereference in sprd_dma_probe()
  dmaengine: pl330: flush before wait, and add dev burst support.
  dmaengine: axi-dmac: Request IRQ with IRQF_SHARED
  dmaengine: stm32-mdma: fix spelling mistake: "avalaible" -> "available"
  dmaengine: rcar-dmac: Document R-Car D3 bindings
  dmaengine: sprd: Move DMA request mode and interrupt type into head file
  dmaengine: sprd: Define the DMA data width type
  dmaengine: sprd: Define the DMA transfer step type
  dmaengine: ti: New directory for Texas Instruments DMA drivers
  dmaengine: shdmac: Change platform check to CONFIG_ARCH_RENESAS
  ...
parents 18f18376 67f31971
...@@ -29,6 +29,7 @@ Required Properties: ...@@ -29,6 +29,7 @@ Required Properties:
- "renesas,dmac-r8a77965" (R-Car M3-N) - "renesas,dmac-r8a77965" (R-Car M3-N)
- "renesas,dmac-r8a77970" (R-Car V3M) - "renesas,dmac-r8a77970" (R-Car V3M)
- "renesas,dmac-r8a77980" (R-Car V3H) - "renesas,dmac-r8a77980" (R-Car V3H)
- "renesas,dmac-r8a77995" (R-Car D3)
- reg: base address and length of the registers block for the DMAC - reg: base address and length of the registers block for the DMAC
......
...@@ -12,6 +12,8 @@ Required Properties: ...@@ -12,6 +12,8 @@ Required Properties:
- "renesas,r8a7795-usb-dmac" (R-Car H3) - "renesas,r8a7795-usb-dmac" (R-Car H3)
- "renesas,r8a7796-usb-dmac" (R-Car M3-W) - "renesas,r8a7796-usb-dmac" (R-Car M3-W)
- "renesas,r8a77965-usb-dmac" (R-Car M3-N) - "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 - reg: base address and length of the registers block for the DMAC
- interrupts: interrupt specifiers for the DMAC, one for each entry in - interrupts: interrupt specifiers for the DMAC, one for each entry in
interrupt-names. interrupt-names.
......
...@@ -11790,6 +11790,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rkuo/linux-hexagon-kernel.g ...@@ -11790,6 +11790,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rkuo/linux-hexagon-kernel.g
S: Supported S: Supported
F: arch/hexagon/ F: arch/hexagon/
QUALCOMM HIDMA DRIVER
M: Sinan Kaya <okaya@codeaurora.org>
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 QUALCOMM IOMMU
M: Rob Clark <robdclark@gmail.com> M: Rob Clark <robdclark@gmail.com>
L: iommu@lists.linux-foundation.org L: iommu@lists.linux-foundation.org
......
...@@ -151,13 +151,6 @@ config DMA_JZ4780 ...@@ -151,13 +151,6 @@ config DMA_JZ4780
If you have a board based on such a SoC and wish to use DMA for 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. 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 config DMA_SA11X0
tristate "SA-11x0 DMA support" tristate "SA-11x0 DMA support"
depends on ARCH_SA1100 || COMPILE_TEST depends on ARCH_SA1100 || COMPILE_TEST
...@@ -574,28 +567,6 @@ config TIMB_DMA ...@@ -574,28 +567,6 @@ config TIMB_DMA
help help
Enable support for the Timberdale FPGA DMA engine. 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 config XGENE_DMA
tristate "APM X-Gene DMA support" tristate "APM X-Gene DMA support"
depends on ARCH_XGENE || COMPILE_TEST depends on ARCH_XGENE || COMPILE_TEST
...@@ -653,6 +624,8 @@ source "drivers/dma/hsu/Kconfig" ...@@ -653,6 +624,8 @@ source "drivers/dma/hsu/Kconfig"
source "drivers/dma/sh/Kconfig" source "drivers/dma/sh/Kconfig"
source "drivers/dma/ti/Kconfig"
# clients # clients
comment "DMA Clients" comment "DMA Clients"
depends on DMA_ENGINE depends on DMA_ENGINE
......
...@@ -24,7 +24,6 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o ...@@ -24,7 +24,6 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.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_SA11X0) += sa11x0-dma.o
obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o
obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
...@@ -69,13 +68,11 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o ...@@ -69,13 +68,11 @@ obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o
obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o obj-$(CONFIG_TEGRA210_ADMA) += tegra210-adma.o
obj-$(CONFIG_TIMB_DMA) += timb_dma.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_XGENE_DMA) += xgene-dma.o
obj-$(CONFIG_ZX_DMA) += zx_dma.o obj-$(CONFIG_ZX_DMA) += zx_dma.o
obj-$(CONFIG_ST_FDMA) += st_fdma.o obj-$(CONFIG_ST_FDMA) += st_fdma.o
obj-y += mediatek/ obj-y += mediatek/
obj-y += qcom/ obj-y += qcom/
obj-y += ti/
obj-y += xilinx/ obj-y += xilinx/
...@@ -2041,8 +2041,7 @@ static void at_dma_shutdown(struct platform_device *pdev) ...@@ -2041,8 +2041,7 @@ static void at_dma_shutdown(struct platform_device *pdev)
static int at_dma_prepare(struct device *dev) static int at_dma_prepare(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = dev_get_drvdata(dev);
struct at_dma *atdma = platform_get_drvdata(pdev);
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
list_for_each_entry_safe(chan, _chan, &atdma->dma_common.channels, 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) ...@@ -2076,8 +2075,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan)
static int at_dma_suspend_noirq(struct device *dev) static int at_dma_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = dev_get_drvdata(dev);
struct at_dma *atdma = platform_get_drvdata(pdev);
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
/* preserve data */ /* preserve data */
...@@ -2118,8 +2116,7 @@ static void atc_resume_cyclic(struct at_dma_chan *atchan) ...@@ -2118,8 +2116,7 @@ static void atc_resume_cyclic(struct at_dma_chan *atchan)
static int at_dma_resume_noirq(struct device *dev) static int at_dma_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_dma *atdma = dev_get_drvdata(dev);
struct at_dma *atdma = platform_get_drvdata(pdev);
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
/* bring back DMA controller */ /* bring back DMA controller */
......
...@@ -1833,8 +1833,7 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan) ...@@ -1833,8 +1833,7 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int atmel_xdmac_prepare(struct device *dev) static int atmel_xdmac_prepare(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_xdmac *atxdmac = dev_get_drvdata(dev);
struct at_xdmac *atxdmac = platform_get_drvdata(pdev);
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
...@@ -1853,8 +1852,7 @@ static int atmel_xdmac_prepare(struct device *dev) ...@@ -1853,8 +1852,7 @@ static int atmel_xdmac_prepare(struct device *dev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int atmel_xdmac_suspend(struct device *dev) static int atmel_xdmac_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_xdmac *atxdmac = dev_get_drvdata(dev);
struct at_xdmac *atxdmac = platform_get_drvdata(pdev);
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
...@@ -1878,8 +1876,7 @@ static int atmel_xdmac_suspend(struct device *dev) ...@@ -1878,8 +1876,7 @@ static int atmel_xdmac_suspend(struct device *dev)
static int atmel_xdmac_resume(struct device *dev) static int atmel_xdmac_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct at_xdmac *atxdmac = dev_get_drvdata(dev);
struct at_xdmac *atxdmac = platform_get_drvdata(pdev);
struct at_xdmac_chan *atchan; struct at_xdmac_chan *atchan;
struct dma_chan *chan, *_chan; struct dma_chan *chan, *_chan;
int i; int i;
......
...@@ -687,7 +687,7 @@ static int axi_dmac_probe(struct platform_device *pdev) ...@@ -687,7 +687,7 @@ static int axi_dmac_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_unregister_device; 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); dev_name(&pdev->dev), dmac);
if (ret) if (ret)
goto err_unregister_of; goto err_unregister_of;
......
...@@ -468,6 +468,8 @@ static int dmatest_func(void *data) ...@@ -468,6 +468,8 @@ static int dmatest_func(void *data)
unsigned long long total_len = 0; unsigned long long total_len = 0;
u8 align = 0; u8 align = 0;
bool is_memset = false; bool is_memset = false;
dma_addr_t *srcs;
dma_addr_t *dma_pq;
set_freezable(); set_freezable();
...@@ -551,6 +553,14 @@ static int dmatest_func(void *data) ...@@ -551,6 +553,14 @@ static int dmatest_func(void *data)
set_user_nice(current, 10); 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 * src and dst buffers are freed by ourselves below
*/ */
...@@ -561,7 +571,6 @@ static int dmatest_func(void *data) ...@@ -561,7 +571,6 @@ static int dmatest_func(void *data)
&& !(params->iterations && total_tests >= params->iterations)) { && !(params->iterations && total_tests >= params->iterations)) {
struct dma_async_tx_descriptor *tx = NULL; struct dma_async_tx_descriptor *tx = NULL;
struct dmaengine_unmap_data *um; struct dmaengine_unmap_data *um;
dma_addr_t srcs[src_cnt];
dma_addr_t *dsts; dma_addr_t *dsts;
unsigned int src_off, dst_off, len; unsigned int src_off, dst_off, len;
...@@ -676,8 +685,6 @@ static int dmatest_func(void *data) ...@@ -676,8 +685,6 @@ static int dmatest_func(void *data)
srcs, src_cnt, srcs, src_cnt,
len, flags); len, flags);
else if (thread->type == DMA_PQ) { else if (thread->type == DMA_PQ) {
dma_addr_t dma_pq[dst_cnt];
for (i = 0; i < dst_cnt; i++) for (i = 0; i < dst_cnt; i++)
dma_pq[i] = dsts[i] + dst_off; dma_pq[i] = dsts[i] + dst_off;
tx = dev->device_prep_dma_pq(chan, dma_pq, srcs, tx = dev->device_prep_dma_pq(chan, dma_pq, srcs,
...@@ -779,6 +786,9 @@ static int dmatest_func(void *data) ...@@ -779,6 +786,9 @@ static int dmatest_func(void *data)
runtime = ktime_to_us(ktime); runtime = ktime_to_us(ktime);
ret = 0; ret = 0;
kfree(dma_pq);
err_srcs_array:
kfree(srcs);
err_dstbuf: err_dstbuf:
for (i = 0; thread->udsts[i]; i++) for (i = 0; thread->udsts[i]; i++)
kfree(thread->udsts[i]); kfree(thread->udsts[i]);
......
...@@ -293,8 +293,7 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table); ...@@ -293,8 +293,7 @@ MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
static int dw_suspend_late(struct device *dev) static int dw_suspend_late(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = dev_get_drvdata(dev);
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
dw_dma_disable(chip); dw_dma_disable(chip);
clk_disable_unprepare(chip->clk); clk_disable_unprepare(chip->clk);
...@@ -304,8 +303,7 @@ static int dw_suspend_late(struct device *dev) ...@@ -304,8 +303,7 @@ static int dw_suspend_late(struct device *dev)
static int dw_resume_early(struct device *dev) static int dw_resume_early(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct dw_dma_chip *chip = dev_get_drvdata(dev);
struct dw_dma_chip *chip = platform_get_drvdata(pdev);
int ret; int ret;
ret = clk_prepare_enable(chip->clk); ret = clk_prepare_enable(chip->clk);
......
...@@ -1328,8 +1328,7 @@ static int fsldma_of_remove(struct platform_device *op) ...@@ -1328,8 +1328,7 @@ static int fsldma_of_remove(struct platform_device *op)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int fsldma_suspend_late(struct device *dev) static int fsldma_suspend_late(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct fsldma_device *fdev = dev_get_drvdata(dev);
struct fsldma_device *fdev = platform_get_drvdata(pdev);
struct fsldma_chan *chan; struct fsldma_chan *chan;
int i; int i;
...@@ -1360,8 +1359,7 @@ static int fsldma_suspend_late(struct device *dev) ...@@ -1360,8 +1359,7 @@ static int fsldma_suspend_late(struct device *dev)
static int fsldma_resume_early(struct device *dev) static int fsldma_resume_early(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct fsldma_device *fdev = dev_get_drvdata(dev);
struct fsldma_device *fdev = platform_get_drvdata(pdev);
struct fsldma_chan *chan; struct fsldma_chan *chan;
u32 mode; u32 mode;
int i; int i;
......
...@@ -670,8 +670,7 @@ static int idma64_platform_remove(struct platform_device *pdev) ...@@ -670,8 +670,7 @@ static int idma64_platform_remove(struct platform_device *pdev)
static int idma64_pm_suspend(struct device *dev) static int idma64_pm_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct idma64_chip *chip = dev_get_drvdata(dev);
struct idma64_chip *chip = platform_get_drvdata(pdev);
idma64_off(chip->idma64); idma64_off(chip->idma64);
return 0; return 0;
...@@ -679,8 +678,7 @@ static int idma64_pm_suspend(struct device *dev) ...@@ -679,8 +678,7 @@ static int idma64_pm_suspend(struct device *dev)
static int idma64_pm_resume(struct device *dev) static int idma64_pm_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct idma64_chip *chip = dev_get_drvdata(dev);
struct idma64_chip *chip = platform_get_drvdata(pdev);
idma64_on(chip->idma64); idma64_on(chip->idma64);
return 0; return 0;
......
/* // SPDX-License-Identifier: GPL-2.0+
* drivers/dma/imx-dma.c //
* // drivers/dma/imx-dma.c
* This file contains a driver for the Freescale i.MX DMA engine //
* found on i.MX1/21/27 // This file contains a driver for the Freescale i.MX DMA engine
* // found on i.MX1/21/27
* Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> //
* Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com> // Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* // Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
* 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
*/
#include <linux/err.h> #include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
......
/* // SPDX-License-Identifier: GPL-2.0+
* drivers/dma/imx-sdma.c //
* // drivers/dma/imx-sdma.c
* This file contains a driver for the Freescale Smart DMA engine //
* // This file contains a driver for the Freescale Smart DMA engine
* Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> //
* // Copyright 2010 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
* Based on code from Freescale: //
* // Based on code from Freescale:
* Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. //
* // 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
*/
#include <linux/init.h> #include <linux/init.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
......
/* // SPDX-License-Identifier: GPL-2.0
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved. //
* // Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
* Refer to drivers/dma/imx-sdma.c //
* // 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.
*/
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/of_dma.h> #include <linux/of_dma.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/bug.h>
#include "dmaengine.h" #include "dmaengine.h"
#define PL330_MAX_CHAN 8 #define PL330_MAX_CHAN 8
...@@ -1094,51 +1095,96 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[], ...@@ -1094,51 +1095,96 @@ static inline int _ldst_memtomem(unsigned dry_run, u8 buf[],
return off; return off;
} }
static inline int _ldst_devtomem(struct pl330_dmac *pl330, unsigned dry_run, static u32 _emit_load(unsigned int dry_run, u8 buf[],
u8 buf[], const struct _xfer_spec *pxs, enum pl330_cond cond, enum dma_transfer_direction direction,
int cyc) u8 peri)
{ {
int off = 0; int off = 0;
enum pl330_cond cond;
if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) switch (direction) {
cond = BURST; case DMA_MEM_TO_MEM:
else /* fall through */
cond = SINGLE; case DMA_MEM_TO_DEV:
off += _emit_LD(dry_run, &buf[off], cond);
break;
while (cyc--) { case DMA_DEV_TO_MEM:
off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri); if (cond == ALWAYS) {
off += _emit_LDP(dry_run, &buf[off], cond, pxs->desc->peri); off += _emit_LDP(dry_run, &buf[off], SINGLE,
off += _emit_ST(dry_run, &buf[off], ALWAYS); 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)) default:
off += _emit_FLUSHP(dry_run, &buf[off], /* this code should be unreachable */
pxs->desc->peri); WARN_ON(1);
break;
} }
return off; return off;
} }
static inline int _ldst_memtodev(struct pl330_dmac *pl330, 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[], unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs, int cyc) const struct _xfer_spec *pxs, int cyc,
enum pl330_cond cond)
{ {
int off = 0; int off = 0;
enum pl330_cond cond;
if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP) if (pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)
cond = BURST; 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--) { while (cyc--) {
off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri); off += _emit_WFP(dry_run, &buf[off], cond, pxs->desc->peri);
off += _emit_LD(dry_run, &buf[off], ALWAYS); off += _emit_load(dry_run, &buf[off], cond, pxs->desc->rqtype,
off += _emit_STP(dry_run, &buf[off], cond, pxs->desc->peri); pxs->desc->peri);
off += _emit_store(dry_run, &buf[off], cond, pxs->desc->rqtype,
if (!(pl330->quirks & PL330_QUIRK_BROKEN_NO_FLUSHP)) pxs->desc->peri);
off += _emit_FLUSHP(dry_run, &buf[off],
pxs->desc->peri);
} }
return off; return off;
...@@ -1148,19 +1194,65 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[], ...@@ -1148,19 +1194,65 @@ static int _bursts(struct pl330_dmac *pl330, unsigned dry_run, u8 buf[],
const struct _xfer_spec *pxs, int cyc) const struct _xfer_spec *pxs, int cyc)
{ {
int off = 0; int off = 0;
enum pl330_cond cond = BRST_LEN(pxs->ccr) > 1 ? BURST : SINGLE;
switch (pxs->desc->rqtype) { switch (pxs->desc->rqtype) {
case DMA_MEM_TO_DEV: case DMA_MEM_TO_DEV:
off += _ldst_memtodev(pl330, dry_run, &buf[off], pxs, cyc); /* fall through */
break;
case DMA_DEV_TO_MEM: 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; break;
case DMA_MEM_TO_MEM: case DMA_MEM_TO_MEM:
off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc); off += _ldst_memtomem(dry_run, &buf[off], pxs, cyc);
break; break;
default:
/* 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: default:
off += 0x40000000; /* Scare off the Client */ /* this code should be unreachable */
WARN_ON(1);
break; break;
} }
...@@ -1256,6 +1348,8 @@ static inline int _setup_loops(struct pl330_dmac *pl330, ...@@ -1256,6 +1348,8 @@ static inline int _setup_loops(struct pl330_dmac *pl330,
struct pl330_xfer *x = &pxs->desc->px; struct pl330_xfer *x = &pxs->desc->px;
u32 ccr = pxs->ccr; u32 ccr = pxs->ccr;
unsigned long c, bursts = BYTE_TO_BURST(x->bytes, 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; int off = 0;
while (bursts) { while (bursts) {
...@@ -1263,6 +1357,7 @@ static inline int _setup_loops(struct pl330_dmac *pl330, ...@@ -1263,6 +1357,7 @@ static inline int _setup_loops(struct pl330_dmac *pl330,
off += _loop(pl330, dry_run, &buf[off], &c, pxs); off += _loop(pl330, dry_run, &buf[off], &c, pxs);
bursts -= c; bursts -= c;
} }
off += _dregs(pl330, dry_run, &buf[off], pxs, num_dregs);
return off; return off;
} }
...@@ -1294,7 +1389,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run, ...@@ -1294,7 +1389,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run,
struct _xfer_spec *pxs) struct _xfer_spec *pxs)
{ {
struct _pl330_req *req = &thrd->req[index]; struct _pl330_req *req = &thrd->req[index];
struct pl330_xfer *x;
u8 *buf = req->mc_cpu; u8 *buf = req->mc_cpu;
int off = 0; int off = 0;
...@@ -1303,11 +1397,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run, ...@@ -1303,11 +1397,6 @@ static int _setup_req(struct pl330_dmac *pl330, unsigned dry_run,
/* DMAMOV CCR, ccr */ /* DMAMOV CCR, ccr */
off += _emit_MOV(dry_run, &buf[off], CCR, pxs->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); off += _setup_xfer(pl330, dry_run, &buf[off], pxs);
/* DMASEV peripheral/event */ /* DMASEV peripheral/event */
...@@ -1365,6 +1454,20 @@ static int pl330_submit_req(struct pl330_thread *thrd, ...@@ -1365,6 +1454,20 @@ static int pl330_submit_req(struct pl330_thread *thrd,
u32 ccr; u32 ccr;
int ret = 0; 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 if (pl330->state == DYING
|| pl330->dmac_tbd.reset_chan & (1 << thrd->id)) { || pl330->dmac_tbd.reset_chan & (1 << thrd->id)) {
dev_info(thrd->dmac->ddma.dev, "%s:%d\n", dev_info(thrd->dmac->ddma.dev, "%s:%d\n",
...@@ -2106,6 +2209,18 @@ static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch, ...@@ -2106,6 +2209,18 @@ static bool pl330_prep_slave_fifo(struct dma_pl330_chan *pch,
return true; 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, static int pl330_config(struct dma_chan *chan,
struct dma_slave_config *slave_config) struct dma_slave_config *slave_config)
{ {
...@@ -2117,15 +2232,15 @@ static int pl330_config(struct dma_chan *chan, ...@@ -2117,15 +2232,15 @@ static int pl330_config(struct dma_chan *chan,
pch->fifo_addr = slave_config->dst_addr; pch->fifo_addr = slave_config->dst_addr;
if (slave_config->dst_addr_width) if (slave_config->dst_addr_width)
pch->burst_sz = __ffs(slave_config->dst_addr_width); pch->burst_sz = __ffs(slave_config->dst_addr_width);
if (slave_config->dst_maxburst) pch->burst_len = fixup_burst_len(slave_config->dst_maxburst,
pch->burst_len = slave_config->dst_maxburst; pch->dmac->quirks);
} else if (slave_config->direction == DMA_DEV_TO_MEM) { } else if (slave_config->direction == DMA_DEV_TO_MEM) {
if (slave_config->src_addr) if (slave_config->src_addr)
pch->fifo_addr = slave_config->src_addr; pch->fifo_addr = slave_config->src_addr;
if (slave_config->src_addr_width) if (slave_config->src_addr_width)
pch->burst_sz = __ffs(slave_config->src_addr_width); pch->burst_sz = __ffs(slave_config->src_addr_width);
if (slave_config->src_maxburst) pch->burst_len = fixup_burst_len(slave_config->src_maxburst,
pch->burst_len = slave_config->src_maxburst; pch->dmac->quirks);
} }
return 0; return 0;
...@@ -2519,14 +2634,8 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) ...@@ -2519,14 +2634,8 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
burst_len >>= desc->rqcfg.brst_size; burst_len >>= desc->rqcfg.brst_size;
/* src/dst_burst_len can't be more than 16 */ /* src/dst_burst_len can't be more than 16 */
if (burst_len > 16) if (burst_len > PL330_MAX_BURST)
burst_len = 16; burst_len = PL330_MAX_BURST;
while (burst_len > 1) {
if (!(len % (burst_len << desc->rqcfg.brst_size)))
break;
burst_len--;
}
return burst_len; return burst_len;
} }
...@@ -2598,7 +2707,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic( ...@@ -2598,7 +2707,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
desc->rqtype = direction; desc->rqtype = direction;
desc->rqcfg.brst_size = pch->burst_sz; desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1; desc->rqcfg.brst_len = pch->burst_len;
desc->bytes_requested = period_len; desc->bytes_requested = period_len;
fill_px(&desc->px, dst, src, 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, ...@@ -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_size = pch->burst_sz;
desc->rqcfg.brst_len = 1; desc->rqcfg.brst_len = pch->burst_len;
desc->rqtype = direction; desc->rqtype = direction;
desc->bytes_requested = sg_dma_len(sg); desc->bytes_requested = sg_dma_len(sg);
} }
......
...@@ -451,6 +451,7 @@ static void bam_reset_channel(struct bam_chan *bchan) ...@@ -451,6 +451,7 @@ static void bam_reset_channel(struct bam_chan *bchan)
/** /**
* bam_chan_init_hw - Initialize channel hardware * bam_chan_init_hw - Initialize channel hardware
* @bchan: bam channel * @bchan: bam channel
* @dir: DMA transfer direction
* *
* This function resets and initializes the BAM channel * This function resets and initializes the BAM channel
*/ */
...@@ -673,7 +674,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, ...@@ -673,7 +674,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
remainder = 0; remainder = 0;
} }
async_desc->length += desc->size; async_desc->length += le16_to_cpu(desc->size);
desc++; desc++;
} while (remainder > 0); } while (remainder > 0);
} }
...@@ -687,7 +688,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan, ...@@ -687,7 +688,7 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
/** /**
* bam_dma_terminate_all - terminate all transactions on a channel * bam_dma_terminate_all - terminate all transactions on a channel
* @bchan: bam dma channel * @chan: bam dma channel
* *
* Dequeues and frees all transactions * Dequeues and frees all transactions
* No callbacks are done * No callbacks are done
...@@ -918,7 +919,8 @@ static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie, ...@@ -918,7 +919,8 @@ static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
continue; continue;
for (i = 0; i < async_desc->num_desc; i++) 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);
} }
} }
...@@ -958,7 +960,7 @@ static void bam_apply_new_config(struct bam_chan *bchan, ...@@ -958,7 +960,7 @@ static void bam_apply_new_config(struct bam_chan *bchan,
/** /**
* bam_start_dma - start next transaction * bam_start_dma - start next transaction
* @bchan - bam dma channel * @bchan: bam dma channel
*/ */
static void bam_start_dma(struct bam_chan *bchan) static void bam_start_dma(struct bam_chan *bchan)
{ {
......
...@@ -616,8 +616,7 @@ static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg) ...@@ -616,8 +616,7 @@ static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg)
static ssize_t hidma_show_values(struct device *dev, static ssize_t hidma_show_values(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hidma_dev *mdev = dev_get_drvdata(dev);
struct hidma_dev *mdev = platform_get_drvdata(pdev);
buf[0] = 0; buf[0] = 0;
......
...@@ -107,8 +107,7 @@ static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = { ...@@ -107,8 +107,7 @@ static struct hidma_mgmt_fileinfo hidma_mgmt_files[] = {
static ssize_t show_values(struct device *dev, struct device_attribute *attr, static ssize_t show_values(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev);
unsigned int i; unsigned int i;
buf[0] = 0; buf[0] = 0;
...@@ -125,8 +124,7 @@ static ssize_t show_values(struct device *dev, struct device_attribute *attr, ...@@ -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, static ssize_t set_values(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hidma_mgmt_dev *mdev = dev_get_drvdata(dev);
struct hidma_mgmt_dev *mdev = platform_get_drvdata(pdev);
unsigned long tmp; unsigned long tmp;
unsigned int i; unsigned int i;
int rc; int rc;
......
...@@ -443,7 +443,6 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev) ...@@ -443,7 +443,6 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
return ret; return ret;
} }
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
static irqreturn_t sh_dmae_err(int irq, void *data) static irqreturn_t sh_dmae_err(int irq, void *data)
{ {
struct sh_dmae_device *shdev = data; struct sh_dmae_device *shdev = data;
...@@ -454,7 +453,6 @@ static irqreturn_t sh_dmae_err(int irq, void *data) ...@@ -454,7 +453,6 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
sh_dmae_reset(shdev); sh_dmae_reset(shdev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#endif
static bool sh_dmae_desc_completed(struct shdma_chan *schan, static bool sh_dmae_desc_completed(struct shdma_chan *schan,
struct shdma_desc *sdesc) struct shdma_desc *sdesc)
...@@ -686,11 +684,8 @@ static int sh_dmae_probe(struct platform_device *pdev) ...@@ -686,11 +684,8 @@ static int sh_dmae_probe(struct platform_device *pdev)
const struct sh_dmae_pdata *pdata; const struct sh_dmae_pdata *pdata;
unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {}; unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {};
int chan_irq[SH_DMAE_MAX_CHANNELS]; int chan_irq[SH_DMAE_MAX_CHANNELS];
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
unsigned long irqflags = 0; unsigned long irqflags = 0;
int errirq; int err, errirq, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
#endif
int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
struct sh_dmae_device *shdev; struct sh_dmae_device *shdev;
struct dma_device *dma_dev; struct dma_device *dma_dev;
struct resource *chan, *dmars, *errirq_res, *chanirq_res; struct resource *chan, *dmars, *errirq_res, *chanirq_res;
...@@ -792,33 +787,32 @@ static int sh_dmae_probe(struct platform_device *pdev) ...@@ -792,33 +787,32 @@ static int sh_dmae_probe(struct platform_device *pdev)
if (err) if (err)
goto rst_err; goto rst_err;
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) if (IS_ENABLED(CONFIG_CPU_SH4) || IS_ENABLED(CONFIG_ARCH_RENESAS)) {
chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!chanirq_res) if (!chanirq_res)
chanirq_res = errirq_res; chanirq_res = errirq_res;
else else
irqres++; irqres++;
if (chanirq_res == errirq_res || if (chanirq_res == errirq_res ||
(errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE) (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE)
irqflags = IRQF_SHARED; irqflags = IRQF_SHARED;
errirq = errirq_res->start; errirq = errirq_res->start;
err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags, err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err,
"DMAC Address Error", shdev); irqflags, "DMAC Address Error", shdev);
if (err) { if (err) {
dev_err(&pdev->dev, dev_err(&pdev->dev,
"DMA failed requesting irq #%d, error %d\n", "DMA failed requesting irq #%d, error %d\n",
errirq, err); errirq, err);
goto eirq_err; goto eirq_err;
}
} else {
chanirq_res = errirq_res;
} }
#else
chanirq_res = errirq_res;
#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */
if (chanirq_res->start == chanirq_res->end && if (chanirq_res->start == chanirq_res->end &&
!platform_get_resource(pdev, IORESOURCE_IRQ, 1)) { !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
/* Special case - all multiplexed */ /* Special case - all multiplexed */
...@@ -884,9 +878,7 @@ static int sh_dmae_probe(struct platform_device *pdev) ...@@ -884,9 +878,7 @@ static int sh_dmae_probe(struct platform_device *pdev)
chan_probe_err: chan_probe_err:
sh_dmae_chan_remove(shdev); sh_dmae_chan_remove(shdev);
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
eirq_err: eirq_err:
#endif
rst_err: rst_err:
spin_lock_irq(&sh_dmae_lock); spin_lock_irq(&sh_dmae_lock);
list_del_rcu(&shdev->node); list_del_rcu(&shdev->node);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dma/sprd-dma.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
...@@ -116,57 +117,21 @@ ...@@ -116,57 +117,21 @@
#define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0 #define SPRD_DMA_SRC_TRSF_STEP_OFFSET 0
#define SPRD_DMA_TRSF_STEP_MASK GENMASK(15, 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 #define SPRD_DMA_SOFTWARE_UID 0
/* /* dma data width values */
* enum sprd_dma_req_mode: define the DMA request mode enum sprd_dma_datawidth {
* @SPRD_DMA_FRAG_REQ: fragment request mode SPRD_DMA_DATAWIDTH_1_BYTE,
* @SPRD_DMA_BLK_REQ: block request mode SPRD_DMA_DATAWIDTH_2_BYTES,
* @SPRD_DMA_TRANS_REQ: transaction request mode SPRD_DMA_DATAWIDTH_4_BYTES,
* @SPRD_DMA_LIST_REQ: link-list request mode SPRD_DMA_DATAWIDTH_8_BYTES,
*
* 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 channel hardware configuration */ /* dma channel hardware configuration */
...@@ -199,6 +164,7 @@ struct sprd_dma_desc { ...@@ -199,6 +164,7 @@ struct sprd_dma_desc {
struct sprd_dma_chn { struct sprd_dma_chn {
struct virt_dma_chan vc; struct virt_dma_chan vc;
void __iomem *chn_base; void __iomem *chn_base;
struct dma_slave_config slave_cfg;
u32 chn_num; u32 chn_num;
u32 dev_id; u32 dev_id;
struct sprd_dma_desc *cur_desc; struct sprd_dma_desc *cur_desc;
...@@ -587,52 +553,97 @@ static void sprd_dma_issue_pending(struct dma_chan *chan) ...@@ -587,52 +553,97 @@ static void sprd_dma_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&schan->vc.lock, flags); spin_unlock_irqrestore(&schan->vc.lock, flags);
} }
static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, static int sprd_dma_get_datawidth(enum dma_slave_buswidth buswidth)
dma_addr_t dest, dma_addr_t src, size_t len) {
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_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; struct sprd_dma_chn_hw *hw = &sdesc->chn_hw;
u32 datawidth, src_step, des_step, fragment_len; u32 req_mode = (flags >> SPRD_DMA_REQ_SHIFT) & SPRD_DMA_REQ_MODE_MASK;
u32 block_len, req_mode, irq_mode, transcation_len; u32 int_mode = flags & SPRD_DMA_INT_MASK;
u32 fix_mode = 0, fix_en = 0; int src_datawidth, dst_datawidth, src_step, dst_step;
u32 temp, fix_mode = 0, fix_en = 0;
if (IS_ALIGNED(len, 4)) {
datawidth = 2; if (dir == DMA_MEM_TO_DEV) {
src_step = 4; src_step = sprd_dma_get_step(slave_cfg->src_addr_width);
des_step = 4; if (src_step < 0) {
} else if (IS_ALIGNED(len, 2)) { dev_err(sdev->dma_dev.dev, "invalid source step\n");
datawidth = 1; return src_step;
src_step = 2; }
des_step = 2; dst_step = SPRD_DMA_NONE_STEP;
} else { } else {
datawidth = 0; dst_step = sprd_dma_get_step(slave_cfg->dst_addr_width);
src_step = 1; if (dst_step < 0) {
des_step = 1; dev_err(sdev->dma_dev.dev, "invalid destination step\n");
return dst_step;
}
src_step = SPRD_DMA_NONE_STEP;
} }
fragment_len = SPRD_DMA_MEMCPY_MIN_SIZE; src_datawidth = sprd_dma_get_datawidth(slave_cfg->src_addr_width);
if (len <= SPRD_DMA_BLK_LEN_MASK) { if (src_datawidth < 0) {
block_len = len; dev_err(sdev->dma_dev.dev, "invalid source datawidth\n");
transcation_len = 0; return src_datawidth;
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;
} }
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; 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); * 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 ((src_step != 0 && des_step != 0) || (src_step | des_step) == 0) { /*
* 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; fix_en = 0;
} else { } else {
fix_en = 1; fix_en = 1;
...@@ -642,87 +653,119 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc, ...@@ -642,87 +653,119 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc,
fix_mode = 0; fix_mode = 0;
} }
hw->frg_len = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET | hw->intc = int_mode | SPRD_DMA_CFG_ERR_INT_EN;
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: temp = src_datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET;
hw->intc |= SPRD_DMA_BLK_INT_EN; temp |= dst_datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET;
break; 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;
case SPRD_DMA_BLK_FRAG_INT: hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK;
hw->intc |= SPRD_DMA_BLK_INT_EN | SPRD_DMA_FRAG_INT_EN; hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK;
break;
case SPRD_DMA_TRANS_INT: temp = (dst_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET;
hw->intc |= SPRD_DMA_TRANS_INT_EN; temp |= (src_step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
break; hw->trsf_step = temp;
case SPRD_DMA_TRANS_FRAG_INT: hw->frg_step = 0;
hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_FRAG_INT_EN; hw->src_blk_step = 0;
break; hw->des_blk_step = 0;
return 0;
}
case SPRD_DMA_TRANS_BLK_INT: static struct dma_async_tx_descriptor *
hw->intc |= SPRD_DMA_TRANS_INT_EN | SPRD_DMA_BLK_INT_EN; sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
break; size_t len, unsigned long flags)
{
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
struct sprd_dma_desc *sdesc;
struct sprd_dma_chn_hw *hw;
enum sprd_dma_datawidth datawidth;
u32 step, temp;
case SPRD_DMA_LIST_INT: sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
hw->intc |= SPRD_DMA_LIST_INT_EN; if (!sdesc)
break; return NULL;
case SPRD_DMA_CFGERR_INT: hw = &sdesc->chn_hw;
hw->intc |= SPRD_DMA_CFG_ERR_INT_EN;
break;
default: hw->cfg = SPRD_DMA_DONOT_WAIT_BDONE << SPRD_DMA_WAIT_BDONE_OFFSET;
dev_err(sdev->dma_dev.dev, "invalid irq mode\n"); hw->intc = SPRD_DMA_TRANS_INT | SPRD_DMA_CFG_ERR_INT_EN;
return -EINVAL; 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;
} }
if (transcation_len == 0) temp = datawidth << SPRD_DMA_SRC_DATAWIDTH_OFFSET;
hw->trsc_len = block_len & SPRD_DMA_TRSC_LEN_MASK; temp |= datawidth << SPRD_DMA_DES_DATAWIDTH_OFFSET;
else temp |= SPRD_DMA_TRANS_REQ << SPRD_DMA_REQ_MODE_OFFSET;
hw->trsc_len = transcation_len & SPRD_DMA_TRSC_LEN_MASK; temp |= len & SPRD_DMA_FRG_LEN_MASK;
hw->frg_len = temp;
hw->trsf_step = (des_step & SPRD_DMA_TRSF_STEP_MASK) << hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK;
SPRD_DMA_DEST_TRSF_STEP_OFFSET | hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK;
(src_step & SPRD_DMA_TRSF_STEP_MASK) <<
SPRD_DMA_SRC_TRSF_STEP_OFFSET;
hw->frg_step = 0; temp = (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_DEST_TRSF_STEP_OFFSET;
hw->src_blk_step = 0; temp |= (step & SPRD_DMA_TRSF_STEP_MASK) << SPRD_DMA_SRC_TRSF_STEP_OFFSET;
hw->des_blk_step = 0; hw->trsf_step = temp;
hw->src_blk_step = 0;
return 0; return vchan_tx_prep(&schan->vc, &sdesc->vd, flags);
} }
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, sprd_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
size_t len, unsigned long flags) unsigned int sglen, enum dma_transfer_direction dir,
unsigned long flags, void *context)
{ {
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); 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 sprd_dma_desc *sdesc;
int ret; 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); sdesc = kzalloc(sizeof(*sdesc), GFP_NOWAIT);
if (!sdesc) if (!sdesc)
return NULL; return NULL;
ret = sprd_dma_config(chan, sdesc, dest, src, len); 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) { if (ret) {
kfree(sdesc); kfree(sdesc);
return NULL; return NULL;
...@@ -731,6 +774,19 @@ sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, ...@@ -731,6 +774,19 @@ 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); 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) static int sprd_dma_pause(struct dma_chan *chan)
{ {
struct sprd_dma_chn *schan = to_sprd_dma_chan(chan); struct sprd_dma_chn *schan = to_sprd_dma_chan(chan);
...@@ -842,10 +898,9 @@ static int sprd_dma_probe(struct platform_device *pdev) ...@@ -842,10 +898,9 @@ static int sprd_dma_probe(struct platform_device *pdev)
} }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
sdev->glb_base = devm_ioremap_nocache(&pdev->dev, res->start, sdev->glb_base = devm_ioremap_resource(&pdev->dev, res);
resource_size(res)); if (IS_ERR(sdev->glb_base))
if (!sdev->glb_base) return PTR_ERR(sdev->glb_base);
return -ENOMEM;
dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask); dma_cap_set(DMA_MEMCPY, sdev->dma_dev.cap_mask);
sdev->total_chns = chn_count; sdev->total_chns = chn_count;
...@@ -858,6 +913,8 @@ static int sprd_dma_probe(struct platform_device *pdev) ...@@ -858,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_tx_status = sprd_dma_tx_status;
sdev->dma_dev.device_issue_pending = sprd_dma_issue_pending; 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_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_pause = sprd_dma_pause;
sdev->dma_dev.device_resume = sprd_dma_resume; sdev->dma_dev.device_resume = sprd_dma_resume;
sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all; sdev->dma_dev.device_terminate_all = sprd_dma_terminate_all;
......
...@@ -2889,8 +2889,7 @@ static int __init d40_dmaengine_init(struct d40_base *base, ...@@ -2889,8 +2889,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int dma40_suspend(struct device *dev) static int dma40_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = dev_get_drvdata(dev);
struct d40_base *base = platform_get_drvdata(pdev);
int ret; int ret;
ret = pm_runtime_force_suspend(dev); ret = pm_runtime_force_suspend(dev);
...@@ -2904,8 +2903,7 @@ static int dma40_suspend(struct device *dev) ...@@ -2904,8 +2903,7 @@ static int dma40_suspend(struct device *dev)
static int dma40_resume(struct device *dev) static int dma40_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = dev_get_drvdata(dev);
struct d40_base *base = platform_get_drvdata(pdev);
int ret = 0; int ret = 0;
if (base->lcpa_regulator) { if (base->lcpa_regulator) {
...@@ -2970,8 +2968,7 @@ static void d40_save_restore_registers(struct d40_base *base, bool save) ...@@ -2970,8 +2968,7 @@ static void d40_save_restore_registers(struct d40_base *base, bool save)
static int dma40_runtime_suspend(struct device *dev) static int dma40_runtime_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = dev_get_drvdata(dev);
struct d40_base *base = platform_get_drvdata(pdev);
d40_save_restore_registers(base, true); d40_save_restore_registers(base, true);
...@@ -2985,8 +2982,7 @@ static int dma40_runtime_suspend(struct device *dev) ...@@ -2985,8 +2982,7 @@ static int dma40_runtime_suspend(struct device *dev)
static int dma40_runtime_resume(struct device *dev) static int dma40_runtime_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct d40_base *base = dev_get_drvdata(dev);
struct d40_base *base = platform_get_drvdata(pdev);
d40_save_restore_registers(base, false); d40_save_restore_registers(base, false);
......
...@@ -252,13 +252,17 @@ struct stm32_mdma_hwdesc { ...@@ -252,13 +252,17 @@ struct stm32_mdma_hwdesc {
u32 cmdr; u32 cmdr;
} __aligned(64); } __aligned(64);
struct stm32_mdma_desc_node {
struct stm32_mdma_hwdesc *hwdesc;
dma_addr_t hwdesc_phys;
};
struct stm32_mdma_desc { struct stm32_mdma_desc {
struct virt_dma_desc vdesc; struct virt_dma_desc vdesc;
u32 ccr; u32 ccr;
struct stm32_mdma_hwdesc *hwdesc;
dma_addr_t hwdesc_phys;
bool cyclic; bool cyclic;
u32 count; u32 count;
struct stm32_mdma_desc_node node[];
}; };
struct stm32_mdma_chan { struct stm32_mdma_chan {
...@@ -344,30 +348,42 @@ static struct stm32_mdma_desc *stm32_mdma_alloc_desc( ...@@ -344,30 +348,42 @@ static struct stm32_mdma_desc *stm32_mdma_alloc_desc(
struct stm32_mdma_chan *chan, u32 count) struct stm32_mdma_chan *chan, u32 count)
{ {
struct stm32_mdma_desc *desc; struct stm32_mdma_desc *desc;
int i;
desc = kzalloc(sizeof(*desc), GFP_NOWAIT); desc = kzalloc(offsetof(typeof(*desc), node[count]), GFP_NOWAIT);
if (!desc) if (!desc)
return NULL; return NULL;
desc->hwdesc = dma_pool_alloc(chan->desc_pool, GFP_NOWAIT, for (i = 0; i < count; i++) {
&desc->hwdesc_phys); desc->node[i].hwdesc =
if (!desc->hwdesc) { dma_pool_alloc(chan->desc_pool, GFP_NOWAIT,
dev_err(chan2dev(chan), "Failed to allocate descriptor\n"); &desc->node[i].hwdesc_phys);
kfree(desc); if (!desc->node[i].hwdesc)
return NULL; goto err;
} }
desc->count = count; desc->count = count;
return desc; 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) static void stm32_mdma_desc_free(struct virt_dma_desc *vdesc)
{ {
struct stm32_mdma_desc *desc = to_stm32_mdma_desc(vdesc); struct stm32_mdma_desc *desc = to_stm32_mdma_desc(vdesc);
struct stm32_mdma_chan *chan = to_stm32_mdma_chan(vdesc->tx.chan); 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); kfree(desc);
} }
...@@ -410,13 +426,10 @@ static enum dma_slave_buswidth stm32_mdma_get_max_width(dma_addr_t addr, ...@@ -410,13 +426,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, static u32 stm32_mdma_get_best_burst(u32 buf_len, u32 tlen, u32 max_burst,
enum dma_slave_buswidth width) enum dma_slave_buswidth width)
{ {
u32 best_burst = max_burst; u32 best_burst;
u32 burst_len = best_burst * width;
while ((burst_len > 0) && (tlen % burst_len)) { best_burst = min((u32)1 << __ffs(tlen | buf_len),
best_burst = best_burst >> 1; max_burst * width) / width;
burst_len = best_burst * width;
}
return (best_burst > 0) ? best_burst : 1; return (best_burst > 0) ? best_burst : 1;
} }
...@@ -669,18 +682,18 @@ static int stm32_mdma_set_xfer_param(struct stm32_mdma_chan *chan, ...@@ -669,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, 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), "hwdesc: %pad\n", &node->hwdesc_phys);
dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n", hwdesc->ctcr); dev_dbg(chan2dev(chan), "CTCR: 0x%08x\n", node->hwdesc->ctcr);
dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n", hwdesc->cbndtr); dev_dbg(chan2dev(chan), "CBNDTR: 0x%08x\n", node->hwdesc->cbndtr);
dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n", hwdesc->csar); dev_dbg(chan2dev(chan), "CSAR: 0x%08x\n", node->hwdesc->csar);
dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n", hwdesc->cdar); dev_dbg(chan2dev(chan), "CDAR: 0x%08x\n", node->hwdesc->cdar);
dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n", hwdesc->cbrur); dev_dbg(chan2dev(chan), "CBRUR: 0x%08x\n", node->hwdesc->cbrur);
dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n", hwdesc->clar); dev_dbg(chan2dev(chan), "CLAR: 0x%08x\n", node->hwdesc->clar);
dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n", hwdesc->ctbr); dev_dbg(chan2dev(chan), "CTBR: 0x%08x\n", node->hwdesc->ctbr);
dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n", hwdesc->cmar); dev_dbg(chan2dev(chan), "CMAR: 0x%08x\n", node->hwdesc->cmar);
dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n\n", hwdesc->cmdr); dev_dbg(chan2dev(chan), "CMDR: 0x%08x\n\n", node->hwdesc->cmdr);
} }
static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan,
...@@ -694,7 +707,7 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, ...@@ -694,7 +707,7 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan,
struct stm32_mdma_hwdesc *hwdesc; struct stm32_mdma_hwdesc *hwdesc;
u32 next = count + 1; u32 next = count + 1;
hwdesc = &desc->hwdesc[count]; hwdesc = desc->node[count].hwdesc;
hwdesc->ctcr = ctcr; hwdesc->ctcr = ctcr;
hwdesc->cbndtr &= ~(STM32_MDMA_CBNDTR_BRC_MK | hwdesc->cbndtr &= ~(STM32_MDMA_CBNDTR_BRC_MK |
STM32_MDMA_CBNDTR_BRDUM | STM32_MDMA_CBNDTR_BRDUM |
...@@ -704,19 +717,20 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan, ...@@ -704,19 +717,20 @@ static void stm32_mdma_setup_hwdesc(struct stm32_mdma_chan *chan,
hwdesc->csar = src_addr; hwdesc->csar = src_addr;
hwdesc->cdar = dst_addr; hwdesc->cdar = dst_addr;
hwdesc->cbrur = 0; hwdesc->cbrur = 0;
hwdesc->clar = desc->hwdesc_phys + next * sizeof(*hwdesc);
hwdesc->ctbr = ctbr; hwdesc->ctbr = ctbr;
hwdesc->cmar = config->mask_addr; hwdesc->cmar = config->mask_addr;
hwdesc->cmdr = config->mask_data; hwdesc->cmdr = config->mask_data;
if (is_last) { if (is_last) {
if (is_cyclic) if (is_cyclic)
hwdesc->clar = desc->hwdesc_phys; hwdesc->clar = desc->node[0].hwdesc_phys;
else else
hwdesc->clar = 0; 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, static int stm32_mdma_setup_xfer(struct stm32_mdma_chan *chan,
...@@ -780,7 +794,7 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, ...@@ -780,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_chan *chan = to_stm32_mdma_chan(c);
struct stm32_mdma_desc *desc; struct stm32_mdma_desc *desc;
int ret; int i, ret;
/* /*
* Once DMA is in setup cyclic mode the channel we cannot assign this * Once DMA is in setup cyclic mode the channel we cannot assign this
...@@ -806,7 +820,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl, ...@@ -806,7 +820,9 @@ stm32_mdma_prep_slave_sg(struct dma_chan *c, struct scatterlist *sgl,
return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
xfer_setup_err: 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); kfree(desc);
return NULL; return NULL;
} }
...@@ -895,7 +911,9 @@ stm32_mdma_prep_dma_cyclic(struct dma_chan *c, dma_addr_t buf_addr, ...@@ -895,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); return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
xfer_setup_err: 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); kfree(desc);
return NULL; return NULL;
} }
...@@ -1009,7 +1027,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src, ...@@ -1009,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; ctcr |= STM32_MDMA_CTCR_PKE;
/* Prepare hardware descriptor */ /* Prepare hardware descriptor */
hwdesc = desc->hwdesc; hwdesc = desc->node[0].hwdesc;
hwdesc->ctcr = ctcr; hwdesc->ctcr = ctcr;
hwdesc->cbndtr = cbndtr; hwdesc->cbndtr = cbndtr;
hwdesc->csar = src; hwdesc->csar = src;
...@@ -1020,7 +1038,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src, ...@@ -1020,7 +1038,7 @@ stm32_mdma_prep_dma_memcpy(struct dma_chan *c, dma_addr_t dest, dma_addr_t src,
hwdesc->cmar = 0; hwdesc->cmar = 0;
hwdesc->cmdr = 0; hwdesc->cmdr = 0;
stm32_mdma_dump_hwdesc(chan, hwdesc); stm32_mdma_dump_hwdesc(chan, &desc->node[0]);
} else { } else {
/* Setup a LLI transfer */ /* Setup a LLI transfer */
ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_LINKED_LIST) | ctcr |= STM32_MDMA_CTCR_TRGM(STM32_MDMA_LINKED_LIST) |
...@@ -1120,7 +1138,7 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan) ...@@ -1120,7 +1138,7 @@ static void stm32_mdma_start_transfer(struct stm32_mdma_chan *chan)
} }
chan->desc = to_stm32_mdma_desc(vdesc); chan->desc = to_stm32_mdma_desc(vdesc);
hwdesc = chan->desc->hwdesc; hwdesc = chan->desc->node[0].hwdesc;
chan->curr_hwdesc = 0; chan->curr_hwdesc = 0;
stm32_mdma_write(dmadev, STM32_MDMA_CCR(id), chan->desc->ccr); stm32_mdma_write(dmadev, STM32_MDMA_CCR(id), chan->desc->ccr);
...@@ -1198,7 +1216,7 @@ static int stm32_mdma_resume(struct dma_chan *c) ...@@ -1198,7 +1216,7 @@ static int stm32_mdma_resume(struct dma_chan *c)
unsigned long flags; unsigned long flags;
u32 status, reg; 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); spin_lock_irqsave(&chan->vchan.lock, flags);
...@@ -1268,13 +1286,13 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan, ...@@ -1268,13 +1286,13 @@ static size_t stm32_mdma_desc_residue(struct stm32_mdma_chan *chan,
u32 curr_hwdesc) u32 curr_hwdesc)
{ {
struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); 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; u32 cbndtr, residue, modulo, burst_size;
int i; int i;
residue = 0; residue = 0;
for (i = curr_hwdesc + 1; i < desc->count; i++) { 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); residue += STM32_MDMA_CBNDTR_BNDT(hwdesc->cbndtr);
} }
cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id)); cbndtr = stm32_mdma_read(dmadev, STM32_MDMA_CBNDTR(chan->id));
...@@ -1503,7 +1521,7 @@ static struct dma_chan *stm32_mdma_of_xlate(struct of_phandle_args *dma_spec, ...@@ -1503,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); c = dma_get_any_slave_channel(&dmadev->ddev);
if (!c) { if (!c) {
dev_err(mdma2dev(dmadev), "No more channel avalaible\n"); dev_err(mdma2dev(dmadev), "No more channels available\n");
return NULL; return NULL;
} }
......
#
# 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
# 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
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include "dmaengine.h" #include "../dmaengine.h"
#define DESC_TYPE 27 #define DESC_TYPE 27
#define DESC_TYPE_HOST 0x10 #define DESC_TYPE_HOST 0x10
......
...@@ -33,8 +33,8 @@ ...@@ -33,8 +33,8 @@
#include <linux/platform_data/edma.h> #include <linux/platform_data/edma.h>
#include "dmaengine.h" #include "../dmaengine.h"
#include "virt-dma.h" #include "../virt-dma.h"
/* Offsets matching "struct edmacc_param" */ /* Offsets matching "struct edmacc_param" */
#define PARM_OPT 0x00 #define PARM_OPT 0x00
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
#include <linux/of_dma.h> #include <linux/of_dma.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include "virt-dma.h" #include "../virt-dma.h"
#define OMAP_SDMA_REQUESTS 127 #define OMAP_SDMA_REQUESTS 127
#define OMAP_SDMA_CHANNELS 32 #define OMAP_SDMA_CHANNELS 32
......
...@@ -1244,8 +1244,7 @@ static void txx9dmac_shutdown(struct platform_device *pdev) ...@@ -1244,8 +1244,7 @@ static void txx9dmac_shutdown(struct platform_device *pdev)
static int txx9dmac_suspend_noirq(struct device *dev) static int txx9dmac_suspend_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct txx9dmac_dev *ddev = dev_get_drvdata(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
txx9dmac_off(ddev); txx9dmac_off(ddev);
return 0; return 0;
...@@ -1253,9 +1252,8 @@ static int txx9dmac_suspend_noirq(struct device *dev) ...@@ -1253,9 +1252,8 @@ static int txx9dmac_suspend_noirq(struct device *dev)
static int txx9dmac_resume_noirq(struct device *dev) static int txx9dmac_resume_noirq(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct txx9dmac_dev *ddev = dev_get_drvdata(dev);
struct txx9dmac_dev *ddev = platform_get_drvdata(pdev); struct txx9dmac_platform_data *pdata = dev_get_platdata(dev);
struct txx9dmac_platform_data *pdata = dev_get_platdata(&pdev->dev);
u32 mcr; u32 mcr;
mcr = TXX9_DMA_MCR_MSTEN | MCR_LE; mcr = TXX9_DMA_MCR_MSTEN | MCR_LE;
......
/* SPDX-License-Identifier: GPL-2.0 */
#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
* @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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment