162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/delay.h>
362306a36Sopenharmony_ci#include <linux/dmaengine.h>
462306a36Sopenharmony_ci#include <linux/dma-mapping.h>
562306a36Sopenharmony_ci#include <linux/platform_device.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/of.h>
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/of_dma.h>
1062306a36Sopenharmony_ci#include <linux/of_irq.h>
1162306a36Sopenharmony_ci#include <linux/dmapool.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/of_address.h>
1462306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1562306a36Sopenharmony_ci#include "../dmaengine.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define DESC_TYPE	27
1862306a36Sopenharmony_ci#define DESC_TYPE_HOST	0x10
1962306a36Sopenharmony_ci#define DESC_TYPE_TEARD	0x13
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define TD_DESC_IS_RX	(1 << 16)
2262306a36Sopenharmony_ci#define TD_DESC_DMA_NUM	10
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define DESC_LENGTH_BITS_NUM	21
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define DESC_TYPE_USB	(5 << 26)
2762306a36Sopenharmony_ci#define DESC_PD_COMPLETE	(1 << 31)
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/* DMA engine */
3062306a36Sopenharmony_ci#define DMA_TDFDQ	4
3162306a36Sopenharmony_ci#define DMA_TXGCR(x)	(0x800 + (x) * 0x20)
3262306a36Sopenharmony_ci#define DMA_RXGCR(x)	(0x808 + (x) * 0x20)
3362306a36Sopenharmony_ci#define RXHPCRA0		4
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define GCR_CHAN_ENABLE		(1 << 31)
3662306a36Sopenharmony_ci#define GCR_TEARDOWN		(1 << 30)
3762306a36Sopenharmony_ci#define GCR_STARV_RETRY		(1 << 24)
3862306a36Sopenharmony_ci#define GCR_DESC_TYPE_HOST	(1 << 14)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/* DMA scheduler */
4162306a36Sopenharmony_ci#define DMA_SCHED_CTRL		0
4262306a36Sopenharmony_ci#define DMA_SCHED_CTRL_EN	(1 << 31)
4362306a36Sopenharmony_ci#define DMA_SCHED_WORD(x)	((x) * 4 + 0x800)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#define SCHED_ENTRY0_CHAN(x)	((x) << 0)
4662306a36Sopenharmony_ci#define SCHED_ENTRY0_IS_RX	(1 << 7)
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define SCHED_ENTRY1_CHAN(x)	((x) << 8)
4962306a36Sopenharmony_ci#define SCHED_ENTRY1_IS_RX	(1 << 15)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define SCHED_ENTRY2_CHAN(x)	((x) << 16)
5262306a36Sopenharmony_ci#define SCHED_ENTRY2_IS_RX	(1 << 23)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define SCHED_ENTRY3_CHAN(x)	((x) << 24)
5562306a36Sopenharmony_ci#define SCHED_ENTRY3_IS_RX	(1 << 31)
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Queue manager */
5862306a36Sopenharmony_ci/* 4 KiB of memory for descriptors, 2 for each endpoint */
5962306a36Sopenharmony_ci#define ALLOC_DECS_NUM		128
6062306a36Sopenharmony_ci#define DESCS_AREAS		1
6162306a36Sopenharmony_ci#define TOTAL_DESCS_NUM		(ALLOC_DECS_NUM * DESCS_AREAS)
6262306a36Sopenharmony_ci#define QMGR_SCRATCH_SIZE	(TOTAL_DESCS_NUM * 4)
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#define QMGR_LRAM0_BASE		0x80
6562306a36Sopenharmony_ci#define QMGR_LRAM_SIZE		0x84
6662306a36Sopenharmony_ci#define QMGR_LRAM1_BASE		0x88
6762306a36Sopenharmony_ci#define QMGR_MEMBASE(x)		(0x1000 + (x) * 0x10)
6862306a36Sopenharmony_ci#define QMGR_MEMCTRL(x)		(0x1004 + (x) * 0x10)
6962306a36Sopenharmony_ci#define QMGR_MEMCTRL_IDX_SH	16
7062306a36Sopenharmony_ci#define QMGR_MEMCTRL_DESC_SH	8
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define QMGR_PEND(x)	(0x90 + (x) * 4)
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci#define QMGR_PENDING_SLOT_Q(x)	(x / 32)
7562306a36Sopenharmony_ci#define QMGR_PENDING_BIT_Q(x)	(x % 32)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define QMGR_QUEUE_A(n)	(0x2000 + (n) * 0x10)
7862306a36Sopenharmony_ci#define QMGR_QUEUE_B(n)	(0x2004 + (n) * 0x10)
7962306a36Sopenharmony_ci#define QMGR_QUEUE_C(n)	(0x2008 + (n) * 0x10)
8062306a36Sopenharmony_ci#define QMGR_QUEUE_D(n)	(0x200c + (n) * 0x10)
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* Packet Descriptor */
8362306a36Sopenharmony_ci#define PD2_ZERO_LENGTH		(1 << 19)
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cistruct cppi41_channel {
8662306a36Sopenharmony_ci	struct dma_chan chan;
8762306a36Sopenharmony_ci	struct dma_async_tx_descriptor txd;
8862306a36Sopenharmony_ci	struct cppi41_dd *cdd;
8962306a36Sopenharmony_ci	struct cppi41_desc *desc;
9062306a36Sopenharmony_ci	dma_addr_t desc_phys;
9162306a36Sopenharmony_ci	void __iomem *gcr_reg;
9262306a36Sopenharmony_ci	int is_tx;
9362306a36Sopenharmony_ci	u32 residue;
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	unsigned int q_num;
9662306a36Sopenharmony_ci	unsigned int q_comp_num;
9762306a36Sopenharmony_ci	unsigned int port_num;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	unsigned td_retry;
10062306a36Sopenharmony_ci	unsigned td_queued:1;
10162306a36Sopenharmony_ci	unsigned td_seen:1;
10262306a36Sopenharmony_ci	unsigned td_desc_seen:1;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	struct list_head node;		/* Node for pending list */
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistruct cppi41_desc {
10862306a36Sopenharmony_ci	u32 pd0;
10962306a36Sopenharmony_ci	u32 pd1;
11062306a36Sopenharmony_ci	u32 pd2;
11162306a36Sopenharmony_ci	u32 pd3;
11262306a36Sopenharmony_ci	u32 pd4;
11362306a36Sopenharmony_ci	u32 pd5;
11462306a36Sopenharmony_ci	u32 pd6;
11562306a36Sopenharmony_ci	u32 pd7;
11662306a36Sopenharmony_ci} __aligned(32);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistruct chan_queues {
11962306a36Sopenharmony_ci	u16 submit;
12062306a36Sopenharmony_ci	u16 complete;
12162306a36Sopenharmony_ci};
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistruct cppi41_dd {
12462306a36Sopenharmony_ci	struct dma_device ddev;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	void *qmgr_scratch;
12762306a36Sopenharmony_ci	dma_addr_t scratch_phys;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	struct cppi41_desc *cd;
13062306a36Sopenharmony_ci	dma_addr_t descs_phys;
13162306a36Sopenharmony_ci	u32 first_td_desc;
13262306a36Sopenharmony_ci	struct cppi41_channel *chan_busy[ALLOC_DECS_NUM];
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	void __iomem *ctrl_mem;
13562306a36Sopenharmony_ci	void __iomem *sched_mem;
13662306a36Sopenharmony_ci	void __iomem *qmgr_mem;
13762306a36Sopenharmony_ci	unsigned int irq;
13862306a36Sopenharmony_ci	const struct chan_queues *queues_rx;
13962306a36Sopenharmony_ci	const struct chan_queues *queues_tx;
14062306a36Sopenharmony_ci	struct chan_queues td_queue;
14162306a36Sopenharmony_ci	u16 first_completion_queue;
14262306a36Sopenharmony_ci	u16 qmgr_num_pend;
14362306a36Sopenharmony_ci	u32 n_chans;
14462306a36Sopenharmony_ci	u8 platform;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	struct list_head pending;	/* Pending queued transfers */
14762306a36Sopenharmony_ci	spinlock_t lock;		/* Lock for pending list */
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	/* context for suspend/resume */
15062306a36Sopenharmony_ci	unsigned int dma_tdfdq;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	bool is_suspended;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic struct chan_queues am335x_usb_queues_tx[] = {
15662306a36Sopenharmony_ci	/* USB0 ENDP 1 */
15762306a36Sopenharmony_ci	[ 0] = { .submit = 32, .complete =  93},
15862306a36Sopenharmony_ci	[ 1] = { .submit = 34, .complete =  94},
15962306a36Sopenharmony_ci	[ 2] = { .submit = 36, .complete =  95},
16062306a36Sopenharmony_ci	[ 3] = { .submit = 38, .complete =  96},
16162306a36Sopenharmony_ci	[ 4] = { .submit = 40, .complete =  97},
16262306a36Sopenharmony_ci	[ 5] = { .submit = 42, .complete =  98},
16362306a36Sopenharmony_ci	[ 6] = { .submit = 44, .complete =  99},
16462306a36Sopenharmony_ci	[ 7] = { .submit = 46, .complete = 100},
16562306a36Sopenharmony_ci	[ 8] = { .submit = 48, .complete = 101},
16662306a36Sopenharmony_ci	[ 9] = { .submit = 50, .complete = 102},
16762306a36Sopenharmony_ci	[10] = { .submit = 52, .complete = 103},
16862306a36Sopenharmony_ci	[11] = { .submit = 54, .complete = 104},
16962306a36Sopenharmony_ci	[12] = { .submit = 56, .complete = 105},
17062306a36Sopenharmony_ci	[13] = { .submit = 58, .complete = 106},
17162306a36Sopenharmony_ci	[14] = { .submit = 60, .complete = 107},
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* USB1 ENDP1 */
17462306a36Sopenharmony_ci	[15] = { .submit = 62, .complete = 125},
17562306a36Sopenharmony_ci	[16] = { .submit = 64, .complete = 126},
17662306a36Sopenharmony_ci	[17] = { .submit = 66, .complete = 127},
17762306a36Sopenharmony_ci	[18] = { .submit = 68, .complete = 128},
17862306a36Sopenharmony_ci	[19] = { .submit = 70, .complete = 129},
17962306a36Sopenharmony_ci	[20] = { .submit = 72, .complete = 130},
18062306a36Sopenharmony_ci	[21] = { .submit = 74, .complete = 131},
18162306a36Sopenharmony_ci	[22] = { .submit = 76, .complete = 132},
18262306a36Sopenharmony_ci	[23] = { .submit = 78, .complete = 133},
18362306a36Sopenharmony_ci	[24] = { .submit = 80, .complete = 134},
18462306a36Sopenharmony_ci	[25] = { .submit = 82, .complete = 135},
18562306a36Sopenharmony_ci	[26] = { .submit = 84, .complete = 136},
18662306a36Sopenharmony_ci	[27] = { .submit = 86, .complete = 137},
18762306a36Sopenharmony_ci	[28] = { .submit = 88, .complete = 138},
18862306a36Sopenharmony_ci	[29] = { .submit = 90, .complete = 139},
18962306a36Sopenharmony_ci};
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic const struct chan_queues am335x_usb_queues_rx[] = {
19262306a36Sopenharmony_ci	/* USB0 ENDP 1 */
19362306a36Sopenharmony_ci	[ 0] = { .submit =  1, .complete = 109},
19462306a36Sopenharmony_ci	[ 1] = { .submit =  2, .complete = 110},
19562306a36Sopenharmony_ci	[ 2] = { .submit =  3, .complete = 111},
19662306a36Sopenharmony_ci	[ 3] = { .submit =  4, .complete = 112},
19762306a36Sopenharmony_ci	[ 4] = { .submit =  5, .complete = 113},
19862306a36Sopenharmony_ci	[ 5] = { .submit =  6, .complete = 114},
19962306a36Sopenharmony_ci	[ 6] = { .submit =  7, .complete = 115},
20062306a36Sopenharmony_ci	[ 7] = { .submit =  8, .complete = 116},
20162306a36Sopenharmony_ci	[ 8] = { .submit =  9, .complete = 117},
20262306a36Sopenharmony_ci	[ 9] = { .submit = 10, .complete = 118},
20362306a36Sopenharmony_ci	[10] = { .submit = 11, .complete = 119},
20462306a36Sopenharmony_ci	[11] = { .submit = 12, .complete = 120},
20562306a36Sopenharmony_ci	[12] = { .submit = 13, .complete = 121},
20662306a36Sopenharmony_ci	[13] = { .submit = 14, .complete = 122},
20762306a36Sopenharmony_ci	[14] = { .submit = 15, .complete = 123},
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	/* USB1 ENDP 1 */
21062306a36Sopenharmony_ci	[15] = { .submit = 16, .complete = 141},
21162306a36Sopenharmony_ci	[16] = { .submit = 17, .complete = 142},
21262306a36Sopenharmony_ci	[17] = { .submit = 18, .complete = 143},
21362306a36Sopenharmony_ci	[18] = { .submit = 19, .complete = 144},
21462306a36Sopenharmony_ci	[19] = { .submit = 20, .complete = 145},
21562306a36Sopenharmony_ci	[20] = { .submit = 21, .complete = 146},
21662306a36Sopenharmony_ci	[21] = { .submit = 22, .complete = 147},
21762306a36Sopenharmony_ci	[22] = { .submit = 23, .complete = 148},
21862306a36Sopenharmony_ci	[23] = { .submit = 24, .complete = 149},
21962306a36Sopenharmony_ci	[24] = { .submit = 25, .complete = 150},
22062306a36Sopenharmony_ci	[25] = { .submit = 26, .complete = 151},
22162306a36Sopenharmony_ci	[26] = { .submit = 27, .complete = 152},
22262306a36Sopenharmony_ci	[27] = { .submit = 28, .complete = 153},
22362306a36Sopenharmony_ci	[28] = { .submit = 29, .complete = 154},
22462306a36Sopenharmony_ci	[29] = { .submit = 30, .complete = 155},
22562306a36Sopenharmony_ci};
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_tx[] = {
22862306a36Sopenharmony_ci	[0] = { .submit =  16, .complete = 24},
22962306a36Sopenharmony_ci	[1] = { .submit =  18, .complete = 24},
23062306a36Sopenharmony_ci	[2] = { .submit =  20, .complete = 24},
23162306a36Sopenharmony_ci	[3] = { .submit =  22, .complete = 24},
23262306a36Sopenharmony_ci};
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_rx[] = {
23562306a36Sopenharmony_ci	[0] = { .submit =  1, .complete = 26},
23662306a36Sopenharmony_ci	[1] = { .submit =  3, .complete = 26},
23762306a36Sopenharmony_ci	[2] = { .submit =  5, .complete = 26},
23862306a36Sopenharmony_ci	[3] = { .submit =  7, .complete = 26},
23962306a36Sopenharmony_ci};
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistruct cppi_glue_infos {
24262306a36Sopenharmony_ci	const struct chan_queues *queues_rx;
24362306a36Sopenharmony_ci	const struct chan_queues *queues_tx;
24462306a36Sopenharmony_ci	struct chan_queues td_queue;
24562306a36Sopenharmony_ci	u16 first_completion_queue;
24662306a36Sopenharmony_ci	u16 qmgr_num_pend;
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic struct cppi41_channel *to_cpp41_chan(struct dma_chan *c)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return container_of(c, struct cppi41_channel, chan);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct cppi41_channel *c;
25762306a36Sopenharmony_ci	u32 descs_size;
25862306a36Sopenharmony_ci	u32 desc_num;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (!((desc >= cdd->descs_phys) &&
26362306a36Sopenharmony_ci			(desc < (cdd->descs_phys + descs_size)))) {
26462306a36Sopenharmony_ci		return NULL;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc);
26862306a36Sopenharmony_ci	BUG_ON(desc_num >= ALLOC_DECS_NUM);
26962306a36Sopenharmony_ci	c = cdd->chan_busy[desc_num];
27062306a36Sopenharmony_ci	cdd->chan_busy[desc_num] = NULL;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Usecount for chan_busy[], paired with push_desc_queue() */
27362306a36Sopenharmony_ci	pm_runtime_put(cdd->ddev.dev);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	return c;
27662306a36Sopenharmony_ci}
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic void cppi_writel(u32 val, void *__iomem *mem)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	__raw_writel(val, mem);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_cistatic u32 cppi_readl(void *__iomem *mem)
28462306a36Sopenharmony_ci{
28562306a36Sopenharmony_ci	return __raw_readl(mem);
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic u32 pd_trans_len(u32 val)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1);
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	u32 desc;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num));
29862306a36Sopenharmony_ci	desc &= ~0x1f;
29962306a36Sopenharmony_ci	return desc;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic irqreturn_t cppi41_irq(int irq, void *data)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	struct cppi41_dd *cdd = data;
30562306a36Sopenharmony_ci	u16 first_completion_queue = cdd->first_completion_queue;
30662306a36Sopenharmony_ci	u16 qmgr_num_pend = cdd->qmgr_num_pend;
30762306a36Sopenharmony_ci	struct cppi41_channel *c;
30862306a36Sopenharmony_ci	int i;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	for (i = QMGR_PENDING_SLOT_Q(first_completion_queue); i < qmgr_num_pend;
31162306a36Sopenharmony_ci			i++) {
31262306a36Sopenharmony_ci		u32 val;
31362306a36Sopenharmony_ci		u32 q_num;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i));
31662306a36Sopenharmony_ci		if (i == QMGR_PENDING_SLOT_Q(first_completion_queue) && val) {
31762306a36Sopenharmony_ci			u32 mask;
31862306a36Sopenharmony_ci			/* set corresponding bit for completion Q 93 */
31962306a36Sopenharmony_ci			mask = 1 << QMGR_PENDING_BIT_Q(first_completion_queue);
32062306a36Sopenharmony_ci			/* not set all bits for queues less than Q 93 */
32162306a36Sopenharmony_ci			mask--;
32262306a36Sopenharmony_ci			/* now invert and keep only Q 93+ set */
32362306a36Sopenharmony_ci			val &= ~mask;
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		if (val)
32762306a36Sopenharmony_ci			__iormb();
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		while (val) {
33062306a36Sopenharmony_ci			u32 desc, len;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci			/*
33362306a36Sopenharmony_ci			 * This should never trigger, see the comments in
33462306a36Sopenharmony_ci			 * push_desc_queue()
33562306a36Sopenharmony_ci			 */
33662306a36Sopenharmony_ci			WARN_ON(cdd->is_suspended);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci			q_num = __fls(val);
33962306a36Sopenharmony_ci			val &= ~(1 << q_num);
34062306a36Sopenharmony_ci			q_num += 32 * i;
34162306a36Sopenharmony_ci			desc = cppi41_pop_desc(cdd, q_num);
34262306a36Sopenharmony_ci			c = desc_to_chan(cdd, desc);
34362306a36Sopenharmony_ci			if (WARN_ON(!c)) {
34462306a36Sopenharmony_ci				pr_err("%s() q %d desc %08x\n", __func__,
34562306a36Sopenharmony_ci						q_num, desc);
34662306a36Sopenharmony_ci				continue;
34762306a36Sopenharmony_ci			}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci			if (c->desc->pd2 & PD2_ZERO_LENGTH)
35062306a36Sopenharmony_ci				len = 0;
35162306a36Sopenharmony_ci			else
35262306a36Sopenharmony_ci				len = pd_trans_len(c->desc->pd0);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci			c->residue = pd_trans_len(c->desc->pd6) - len;
35562306a36Sopenharmony_ci			dma_cookie_complete(&c->txd);
35662306a36Sopenharmony_ci			dmaengine_desc_get_callback_invoke(&c->txd, NULL);
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci	return IRQ_HANDLED;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx)
36362306a36Sopenharmony_ci{
36462306a36Sopenharmony_ci	dma_cookie_t cookie;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	cookie = dma_cookie_assign(tx);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	return cookie;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int cppi41_dma_alloc_chan_resources(struct dma_chan *chan)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
37462306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
37562306a36Sopenharmony_ci	int error;
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	error = pm_runtime_get_sync(cdd->ddev.dev);
37862306a36Sopenharmony_ci	if (error < 0) {
37962306a36Sopenharmony_ci		dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n",
38062306a36Sopenharmony_ci			__func__, error);
38162306a36Sopenharmony_ci		pm_runtime_put_noidle(cdd->ddev.dev);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci		return error;
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	dma_cookie_init(chan);
38762306a36Sopenharmony_ci	dma_async_tx_descriptor_init(&c->txd, chan);
38862306a36Sopenharmony_ci	c->txd.tx_submit = cppi41_tx_submit;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (!c->is_tx)
39162306a36Sopenharmony_ci		cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	pm_runtime_mark_last_busy(cdd->ddev.dev);
39462306a36Sopenharmony_ci	pm_runtime_put_autosuspend(cdd->ddev.dev);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	return 0;
39762306a36Sopenharmony_ci}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_cistatic void cppi41_dma_free_chan_resources(struct dma_chan *chan)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
40262306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
40362306a36Sopenharmony_ci	int error;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	error = pm_runtime_get_sync(cdd->ddev.dev);
40662306a36Sopenharmony_ci	if (error < 0) {
40762306a36Sopenharmony_ci		pm_runtime_put_noidle(cdd->ddev.dev);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci		return;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	WARN_ON(!list_empty(&cdd->pending));
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	pm_runtime_mark_last_busy(cdd->ddev.dev);
41562306a36Sopenharmony_ci	pm_runtime_put_autosuspend(cdd->ddev.dev);
41662306a36Sopenharmony_ci}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_cistatic enum dma_status cppi41_dma_tx_status(struct dma_chan *chan,
41962306a36Sopenharmony_ci	dma_cookie_t cookie, struct dma_tx_state *txstate)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
42262306a36Sopenharmony_ci	enum dma_status ret;
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	dma_set_residue(txstate, c->residue);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	return ret;
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic void push_desc_queue(struct cppi41_channel *c)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
43462306a36Sopenharmony_ci	u32 desc_num;
43562306a36Sopenharmony_ci	u32 desc_phys;
43662306a36Sopenharmony_ci	u32 reg;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	c->residue = 0;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	reg = GCR_CHAN_ENABLE;
44162306a36Sopenharmony_ci	if (!c->is_tx) {
44262306a36Sopenharmony_ci		reg |= GCR_STARV_RETRY;
44362306a36Sopenharmony_ci		reg |= GCR_DESC_TYPE_HOST;
44462306a36Sopenharmony_ci		reg |= c->q_comp_num;
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	cppi_writel(reg, c->gcr_reg);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	/*
45062306a36Sopenharmony_ci	 * We don't use writel() but __raw_writel() so we have to make sure
45162306a36Sopenharmony_ci	 * that the DMA descriptor in coherent memory made to the main memory
45262306a36Sopenharmony_ci	 * before starting the dma engine.
45362306a36Sopenharmony_ci	 */
45462306a36Sopenharmony_ci	__iowmb();
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	/*
45762306a36Sopenharmony_ci	 * DMA transfers can take at least 200ms to complete with USB mass
45862306a36Sopenharmony_ci	 * storage connected. To prevent autosuspend timeouts, we must use
45962306a36Sopenharmony_ci	 * pm_runtime_get/put() when chan_busy[] is modified. This will get
46062306a36Sopenharmony_ci	 * cleared in desc_to_chan() or cppi41_stop_chan() depending on the
46162306a36Sopenharmony_ci	 * outcome of the transfer.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci	pm_runtime_get(cdd->ddev.dev);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	desc_phys = lower_32_bits(c->desc_phys);
46662306a36Sopenharmony_ci	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
46762306a36Sopenharmony_ci	WARN_ON(cdd->chan_busy[desc_num]);
46862306a36Sopenharmony_ci	cdd->chan_busy[desc_num] = c;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	reg = (sizeof(struct cppi41_desc) - 24) / 4;
47162306a36Sopenharmony_ci	reg |= desc_phys;
47262306a36Sopenharmony_ci	cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num));
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/*
47662306a36Sopenharmony_ci * Caller must hold cdd->lock to prevent push_desc_queue()
47762306a36Sopenharmony_ci * getting called out of order. We have both cppi41_dma_issue_pending()
47862306a36Sopenharmony_ci * and cppi41_runtime_resume() call this function.
47962306a36Sopenharmony_ci */
48062306a36Sopenharmony_cistatic void cppi41_run_queue(struct cppi41_dd *cdd)
48162306a36Sopenharmony_ci{
48262306a36Sopenharmony_ci	struct cppi41_channel *c, *_c;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	list_for_each_entry_safe(c, _c, &cdd->pending, node) {
48562306a36Sopenharmony_ci		push_desc_queue(c);
48662306a36Sopenharmony_ci		list_del(&c->node);
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic void cppi41_dma_issue_pending(struct dma_chan *chan)
49162306a36Sopenharmony_ci{
49262306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
49362306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
49462306a36Sopenharmony_ci	unsigned long flags;
49562306a36Sopenharmony_ci	int error;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	error = pm_runtime_get(cdd->ddev.dev);
49862306a36Sopenharmony_ci	if ((error != -EINPROGRESS) && error < 0) {
49962306a36Sopenharmony_ci		pm_runtime_put_noidle(cdd->ddev.dev);
50062306a36Sopenharmony_ci		dev_err(cdd->ddev.dev, "Failed to pm_runtime_get: %i\n",
50162306a36Sopenharmony_ci			error);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci		return;
50462306a36Sopenharmony_ci	}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	spin_lock_irqsave(&cdd->lock, flags);
50762306a36Sopenharmony_ci	list_add_tail(&c->node, &cdd->pending);
50862306a36Sopenharmony_ci	if (!cdd->is_suspended)
50962306a36Sopenharmony_ci		cppi41_run_queue(cdd);
51062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cdd->lock, flags);
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(cdd->ddev.dev);
51362306a36Sopenharmony_ci	pm_runtime_put_autosuspend(cdd->ddev.dev);
51462306a36Sopenharmony_ci}
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cistatic u32 get_host_pd0(u32 length)
51762306a36Sopenharmony_ci{
51862306a36Sopenharmony_ci	u32 reg;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	reg = DESC_TYPE_HOST << DESC_TYPE;
52162306a36Sopenharmony_ci	reg |= length;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	return reg;
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic u32 get_host_pd1(struct cppi41_channel *c)
52762306a36Sopenharmony_ci{
52862306a36Sopenharmony_ci	u32 reg;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	reg = 0;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	return reg;
53362306a36Sopenharmony_ci}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic u32 get_host_pd2(struct cppi41_channel *c)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	u32 reg;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	reg = DESC_TYPE_USB;
54062306a36Sopenharmony_ci	reg |= c->q_comp_num;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	return reg;
54362306a36Sopenharmony_ci}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_cistatic u32 get_host_pd3(u32 length)
54662306a36Sopenharmony_ci{
54762306a36Sopenharmony_ci	u32 reg;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	/* PD3 = packet size */
55062306a36Sopenharmony_ci	reg = length;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	return reg;
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic u32 get_host_pd6(u32 length)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	u32 reg;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	/* PD6 buffer size */
56062306a36Sopenharmony_ci	reg = DESC_PD_COMPLETE;
56162306a36Sopenharmony_ci	reg |= length;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return reg;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic u32 get_host_pd4_or_7(u32 addr)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	u32 reg;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	reg = addr;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	return reg;
57362306a36Sopenharmony_ci}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_cistatic u32 get_host_pd5(void)
57662306a36Sopenharmony_ci{
57762306a36Sopenharmony_ci	u32 reg;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	reg = 0;
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	return reg;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
58562306a36Sopenharmony_ci	struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len,
58662306a36Sopenharmony_ci	enum dma_transfer_direction dir, unsigned long tx_flags, void *context)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
58962306a36Sopenharmony_ci	struct dma_async_tx_descriptor *txd = NULL;
59062306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
59162306a36Sopenharmony_ci	struct cppi41_desc *d;
59262306a36Sopenharmony_ci	struct scatterlist *sg;
59362306a36Sopenharmony_ci	unsigned int i;
59462306a36Sopenharmony_ci	int error;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	error = pm_runtime_get(cdd->ddev.dev);
59762306a36Sopenharmony_ci	if (error < 0) {
59862306a36Sopenharmony_ci		pm_runtime_put_noidle(cdd->ddev.dev);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci		return NULL;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (cdd->is_suspended)
60462306a36Sopenharmony_ci		goto err_out_not_ready;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	d = c->desc;
60762306a36Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
60862306a36Sopenharmony_ci		u32 addr;
60962306a36Sopenharmony_ci		u32 len;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci		/* We need to use more than one desc once musb supports sg */
61262306a36Sopenharmony_ci		addr = lower_32_bits(sg_dma_address(sg));
61362306a36Sopenharmony_ci		len = sg_dma_len(sg);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci		d->pd0 = get_host_pd0(len);
61662306a36Sopenharmony_ci		d->pd1 = get_host_pd1(c);
61762306a36Sopenharmony_ci		d->pd2 = get_host_pd2(c);
61862306a36Sopenharmony_ci		d->pd3 = get_host_pd3(len);
61962306a36Sopenharmony_ci		d->pd4 = get_host_pd4_or_7(addr);
62062306a36Sopenharmony_ci		d->pd5 = get_host_pd5();
62162306a36Sopenharmony_ci		d->pd6 = get_host_pd6(len);
62262306a36Sopenharmony_ci		d->pd7 = get_host_pd4_or_7(addr);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		d++;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	txd = &c->txd;
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cierr_out_not_ready:
63062306a36Sopenharmony_ci	pm_runtime_mark_last_busy(cdd->ddev.dev);
63162306a36Sopenharmony_ci	pm_runtime_put_autosuspend(cdd->ddev.dev);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return txd;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_cistatic void cppi41_compute_td_desc(struct cppi41_desc *d)
63762306a36Sopenharmony_ci{
63862306a36Sopenharmony_ci	d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic int cppi41_tear_down_chan(struct cppi41_channel *c)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	struct dmaengine_result abort_result;
64462306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
64562306a36Sopenharmony_ci	struct cppi41_desc *td;
64662306a36Sopenharmony_ci	u32 reg;
64762306a36Sopenharmony_ci	u32 desc_phys;
64862306a36Sopenharmony_ci	u32 td_desc_phys;
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	td = cdd->cd;
65162306a36Sopenharmony_ci	td += cdd->first_td_desc;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	td_desc_phys = cdd->descs_phys;
65462306a36Sopenharmony_ci	td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (!c->td_queued) {
65762306a36Sopenharmony_ci		cppi41_compute_td_desc(td);
65862306a36Sopenharmony_ci		__iowmb();
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		reg = (sizeof(struct cppi41_desc) - 24) / 4;
66162306a36Sopenharmony_ci		reg |= td_desc_phys;
66262306a36Sopenharmony_ci		cppi_writel(reg, cdd->qmgr_mem +
66362306a36Sopenharmony_ci				QMGR_QUEUE_D(cdd->td_queue.submit));
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci		reg = GCR_CHAN_ENABLE;
66662306a36Sopenharmony_ci		if (!c->is_tx) {
66762306a36Sopenharmony_ci			reg |= GCR_STARV_RETRY;
66862306a36Sopenharmony_ci			reg |= GCR_DESC_TYPE_HOST;
66962306a36Sopenharmony_ci			reg |= cdd->td_queue.complete;
67062306a36Sopenharmony_ci		}
67162306a36Sopenharmony_ci		reg |= GCR_TEARDOWN;
67262306a36Sopenharmony_ci		cppi_writel(reg, c->gcr_reg);
67362306a36Sopenharmony_ci		c->td_queued = 1;
67462306a36Sopenharmony_ci		c->td_retry = 500;
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (!c->td_seen || !c->td_desc_seen) {
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci		desc_phys = cppi41_pop_desc(cdd, cdd->td_queue.complete);
68062306a36Sopenharmony_ci		if (!desc_phys && c->is_tx)
68162306a36Sopenharmony_ci			desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci		if (desc_phys == c->desc_phys) {
68462306a36Sopenharmony_ci			c->td_desc_seen = 1;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci		} else if (desc_phys == td_desc_phys) {
68762306a36Sopenharmony_ci			u32 pd0;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci			__iormb();
69062306a36Sopenharmony_ci			pd0 = td->pd0;
69162306a36Sopenharmony_ci			WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD);
69262306a36Sopenharmony_ci			WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX));
69362306a36Sopenharmony_ci			WARN_ON((pd0 & 0x1f) != c->port_num);
69462306a36Sopenharmony_ci			c->td_seen = 1;
69562306a36Sopenharmony_ci		} else if (desc_phys) {
69662306a36Sopenharmony_ci			WARN_ON_ONCE(1);
69762306a36Sopenharmony_ci		}
69862306a36Sopenharmony_ci	}
69962306a36Sopenharmony_ci	c->td_retry--;
70062306a36Sopenharmony_ci	/*
70162306a36Sopenharmony_ci	 * If the TX descriptor / channel is in use, the caller needs to poke
70262306a36Sopenharmony_ci	 * his TD bit multiple times. After that he hardware releases the
70362306a36Sopenharmony_ci	 * transfer descriptor followed by TD descriptor. Waiting seems not to
70462306a36Sopenharmony_ci	 * cause any difference.
70562306a36Sopenharmony_ci	 * RX seems to be thrown out right away. However once the TearDown
70662306a36Sopenharmony_ci	 * descriptor gets through we are done. If we have seen the transfer
70762306a36Sopenharmony_ci	 * descriptor before the TD we fetch it from enqueue, it has to be
70862306a36Sopenharmony_ci	 * there waiting for us.
70962306a36Sopenharmony_ci	 */
71062306a36Sopenharmony_ci	if (!c->td_seen && c->td_retry) {
71162306a36Sopenharmony_ci		udelay(1);
71262306a36Sopenharmony_ci		return -EAGAIN;
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	WARN_ON(!c->td_retry);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	if (!c->td_desc_seen) {
71762306a36Sopenharmony_ci		desc_phys = cppi41_pop_desc(cdd, c->q_num);
71862306a36Sopenharmony_ci		if (!desc_phys)
71962306a36Sopenharmony_ci			desc_phys = cppi41_pop_desc(cdd, c->q_comp_num);
72062306a36Sopenharmony_ci		WARN_ON(!desc_phys);
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	c->td_queued = 0;
72462306a36Sopenharmony_ci	c->td_seen = 0;
72562306a36Sopenharmony_ci	c->td_desc_seen = 0;
72662306a36Sopenharmony_ci	cppi_writel(0, c->gcr_reg);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	/* Invoke the callback to do the necessary clean-up */
72962306a36Sopenharmony_ci	abort_result.result = DMA_TRANS_ABORTED;
73062306a36Sopenharmony_ci	dma_cookie_complete(&c->txd);
73162306a36Sopenharmony_ci	dmaengine_desc_get_callback_invoke(&c->txd, &abort_result);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	return 0;
73462306a36Sopenharmony_ci}
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_cistatic int cppi41_stop_chan(struct dma_chan *chan)
73762306a36Sopenharmony_ci{
73862306a36Sopenharmony_ci	struct cppi41_channel *c = to_cpp41_chan(chan);
73962306a36Sopenharmony_ci	struct cppi41_dd *cdd = c->cdd;
74062306a36Sopenharmony_ci	u32 desc_num;
74162306a36Sopenharmony_ci	u32 desc_phys;
74262306a36Sopenharmony_ci	int ret;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	desc_phys = lower_32_bits(c->desc_phys);
74562306a36Sopenharmony_ci	desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
74662306a36Sopenharmony_ci	if (!cdd->chan_busy[desc_num]) {
74762306a36Sopenharmony_ci		struct cppi41_channel *cc, *_ct;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci		/*
75062306a36Sopenharmony_ci		 * channels might still be in the pending list if
75162306a36Sopenharmony_ci		 * cppi41_dma_issue_pending() is called after
75262306a36Sopenharmony_ci		 * cppi41_runtime_suspend() is called
75362306a36Sopenharmony_ci		 */
75462306a36Sopenharmony_ci		list_for_each_entry_safe(cc, _ct, &cdd->pending, node) {
75562306a36Sopenharmony_ci			if (cc != c)
75662306a36Sopenharmony_ci				continue;
75762306a36Sopenharmony_ci			list_del(&cc->node);
75862306a36Sopenharmony_ci			break;
75962306a36Sopenharmony_ci		}
76062306a36Sopenharmony_ci		return 0;
76162306a36Sopenharmony_ci	}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	ret = cppi41_tear_down_chan(c);
76462306a36Sopenharmony_ci	if (ret)
76562306a36Sopenharmony_ci		return ret;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	WARN_ON(!cdd->chan_busy[desc_num]);
76862306a36Sopenharmony_ci	cdd->chan_busy[desc_num] = NULL;
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	/* Usecount for chan_busy[], paired with push_desc_queue() */
77162306a36Sopenharmony_ci	pm_runtime_put(cdd->ddev.dev);
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return 0;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	struct cppi41_channel *cchan, *chans;
77962306a36Sopenharmony_ci	int i;
78062306a36Sopenharmony_ci	u32 n_chans = cdd->n_chans;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	/*
78362306a36Sopenharmony_ci	 * The channels can only be used as TX or as RX. So we add twice
78462306a36Sopenharmony_ci	 * that much dma channels because USB can only do RX or TX.
78562306a36Sopenharmony_ci	 */
78662306a36Sopenharmony_ci	n_chans *= 2;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	chans = devm_kcalloc(dev, n_chans, sizeof(*chans), GFP_KERNEL);
78962306a36Sopenharmony_ci	if (!chans)
79062306a36Sopenharmony_ci		return -ENOMEM;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	for (i = 0; i < n_chans; i++) {
79362306a36Sopenharmony_ci		cchan = &chans[i];
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		cchan->cdd = cdd;
79662306a36Sopenharmony_ci		if (i & 1) {
79762306a36Sopenharmony_ci			cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1);
79862306a36Sopenharmony_ci			cchan->is_tx = 1;
79962306a36Sopenharmony_ci		} else {
80062306a36Sopenharmony_ci			cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1);
80162306a36Sopenharmony_ci			cchan->is_tx = 0;
80262306a36Sopenharmony_ci		}
80362306a36Sopenharmony_ci		cchan->port_num = i >> 1;
80462306a36Sopenharmony_ci		cchan->desc = &cdd->cd[i];
80562306a36Sopenharmony_ci		cchan->desc_phys = cdd->descs_phys;
80662306a36Sopenharmony_ci		cchan->desc_phys += i * sizeof(struct cppi41_desc);
80762306a36Sopenharmony_ci		cchan->chan.device = &cdd->ddev;
80862306a36Sopenharmony_ci		list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci	cdd->first_td_desc = n_chans;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	return 0;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_cistatic void purge_descs(struct device *dev, struct cppi41_dd *cdd)
81662306a36Sopenharmony_ci{
81762306a36Sopenharmony_ci	unsigned int mem_decs;
81862306a36Sopenharmony_ci	int i;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc);
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	for (i = 0; i < DESCS_AREAS; i++) {
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i));
82562306a36Sopenharmony_ci		cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i));
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci		dma_free_coherent(dev, mem_decs, cdd->cd,
82862306a36Sopenharmony_ci				cdd->descs_phys);
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cistatic void disable_sched(struct cppi41_dd *cdd)
83362306a36Sopenharmony_ci{
83462306a36Sopenharmony_ci	cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_cistatic void deinit_cppi41(struct device *dev, struct cppi41_dd *cdd)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	disable_sched(cdd);
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	purge_descs(dev, cdd);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
84462306a36Sopenharmony_ci	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE);
84562306a36Sopenharmony_ci	dma_free_coherent(dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch,
84662306a36Sopenharmony_ci			cdd->scratch_phys);
84762306a36Sopenharmony_ci}
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic int init_descs(struct device *dev, struct cppi41_dd *cdd)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	unsigned int desc_size;
85262306a36Sopenharmony_ci	unsigned int mem_decs;
85362306a36Sopenharmony_ci	int i;
85462306a36Sopenharmony_ci	u32 reg;
85562306a36Sopenharmony_ci	u32 idx;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct cppi41_desc) &
85862306a36Sopenharmony_ci			(sizeof(struct cppi41_desc) - 1));
85962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32);
86062306a36Sopenharmony_ci	BUILD_BUG_ON(ALLOC_DECS_NUM < 32);
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	desc_size = sizeof(struct cppi41_desc);
86362306a36Sopenharmony_ci	mem_decs = ALLOC_DECS_NUM * desc_size;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	idx = 0;
86662306a36Sopenharmony_ci	for (i = 0; i < DESCS_AREAS; i++) {
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci		reg = idx << QMGR_MEMCTRL_IDX_SH;
86962306a36Sopenharmony_ci		reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH;
87062306a36Sopenharmony_ci		reg |= ilog2(ALLOC_DECS_NUM) - 5;
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		BUILD_BUG_ON(DESCS_AREAS != 1);
87362306a36Sopenharmony_ci		cdd->cd = dma_alloc_coherent(dev, mem_decs,
87462306a36Sopenharmony_ci				&cdd->descs_phys, GFP_KERNEL);
87562306a36Sopenharmony_ci		if (!cdd->cd)
87662306a36Sopenharmony_ci			return -ENOMEM;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
87962306a36Sopenharmony_ci		cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i));
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci		idx += ALLOC_DECS_NUM;
88262306a36Sopenharmony_ci	}
88362306a36Sopenharmony_ci	return 0;
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic void init_sched(struct cppi41_dd *cdd)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	unsigned ch;
88962306a36Sopenharmony_ci	unsigned word;
89062306a36Sopenharmony_ci	u32 reg;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	word = 0;
89362306a36Sopenharmony_ci	cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL);
89462306a36Sopenharmony_ci	for (ch = 0; ch < cdd->n_chans; ch += 2) {
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci		reg = SCHED_ENTRY0_CHAN(ch);
89762306a36Sopenharmony_ci		reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		reg |= SCHED_ENTRY2_CHAN(ch + 1);
90062306a36Sopenharmony_ci		reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX;
90162306a36Sopenharmony_ci		cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word));
90262306a36Sopenharmony_ci		word++;
90362306a36Sopenharmony_ci	}
90462306a36Sopenharmony_ci	reg = cdd->n_chans * 2 - 1;
90562306a36Sopenharmony_ci	reg |= DMA_SCHED_CTRL_EN;
90662306a36Sopenharmony_ci	cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL);
90762306a36Sopenharmony_ci}
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_cistatic int init_cppi41(struct device *dev, struct cppi41_dd *cdd)
91062306a36Sopenharmony_ci{
91162306a36Sopenharmony_ci	int ret;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1));
91462306a36Sopenharmony_ci	cdd->qmgr_scratch = dma_alloc_coherent(dev, QMGR_SCRATCH_SIZE,
91562306a36Sopenharmony_ci			&cdd->scratch_phys, GFP_KERNEL);
91662306a36Sopenharmony_ci	if (!cdd->qmgr_scratch)
91762306a36Sopenharmony_ci		return -ENOMEM;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
92062306a36Sopenharmony_ci	cppi_writel(TOTAL_DESCS_NUM, cdd->qmgr_mem + QMGR_LRAM_SIZE);
92162306a36Sopenharmony_ci	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	ret = init_descs(dev, cdd);
92462306a36Sopenharmony_ci	if (ret)
92562306a36Sopenharmony_ci		goto err_td;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ);
92862306a36Sopenharmony_ci	init_sched(cdd);
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	return 0;
93162306a36Sopenharmony_cierr_td:
93262306a36Sopenharmony_ci	deinit_cppi41(dev, cdd);
93362306a36Sopenharmony_ci	return ret;
93462306a36Sopenharmony_ci}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_cistatic struct platform_driver cpp41_dma_driver;
93762306a36Sopenharmony_ci/*
93862306a36Sopenharmony_ci * The param format is:
93962306a36Sopenharmony_ci * X Y
94062306a36Sopenharmony_ci * X: Port
94162306a36Sopenharmony_ci * Y: 0 = RX else TX
94262306a36Sopenharmony_ci */
94362306a36Sopenharmony_ci#define INFO_PORT	0
94462306a36Sopenharmony_ci#define INFO_IS_TX	1
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param)
94762306a36Sopenharmony_ci{
94862306a36Sopenharmony_ci	struct cppi41_channel *cchan;
94962306a36Sopenharmony_ci	struct cppi41_dd *cdd;
95062306a36Sopenharmony_ci	const struct chan_queues *queues;
95162306a36Sopenharmony_ci	u32 *num = param;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	if (chan->device->dev->driver != &cpp41_dma_driver.driver)
95462306a36Sopenharmony_ci		return false;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	cchan = to_cpp41_chan(chan);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	if (cchan->port_num != num[INFO_PORT])
95962306a36Sopenharmony_ci		return false;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	if (cchan->is_tx && !num[INFO_IS_TX])
96262306a36Sopenharmony_ci		return false;
96362306a36Sopenharmony_ci	cdd = cchan->cdd;
96462306a36Sopenharmony_ci	if (cchan->is_tx)
96562306a36Sopenharmony_ci		queues = cdd->queues_tx;
96662306a36Sopenharmony_ci	else
96762306a36Sopenharmony_ci		queues = cdd->queues_rx;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) !=
97062306a36Sopenharmony_ci		     ARRAY_SIZE(am335x_usb_queues_tx));
97162306a36Sopenharmony_ci	if (WARN_ON(cchan->port_num >= ARRAY_SIZE(am335x_usb_queues_rx)))
97262306a36Sopenharmony_ci		return false;
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	cchan->q_num = queues[cchan->port_num].submit;
97562306a36Sopenharmony_ci	cchan->q_comp_num = queues[cchan->port_num].complete;
97662306a36Sopenharmony_ci	return true;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic struct of_dma_filter_info cpp41_dma_info = {
98062306a36Sopenharmony_ci	.filter_fn = cpp41_dma_filter_fn,
98162306a36Sopenharmony_ci};
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_cistatic struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec,
98462306a36Sopenharmony_ci		struct of_dma *ofdma)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	int count = dma_spec->args_count;
98762306a36Sopenharmony_ci	struct of_dma_filter_info *info = ofdma->of_dma_data;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	if (!info || !info->filter_fn)
99062306a36Sopenharmony_ci		return NULL;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	if (count != 2)
99362306a36Sopenharmony_ci		return NULL;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	return dma_request_channel(info->dma_cap, info->filter_fn,
99662306a36Sopenharmony_ci			&dma_spec->args[0]);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic const struct cppi_glue_infos am335x_usb_infos = {
100062306a36Sopenharmony_ci	.queues_rx = am335x_usb_queues_rx,
100162306a36Sopenharmony_ci	.queues_tx = am335x_usb_queues_tx,
100262306a36Sopenharmony_ci	.td_queue = { .submit = 31, .complete = 0 },
100362306a36Sopenharmony_ci	.first_completion_queue = 93,
100462306a36Sopenharmony_ci	.qmgr_num_pend = 5,
100562306a36Sopenharmony_ci};
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_cistatic const struct cppi_glue_infos da8xx_usb_infos = {
100862306a36Sopenharmony_ci	.queues_rx = da8xx_usb_queues_rx,
100962306a36Sopenharmony_ci	.queues_tx = da8xx_usb_queues_tx,
101062306a36Sopenharmony_ci	.td_queue = { .submit = 31, .complete = 0 },
101162306a36Sopenharmony_ci	.first_completion_queue = 24,
101262306a36Sopenharmony_ci	.qmgr_num_pend = 2,
101362306a36Sopenharmony_ci};
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic const struct of_device_id cppi41_dma_ids[] = {
101662306a36Sopenharmony_ci	{ .compatible = "ti,am3359-cppi41", .data = &am335x_usb_infos},
101762306a36Sopenharmony_ci	{ .compatible = "ti,da830-cppi41", .data = &da8xx_usb_infos},
101862306a36Sopenharmony_ci	{},
101962306a36Sopenharmony_ci};
102062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cppi41_dma_ids);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic const struct cppi_glue_infos *get_glue_info(struct device *dev)
102362306a36Sopenharmony_ci{
102462306a36Sopenharmony_ci	const struct of_device_id *of_id;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	of_id = of_match_node(cppi41_dma_ids, dev->of_node);
102762306a36Sopenharmony_ci	if (!of_id)
102862306a36Sopenharmony_ci		return NULL;
102962306a36Sopenharmony_ci	return of_id->data;
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci#define CPPI41_DMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
103362306a36Sopenharmony_ci				BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
103462306a36Sopenharmony_ci				BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
103562306a36Sopenharmony_ci				BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int cppi41_dma_probe(struct platform_device *pdev)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct cppi41_dd *cdd;
104062306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
104162306a36Sopenharmony_ci	const struct cppi_glue_infos *glue_info;
104262306a36Sopenharmony_ci	int index;
104362306a36Sopenharmony_ci	int irq;
104462306a36Sopenharmony_ci	int ret;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	glue_info = get_glue_info(dev);
104762306a36Sopenharmony_ci	if (!glue_info)
104862306a36Sopenharmony_ci		return -EINVAL;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	cdd = devm_kzalloc(&pdev->dev, sizeof(*cdd), GFP_KERNEL);
105162306a36Sopenharmony_ci	if (!cdd)
105262306a36Sopenharmony_ci		return -ENOMEM;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask);
105562306a36Sopenharmony_ci	cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources;
105662306a36Sopenharmony_ci	cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources;
105762306a36Sopenharmony_ci	cdd->ddev.device_tx_status = cppi41_dma_tx_status;
105862306a36Sopenharmony_ci	cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
105962306a36Sopenharmony_ci	cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
106062306a36Sopenharmony_ci	cdd->ddev.device_terminate_all = cppi41_stop_chan;
106162306a36Sopenharmony_ci	cdd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
106262306a36Sopenharmony_ci	cdd->ddev.src_addr_widths = CPPI41_DMA_BUSWIDTHS;
106362306a36Sopenharmony_ci	cdd->ddev.dst_addr_widths = CPPI41_DMA_BUSWIDTHS;
106462306a36Sopenharmony_ci	cdd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
106562306a36Sopenharmony_ci	cdd->ddev.dev = dev;
106662306a36Sopenharmony_ci	INIT_LIST_HEAD(&cdd->ddev.channels);
106762306a36Sopenharmony_ci	cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	index = of_property_match_string(dev->of_node,
107062306a36Sopenharmony_ci					 "reg-names", "controller");
107162306a36Sopenharmony_ci	if (index < 0)
107262306a36Sopenharmony_ci		return index;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	cdd->ctrl_mem = devm_platform_ioremap_resource(pdev, index);
107562306a36Sopenharmony_ci	if (IS_ERR(cdd->ctrl_mem))
107662306a36Sopenharmony_ci		return PTR_ERR(cdd->ctrl_mem);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	cdd->sched_mem = devm_platform_ioremap_resource(pdev, index + 1);
107962306a36Sopenharmony_ci	if (IS_ERR(cdd->sched_mem))
108062306a36Sopenharmony_ci		return PTR_ERR(cdd->sched_mem);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	cdd->qmgr_mem = devm_platform_ioremap_resource(pdev, index + 2);
108362306a36Sopenharmony_ci	if (IS_ERR(cdd->qmgr_mem))
108462306a36Sopenharmony_ci		return PTR_ERR(cdd->qmgr_mem);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	spin_lock_init(&cdd->lock);
108762306a36Sopenharmony_ci	INIT_LIST_HEAD(&cdd->pending);
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	platform_set_drvdata(pdev, cdd);
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_ci	pm_runtime_enable(dev);
109262306a36Sopenharmony_ci	pm_runtime_set_autosuspend_delay(dev, 100);
109362306a36Sopenharmony_ci	pm_runtime_use_autosuspend(dev);
109462306a36Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
109562306a36Sopenharmony_ci	if (ret < 0)
109662306a36Sopenharmony_ci		goto err_get_sync;
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci	cdd->queues_rx = glue_info->queues_rx;
109962306a36Sopenharmony_ci	cdd->queues_tx = glue_info->queues_tx;
110062306a36Sopenharmony_ci	cdd->td_queue = glue_info->td_queue;
110162306a36Sopenharmony_ci	cdd->qmgr_num_pend = glue_info->qmgr_num_pend;
110262306a36Sopenharmony_ci	cdd->first_completion_queue = glue_info->first_completion_queue;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/* Parse new and deprecated dma-channels properties */
110562306a36Sopenharmony_ci	ret = of_property_read_u32(dev->of_node,
110662306a36Sopenharmony_ci				   "dma-channels", &cdd->n_chans);
110762306a36Sopenharmony_ci	if (ret)
110862306a36Sopenharmony_ci		ret = of_property_read_u32(dev->of_node,
110962306a36Sopenharmony_ci					   "#dma-channels", &cdd->n_chans);
111062306a36Sopenharmony_ci	if (ret)
111162306a36Sopenharmony_ci		goto err_get_n_chans;
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	ret = init_cppi41(dev, cdd);
111462306a36Sopenharmony_ci	if (ret)
111562306a36Sopenharmony_ci		goto err_init_cppi;
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	ret = cppi41_add_chans(dev, cdd);
111862306a36Sopenharmony_ci	if (ret)
111962306a36Sopenharmony_ci		goto err_chans;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	irq = irq_of_parse_and_map(dev->of_node, 0);
112262306a36Sopenharmony_ci	if (!irq) {
112362306a36Sopenharmony_ci		ret = -EINVAL;
112462306a36Sopenharmony_ci		goto err_chans;
112562306a36Sopenharmony_ci	}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, irq, cppi41_irq, IRQF_SHARED,
112862306a36Sopenharmony_ci			dev_name(dev), cdd);
112962306a36Sopenharmony_ci	if (ret)
113062306a36Sopenharmony_ci		goto err_chans;
113162306a36Sopenharmony_ci	cdd->irq = irq;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	ret = dma_async_device_register(&cdd->ddev);
113462306a36Sopenharmony_ci	if (ret)
113562306a36Sopenharmony_ci		goto err_chans;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	ret = of_dma_controller_register(dev->of_node,
113862306a36Sopenharmony_ci			cppi41_dma_xlate, &cpp41_dma_info);
113962306a36Sopenharmony_ci	if (ret)
114062306a36Sopenharmony_ci		goto err_of;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	pm_runtime_mark_last_busy(dev);
114362306a36Sopenharmony_ci	pm_runtime_put_autosuspend(dev);
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci	return 0;
114662306a36Sopenharmony_cierr_of:
114762306a36Sopenharmony_ci	dma_async_device_unregister(&cdd->ddev);
114862306a36Sopenharmony_cierr_chans:
114962306a36Sopenharmony_ci	deinit_cppi41(dev, cdd);
115062306a36Sopenharmony_cierr_init_cppi:
115162306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(dev);
115262306a36Sopenharmony_cierr_get_n_chans:
115362306a36Sopenharmony_cierr_get_sync:
115462306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
115562306a36Sopenharmony_ci	pm_runtime_disable(dev);
115662306a36Sopenharmony_ci	return ret;
115762306a36Sopenharmony_ci}
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_cistatic int cppi41_dma_remove(struct platform_device *pdev)
116062306a36Sopenharmony_ci{
116162306a36Sopenharmony_ci	struct cppi41_dd *cdd = platform_get_drvdata(pdev);
116262306a36Sopenharmony_ci	int error;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	error = pm_runtime_get_sync(&pdev->dev);
116562306a36Sopenharmony_ci	if (error < 0)
116662306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s could not pm_runtime_get: %i\n",
116762306a36Sopenharmony_ci			__func__, error);
116862306a36Sopenharmony_ci	of_dma_controller_free(pdev->dev.of_node);
116962306a36Sopenharmony_ci	dma_async_device_unregister(&cdd->ddev);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci	devm_free_irq(&pdev->dev, cdd->irq, cdd);
117262306a36Sopenharmony_ci	deinit_cppi41(&pdev->dev, cdd);
117362306a36Sopenharmony_ci	pm_runtime_dont_use_autosuspend(&pdev->dev);
117462306a36Sopenharmony_ci	pm_runtime_put_sync(&pdev->dev);
117562306a36Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
117662306a36Sopenharmony_ci	return 0;
117762306a36Sopenharmony_ci}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_cistatic int __maybe_unused cppi41_suspend(struct device *dev)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct cppi41_dd *cdd = dev_get_drvdata(dev);
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	cdd->dma_tdfdq = cppi_readl(cdd->ctrl_mem + DMA_TDFDQ);
118462306a36Sopenharmony_ci	disable_sched(cdd);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	return 0;
118762306a36Sopenharmony_ci}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_cistatic int __maybe_unused cppi41_resume(struct device *dev)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	struct cppi41_dd *cdd = dev_get_drvdata(dev);
119262306a36Sopenharmony_ci	struct cppi41_channel *c;
119362306a36Sopenharmony_ci	int i;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	for (i = 0; i < DESCS_AREAS; i++)
119662306a36Sopenharmony_ci		cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i));
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	list_for_each_entry(c, &cdd->ddev.channels, chan.device_node)
119962306a36Sopenharmony_ci		if (!c->is_tx)
120062306a36Sopenharmony_ci			cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0);
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	init_sched(cdd);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	cppi_writel(cdd->dma_tdfdq, cdd->ctrl_mem + DMA_TDFDQ);
120562306a36Sopenharmony_ci	cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE);
120662306a36Sopenharmony_ci	cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE);
120762306a36Sopenharmony_ci	cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	return 0;
121062306a36Sopenharmony_ci}
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_cistatic int __maybe_unused cppi41_runtime_suspend(struct device *dev)
121362306a36Sopenharmony_ci{
121462306a36Sopenharmony_ci	struct cppi41_dd *cdd = dev_get_drvdata(dev);
121562306a36Sopenharmony_ci	unsigned long flags;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	spin_lock_irqsave(&cdd->lock, flags);
121862306a36Sopenharmony_ci	cdd->is_suspended = true;
121962306a36Sopenharmony_ci	WARN_ON(!list_empty(&cdd->pending));
122062306a36Sopenharmony_ci	spin_unlock_irqrestore(&cdd->lock, flags);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	return 0;
122362306a36Sopenharmony_ci}
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_cistatic int __maybe_unused cppi41_runtime_resume(struct device *dev)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	struct cppi41_dd *cdd = dev_get_drvdata(dev);
122862306a36Sopenharmony_ci	unsigned long flags;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	spin_lock_irqsave(&cdd->lock, flags);
123162306a36Sopenharmony_ci	cdd->is_suspended = false;
123262306a36Sopenharmony_ci	cppi41_run_queue(cdd);
123362306a36Sopenharmony_ci	spin_unlock_irqrestore(&cdd->lock, flags);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	return 0;
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_cistatic const struct dev_pm_ops cppi41_pm_ops = {
123962306a36Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(cppi41_suspend, cppi41_resume)
124062306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(cppi41_runtime_suspend,
124162306a36Sopenharmony_ci			   cppi41_runtime_resume,
124262306a36Sopenharmony_ci			   NULL)
124362306a36Sopenharmony_ci};
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic struct platform_driver cpp41_dma_driver = {
124662306a36Sopenharmony_ci	.probe  = cppi41_dma_probe,
124762306a36Sopenharmony_ci	.remove = cppi41_dma_remove,
124862306a36Sopenharmony_ci	.driver = {
124962306a36Sopenharmony_ci		.name = "cppi41-dma-engine",
125062306a36Sopenharmony_ci		.pm = &cppi41_pm_ops,
125162306a36Sopenharmony_ci		.of_match_table = of_match_ptr(cppi41_dma_ids),
125262306a36Sopenharmony_ci	},
125362306a36Sopenharmony_ci};
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cimodule_platform_driver(cpp41_dma_driver);
125662306a36Sopenharmony_ciMODULE_LICENSE("GPL");
125762306a36Sopenharmony_ciMODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
1258