162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * DMA driver for NVIDIA Tegra GPC DMA controller.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2014-2022, NVIDIA CORPORATION.  All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitfield.h>
962306a36Sopenharmony_ci#include <linux/dmaengine.h>
1062306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1162306a36Sopenharmony_ci#include <linux/interrupt.h>
1262306a36Sopenharmony_ci#include <linux/iommu.h>
1362306a36Sopenharmony_ci#include <linux/iopoll.h>
1462306a36Sopenharmony_ci#include <linux/minmax.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/of.h>
1762306a36Sopenharmony_ci#include <linux/of_dma.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/reset.h>
2062306a36Sopenharmony_ci#include <linux/slab.h>
2162306a36Sopenharmony_ci#include <dt-bindings/memory/tegra186-mc.h>
2262306a36Sopenharmony_ci#include "virt-dma.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* CSR register */
2562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSR			0x00
2662306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_ENB			BIT(31)
2762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_IE_EOC			BIT(30)
2862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_ONCE			BIT(27)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE		GENMASK(25, 24)
3162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_NO_MMIO	\
3262306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 0)
3362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_ONE_MMIO	\
3462306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 1)
3562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_TWO_MMIO	\
3662306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 2)
3762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_FOUR_MMIO	\
3862306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 3)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA			GENMASK(23, 21)
4162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_IO2MEM_NO_FC	\
4262306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 0)
4362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_IO2MEM_FC		\
4462306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 1)
4562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2IO_NO_FC	\
4662306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 2)
4762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2IO_FC		\
4862306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 3)
4962306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2MEM		\
5062306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 4)
5162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_FIXED_PAT		\
5262306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 6)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_REQ_SEL_MASK		GENMASK(20, 16)
5562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED		\
5662306a36Sopenharmony_ci					FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, 4)
5762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_IRQ_MASK		BIT(15)
5862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_WEIGHT			GENMASK(13, 10)
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci/* STATUS register */
6162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_STATUS		0x004
6262306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_BUSY		BIT(31)
6362306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_ISE_EOC		BIT(30)
6462306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_PING_PONG		BIT(28)
6562306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_DMA_ACTIVITY	BIT(27)
6662306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_PAUSE	BIT(26)
6762306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_RX		BIT(25)
6862306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_TX		BIT(24)
6962306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_INTR_STA	BIT(23)
7062306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_STA		BIT(21)
7162306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_TRIG_STA	BIT(20)
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSRE			0x008
7462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSRE_PAUSE		BIT(31)
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Source address */
7762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SRC_PTR		0x00C
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/* Destination address */
8062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_DST_PTR		0x010
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* High address pointer */
8362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR		0x014
8462306a36Sopenharmony_ci#define TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR		GENMASK(7, 0)
8562306a36Sopenharmony_ci#define TEGRA_GPCDMA_HIGH_ADDR_DST_PTR		GENMASK(23, 16)
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci/* MC sequence register */
8862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_MCSEQ			0x18
8962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_DATA_SWAP		BIT(31)
9062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_REQ_COUNT		GENMASK(30, 25)
9162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST		GENMASK(24, 23)
9262306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST_2		\
9362306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_MCSEQ_BURST, 0)
9462306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST_16		\
9562306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_MCSEQ_BURST, 3)
9662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP1		GENMASK(22, 20)
9762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP0		GENMASK(19, 17)
9862306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP_NONE		0
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK	GENMASK(13, 7)
10162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK	GENMASK(6, 0)
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/* MMIO sequence register */
10462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_MMIOSEQ			0x01c
10562306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_DBL_BUF		BIT(31)
10662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH		GENMASK(30, 28)
10762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8	\
10862306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 0)
10962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_16	\
11062306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 1)
11162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_32	\
11262306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 2)
11362306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_DATA_SWAP		BIT(27)
11462306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_SHIFT	23
11562306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_MIN		2U
11662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_MAX		32U
11762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST(bs)	\
11862306a36Sopenharmony_ci		(GENMASK((fls(bs) - 2), 0) << TEGRA_GPCDMA_MMIOSEQ_BURST_SHIFT)
11962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_MASTER_ID		GENMASK(22, 19)
12062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD		GENMASK(18, 16)
12162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_MMIO_PROT		GENMASK(8, 7)
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* Channel WCOUNT */
12462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_WCOUNT		0x20
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci/* Transfer count */
12762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_XFER_COUNT		0x24
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci/* DMA byte count status */
13062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS	0x28
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* Error Status Register */
13362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_STATUS		0x30
13462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT	8
13562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK	0xF
13662306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE(err)	(			\
13762306a36Sopenharmony_ci		((err) >> TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT) &	\
13862306a36Sopenharmony_ci		TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK)
13962306a36Sopenharmony_ci#define TEGRA_DMA_BM_FIFO_FULL_ERR		0xF
14062306a36Sopenharmony_ci#define TEGRA_DMA_PERIPH_FIFO_FULL_ERR		0xE
14162306a36Sopenharmony_ci#define TEGRA_DMA_PERIPH_ID_ERR			0xD
14262306a36Sopenharmony_ci#define TEGRA_DMA_STREAM_ID_ERR			0xC
14362306a36Sopenharmony_ci#define TEGRA_DMA_MC_SLAVE_ERR			0xB
14462306a36Sopenharmony_ci#define TEGRA_DMA_MMIO_SLAVE_ERR		0xA
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* Fixed Pattern */
14762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_FIXED_PATTERN		0x34
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ			0x38
15062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ_MMIO_PROT_1	BIT(0)
15162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ_MC_PROT_1		BIT(1)
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SPARE			0x3c
15462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SPARE_EN_LEGACY_FC	BIT(16)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/*
15762306a36Sopenharmony_ci * If any burst is in flight and DMA paused then this is the time to complete
15862306a36Sopenharmony_ci * on-flight burst and update DMA status register.
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_ci#define TEGRA_GPCDMA_BURST_COMPLETE_TIME	10
16162306a36Sopenharmony_ci#define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT	5000 /* 5 msec */
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci/* Channel base address offset from GPCDMA base address */
16462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET	0x10000
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/* Default channel mask reserving channel0 */
16762306a36Sopenharmony_ci#define TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK	0xfffffffe
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct tegra_dma;
17062306a36Sopenharmony_cistruct tegra_dma_channel;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * tegra_dma_chip_data Tegra chip specific DMA data
17462306a36Sopenharmony_ci * @nr_channels: Number of channels available in the controller.
17562306a36Sopenharmony_ci * @channel_reg_size: Channel register size.
17662306a36Sopenharmony_ci * @max_dma_count: Maximum DMA transfer count supported by DMA controller.
17762306a36Sopenharmony_ci * @hw_support_pause: DMA HW engine support pause of the channel.
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_cistruct tegra_dma_chip_data {
18062306a36Sopenharmony_ci	bool hw_support_pause;
18162306a36Sopenharmony_ci	unsigned int nr_channels;
18262306a36Sopenharmony_ci	unsigned int channel_reg_size;
18362306a36Sopenharmony_ci	unsigned int max_dma_count;
18462306a36Sopenharmony_ci	int (*terminate)(struct tegra_dma_channel *tdc);
18562306a36Sopenharmony_ci};
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci/* DMA channel registers */
18862306a36Sopenharmony_cistruct tegra_dma_channel_regs {
18962306a36Sopenharmony_ci	u32 csr;
19062306a36Sopenharmony_ci	u32 src_ptr;
19162306a36Sopenharmony_ci	u32 dst_ptr;
19262306a36Sopenharmony_ci	u32 high_addr_ptr;
19362306a36Sopenharmony_ci	u32 mc_seq;
19462306a36Sopenharmony_ci	u32 mmio_seq;
19562306a36Sopenharmony_ci	u32 wcount;
19662306a36Sopenharmony_ci	u32 fixed_pattern;
19762306a36Sopenharmony_ci};
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/*
20062306a36Sopenharmony_ci * tegra_dma_sg_req: DMA request details to configure hardware. This
20162306a36Sopenharmony_ci * contains the details for one transfer to configure DMA hw.
20262306a36Sopenharmony_ci * The client's request for data transfer can be broken into multiple
20362306a36Sopenharmony_ci * sub-transfer as per requester details and hw support. This sub transfer
20462306a36Sopenharmony_ci * get added as an array in Tegra DMA desc which manages the transfer details.
20562306a36Sopenharmony_ci */
20662306a36Sopenharmony_cistruct tegra_dma_sg_req {
20762306a36Sopenharmony_ci	unsigned int len;
20862306a36Sopenharmony_ci	struct tegra_dma_channel_regs ch_regs;
20962306a36Sopenharmony_ci};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci/*
21262306a36Sopenharmony_ci * tegra_dma_desc: Tegra DMA descriptors which uses virt_dma_desc to
21362306a36Sopenharmony_ci * manage client request and keep track of transfer status, callbacks
21462306a36Sopenharmony_ci * and request counts etc.
21562306a36Sopenharmony_ci */
21662306a36Sopenharmony_cistruct tegra_dma_desc {
21762306a36Sopenharmony_ci	bool cyclic;
21862306a36Sopenharmony_ci	unsigned int bytes_req;
21962306a36Sopenharmony_ci	unsigned int bytes_xfer;
22062306a36Sopenharmony_ci	unsigned int sg_idx;
22162306a36Sopenharmony_ci	unsigned int sg_count;
22262306a36Sopenharmony_ci	struct virt_dma_desc vd;
22362306a36Sopenharmony_ci	struct tegra_dma_channel *tdc;
22462306a36Sopenharmony_ci	struct tegra_dma_sg_req sg_req[];
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/*
22862306a36Sopenharmony_ci * tegra_dma_channel: Channel specific information
22962306a36Sopenharmony_ci */
23062306a36Sopenharmony_cistruct tegra_dma_channel {
23162306a36Sopenharmony_ci	bool config_init;
23262306a36Sopenharmony_ci	char name[30];
23362306a36Sopenharmony_ci	enum dma_transfer_direction sid_dir;
23462306a36Sopenharmony_ci	int id;
23562306a36Sopenharmony_ci	int irq;
23662306a36Sopenharmony_ci	int slave_id;
23762306a36Sopenharmony_ci	struct tegra_dma *tdma;
23862306a36Sopenharmony_ci	struct virt_dma_chan vc;
23962306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
24062306a36Sopenharmony_ci	struct dma_slave_config dma_sconfig;
24162306a36Sopenharmony_ci	unsigned int stream_id;
24262306a36Sopenharmony_ci	unsigned long chan_base_offset;
24362306a36Sopenharmony_ci};
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci/*
24662306a36Sopenharmony_ci * tegra_dma: Tegra DMA specific information
24762306a36Sopenharmony_ci */
24862306a36Sopenharmony_cistruct tegra_dma {
24962306a36Sopenharmony_ci	const struct tegra_dma_chip_data *chip_data;
25062306a36Sopenharmony_ci	unsigned long sid_m2d_reserved;
25162306a36Sopenharmony_ci	unsigned long sid_d2m_reserved;
25262306a36Sopenharmony_ci	u32 chan_mask;
25362306a36Sopenharmony_ci	void __iomem *base_addr;
25462306a36Sopenharmony_ci	struct device *dev;
25562306a36Sopenharmony_ci	struct dma_device dma_dev;
25662306a36Sopenharmony_ci	struct reset_control *rst;
25762306a36Sopenharmony_ci	struct tegra_dma_channel channels[];
25862306a36Sopenharmony_ci};
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_cistatic inline void tdc_write(struct tegra_dma_channel *tdc,
26162306a36Sopenharmony_ci			     u32 reg, u32 val)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	writel_relaxed(val, tdc->tdma->base_addr + tdc->chan_base_offset + reg);
26462306a36Sopenharmony_ci}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_cistatic inline u32 tdc_read(struct tegra_dma_channel *tdc, u32 reg)
26762306a36Sopenharmony_ci{
26862306a36Sopenharmony_ci	return readl_relaxed(tdc->tdma->base_addr + tdc->chan_base_offset + reg);
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic inline struct tegra_dma_channel *to_tegra_dma_chan(struct dma_chan *dc)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	return container_of(dc, struct tegra_dma_channel, vc.chan);
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic inline struct tegra_dma_desc *vd_to_tegra_dma_desc(struct virt_dma_desc *vd)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	return container_of(vd, struct tegra_dma_desc, vd);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic inline struct device *tdc2dev(struct tegra_dma_channel *tdc)
28262306a36Sopenharmony_ci{
28362306a36Sopenharmony_ci	return tdc->vc.chan.device->dev;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n",
28962306a36Sopenharmony_ci		tdc->id, tdc->name);
29062306a36Sopenharmony_ci	dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x SRC %x DST %x\n",
29162306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR),
29262306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS),
29362306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE),
29462306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR),
29562306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_DST_PTR)
29662306a36Sopenharmony_ci	);
29762306a36Sopenharmony_ci	dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x BSTA %x\n",
29862306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ),
29962306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ),
30062306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_WCOUNT),
30162306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT),
30262306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS)
30362306a36Sopenharmony_ci	);
30462306a36Sopenharmony_ci	dev_dbg(tdc2dev(tdc), "DMA ERR_STA %x\n",
30562306a36Sopenharmony_ci		tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS));
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int tegra_dma_sid_reserve(struct tegra_dma_channel *tdc,
30962306a36Sopenharmony_ci				 enum dma_transfer_direction direction)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	struct tegra_dma *tdma = tdc->tdma;
31262306a36Sopenharmony_ci	int sid = tdc->slave_id;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (!is_slave_direction(direction))
31562306a36Sopenharmony_ci		return 0;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	switch (direction) {
31862306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
31962306a36Sopenharmony_ci		if (test_and_set_bit(sid, &tdma->sid_m2d_reserved)) {
32062306a36Sopenharmony_ci			dev_err(tdma->dev, "slave id already in use\n");
32162306a36Sopenharmony_ci			return -EINVAL;
32262306a36Sopenharmony_ci		}
32362306a36Sopenharmony_ci		break;
32462306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
32562306a36Sopenharmony_ci		if (test_and_set_bit(sid, &tdma->sid_d2m_reserved)) {
32662306a36Sopenharmony_ci			dev_err(tdma->dev, "slave id already in use\n");
32762306a36Sopenharmony_ci			return -EINVAL;
32862306a36Sopenharmony_ci		}
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	default:
33162306a36Sopenharmony_ci		break;
33262306a36Sopenharmony_ci	}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	tdc->sid_dir = direction;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	return 0;
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void tegra_dma_sid_free(struct tegra_dma_channel *tdc)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct tegra_dma *tdma = tdc->tdma;
34262306a36Sopenharmony_ci	int sid = tdc->slave_id;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	switch (tdc->sid_dir) {
34562306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
34662306a36Sopenharmony_ci		clear_bit(sid,  &tdma->sid_m2d_reserved);
34762306a36Sopenharmony_ci		break;
34862306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
34962306a36Sopenharmony_ci		clear_bit(sid,  &tdma->sid_d2m_reserved);
35062306a36Sopenharmony_ci		break;
35162306a36Sopenharmony_ci	default:
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	tdc->sid_dir = DMA_TRANS_NONE;
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic void tegra_dma_desc_free(struct virt_dma_desc *vd)
35962306a36Sopenharmony_ci{
36062306a36Sopenharmony_ci	kfree(container_of(vd, struct tegra_dma_desc, vd));
36162306a36Sopenharmony_ci}
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_cistatic int tegra_dma_slave_config(struct dma_chan *dc,
36462306a36Sopenharmony_ci				  struct dma_slave_config *sconfig)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig));
36962306a36Sopenharmony_ci	tdc->config_init = true;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	return 0;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic int tegra_dma_pause(struct tegra_dma_channel *tdc)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	int ret;
37762306a36Sopenharmony_ci	u32 val;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
38062306a36Sopenharmony_ci	val |= TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
38162306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	/* Wait until busy bit is de-asserted */
38462306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
38562306a36Sopenharmony_ci			tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
38662306a36Sopenharmony_ci			val,
38762306a36Sopenharmony_ci			!(val & TEGRA_GPCDMA_STATUS_BUSY),
38862306a36Sopenharmony_ci			TEGRA_GPCDMA_BURST_COMPLETE_TIME,
38962306a36Sopenharmony_ci			TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (ret) {
39262306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "DMA pause timed out\n");
39362306a36Sopenharmony_ci		tegra_dma_dump_chan_regs(tdc);
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return ret;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic int tegra_dma_device_pause(struct dma_chan *dc)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
40262306a36Sopenharmony_ci	unsigned long flags;
40362306a36Sopenharmony_ci	int ret;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (!tdc->tdma->chip_data->hw_support_pause)
40662306a36Sopenharmony_ci		return -ENOSYS;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	spin_lock_irqsave(&tdc->vc.lock, flags);
40962306a36Sopenharmony_ci	ret = tegra_dma_pause(tdc);
41062306a36Sopenharmony_ci	spin_unlock_irqrestore(&tdc->vc.lock, flags);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return ret;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void tegra_dma_resume(struct tegra_dma_channel *tdc)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	u32 val;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE);
42062306a36Sopenharmony_ci	val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE;
42162306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cistatic int tegra_dma_device_resume(struct dma_chan *dc)
42562306a36Sopenharmony_ci{
42662306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
42762306a36Sopenharmony_ci	unsigned long flags;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (!tdc->tdma->chip_data->hw_support_pause)
43062306a36Sopenharmony_ci		return -ENOSYS;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	spin_lock_irqsave(&tdc->vc.lock, flags);
43362306a36Sopenharmony_ci	tegra_dma_resume(tdc);
43462306a36Sopenharmony_ci	spin_unlock_irqrestore(&tdc->vc.lock, flags);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic inline int tegra_dma_pause_noerr(struct tegra_dma_channel *tdc)
44062306a36Sopenharmony_ci{
44162306a36Sopenharmony_ci	/* Return 0 irrespective of PAUSE status.
44262306a36Sopenharmony_ci	 * This is useful to recover channels that can exit out of flush
44362306a36Sopenharmony_ci	 * state when the channel is disabled.
44462306a36Sopenharmony_ci	 */
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	tegra_dma_pause(tdc);
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_cistatic void tegra_dma_disable(struct tegra_dma_channel *tdc)
45162306a36Sopenharmony_ci{
45262306a36Sopenharmony_ci	u32 csr, status;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/* Disable interrupts */
45762306a36Sopenharmony_ci	csr &= ~TEGRA_GPCDMA_CSR_IE_EOC;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	/* Disable DMA */
46062306a36Sopenharmony_ci	csr &= ~TEGRA_GPCDMA_CSR_ENB;
46162306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	/* Clear interrupt status if it is there */
46462306a36Sopenharmony_ci	status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
46562306a36Sopenharmony_ci	if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) {
46662306a36Sopenharmony_ci		dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__);
46762306a36Sopenharmony_ci		tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, status);
46862306a36Sopenharmony_ci	}
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc = tdc->dma_desc;
47462306a36Sopenharmony_ci	struct tegra_dma_channel_regs *ch_regs;
47562306a36Sopenharmony_ci	int ret;
47662306a36Sopenharmony_ci	u32 val;
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	dma_desc->sg_idx++;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* Reset the sg index for cyclic transfers */
48162306a36Sopenharmony_ci	if (dma_desc->sg_idx == dma_desc->sg_count)
48262306a36Sopenharmony_ci		dma_desc->sg_idx = 0;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	/* Configure next transfer immediately after DMA is busy */
48562306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
48662306a36Sopenharmony_ci			tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS,
48762306a36Sopenharmony_ci			val,
48862306a36Sopenharmony_ci			(val & TEGRA_GPCDMA_STATUS_BUSY), 0,
48962306a36Sopenharmony_ci			TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT);
49062306a36Sopenharmony_ci	if (ret)
49162306a36Sopenharmony_ci		return;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
49662306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
49762306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
49862306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	/* Start DMA */
50162306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
50262306a36Sopenharmony_ci		  ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void tegra_dma_start(struct tegra_dma_channel *tdc)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc = tdc->dma_desc;
50862306a36Sopenharmony_ci	struct tegra_dma_channel_regs *ch_regs;
50962306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (!dma_desc) {
51262306a36Sopenharmony_ci		vdesc = vchan_next_desc(&tdc->vc);
51362306a36Sopenharmony_ci		if (!vdesc)
51462306a36Sopenharmony_ci			return;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci		dma_desc = vd_to_tegra_dma_desc(vdesc);
51762306a36Sopenharmony_ci		list_del(&vdesc->node);
51862306a36Sopenharmony_ci		dma_desc->tdc = tdc;
51962306a36Sopenharmony_ci		tdc->dma_desc = dma_desc;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		tegra_dma_resume(tdc);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount);
52762306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 0);
52862306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr);
52962306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr);
53062306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr);
53162306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_FIXED_PATTERN, ch_regs->fixed_pattern);
53262306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ, ch_regs->mmio_seq);
53362306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, ch_regs->mc_seq);
53462306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, ch_regs->csr);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/* Start DMA */
53762306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR,
53862306a36Sopenharmony_ci		  ch_regs->csr | TEGRA_GPCDMA_CSR_ENB);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	vchan_cookie_complete(&tdc->dma_desc->vd);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	tegra_dma_sid_free(tdc);
54662306a36Sopenharmony_ci	tdc->dma_desc = NULL;
54762306a36Sopenharmony_ci}
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_cistatic void tegra_dma_chan_decode_error(struct tegra_dma_channel *tdc,
55062306a36Sopenharmony_ci					unsigned int err_status)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	switch (TEGRA_GPCDMA_CHAN_ERR_TYPE(err_status)) {
55362306a36Sopenharmony_ci	case TEGRA_DMA_BM_FIFO_FULL_ERR:
55462306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
55562306a36Sopenharmony_ci			"GPCDMA CH%d bm fifo full\n", tdc->id);
55662306a36Sopenharmony_ci		break;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	case TEGRA_DMA_PERIPH_FIFO_FULL_ERR:
55962306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
56062306a36Sopenharmony_ci			"GPCDMA CH%d peripheral fifo full\n", tdc->id);
56162306a36Sopenharmony_ci		break;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	case TEGRA_DMA_PERIPH_ID_ERR:
56462306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
56562306a36Sopenharmony_ci			"GPCDMA CH%d illegal peripheral id\n", tdc->id);
56662306a36Sopenharmony_ci		break;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	case TEGRA_DMA_STREAM_ID_ERR:
56962306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
57062306a36Sopenharmony_ci			"GPCDMA CH%d illegal stream id\n", tdc->id);
57162306a36Sopenharmony_ci		break;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	case TEGRA_DMA_MC_SLAVE_ERR:
57462306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
57562306a36Sopenharmony_ci			"GPCDMA CH%d mc slave error\n", tdc->id);
57662306a36Sopenharmony_ci		break;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	case TEGRA_DMA_MMIO_SLAVE_ERR:
57962306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
58062306a36Sopenharmony_ci			"GPCDMA CH%d mmio slave error\n", tdc->id);
58162306a36Sopenharmony_ci		break;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	default:
58462306a36Sopenharmony_ci		dev_err(tdc->tdma->dev,
58562306a36Sopenharmony_ci			"GPCDMA CH%d security violation %x\n", tdc->id,
58662306a36Sopenharmony_ci			err_status);
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic irqreturn_t tegra_dma_isr(int irq, void *dev_id)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = dev_id;
59362306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc = tdc->dma_desc;
59462306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req;
59562306a36Sopenharmony_ci	u32 status;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* Check channel error status register */
59862306a36Sopenharmony_ci	status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS);
59962306a36Sopenharmony_ci	if (status) {
60062306a36Sopenharmony_ci		tegra_dma_chan_decode_error(tdc, status);
60162306a36Sopenharmony_ci		tegra_dma_dump_chan_regs(tdc);
60262306a36Sopenharmony_ci		tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF);
60362306a36Sopenharmony_ci	}
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	spin_lock(&tdc->vc.lock);
60662306a36Sopenharmony_ci	status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
60762306a36Sopenharmony_ci	if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC))
60862306a36Sopenharmony_ci		goto irq_done;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS,
61162306a36Sopenharmony_ci		  TEGRA_GPCDMA_STATUS_ISE_EOC);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (!dma_desc)
61462306a36Sopenharmony_ci		goto irq_done;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	sg_req = dma_desc->sg_req;
61762306a36Sopenharmony_ci	dma_desc->bytes_xfer += sg_req[dma_desc->sg_idx].len;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (dma_desc->cyclic) {
62062306a36Sopenharmony_ci		vchan_cyclic_callback(&dma_desc->vd);
62162306a36Sopenharmony_ci		tegra_dma_configure_next_sg(tdc);
62262306a36Sopenharmony_ci	} else {
62362306a36Sopenharmony_ci		dma_desc->sg_idx++;
62462306a36Sopenharmony_ci		if (dma_desc->sg_idx == dma_desc->sg_count)
62562306a36Sopenharmony_ci			tegra_dma_xfer_complete(tdc);
62662306a36Sopenharmony_ci		else
62762306a36Sopenharmony_ci			tegra_dma_start(tdc);
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ciirq_done:
63162306a36Sopenharmony_ci	spin_unlock(&tdc->vc.lock);
63262306a36Sopenharmony_ci	return IRQ_HANDLED;
63362306a36Sopenharmony_ci}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_cistatic void tegra_dma_issue_pending(struct dma_chan *dc)
63662306a36Sopenharmony_ci{
63762306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
63862306a36Sopenharmony_ci	unsigned long flags;
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (tdc->dma_desc)
64162306a36Sopenharmony_ci		return;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	spin_lock_irqsave(&tdc->vc.lock, flags);
64462306a36Sopenharmony_ci	if (vchan_issue_pending(&tdc->vc))
64562306a36Sopenharmony_ci		tegra_dma_start(tdc);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci	/*
64862306a36Sopenharmony_ci	 * For cyclic DMA transfers, program the second
64962306a36Sopenharmony_ci	 * transfer parameters as soon as the first DMA
65062306a36Sopenharmony_ci	 * transfer is started inorder for the DMA
65162306a36Sopenharmony_ci	 * controller to trigger the second transfer
65262306a36Sopenharmony_ci	 * with the correct parameters.
65362306a36Sopenharmony_ci	 */
65462306a36Sopenharmony_ci	if (tdc->dma_desc && tdc->dma_desc->cyclic)
65562306a36Sopenharmony_ci		tegra_dma_configure_next_sg(tdc);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	spin_unlock_irqrestore(&tdc->vc.lock, flags);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_cistatic int tegra_dma_stop_client(struct tegra_dma_channel *tdc)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	int ret;
66362306a36Sopenharmony_ci	u32 status, csr;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * Change the client associated with the DMA channel
66762306a36Sopenharmony_ci	 * to stop DMA engine from starting any more bursts for
66862306a36Sopenharmony_ci	 * the given client and wait for in flight bursts to complete
66962306a36Sopenharmony_ci	 */
67062306a36Sopenharmony_ci	csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR);
67162306a36Sopenharmony_ci	csr &= ~(TEGRA_GPCDMA_CSR_REQ_SEL_MASK);
67262306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED;
67362306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	/* Wait for in flight data transfer to finish */
67662306a36Sopenharmony_ci	udelay(TEGRA_GPCDMA_BURST_COMPLETE_TIME);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* If TX/RX path is still active wait till it becomes
67962306a36Sopenharmony_ci	 * inactive
68062306a36Sopenharmony_ci	 */
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr +
68362306a36Sopenharmony_ci				tdc->chan_base_offset +
68462306a36Sopenharmony_ci				TEGRA_GPCDMA_CHAN_STATUS,
68562306a36Sopenharmony_ci				status,
68662306a36Sopenharmony_ci				!(status & (TEGRA_GPCDMA_STATUS_CHANNEL_TX |
68762306a36Sopenharmony_ci				TEGRA_GPCDMA_STATUS_CHANNEL_RX)),
68862306a36Sopenharmony_ci				5,
68962306a36Sopenharmony_ci				TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT);
69062306a36Sopenharmony_ci	if (ret) {
69162306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "Timeout waiting for DMA burst completion!\n");
69262306a36Sopenharmony_ci		tegra_dma_dump_chan_regs(tdc);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	return ret;
69662306a36Sopenharmony_ci}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_cistatic int tegra_dma_terminate_all(struct dma_chan *dc)
69962306a36Sopenharmony_ci{
70062306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
70162306a36Sopenharmony_ci	unsigned long flags;
70262306a36Sopenharmony_ci	LIST_HEAD(head);
70362306a36Sopenharmony_ci	int err;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	spin_lock_irqsave(&tdc->vc.lock, flags);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (tdc->dma_desc) {
70862306a36Sopenharmony_ci		err = tdc->tdma->chip_data->terminate(tdc);
70962306a36Sopenharmony_ci		if (err) {
71062306a36Sopenharmony_ci			spin_unlock_irqrestore(&tdc->vc.lock, flags);
71162306a36Sopenharmony_ci			return err;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci		vchan_terminate_vdesc(&tdc->dma_desc->vd);
71562306a36Sopenharmony_ci		tegra_dma_disable(tdc);
71662306a36Sopenharmony_ci		tdc->dma_desc = NULL;
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	tegra_dma_sid_free(tdc);
72062306a36Sopenharmony_ci	vchan_get_all_descriptors(&tdc->vc, &head);
72162306a36Sopenharmony_ci	spin_unlock_irqrestore(&tdc->vc.lock, flags);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	vchan_dma_desc_free_list(&tdc->vc, &head);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return 0;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic int tegra_dma_get_residual(struct tegra_dma_channel *tdc)
72962306a36Sopenharmony_ci{
73062306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc = tdc->dma_desc;
73162306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req = dma_desc->sg_req;
73262306a36Sopenharmony_ci	unsigned int bytes_xfer, residual;
73362306a36Sopenharmony_ci	u32 wcount = 0, status;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/*
73862306a36Sopenharmony_ci	 * Set wcount = 0 if EOC bit is set. The transfer would have
73962306a36Sopenharmony_ci	 * already completed and the CHAN_XFER_COUNT could have updated
74062306a36Sopenharmony_ci	 * for the next transfer, specifically in case of cyclic transfers.
74162306a36Sopenharmony_ci	 */
74262306a36Sopenharmony_ci	status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS);
74362306a36Sopenharmony_ci	if (status & TEGRA_GPCDMA_STATUS_ISE_EOC)
74462306a36Sopenharmony_ci		wcount = 0;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	bytes_xfer = dma_desc->bytes_xfer +
74762306a36Sopenharmony_ci		     sg_req[dma_desc->sg_idx].len - (wcount * 4);
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	residual = dma_desc->bytes_req - (bytes_xfer % dma_desc->bytes_req);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	return residual;
75262306a36Sopenharmony_ci}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_cistatic enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
75562306a36Sopenharmony_ci					   dma_cookie_t cookie,
75662306a36Sopenharmony_ci					   struct dma_tx_state *txstate)
75762306a36Sopenharmony_ci{
75862306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
75962306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
76062306a36Sopenharmony_ci	struct virt_dma_desc *vd;
76162306a36Sopenharmony_ci	unsigned int residual;
76262306a36Sopenharmony_ci	unsigned long flags;
76362306a36Sopenharmony_ci	enum dma_status ret;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ret = dma_cookie_status(dc, cookie, txstate);
76662306a36Sopenharmony_ci	if (ret == DMA_COMPLETE)
76762306a36Sopenharmony_ci		return ret;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	spin_lock_irqsave(&tdc->vc.lock, flags);
77062306a36Sopenharmony_ci	vd = vchan_find_desc(&tdc->vc, cookie);
77162306a36Sopenharmony_ci	if (vd) {
77262306a36Sopenharmony_ci		dma_desc = vd_to_tegra_dma_desc(vd);
77362306a36Sopenharmony_ci		residual = dma_desc->bytes_req;
77462306a36Sopenharmony_ci		dma_set_residue(txstate, residual);
77562306a36Sopenharmony_ci	} else if (tdc->dma_desc && tdc->dma_desc->vd.tx.cookie == cookie) {
77662306a36Sopenharmony_ci		residual =  tegra_dma_get_residual(tdc);
77762306a36Sopenharmony_ci		dma_set_residue(txstate, residual);
77862306a36Sopenharmony_ci	} else {
77962306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "cookie %d is not found\n", cookie);
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci	spin_unlock_irqrestore(&tdc->vc.lock, flags);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return ret;
78462306a36Sopenharmony_ci}
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_cistatic inline int get_bus_width(struct tegra_dma_channel *tdc,
78762306a36Sopenharmony_ci				enum dma_slave_buswidth slave_bw)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	switch (slave_bw) {
79062306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_1_BYTE:
79162306a36Sopenharmony_ci		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8;
79262306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_2_BYTES:
79362306a36Sopenharmony_ci		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_16;
79462306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_4_BYTES:
79562306a36Sopenharmony_ci		return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_32;
79662306a36Sopenharmony_ci	default:
79762306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "given slave bus width is not supported\n");
79862306a36Sopenharmony_ci		return -EINVAL;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci}
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_cistatic unsigned int get_burst_size(struct tegra_dma_channel *tdc,
80362306a36Sopenharmony_ci				   u32 burst_size, enum dma_slave_buswidth slave_bw,
80462306a36Sopenharmony_ci				   int len)
80562306a36Sopenharmony_ci{
80662306a36Sopenharmony_ci	unsigned int burst_mmio_width, burst_byte;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/*
80962306a36Sopenharmony_ci	 * burst_size from client is in terms of the bus_width.
81062306a36Sopenharmony_ci	 * convert that into words.
81162306a36Sopenharmony_ci	 * If burst_size is not specified from client, then use
81262306a36Sopenharmony_ci	 * len to calculate the optimum burst size
81362306a36Sopenharmony_ci	 */
81462306a36Sopenharmony_ci	burst_byte = burst_size ? burst_size * slave_bw : len;
81562306a36Sopenharmony_ci	burst_mmio_width = burst_byte / 4;
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	if (burst_mmio_width < TEGRA_GPCDMA_MMIOSEQ_BURST_MIN)
81862306a36Sopenharmony_ci		return 0;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	burst_mmio_width = min(burst_mmio_width, TEGRA_GPCDMA_MMIOSEQ_BURST_MAX);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	return TEGRA_GPCDMA_MMIOSEQ_BURST(burst_mmio_width);
82362306a36Sopenharmony_ci}
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_cistatic int get_transfer_param(struct tegra_dma_channel *tdc,
82662306a36Sopenharmony_ci			      enum dma_transfer_direction direction,
82762306a36Sopenharmony_ci			      u32 *apb_addr,
82862306a36Sopenharmony_ci			      u32 *mmio_seq,
82962306a36Sopenharmony_ci			      u32 *csr,
83062306a36Sopenharmony_ci			      unsigned int *burst_size,
83162306a36Sopenharmony_ci			      enum dma_slave_buswidth *slave_bw)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	switch (direction) {
83462306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
83562306a36Sopenharmony_ci		*apb_addr = tdc->dma_sconfig.dst_addr;
83662306a36Sopenharmony_ci		*mmio_seq = get_bus_width(tdc, tdc->dma_sconfig.dst_addr_width);
83762306a36Sopenharmony_ci		*burst_size = tdc->dma_sconfig.dst_maxburst;
83862306a36Sopenharmony_ci		*slave_bw = tdc->dma_sconfig.dst_addr_width;
83962306a36Sopenharmony_ci		*csr = TEGRA_GPCDMA_CSR_DMA_MEM2IO_FC;
84062306a36Sopenharmony_ci		return 0;
84162306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
84262306a36Sopenharmony_ci		*apb_addr = tdc->dma_sconfig.src_addr;
84362306a36Sopenharmony_ci		*mmio_seq = get_bus_width(tdc, tdc->dma_sconfig.src_addr_width);
84462306a36Sopenharmony_ci		*burst_size = tdc->dma_sconfig.src_maxburst;
84562306a36Sopenharmony_ci		*slave_bw = tdc->dma_sconfig.src_addr_width;
84662306a36Sopenharmony_ci		*csr = TEGRA_GPCDMA_CSR_DMA_IO2MEM_FC;
84762306a36Sopenharmony_ci		return 0;
84862306a36Sopenharmony_ci	default:
84962306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "DMA direction is not supported\n");
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	return -EINVAL;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
85662306a36Sopenharmony_citegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value,
85762306a36Sopenharmony_ci			  size_t len, unsigned long flags)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
86062306a36Sopenharmony_ci	unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count;
86162306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req;
86262306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
86362306a36Sopenharmony_ci	u32 csr, mc_seq;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if ((len & 3) || (dest & 3) || len > max_dma_count) {
86662306a36Sopenharmony_ci		dev_err(tdc2dev(tdc),
86762306a36Sopenharmony_ci			"DMA length/memory address is not supported\n");
86862306a36Sopenharmony_ci		return NULL;
86962306a36Sopenharmony_ci	}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	/* Set DMA mode to fixed pattern */
87262306a36Sopenharmony_ci	csr = TEGRA_GPCDMA_CSR_DMA_FIXED_PAT;
87362306a36Sopenharmony_ci	/* Enable once or continuous mode */
87462306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_ONCE;
87562306a36Sopenharmony_ci	/* Enable IRQ mask */
87662306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_IRQ_MASK;
87762306a36Sopenharmony_ci	/* Enable the DMA interrupt */
87862306a36Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
87962306a36Sopenharmony_ci		csr |= TEGRA_GPCDMA_CSR_IE_EOC;
88062306a36Sopenharmony_ci	/* Configure default priority weight for the channel */
88162306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	mc_seq =  tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
88462306a36Sopenharmony_ci	/* retain stream-id and clean rest */
88562306a36Sopenharmony_ci	mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* Set the address wrapping */
88862306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0,
88962306a36Sopenharmony_ci						TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
89062306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1,
89162306a36Sopenharmony_ci						TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	/* Program outstanding MC requests */
89462306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1);
89562306a36Sopenharmony_ci	/* Set burst size */
89662306a36Sopenharmony_ci	mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16;
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	dma_desc = kzalloc(struct_size(dma_desc, sg_req, 1), GFP_NOWAIT);
89962306a36Sopenharmony_ci	if (!dma_desc)
90062306a36Sopenharmony_ci		return NULL;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	dma_desc->bytes_req = len;
90362306a36Sopenharmony_ci	dma_desc->sg_count = 1;
90462306a36Sopenharmony_ci	sg_req = dma_desc->sg_req;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	sg_req[0].ch_regs.src_ptr = 0;
90762306a36Sopenharmony_ci	sg_req[0].ch_regs.dst_ptr = dest;
90862306a36Sopenharmony_ci	sg_req[0].ch_regs.high_addr_ptr =
90962306a36Sopenharmony_ci			FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
91062306a36Sopenharmony_ci	sg_req[0].ch_regs.fixed_pattern = value;
91162306a36Sopenharmony_ci	/* Word count reg takes value as (N +1) words */
91262306a36Sopenharmony_ci	sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
91362306a36Sopenharmony_ci	sg_req[0].ch_regs.csr = csr;
91462306a36Sopenharmony_ci	sg_req[0].ch_regs.mmio_seq = 0;
91562306a36Sopenharmony_ci	sg_req[0].ch_regs.mc_seq = mc_seq;
91662306a36Sopenharmony_ci	sg_req[0].len = len;
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	dma_desc->cyclic = false;
91962306a36Sopenharmony_ci	return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags);
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
92362306a36Sopenharmony_citegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest,
92462306a36Sopenharmony_ci			  dma_addr_t src, size_t len, unsigned long flags)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
92762306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req;
92862306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
92962306a36Sopenharmony_ci	unsigned int max_dma_count;
93062306a36Sopenharmony_ci	u32 csr, mc_seq;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	max_dma_count = tdc->tdma->chip_data->max_dma_count;
93362306a36Sopenharmony_ci	if ((len & 3) || (src & 3) || (dest & 3) || len > max_dma_count) {
93462306a36Sopenharmony_ci		dev_err(tdc2dev(tdc),
93562306a36Sopenharmony_ci			"DMA length/memory address is not supported\n");
93662306a36Sopenharmony_ci		return NULL;
93762306a36Sopenharmony_ci	}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	/* Set DMA mode to memory to memory transfer */
94062306a36Sopenharmony_ci	csr = TEGRA_GPCDMA_CSR_DMA_MEM2MEM;
94162306a36Sopenharmony_ci	/* Enable once or continuous mode */
94262306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_ONCE;
94362306a36Sopenharmony_ci	/* Enable IRQ mask */
94462306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_IRQ_MASK;
94562306a36Sopenharmony_ci	/* Enable the DMA interrupt */
94662306a36Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
94762306a36Sopenharmony_ci		csr |= TEGRA_GPCDMA_CSR_IE_EOC;
94862306a36Sopenharmony_ci	/* Configure default priority weight for the channel */
94962306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	mc_seq =  tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
95262306a36Sopenharmony_ci	/* retain stream-id and clean rest */
95362306a36Sopenharmony_ci	mc_seq &= (TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK) |
95462306a36Sopenharmony_ci		  (TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	/* Set the address wrapping */
95762306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0,
95862306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
95962306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1,
96062306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	/* Program outstanding MC requests */
96362306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1);
96462306a36Sopenharmony_ci	/* Set burst size */
96562306a36Sopenharmony_ci	mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci	dma_desc = kzalloc(struct_size(dma_desc, sg_req, 1), GFP_NOWAIT);
96862306a36Sopenharmony_ci	if (!dma_desc)
96962306a36Sopenharmony_ci		return NULL;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	dma_desc->bytes_req = len;
97262306a36Sopenharmony_ci	dma_desc->sg_count = 1;
97362306a36Sopenharmony_ci	sg_req = dma_desc->sg_req;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	sg_req[0].ch_regs.src_ptr = src;
97662306a36Sopenharmony_ci	sg_req[0].ch_regs.dst_ptr = dest;
97762306a36Sopenharmony_ci	sg_req[0].ch_regs.high_addr_ptr =
97862306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (src >> 32));
97962306a36Sopenharmony_ci	sg_req[0].ch_regs.high_addr_ptr |=
98062306a36Sopenharmony_ci		FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32));
98162306a36Sopenharmony_ci	/* Word count reg takes value as (N +1) words */
98262306a36Sopenharmony_ci	sg_req[0].ch_regs.wcount = ((len - 4) >> 2);
98362306a36Sopenharmony_ci	sg_req[0].ch_regs.csr = csr;
98462306a36Sopenharmony_ci	sg_req[0].ch_regs.mmio_seq = 0;
98562306a36Sopenharmony_ci	sg_req[0].ch_regs.mc_seq = mc_seq;
98662306a36Sopenharmony_ci	sg_req[0].len = len;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	dma_desc->cyclic = false;
98962306a36Sopenharmony_ci	return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags);
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
99362306a36Sopenharmony_citegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl,
99462306a36Sopenharmony_ci			unsigned int sg_len, enum dma_transfer_direction direction,
99562306a36Sopenharmony_ci			unsigned long flags, void *context)
99662306a36Sopenharmony_ci{
99762306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
99862306a36Sopenharmony_ci	unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count;
99962306a36Sopenharmony_ci	enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED;
100062306a36Sopenharmony_ci	u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0;
100162306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req;
100262306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
100362306a36Sopenharmony_ci	struct scatterlist *sg;
100462306a36Sopenharmony_ci	u32 burst_size;
100562306a36Sopenharmony_ci	unsigned int i;
100662306a36Sopenharmony_ci	int ret;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!tdc->config_init) {
100962306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "DMA channel is not configured\n");
101062306a36Sopenharmony_ci		return NULL;
101162306a36Sopenharmony_ci	}
101262306a36Sopenharmony_ci	if (sg_len < 1) {
101362306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "Invalid segment length %d\n", sg_len);
101462306a36Sopenharmony_ci		return NULL;
101562306a36Sopenharmony_ci	}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	ret = tegra_dma_sid_reserve(tdc, direction);
101862306a36Sopenharmony_ci	if (ret)
101962306a36Sopenharmony_ci		return NULL;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	ret = get_transfer_param(tdc, direction, &apb_ptr, &mmio_seq, &csr,
102262306a36Sopenharmony_ci				 &burst_size, &slave_bw);
102362306a36Sopenharmony_ci	if (ret < 0)
102462306a36Sopenharmony_ci		return NULL;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	/* Enable once or continuous mode */
102762306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_ONCE;
102862306a36Sopenharmony_ci	/* Program the slave id in requestor select */
102962306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, tdc->slave_id);
103062306a36Sopenharmony_ci	/* Enable IRQ mask */
103162306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_IRQ_MASK;
103262306a36Sopenharmony_ci	/* Configure default priority weight for the channel*/
103362306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	/* Enable the DMA interrupt */
103662306a36Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
103762306a36Sopenharmony_ci		csr |= TEGRA_GPCDMA_CSR_IE_EOC;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	mc_seq =  tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
104062306a36Sopenharmony_ci	/* retain stream-id and clean rest */
104162306a36Sopenharmony_ci	mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* Set the address wrapping on both MC and MMIO side */
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0,
104662306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
104762306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1,
104862306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
104962306a36Sopenharmony_ci	mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1);
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	/* Program 2 MC outstanding requests by default. */
105262306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1);
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	/* Setting MC burst size depending on MMIO burst size */
105562306a36Sopenharmony_ci	if (burst_size == 64)
105662306a36Sopenharmony_ci		mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16;
105762306a36Sopenharmony_ci	else
105862306a36Sopenharmony_ci		mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_2;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	dma_desc = kzalloc(struct_size(dma_desc, sg_req, sg_len), GFP_NOWAIT);
106162306a36Sopenharmony_ci	if (!dma_desc)
106262306a36Sopenharmony_ci		return NULL;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	dma_desc->sg_count = sg_len;
106562306a36Sopenharmony_ci	sg_req = dma_desc->sg_req;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	/* Make transfer requests */
106862306a36Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
106962306a36Sopenharmony_ci		u32 len;
107062306a36Sopenharmony_ci		dma_addr_t mem;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci		mem = sg_dma_address(sg);
107362306a36Sopenharmony_ci		len = sg_dma_len(sg);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci		if ((len & 3) || (mem & 3) || len > max_dma_count) {
107662306a36Sopenharmony_ci			dev_err(tdc2dev(tdc),
107762306a36Sopenharmony_ci				"DMA length/memory address is not supported\n");
107862306a36Sopenharmony_ci			kfree(dma_desc);
107962306a36Sopenharmony_ci			return NULL;
108062306a36Sopenharmony_ci		}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci		mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
108362306a36Sopenharmony_ci		dma_desc->bytes_req += len;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		if (direction == DMA_MEM_TO_DEV) {
108662306a36Sopenharmony_ci			sg_req[i].ch_regs.src_ptr = mem;
108762306a36Sopenharmony_ci			sg_req[i].ch_regs.dst_ptr = apb_ptr;
108862306a36Sopenharmony_ci			sg_req[i].ch_regs.high_addr_ptr =
108962306a36Sopenharmony_ci				FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
109062306a36Sopenharmony_ci		} else if (direction == DMA_DEV_TO_MEM) {
109162306a36Sopenharmony_ci			sg_req[i].ch_regs.src_ptr = apb_ptr;
109262306a36Sopenharmony_ci			sg_req[i].ch_regs.dst_ptr = mem;
109362306a36Sopenharmony_ci			sg_req[i].ch_regs.high_addr_ptr =
109462306a36Sopenharmony_ci				FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
109562306a36Sopenharmony_ci		}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		/*
109862306a36Sopenharmony_ci		 * Word count register takes input in words. Writing a value
109962306a36Sopenharmony_ci		 * of N into word count register means a req of (N+1) words.
110062306a36Sopenharmony_ci		 */
110162306a36Sopenharmony_ci		sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
110262306a36Sopenharmony_ci		sg_req[i].ch_regs.csr = csr;
110362306a36Sopenharmony_ci		sg_req[i].ch_regs.mmio_seq = mmio_seq;
110462306a36Sopenharmony_ci		sg_req[i].ch_regs.mc_seq = mc_seq;
110562306a36Sopenharmony_ci		sg_req[i].len = len;
110662306a36Sopenharmony_ci	}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	dma_desc->cyclic = false;
110962306a36Sopenharmony_ci	return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags);
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
111362306a36Sopenharmony_citegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len,
111462306a36Sopenharmony_ci			  size_t period_len, enum dma_transfer_direction direction,
111562306a36Sopenharmony_ci			  unsigned long flags)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED;
111862306a36Sopenharmony_ci	u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0, burst_size;
111962306a36Sopenharmony_ci	unsigned int max_dma_count, len, period_count, i;
112062306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
112162306a36Sopenharmony_ci	struct tegra_dma_desc *dma_desc;
112262306a36Sopenharmony_ci	struct tegra_dma_sg_req *sg_req;
112362306a36Sopenharmony_ci	dma_addr_t mem = buf_addr;
112462306a36Sopenharmony_ci	int ret;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (!buf_len || !period_len) {
112762306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "Invalid buffer/period len\n");
112862306a36Sopenharmony_ci		return NULL;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (!tdc->config_init) {
113262306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "DMA slave is not configured\n");
113362306a36Sopenharmony_ci		return NULL;
113462306a36Sopenharmony_ci	}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	ret = tegra_dma_sid_reserve(tdc, direction);
113762306a36Sopenharmony_ci	if (ret)
113862306a36Sopenharmony_ci		return NULL;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	/*
114162306a36Sopenharmony_ci	 * We only support cycle transfer when buf_len is multiple of
114262306a36Sopenharmony_ci	 * period_len.
114362306a36Sopenharmony_ci	 */
114462306a36Sopenharmony_ci	if (buf_len % period_len) {
114562306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "buf_len is not multiple of period_len\n");
114662306a36Sopenharmony_ci		return NULL;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	len = period_len;
115062306a36Sopenharmony_ci	max_dma_count = tdc->tdma->chip_data->max_dma_count;
115162306a36Sopenharmony_ci	if ((len & 3) || (buf_addr & 3) || len > max_dma_count) {
115262306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "Req len/mem address is not correct\n");
115362306a36Sopenharmony_ci		return NULL;
115462306a36Sopenharmony_ci	}
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci	ret = get_transfer_param(tdc, direction, &apb_ptr, &mmio_seq, &csr,
115762306a36Sopenharmony_ci				 &burst_size, &slave_bw);
115862306a36Sopenharmony_ci	if (ret < 0)
115962306a36Sopenharmony_ci		return NULL;
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	/* Enable once or continuous mode */
116262306a36Sopenharmony_ci	csr &= ~TEGRA_GPCDMA_CSR_ONCE;
116362306a36Sopenharmony_ci	/* Program the slave id in requestor select */
116462306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, tdc->slave_id);
116562306a36Sopenharmony_ci	/* Enable IRQ mask */
116662306a36Sopenharmony_ci	csr |= TEGRA_GPCDMA_CSR_IRQ_MASK;
116762306a36Sopenharmony_ci	/* Configure default priority weight for the channel*/
116862306a36Sopenharmony_ci	csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	/* Enable the DMA interrupt */
117162306a36Sopenharmony_ci	if (flags & DMA_PREP_INTERRUPT)
117262306a36Sopenharmony_ci		csr |= TEGRA_GPCDMA_CSR_IE_EOC;
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	mc_seq =  tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
117762306a36Sopenharmony_ci	/* retain stream-id and clean rest */
117862306a36Sopenharmony_ci	mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	/* Set the address wrapping on both MC and MMIO side */
118162306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0,
118262306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
118362306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1,
118462306a36Sopenharmony_ci			     TEGRA_GPCDMA_MCSEQ_WRAP_NONE);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* Program 2 MC outstanding requests by default. */
118762306a36Sopenharmony_ci	mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1);
118862306a36Sopenharmony_ci	/* Setting MC burst size depending on MMIO burst size */
118962306a36Sopenharmony_ci	if (burst_size == 64)
119062306a36Sopenharmony_ci		mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16;
119162306a36Sopenharmony_ci	else
119262306a36Sopenharmony_ci		mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_2;
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	period_count = buf_len / period_len;
119562306a36Sopenharmony_ci	dma_desc = kzalloc(struct_size(dma_desc, sg_req, period_count),
119662306a36Sopenharmony_ci			   GFP_NOWAIT);
119762306a36Sopenharmony_ci	if (!dma_desc)
119862306a36Sopenharmony_ci		return NULL;
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	dma_desc->bytes_req = buf_len;
120162306a36Sopenharmony_ci	dma_desc->sg_count = period_count;
120262306a36Sopenharmony_ci	sg_req = dma_desc->sg_req;
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	/* Split transfer equal to period size */
120562306a36Sopenharmony_ci	for (i = 0; i < period_count; i++) {
120662306a36Sopenharmony_ci		mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
120762306a36Sopenharmony_ci		if (direction == DMA_MEM_TO_DEV) {
120862306a36Sopenharmony_ci			sg_req[i].ch_regs.src_ptr = mem;
120962306a36Sopenharmony_ci			sg_req[i].ch_regs.dst_ptr = apb_ptr;
121062306a36Sopenharmony_ci			sg_req[i].ch_regs.high_addr_ptr =
121162306a36Sopenharmony_ci				FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32));
121262306a36Sopenharmony_ci		} else if (direction == DMA_DEV_TO_MEM) {
121362306a36Sopenharmony_ci			sg_req[i].ch_regs.src_ptr = apb_ptr;
121462306a36Sopenharmony_ci			sg_req[i].ch_regs.dst_ptr = mem;
121562306a36Sopenharmony_ci			sg_req[i].ch_regs.high_addr_ptr =
121662306a36Sopenharmony_ci				FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32));
121762306a36Sopenharmony_ci		}
121862306a36Sopenharmony_ci		/*
121962306a36Sopenharmony_ci		 * Word count register takes input in words. Writing a value
122062306a36Sopenharmony_ci		 * of N into word count register means a req of (N+1) words.
122162306a36Sopenharmony_ci		 */
122262306a36Sopenharmony_ci		sg_req[i].ch_regs.wcount = ((len - 4) >> 2);
122362306a36Sopenharmony_ci		sg_req[i].ch_regs.csr = csr;
122462306a36Sopenharmony_ci		sg_req[i].ch_regs.mmio_seq = mmio_seq;
122562306a36Sopenharmony_ci		sg_req[i].ch_regs.mc_seq = mc_seq;
122662306a36Sopenharmony_ci		sg_req[i].len = len;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		mem += len;
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	dma_desc->cyclic = true;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags);
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic int tegra_dma_alloc_chan_resources(struct dma_chan *dc)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
123962306a36Sopenharmony_ci	int ret;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	ret = request_irq(tdc->irq, tegra_dma_isr, 0, tdc->name, tdc);
124262306a36Sopenharmony_ci	if (ret) {
124362306a36Sopenharmony_ci		dev_err(tdc2dev(tdc), "request_irq failed for %s\n", tdc->name);
124462306a36Sopenharmony_ci		return ret;
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	dma_cookie_init(&tdc->vc.chan);
124862306a36Sopenharmony_ci	tdc->config_init = false;
124962306a36Sopenharmony_ci	return 0;
125062306a36Sopenharmony_ci}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_cistatic void tegra_dma_chan_synchronize(struct dma_chan *dc)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	synchronize_irq(tdc->irq);
125762306a36Sopenharmony_ci	vchan_synchronize(&tdc->vc);
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void tegra_dma_free_chan_resources(struct dma_chan *dc)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	dev_dbg(tdc2dev(tdc), "Freeing channel %d\n", tdc->id);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	tegra_dma_terminate_all(dc);
126762306a36Sopenharmony_ci	synchronize_irq(tdc->irq);
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	tasklet_kill(&tdc->vc.task);
127062306a36Sopenharmony_ci	tdc->config_init = false;
127162306a36Sopenharmony_ci	tdc->slave_id = -1;
127262306a36Sopenharmony_ci	tdc->sid_dir = DMA_TRANS_NONE;
127362306a36Sopenharmony_ci	free_irq(tdc->irq, tdc);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	vchan_free_chan_resources(&tdc->vc);
127662306a36Sopenharmony_ci}
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_cistatic struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
127962306a36Sopenharmony_ci					   struct of_dma *ofdma)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	struct tegra_dma *tdma = ofdma->of_dma_data;
128262306a36Sopenharmony_ci	struct tegra_dma_channel *tdc;
128362306a36Sopenharmony_ci	struct dma_chan *chan;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	chan = dma_get_any_slave_channel(&tdma->dma_dev);
128662306a36Sopenharmony_ci	if (!chan)
128762306a36Sopenharmony_ci		return NULL;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	tdc = to_tegra_dma_chan(chan);
129062306a36Sopenharmony_ci	tdc->slave_id = dma_spec->args[0];
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	return chan;
129362306a36Sopenharmony_ci}
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra186_dma_chip_data = {
129662306a36Sopenharmony_ci	.nr_channels = 32,
129762306a36Sopenharmony_ci	.channel_reg_size = SZ_64K,
129862306a36Sopenharmony_ci	.max_dma_count = SZ_1G,
129962306a36Sopenharmony_ci	.hw_support_pause = false,
130062306a36Sopenharmony_ci	.terminate = tegra_dma_stop_client,
130162306a36Sopenharmony_ci};
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra194_dma_chip_data = {
130462306a36Sopenharmony_ci	.nr_channels = 32,
130562306a36Sopenharmony_ci	.channel_reg_size = SZ_64K,
130662306a36Sopenharmony_ci	.max_dma_count = SZ_1G,
130762306a36Sopenharmony_ci	.hw_support_pause = true,
130862306a36Sopenharmony_ci	.terminate = tegra_dma_pause,
130962306a36Sopenharmony_ci};
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra234_dma_chip_data = {
131262306a36Sopenharmony_ci	.nr_channels = 32,
131362306a36Sopenharmony_ci	.channel_reg_size = SZ_64K,
131462306a36Sopenharmony_ci	.max_dma_count = SZ_1G,
131562306a36Sopenharmony_ci	.hw_support_pause = true,
131662306a36Sopenharmony_ci	.terminate = tegra_dma_pause_noerr,
131762306a36Sopenharmony_ci};
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic const struct of_device_id tegra_dma_of_match[] = {
132062306a36Sopenharmony_ci	{
132162306a36Sopenharmony_ci		.compatible = "nvidia,tegra186-gpcdma",
132262306a36Sopenharmony_ci		.data = &tegra186_dma_chip_data,
132362306a36Sopenharmony_ci	}, {
132462306a36Sopenharmony_ci		.compatible = "nvidia,tegra194-gpcdma",
132562306a36Sopenharmony_ci		.data = &tegra194_dma_chip_data,
132662306a36Sopenharmony_ci	}, {
132762306a36Sopenharmony_ci		.compatible = "nvidia,tegra234-gpcdma",
132862306a36Sopenharmony_ci		.data = &tegra234_dma_chip_data,
132962306a36Sopenharmony_ci	}, {
133062306a36Sopenharmony_ci	},
133162306a36Sopenharmony_ci};
133262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_dma_of_match);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_cistatic int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id)
133562306a36Sopenharmony_ci{
133662306a36Sopenharmony_ci	unsigned int reg_val =  tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK);
133962306a36Sopenharmony_ci	reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK);
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK, stream_id);
134262306a36Sopenharmony_ci	reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK, stream_id);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, reg_val);
134562306a36Sopenharmony_ci	return 0;
134662306a36Sopenharmony_ci}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_cistatic int tegra_dma_probe(struct platform_device *pdev)
134962306a36Sopenharmony_ci{
135062306a36Sopenharmony_ci	const struct tegra_dma_chip_data *cdata = NULL;
135162306a36Sopenharmony_ci	struct iommu_fwspec *iommu_spec;
135262306a36Sopenharmony_ci	unsigned int stream_id, i;
135362306a36Sopenharmony_ci	struct tegra_dma *tdma;
135462306a36Sopenharmony_ci	int ret;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	cdata = of_device_get_match_data(&pdev->dev);
135762306a36Sopenharmony_ci
135862306a36Sopenharmony_ci	tdma = devm_kzalloc(&pdev->dev,
135962306a36Sopenharmony_ci			    struct_size(tdma, channels, cdata->nr_channels),
136062306a36Sopenharmony_ci			    GFP_KERNEL);
136162306a36Sopenharmony_ci	if (!tdma)
136262306a36Sopenharmony_ci		return -ENOMEM;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	tdma->dev = &pdev->dev;
136562306a36Sopenharmony_ci	tdma->chip_data = cdata;
136662306a36Sopenharmony_ci	platform_set_drvdata(pdev, tdma);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	tdma->base_addr = devm_platform_ioremap_resource(pdev, 0);
136962306a36Sopenharmony_ci	if (IS_ERR(tdma->base_addr))
137062306a36Sopenharmony_ci		return PTR_ERR(tdma->base_addr);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	tdma->rst = devm_reset_control_get_exclusive(&pdev->dev, "gpcdma");
137362306a36Sopenharmony_ci	if (IS_ERR(tdma->rst)) {
137462306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(tdma->rst),
137562306a36Sopenharmony_ci			      "Missing controller reset\n");
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci	reset_control_reset(tdma->rst);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	tdma->dma_dev.dev = &pdev->dev;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	iommu_spec = dev_iommu_fwspec_get(&pdev->dev);
138262306a36Sopenharmony_ci	if (!iommu_spec) {
138362306a36Sopenharmony_ci		dev_err(&pdev->dev, "Missing iommu stream-id\n");
138462306a36Sopenharmony_ci		return -EINVAL;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci	stream_id = iommu_spec->ids[0] & 0xffff;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	ret = device_property_read_u32(&pdev->dev, "dma-channel-mask",
138962306a36Sopenharmony_ci				       &tdma->chan_mask);
139062306a36Sopenharmony_ci	if (ret) {
139162306a36Sopenharmony_ci		dev_warn(&pdev->dev,
139262306a36Sopenharmony_ci			 "Missing dma-channel-mask property, using default channel mask %#x\n",
139362306a36Sopenharmony_ci			 TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK);
139462306a36Sopenharmony_ci		tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK;
139562306a36Sopenharmony_ci	}
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	INIT_LIST_HEAD(&tdma->dma_dev.channels);
139862306a36Sopenharmony_ci	for (i = 0; i < cdata->nr_channels; i++) {
139962306a36Sopenharmony_ci		struct tegra_dma_channel *tdc = &tdma->channels[i];
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci		/* Check for channel mask */
140262306a36Sopenharmony_ci		if (!(tdma->chan_mask & BIT(i)))
140362306a36Sopenharmony_ci			continue;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci		tdc->irq = platform_get_irq(pdev, i);
140662306a36Sopenharmony_ci		if (tdc->irq < 0)
140762306a36Sopenharmony_ci			return tdc->irq;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET +
141062306a36Sopenharmony_ci					i * cdata->channel_reg_size;
141162306a36Sopenharmony_ci		snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i);
141262306a36Sopenharmony_ci		tdc->tdma = tdma;
141362306a36Sopenharmony_ci		tdc->id = i;
141462306a36Sopenharmony_ci		tdc->slave_id = -1;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci		vchan_init(&tdc->vc, &tdma->dma_dev);
141762306a36Sopenharmony_ci		tdc->vc.desc_free = tegra_dma_desc_free;
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_ci		/* program stream-id for this channel */
142062306a36Sopenharmony_ci		tegra_dma_program_sid(tdc, stream_id);
142162306a36Sopenharmony_ci		tdc->stream_id = stream_id;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask);
142562306a36Sopenharmony_ci	dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask);
142662306a36Sopenharmony_ci	dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask);
142762306a36Sopenharmony_ci	dma_cap_set(DMA_MEMSET, tdma->dma_dev.cap_mask);
142862306a36Sopenharmony_ci	dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask);
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci	/*
143162306a36Sopenharmony_ci	 * Only word aligned transfers are supported. Set the copy
143262306a36Sopenharmony_ci	 * alignment shift.
143362306a36Sopenharmony_ci	 */
143462306a36Sopenharmony_ci	tdma->dma_dev.copy_align = 2;
143562306a36Sopenharmony_ci	tdma->dma_dev.fill_align = 2;
143662306a36Sopenharmony_ci	tdma->dma_dev.device_alloc_chan_resources =
143762306a36Sopenharmony_ci					tegra_dma_alloc_chan_resources;
143862306a36Sopenharmony_ci	tdma->dma_dev.device_free_chan_resources =
143962306a36Sopenharmony_ci					tegra_dma_free_chan_resources;
144062306a36Sopenharmony_ci	tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg;
144162306a36Sopenharmony_ci	tdma->dma_dev.device_prep_dma_memcpy = tegra_dma_prep_dma_memcpy;
144262306a36Sopenharmony_ci	tdma->dma_dev.device_prep_dma_memset = tegra_dma_prep_dma_memset;
144362306a36Sopenharmony_ci	tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic;
144462306a36Sopenharmony_ci	tdma->dma_dev.device_config = tegra_dma_slave_config;
144562306a36Sopenharmony_ci	tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all;
144662306a36Sopenharmony_ci	tdma->dma_dev.device_tx_status = tegra_dma_tx_status;
144762306a36Sopenharmony_ci	tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending;
144862306a36Sopenharmony_ci	tdma->dma_dev.device_pause = tegra_dma_device_pause;
144962306a36Sopenharmony_ci	tdma->dma_dev.device_resume = tegra_dma_device_resume;
145062306a36Sopenharmony_ci	tdma->dma_dev.device_synchronize = tegra_dma_chan_synchronize;
145162306a36Sopenharmony_ci	tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	ret = dma_async_device_register(&tdma->dma_dev);
145462306a36Sopenharmony_ci	if (ret < 0) {
145562306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret,
145662306a36Sopenharmony_ci			      "GPC DMA driver registration failed\n");
145762306a36Sopenharmony_ci		return ret;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	ret = of_dma_controller_register(pdev->dev.of_node,
146162306a36Sopenharmony_ci					 tegra_dma_of_xlate, tdma);
146262306a36Sopenharmony_ci	if (ret < 0) {
146362306a36Sopenharmony_ci		dev_err_probe(&pdev->dev, ret,
146462306a36Sopenharmony_ci			      "GPC DMA OF registration failed\n");
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci		dma_async_device_unregister(&tdma->dma_dev);
146762306a36Sopenharmony_ci		return ret;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n",
147162306a36Sopenharmony_ci		 hweight_long(tdma->chan_mask));
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic int tegra_dma_remove(struct platform_device *pdev)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	struct tegra_dma *tdma = platform_get_drvdata(pdev);
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	of_dma_controller_free(pdev->dev.of_node);
148162306a36Sopenharmony_ci	dma_async_device_unregister(&tdma->dma_dev);
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	return 0;
148462306a36Sopenharmony_ci}
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_cistatic int __maybe_unused tegra_dma_pm_suspend(struct device *dev)
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	struct tegra_dma *tdma = dev_get_drvdata(dev);
148962306a36Sopenharmony_ci	unsigned int i;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
149262306a36Sopenharmony_ci		struct tegra_dma_channel *tdc = &tdma->channels[i];
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		if (!(tdma->chan_mask & BIT(i)))
149562306a36Sopenharmony_ci			continue;
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci		if (tdc->dma_desc) {
149862306a36Sopenharmony_ci			dev_err(tdma->dev, "channel %u busy\n", i);
149962306a36Sopenharmony_ci			return -EBUSY;
150062306a36Sopenharmony_ci		}
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	return 0;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_cistatic int __maybe_unused tegra_dma_pm_resume(struct device *dev)
150762306a36Sopenharmony_ci{
150862306a36Sopenharmony_ci	struct tegra_dma *tdma = dev_get_drvdata(dev);
150962306a36Sopenharmony_ci	unsigned int i;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	reset_control_reset(tdma->rst);
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	for (i = 0; i < tdma->chip_data->nr_channels; i++) {
151462306a36Sopenharmony_ci		struct tegra_dma_channel *tdc = &tdma->channels[i];
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		if (!(tdma->chan_mask & BIT(i)))
151762306a36Sopenharmony_ci			continue;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		tegra_dma_program_sid(tdc, tdc->stream_id);
152062306a36Sopenharmony_ci	}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	return 0;
152362306a36Sopenharmony_ci}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_cistatic const struct dev_pm_ops tegra_dma_dev_pm_ops = {
152662306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume)
152762306a36Sopenharmony_ci};
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic struct platform_driver tegra_dma_driver = {
153062306a36Sopenharmony_ci	.driver = {
153162306a36Sopenharmony_ci		.name	= "tegra-gpcdma",
153262306a36Sopenharmony_ci		.pm	= &tegra_dma_dev_pm_ops,
153362306a36Sopenharmony_ci		.of_match_table = tegra_dma_of_match,
153462306a36Sopenharmony_ci	},
153562306a36Sopenharmony_ci	.probe		= tegra_dma_probe,
153662306a36Sopenharmony_ci	.remove		= tegra_dma_remove,
153762306a36Sopenharmony_ci};
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cimodule_platform_driver(tegra_dma_driver);
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra GPC DMA Controller driver");
154262306a36Sopenharmony_ciMODULE_AUTHOR("Pavan Kunapuli <pkunapuli@nvidia.com>");
154362306a36Sopenharmony_ciMODULE_AUTHOR("Rajesh Gumasta <rgumasta@nvidia.com>");
154462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1545