|
@@ -1,86 +1,95 @@
|
|
|
-From 563fa24db4e529c5a3311928d73a8a90531ee527 Mon Sep 17 00:00:00 2001
|
|
|
-From: Thomas Pedersen <[email protected]>
|
|
|
-Date: Mon, 16 May 2016 17:58:51 -0700
|
|
|
-Subject: [PATCH 02/69] dmaengine: Add ADM driver
|
|
|
-
|
|
|
-Original patch by Andy Gross.
|
|
|
+From 5c9f8c2dbdbe53818bcde6aa6695e1331e5f841f Mon Sep 17 00:00:00 2001
|
|
|
+From: Jonathan McDowell <[email protected]>
|
|
|
+Date: Sat, 14 Nov 2020 14:02:33 +0000
|
|
|
+Subject: dmaengine: qcom: Add ADM driver
|
|
|
|
|
|
Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA
|
|
|
controller found in the MSM8x60 and IPQ/APQ8064 platforms.
|
|
|
|
|
|
The ADM supports both memory to memory transactions and memory
|
|
|
-to/from peripheral device transactions. The controller also provides flow
|
|
|
-control capabilities for transactions to/from peripheral devices.
|
|
|
+to/from peripheral device transactions. The controller also provides
|
|
|
+flow control capabilities for transactions to/from peripheral devices.
|
|
|
+
|
|
|
+The initial release of this driver supports slave transfers to/from
|
|
|
+peripherals and also incorporates CRCI (client rate control interface)
|
|
|
+flow control.
|
|
|
|
|
|
-The initial release of this driver supports slave transfers to/from peripherals
|
|
|
-and also incorporates CRCI (client rate control interface) flow control.
|
|
|
+The hardware only supports a 32 bit physical address, so specifying
|
|
|
+!PHYS_ADDR_T_64BIT gives maximum COMPILE_TEST coverage without having to
|
|
|
+spend effort on kludging things in the code that will never actually be
|
|
|
+needed on real hardware.
|
|
|
|
|
|
Signed-off-by: Andy Gross <[email protected]>
|
|
|
Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+Signed-off-by: Jonathan McDowell <[email protected]>
|
|
|
+Link: https://lore.kernel.org/r/[email protected]
|
|
|
+Signed-off-by: Vinod Koul <[email protected]>
|
|
|
---
|
|
|
- drivers/dma/qcom/Kconfig | 10 +
|
|
|
+ drivers/dma/qcom/Kconfig | 11 +
|
|
|
drivers/dma/qcom/Makefile | 1 +
|
|
|
- drivers/dma/qcom/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
- 3 files changed, 911 insertions(+)
|
|
|
+ drivers/dma/qcom/qcom_adm.c | 903 ++++++++++++++++++++++++++++++++++++++++++++
|
|
|
+ 3 files changed, 915 insertions(+)
|
|
|
create mode 100644 drivers/dma/qcom/qcom_adm.c
|
|
|
|
|
|
+diff --git a/drivers/dma/qcom/Kconfig b/drivers/dma/qcom/Kconfig
|
|
|
+index 3bcb689162c67..0389d60d2604a 100644
|
|
|
--- a/drivers/dma/qcom/Kconfig
|
|
|
+++ b/drivers/dma/qcom/Kconfig
|
|
|
-@@ -28,3 +28,13 @@ config QCOM_HIDMA
|
|
|
- (user to kernel, kernel to kernel, etc.). It only supports
|
|
|
- memcpy interface. The core is not intended for general
|
|
|
- purpose slave DMA.
|
|
|
-+
|
|
|
+@@ -1,4 +1,15 @@
|
|
|
+ # SPDX-License-Identifier: GPL-2.0-only
|
|
|
+config QCOM_ADM
|
|
|
+ tristate "Qualcomm ADM support"
|
|
|
-+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
|
|
|
++ depends on (ARCH_QCOM || COMPILE_TEST) && !PHYS_ADDR_T_64BIT
|
|
|
+ select DMA_ENGINE
|
|
|
+ select DMA_VIRTUAL_CHANNELS
|
|
|
-+ ---help---
|
|
|
-+ Enable support for the Qualcomm ADM DMA controller. This controller
|
|
|
-+ provides DMA capabilities for both general purpose and on-chip
|
|
|
-+ peripheral devices.
|
|
|
++ help
|
|
|
++ Enable support for the Qualcomm Application Data Mover (ADM) DMA
|
|
|
++ controller, as present on MSM8x60, APQ8064, and IPQ8064 devices.
|
|
|
++ This controller provides DMA capabilities for both general purpose
|
|
|
++ and on-chip peripheral devices.
|
|
|
++
|
|
|
+ config QCOM_BAM_DMA
|
|
|
+ tristate "QCOM BAM DMA support"
|
|
|
+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
|
|
|
+diff --git a/drivers/dma/qcom/Makefile b/drivers/dma/qcom/Makefile
|
|
|
+index 1ae92da88b0c9..346e643fbb6db 100644
|
|
|
--- a/drivers/dma/qcom/Makefile
|
|
|
+++ b/drivers/dma/qcom/Makefile
|
|
|
-@@ -4,3 +4,4 @@ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mg
|
|
|
- hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o
|
|
|
- obj-$(CONFIG_QCOM_HIDMA) += hdma.o
|
|
|
- hdma-objs := hidma_ll.o hidma.o hidma_dbg.o
|
|
|
+@@ -1,4 +1,5 @@
|
|
|
+ # SPDX-License-Identifier: GPL-2.0
|
|
|
+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o
|
|
|
+ obj-$(CONFIG_QCOM_BAM_DMA) += bam_dma.o
|
|
|
+ obj-$(CONFIG_QCOM_HIDMA_MGMT) += hdma_mgmt.o
|
|
|
+ hdma_mgmt-objs := hidma_mgmt.o hidma_mgmt_sys.o
|
|
|
+diff --git a/drivers/dma/qcom/qcom_adm.c b/drivers/dma/qcom/qcom_adm.c
|
|
|
+new file mode 100644
|
|
|
+index 0000000000000..9b6f8e050ecce
|
|
|
--- /dev/null
|
|
|
+++ b/drivers/dma/qcom/qcom_adm.c
|
|
|
-@@ -0,0 +1,914 @@
|
|
|
+@@ -0,0 +1,903 @@
|
|
|
++// SPDX-License-Identifier: GPL-2.0-only
|
|
|
+/*
|
|
|
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
|
|
|
-+ *
|
|
|
-+ * This program is free software; you can redistribute it and/or modify
|
|
|
-+ * it under the terms of the GNU General Public License version 2 and
|
|
|
-+ * only version 2 as published by the Free Software Foundation.
|
|
|
-+ *
|
|
|
-+ * This program is distributed in the hope that it will be useful,
|
|
|
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+ * GNU General Public License for more details.
|
|
|
-+ *
|
|
|
+ */
|
|
|
+
|
|
|
-+#include <linux/kernel.h>
|
|
|
-+#include <linux/io.h>
|
|
|
++#include <linux/clk.h>
|
|
|
++#include <linux/delay.h>
|
|
|
++#include <linux/device.h>
|
|
|
++#include <linux/dmaengine.h>
|
|
|
++#include <linux/dma-mapping.h>
|
|
|
+#include <linux/init.h>
|
|
|
-+#include <linux/slab.h>
|
|
|
-+#include <linux/module.h>
|
|
|
+#include <linux/interrupt.h>
|
|
|
-+#include <linux/dma-mapping.h>
|
|
|
-+#include <linux/scatterlist.h>
|
|
|
-+#include <linux/device.h>
|
|
|
-+#include <linux/platform_device.h>
|
|
|
++#include <linux/io.h>
|
|
|
++#include <linux/kernel.h>
|
|
|
++#include <linux/module.h>
|
|
|
+#include <linux/of.h>
|
|
|
+#include <linux/of_address.h>
|
|
|
+#include <linux/of_irq.h>
|
|
|
+#include <linux/of_dma.h>
|
|
|
++#include <linux/platform_device.h>
|
|
|
+#include <linux/reset.h>
|
|
|
-+#include <linux/clk.h>
|
|
|
-+#include <linux/dmaengine.h>
|
|
|
++#include <linux/scatterlist.h>
|
|
|
++#include <linux/slab.h>
|
|
|
+
|
|
|
+#include "../dmaengine.h"
|
|
|
+#include "../virt-dma.h"
|
|
@@ -90,10 +99,10 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+#define ADM_CI_MULTI 0x4
|
|
|
+#define ADM_CRCI_MULTI 0x4
|
|
|
+#define ADM_EE_MULTI 0x800
|
|
|
-+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan)
|
|
|
-+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee)
|
|
|
++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan))
|
|
|
++#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * (ee))
|
|
|
+#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee))
|
|
|
-+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan)
|
|
|
++#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * (chan))
|
|
|
+#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci))
|
|
|
+#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee))
|
|
|
+#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee))
|
|
@@ -102,62 +111,62 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan))
|
|
|
+#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee))
|
|
|
+#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee))
|
|
|
-+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI)
|
|
|
++#define ADM_CI_CONF(ci) (0x390 + (ci) * ADM_CI_MULTI)
|
|
|
+#define ADM_GP_CTL 0x3d8
|
|
|
-+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \
|
|
|
++#define ADM_CRCI_CTL(crci, ee) (0x400 + (crci) * ADM_CRCI_MULTI + \
|
|
|
+ ADM_EE_OFFS(ee))
|
|
|
+
|
|
|
+/* channel status */
|
|
|
-+#define ADM_CH_STATUS_VALID BIT(1)
|
|
|
++#define ADM_CH_STATUS_VALID BIT(1)
|
|
|
+
|
|
|
+/* channel result */
|
|
|
-+#define ADM_CH_RSLT_VALID BIT(31)
|
|
|
-+#define ADM_CH_RSLT_ERR BIT(3)
|
|
|
-+#define ADM_CH_RSLT_FLUSH BIT(2)
|
|
|
-+#define ADM_CH_RSLT_TPD BIT(1)
|
|
|
++#define ADM_CH_RSLT_VALID BIT(31)
|
|
|
++#define ADM_CH_RSLT_ERR BIT(3)
|
|
|
++#define ADM_CH_RSLT_FLUSH BIT(2)
|
|
|
++#define ADM_CH_RSLT_TPD BIT(1)
|
|
|
+
|
|
|
+/* channel conf */
|
|
|
+#define ADM_CH_CONF_SHADOW_EN BIT(12)
|
|
|
+#define ADM_CH_CONF_MPU_DISABLE BIT(11)
|
|
|
+#define ADM_CH_CONF_PERM_MPU_CONF BIT(9)
|
|
|
+#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7)
|
|
|
-+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11))
|
|
|
++#define ADM_CH_CONF_SEC_DOMAIN(ee) ((((ee) & 0x3) << 4) | (((ee) & 0x4) << 11))
|
|
|
+
|
|
|
+/* channel result conf */
|
|
|
+#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1)
|
|
|
+#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0)
|
|
|
+
|
|
|
+/* CRCI CTL */
|
|
|
-+#define ADM_CRCI_CTL_MUX_SEL BIT(18)
|
|
|
-+#define ADM_CRCI_CTL_RST BIT(17)
|
|
|
++#define ADM_CRCI_CTL_MUX_SEL BIT(18)
|
|
|
++#define ADM_CRCI_CTL_RST BIT(17)
|
|
|
+
|
|
|
+/* CI configuration */
|
|
|
-+#define ADM_CI_RANGE_END(x) (x << 24)
|
|
|
-+#define ADM_CI_RANGE_START(x) (x << 16)
|
|
|
-+#define ADM_CI_BURST_4_WORDS BIT(2)
|
|
|
-+#define ADM_CI_BURST_8_WORDS BIT(3)
|
|
|
++#define ADM_CI_RANGE_END(x) ((x) << 24)
|
|
|
++#define ADM_CI_RANGE_START(x) ((x) << 16)
|
|
|
++#define ADM_CI_BURST_4_WORDS BIT(2)
|
|
|
++#define ADM_CI_BURST_8_WORDS BIT(3)
|
|
|
+
|
|
|
+/* GP CTL */
|
|
|
-+#define ADM_GP_CTL_LP_EN BIT(12)
|
|
|
-+#define ADM_GP_CTL_LP_CNT(x) (x << 8)
|
|
|
++#define ADM_GP_CTL_LP_EN BIT(12)
|
|
|
++#define ADM_GP_CTL_LP_CNT(x) ((x) << 8)
|
|
|
+
|
|
|
+/* Command pointer list entry */
|
|
|
-+#define ADM_CPLE_LP BIT(31)
|
|
|
-+#define ADM_CPLE_CMD_PTR_LIST BIT(29)
|
|
|
++#define ADM_CPLE_LP BIT(31)
|
|
|
++#define ADM_CPLE_CMD_PTR_LIST BIT(29)
|
|
|
+
|
|
|
+/* Command list entry */
|
|
|
-+#define ADM_CMD_LC BIT(31)
|
|
|
-+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7)
|
|
|
-+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3)
|
|
|
++#define ADM_CMD_LC BIT(31)
|
|
|
++#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7)
|
|
|
++#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3)
|
|
|
+
|
|
|
-+#define ADM_CMD_TYPE_SINGLE 0x0
|
|
|
-+#define ADM_CMD_TYPE_BOX 0x3
|
|
|
++#define ADM_CMD_TYPE_SINGLE 0x0
|
|
|
++#define ADM_CMD_TYPE_BOX 0x3
|
|
|
+
|
|
|
-+#define ADM_CRCI_MUX_SEL BIT(4)
|
|
|
-+#define ADM_DESC_ALIGN 8
|
|
|
-+#define ADM_MAX_XFER (SZ_64K-1)
|
|
|
-+#define ADM_MAX_ROWS (SZ_64K-1)
|
|
|
-+#define ADM_MAX_CHANNELS 16
|
|
|
++#define ADM_CRCI_MUX_SEL BIT(4)
|
|
|
++#define ADM_DESC_ALIGN 8
|
|
|
++#define ADM_MAX_XFER (SZ_64K - 1)
|
|
|
++#define ADM_MAX_ROWS (SZ_64K - 1)
|
|
|
++#define ADM_MAX_CHANNELS 16
|
|
|
+
|
|
|
+struct adm_desc_hw_box {
|
|
|
+ u32 cmd;
|
|
@@ -255,7 +264,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ case 32:
|
|
|
+ case 64:
|
|
|
+ case 128:
|
|
|
-+ ret = ffs(burst>>4) - 1;
|
|
|
++ ret = ffs(burst >> 4) - 1;
|
|
|
+ break;
|
|
|
+ case 192:
|
|
|
+ ret = 4;
|
|
@@ -281,9 +290,10 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ * @burst: Burst size of transaction
|
|
|
+ * @direction: DMA transfer direction
|
|
|
+ */
|
|
|
-+static void *adm_process_fc_descriptors(struct adm_chan *achan,
|
|
|
-+ void *desc, struct scatterlist *sg, u32 crci, u32 burst,
|
|
|
-+ enum dma_transfer_direction direction)
|
|
|
++static void *adm_process_fc_descriptors(struct adm_chan *achan, void *desc,
|
|
|
++ struct scatterlist *sg, u32 crci,
|
|
|
++ u32 burst,
|
|
|
++ enum dma_transfer_direction direction)
|
|
|
+{
|
|
|
+ struct adm_desc_hw_box *box_desc = NULL;
|
|
|
+ struct adm_desc_hw_single *single_desc;
|
|
@@ -349,9 +359,9 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ * @sg: Scatterlist entry
|
|
|
+ * @direction: DMA transfer direction
|
|
|
+ */
|
|
|
-+static void *adm_process_non_fc_descriptors(struct adm_chan *achan,
|
|
|
-+ void *desc, struct scatterlist *sg,
|
|
|
-+ enum dma_transfer_direction direction)
|
|
|
++static void *adm_process_non_fc_descriptors(struct adm_chan *achan, void *desc,
|
|
|
++ struct scatterlist *sg,
|
|
|
++ enum dma_transfer_direction direction)
|
|
|
+{
|
|
|
+ struct adm_desc_hw_single *single_desc;
|
|
|
+ u32 remainder = sg_dma_len(sg);
|
|
@@ -398,9 +408,11 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ * @context: transfer context (unused)
|
|
|
+ */
|
|
|
+static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan,
|
|
|
-+ struct scatterlist *sgl, unsigned int sg_len,
|
|
|
-+ enum dma_transfer_direction direction, unsigned long flags,
|
|
|
-+ void *context)
|
|
|
++ struct scatterlist *sgl,
|
|
|
++ unsigned int sg_len,
|
|
|
++ enum dma_transfer_direction direction,
|
|
|
++ unsigned long flags,
|
|
|
++ void *context)
|
|
|
+{
|
|
|
+ struct adm_chan *achan = to_adm_chan(chan);
|
|
|
+ struct adm_device *adev = achan->adev;
|
|
@@ -427,7 +439,6 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ /* if using flow control, validate burst and crci values */
|
|
|
+ if (achan->slave.device_fc) {
|
|
|
-+
|
|
|
+ blk_size = adm_get_blksize(burst);
|
|
|
+ if (blk_size < 0) {
|
|
|
+ dev_err(adev->dev, "invalid burst value: %d\n",
|
|
@@ -455,7 +466,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
-+ async_desc = kzalloc(sizeof(*async_desc), GFP_ATOMIC);
|
|
|
++ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT);
|
|
|
+ if (!async_desc)
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
+
|
|
@@ -468,7 +479,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ box_count * sizeof(struct adm_desc_hw_box) +
|
|
|
+ sizeof(*cple) + 2 * ADM_DESC_ALIGN;
|
|
|
+
|
|
|
-+ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_ATOMIC);
|
|
|
++ async_desc->cpl = kzalloc(async_desc->dma_len, GFP_NOWAIT);
|
|
|
+ if (!async_desc->cpl)
|
|
|
+ goto free;
|
|
|
+
|
|
@@ -483,10 +494,10 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ if (achan->slave.device_fc)
|
|
|
+ desc = adm_process_fc_descriptors(achan, desc, sg, crci,
|
|
|
-+ burst, direction);
|
|
|
++ burst, direction);
|
|
|
+ else
|
|
|
+ desc = adm_process_non_fc_descriptors(achan, desc, sg,
|
|
|
-+ direction);
|
|
|
++ direction);
|
|
|
+ }
|
|
|
+
|
|
|
+ async_desc->dma_addr = dma_map_single(adev->dev, async_desc->cpl,
|
|
@@ -532,7 +543,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ /* send flush command to terminate current transaction */
|
|
|
+ writel_relaxed(0x0,
|
|
|
-+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee));
|
|
|
++ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee));
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&achan->vc.lock, flags);
|
|
|
+
|
|
@@ -586,7 +597,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ adev->regs + ADM_CH_CONF(achan->id));
|
|
|
+
|
|
|
+ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN,
|
|
|
-+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
|
|
|
++ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
|
|
|
+
|
|
|
+ achan->initialized = 1;
|
|
|
+ }
|
|
@@ -594,7 +605,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ /* set the crci block size if this transaction requires CRCI */
|
|
|
+ if (async_desc->crci) {
|
|
|
+ writel(async_desc->mux | async_desc->blk_size,
|
|
|
-+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee));
|
|
|
++ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* make sure IRQ enable doesn't get reordered */
|
|
@@ -602,7 +613,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ /* write next command list out to the CMD FIFO */
|
|
|
+ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3,
|
|
|
-+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee));
|
|
|
++ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
@@ -628,7 +639,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ if (srcs & BIT(i)) {
|
|
|
+ status = readl_relaxed(adev->regs +
|
|
|
-+ ADM_CH_STATUS_SD(i, adev->ee));
|
|
|
++ ADM_CH_STATUS_SD(i, adev->ee));
|
|
|
+
|
|
|
+ /* if no result present, skip */
|
|
|
+ if (!(status & ADM_CH_STATUS_VALID))
|
|
@@ -673,7 +684,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ * Return status of dma transaction
|
|
|
+ */
|
|
|
+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
|
|
|
-+ struct dma_tx_state *txstate)
|
|
|
++ struct dma_tx_state *txstate)
|
|
|
+{
|
|
|
+ struct adm_chan *achan = to_adm_chan(chan);
|
|
|
+ struct virt_dma_desc *vd;
|
|
@@ -697,7 +708,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ * residue is either the full length if it is in the issued list, or 0
|
|
|
+ * if it is in progress. We have no reliable way of determining
|
|
|
+ * anything inbetween
|
|
|
-+ */
|
|
|
++ */
|
|
|
+ dma_set_residue(txstate, residue);
|
|
|
+
|
|
|
+ if (achan->error)
|
|
@@ -741,7 +752,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+}
|
|
|
+
|
|
|
+static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan,
|
|
|
-+ u32 index)
|
|
|
++ u32 index)
|
|
|
+{
|
|
|
+ achan->id = index;
|
|
|
+ achan->adev = adev;
|
|
@@ -753,7 +764,6 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+static int adm_dma_probe(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct adm_device *adev;
|
|
|
-+ struct resource *iores;
|
|
|
+ int ret;
|
|
|
+ u32 i;
|
|
|
+
|
|
@@ -763,8 +773,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ adev->dev = &pdev->dev;
|
|
|
+
|
|
|
-+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
|
-+ adev->regs = devm_ioremap_resource(&pdev->dev, iores);
|
|
|
++ adev->regs = devm_platform_ioremap_resource(pdev, 0);
|
|
|
+ if (IS_ERR(adev->regs))
|
|
|
+ return PTR_ERR(adev->regs);
|
|
|
+
|
|
@@ -782,50 +791,44 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ if (IS_ERR(adev->core_clk))
|
|
|
+ return PTR_ERR(adev->core_clk);
|
|
|
+
|
|
|
-+ ret = clk_prepare_enable(adev->core_clk);
|
|
|
-+ if (ret) {
|
|
|
-+ dev_err(adev->dev, "failed to prepare/enable core clock\n");
|
|
|
-+ return ret;
|
|
|
-+ }
|
|
|
-+
|
|
|
+ adev->iface_clk = devm_clk_get(adev->dev, "iface");
|
|
|
-+ if (IS_ERR(adev->iface_clk)) {
|
|
|
-+ ret = PTR_ERR(adev->iface_clk);
|
|
|
-+ goto err_disable_core_clk;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ret = clk_prepare_enable(adev->iface_clk);
|
|
|
-+ if (ret) {
|
|
|
-+ dev_err(adev->dev, "failed to prepare/enable iface clock\n");
|
|
|
-+ goto err_disable_core_clk;
|
|
|
-+ }
|
|
|
++ if (IS_ERR(adev->iface_clk))
|
|
|
++ return PTR_ERR(adev->iface_clk);
|
|
|
+
|
|
|
-+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk");
|
|
|
++ adev->clk_reset = devm_reset_control_get_exclusive(&pdev->dev, "clk");
|
|
|
+ if (IS_ERR(adev->clk_reset)) {
|
|
|
+ dev_err(adev->dev, "failed to get ADM0 reset\n");
|
|
|
-+ ret = PTR_ERR(adev->clk_reset);
|
|
|
-+ goto err_disable_clks;
|
|
|
++ return PTR_ERR(adev->clk_reset);
|
|
|
+ }
|
|
|
+
|
|
|
-+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0");
|
|
|
++ adev->c0_reset = devm_reset_control_get_exclusive(&pdev->dev, "c0");
|
|
|
+ if (IS_ERR(adev->c0_reset)) {
|
|
|
+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n");
|
|
|
-+ ret = PTR_ERR(adev->c0_reset);
|
|
|
-+ goto err_disable_clks;
|
|
|
++ return PTR_ERR(adev->c0_reset);
|
|
|
+ }
|
|
|
+
|
|
|
-+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1");
|
|
|
++ adev->c1_reset = devm_reset_control_get_exclusive(&pdev->dev, "c1");
|
|
|
+ if (IS_ERR(adev->c1_reset)) {
|
|
|
+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n");
|
|
|
-+ ret = PTR_ERR(adev->c1_reset);
|
|
|
-+ goto err_disable_clks;
|
|
|
++ return PTR_ERR(adev->c1_reset);
|
|
|
+ }
|
|
|
+
|
|
|
-+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2");
|
|
|
++ adev->c2_reset = devm_reset_control_get_exclusive(&pdev->dev, "c2");
|
|
|
+ if (IS_ERR(adev->c2_reset)) {
|
|
|
+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n");
|
|
|
-+ ret = PTR_ERR(adev->c2_reset);
|
|
|
-+ goto err_disable_clks;
|
|
|
++ return PTR_ERR(adev->c2_reset);
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = clk_prepare_enable(adev->core_clk);
|
|
|
++ if (ret) {
|
|
|
++ dev_err(adev->dev, "failed to prepare/enable core clock\n");
|
|
|
++ return ret;
|
|
|
++ }
|
|
|
++
|
|
|
++ ret = clk_prepare_enable(adev->iface_clk);
|
|
|
++ if (ret) {
|
|
|
++ dev_err(adev->dev, "failed to prepare/enable iface clock\n");
|
|
|
++ goto err_disable_core_clk;
|
|
|
+ }
|
|
|
+
|
|
|
+ reset_control_assert(adev->clk_reset);
|
|
@@ -833,13 +836,15 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ reset_control_assert(adev->c1_reset);
|
|
|
+ reset_control_assert(adev->c2_reset);
|
|
|
+
|
|
|
++ udelay(2);
|
|
|
++
|
|
|
+ reset_control_deassert(adev->clk_reset);
|
|
|
+ reset_control_deassert(adev->c0_reset);
|
|
|
+ reset_control_deassert(adev->c1_reset);
|
|
|
+ reset_control_deassert(adev->c2_reset);
|
|
|
+
|
|
|
+ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS,
|
|
|
-+ sizeof(*adev->channels), GFP_KERNEL);
|
|
|
++ sizeof(*adev->channels), GFP_KERNEL);
|
|
|
+
|
|
|
+ if (!adev->channels) {
|
|
|
+ ret = -ENOMEM;
|
|
@@ -859,16 +864,16 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+
|
|
|
+ /* configure client interfaces */
|
|
|
+ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) |
|
|
|
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0));
|
|
|
++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0));
|
|
|
+ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) |
|
|
|
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1));
|
|
|
++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1));
|
|
|
+ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) |
|
|
|
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2));
|
|
|
++ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2));
|
|
|
+ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf),
|
|
|
-+ adev->regs + ADM_GP_CTL);
|
|
|
++ adev->regs + ADM_GP_CTL);
|
|
|
+
|
|
|
+ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq,
|
|
|
-+ 0, "adm_dma", adev);
|
|
|
++ 0, "adm_dma", adev);
|
|
|
+ if (ret)
|
|
|
+ goto err_disable_clks;
|
|
|
+
|
|
@@ -933,6 +938,7 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+ /* mask IRQs for this channel/EE pair */
|
|
|
+ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
|
|
|
+
|
|
|
++ tasklet_kill(&adev->channels[i].vc.task);
|
|
|
+ adm_terminate_all(&adev->channels[i].vc.chan);
|
|
|
+ }
|
|
|
+
|
|
@@ -964,3 +970,6 @@ Signed-off-by: Thomas Pedersen <[email protected]>
|
|
|
+MODULE_AUTHOR("Andy Gross <[email protected]>");
|
|
|
+MODULE_DESCRIPTION("QCOM ADM DMA engine driver");
|
|
|
+MODULE_LICENSE("GPL v2");
|
|
|
+--
|
|
|
+cgit 1.2.3-1.el7
|
|
|
+
|