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