Skip to contentSkip to conversation

Add Qualcomm ADM dmaengine driver

PATCH RESEND Applied Andy Gross 2 participants 7 messages Sep 11, 2014 – Sep 24, 2014

Subsystems (3)

v1 of 6 Applied Latest is v6 →

lore
Share & tools
lore

Andy Gross

author
#0 lore raw

cover Add Qualcomm ADM dmaengine driver

I am resending this patch set at the request of the maintainer. The original text is shown below.

This patch set introduces the dmaengine driver for the Qualcomm Application Data Mover (ADM) DMA controller present on MSM8960, APQ8064, and IPQ8064 devices.

The initial version of this driver will only support slave DMA operations between system memory and peripherals. Flow control via the CRCI (client rate control interface) is supported and can be configured via device tree configuration. Flow control usage is required for some peripheral devices.

Andy Gross (2):
dmaengine: Add QCOM ADM DMA driver
dmaengine: qcom_adm: Add device tree binding

 Documentation/devicetree/bindings/dma/qcom_adm.txt |   62 ++
 drivers/dma/Kconfig                                |   10 +
 drivers/dma/Makefile                               |    1 +
 drivers/dma/qcom_adm.c                             |  872 ++++++++++++++++++++
 4 files changed, 945 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/qcom_adm.txt
 create mode 100644 drivers/dma/qcom_adm.c
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
author
#1 lore raw

PATCH 1/2 dmaengine: Add QCOM ADM DMA driver

Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA controller found in the MSM8960 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.

The initial release of this driver supports slave transfers to/from peripherals and also incorporates CRCI (client rate control interface) flow control.

---
 drivers/dma/Kconfig    |   10 +
 drivers/dma/Makefile   |    1 +
 drivers/dma/qcom_adm.c |  872 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 883 insertions(+)
 create mode 100644 drivers/dma/qcom_adm.c
drivers/dma/Kconfig +10 -0
index 9b1ea0e..88291ec 100644
@@ -469,4 +469,14 @@ config QCOM_BAM_DMA
 	  Enable support for the QCOM BAM DMA controller.  This controller
 	  provides DMA capabilities for a variety of on-chip devices.
 
+config QCOM_ADM
+	tristate "Qualcomm ADM support"
+	depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
+	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.
+
 endif
drivers/dma/Makefile +1 -0
index c6adb92..3bad47d 100644
@@ -50,3 +50,4 @@ obj-y += xilinx/
 obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
 obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
 obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o
drivers/dma/qcom_adm.c new file +872 -0

872 lines not on this page · raw message

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#2 lore raw

Re: [PATCH 1/2] dmaengine: Add QCOM ADM DMA driver

Quoted 25 lines · Andy Gross
drivers/dma/qcom_adm.c new file +25 -0
+static int adm_slave_config(struct adm_chan *achan,
+		struct dma_slave_config *cfg)
+{
+	int ret = 0;
+	u32 burst;
+	struct adm_device *adev = achan->adev;
+
+	memcpy(&achan->slave, cfg, sizeof(*cfg));
+
+	/* set channel CRCI burst, if applicable */
+	if (achan->crci) {
+		burst = max_t(u32, cfg->src_maxburst, cfg->dst_maxburst);
+
+		switch (burst) {
+		case 16:
+			achan->blk_size = 0;
+			break;
+		case 32:
+			achan->blk_size = 1;
+			break;
+		case 64:
+			achan->blk_size = 2;
+			break;
+		case 128:
+			achan->blk_size = 3;

drivers/dma/qcom_adm.c line 374

Quoted 10 lines
drivers/dma/qcom_adm.c new file +10 -0
+			break;
+		case 192:
+			achan->blk_size = 4;
+			break;
+		case 256:
+			achan->blk_size = 5;
+			break;
+		default:
+			achan->slave.src_maxburst = 0;
+			achan->slave.dst_maxburst = 0;

Why clear these for error cases

drivers/dma/qcom_adm.c line 381

Quoted 7 lines
drivers/dma/qcom_adm.c new file +7 -0
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!ret)
+			writel(achan->blk_size,
+				adev->regs + HI_CRCI_CTL(achan->id, adev->ee));

and why do we write to HW on this. Shouldn't this be done when you program the descriptor?

drivers/dma/qcom_adm.c line 575

Quoted 11 lines
drivers/dma/qcom_adm.c new file +11 -0
+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+	struct dma_tx_state *txstate)
+{
+	struct adm_chan *achan = to_adm_chan(chan);
+	struct virt_dma_desc *vd;
+	enum dma_status ret;
+	unsigned long flags;
+	size_t residue = 0;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+

Last arg can be null to this, so before you do residue calcluation and block interrupts would make sense to return from here if arg is NULL

drivers/dma/qcom_adm.c line 582

Quoted 7 lines
drivers/dma/qcom_adm.c new file +7 -0
+	spin_lock_irqsave(&achan->vc.lock, flags);
+
+	vd = vchan_find_desc(&achan->vc, cookie);
+	if (vd)
+		residue = container_of(vd, struct adm_async_desc, vd)->length;
+	else if (achan->curr_txd && achan->curr_txd->vd.tx.cookie == cookie)
+		residue = achan->curr_txd->length;

so this is current cookie, so you need to read from HW on current position

Quoted 9 lines
drivers/dma/qcom_adm.c new file +9 -0
+
+	spin_unlock_irqrestore(&achan->vc.lock, flags);
+
+	dma_set_residue(txstate, residue);
+
+	if (achan->error)
+		return DMA_ERROR;
+
+	return ret;
Signature · 1 line
~Vinod
author
#3 lore raw

Re: [PATCH 1/2] dmaengine: Add QCOM ADM DMA driver

<snip>

Quoted 5 lines

drivers/dma/qcom_adm.c line 374

Quoted 4 lines
drivers/dma/qcom_adm.c new file +4 -0
+			break;
+		default:
+			achan->slave.src_maxburst = 0;
+			achan->slave.dst_maxburst = 0;

Why clear these for error cases

With the return I shouldn't need to. I'll fix this.

Quoted 9 lines

drivers/dma/qcom_adm.c line 381

Quoted 7 lines
drivers/dma/qcom_adm.c new file +7 -0
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!ret)
+			writel(achan->blk_size,
+				adev->regs + HI_CRCI_CTL(achan->id, adev->ee));

and why do we write to HW on this. Shouldn't this be done when you program the descriptor?

It could be deferred to later. The main point is that I don't see the slave_config happening every transaction. I was only modifying it now instead of making a register write for every transaction.

Quoted 14 lines

drivers/dma/qcom_adm.c line 575

Quoted 12 lines
drivers/dma/qcom_adm.c new file +11 -0
+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+	struct dma_tx_state *txstate)
+{
+	struct adm_chan *achan = to_adm_chan(chan);
+	struct virt_dma_desc *vd;
+	enum dma_status ret;
+	unsigned long flags;
+	size_t residue = 0;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+

Last arg can be null to this, so before you do residue calcluation and block interrupts would make sense to return from here if arg is NULL

Good catch. Will fix.

Quoted 9 lines

drivers/dma/qcom_adm.c line 582

Quoted 8 lines
drivers/dma/qcom_adm.c new file +7 -0
+	spin_lock_irqsave(&achan->vc.lock, flags);
+
+	vd = vchan_find_desc(&achan->vc, cookie);
+	if (vd)
+		residue = container_of(vd, struct adm_async_desc, vd)->length;
+	else if (achan->curr_txd && achan->curr_txd->vd.tx.cookie == cookie)
+		residue = achan->curr_txd->length;

so this is current cookie, so you need to read from HW on current position

There is no way to get current position unfortunately without relying on unreliable debug registers.

Quoted 17 lines
Quoted 9 lines
drivers/dma/qcom_adm.c new file +9 -0
+
+	spin_unlock_irqrestore(&achan->vc.lock, flags);
+
+	dma_set_residue(txstate, residue);
+
+	if (achan->error)
+		return DMA_ERROR;
+
+	return ret;
Signature · 6 lines
~Vinod

--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
#4 lore raw

Re: [PATCH 1/2] dmaengine: Add QCOM ADM DMA driver

Quoted 20 lines · Andy Gross

<snip>

Quoted 5 lines

drivers/dma/qcom_adm.c line 374

Quoted 4 lines
drivers/dma/qcom_adm.c new file +4 -0
+			break;
+		default:
+			achan->slave.src_maxburst = 0;
+			achan->slave.dst_maxburst = 0;

Why clear these for error cases

With the return I shouldn't need to. I'll fix this.

Quoted 9 lines

drivers/dma/qcom_adm.c line 381

Quoted 7 lines
drivers/dma/qcom_adm.c new file +7 -0
+			ret = -EINVAL;
+			break;
+		}
+
+		if (!ret)
+			writel(achan->blk_size,
+				adev->regs + HI_CRCI_CTL(achan->id, adev->ee));

and why do we write to HW on this. Shouldn't this be done when you program the descriptor?

Quoted 3 lines

It could be deferred to later. The main point is that I don't see the slave_config happening every transaction. I was only modifying it now instead of making a register write for every transaction.

Well wouldn't it cause a problem if you write to hardware and a transaction is already in progress.
So it makese sense to write every time at transaction start with latest value programmed.

Quoted 27 lines
Quoted 14 lines

drivers/dma/qcom_adm.c line 575

Quoted 12 lines
drivers/dma/qcom_adm.c new file +11 -0
+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+	struct dma_tx_state *txstate)
+{
+	struct adm_chan *achan = to_adm_chan(chan);
+	struct virt_dma_desc *vd;
+	enum dma_status ret;
+	unsigned long flags;
+	size_t residue = 0;
+
+	ret = dma_cookie_status(chan, cookie, txstate);
+

Last arg can be null to this, so before you do residue calcluation and block interrupts would make sense to return from here if arg is NULL

Good catch. Will fix.

Quoted 9 lines

drivers/dma/qcom_adm.c line 582

Quoted 8 lines
drivers/dma/qcom_adm.c new file +7 -0
+	spin_lock_irqsave(&achan->vc.lock, flags);
+
+	vd = vchan_find_desc(&achan->vc, cookie);
+	if (vd)
+		residue = container_of(vd, struct adm_async_desc, vd)->length;
+	else if (achan->curr_txd && achan->curr_txd->vd.tx.cookie == cookie)
+		residue = achan->curr_txd->length;

so this is current cookie, so you need to read from HW on current position

Quoted 2 lines

There is no way to get current position unfortunately without relying on unreliable debug registers.

In that case would it make sense to return complete txn length?

Signature · 1 line
~Vinod
author
#5 lore raw

PATCH 2/2 dmaengine: qcom_adm: Add device tree binding

In reply to Andy Gross

Add device tree binding support for the QCOM ADM DMA driver.

---
 Documentation/devicetree/bindings/dma/qcom_adm.txt |   62 ++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/dma/qcom_adm.txt
Documentation/devicetree/bindings/dma/qcom_adm.txt new file +62 -0
new file mode 100644
index 0000000..9bcab91
@@ -0,0 +1,62 @@
+QCOM ADM DMA Controller
+
+Required properties:
+- compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960
+- reg: Address range for DMA registers
+- interrupts: Should contain one interrupt shared by all channels
+- #dma-cells: must be <2>.  First cell denotes the channel number.  Second cell
+  denotes CRCI (client rate control interface) flow control assignment.
+- clocks: Should contain the core clock and interface clock.
+- clock-names: Must contain "core" for the core clock and "iface" for the
+  interface clock.
+- resets: Must contain an entry for each entry in reset names.
+- reset-names: Must include the following entries:
+  - clk
+  - c0
+  - c1
+  - c2
+- qcom,ee: indicates the security domain identifier used in the secure world.
+
+Example:
+		adm_dma: dma at 18300000 {
+			compatible = "qcom,adm";
+			reg = <0x18300000 0x100000>;
+			interrupts = <0 170 0>;
+			#dma-cells = <2>;
+
+			clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
+			clock-names = "core", "iface";
+
+			resets = <&gcc ADM0_RESET>,
+				<&gcc ADM0_C0_RESET>,
+				<&gcc ADM0_C1_RESET>,
+				<&gcc ADM0_C2_RESET>;
+			reset-names = "clk", "c0", "c1", "c2";
+			qcom,ee = <0>;
+		};
+
+DMA clients must use the format descripted in the dma.txt file, using a three
+cell specifier for each channel.
+
+Each dmas request consists of 3 cells:
+ 1. phandle pointing to the DMA controller
+ 2. channel number
+ 3. CRCI assignment, if applicable.  If no CRCI flow control is required, use 0.
+    The CRCI is used for flow control.  It identifies the peripheral device that
+    is the source/destination for the transferred data.
+
+Example:
+
+	spi4: spi at 1a280000 {
+		status = "ok";
+		spi-max-frequency = <50000000>;
+
+		pinctrl-0 = <&spi_pins>;
+		pinctrl-names = "default";
+
+		cs-gpios = <&qcom_pinmux 20 0>;
+
+		dmas = <&adm_dma 6 9>,
+			<&adm_dma 5 10>;
+		dma-names = "rx", "tx";
+	};
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation
Applied
#6 lore raw

Re: [PATCH 2/2] dmaengine: qcom_adm: Add device tree binding

Quoted 2 lines · Andy Gross

Add device tree binding support for the QCOM ADM DMA driver.

Applied, thanks

Signature · 1 line
~Vinod