dmaengine updates for 4.18-rc1
- Updates to sprd, bam_dma, stm drivers. - removal of VLAs in dmatest. - Move TI drivers its own subdir. - Switch to SPDX tags for ima/mxs dma drivers. - Simplify getting .drvdata on bunch of drivers by Wolfram Sang. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbGPc+AAoJEHwUBw8lI4NHRxMQAMekjobWFidkB2QkNub53jlB CAH2owLSFa/rk4CzEtxHts0q4YfW84xGcFiYMeVXeN5F62XQe4kacnbov7jVgxXe wHx5UlyEjMODFz1SwqysdB1T7wj6CtnFkPeCW4Wz3Kh6EcynoMCpV5XG4EXxoHMI 4hLNafsKSH+yX2OudpcivU+FSqT7GVHs2rT1ZLaUcGosme2iM2EHMplfQYQ2bTXr +W/cmDf58OIuu2G3gECSb3qeFDTBnJrCkAtCemHFT01mtMeBA67m1zns+5nQTFGz WD9XiB/OQuCVxfh7X6EvwdTkA5+w+gOkMp+H4OSScRiScK1hCcEeP7Uf4gGviQi0 qzzV/snBXm68/pijkvbGhjE2oDz0ydExmaunrA3pHzBx1YEs07uhrw8aiyqhiG73 YaoB2auUSyiTKshhnGq5jedeCsoKIRGxlmZ4ophAzyi+6GWDGDSoFd0L9WswR3RU yY3xGn5jpGN8DLmya2El4oDz3MAE9e+OxeQ9ZnanXFgFOJQK4zlybFDp7vjDK4LJ ILPm5FCiyrWZiovcUNt191UP+hywPL1SEgCEF3f38F8yiTe6bB8VhCQ5/0wVy6uc pGmWTOBT7Bvw9VN18JbvCSrrZqc2pAThnDHxrCzCSYro1JWOwdvKG5v9hVeFCPwl l+UOrjg8q2bgVn4yPJ5R =8mGV -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
2996148a9d
31 changed files with 635 additions and 401 deletions
|
@ -29,6 +29,7 @@ Required Properties:
|
|||
- "renesas,dmac-r8a77965" (R-Car M3-N)
|
||||
- "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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -11790,6 +11790,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 <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
|
||||
M: Rob Clark <robdclark@gmail.com>
|
||||
L: iommu@lists.linux-foundation.org
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 @@ static int fsldma_suspend_late(struct device *dev)
|
|||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <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
|
||||
*/
|
||||
// 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 <s.hauer@pengutronix.de>
|
||||
// Copyright 2012 Javier Martin, Vista Silicon <javier.martin@vista-silicon.com>
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
|
|
@ -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 <s.hauer@pengutronix.de>
|
||||
*
|
||||
* 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 <s.hauer@pengutronix.de>
|
||||
//
|
||||
// Based on code from Freescale:
|
||||
//
|
||||
// Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
|
|
@ -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 <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <linux/of_dma.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
@ -673,7 +674,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);
|
||||
}
|
||||
|
@ -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
|
||||
* @bchan: bam dma channel
|
||||
* @chan: bam dma channel
|
||||
*
|
||||
* Dequeues and frees all transactions
|
||||
* No callbacks are done
|
||||
|
@ -918,7 +919,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -958,7 +960,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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 @@ static int sh_dmae_probe(struct platform_device *pdev)
|
|||
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);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/dma/sprd-dma.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
@ -116,57 +117,21 @@
|
|||
#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
|
||||
|
||||
/*
|
||||
* 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,
|
||||
SPRD_DMA_DATAWIDTH_2_BYTES,
|
||||
SPRD_DMA_DATAWIDTH_4_BYTES,
|
||||
SPRD_DMA_DATAWIDTH_8_BYTES,
|
||||
};
|
||||
|
||||
/* dma channel hardware configuration */
|
||||
|
@ -199,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;
|
||||
|
@ -587,52 +553,97 @@ 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)
|
||||
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 datawidth, src_step, des_step, fragment_len;
|
||||
u32 block_len, req_mode, irq_mode, transcation_len;
|
||||
u32 fix_mode = 0, fix_en = 0;
|
||||
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 (IS_ALIGNED(len, 4)) {
|
||||
datawidth = 2;
|
||||
src_step = 4;
|
||||
des_step = 4;
|
||||
} else if (IS_ALIGNED(len, 2)) {
|
||||
datawidth = 1;
|
||||
src_step = 2;
|
||||
des_step = 2;
|
||||
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 {
|
||||
datawidth = 0;
|
||||
src_step = 1;
|
||||
des_step = 1;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
} else {
|
||||
fix_en = 1;
|
||||
|
@ -642,71 +653,26 @@ static int sprd_dma_config(struct dma_chan *chan, struct sprd_dma_desc *sdesc,
|
|||
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 = int_mode | SPRD_DMA_CFG_ERR_INT_EN;
|
||||
|
||||
hw->intc = 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;
|
||||
|
||||
switch (irq_mode) {
|
||||
case SPRD_DMA_NO_INT:
|
||||
break;
|
||||
hw->blk_len = len & SPRD_DMA_BLK_LEN_MASK;
|
||||
hw->trsc_len = len & SPRD_DMA_TRSC_LEN_MASK;
|
||||
|
||||
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;
|
||||
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;
|
||||
hw->src_blk_step = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -716,13 +682,90 @@ sprd_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
|
|||
{
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -842,10 +898,9 @@ static int sprd_dma_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
sdev->glb_base = devm_ioremap_nocache(&pdev->dev, res->start,
|
||||
resource_size(res));
|
||||
if (!sdev->glb_base)
|
||||
return -ENOMEM;
|
||||
sdev->glb_base = devm_ioremap_resource(&pdev->dev, res);
|
||||
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;
|
||||
|
@ -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_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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
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;
|
||||
}
|
||||
|
@ -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,
|
||||
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,
|
||||
|
@ -694,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 |
|
||||
|
@ -704,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,
|
||||
|
@ -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_desc *desc;
|
||||
int ret;
|
||||
int i, ret;
|
||||
|
||||
/*
|
||||
* 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,
|
|||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/* Prepare hardware descriptor */
|
||||
hwdesc = desc->hwdesc;
|
||||
hwdesc = desc->node[0].hwdesc;
|
||||
hwdesc->ctcr = ctcr;
|
||||
hwdesc->cbndtr = cbndtr;
|
||||
hwdesc->csar = 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->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) |
|
||||
|
@ -1120,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);
|
||||
|
@ -1198,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);
|
||||
|
||||
|
@ -1268,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));
|
||||
|
@ -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);
|
||||
if (!c) {
|
||||
dev_err(mdma2dev(dmadev), "No more channel avalaible\n");
|
||||
dev_err(mdma2dev(dmadev), "No more channels available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
37
drivers/dma/ti/Kconfig
Normal file
37
drivers/dma/ti/Kconfig
Normal file
|
@ -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
|
5
drivers/dma/ti/Makefile
Normal file
5
drivers/dma/ti/Makefile
Normal file
|
@ -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
|
|
@ -11,7 +11,7 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include "dmaengine.h"
|
||||
#include "../dmaengine.h"
|
||||
|
||||
#define DESC_TYPE 27
|
||||
#define DESC_TYPE_HOST 0x10
|
|
@ -33,8 +33,8 @@
|
|||
|
||||
#include <linux/platform_data/edma.h>
|
||||
|
||||
#include "dmaengine.h"
|
||||
#include "virt-dma.h"
|
||||
#include "../dmaengine.h"
|
||||
#include "../virt-dma.h"
|
||||
|
||||
/* Offsets matching "struct edmacc_param" */
|
||||
#define PARM_OPT 0x00
|
|
@ -21,7 +21,7 @@
|
|||
#include <linux/of_dma.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include "virt-dma.h"
|
||||
#include "../virt-dma.h"
|
||||
|
||||
#define OMAP_SDMA_REQUESTS 127
|
||||
#define OMAP_SDMA_CHANNELS 32
|
|
@ -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;
|
||||
|
|
61
include/linux/dma/sprd-dma.h
Normal file
61
include/linux/dma/sprd-dma.h
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* 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
|
Loading…
Reference in a new issue