Re: [PATCH v7 2/4] dmaengine: tegra: Add tegra gpcdma driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





On 23/09/2021 08:51, Akhil R wrote:
Adding GPC DMA controller driver for Tegra186 and Tegra194. The driver
supports dma transfers between memory to memory, IO peripheral to memory
and memory to IO peripheral.

Signed-off-by: Pavan Kunapuli <pkunapuli@xxxxxxxxxx>
Signed-off-by: Rajesh Gumasta <rgumasta@xxxxxxxxxx>
Signed-off-by: Akhil R <akhilrajeev@xxxxxxxxxx>
---
  drivers/dma/Kconfig            |   12 +
  drivers/dma/Makefile           |    1 +
  drivers/dma/tegra186-gpc-dma.c | 1354 ++++++++++++++++++++++++++++++++++++++++
  3 files changed, 1367 insertions(+)
  create mode 100644 drivers/dma/tegra186-gpc-dma.c

...

+static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
+					   dma_cookie_t cookie,
+					   struct dma_tx_state *txstate)
+{
+	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+	struct tegra_dma_desc *dma_desc = NULL;
+	struct virt_dma_desc *vd;
+	unsigned int residual;
+	enum dma_status ret;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&tdc->lock, flags);
+
+	ret = dma_cookie_status(dc, cookie, txstate);
+	if (ret == DMA_COMPLETE) {
+		raw_spin_unlock_irqrestore(&tdc->lock, flags);
+		return ret;
+	}
+
+	vd = vchan_find_desc(&tdc->vc, cookie);
+	if (vd)
+		dma_desc = vd_to_tegra_dma_desc(vd);

This first case implies that the transfer has not started yet and so the residual is just dma_desc->bytes_requested.

+	else if (tdc->dma_desc && tdc->dma_desc->vd.tx.cookie == cookie)
+		dma_desc = tdc->dma_desc;
+
+	if (dma_desc) {
+		residual =  dma_desc->bytes_requested -
+					(dma_desc->bytes_transferred %
+					dma_desc->bytes_requested);
+		dma_set_residue(txstate, residual);
+	} else {
+		dev_err(tdc2dev(tdc), "cookie %d is not found\n", cookie);
+	}
+
+	raw_spin_unlock_irqrestore(&tdc->lock, flags);
+	return ret;
+}
+
+static inline int get_bus_width(struct tegra_dma_channel *tdc,
+				enum dma_slave_buswidth slave_bw)
+{
+	switch (slave_bw) {
+	case DMA_SLAVE_BUSWIDTH_1_BYTE:
+		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8;
+	case DMA_SLAVE_BUSWIDTH_2_BYTES:
+		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_16;
+	case DMA_SLAVE_BUSWIDTH_4_BYTES:
+		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_32;
+	default:
+		dev_err(tdc2dev(tdc), "given slave bus width is not supported\n");
+		return -EINVAL;
+	}
+}
+
+static inline int get_burst_size_by_len(int len)
+{
+	int ret;
+
+	/* Get burst size based on the first set bit */
+	switch (ffs(len)) {
+	case 0:
+	case 1:
+	case 2:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_1;
+		break;
+	case 3:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_2;
+		break;
+	case 4:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_4;
+		break;
+	case 5:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_8;
+		break;
+	default:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_16;
+		break;
+	}
+
+	return ret;
+}
+
+static inline int get_burst_size(struct tegra_dma_channel *tdc,
+				 u32 burst_size,
+				 enum dma_slave_buswidth slave_bw,
+				 int len)
+{
+	int burst_mmio_width, burst_byte, ret;
+
+	/*
+	 * burst_size from client is in terms of the bus_width.
+	 * convert that into words.
+	 */
+	burst_byte = burst_size * slave_bw;
+	burst_mmio_width = ffs(burst_byte / 4);
+
+	/* Get burst size based on the first set bit */
+	switch (burst_mmio_width) {
+	case 0:
+		ret = get_burst_size_by_len(len);
+		break;
+	case 1:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_1;
+		break;
+	case 2:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_2;
+		break;
+	case 3:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_4;
+		break;
+	case 4:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_8;
+		break;
+	default:
+		ret = TEGRA_GPCDMA_MMIOSEQ_BURST_16;
+		break;
+	}
+
+	return ret;
+}

Something seems a bit odd here in the sense that if burst_mmio_width == 0, we could still end up with a burst of 16? I am not sure I understand this logic.

Jon

--
nvpublic



[Index of Archives]     [ARM Kernel]     [Linux ARM]     [Linux ARM MSM]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux