xref: /kernel/linux/linux-6.6/drivers/dma/ti/edma.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TI EDMA DMA engine driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2012 Texas Instruments
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/dmaengine.h>
962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1062306a36Sopenharmony_ci#include <linux/bitmap.h>
1162306a36Sopenharmony_ci#include <linux/err.h>
1262306a36Sopenharmony_ci#include <linux/init.h>
1362306a36Sopenharmony_ci#include <linux/interrupt.h>
1462306a36Sopenharmony_ci#include <linux/list.h>
1562306a36Sopenharmony_ci#include <linux/module.h>
1662306a36Sopenharmony_ci#include <linux/platform_device.h>
1762306a36Sopenharmony_ci#include <linux/slab.h>
1862306a36Sopenharmony_ci#include <linux/spinlock.h>
1962306a36Sopenharmony_ci#include <linux/of.h>
2062306a36Sopenharmony_ci#include <linux/of_dma.h>
2162306a36Sopenharmony_ci#include <linux/of_irq.h>
2262306a36Sopenharmony_ci#include <linux/of_address.h>
2362306a36Sopenharmony_ci#include <linux/pm_runtime.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/platform_data/edma.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include "../dmaengine.h"
2862306a36Sopenharmony_ci#include "../virt-dma.h"
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Offsets matching "struct edmacc_param" */
3162306a36Sopenharmony_ci#define PARM_OPT		0x00
3262306a36Sopenharmony_ci#define PARM_SRC		0x04
3362306a36Sopenharmony_ci#define PARM_A_B_CNT		0x08
3462306a36Sopenharmony_ci#define PARM_DST		0x0c
3562306a36Sopenharmony_ci#define PARM_SRC_DST_BIDX	0x10
3662306a36Sopenharmony_ci#define PARM_LINK_BCNTRLD	0x14
3762306a36Sopenharmony_ci#define PARM_SRC_DST_CIDX	0x18
3862306a36Sopenharmony_ci#define PARM_CCNT		0x1c
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define PARM_SIZE		0x20
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* Offsets for EDMA CC global channel registers and their shadows */
4362306a36Sopenharmony_ci#define SH_ER			0x00	/* 64 bits */
4462306a36Sopenharmony_ci#define SH_ECR			0x08	/* 64 bits */
4562306a36Sopenharmony_ci#define SH_ESR			0x10	/* 64 bits */
4662306a36Sopenharmony_ci#define SH_CER			0x18	/* 64 bits */
4762306a36Sopenharmony_ci#define SH_EER			0x20	/* 64 bits */
4862306a36Sopenharmony_ci#define SH_EECR			0x28	/* 64 bits */
4962306a36Sopenharmony_ci#define SH_EESR			0x30	/* 64 bits */
5062306a36Sopenharmony_ci#define SH_SER			0x38	/* 64 bits */
5162306a36Sopenharmony_ci#define SH_SECR			0x40	/* 64 bits */
5262306a36Sopenharmony_ci#define SH_IER			0x50	/* 64 bits */
5362306a36Sopenharmony_ci#define SH_IECR			0x58	/* 64 bits */
5462306a36Sopenharmony_ci#define SH_IESR			0x60	/* 64 bits */
5562306a36Sopenharmony_ci#define SH_IPR			0x68	/* 64 bits */
5662306a36Sopenharmony_ci#define SH_ICR			0x70	/* 64 bits */
5762306a36Sopenharmony_ci#define SH_IEVAL		0x78
5862306a36Sopenharmony_ci#define SH_QER			0x80
5962306a36Sopenharmony_ci#define SH_QEER			0x84
6062306a36Sopenharmony_ci#define SH_QEECR		0x88
6162306a36Sopenharmony_ci#define SH_QEESR		0x8c
6262306a36Sopenharmony_ci#define SH_QSER			0x90
6362306a36Sopenharmony_ci#define SH_QSECR		0x94
6462306a36Sopenharmony_ci#define SH_SIZE			0x200
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/* Offsets for EDMA CC global registers */
6762306a36Sopenharmony_ci#define EDMA_REV		0x0000
6862306a36Sopenharmony_ci#define EDMA_CCCFG		0x0004
6962306a36Sopenharmony_ci#define EDMA_QCHMAP		0x0200	/* 8 registers */
7062306a36Sopenharmony_ci#define EDMA_DMAQNUM		0x0240	/* 8 registers (4 on OMAP-L1xx) */
7162306a36Sopenharmony_ci#define EDMA_QDMAQNUM		0x0260
7262306a36Sopenharmony_ci#define EDMA_QUETCMAP		0x0280
7362306a36Sopenharmony_ci#define EDMA_QUEPRI		0x0284
7462306a36Sopenharmony_ci#define EDMA_EMR		0x0300	/* 64 bits */
7562306a36Sopenharmony_ci#define EDMA_EMCR		0x0308	/* 64 bits */
7662306a36Sopenharmony_ci#define EDMA_QEMR		0x0310
7762306a36Sopenharmony_ci#define EDMA_QEMCR		0x0314
7862306a36Sopenharmony_ci#define EDMA_CCERR		0x0318
7962306a36Sopenharmony_ci#define EDMA_CCERRCLR		0x031c
8062306a36Sopenharmony_ci#define EDMA_EEVAL		0x0320
8162306a36Sopenharmony_ci#define EDMA_DRAE		0x0340	/* 4 x 64 bits*/
8262306a36Sopenharmony_ci#define EDMA_QRAE		0x0380	/* 4 registers */
8362306a36Sopenharmony_ci#define EDMA_QUEEVTENTRY	0x0400	/* 2 x 16 registers */
8462306a36Sopenharmony_ci#define EDMA_QSTAT		0x0600	/* 2 registers */
8562306a36Sopenharmony_ci#define EDMA_QWMTHRA		0x0620
8662306a36Sopenharmony_ci#define EDMA_QWMTHRB		0x0624
8762306a36Sopenharmony_ci#define EDMA_CCSTAT		0x0640
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define EDMA_M			0x1000	/* global channel registers */
9062306a36Sopenharmony_ci#define EDMA_ECR		0x1008
9162306a36Sopenharmony_ci#define EDMA_ECRH		0x100C
9262306a36Sopenharmony_ci#define EDMA_SHADOW0		0x2000	/* 4 shadow regions */
9362306a36Sopenharmony_ci#define EDMA_PARM		0x4000	/* PaRAM entries */
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci#define PARM_OFFSET(param_no)	(EDMA_PARM + ((param_no) << 5))
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define EDMA_DCHMAP		0x0100  /* 64 registers */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* CCCFG register */
10062306a36Sopenharmony_ci#define GET_NUM_DMACH(x)	(x & 0x7) /* bits 0-2 */
10162306a36Sopenharmony_ci#define GET_NUM_QDMACH(x)	((x & 0x70) >> 4) /* bits 4-6 */
10262306a36Sopenharmony_ci#define GET_NUM_PAENTRY(x)	((x & 0x7000) >> 12) /* bits 12-14 */
10362306a36Sopenharmony_ci#define GET_NUM_EVQUE(x)	((x & 0x70000) >> 16) /* bits 16-18 */
10462306a36Sopenharmony_ci#define GET_NUM_REGN(x)		((x & 0x300000) >> 20) /* bits 20-21 */
10562306a36Sopenharmony_ci#define CHMAP_EXIST		BIT(24)
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci/* CCSTAT register */
10862306a36Sopenharmony_ci#define EDMA_CCSTAT_ACTV	BIT(4)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * Max of 20 segments per channel to conserve PaRAM slots
11262306a36Sopenharmony_ci * Also note that MAX_NR_SG should be at least the no.of periods
11362306a36Sopenharmony_ci * that are required for ASoC, otherwise DMA prep calls will
11462306a36Sopenharmony_ci * fail. Today davinci-pcm is the only user of this driver and
11562306a36Sopenharmony_ci * requires at least 17 slots, so we setup the default to 20.
11662306a36Sopenharmony_ci */
11762306a36Sopenharmony_ci#define MAX_NR_SG		20
11862306a36Sopenharmony_ci#define EDMA_MAX_SLOTS		MAX_NR_SG
11962306a36Sopenharmony_ci#define EDMA_DESCRIPTORS	16
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define EDMA_CHANNEL_ANY		-1	/* for edma_alloc_channel() */
12262306a36Sopenharmony_ci#define EDMA_SLOT_ANY			-1	/* for edma_alloc_slot() */
12362306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_ANY		 1001
12462306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_FIXED_EXACT	 1002
12562306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/*
12862306a36Sopenharmony_ci * 64bit array registers are split into two 32bit registers:
12962306a36Sopenharmony_ci * reg0: channel/event 0-31
13062306a36Sopenharmony_ci * reg1: channel/event 32-63
13162306a36Sopenharmony_ci *
13262306a36Sopenharmony_ci * bit 5 in the channel number tells the array index (0/1)
13362306a36Sopenharmony_ci * bit 0-4 (0x1f) is the bit offset within the register
13462306a36Sopenharmony_ci */
13562306a36Sopenharmony_ci#define EDMA_REG_ARRAY_INDEX(channel)	((channel) >> 5)
13662306a36Sopenharmony_ci#define EDMA_CHANNEL_BIT(channel)	(BIT((channel) & 0x1f))
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/* PaRAM slots are laid out like this */
13962306a36Sopenharmony_cistruct edmacc_param {
14062306a36Sopenharmony_ci	u32 opt;
14162306a36Sopenharmony_ci	u32 src;
14262306a36Sopenharmony_ci	u32 a_b_cnt;
14362306a36Sopenharmony_ci	u32 dst;
14462306a36Sopenharmony_ci	u32 src_dst_bidx;
14562306a36Sopenharmony_ci	u32 link_bcntrld;
14662306a36Sopenharmony_ci	u32 src_dst_cidx;
14762306a36Sopenharmony_ci	u32 ccnt;
14862306a36Sopenharmony_ci} __packed;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/* fields in edmacc_param.opt */
15162306a36Sopenharmony_ci#define SAM		BIT(0)
15262306a36Sopenharmony_ci#define DAM		BIT(1)
15362306a36Sopenharmony_ci#define SYNCDIM		BIT(2)
15462306a36Sopenharmony_ci#define STATIC		BIT(3)
15562306a36Sopenharmony_ci#define EDMA_FWID	(0x07 << 8)
15662306a36Sopenharmony_ci#define TCCMODE		BIT(11)
15762306a36Sopenharmony_ci#define EDMA_TCC(t)	((t) << 12)
15862306a36Sopenharmony_ci#define TCINTEN		BIT(20)
15962306a36Sopenharmony_ci#define ITCINTEN	BIT(21)
16062306a36Sopenharmony_ci#define TCCHEN		BIT(22)
16162306a36Sopenharmony_ci#define ITCCHEN		BIT(23)
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct edma_pset {
16462306a36Sopenharmony_ci	u32				len;
16562306a36Sopenharmony_ci	dma_addr_t			addr;
16662306a36Sopenharmony_ci	struct edmacc_param		param;
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct edma_desc {
17062306a36Sopenharmony_ci	struct virt_dma_desc		vdesc;
17162306a36Sopenharmony_ci	struct list_head		node;
17262306a36Sopenharmony_ci	enum dma_transfer_direction	direction;
17362306a36Sopenharmony_ci	int				cyclic;
17462306a36Sopenharmony_ci	bool				polled;
17562306a36Sopenharmony_ci	int				absync;
17662306a36Sopenharmony_ci	int				pset_nr;
17762306a36Sopenharmony_ci	struct edma_chan		*echan;
17862306a36Sopenharmony_ci	int				processed;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/*
18162306a36Sopenharmony_ci	 * The following 4 elements are used for residue accounting.
18262306a36Sopenharmony_ci	 *
18362306a36Sopenharmony_ci	 * - processed_stat: the number of SG elements we have traversed
18462306a36Sopenharmony_ci	 * so far to cover accounting. This is updated directly to processed
18562306a36Sopenharmony_ci	 * during edma_callback and is always <= processed, because processed
18662306a36Sopenharmony_ci	 * refers to the number of pending transfer (programmed to EDMA
18762306a36Sopenharmony_ci	 * controller), where as processed_stat tracks number of transfers
18862306a36Sopenharmony_ci	 * accounted for so far.
18962306a36Sopenharmony_ci	 *
19062306a36Sopenharmony_ci	 * - residue: The amount of bytes we have left to transfer for this desc
19162306a36Sopenharmony_ci	 *
19262306a36Sopenharmony_ci	 * - residue_stat: The residue in bytes of data we have covered
19362306a36Sopenharmony_ci	 * so far for accounting. This is updated directly to residue
19462306a36Sopenharmony_ci	 * during callbacks to keep it current.
19562306a36Sopenharmony_ci	 *
19662306a36Sopenharmony_ci	 * - sg_len: Tracks the length of the current intermediate transfer,
19762306a36Sopenharmony_ci	 * this is required to update the residue during intermediate transfer
19862306a36Sopenharmony_ci	 * completion callback.
19962306a36Sopenharmony_ci	 */
20062306a36Sopenharmony_ci	int				processed_stat;
20162306a36Sopenharmony_ci	u32				sg_len;
20262306a36Sopenharmony_ci	u32				residue;
20362306a36Sopenharmony_ci	u32				residue_stat;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	struct edma_pset		pset[];
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistruct edma_cc;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistruct edma_tc {
21162306a36Sopenharmony_ci	struct device_node		*node;
21262306a36Sopenharmony_ci	u16				id;
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistruct edma_chan {
21662306a36Sopenharmony_ci	struct virt_dma_chan		vchan;
21762306a36Sopenharmony_ci	struct list_head		node;
21862306a36Sopenharmony_ci	struct edma_desc		*edesc;
21962306a36Sopenharmony_ci	struct edma_cc			*ecc;
22062306a36Sopenharmony_ci	struct edma_tc			*tc;
22162306a36Sopenharmony_ci	int				ch_num;
22262306a36Sopenharmony_ci	bool				alloced;
22362306a36Sopenharmony_ci	bool				hw_triggered;
22462306a36Sopenharmony_ci	int				slot[EDMA_MAX_SLOTS];
22562306a36Sopenharmony_ci	int				missed;
22662306a36Sopenharmony_ci	struct dma_slave_config		cfg;
22762306a36Sopenharmony_ci};
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistruct edma_cc {
23062306a36Sopenharmony_ci	struct device			*dev;
23162306a36Sopenharmony_ci	struct edma_soc_info		*info;
23262306a36Sopenharmony_ci	void __iomem			*base;
23362306a36Sopenharmony_ci	int				id;
23462306a36Sopenharmony_ci	bool				legacy_mode;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	/* eDMA3 resource information */
23762306a36Sopenharmony_ci	unsigned			num_channels;
23862306a36Sopenharmony_ci	unsigned			num_qchannels;
23962306a36Sopenharmony_ci	unsigned			num_region;
24062306a36Sopenharmony_ci	unsigned			num_slots;
24162306a36Sopenharmony_ci	unsigned			num_tc;
24262306a36Sopenharmony_ci	bool				chmap_exist;
24362306a36Sopenharmony_ci	enum dma_event_q		default_queue;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	unsigned int			ccint;
24662306a36Sopenharmony_ci	unsigned int			ccerrint;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/*
24962306a36Sopenharmony_ci	 * The slot_inuse bit for each PaRAM slot is clear unless the slot is
25062306a36Sopenharmony_ci	 * in use by Linux or if it is allocated to be used by DSP.
25162306a36Sopenharmony_ci	 */
25262306a36Sopenharmony_ci	unsigned long *slot_inuse;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/*
25562306a36Sopenharmony_ci	 * For tracking reserved channels used by DSP.
25662306a36Sopenharmony_ci	 * If the bit is cleared, the channel is allocated to be used by DSP
25762306a36Sopenharmony_ci	 * and Linux must not touch it.
25862306a36Sopenharmony_ci	 */
25962306a36Sopenharmony_ci	unsigned long *channels_mask;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	struct dma_device		dma_slave;
26262306a36Sopenharmony_ci	struct dma_device		*dma_memcpy;
26362306a36Sopenharmony_ci	struct edma_chan		*slave_chans;
26462306a36Sopenharmony_ci	struct edma_tc			*tc_list;
26562306a36Sopenharmony_ci	int				dummy_slot;
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci/* dummy param set used to (re)initialize parameter RAM slots */
26962306a36Sopenharmony_cistatic const struct edmacc_param dummy_paramset = {
27062306a36Sopenharmony_ci	.link_bcntrld = 0xffff,
27162306a36Sopenharmony_ci	.ccnt = 1,
27262306a36Sopenharmony_ci};
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci#define EDMA_BINDING_LEGACY	0
27562306a36Sopenharmony_ci#define EDMA_BINDING_TPCC	1
27662306a36Sopenharmony_cistatic const u32 edma_binding_type[] = {
27762306a36Sopenharmony_ci	[EDMA_BINDING_LEGACY] = EDMA_BINDING_LEGACY,
27862306a36Sopenharmony_ci	[EDMA_BINDING_TPCC] = EDMA_BINDING_TPCC,
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic const struct of_device_id edma_of_ids[] = {
28262306a36Sopenharmony_ci	{
28362306a36Sopenharmony_ci		.compatible = "ti,edma3",
28462306a36Sopenharmony_ci		.data = &edma_binding_type[EDMA_BINDING_LEGACY],
28562306a36Sopenharmony_ci	},
28662306a36Sopenharmony_ci	{
28762306a36Sopenharmony_ci		.compatible = "ti,edma3-tpcc",
28862306a36Sopenharmony_ci		.data = &edma_binding_type[EDMA_BINDING_TPCC],
28962306a36Sopenharmony_ci	},
29062306a36Sopenharmony_ci	{}
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, edma_of_ids);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_cistatic const struct of_device_id edma_tptc_of_ids[] = {
29562306a36Sopenharmony_ci	{ .compatible = "ti,edma3-tptc", },
29662306a36Sopenharmony_ci	{}
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, edma_tptc_of_ids);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic inline unsigned int edma_read(struct edma_cc *ecc, int offset)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	return (unsigned int)__raw_readl(ecc->base + offset);
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_cistatic inline void edma_write(struct edma_cc *ecc, int offset, int val)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	__raw_writel(val, ecc->base + offset);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic inline void edma_modify(struct edma_cc *ecc, int offset, unsigned and,
31162306a36Sopenharmony_ci			       unsigned or)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	unsigned val = edma_read(ecc, offset);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	val &= and;
31662306a36Sopenharmony_ci	val |= or;
31762306a36Sopenharmony_ci	edma_write(ecc, offset, val);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic inline void edma_or(struct edma_cc *ecc, int offset, unsigned or)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	unsigned val = edma_read(ecc, offset);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	val |= or;
32562306a36Sopenharmony_ci	edma_write(ecc, offset, val);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic inline unsigned int edma_read_array(struct edma_cc *ecc, int offset,
32962306a36Sopenharmony_ci					   int i)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	return edma_read(ecc, offset + (i << 2));
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic inline void edma_write_array(struct edma_cc *ecc, int offset, int i,
33562306a36Sopenharmony_ci				    unsigned val)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	edma_write(ecc, offset + (i << 2), val);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic inline void edma_modify_array(struct edma_cc *ecc, int offset, int i,
34162306a36Sopenharmony_ci				     unsigned and, unsigned or)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	edma_modify(ecc, offset + (i << 2), and, or);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic inline void edma_or_array2(struct edma_cc *ecc, int offset, int i, int j,
34762306a36Sopenharmony_ci				  unsigned or)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	edma_or(ecc, offset + ((i * 2 + j) << 2), or);
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic inline void edma_write_array2(struct edma_cc *ecc, int offset, int i,
35362306a36Sopenharmony_ci				     int j, unsigned val)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	edma_write(ecc, offset + ((i * 2 + j) << 2), val);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic inline unsigned int edma_shadow0_read_array(struct edma_cc *ecc,
35962306a36Sopenharmony_ci						   int offset, int i)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	return edma_read(ecc, EDMA_SHADOW0 + offset + (i << 2));
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic inline void edma_shadow0_write(struct edma_cc *ecc, int offset,
36562306a36Sopenharmony_ci				      unsigned val)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	edma_write(ecc, EDMA_SHADOW0 + offset, val);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic inline void edma_shadow0_write_array(struct edma_cc *ecc, int offset,
37162306a36Sopenharmony_ci					    int i, unsigned val)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	edma_write(ecc, EDMA_SHADOW0 + offset + (i << 2), val);
37462306a36Sopenharmony_ci}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_cistatic inline void edma_param_modify(struct edma_cc *ecc, int offset,
37762306a36Sopenharmony_ci				     int param_no, unsigned and, unsigned or)
37862306a36Sopenharmony_ci{
37962306a36Sopenharmony_ci	edma_modify(ecc, EDMA_PARM + offset + (param_no << 5), and, or);
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no,
38362306a36Sopenharmony_ci					  int priority)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	int bit = queue_no * 4;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	edma_modify(ecc, EDMA_QUEPRI, ~(0x7 << bit), ((priority & 0x7) << bit));
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void edma_set_chmap(struct edma_chan *echan, int slot)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
39362306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	if (ecc->chmap_exist) {
39662306a36Sopenharmony_ci		slot = EDMA_CHAN_SLOT(slot);
39762306a36Sopenharmony_ci		edma_write_array(ecc, EDMA_DCHMAP, channel, (slot << 5));
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci}
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_cistatic void edma_setup_interrupt(struct edma_chan *echan, bool enable)
40262306a36Sopenharmony_ci{
40362306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
40462306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
40562306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
40662306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (enable) {
40962306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit);
41062306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_IESR, idx, ch_bit);
41162306a36Sopenharmony_ci	} else {
41262306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_IECR, idx, ch_bit);
41362306a36Sopenharmony_ci	}
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/*
41762306a36Sopenharmony_ci * paRAM slot management functions
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_cistatic void edma_write_slot(struct edma_cc *ecc, unsigned slot,
42062306a36Sopenharmony_ci			    const struct edmacc_param *param)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	slot = EDMA_CHAN_SLOT(slot);
42362306a36Sopenharmony_ci	if (slot >= ecc->num_slots)
42462306a36Sopenharmony_ci		return;
42562306a36Sopenharmony_ci	memcpy_toio(ecc->base + PARM_OFFSET(slot), param, PARM_SIZE);
42662306a36Sopenharmony_ci}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_cistatic int edma_read_slot(struct edma_cc *ecc, unsigned slot,
42962306a36Sopenharmony_ci			   struct edmacc_param *param)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	slot = EDMA_CHAN_SLOT(slot);
43262306a36Sopenharmony_ci	if (slot >= ecc->num_slots)
43362306a36Sopenharmony_ci		return -EINVAL;
43462306a36Sopenharmony_ci	memcpy_fromio(param, ecc->base + PARM_OFFSET(slot), PARM_SIZE);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	return 0;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/**
44062306a36Sopenharmony_ci * edma_alloc_slot - allocate DMA parameter RAM
44162306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct
44262306a36Sopenharmony_ci * @slot: specific slot to allocate; negative for "any unused slot"
44362306a36Sopenharmony_ci *
44462306a36Sopenharmony_ci * This allocates a parameter RAM slot, initializing it to hold a
44562306a36Sopenharmony_ci * dummy transfer.  Slots allocated using this routine have not been
44662306a36Sopenharmony_ci * mapped to a hardware DMA channel, and will normally be used by
44762306a36Sopenharmony_ci * linking to them from a slot associated with a DMA channel.
44862306a36Sopenharmony_ci *
44962306a36Sopenharmony_ci * Normal use is to pass EDMA_SLOT_ANY as the @slot, but specific
45062306a36Sopenharmony_ci * slots may be allocated on behalf of DSP firmware.
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * Returns the number of the slot, else negative errno.
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_cistatic int edma_alloc_slot(struct edma_cc *ecc, int slot)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	if (slot >= 0) {
45762306a36Sopenharmony_ci		slot = EDMA_CHAN_SLOT(slot);
45862306a36Sopenharmony_ci		/* Requesting entry paRAM slot for a HW triggered channel. */
45962306a36Sopenharmony_ci		if (ecc->chmap_exist && slot < ecc->num_channels)
46062306a36Sopenharmony_ci			slot = EDMA_SLOT_ANY;
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (slot < 0) {
46462306a36Sopenharmony_ci		if (ecc->chmap_exist)
46562306a36Sopenharmony_ci			slot = 0;
46662306a36Sopenharmony_ci		else
46762306a36Sopenharmony_ci			slot = ecc->num_channels;
46862306a36Sopenharmony_ci		for (;;) {
46962306a36Sopenharmony_ci			slot = find_next_zero_bit(ecc->slot_inuse,
47062306a36Sopenharmony_ci						  ecc->num_slots,
47162306a36Sopenharmony_ci						  slot);
47262306a36Sopenharmony_ci			if (slot == ecc->num_slots)
47362306a36Sopenharmony_ci				return -ENOMEM;
47462306a36Sopenharmony_ci			if (!test_and_set_bit(slot, ecc->slot_inuse))
47562306a36Sopenharmony_ci				break;
47662306a36Sopenharmony_ci		}
47762306a36Sopenharmony_ci	} else if (slot >= ecc->num_slots) {
47862306a36Sopenharmony_ci		return -EINVAL;
47962306a36Sopenharmony_ci	} else if (test_and_set_bit(slot, ecc->slot_inuse)) {
48062306a36Sopenharmony_ci		return -EBUSY;
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	edma_write_slot(ecc, slot, &dummy_paramset);
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	return EDMA_CTLR_CHAN(ecc->id, slot);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic void edma_free_slot(struct edma_cc *ecc, unsigned slot)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	slot = EDMA_CHAN_SLOT(slot);
49162306a36Sopenharmony_ci	if (slot >= ecc->num_slots)
49262306a36Sopenharmony_ci		return;
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	edma_write_slot(ecc, slot, &dummy_paramset);
49562306a36Sopenharmony_ci	clear_bit(slot, ecc->slot_inuse);
49662306a36Sopenharmony_ci}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci/**
49962306a36Sopenharmony_ci * edma_link - link one parameter RAM slot to another
50062306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct
50162306a36Sopenharmony_ci * @from: parameter RAM slot originating the link
50262306a36Sopenharmony_ci * @to: parameter RAM slot which is the link target
50362306a36Sopenharmony_ci *
50462306a36Sopenharmony_ci * The originating slot should not be part of any active DMA transfer.
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic void edma_link(struct edma_cc *ecc, unsigned from, unsigned to)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	if (unlikely(EDMA_CTLR(from) != EDMA_CTLR(to)))
50962306a36Sopenharmony_ci		dev_warn(ecc->dev, "Ignoring eDMA instance for linking\n");
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	from = EDMA_CHAN_SLOT(from);
51262306a36Sopenharmony_ci	to = EDMA_CHAN_SLOT(to);
51362306a36Sopenharmony_ci	if (from >= ecc->num_slots || to >= ecc->num_slots)
51462306a36Sopenharmony_ci		return;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	edma_param_modify(ecc, PARM_LINK_BCNTRLD, from, 0xffff0000,
51762306a36Sopenharmony_ci			  PARM_OFFSET(to));
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci/**
52162306a36Sopenharmony_ci * edma_get_position - returns the current transfer point
52262306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct
52362306a36Sopenharmony_ci * @slot: parameter RAM slot being examined
52462306a36Sopenharmony_ci * @dst:  true selects the dest position, false the source
52562306a36Sopenharmony_ci *
52662306a36Sopenharmony_ci * Returns the position of the current active slot
52762306a36Sopenharmony_ci */
52862306a36Sopenharmony_cistatic dma_addr_t edma_get_position(struct edma_cc *ecc, unsigned slot,
52962306a36Sopenharmony_ci				    bool dst)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	u32 offs;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	slot = EDMA_CHAN_SLOT(slot);
53462306a36Sopenharmony_ci	offs = PARM_OFFSET(slot);
53562306a36Sopenharmony_ci	offs += dst ? PARM_DST : PARM_SRC;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	return edma_read(ecc, offs);
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/*
54162306a36Sopenharmony_ci * Channels with event associations will be triggered by their hardware
54262306a36Sopenharmony_ci * events, and channels without such associations will be triggered by
54362306a36Sopenharmony_ci * software.  (At this writing there is no interface for using software
54462306a36Sopenharmony_ci * triggers except with channels that don't support hardware triggers.)
54562306a36Sopenharmony_ci */
54662306a36Sopenharmony_cistatic void edma_start(struct edma_chan *echan)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
54962306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
55062306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
55162306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (!echan->hw_triggered) {
55462306a36Sopenharmony_ci		/* EDMA channels without event association */
55562306a36Sopenharmony_ci		dev_dbg(ecc->dev, "ESR%d %08x\n", idx,
55662306a36Sopenharmony_ci			edma_shadow0_read_array(ecc, SH_ESR, idx));
55762306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit);
55862306a36Sopenharmony_ci	} else {
55962306a36Sopenharmony_ci		/* EDMA channel with event association */
56062306a36Sopenharmony_ci		dev_dbg(ecc->dev, "ER%d %08x\n", idx,
56162306a36Sopenharmony_ci			edma_shadow0_read_array(ecc, SH_ER, idx));
56262306a36Sopenharmony_ci		/* Clear any pending event or error */
56362306a36Sopenharmony_ci		edma_write_array(ecc, EDMA_ECR, idx, ch_bit);
56462306a36Sopenharmony_ci		edma_write_array(ecc, EDMA_EMCR, idx, ch_bit);
56562306a36Sopenharmony_ci		/* Clear any SER */
56662306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit);
56762306a36Sopenharmony_ci		edma_shadow0_write_array(ecc, SH_EESR, idx, ch_bit);
56862306a36Sopenharmony_ci		dev_dbg(ecc->dev, "EER%d %08x\n", idx,
56962306a36Sopenharmony_ci			edma_shadow0_read_array(ecc, SH_EER, idx));
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void edma_stop(struct edma_chan *echan)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
57662306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
57762306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
57862306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_EECR, idx, ch_bit);
58162306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit);
58262306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit);
58362306a36Sopenharmony_ci	edma_write_array(ecc, EDMA_EMCR, idx, ch_bit);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	/* clear possibly pending completion interrupt */
58662306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	dev_dbg(ecc->dev, "EER%d %08x\n", idx,
58962306a36Sopenharmony_ci		edma_shadow0_read_array(ecc, SH_EER, idx));
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/* REVISIT:  consider guarding against inappropriate event
59262306a36Sopenharmony_ci	 * chaining by overwriting with dummy_paramset.
59362306a36Sopenharmony_ci	 */
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/*
59762306a36Sopenharmony_ci * Temporarily disable EDMA hardware events on the specified channel,
59862306a36Sopenharmony_ci * preventing them from triggering new transfers
59962306a36Sopenharmony_ci */
60062306a36Sopenharmony_cistatic void edma_pause(struct edma_chan *echan)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	edma_shadow0_write_array(echan->ecc, SH_EECR,
60562306a36Sopenharmony_ci				 EDMA_REG_ARRAY_INDEX(channel),
60662306a36Sopenharmony_ci				 EDMA_CHANNEL_BIT(channel));
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/* Re-enable EDMA hardware events on the specified channel.  */
61062306a36Sopenharmony_cistatic void edma_resume(struct edma_chan *echan)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	edma_shadow0_write_array(echan->ecc, SH_EESR,
61562306a36Sopenharmony_ci				 EDMA_REG_ARRAY_INDEX(channel),
61662306a36Sopenharmony_ci				 EDMA_CHANNEL_BIT(channel));
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void edma_trigger_channel(struct edma_chan *echan)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
62262306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
62362306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
62462306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit);
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	dev_dbg(ecc->dev, "ESR%d %08x\n", idx,
62962306a36Sopenharmony_ci		edma_shadow0_read_array(ecc, SH_ESR, idx));
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic void edma_clean_channel(struct edma_chan *echan)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
63562306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
63662306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
63762306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	dev_dbg(ecc->dev, "EMR%d %08x\n", idx,
64062306a36Sopenharmony_ci		edma_read_array(ecc, EDMA_EMR, idx));
64162306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit);
64262306a36Sopenharmony_ci	/* Clear the corresponding EMR bits */
64362306a36Sopenharmony_ci	edma_write_array(ecc, EDMA_EMCR, idx, ch_bit);
64462306a36Sopenharmony_ci	/* Clear any SER */
64562306a36Sopenharmony_ci	edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit);
64662306a36Sopenharmony_ci	edma_write(ecc, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0));
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci/* Move channel to a specific event queue */
65062306a36Sopenharmony_cistatic void edma_assign_channel_eventq(struct edma_chan *echan,
65162306a36Sopenharmony_ci				       enum dma_event_q eventq_no)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
65462306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
65562306a36Sopenharmony_ci	int bit = (channel & 0x7) * 4;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* default to low priority queue */
65862306a36Sopenharmony_ci	if (eventq_no == EVENTQ_DEFAULT)
65962306a36Sopenharmony_ci		eventq_no = ecc->default_queue;
66062306a36Sopenharmony_ci	if (eventq_no >= ecc->num_tc)
66162306a36Sopenharmony_ci		return;
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	eventq_no &= 7;
66462306a36Sopenharmony_ci	edma_modify_array(ecc, EDMA_DMAQNUM, (channel >> 3), ~(0x7 << bit),
66562306a36Sopenharmony_ci			  eventq_no << bit);
66662306a36Sopenharmony_ci}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int edma_alloc_channel(struct edma_chan *echan,
66962306a36Sopenharmony_ci			      enum dma_event_q eventq_no)
67062306a36Sopenharmony_ci{
67162306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
67262306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	if (!test_bit(echan->ch_num, ecc->channels_mask)) {
67562306a36Sopenharmony_ci		dev_err(ecc->dev, "Channel%d is reserved, can not be used!\n",
67662306a36Sopenharmony_ci			echan->ch_num);
67762306a36Sopenharmony_ci		return -EINVAL;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	/* ensure access through shadow region 0 */
68162306a36Sopenharmony_ci	edma_or_array2(ecc, EDMA_DRAE, 0, EDMA_REG_ARRAY_INDEX(channel),
68262306a36Sopenharmony_ci		       EDMA_CHANNEL_BIT(channel));
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	/* ensure no events are pending */
68562306a36Sopenharmony_ci	edma_stop(echan);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	edma_setup_interrupt(echan, true);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	edma_assign_channel_eventq(echan, eventq_no);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	return 0;
69262306a36Sopenharmony_ci}
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cistatic void edma_free_channel(struct edma_chan *echan)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	/* ensure no events are pending */
69762306a36Sopenharmony_ci	edma_stop(echan);
69862306a36Sopenharmony_ci	/* REVISIT should probably take out of shadow region 0 */
69962306a36Sopenharmony_ci	edma_setup_interrupt(echan, false);
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic inline struct edma_chan *to_edma_chan(struct dma_chan *c)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	return container_of(c, struct edma_chan, vchan.chan);
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_cistatic inline struct edma_desc *to_edma_desc(struct dma_async_tx_descriptor *tx)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	return container_of(tx, struct edma_desc, vdesc.tx);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_cistatic void edma_desc_free(struct virt_dma_desc *vdesc)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	kfree(container_of(vdesc, struct edma_desc, vdesc));
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci/* Dispatch a queued descriptor to the controller (caller holds lock) */
71862306a36Sopenharmony_cistatic void edma_execute(struct edma_chan *echan)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
72162306a36Sopenharmony_ci	struct virt_dma_desc *vdesc;
72262306a36Sopenharmony_ci	struct edma_desc *edesc;
72362306a36Sopenharmony_ci	struct device *dev = echan->vchan.chan.device->dev;
72462306a36Sopenharmony_ci	int i, j, left, nslots;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (!echan->edesc) {
72762306a36Sopenharmony_ci		/* Setup is needed for the first transfer */
72862306a36Sopenharmony_ci		vdesc = vchan_next_desc(&echan->vchan);
72962306a36Sopenharmony_ci		if (!vdesc)
73062306a36Sopenharmony_ci			return;
73162306a36Sopenharmony_ci		list_del(&vdesc->node);
73262306a36Sopenharmony_ci		echan->edesc = to_edma_desc(&vdesc->tx);
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	edesc = echan->edesc;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	/* Find out how many left */
73862306a36Sopenharmony_ci	left = edesc->pset_nr - edesc->processed;
73962306a36Sopenharmony_ci	nslots = min(MAX_NR_SG, left);
74062306a36Sopenharmony_ci	edesc->sg_len = 0;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Write descriptor PaRAM set(s) */
74362306a36Sopenharmony_ci	for (i = 0; i < nslots; i++) {
74462306a36Sopenharmony_ci		j = i + edesc->processed;
74562306a36Sopenharmony_ci		edma_write_slot(ecc, echan->slot[i], &edesc->pset[j].param);
74662306a36Sopenharmony_ci		edesc->sg_len += edesc->pset[j].len;
74762306a36Sopenharmony_ci		dev_vdbg(dev,
74862306a36Sopenharmony_ci			 "\n pset[%d]:\n"
74962306a36Sopenharmony_ci			 "  chnum\t%d\n"
75062306a36Sopenharmony_ci			 "  slot\t%d\n"
75162306a36Sopenharmony_ci			 "  opt\t%08x\n"
75262306a36Sopenharmony_ci			 "  src\t%08x\n"
75362306a36Sopenharmony_ci			 "  dst\t%08x\n"
75462306a36Sopenharmony_ci			 "  abcnt\t%08x\n"
75562306a36Sopenharmony_ci			 "  ccnt\t%08x\n"
75662306a36Sopenharmony_ci			 "  bidx\t%08x\n"
75762306a36Sopenharmony_ci			 "  cidx\t%08x\n"
75862306a36Sopenharmony_ci			 "  lkrld\t%08x\n",
75962306a36Sopenharmony_ci			 j, echan->ch_num, echan->slot[i],
76062306a36Sopenharmony_ci			 edesc->pset[j].param.opt,
76162306a36Sopenharmony_ci			 edesc->pset[j].param.src,
76262306a36Sopenharmony_ci			 edesc->pset[j].param.dst,
76362306a36Sopenharmony_ci			 edesc->pset[j].param.a_b_cnt,
76462306a36Sopenharmony_ci			 edesc->pset[j].param.ccnt,
76562306a36Sopenharmony_ci			 edesc->pset[j].param.src_dst_bidx,
76662306a36Sopenharmony_ci			 edesc->pset[j].param.src_dst_cidx,
76762306a36Sopenharmony_ci			 edesc->pset[j].param.link_bcntrld);
76862306a36Sopenharmony_ci		/* Link to the previous slot if not the last set */
76962306a36Sopenharmony_ci		if (i != (nslots - 1))
77062306a36Sopenharmony_ci			edma_link(ecc, echan->slot[i], echan->slot[i + 1]);
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	edesc->processed += nslots;
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/*
77662306a36Sopenharmony_ci	 * If this is either the last set in a set of SG-list transactions
77762306a36Sopenharmony_ci	 * then setup a link to the dummy slot, this results in all future
77862306a36Sopenharmony_ci	 * events being absorbed and that's OK because we're done
77962306a36Sopenharmony_ci	 */
78062306a36Sopenharmony_ci	if (edesc->processed == edesc->pset_nr) {
78162306a36Sopenharmony_ci		if (edesc->cyclic)
78262306a36Sopenharmony_ci			edma_link(ecc, echan->slot[nslots - 1], echan->slot[1]);
78362306a36Sopenharmony_ci		else
78462306a36Sopenharmony_ci			edma_link(ecc, echan->slot[nslots - 1],
78562306a36Sopenharmony_ci				  echan->ecc->dummy_slot);
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	if (echan->missed) {
78962306a36Sopenharmony_ci		/*
79062306a36Sopenharmony_ci		 * This happens due to setup times between intermediate
79162306a36Sopenharmony_ci		 * transfers in long SG lists which have to be broken up into
79262306a36Sopenharmony_ci		 * transfers of MAX_NR_SG
79362306a36Sopenharmony_ci		 */
79462306a36Sopenharmony_ci		dev_dbg(dev, "missed event on channel %d\n", echan->ch_num);
79562306a36Sopenharmony_ci		edma_clean_channel(echan);
79662306a36Sopenharmony_ci		edma_stop(echan);
79762306a36Sopenharmony_ci		edma_start(echan);
79862306a36Sopenharmony_ci		edma_trigger_channel(echan);
79962306a36Sopenharmony_ci		echan->missed = 0;
80062306a36Sopenharmony_ci	} else if (edesc->processed <= MAX_NR_SG) {
80162306a36Sopenharmony_ci		dev_dbg(dev, "first transfer starting on channel %d\n",
80262306a36Sopenharmony_ci			echan->ch_num);
80362306a36Sopenharmony_ci		edma_start(echan);
80462306a36Sopenharmony_ci	} else {
80562306a36Sopenharmony_ci		dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
80662306a36Sopenharmony_ci			echan->ch_num, edesc->processed);
80762306a36Sopenharmony_ci		edma_resume(echan);
80862306a36Sopenharmony_ci	}
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_cistatic int edma_terminate_all(struct dma_chan *chan)
81262306a36Sopenharmony_ci{
81362306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
81462306a36Sopenharmony_ci	unsigned long flags;
81562306a36Sopenharmony_ci	LIST_HEAD(head);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	spin_lock_irqsave(&echan->vchan.lock, flags);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/*
82062306a36Sopenharmony_ci	 * Stop DMA activity: we assume the callback will not be called
82162306a36Sopenharmony_ci	 * after edma_dma() returns (even if it does, it will see
82262306a36Sopenharmony_ci	 * echan->edesc is NULL and exit.)
82362306a36Sopenharmony_ci	 */
82462306a36Sopenharmony_ci	if (echan->edesc) {
82562306a36Sopenharmony_ci		edma_stop(echan);
82662306a36Sopenharmony_ci		/* Move the cyclic channel back to default queue */
82762306a36Sopenharmony_ci		if (!echan->tc && echan->edesc->cyclic)
82862306a36Sopenharmony_ci			edma_assign_channel_eventq(echan, EVENTQ_DEFAULT);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci		vchan_terminate_vdesc(&echan->edesc->vdesc);
83162306a36Sopenharmony_ci		echan->edesc = NULL;
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	vchan_get_all_descriptors(&echan->vchan, &head);
83562306a36Sopenharmony_ci	spin_unlock_irqrestore(&echan->vchan.lock, flags);
83662306a36Sopenharmony_ci	vchan_dma_desc_free_list(&echan->vchan, &head);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic void edma_synchronize(struct dma_chan *chan)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	vchan_synchronize(&echan->vchan);
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int edma_slave_config(struct dma_chan *chan,
84962306a36Sopenharmony_ci	struct dma_slave_config *cfg)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
85462306a36Sopenharmony_ci	    cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
85562306a36Sopenharmony_ci		return -EINVAL;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (cfg->src_maxburst > chan->device->max_burst ||
85862306a36Sopenharmony_ci	    cfg->dst_maxburst > chan->device->max_burst)
85962306a36Sopenharmony_ci		return -EINVAL;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	memcpy(&echan->cfg, cfg, sizeof(echan->cfg));
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	return 0;
86462306a36Sopenharmony_ci}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_cistatic int edma_dma_pause(struct dma_chan *chan)
86762306a36Sopenharmony_ci{
86862306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	if (!echan->edesc)
87162306a36Sopenharmony_ci		return -EINVAL;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	edma_pause(echan);
87462306a36Sopenharmony_ci	return 0;
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic int edma_dma_resume(struct dma_chan *chan)
87862306a36Sopenharmony_ci{
87962306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	edma_resume(echan);
88262306a36Sopenharmony_ci	return 0;
88362306a36Sopenharmony_ci}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci/*
88662306a36Sopenharmony_ci * A PaRAM set configuration abstraction used by other modes
88762306a36Sopenharmony_ci * @chan: Channel who's PaRAM set we're configuring
88862306a36Sopenharmony_ci * @pset: PaRAM set to initialize and setup.
88962306a36Sopenharmony_ci * @src_addr: Source address of the DMA
89062306a36Sopenharmony_ci * @dst_addr: Destination address of the DMA
89162306a36Sopenharmony_ci * @burst: In units of dev_width, how much to send
89262306a36Sopenharmony_ci * @dev_width: How much is the dev_width
89362306a36Sopenharmony_ci * @dma_length: Total length of the DMA transfer
89462306a36Sopenharmony_ci * @direction: Direction of the transfer
89562306a36Sopenharmony_ci */
89662306a36Sopenharmony_cistatic int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset,
89762306a36Sopenharmony_ci			    dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst,
89862306a36Sopenharmony_ci			    unsigned int acnt, unsigned int dma_length,
89962306a36Sopenharmony_ci			    enum dma_transfer_direction direction)
90062306a36Sopenharmony_ci{
90162306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
90262306a36Sopenharmony_ci	struct device *dev = chan->device->dev;
90362306a36Sopenharmony_ci	struct edmacc_param *param = &epset->param;
90462306a36Sopenharmony_ci	int bcnt, ccnt, cidx;
90562306a36Sopenharmony_ci	int src_bidx, dst_bidx, src_cidx, dst_cidx;
90662306a36Sopenharmony_ci	int absync;
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* src/dst_maxburst == 0 is the same case as src/dst_maxburst == 1 */
90962306a36Sopenharmony_ci	if (!burst)
91062306a36Sopenharmony_ci		burst = 1;
91162306a36Sopenharmony_ci	/*
91262306a36Sopenharmony_ci	 * If the maxburst is equal to the fifo width, use
91362306a36Sopenharmony_ci	 * A-synced transfers. This allows for large contiguous
91462306a36Sopenharmony_ci	 * buffer transfers using only one PaRAM set.
91562306a36Sopenharmony_ci	 */
91662306a36Sopenharmony_ci	if (burst == 1) {
91762306a36Sopenharmony_ci		/*
91862306a36Sopenharmony_ci		 * For the A-sync case, bcnt and ccnt are the remainder
91962306a36Sopenharmony_ci		 * and quotient respectively of the division of:
92062306a36Sopenharmony_ci		 * (dma_length / acnt) by (SZ_64K -1). This is so
92162306a36Sopenharmony_ci		 * that in case bcnt over flows, we have ccnt to use.
92262306a36Sopenharmony_ci		 * Note: In A-sync transfer only, bcntrld is used, but it
92362306a36Sopenharmony_ci		 * only applies for sg_dma_len(sg) >= SZ_64K.
92462306a36Sopenharmony_ci		 * In this case, the best way adopted is- bccnt for the
92562306a36Sopenharmony_ci		 * first frame will be the remainder below. Then for
92662306a36Sopenharmony_ci		 * every successive frame, bcnt will be SZ_64K-1. This
92762306a36Sopenharmony_ci		 * is assured as bcntrld = 0xffff in end of function.
92862306a36Sopenharmony_ci		 */
92962306a36Sopenharmony_ci		absync = false;
93062306a36Sopenharmony_ci		ccnt = dma_length / acnt / (SZ_64K - 1);
93162306a36Sopenharmony_ci		bcnt = dma_length / acnt - ccnt * (SZ_64K - 1);
93262306a36Sopenharmony_ci		/*
93362306a36Sopenharmony_ci		 * If bcnt is non-zero, we have a remainder and hence an
93462306a36Sopenharmony_ci		 * extra frame to transfer, so increment ccnt.
93562306a36Sopenharmony_ci		 */
93662306a36Sopenharmony_ci		if (bcnt)
93762306a36Sopenharmony_ci			ccnt++;
93862306a36Sopenharmony_ci		else
93962306a36Sopenharmony_ci			bcnt = SZ_64K - 1;
94062306a36Sopenharmony_ci		cidx = acnt;
94162306a36Sopenharmony_ci	} else {
94262306a36Sopenharmony_ci		/*
94362306a36Sopenharmony_ci		 * If maxburst is greater than the fifo address_width,
94462306a36Sopenharmony_ci		 * use AB-synced transfers where A count is the fifo
94562306a36Sopenharmony_ci		 * address_width and B count is the maxburst. In this
94662306a36Sopenharmony_ci		 * case, we are limited to transfers of C count frames
94762306a36Sopenharmony_ci		 * of (address_width * maxburst) where C count is limited
94862306a36Sopenharmony_ci		 * to SZ_64K-1. This places an upper bound on the length
94962306a36Sopenharmony_ci		 * of an SG segment that can be handled.
95062306a36Sopenharmony_ci		 */
95162306a36Sopenharmony_ci		absync = true;
95262306a36Sopenharmony_ci		bcnt = burst;
95362306a36Sopenharmony_ci		ccnt = dma_length / (acnt * bcnt);
95462306a36Sopenharmony_ci		if (ccnt > (SZ_64K - 1)) {
95562306a36Sopenharmony_ci			dev_err(dev, "Exceeded max SG segment size\n");
95662306a36Sopenharmony_ci			return -EINVAL;
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci		cidx = acnt * bcnt;
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	epset->len = dma_length;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci	if (direction == DMA_MEM_TO_DEV) {
96462306a36Sopenharmony_ci		src_bidx = acnt;
96562306a36Sopenharmony_ci		src_cidx = cidx;
96662306a36Sopenharmony_ci		dst_bidx = 0;
96762306a36Sopenharmony_ci		dst_cidx = 0;
96862306a36Sopenharmony_ci		epset->addr = src_addr;
96962306a36Sopenharmony_ci	} else if (direction == DMA_DEV_TO_MEM)  {
97062306a36Sopenharmony_ci		src_bidx = 0;
97162306a36Sopenharmony_ci		src_cidx = 0;
97262306a36Sopenharmony_ci		dst_bidx = acnt;
97362306a36Sopenharmony_ci		dst_cidx = cidx;
97462306a36Sopenharmony_ci		epset->addr = dst_addr;
97562306a36Sopenharmony_ci	} else if (direction == DMA_MEM_TO_MEM)  {
97662306a36Sopenharmony_ci		src_bidx = acnt;
97762306a36Sopenharmony_ci		src_cidx = cidx;
97862306a36Sopenharmony_ci		dst_bidx = acnt;
97962306a36Sopenharmony_ci		dst_cidx = cidx;
98062306a36Sopenharmony_ci		epset->addr = src_addr;
98162306a36Sopenharmony_ci	} else {
98262306a36Sopenharmony_ci		dev_err(dev, "%s: direction not implemented yet\n", __func__);
98362306a36Sopenharmony_ci		return -EINVAL;
98462306a36Sopenharmony_ci	}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
98762306a36Sopenharmony_ci	/* Configure A or AB synchronized transfers */
98862306a36Sopenharmony_ci	if (absync)
98962306a36Sopenharmony_ci		param->opt |= SYNCDIM;
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	param->src = src_addr;
99262306a36Sopenharmony_ci	param->dst = dst_addr;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	param->src_dst_bidx = (dst_bidx << 16) | src_bidx;
99562306a36Sopenharmony_ci	param->src_dst_cidx = (dst_cidx << 16) | src_cidx;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	param->a_b_cnt = bcnt << 16 | acnt;
99862306a36Sopenharmony_ci	param->ccnt = ccnt;
99962306a36Sopenharmony_ci	/*
100062306a36Sopenharmony_ci	 * Only time when (bcntrld) auto reload is required is for
100162306a36Sopenharmony_ci	 * A-sync case, and in this case, a requirement of reload value
100262306a36Sopenharmony_ci	 * of SZ_64K-1 only is assured. 'link' is initially set to NULL
100362306a36Sopenharmony_ci	 * and then later will be populated by edma_execute.
100462306a36Sopenharmony_ci	 */
100562306a36Sopenharmony_ci	param->link_bcntrld = 0xffffffff;
100662306a36Sopenharmony_ci	return absync;
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_slave_sg(
101062306a36Sopenharmony_ci	struct dma_chan *chan, struct scatterlist *sgl,
101162306a36Sopenharmony_ci	unsigned int sg_len, enum dma_transfer_direction direction,
101262306a36Sopenharmony_ci	unsigned long tx_flags, void *context)
101362306a36Sopenharmony_ci{
101462306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
101562306a36Sopenharmony_ci	struct device *dev = chan->device->dev;
101662306a36Sopenharmony_ci	struct edma_desc *edesc;
101762306a36Sopenharmony_ci	dma_addr_t src_addr = 0, dst_addr = 0;
101862306a36Sopenharmony_ci	enum dma_slave_buswidth dev_width;
101962306a36Sopenharmony_ci	u32 burst;
102062306a36Sopenharmony_ci	struct scatterlist *sg;
102162306a36Sopenharmony_ci	int i, nslots, ret;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	if (unlikely(!echan || !sgl || !sg_len))
102462306a36Sopenharmony_ci		return NULL;
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	if (direction == DMA_DEV_TO_MEM) {
102762306a36Sopenharmony_ci		src_addr = echan->cfg.src_addr;
102862306a36Sopenharmony_ci		dev_width = echan->cfg.src_addr_width;
102962306a36Sopenharmony_ci		burst = echan->cfg.src_maxburst;
103062306a36Sopenharmony_ci	} else if (direction == DMA_MEM_TO_DEV) {
103162306a36Sopenharmony_ci		dst_addr = echan->cfg.dst_addr;
103262306a36Sopenharmony_ci		dev_width = echan->cfg.dst_addr_width;
103362306a36Sopenharmony_ci		burst = echan->cfg.dst_maxburst;
103462306a36Sopenharmony_ci	} else {
103562306a36Sopenharmony_ci		dev_err(dev, "%s: bad direction: %d\n", __func__, direction);
103662306a36Sopenharmony_ci		return NULL;
103762306a36Sopenharmony_ci	}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
104062306a36Sopenharmony_ci		dev_err(dev, "%s: Undefined slave buswidth\n", __func__);
104162306a36Sopenharmony_ci		return NULL;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	edesc = kzalloc(struct_size(edesc, pset, sg_len), GFP_ATOMIC);
104562306a36Sopenharmony_ci	if (!edesc)
104662306a36Sopenharmony_ci		return NULL;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	edesc->pset_nr = sg_len;
104962306a36Sopenharmony_ci	edesc->residue = 0;
105062306a36Sopenharmony_ci	edesc->direction = direction;
105162306a36Sopenharmony_ci	edesc->echan = echan;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	/* Allocate a PaRAM slot, if needed */
105462306a36Sopenharmony_ci	nslots = min_t(unsigned, MAX_NR_SG, sg_len);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	for (i = 0; i < nslots; i++) {
105762306a36Sopenharmony_ci		if (echan->slot[i] < 0) {
105862306a36Sopenharmony_ci			echan->slot[i] =
105962306a36Sopenharmony_ci				edma_alloc_slot(echan->ecc, EDMA_SLOT_ANY);
106062306a36Sopenharmony_ci			if (echan->slot[i] < 0) {
106162306a36Sopenharmony_ci				kfree(edesc);
106262306a36Sopenharmony_ci				dev_err(dev, "%s: Failed to allocate slot\n",
106362306a36Sopenharmony_ci					__func__);
106462306a36Sopenharmony_ci				return NULL;
106562306a36Sopenharmony_ci			}
106662306a36Sopenharmony_ci		}
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	/* Configure PaRAM sets for each SG */
107062306a36Sopenharmony_ci	for_each_sg(sgl, sg, sg_len, i) {
107162306a36Sopenharmony_ci		/* Get address for each SG */
107262306a36Sopenharmony_ci		if (direction == DMA_DEV_TO_MEM)
107362306a36Sopenharmony_ci			dst_addr = sg_dma_address(sg);
107462306a36Sopenharmony_ci		else
107562306a36Sopenharmony_ci			src_addr = sg_dma_address(sg);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		ret = edma_config_pset(chan, &edesc->pset[i], src_addr,
107862306a36Sopenharmony_ci				       dst_addr, burst, dev_width,
107962306a36Sopenharmony_ci				       sg_dma_len(sg), direction);
108062306a36Sopenharmony_ci		if (ret < 0) {
108162306a36Sopenharmony_ci			kfree(edesc);
108262306a36Sopenharmony_ci			return NULL;
108362306a36Sopenharmony_ci		}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci		edesc->absync = ret;
108662306a36Sopenharmony_ci		edesc->residue += sg_dma_len(sg);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci		if (i == sg_len - 1)
108962306a36Sopenharmony_ci			/* Enable completion interrupt */
109062306a36Sopenharmony_ci			edesc->pset[i].param.opt |= TCINTEN;
109162306a36Sopenharmony_ci		else if (!((i+1) % MAX_NR_SG))
109262306a36Sopenharmony_ci			/*
109362306a36Sopenharmony_ci			 * Enable early completion interrupt for the
109462306a36Sopenharmony_ci			 * intermediateset. In this case the driver will be
109562306a36Sopenharmony_ci			 * notified when the paRAM set is submitted to TC. This
109662306a36Sopenharmony_ci			 * will allow more time to set up the next set of slots.
109762306a36Sopenharmony_ci			 */
109862306a36Sopenharmony_ci			edesc->pset[i].param.opt |= (TCINTEN | TCCMODE);
109962306a36Sopenharmony_ci	}
110062306a36Sopenharmony_ci	edesc->residue_stat = edesc->residue;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
110662306a36Sopenharmony_ci	struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
110762306a36Sopenharmony_ci	size_t len, unsigned long tx_flags)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	int ret, nslots;
111062306a36Sopenharmony_ci	struct edma_desc *edesc;
111162306a36Sopenharmony_ci	struct device *dev = chan->device->dev;
111262306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
111362306a36Sopenharmony_ci	unsigned int width, pset_len, array_size;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (unlikely(!echan || !len))
111662306a36Sopenharmony_ci		return NULL;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* Align the array size (acnt block) with the transfer properties */
111962306a36Sopenharmony_ci	switch (__ffs((src | dest | len))) {
112062306a36Sopenharmony_ci	case 0:
112162306a36Sopenharmony_ci		array_size = SZ_32K - 1;
112262306a36Sopenharmony_ci		break;
112362306a36Sopenharmony_ci	case 1:
112462306a36Sopenharmony_ci		array_size = SZ_32K - 2;
112562306a36Sopenharmony_ci		break;
112662306a36Sopenharmony_ci	default:
112762306a36Sopenharmony_ci		array_size = SZ_32K - 4;
112862306a36Sopenharmony_ci		break;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (len < SZ_64K) {
113262306a36Sopenharmony_ci		/*
113362306a36Sopenharmony_ci		 * Transfer size less than 64K can be handled with one paRAM
113462306a36Sopenharmony_ci		 * slot and with one burst.
113562306a36Sopenharmony_ci		 * ACNT = length
113662306a36Sopenharmony_ci		 */
113762306a36Sopenharmony_ci		width = len;
113862306a36Sopenharmony_ci		pset_len = len;
113962306a36Sopenharmony_ci		nslots = 1;
114062306a36Sopenharmony_ci	} else {
114162306a36Sopenharmony_ci		/*
114262306a36Sopenharmony_ci		 * Transfer size bigger than 64K will be handled with maximum of
114362306a36Sopenharmony_ci		 * two paRAM slots.
114462306a36Sopenharmony_ci		 * slot1: (full_length / 32767) times 32767 bytes bursts.
114562306a36Sopenharmony_ci		 *	  ACNT = 32767, length1: (full_length / 32767) * 32767
114662306a36Sopenharmony_ci		 * slot2: the remaining amount of data after slot1.
114762306a36Sopenharmony_ci		 *	  ACNT = full_length - length1, length2 = ACNT
114862306a36Sopenharmony_ci		 *
114962306a36Sopenharmony_ci		 * When the full_length is a multiple of 32767 one slot can be
115062306a36Sopenharmony_ci		 * used to complete the transfer.
115162306a36Sopenharmony_ci		 */
115262306a36Sopenharmony_ci		width = array_size;
115362306a36Sopenharmony_ci		pset_len = rounddown(len, width);
115462306a36Sopenharmony_ci		/* One slot is enough for lengths multiple of (SZ_32K -1) */
115562306a36Sopenharmony_ci		if (unlikely(pset_len == len))
115662306a36Sopenharmony_ci			nslots = 1;
115762306a36Sopenharmony_ci		else
115862306a36Sopenharmony_ci			nslots = 2;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC);
116262306a36Sopenharmony_ci	if (!edesc)
116362306a36Sopenharmony_ci		return NULL;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	edesc->pset_nr = nslots;
116662306a36Sopenharmony_ci	edesc->residue = edesc->residue_stat = len;
116762306a36Sopenharmony_ci	edesc->direction = DMA_MEM_TO_MEM;
116862306a36Sopenharmony_ci	edesc->echan = echan;
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	ret = edma_config_pset(chan, &edesc->pset[0], src, dest, 1,
117162306a36Sopenharmony_ci			       width, pset_len, DMA_MEM_TO_MEM);
117262306a36Sopenharmony_ci	if (ret < 0) {
117362306a36Sopenharmony_ci		kfree(edesc);
117462306a36Sopenharmony_ci		return NULL;
117562306a36Sopenharmony_ci	}
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	edesc->absync = ret;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	edesc->pset[0].param.opt |= ITCCHEN;
118062306a36Sopenharmony_ci	if (nslots == 1) {
118162306a36Sopenharmony_ci		/* Enable transfer complete interrupt if requested */
118262306a36Sopenharmony_ci		if (tx_flags & DMA_PREP_INTERRUPT)
118362306a36Sopenharmony_ci			edesc->pset[0].param.opt |= TCINTEN;
118462306a36Sopenharmony_ci	} else {
118562306a36Sopenharmony_ci		/* Enable transfer complete chaining for the first slot */
118662306a36Sopenharmony_ci		edesc->pset[0].param.opt |= TCCHEN;
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci		if (echan->slot[1] < 0) {
118962306a36Sopenharmony_ci			echan->slot[1] = edma_alloc_slot(echan->ecc,
119062306a36Sopenharmony_ci							 EDMA_SLOT_ANY);
119162306a36Sopenharmony_ci			if (echan->slot[1] < 0) {
119262306a36Sopenharmony_ci				kfree(edesc);
119362306a36Sopenharmony_ci				dev_err(dev, "%s: Failed to allocate slot\n",
119462306a36Sopenharmony_ci					__func__);
119562306a36Sopenharmony_ci				return NULL;
119662306a36Sopenharmony_ci			}
119762306a36Sopenharmony_ci		}
119862306a36Sopenharmony_ci		dest += pset_len;
119962306a36Sopenharmony_ci		src += pset_len;
120062306a36Sopenharmony_ci		pset_len = width = len % array_size;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci		ret = edma_config_pset(chan, &edesc->pset[1], src, dest, 1,
120362306a36Sopenharmony_ci				       width, pset_len, DMA_MEM_TO_MEM);
120462306a36Sopenharmony_ci		if (ret < 0) {
120562306a36Sopenharmony_ci			kfree(edesc);
120662306a36Sopenharmony_ci			return NULL;
120762306a36Sopenharmony_ci		}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci		edesc->pset[1].param.opt |= ITCCHEN;
121062306a36Sopenharmony_ci		/* Enable transfer complete interrupt if requested */
121162306a36Sopenharmony_ci		if (tx_flags & DMA_PREP_INTERRUPT)
121262306a36Sopenharmony_ci			edesc->pset[1].param.opt |= TCINTEN;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	if (!(tx_flags & DMA_PREP_INTERRUPT))
121662306a36Sopenharmony_ci		edesc->polled = true;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
121962306a36Sopenharmony_ci}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
122262306a36Sopenharmony_ciedma_prep_dma_interleaved(struct dma_chan *chan,
122362306a36Sopenharmony_ci			  struct dma_interleaved_template *xt,
122462306a36Sopenharmony_ci			  unsigned long tx_flags)
122562306a36Sopenharmony_ci{
122662306a36Sopenharmony_ci	struct device *dev = chan->device->dev;
122762306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
122862306a36Sopenharmony_ci	struct edmacc_param *param;
122962306a36Sopenharmony_ci	struct edma_desc *edesc;
123062306a36Sopenharmony_ci	size_t src_icg, dst_icg;
123162306a36Sopenharmony_ci	int src_bidx, dst_bidx;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	/* Slave mode is not supported */
123462306a36Sopenharmony_ci	if (is_slave_direction(xt->dir))
123562306a36Sopenharmony_ci		return NULL;
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	if (xt->frame_size != 1 || xt->numf == 0)
123862306a36Sopenharmony_ci		return NULL;
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (xt->sgl[0].size > SZ_64K || xt->numf > SZ_64K)
124162306a36Sopenharmony_ci		return NULL;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]);
124462306a36Sopenharmony_ci	if (src_icg) {
124562306a36Sopenharmony_ci		src_bidx = src_icg + xt->sgl[0].size;
124662306a36Sopenharmony_ci	} else if (xt->src_inc) {
124762306a36Sopenharmony_ci		src_bidx = xt->sgl[0].size;
124862306a36Sopenharmony_ci	} else {
124962306a36Sopenharmony_ci		dev_err(dev, "%s: SRC constant addressing is not supported\n",
125062306a36Sopenharmony_ci			__func__);
125162306a36Sopenharmony_ci		return NULL;
125262306a36Sopenharmony_ci	}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]);
125562306a36Sopenharmony_ci	if (dst_icg) {
125662306a36Sopenharmony_ci		dst_bidx = dst_icg + xt->sgl[0].size;
125762306a36Sopenharmony_ci	} else if (xt->dst_inc) {
125862306a36Sopenharmony_ci		dst_bidx = xt->sgl[0].size;
125962306a36Sopenharmony_ci	} else {
126062306a36Sopenharmony_ci		dev_err(dev, "%s: DST constant addressing is not supported\n",
126162306a36Sopenharmony_ci			__func__);
126262306a36Sopenharmony_ci		return NULL;
126362306a36Sopenharmony_ci	}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	if (src_bidx > SZ_64K || dst_bidx > SZ_64K)
126662306a36Sopenharmony_ci		return NULL;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	edesc = kzalloc(struct_size(edesc, pset, 1), GFP_ATOMIC);
126962306a36Sopenharmony_ci	if (!edesc)
127062306a36Sopenharmony_ci		return NULL;
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	edesc->direction = DMA_MEM_TO_MEM;
127362306a36Sopenharmony_ci	edesc->echan = echan;
127462306a36Sopenharmony_ci	edesc->pset_nr = 1;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	param = &edesc->pset[0].param;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	param->src = xt->src_start;
127962306a36Sopenharmony_ci	param->dst = xt->dst_start;
128062306a36Sopenharmony_ci	param->a_b_cnt = xt->numf << 16 | xt->sgl[0].size;
128162306a36Sopenharmony_ci	param->ccnt = 1;
128262306a36Sopenharmony_ci	param->src_dst_bidx = (dst_bidx << 16) | src_bidx;
128362306a36Sopenharmony_ci	param->src_dst_cidx = 0;
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num));
128662306a36Sopenharmony_ci	param->opt |= ITCCHEN;
128762306a36Sopenharmony_ci	/* Enable transfer complete interrupt if requested */
128862306a36Sopenharmony_ci	if (tx_flags & DMA_PREP_INTERRUPT)
128962306a36Sopenharmony_ci		param->opt |= TCINTEN;
129062306a36Sopenharmony_ci	else
129162306a36Sopenharmony_ci		edesc->polled = true;
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
129762306a36Sopenharmony_ci	struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
129862306a36Sopenharmony_ci	size_t period_len, enum dma_transfer_direction direction,
129962306a36Sopenharmony_ci	unsigned long tx_flags)
130062306a36Sopenharmony_ci{
130162306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
130262306a36Sopenharmony_ci	struct device *dev = chan->device->dev;
130362306a36Sopenharmony_ci	struct edma_desc *edesc;
130462306a36Sopenharmony_ci	dma_addr_t src_addr, dst_addr;
130562306a36Sopenharmony_ci	enum dma_slave_buswidth dev_width;
130662306a36Sopenharmony_ci	bool use_intermediate = false;
130762306a36Sopenharmony_ci	u32 burst;
130862306a36Sopenharmony_ci	int i, ret, nslots;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (unlikely(!echan || !buf_len || !period_len))
131162306a36Sopenharmony_ci		return NULL;
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci	if (direction == DMA_DEV_TO_MEM) {
131462306a36Sopenharmony_ci		src_addr = echan->cfg.src_addr;
131562306a36Sopenharmony_ci		dst_addr = buf_addr;
131662306a36Sopenharmony_ci		dev_width = echan->cfg.src_addr_width;
131762306a36Sopenharmony_ci		burst = echan->cfg.src_maxburst;
131862306a36Sopenharmony_ci	} else if (direction == DMA_MEM_TO_DEV) {
131962306a36Sopenharmony_ci		src_addr = buf_addr;
132062306a36Sopenharmony_ci		dst_addr = echan->cfg.dst_addr;
132162306a36Sopenharmony_ci		dev_width = echan->cfg.dst_addr_width;
132262306a36Sopenharmony_ci		burst = echan->cfg.dst_maxburst;
132362306a36Sopenharmony_ci	} else {
132462306a36Sopenharmony_ci		dev_err(dev, "%s: bad direction: %d\n", __func__, direction);
132562306a36Sopenharmony_ci		return NULL;
132662306a36Sopenharmony_ci	}
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) {
132962306a36Sopenharmony_ci		dev_err(dev, "%s: Undefined slave buswidth\n", __func__);
133062306a36Sopenharmony_ci		return NULL;
133162306a36Sopenharmony_ci	}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (unlikely(buf_len % period_len)) {
133462306a36Sopenharmony_ci		dev_err(dev, "Period should be multiple of Buffer length\n");
133562306a36Sopenharmony_ci		return NULL;
133662306a36Sopenharmony_ci	}
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	nslots = (buf_len / period_len) + 1;
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/*
134162306a36Sopenharmony_ci	 * Cyclic DMA users such as audio cannot tolerate delays introduced
134262306a36Sopenharmony_ci	 * by cases where the number of periods is more than the maximum
134362306a36Sopenharmony_ci	 * number of SGs the EDMA driver can handle at a time. For DMA types
134462306a36Sopenharmony_ci	 * such as Slave SGs, such delays are tolerable and synchronized,
134562306a36Sopenharmony_ci	 * but the synchronization is difficult to achieve with Cyclic and
134662306a36Sopenharmony_ci	 * cannot be guaranteed, so we error out early.
134762306a36Sopenharmony_ci	 */
134862306a36Sopenharmony_ci	if (nslots > MAX_NR_SG) {
134962306a36Sopenharmony_ci		/*
135062306a36Sopenharmony_ci		 * If the burst and period sizes are the same, we can put
135162306a36Sopenharmony_ci		 * the full buffer into a single period and activate
135262306a36Sopenharmony_ci		 * intermediate interrupts. This will produce interrupts
135362306a36Sopenharmony_ci		 * after each burst, which is also after each desired period.
135462306a36Sopenharmony_ci		 */
135562306a36Sopenharmony_ci		if (burst == period_len) {
135662306a36Sopenharmony_ci			period_len = buf_len;
135762306a36Sopenharmony_ci			nslots = 2;
135862306a36Sopenharmony_ci			use_intermediate = true;
135962306a36Sopenharmony_ci		} else {
136062306a36Sopenharmony_ci			return NULL;
136162306a36Sopenharmony_ci		}
136262306a36Sopenharmony_ci	}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC);
136562306a36Sopenharmony_ci	if (!edesc)
136662306a36Sopenharmony_ci		return NULL;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	edesc->cyclic = 1;
136962306a36Sopenharmony_ci	edesc->pset_nr = nslots;
137062306a36Sopenharmony_ci	edesc->residue = edesc->residue_stat = buf_len;
137162306a36Sopenharmony_ci	edesc->direction = direction;
137262306a36Sopenharmony_ci	edesc->echan = echan;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	dev_dbg(dev, "%s: channel=%d nslots=%d period_len=%zu buf_len=%zu\n",
137562306a36Sopenharmony_ci		__func__, echan->ch_num, nslots, period_len, buf_len);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	for (i = 0; i < nslots; i++) {
137862306a36Sopenharmony_ci		/* Allocate a PaRAM slot, if needed */
137962306a36Sopenharmony_ci		if (echan->slot[i] < 0) {
138062306a36Sopenharmony_ci			echan->slot[i] =
138162306a36Sopenharmony_ci				edma_alloc_slot(echan->ecc, EDMA_SLOT_ANY);
138262306a36Sopenharmony_ci			if (echan->slot[i] < 0) {
138362306a36Sopenharmony_ci				kfree(edesc);
138462306a36Sopenharmony_ci				dev_err(dev, "%s: Failed to allocate slot\n",
138562306a36Sopenharmony_ci					__func__);
138662306a36Sopenharmony_ci				return NULL;
138762306a36Sopenharmony_ci			}
138862306a36Sopenharmony_ci		}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci		if (i == nslots - 1) {
139162306a36Sopenharmony_ci			memcpy(&edesc->pset[i], &edesc->pset[0],
139262306a36Sopenharmony_ci			       sizeof(edesc->pset[0]));
139362306a36Sopenharmony_ci			break;
139462306a36Sopenharmony_ci		}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ci		ret = edma_config_pset(chan, &edesc->pset[i], src_addr,
139762306a36Sopenharmony_ci				       dst_addr, burst, dev_width, period_len,
139862306a36Sopenharmony_ci				       direction);
139962306a36Sopenharmony_ci		if (ret < 0) {
140062306a36Sopenharmony_ci			kfree(edesc);
140162306a36Sopenharmony_ci			return NULL;
140262306a36Sopenharmony_ci		}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci		if (direction == DMA_DEV_TO_MEM)
140562306a36Sopenharmony_ci			dst_addr += period_len;
140662306a36Sopenharmony_ci		else
140762306a36Sopenharmony_ci			src_addr += period_len;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		dev_vdbg(dev, "%s: Configure period %d of buf:\n", __func__, i);
141062306a36Sopenharmony_ci		dev_vdbg(dev,
141162306a36Sopenharmony_ci			"\n pset[%d]:\n"
141262306a36Sopenharmony_ci			"  chnum\t%d\n"
141362306a36Sopenharmony_ci			"  slot\t%d\n"
141462306a36Sopenharmony_ci			"  opt\t%08x\n"
141562306a36Sopenharmony_ci			"  src\t%08x\n"
141662306a36Sopenharmony_ci			"  dst\t%08x\n"
141762306a36Sopenharmony_ci			"  abcnt\t%08x\n"
141862306a36Sopenharmony_ci			"  ccnt\t%08x\n"
141962306a36Sopenharmony_ci			"  bidx\t%08x\n"
142062306a36Sopenharmony_ci			"  cidx\t%08x\n"
142162306a36Sopenharmony_ci			"  lkrld\t%08x\n",
142262306a36Sopenharmony_ci			i, echan->ch_num, echan->slot[i],
142362306a36Sopenharmony_ci			edesc->pset[i].param.opt,
142462306a36Sopenharmony_ci			edesc->pset[i].param.src,
142562306a36Sopenharmony_ci			edesc->pset[i].param.dst,
142662306a36Sopenharmony_ci			edesc->pset[i].param.a_b_cnt,
142762306a36Sopenharmony_ci			edesc->pset[i].param.ccnt,
142862306a36Sopenharmony_ci			edesc->pset[i].param.src_dst_bidx,
142962306a36Sopenharmony_ci			edesc->pset[i].param.src_dst_cidx,
143062306a36Sopenharmony_ci			edesc->pset[i].param.link_bcntrld);
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci		edesc->absync = ret;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci		/*
143562306a36Sopenharmony_ci		 * Enable period interrupt only if it is requested
143662306a36Sopenharmony_ci		 */
143762306a36Sopenharmony_ci		if (tx_flags & DMA_PREP_INTERRUPT) {
143862306a36Sopenharmony_ci			edesc->pset[i].param.opt |= TCINTEN;
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci			/* Also enable intermediate interrupts if necessary */
144162306a36Sopenharmony_ci			if (use_intermediate)
144262306a36Sopenharmony_ci				edesc->pset[i].param.opt |= ITCINTEN;
144362306a36Sopenharmony_ci		}
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	/* Place the cyclic channel to highest priority queue */
144762306a36Sopenharmony_ci	if (!echan->tc)
144862306a36Sopenharmony_ci		edma_assign_channel_eventq(echan, EVENTQ_0);
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
145162306a36Sopenharmony_ci}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_cistatic void edma_completion_handler(struct edma_chan *echan)
145462306a36Sopenharmony_ci{
145562306a36Sopenharmony_ci	struct device *dev = echan->vchan.chan.device->dev;
145662306a36Sopenharmony_ci	struct edma_desc *edesc;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci	spin_lock(&echan->vchan.lock);
145962306a36Sopenharmony_ci	edesc = echan->edesc;
146062306a36Sopenharmony_ci	if (edesc) {
146162306a36Sopenharmony_ci		if (edesc->cyclic) {
146262306a36Sopenharmony_ci			vchan_cyclic_callback(&edesc->vdesc);
146362306a36Sopenharmony_ci			spin_unlock(&echan->vchan.lock);
146462306a36Sopenharmony_ci			return;
146562306a36Sopenharmony_ci		} else if (edesc->processed == edesc->pset_nr) {
146662306a36Sopenharmony_ci			edesc->residue = 0;
146762306a36Sopenharmony_ci			edma_stop(echan);
146862306a36Sopenharmony_ci			vchan_cookie_complete(&edesc->vdesc);
146962306a36Sopenharmony_ci			echan->edesc = NULL;
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci			dev_dbg(dev, "Transfer completed on channel %d\n",
147262306a36Sopenharmony_ci				echan->ch_num);
147362306a36Sopenharmony_ci		} else {
147462306a36Sopenharmony_ci			dev_dbg(dev, "Sub transfer completed on channel %d\n",
147562306a36Sopenharmony_ci				echan->ch_num);
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci			edma_pause(echan);
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci			/* Update statistics for tx_status */
148062306a36Sopenharmony_ci			edesc->residue -= edesc->sg_len;
148162306a36Sopenharmony_ci			edesc->residue_stat = edesc->residue;
148262306a36Sopenharmony_ci			edesc->processed_stat = edesc->processed;
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci		edma_execute(echan);
148562306a36Sopenharmony_ci	}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	spin_unlock(&echan->vchan.lock);
148862306a36Sopenharmony_ci}
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci/* eDMA interrupt handler */
149162306a36Sopenharmony_cistatic irqreturn_t dma_irq_handler(int irq, void *data)
149262306a36Sopenharmony_ci{
149362306a36Sopenharmony_ci	struct edma_cc *ecc = data;
149462306a36Sopenharmony_ci	int ctlr;
149562306a36Sopenharmony_ci	u32 sh_ier;
149662306a36Sopenharmony_ci	u32 sh_ipr;
149762306a36Sopenharmony_ci	u32 bank;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	ctlr = ecc->id;
150062306a36Sopenharmony_ci	if (ctlr < 0)
150162306a36Sopenharmony_ci		return IRQ_NONE;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	dev_vdbg(ecc->dev, "dma_irq_handler\n");
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci	sh_ipr = edma_shadow0_read_array(ecc, SH_IPR, 0);
150662306a36Sopenharmony_ci	if (!sh_ipr) {
150762306a36Sopenharmony_ci		sh_ipr = edma_shadow0_read_array(ecc, SH_IPR, 1);
150862306a36Sopenharmony_ci		if (!sh_ipr)
150962306a36Sopenharmony_ci			return IRQ_NONE;
151062306a36Sopenharmony_ci		sh_ier = edma_shadow0_read_array(ecc, SH_IER, 1);
151162306a36Sopenharmony_ci		bank = 1;
151262306a36Sopenharmony_ci	} else {
151362306a36Sopenharmony_ci		sh_ier = edma_shadow0_read_array(ecc, SH_IER, 0);
151462306a36Sopenharmony_ci		bank = 0;
151562306a36Sopenharmony_ci	}
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	do {
151862306a36Sopenharmony_ci		u32 slot;
151962306a36Sopenharmony_ci		u32 channel;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		slot = __ffs(sh_ipr);
152262306a36Sopenharmony_ci		sh_ipr &= ~(BIT(slot));
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci		if (sh_ier & BIT(slot)) {
152562306a36Sopenharmony_ci			channel = (bank << 5) | slot;
152662306a36Sopenharmony_ci			/* Clear the corresponding IPR bits */
152762306a36Sopenharmony_ci			edma_shadow0_write_array(ecc, SH_ICR, bank, BIT(slot));
152862306a36Sopenharmony_ci			edma_completion_handler(&ecc->slave_chans[channel]);
152962306a36Sopenharmony_ci		}
153062306a36Sopenharmony_ci	} while (sh_ipr);
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	edma_shadow0_write(ecc, SH_IEVAL, 1);
153362306a36Sopenharmony_ci	return IRQ_HANDLED;
153462306a36Sopenharmony_ci}
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_cistatic void edma_error_handler(struct edma_chan *echan)
153762306a36Sopenharmony_ci{
153862306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
153962306a36Sopenharmony_ci	struct device *dev = echan->vchan.chan.device->dev;
154062306a36Sopenharmony_ci	struct edmacc_param p;
154162306a36Sopenharmony_ci	int err;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	if (!echan->edesc)
154462306a36Sopenharmony_ci		return;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	spin_lock(&echan->vchan.lock);
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	err = edma_read_slot(ecc, echan->slot[0], &p);
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	/*
155162306a36Sopenharmony_ci	 * Issue later based on missed flag which will be sure
155262306a36Sopenharmony_ci	 * to happen as:
155362306a36Sopenharmony_ci	 * (1) we finished transmitting an intermediate slot and
155462306a36Sopenharmony_ci	 *     edma_execute is coming up.
155562306a36Sopenharmony_ci	 * (2) or we finished current transfer and issue will
155662306a36Sopenharmony_ci	 *     call edma_execute.
155762306a36Sopenharmony_ci	 *
155862306a36Sopenharmony_ci	 * Important note: issuing can be dangerous here and
155962306a36Sopenharmony_ci	 * lead to some nasty recursion when we are in a NULL
156062306a36Sopenharmony_ci	 * slot. So we avoid doing so and set the missed flag.
156162306a36Sopenharmony_ci	 */
156262306a36Sopenharmony_ci	if (err || (p.a_b_cnt == 0 && p.ccnt == 0)) {
156362306a36Sopenharmony_ci		dev_dbg(dev, "Error on null slot, setting miss\n");
156462306a36Sopenharmony_ci		echan->missed = 1;
156562306a36Sopenharmony_ci	} else {
156662306a36Sopenharmony_ci		/*
156762306a36Sopenharmony_ci		 * The slot is already programmed but the event got
156862306a36Sopenharmony_ci		 * missed, so its safe to issue it here.
156962306a36Sopenharmony_ci		 */
157062306a36Sopenharmony_ci		dev_dbg(dev, "Missed event, TRIGGERING\n");
157162306a36Sopenharmony_ci		edma_clean_channel(echan);
157262306a36Sopenharmony_ci		edma_stop(echan);
157362306a36Sopenharmony_ci		edma_start(echan);
157462306a36Sopenharmony_ci		edma_trigger_channel(echan);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci	spin_unlock(&echan->vchan.lock);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic inline bool edma_error_pending(struct edma_cc *ecc)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	if (edma_read_array(ecc, EDMA_EMR, 0) ||
158262306a36Sopenharmony_ci	    edma_read_array(ecc, EDMA_EMR, 1) ||
158362306a36Sopenharmony_ci	    edma_read(ecc, EDMA_QEMR) || edma_read(ecc, EDMA_CCERR))
158462306a36Sopenharmony_ci		return true;
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	return false;
158762306a36Sopenharmony_ci}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci/* eDMA error interrupt handler */
159062306a36Sopenharmony_cistatic irqreturn_t dma_ccerr_handler(int irq, void *data)
159162306a36Sopenharmony_ci{
159262306a36Sopenharmony_ci	struct edma_cc *ecc = data;
159362306a36Sopenharmony_ci	int i, j;
159462306a36Sopenharmony_ci	int ctlr;
159562306a36Sopenharmony_ci	unsigned int cnt = 0;
159662306a36Sopenharmony_ci	unsigned int val;
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	ctlr = ecc->id;
159962306a36Sopenharmony_ci	if (ctlr < 0)
160062306a36Sopenharmony_ci		return IRQ_NONE;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	dev_vdbg(ecc->dev, "dma_ccerr_handler\n");
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	if (!edma_error_pending(ecc)) {
160562306a36Sopenharmony_ci		/*
160662306a36Sopenharmony_ci		 * The registers indicate no pending error event but the irq
160762306a36Sopenharmony_ci		 * handler has been called.
160862306a36Sopenharmony_ci		 * Ask eDMA to re-evaluate the error registers.
160962306a36Sopenharmony_ci		 */
161062306a36Sopenharmony_ci		dev_err(ecc->dev, "%s: Error interrupt without error event!\n",
161162306a36Sopenharmony_ci			__func__);
161262306a36Sopenharmony_ci		edma_write(ecc, EDMA_EEVAL, 1);
161362306a36Sopenharmony_ci		return IRQ_NONE;
161462306a36Sopenharmony_ci	}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci	while (1) {
161762306a36Sopenharmony_ci		/* Event missed register(s) */
161862306a36Sopenharmony_ci		for (j = 0; j < 2; j++) {
161962306a36Sopenharmony_ci			unsigned long emr;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci			val = edma_read_array(ecc, EDMA_EMR, j);
162262306a36Sopenharmony_ci			if (!val)
162362306a36Sopenharmony_ci				continue;
162462306a36Sopenharmony_ci
162562306a36Sopenharmony_ci			dev_dbg(ecc->dev, "EMR%d 0x%08x\n", j, val);
162662306a36Sopenharmony_ci			emr = val;
162762306a36Sopenharmony_ci			for_each_set_bit(i, &emr, 32) {
162862306a36Sopenharmony_ci				int k = (j << 5) + i;
162962306a36Sopenharmony_ci
163062306a36Sopenharmony_ci				/* Clear the corresponding EMR bits */
163162306a36Sopenharmony_ci				edma_write_array(ecc, EDMA_EMCR, j, BIT(i));
163262306a36Sopenharmony_ci				/* Clear any SER */
163362306a36Sopenharmony_ci				edma_shadow0_write_array(ecc, SH_SECR, j,
163462306a36Sopenharmony_ci							 BIT(i));
163562306a36Sopenharmony_ci				edma_error_handler(&ecc->slave_chans[k]);
163662306a36Sopenharmony_ci			}
163762306a36Sopenharmony_ci		}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_ci		val = edma_read(ecc, EDMA_QEMR);
164062306a36Sopenharmony_ci		if (val) {
164162306a36Sopenharmony_ci			dev_dbg(ecc->dev, "QEMR 0x%02x\n", val);
164262306a36Sopenharmony_ci			/* Not reported, just clear the interrupt reason. */
164362306a36Sopenharmony_ci			edma_write(ecc, EDMA_QEMCR, val);
164462306a36Sopenharmony_ci			edma_shadow0_write(ecc, SH_QSECR, val);
164562306a36Sopenharmony_ci		}
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		val = edma_read(ecc, EDMA_CCERR);
164862306a36Sopenharmony_ci		if (val) {
164962306a36Sopenharmony_ci			dev_warn(ecc->dev, "CCERR 0x%08x\n", val);
165062306a36Sopenharmony_ci			/* Not reported, just clear the interrupt reason. */
165162306a36Sopenharmony_ci			edma_write(ecc, EDMA_CCERRCLR, val);
165262306a36Sopenharmony_ci		}
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		if (!edma_error_pending(ecc))
165562306a36Sopenharmony_ci			break;
165662306a36Sopenharmony_ci		cnt++;
165762306a36Sopenharmony_ci		if (cnt > 10)
165862306a36Sopenharmony_ci			break;
165962306a36Sopenharmony_ci	}
166062306a36Sopenharmony_ci	edma_write(ecc, EDMA_EEVAL, 1);
166162306a36Sopenharmony_ci	return IRQ_HANDLED;
166262306a36Sopenharmony_ci}
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/* Alloc channel resources */
166562306a36Sopenharmony_cistatic int edma_alloc_chan_resources(struct dma_chan *chan)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
166862306a36Sopenharmony_ci	struct edma_cc *ecc = echan->ecc;
166962306a36Sopenharmony_ci	struct device *dev = ecc->dev;
167062306a36Sopenharmony_ci	enum dma_event_q eventq_no = EVENTQ_DEFAULT;
167162306a36Sopenharmony_ci	int ret;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	if (echan->tc) {
167462306a36Sopenharmony_ci		eventq_no = echan->tc->id;
167562306a36Sopenharmony_ci	} else if (ecc->tc_list) {
167662306a36Sopenharmony_ci		/* memcpy channel */
167762306a36Sopenharmony_ci		echan->tc = &ecc->tc_list[ecc->info->default_queue];
167862306a36Sopenharmony_ci		eventq_no = echan->tc->id;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	ret = edma_alloc_channel(echan, eventq_no);
168262306a36Sopenharmony_ci	if (ret)
168362306a36Sopenharmony_ci		return ret;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	echan->slot[0] = edma_alloc_slot(ecc, echan->ch_num);
168662306a36Sopenharmony_ci	if (echan->slot[0] < 0) {
168762306a36Sopenharmony_ci		dev_err(dev, "Entry slot allocation failed for channel %u\n",
168862306a36Sopenharmony_ci			EDMA_CHAN_SLOT(echan->ch_num));
168962306a36Sopenharmony_ci		ret = echan->slot[0];
169062306a36Sopenharmony_ci		goto err_slot;
169162306a36Sopenharmony_ci	}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_ci	/* Set up channel -> slot mapping for the entry slot */
169462306a36Sopenharmony_ci	edma_set_chmap(echan, echan->slot[0]);
169562306a36Sopenharmony_ci	echan->alloced = true;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	dev_dbg(dev, "Got eDMA channel %d for virt channel %d (%s trigger)\n",
169862306a36Sopenharmony_ci		EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id,
169962306a36Sopenharmony_ci		echan->hw_triggered ? "HW" : "SW");
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	return 0;
170262306a36Sopenharmony_ci
170362306a36Sopenharmony_cierr_slot:
170462306a36Sopenharmony_ci	edma_free_channel(echan);
170562306a36Sopenharmony_ci	return ret;
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci/* Free channel resources */
170962306a36Sopenharmony_cistatic void edma_free_chan_resources(struct dma_chan *chan)
171062306a36Sopenharmony_ci{
171162306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
171262306a36Sopenharmony_ci	struct device *dev = echan->ecc->dev;
171362306a36Sopenharmony_ci	int i;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	/* Terminate transfers */
171662306a36Sopenharmony_ci	edma_stop(echan);
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_ci	vchan_free_chan_resources(&echan->vchan);
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	/* Free EDMA PaRAM slots */
172162306a36Sopenharmony_ci	for (i = 0; i < EDMA_MAX_SLOTS; i++) {
172262306a36Sopenharmony_ci		if (echan->slot[i] >= 0) {
172362306a36Sopenharmony_ci			edma_free_slot(echan->ecc, echan->slot[i]);
172462306a36Sopenharmony_ci			echan->slot[i] = -1;
172562306a36Sopenharmony_ci		}
172662306a36Sopenharmony_ci	}
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	/* Set entry slot to the dummy slot */
172962306a36Sopenharmony_ci	edma_set_chmap(echan, echan->ecc->dummy_slot);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	/* Free EDMA channel */
173262306a36Sopenharmony_ci	if (echan->alloced) {
173362306a36Sopenharmony_ci		edma_free_channel(echan);
173462306a36Sopenharmony_ci		echan->alloced = false;
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	echan->tc = NULL;
173862306a36Sopenharmony_ci	echan->hw_triggered = false;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	dev_dbg(dev, "Free eDMA channel %d for virt channel %d\n",
174162306a36Sopenharmony_ci		EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id);
174262306a36Sopenharmony_ci}
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci/* Send pending descriptor to hardware */
174562306a36Sopenharmony_cistatic void edma_issue_pending(struct dma_chan *chan)
174662306a36Sopenharmony_ci{
174762306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
174862306a36Sopenharmony_ci	unsigned long flags;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	spin_lock_irqsave(&echan->vchan.lock, flags);
175162306a36Sopenharmony_ci	if (vchan_issue_pending(&echan->vchan) && !echan->edesc)
175262306a36Sopenharmony_ci		edma_execute(echan);
175362306a36Sopenharmony_ci	spin_unlock_irqrestore(&echan->vchan.lock, flags);
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci/*
175762306a36Sopenharmony_ci * This limit exists to avoid a possible infinite loop when waiting for proof
175862306a36Sopenharmony_ci * that a particular transfer is completed. This limit can be hit if there
175962306a36Sopenharmony_ci * are large bursts to/from slow devices or the CPU is never able to catch
176062306a36Sopenharmony_ci * the DMA hardware idle. On an AM335x transferring 48 bytes from the UART
176162306a36Sopenharmony_ci * RX-FIFO, as many as 55 loops have been seen.
176262306a36Sopenharmony_ci */
176362306a36Sopenharmony_ci#define EDMA_MAX_TR_WAIT_LOOPS 1000
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_cistatic u32 edma_residue(struct edma_desc *edesc)
176662306a36Sopenharmony_ci{
176762306a36Sopenharmony_ci	bool dst = edesc->direction == DMA_DEV_TO_MEM;
176862306a36Sopenharmony_ci	int loop_count = EDMA_MAX_TR_WAIT_LOOPS;
176962306a36Sopenharmony_ci	struct edma_chan *echan = edesc->echan;
177062306a36Sopenharmony_ci	struct edma_pset *pset = edesc->pset;
177162306a36Sopenharmony_ci	dma_addr_t done, pos, pos_old;
177262306a36Sopenharmony_ci	int channel = EDMA_CHAN_SLOT(echan->ch_num);
177362306a36Sopenharmony_ci	int idx = EDMA_REG_ARRAY_INDEX(channel);
177462306a36Sopenharmony_ci	int ch_bit = EDMA_CHANNEL_BIT(channel);
177562306a36Sopenharmony_ci	int event_reg;
177662306a36Sopenharmony_ci	int i;
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	/*
177962306a36Sopenharmony_ci	 * We always read the dst/src position from the first RamPar
178062306a36Sopenharmony_ci	 * pset. That's the one which is active now.
178162306a36Sopenharmony_ci	 */
178262306a36Sopenharmony_ci	pos = edma_get_position(echan->ecc, echan->slot[0], dst);
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	/*
178562306a36Sopenharmony_ci	 * "pos" may represent a transfer request that is still being
178662306a36Sopenharmony_ci	 * processed by the EDMACC or EDMATC. We will busy wait until
178762306a36Sopenharmony_ci	 * any one of the situations occurs:
178862306a36Sopenharmony_ci	 *   1. while and event is pending for the channel
178962306a36Sopenharmony_ci	 *   2. a position updated
179062306a36Sopenharmony_ci	 *   3. we hit the loop limit
179162306a36Sopenharmony_ci	 */
179262306a36Sopenharmony_ci	if (is_slave_direction(edesc->direction))
179362306a36Sopenharmony_ci		event_reg = SH_ER;
179462306a36Sopenharmony_ci	else
179562306a36Sopenharmony_ci		event_reg = SH_ESR;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	pos_old = pos;
179862306a36Sopenharmony_ci	while (edma_shadow0_read_array(echan->ecc, event_reg, idx) & ch_bit) {
179962306a36Sopenharmony_ci		pos = edma_get_position(echan->ecc, echan->slot[0], dst);
180062306a36Sopenharmony_ci		if (pos != pos_old)
180162306a36Sopenharmony_ci			break;
180262306a36Sopenharmony_ci
180362306a36Sopenharmony_ci		if (!--loop_count) {
180462306a36Sopenharmony_ci			dev_dbg_ratelimited(echan->vchan.chan.device->dev,
180562306a36Sopenharmony_ci				"%s: timeout waiting for PaRAM update\n",
180662306a36Sopenharmony_ci				__func__);
180762306a36Sopenharmony_ci			break;
180862306a36Sopenharmony_ci		}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci		cpu_relax();
181162306a36Sopenharmony_ci	}
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	/*
181462306a36Sopenharmony_ci	 * Cyclic is simple. Just subtract pset[0].addr from pos.
181562306a36Sopenharmony_ci	 *
181662306a36Sopenharmony_ci	 * We never update edesc->residue in the cyclic case, so we
181762306a36Sopenharmony_ci	 * can tell the remaining room to the end of the circular
181862306a36Sopenharmony_ci	 * buffer.
181962306a36Sopenharmony_ci	 */
182062306a36Sopenharmony_ci	if (edesc->cyclic) {
182162306a36Sopenharmony_ci		done = pos - pset->addr;
182262306a36Sopenharmony_ci		edesc->residue_stat = edesc->residue - done;
182362306a36Sopenharmony_ci		return edesc->residue_stat;
182462306a36Sopenharmony_ci	}
182562306a36Sopenharmony_ci
182662306a36Sopenharmony_ci	/*
182762306a36Sopenharmony_ci	 * If the position is 0, then EDMA loaded the closing dummy slot, the
182862306a36Sopenharmony_ci	 * transfer is completed
182962306a36Sopenharmony_ci	 */
183062306a36Sopenharmony_ci	if (!pos)
183162306a36Sopenharmony_ci		return 0;
183262306a36Sopenharmony_ci	/*
183362306a36Sopenharmony_ci	 * For SG operation we catch up with the last processed
183462306a36Sopenharmony_ci	 * status.
183562306a36Sopenharmony_ci	 */
183662306a36Sopenharmony_ci	pset += edesc->processed_stat;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	for (i = edesc->processed_stat; i < edesc->processed; i++, pset++) {
183962306a36Sopenharmony_ci		/*
184062306a36Sopenharmony_ci		 * If we are inside this pset address range, we know
184162306a36Sopenharmony_ci		 * this is the active one. Get the current delta and
184262306a36Sopenharmony_ci		 * stop walking the psets.
184362306a36Sopenharmony_ci		 */
184462306a36Sopenharmony_ci		if (pos >= pset->addr && pos < pset->addr + pset->len)
184562306a36Sopenharmony_ci			return edesc->residue_stat - (pos - pset->addr);
184662306a36Sopenharmony_ci
184762306a36Sopenharmony_ci		/* Otherwise mark it done and update residue_stat. */
184862306a36Sopenharmony_ci		edesc->processed_stat++;
184962306a36Sopenharmony_ci		edesc->residue_stat -= pset->len;
185062306a36Sopenharmony_ci	}
185162306a36Sopenharmony_ci	return edesc->residue_stat;
185262306a36Sopenharmony_ci}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci/* Check request completion status */
185562306a36Sopenharmony_cistatic enum dma_status edma_tx_status(struct dma_chan *chan,
185662306a36Sopenharmony_ci				      dma_cookie_t cookie,
185762306a36Sopenharmony_ci				      struct dma_tx_state *txstate)
185862306a36Sopenharmony_ci{
185962306a36Sopenharmony_ci	struct edma_chan *echan = to_edma_chan(chan);
186062306a36Sopenharmony_ci	struct dma_tx_state txstate_tmp;
186162306a36Sopenharmony_ci	enum dma_status ret;
186262306a36Sopenharmony_ci	unsigned long flags;
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
186562306a36Sopenharmony_ci
186662306a36Sopenharmony_ci	if (ret == DMA_COMPLETE)
186762306a36Sopenharmony_ci		return ret;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	/* Provide a dummy dma_tx_state for completion checking */
187062306a36Sopenharmony_ci	if (!txstate)
187162306a36Sopenharmony_ci		txstate = &txstate_tmp;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci	spin_lock_irqsave(&echan->vchan.lock, flags);
187462306a36Sopenharmony_ci	if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) {
187562306a36Sopenharmony_ci		txstate->residue = edma_residue(echan->edesc);
187662306a36Sopenharmony_ci	} else {
187762306a36Sopenharmony_ci		struct virt_dma_desc *vdesc = vchan_find_desc(&echan->vchan,
187862306a36Sopenharmony_ci							      cookie);
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci		if (vdesc)
188162306a36Sopenharmony_ci			txstate->residue = to_edma_desc(&vdesc->tx)->residue;
188262306a36Sopenharmony_ci		else
188362306a36Sopenharmony_ci			txstate->residue = 0;
188462306a36Sopenharmony_ci	}
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	/*
188762306a36Sopenharmony_ci	 * Mark the cookie completed if the residue is 0 for non cyclic
188862306a36Sopenharmony_ci	 * transfers
188962306a36Sopenharmony_ci	 */
189062306a36Sopenharmony_ci	if (ret != DMA_COMPLETE && !txstate->residue &&
189162306a36Sopenharmony_ci	    echan->edesc && echan->edesc->polled &&
189262306a36Sopenharmony_ci	    echan->edesc->vdesc.tx.cookie == cookie) {
189362306a36Sopenharmony_ci		edma_stop(echan);
189462306a36Sopenharmony_ci		vchan_cookie_complete(&echan->edesc->vdesc);
189562306a36Sopenharmony_ci		echan->edesc = NULL;
189662306a36Sopenharmony_ci		edma_execute(echan);
189762306a36Sopenharmony_ci		ret = DMA_COMPLETE;
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	spin_unlock_irqrestore(&echan->vchan.lock, flags);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	return ret;
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_cistatic bool edma_is_memcpy_channel(int ch_num, s32 *memcpy_channels)
190662306a36Sopenharmony_ci{
190762306a36Sopenharmony_ci	if (!memcpy_channels)
190862306a36Sopenharmony_ci		return false;
190962306a36Sopenharmony_ci	while (*memcpy_channels != -1) {
191062306a36Sopenharmony_ci		if (*memcpy_channels == ch_num)
191162306a36Sopenharmony_ci			return true;
191262306a36Sopenharmony_ci		memcpy_channels++;
191362306a36Sopenharmony_ci	}
191462306a36Sopenharmony_ci	return false;
191562306a36Sopenharmony_ci}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci#define EDMA_DMA_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
191862306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
191962306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
192062306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
192162306a36Sopenharmony_ci
192262306a36Sopenharmony_cistatic void edma_dma_init(struct edma_cc *ecc, bool legacy_mode)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	struct dma_device *s_ddev = &ecc->dma_slave;
192562306a36Sopenharmony_ci	struct dma_device *m_ddev = NULL;
192662306a36Sopenharmony_ci	s32 *memcpy_channels = ecc->info->memcpy_channels;
192762306a36Sopenharmony_ci	int i, j;
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	dma_cap_zero(s_ddev->cap_mask);
193062306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, s_ddev->cap_mask);
193162306a36Sopenharmony_ci	dma_cap_set(DMA_CYCLIC, s_ddev->cap_mask);
193262306a36Sopenharmony_ci	if (ecc->legacy_mode && !memcpy_channels) {
193362306a36Sopenharmony_ci		dev_warn(ecc->dev,
193462306a36Sopenharmony_ci			 "Legacy memcpy is enabled, things might not work\n");
193562306a36Sopenharmony_ci
193662306a36Sopenharmony_ci		dma_cap_set(DMA_MEMCPY, s_ddev->cap_mask);
193762306a36Sopenharmony_ci		dma_cap_set(DMA_INTERLEAVE, s_ddev->cap_mask);
193862306a36Sopenharmony_ci		s_ddev->device_prep_dma_memcpy = edma_prep_dma_memcpy;
193962306a36Sopenharmony_ci		s_ddev->device_prep_interleaved_dma = edma_prep_dma_interleaved;
194062306a36Sopenharmony_ci		s_ddev->directions = BIT(DMA_MEM_TO_MEM);
194162306a36Sopenharmony_ci	}
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	s_ddev->device_prep_slave_sg = edma_prep_slave_sg;
194462306a36Sopenharmony_ci	s_ddev->device_prep_dma_cyclic = edma_prep_dma_cyclic;
194562306a36Sopenharmony_ci	s_ddev->device_alloc_chan_resources = edma_alloc_chan_resources;
194662306a36Sopenharmony_ci	s_ddev->device_free_chan_resources = edma_free_chan_resources;
194762306a36Sopenharmony_ci	s_ddev->device_issue_pending = edma_issue_pending;
194862306a36Sopenharmony_ci	s_ddev->device_tx_status = edma_tx_status;
194962306a36Sopenharmony_ci	s_ddev->device_config = edma_slave_config;
195062306a36Sopenharmony_ci	s_ddev->device_pause = edma_dma_pause;
195162306a36Sopenharmony_ci	s_ddev->device_resume = edma_dma_resume;
195262306a36Sopenharmony_ci	s_ddev->device_terminate_all = edma_terminate_all;
195362306a36Sopenharmony_ci	s_ddev->device_synchronize = edma_synchronize;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	s_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS;
195662306a36Sopenharmony_ci	s_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS;
195762306a36Sopenharmony_ci	s_ddev->directions |= (BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV));
195862306a36Sopenharmony_ci	s_ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
195962306a36Sopenharmony_ci	s_ddev->max_burst = SZ_32K - 1; /* CIDX: 16bit signed */
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci	s_ddev->dev = ecc->dev;
196262306a36Sopenharmony_ci	INIT_LIST_HEAD(&s_ddev->channels);
196362306a36Sopenharmony_ci
196462306a36Sopenharmony_ci	if (memcpy_channels) {
196562306a36Sopenharmony_ci		m_ddev = devm_kzalloc(ecc->dev, sizeof(*m_ddev), GFP_KERNEL);
196662306a36Sopenharmony_ci		if (!m_ddev) {
196762306a36Sopenharmony_ci			dev_warn(ecc->dev, "memcpy is disabled due to OoM\n");
196862306a36Sopenharmony_ci			memcpy_channels = NULL;
196962306a36Sopenharmony_ci			goto ch_setup;
197062306a36Sopenharmony_ci		}
197162306a36Sopenharmony_ci		ecc->dma_memcpy = m_ddev;
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		dma_cap_zero(m_ddev->cap_mask);
197462306a36Sopenharmony_ci		dma_cap_set(DMA_MEMCPY, m_ddev->cap_mask);
197562306a36Sopenharmony_ci		dma_cap_set(DMA_INTERLEAVE, m_ddev->cap_mask);
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci		m_ddev->device_prep_dma_memcpy = edma_prep_dma_memcpy;
197862306a36Sopenharmony_ci		m_ddev->device_prep_interleaved_dma = edma_prep_dma_interleaved;
197962306a36Sopenharmony_ci		m_ddev->device_alloc_chan_resources = edma_alloc_chan_resources;
198062306a36Sopenharmony_ci		m_ddev->device_free_chan_resources = edma_free_chan_resources;
198162306a36Sopenharmony_ci		m_ddev->device_issue_pending = edma_issue_pending;
198262306a36Sopenharmony_ci		m_ddev->device_tx_status = edma_tx_status;
198362306a36Sopenharmony_ci		m_ddev->device_config = edma_slave_config;
198462306a36Sopenharmony_ci		m_ddev->device_pause = edma_dma_pause;
198562306a36Sopenharmony_ci		m_ddev->device_resume = edma_dma_resume;
198662306a36Sopenharmony_ci		m_ddev->device_terminate_all = edma_terminate_all;
198762306a36Sopenharmony_ci		m_ddev->device_synchronize = edma_synchronize;
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci		m_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS;
199062306a36Sopenharmony_ci		m_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS;
199162306a36Sopenharmony_ci		m_ddev->directions = BIT(DMA_MEM_TO_MEM);
199262306a36Sopenharmony_ci		m_ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci		m_ddev->dev = ecc->dev;
199562306a36Sopenharmony_ci		INIT_LIST_HEAD(&m_ddev->channels);
199662306a36Sopenharmony_ci	} else if (!ecc->legacy_mode) {
199762306a36Sopenharmony_ci		dev_info(ecc->dev, "memcpy is disabled\n");
199862306a36Sopenharmony_ci	}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_cich_setup:
200162306a36Sopenharmony_ci	for (i = 0; i < ecc->num_channels; i++) {
200262306a36Sopenharmony_ci		struct edma_chan *echan = &ecc->slave_chans[i];
200362306a36Sopenharmony_ci		echan->ch_num = EDMA_CTLR_CHAN(ecc->id, i);
200462306a36Sopenharmony_ci		echan->ecc = ecc;
200562306a36Sopenharmony_ci		echan->vchan.desc_free = edma_desc_free;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		if (m_ddev && edma_is_memcpy_channel(i, memcpy_channels))
200862306a36Sopenharmony_ci			vchan_init(&echan->vchan, m_ddev);
200962306a36Sopenharmony_ci		else
201062306a36Sopenharmony_ci			vchan_init(&echan->vchan, s_ddev);
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci		INIT_LIST_HEAD(&echan->node);
201362306a36Sopenharmony_ci		for (j = 0; j < EDMA_MAX_SLOTS; j++)
201462306a36Sopenharmony_ci			echan->slot[j] = -1;
201562306a36Sopenharmony_ci	}
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_cistatic int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata,
201962306a36Sopenharmony_ci			      struct edma_cc *ecc)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	int i;
202262306a36Sopenharmony_ci	u32 value, cccfg;
202362306a36Sopenharmony_ci	s8 (*queue_priority_map)[2];
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	/* Decode the eDMA3 configuration from CCCFG register */
202662306a36Sopenharmony_ci	cccfg = edma_read(ecc, EDMA_CCCFG);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	value = GET_NUM_REGN(cccfg);
202962306a36Sopenharmony_ci	ecc->num_region = BIT(value);
203062306a36Sopenharmony_ci
203162306a36Sopenharmony_ci	value = GET_NUM_DMACH(cccfg);
203262306a36Sopenharmony_ci	ecc->num_channels = BIT(value + 1);
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	value = GET_NUM_QDMACH(cccfg);
203562306a36Sopenharmony_ci	ecc->num_qchannels = value * 2;
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	value = GET_NUM_PAENTRY(cccfg);
203862306a36Sopenharmony_ci	ecc->num_slots = BIT(value + 4);
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	value = GET_NUM_EVQUE(cccfg);
204162306a36Sopenharmony_ci	ecc->num_tc = value + 1;
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	ecc->chmap_exist = (cccfg & CHMAP_EXIST) ? true : false;
204462306a36Sopenharmony_ci
204562306a36Sopenharmony_ci	dev_dbg(dev, "eDMA3 CC HW configuration (cccfg: 0x%08x):\n", cccfg);
204662306a36Sopenharmony_ci	dev_dbg(dev, "num_region: %u\n", ecc->num_region);
204762306a36Sopenharmony_ci	dev_dbg(dev, "num_channels: %u\n", ecc->num_channels);
204862306a36Sopenharmony_ci	dev_dbg(dev, "num_qchannels: %u\n", ecc->num_qchannels);
204962306a36Sopenharmony_ci	dev_dbg(dev, "num_slots: %u\n", ecc->num_slots);
205062306a36Sopenharmony_ci	dev_dbg(dev, "num_tc: %u\n", ecc->num_tc);
205162306a36Sopenharmony_ci	dev_dbg(dev, "chmap_exist: %s\n", ecc->chmap_exist ? "yes" : "no");
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	/* Nothing need to be done if queue priority is provided */
205462306a36Sopenharmony_ci	if (pdata->queue_priority_mapping)
205562306a36Sopenharmony_ci		return 0;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	/*
205862306a36Sopenharmony_ci	 * Configure TC/queue priority as follows:
205962306a36Sopenharmony_ci	 * Q0 - priority 0
206062306a36Sopenharmony_ci	 * Q1 - priority 1
206162306a36Sopenharmony_ci	 * Q2 - priority 2
206262306a36Sopenharmony_ci	 * ...
206362306a36Sopenharmony_ci	 * The meaning of priority numbers: 0 highest priority, 7 lowest
206462306a36Sopenharmony_ci	 * priority. So Q0 is the highest priority queue and the last queue has
206562306a36Sopenharmony_ci	 * the lowest priority.
206662306a36Sopenharmony_ci	 */
206762306a36Sopenharmony_ci	queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1, sizeof(s8),
206862306a36Sopenharmony_ci					  GFP_KERNEL);
206962306a36Sopenharmony_ci	if (!queue_priority_map)
207062306a36Sopenharmony_ci		return -ENOMEM;
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci	for (i = 0; i < ecc->num_tc; i++) {
207362306a36Sopenharmony_ci		queue_priority_map[i][0] = i;
207462306a36Sopenharmony_ci		queue_priority_map[i][1] = i;
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci	queue_priority_map[i][0] = -1;
207762306a36Sopenharmony_ci	queue_priority_map[i][1] = -1;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci	pdata->queue_priority_mapping = queue_priority_map;
208062306a36Sopenharmony_ci	/* Default queue has the lowest priority */
208162306a36Sopenharmony_ci	pdata->default_queue = i - 1;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	return 0;
208462306a36Sopenharmony_ci}
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF)
208762306a36Sopenharmony_cistatic int edma_xbar_event_map(struct device *dev, struct edma_soc_info *pdata,
208862306a36Sopenharmony_ci			       size_t sz)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	const char pname[] = "ti,edma-xbar-event-map";
209162306a36Sopenharmony_ci	struct resource res;
209262306a36Sopenharmony_ci	void __iomem *xbar;
209362306a36Sopenharmony_ci	s16 (*xbar_chans)[2];
209462306a36Sopenharmony_ci	size_t nelm = sz / sizeof(s16);
209562306a36Sopenharmony_ci	u32 shift, offset, mux;
209662306a36Sopenharmony_ci	int ret, i;
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_ci	xbar_chans = devm_kcalloc(dev, nelm + 2, sizeof(s16), GFP_KERNEL);
209962306a36Sopenharmony_ci	if (!xbar_chans)
210062306a36Sopenharmony_ci		return -ENOMEM;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	ret = of_address_to_resource(dev->of_node, 1, &res);
210362306a36Sopenharmony_ci	if (ret)
210462306a36Sopenharmony_ci		return -ENOMEM;
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci	xbar = devm_ioremap(dev, res.start, resource_size(&res));
210762306a36Sopenharmony_ci	if (!xbar)
210862306a36Sopenharmony_ci		return -ENOMEM;
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	ret = of_property_read_u16_array(dev->of_node, pname, (u16 *)xbar_chans,
211162306a36Sopenharmony_ci					 nelm);
211262306a36Sopenharmony_ci	if (ret)
211362306a36Sopenharmony_ci		return -EIO;
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci	/* Invalidate last entry for the other user of this mess */
211662306a36Sopenharmony_ci	nelm >>= 1;
211762306a36Sopenharmony_ci	xbar_chans[nelm][0] = -1;
211862306a36Sopenharmony_ci	xbar_chans[nelm][1] = -1;
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	for (i = 0; i < nelm; i++) {
212162306a36Sopenharmony_ci		shift = (xbar_chans[i][1] & 0x03) << 3;
212262306a36Sopenharmony_ci		offset = xbar_chans[i][1] & 0xfffffffc;
212362306a36Sopenharmony_ci		mux = readl(xbar + offset);
212462306a36Sopenharmony_ci		mux &= ~(0xff << shift);
212562306a36Sopenharmony_ci		mux |= xbar_chans[i][0] << shift;
212662306a36Sopenharmony_ci		writel(mux, (xbar + offset));
212762306a36Sopenharmony_ci	}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	pdata->xbar_chans = (const s16 (*)[2]) xbar_chans;
213062306a36Sopenharmony_ci	return 0;
213162306a36Sopenharmony_ci}
213262306a36Sopenharmony_ci
213362306a36Sopenharmony_cistatic struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
213462306a36Sopenharmony_ci						     bool legacy_mode)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	struct edma_soc_info *info;
213762306a36Sopenharmony_ci	struct property *prop;
213862306a36Sopenharmony_ci	int sz, ret;
213962306a36Sopenharmony_ci
214062306a36Sopenharmony_ci	info = devm_kzalloc(dev, sizeof(struct edma_soc_info), GFP_KERNEL);
214162306a36Sopenharmony_ci	if (!info)
214262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	if (legacy_mode) {
214562306a36Sopenharmony_ci		prop = of_find_property(dev->of_node, "ti,edma-xbar-event-map",
214662306a36Sopenharmony_ci					&sz);
214762306a36Sopenharmony_ci		if (prop) {
214862306a36Sopenharmony_ci			ret = edma_xbar_event_map(dev, info, sz);
214962306a36Sopenharmony_ci			if (ret)
215062306a36Sopenharmony_ci				return ERR_PTR(ret);
215162306a36Sopenharmony_ci		}
215262306a36Sopenharmony_ci		return info;
215362306a36Sopenharmony_ci	}
215462306a36Sopenharmony_ci
215562306a36Sopenharmony_ci	/* Get the list of channels allocated to be used for memcpy */
215662306a36Sopenharmony_ci	prop = of_find_property(dev->of_node, "ti,edma-memcpy-channels", &sz);
215762306a36Sopenharmony_ci	if (prop) {
215862306a36Sopenharmony_ci		const char pname[] = "ti,edma-memcpy-channels";
215962306a36Sopenharmony_ci		size_t nelm = sz / sizeof(s32);
216062306a36Sopenharmony_ci		s32 *memcpy_ch;
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_ci		memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s32),
216362306a36Sopenharmony_ci					 GFP_KERNEL);
216462306a36Sopenharmony_ci		if (!memcpy_ch)
216562306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci		ret = of_property_read_u32_array(dev->of_node, pname,
216862306a36Sopenharmony_ci						 (u32 *)memcpy_ch, nelm);
216962306a36Sopenharmony_ci		if (ret)
217062306a36Sopenharmony_ci			return ERR_PTR(ret);
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci		memcpy_ch[nelm] = -1;
217362306a36Sopenharmony_ci		info->memcpy_channels = memcpy_ch;
217462306a36Sopenharmony_ci	}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_ci	prop = of_find_property(dev->of_node, "ti,edma-reserved-slot-ranges",
217762306a36Sopenharmony_ci				&sz);
217862306a36Sopenharmony_ci	if (prop) {
217962306a36Sopenharmony_ci		const char pname[] = "ti,edma-reserved-slot-ranges";
218062306a36Sopenharmony_ci		u32 (*tmp)[2];
218162306a36Sopenharmony_ci		s16 (*rsv_slots)[2];
218262306a36Sopenharmony_ci		size_t nelm = sz / sizeof(*tmp);
218362306a36Sopenharmony_ci		struct edma_rsv_info *rsv_info;
218462306a36Sopenharmony_ci		int i;
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci		if (!nelm)
218762306a36Sopenharmony_ci			return info;
218862306a36Sopenharmony_ci
218962306a36Sopenharmony_ci		tmp = kcalloc(nelm, sizeof(*tmp), GFP_KERNEL);
219062306a36Sopenharmony_ci		if (!tmp)
219162306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci		rsv_info = devm_kzalloc(dev, sizeof(*rsv_info), GFP_KERNEL);
219462306a36Sopenharmony_ci		if (!rsv_info) {
219562306a36Sopenharmony_ci			kfree(tmp);
219662306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
219762306a36Sopenharmony_ci		}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci		rsv_slots = devm_kcalloc(dev, nelm + 1, sizeof(*rsv_slots),
220062306a36Sopenharmony_ci					 GFP_KERNEL);
220162306a36Sopenharmony_ci		if (!rsv_slots) {
220262306a36Sopenharmony_ci			kfree(tmp);
220362306a36Sopenharmony_ci			return ERR_PTR(-ENOMEM);
220462306a36Sopenharmony_ci		}
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci		ret = of_property_read_u32_array(dev->of_node, pname,
220762306a36Sopenharmony_ci						 (u32 *)tmp, nelm * 2);
220862306a36Sopenharmony_ci		if (ret) {
220962306a36Sopenharmony_ci			kfree(tmp);
221062306a36Sopenharmony_ci			return ERR_PTR(ret);
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		for (i = 0; i < nelm; i++) {
221462306a36Sopenharmony_ci			rsv_slots[i][0] = tmp[i][0];
221562306a36Sopenharmony_ci			rsv_slots[i][1] = tmp[i][1];
221662306a36Sopenharmony_ci		}
221762306a36Sopenharmony_ci		rsv_slots[nelm][0] = -1;
221862306a36Sopenharmony_ci		rsv_slots[nelm][1] = -1;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci		info->rsv = rsv_info;
222162306a36Sopenharmony_ci		info->rsv->rsv_slots = (const s16 (*)[2])rsv_slots;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		kfree(tmp);
222462306a36Sopenharmony_ci	}
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	return info;
222762306a36Sopenharmony_ci}
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_cistatic struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
223062306a36Sopenharmony_ci				      struct of_dma *ofdma)
223162306a36Sopenharmony_ci{
223262306a36Sopenharmony_ci	struct edma_cc *ecc = ofdma->of_dma_data;
223362306a36Sopenharmony_ci	struct dma_chan *chan = NULL;
223462306a36Sopenharmony_ci	struct edma_chan *echan;
223562306a36Sopenharmony_ci	int i;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (!ecc || dma_spec->args_count < 1)
223862306a36Sopenharmony_ci		return NULL;
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	for (i = 0; i < ecc->num_channels; i++) {
224162306a36Sopenharmony_ci		echan = &ecc->slave_chans[i];
224262306a36Sopenharmony_ci		if (echan->ch_num == dma_spec->args[0]) {
224362306a36Sopenharmony_ci			chan = &echan->vchan.chan;
224462306a36Sopenharmony_ci			break;
224562306a36Sopenharmony_ci		}
224662306a36Sopenharmony_ci	}
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (!chan)
224962306a36Sopenharmony_ci		return NULL;
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (echan->ecc->legacy_mode && dma_spec->args_count == 1)
225262306a36Sopenharmony_ci		goto out;
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	if (!echan->ecc->legacy_mode && dma_spec->args_count == 2 &&
225562306a36Sopenharmony_ci	    dma_spec->args[1] < echan->ecc->num_tc) {
225662306a36Sopenharmony_ci		echan->tc = &echan->ecc->tc_list[dma_spec->args[1]];
225762306a36Sopenharmony_ci		goto out;
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci
226062306a36Sopenharmony_ci	return NULL;
226162306a36Sopenharmony_ciout:
226262306a36Sopenharmony_ci	/* The channel is going to be used as HW synchronized */
226362306a36Sopenharmony_ci	echan->hw_triggered = true;
226462306a36Sopenharmony_ci	return dma_get_slave_channel(chan);
226562306a36Sopenharmony_ci}
226662306a36Sopenharmony_ci#else
226762306a36Sopenharmony_cistatic struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
226862306a36Sopenharmony_ci						     bool legacy_mode)
226962306a36Sopenharmony_ci{
227062306a36Sopenharmony_ci	return ERR_PTR(-EINVAL);
227162306a36Sopenharmony_ci}
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_cistatic struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec,
227462306a36Sopenharmony_ci				      struct of_dma *ofdma)
227562306a36Sopenharmony_ci{
227662306a36Sopenharmony_ci	return NULL;
227762306a36Sopenharmony_ci}
227862306a36Sopenharmony_ci#endif
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_cistatic bool edma_filter_fn(struct dma_chan *chan, void *param);
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_cistatic int edma_probe(struct platform_device *pdev)
228362306a36Sopenharmony_ci{
228462306a36Sopenharmony_ci	struct edma_soc_info	*info = pdev->dev.platform_data;
228562306a36Sopenharmony_ci	s8			(*queue_priority_mapping)[2];
228662306a36Sopenharmony_ci	const s16		(*reserved)[2];
228762306a36Sopenharmony_ci	int			i, irq;
228862306a36Sopenharmony_ci	char			*irq_name;
228962306a36Sopenharmony_ci	struct resource		*mem;
229062306a36Sopenharmony_ci	struct device_node	*node = pdev->dev.of_node;
229162306a36Sopenharmony_ci	struct device		*dev = &pdev->dev;
229262306a36Sopenharmony_ci	struct edma_cc		*ecc;
229362306a36Sopenharmony_ci	bool			legacy_mode = true;
229462306a36Sopenharmony_ci	int ret;
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	if (node) {
229762306a36Sopenharmony_ci		const struct of_device_id *match;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci		match = of_match_node(edma_of_ids, node);
230062306a36Sopenharmony_ci		if (match && (*(u32 *)match->data) == EDMA_BINDING_TPCC)
230162306a36Sopenharmony_ci			legacy_mode = false;
230262306a36Sopenharmony_ci
230362306a36Sopenharmony_ci		info = edma_setup_info_from_dt(dev, legacy_mode);
230462306a36Sopenharmony_ci		if (IS_ERR(info)) {
230562306a36Sopenharmony_ci			dev_err(dev, "failed to get DT data\n");
230662306a36Sopenharmony_ci			return PTR_ERR(info);
230762306a36Sopenharmony_ci		}
230862306a36Sopenharmony_ci	}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	if (!info)
231162306a36Sopenharmony_ci		return -ENODEV;
231262306a36Sopenharmony_ci
231362306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
231462306a36Sopenharmony_ci	if (ret)
231562306a36Sopenharmony_ci		return ret;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL);
231862306a36Sopenharmony_ci	if (!ecc)
231962306a36Sopenharmony_ci		return -ENOMEM;
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	ecc->dev = dev;
232262306a36Sopenharmony_ci	ecc->id = pdev->id;
232362306a36Sopenharmony_ci	ecc->legacy_mode = legacy_mode;
232462306a36Sopenharmony_ci	/* When booting with DT the pdev->id is -1 */
232562306a36Sopenharmony_ci	if (ecc->id < 0)
232662306a36Sopenharmony_ci		ecc->id = 0;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc");
232962306a36Sopenharmony_ci	if (!mem) {
233062306a36Sopenharmony_ci		dev_dbg(dev, "mem resource not found, using index 0\n");
233162306a36Sopenharmony_ci		mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
233262306a36Sopenharmony_ci		if (!mem) {
233362306a36Sopenharmony_ci			dev_err(dev, "no mem resource?\n");
233462306a36Sopenharmony_ci			return -ENODEV;
233562306a36Sopenharmony_ci		}
233662306a36Sopenharmony_ci	}
233762306a36Sopenharmony_ci	ecc->base = devm_ioremap_resource(dev, mem);
233862306a36Sopenharmony_ci	if (IS_ERR(ecc->base))
233962306a36Sopenharmony_ci		return PTR_ERR(ecc->base);
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	platform_set_drvdata(pdev, ecc);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	pm_runtime_enable(dev);
234462306a36Sopenharmony_ci	ret = pm_runtime_get_sync(dev);
234562306a36Sopenharmony_ci	if (ret < 0) {
234662306a36Sopenharmony_ci		dev_err(dev, "pm_runtime_get_sync() failed\n");
234762306a36Sopenharmony_ci		pm_runtime_disable(dev);
234862306a36Sopenharmony_ci		return ret;
234962306a36Sopenharmony_ci	}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	/* Get eDMA3 configuration from IP */
235262306a36Sopenharmony_ci	ret = edma_setup_from_hw(dev, info, ecc);
235362306a36Sopenharmony_ci	if (ret)
235462306a36Sopenharmony_ci		goto err_disable_pm;
235562306a36Sopenharmony_ci
235662306a36Sopenharmony_ci	/* Allocate memory based on the information we got from the IP */
235762306a36Sopenharmony_ci	ecc->slave_chans = devm_kcalloc(dev, ecc->num_channels,
235862306a36Sopenharmony_ci					sizeof(*ecc->slave_chans), GFP_KERNEL);
235962306a36Sopenharmony_ci
236062306a36Sopenharmony_ci	ecc->slot_inuse = devm_kcalloc(dev, BITS_TO_LONGS(ecc->num_slots),
236162306a36Sopenharmony_ci				       sizeof(unsigned long), GFP_KERNEL);
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	ecc->channels_mask = devm_kcalloc(dev,
236462306a36Sopenharmony_ci					   BITS_TO_LONGS(ecc->num_channels),
236562306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
236662306a36Sopenharmony_ci	if (!ecc->slave_chans || !ecc->slot_inuse || !ecc->channels_mask) {
236762306a36Sopenharmony_ci		ret = -ENOMEM;
236862306a36Sopenharmony_ci		goto err_disable_pm;
236962306a36Sopenharmony_ci	}
237062306a36Sopenharmony_ci
237162306a36Sopenharmony_ci	/* Mark all channels available initially */
237262306a36Sopenharmony_ci	bitmap_fill(ecc->channels_mask, ecc->num_channels);
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_ci	ecc->default_queue = info->default_queue;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	if (info->rsv) {
237762306a36Sopenharmony_ci		/* Set the reserved slots in inuse list */
237862306a36Sopenharmony_ci		reserved = info->rsv->rsv_slots;
237962306a36Sopenharmony_ci		if (reserved) {
238062306a36Sopenharmony_ci			for (i = 0; reserved[i][0] != -1; i++)
238162306a36Sopenharmony_ci				bitmap_set(ecc->slot_inuse, reserved[i][0],
238262306a36Sopenharmony_ci					   reserved[i][1]);
238362306a36Sopenharmony_ci		}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci		/* Clear channels not usable for Linux */
238662306a36Sopenharmony_ci		reserved = info->rsv->rsv_chans;
238762306a36Sopenharmony_ci		if (reserved) {
238862306a36Sopenharmony_ci			for (i = 0; reserved[i][0] != -1; i++)
238962306a36Sopenharmony_ci				bitmap_clear(ecc->channels_mask, reserved[i][0],
239062306a36Sopenharmony_ci					     reserved[i][1]);
239162306a36Sopenharmony_ci		}
239262306a36Sopenharmony_ci	}
239362306a36Sopenharmony_ci
239462306a36Sopenharmony_ci	for (i = 0; i < ecc->num_slots; i++) {
239562306a36Sopenharmony_ci		/* Reset only unused - not reserved - paRAM slots */
239662306a36Sopenharmony_ci		if (!test_bit(i, ecc->slot_inuse))
239762306a36Sopenharmony_ci			edma_write_slot(ecc, i, &dummy_paramset);
239862306a36Sopenharmony_ci	}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	irq = platform_get_irq_byname(pdev, "edma3_ccint");
240162306a36Sopenharmony_ci	if (irq < 0 && node)
240262306a36Sopenharmony_ci		irq = irq_of_parse_and_map(node, 0);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	if (irq > 0) {
240562306a36Sopenharmony_ci		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint",
240662306a36Sopenharmony_ci					  dev_name(dev));
240762306a36Sopenharmony_ci		if (!irq_name) {
240862306a36Sopenharmony_ci			ret = -ENOMEM;
240962306a36Sopenharmony_ci			goto err_disable_pm;
241062306a36Sopenharmony_ci		}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name,
241362306a36Sopenharmony_ci				       ecc);
241462306a36Sopenharmony_ci		if (ret) {
241562306a36Sopenharmony_ci			dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret);
241662306a36Sopenharmony_ci			goto err_disable_pm;
241762306a36Sopenharmony_ci		}
241862306a36Sopenharmony_ci		ecc->ccint = irq;
241962306a36Sopenharmony_ci	}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci	irq = platform_get_irq_byname(pdev, "edma3_ccerrint");
242262306a36Sopenharmony_ci	if (irq < 0 && node)
242362306a36Sopenharmony_ci		irq = irq_of_parse_and_map(node, 2);
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	if (irq > 0) {
242662306a36Sopenharmony_ci		irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint",
242762306a36Sopenharmony_ci					  dev_name(dev));
242862306a36Sopenharmony_ci		if (!irq_name) {
242962306a36Sopenharmony_ci			ret = -ENOMEM;
243062306a36Sopenharmony_ci			goto err_disable_pm;
243162306a36Sopenharmony_ci		}
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci		ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name,
243462306a36Sopenharmony_ci				       ecc);
243562306a36Sopenharmony_ci		if (ret) {
243662306a36Sopenharmony_ci			dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret);
243762306a36Sopenharmony_ci			goto err_disable_pm;
243862306a36Sopenharmony_ci		}
243962306a36Sopenharmony_ci		ecc->ccerrint = irq;
244062306a36Sopenharmony_ci	}
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY);
244362306a36Sopenharmony_ci	if (ecc->dummy_slot < 0) {
244462306a36Sopenharmony_ci		dev_err(dev, "Can't allocate PaRAM dummy slot\n");
244562306a36Sopenharmony_ci		ret = ecc->dummy_slot;
244662306a36Sopenharmony_ci		goto err_disable_pm;
244762306a36Sopenharmony_ci	}
244862306a36Sopenharmony_ci
244962306a36Sopenharmony_ci	queue_priority_mapping = info->queue_priority_mapping;
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	if (!ecc->legacy_mode) {
245262306a36Sopenharmony_ci		int lowest_priority = 0;
245362306a36Sopenharmony_ci		unsigned int array_max;
245462306a36Sopenharmony_ci		struct of_phandle_args tc_args;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_ci		ecc->tc_list = devm_kcalloc(dev, ecc->num_tc,
245762306a36Sopenharmony_ci					    sizeof(*ecc->tc_list), GFP_KERNEL);
245862306a36Sopenharmony_ci		if (!ecc->tc_list) {
245962306a36Sopenharmony_ci			ret = -ENOMEM;
246062306a36Sopenharmony_ci			goto err_reg1;
246162306a36Sopenharmony_ci		}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci		for (i = 0;; i++) {
246462306a36Sopenharmony_ci			ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs",
246562306a36Sopenharmony_ci							       1, i, &tc_args);
246662306a36Sopenharmony_ci			if (ret || i == ecc->num_tc)
246762306a36Sopenharmony_ci				break;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci			ecc->tc_list[i].node = tc_args.np;
247062306a36Sopenharmony_ci			ecc->tc_list[i].id = i;
247162306a36Sopenharmony_ci			queue_priority_mapping[i][1] = tc_args.args[0];
247262306a36Sopenharmony_ci			if (queue_priority_mapping[i][1] > lowest_priority) {
247362306a36Sopenharmony_ci				lowest_priority = queue_priority_mapping[i][1];
247462306a36Sopenharmony_ci				info->default_queue = i;
247562306a36Sopenharmony_ci			}
247662306a36Sopenharmony_ci		}
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci		/* See if we have optional dma-channel-mask array */
247962306a36Sopenharmony_ci		array_max = DIV_ROUND_UP(ecc->num_channels, BITS_PER_TYPE(u32));
248062306a36Sopenharmony_ci		ret = of_property_read_variable_u32_array(node,
248162306a36Sopenharmony_ci						"dma-channel-mask",
248262306a36Sopenharmony_ci						(u32 *)ecc->channels_mask,
248362306a36Sopenharmony_ci						1, array_max);
248462306a36Sopenharmony_ci		if (ret > 0 && ret != array_max)
248562306a36Sopenharmony_ci			dev_warn(dev, "dma-channel-mask is not complete.\n");
248662306a36Sopenharmony_ci		else if (ret == -EOVERFLOW || ret == -ENODATA)
248762306a36Sopenharmony_ci			dev_warn(dev,
248862306a36Sopenharmony_ci				 "dma-channel-mask is out of range or empty\n");
248962306a36Sopenharmony_ci	}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	/* Event queue priority mapping */
249262306a36Sopenharmony_ci	for (i = 0; queue_priority_mapping[i][0] != -1; i++)
249362306a36Sopenharmony_ci		edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0],
249462306a36Sopenharmony_ci					      queue_priority_mapping[i][1]);
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0);
249762306a36Sopenharmony_ci	edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0);
249862306a36Sopenharmony_ci	edma_write_array(ecc, EDMA_QRAE, 0, 0x0);
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	ecc->info = info;
250162306a36Sopenharmony_ci
250262306a36Sopenharmony_ci	/* Init the dma device and channels */
250362306a36Sopenharmony_ci	edma_dma_init(ecc, legacy_mode);
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	for (i = 0; i < ecc->num_channels; i++) {
250662306a36Sopenharmony_ci		/* Do not touch reserved channels */
250762306a36Sopenharmony_ci		if (!test_bit(i, ecc->channels_mask))
250862306a36Sopenharmony_ci			continue;
250962306a36Sopenharmony_ci
251062306a36Sopenharmony_ci		/* Assign all channels to the default queue */
251162306a36Sopenharmony_ci		edma_assign_channel_eventq(&ecc->slave_chans[i],
251262306a36Sopenharmony_ci					   info->default_queue);
251362306a36Sopenharmony_ci		/* Set entry slot to the dummy slot */
251462306a36Sopenharmony_ci		edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot);
251562306a36Sopenharmony_ci	}
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	ecc->dma_slave.filter.map = info->slave_map;
251862306a36Sopenharmony_ci	ecc->dma_slave.filter.mapcnt = info->slavecnt;
251962306a36Sopenharmony_ci	ecc->dma_slave.filter.fn = edma_filter_fn;
252062306a36Sopenharmony_ci
252162306a36Sopenharmony_ci	ret = dma_async_device_register(&ecc->dma_slave);
252262306a36Sopenharmony_ci	if (ret) {
252362306a36Sopenharmony_ci		dev_err(dev, "slave ddev registration failed (%d)\n", ret);
252462306a36Sopenharmony_ci		goto err_reg1;
252562306a36Sopenharmony_ci	}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci	if (ecc->dma_memcpy) {
252862306a36Sopenharmony_ci		ret = dma_async_device_register(ecc->dma_memcpy);
252962306a36Sopenharmony_ci		if (ret) {
253062306a36Sopenharmony_ci			dev_err(dev, "memcpy ddev registration failed (%d)\n",
253162306a36Sopenharmony_ci				ret);
253262306a36Sopenharmony_ci			dma_async_device_unregister(&ecc->dma_slave);
253362306a36Sopenharmony_ci			goto err_reg1;
253462306a36Sopenharmony_ci		}
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	if (node)
253862306a36Sopenharmony_ci		of_dma_controller_register(node, of_edma_xlate, ecc);
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci	dev_info(dev, "TI EDMA DMA engine driver\n");
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	return 0;
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_cierr_reg1:
254562306a36Sopenharmony_ci	edma_free_slot(ecc, ecc->dummy_slot);
254662306a36Sopenharmony_cierr_disable_pm:
254762306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
254862306a36Sopenharmony_ci	pm_runtime_disable(dev);
254962306a36Sopenharmony_ci	return ret;
255062306a36Sopenharmony_ci}
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_cistatic void edma_cleanupp_vchan(struct dma_device *dmadev)
255362306a36Sopenharmony_ci{
255462306a36Sopenharmony_ci	struct edma_chan *echan, *_echan;
255562306a36Sopenharmony_ci
255662306a36Sopenharmony_ci	list_for_each_entry_safe(echan, _echan,
255762306a36Sopenharmony_ci			&dmadev->channels, vchan.chan.device_node) {
255862306a36Sopenharmony_ci		list_del(&echan->vchan.chan.device_node);
255962306a36Sopenharmony_ci		tasklet_kill(&echan->vchan.task);
256062306a36Sopenharmony_ci	}
256162306a36Sopenharmony_ci}
256262306a36Sopenharmony_ci
256362306a36Sopenharmony_cistatic int edma_remove(struct platform_device *pdev)
256462306a36Sopenharmony_ci{
256562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
256662306a36Sopenharmony_ci	struct edma_cc *ecc = dev_get_drvdata(dev);
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	devm_free_irq(dev, ecc->ccint, ecc);
256962306a36Sopenharmony_ci	devm_free_irq(dev, ecc->ccerrint, ecc);
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci	edma_cleanupp_vchan(&ecc->dma_slave);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	if (dev->of_node)
257462306a36Sopenharmony_ci		of_dma_controller_free(dev->of_node);
257562306a36Sopenharmony_ci	dma_async_device_unregister(&ecc->dma_slave);
257662306a36Sopenharmony_ci	if (ecc->dma_memcpy)
257762306a36Sopenharmony_ci		dma_async_device_unregister(ecc->dma_memcpy);
257862306a36Sopenharmony_ci	edma_free_slot(ecc, ecc->dummy_slot);
257962306a36Sopenharmony_ci	pm_runtime_put_sync(dev);
258062306a36Sopenharmony_ci	pm_runtime_disable(dev);
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	return 0;
258362306a36Sopenharmony_ci}
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
258662306a36Sopenharmony_cistatic int edma_pm_suspend(struct device *dev)
258762306a36Sopenharmony_ci{
258862306a36Sopenharmony_ci	struct edma_cc *ecc = dev_get_drvdata(dev);
258962306a36Sopenharmony_ci	struct edma_chan *echan = ecc->slave_chans;
259062306a36Sopenharmony_ci	int i;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	for (i = 0; i < ecc->num_channels; i++) {
259362306a36Sopenharmony_ci		if (echan[i].alloced)
259462306a36Sopenharmony_ci			edma_setup_interrupt(&echan[i], false);
259562306a36Sopenharmony_ci	}
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	return 0;
259862306a36Sopenharmony_ci}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_cistatic int edma_pm_resume(struct device *dev)
260162306a36Sopenharmony_ci{
260262306a36Sopenharmony_ci	struct edma_cc *ecc = dev_get_drvdata(dev);
260362306a36Sopenharmony_ci	struct edma_chan *echan = ecc->slave_chans;
260462306a36Sopenharmony_ci	int i;
260562306a36Sopenharmony_ci	s8 (*queue_priority_mapping)[2];
260662306a36Sopenharmony_ci
260762306a36Sopenharmony_ci	/* re initialize dummy slot to dummy param set */
260862306a36Sopenharmony_ci	edma_write_slot(ecc, ecc->dummy_slot, &dummy_paramset);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	queue_priority_mapping = ecc->info->queue_priority_mapping;
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	/* Event queue priority mapping */
261362306a36Sopenharmony_ci	for (i = 0; queue_priority_mapping[i][0] != -1; i++)
261462306a36Sopenharmony_ci		edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0],
261562306a36Sopenharmony_ci					      queue_priority_mapping[i][1]);
261662306a36Sopenharmony_ci
261762306a36Sopenharmony_ci	for (i = 0; i < ecc->num_channels; i++) {
261862306a36Sopenharmony_ci		if (echan[i].alloced) {
261962306a36Sopenharmony_ci			/* ensure access through shadow region 0 */
262062306a36Sopenharmony_ci			edma_or_array2(ecc, EDMA_DRAE, 0,
262162306a36Sopenharmony_ci				       EDMA_REG_ARRAY_INDEX(i),
262262306a36Sopenharmony_ci				       EDMA_CHANNEL_BIT(i));
262362306a36Sopenharmony_ci
262462306a36Sopenharmony_ci			edma_setup_interrupt(&echan[i], true);
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_ci			/* Set up channel -> slot mapping for the entry slot */
262762306a36Sopenharmony_ci			edma_set_chmap(&echan[i], echan[i].slot[0]);
262862306a36Sopenharmony_ci		}
262962306a36Sopenharmony_ci	}
263062306a36Sopenharmony_ci
263162306a36Sopenharmony_ci	return 0;
263262306a36Sopenharmony_ci}
263362306a36Sopenharmony_ci#endif
263462306a36Sopenharmony_ci
263562306a36Sopenharmony_cistatic const struct dev_pm_ops edma_pm_ops = {
263662306a36Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(edma_pm_suspend, edma_pm_resume)
263762306a36Sopenharmony_ci};
263862306a36Sopenharmony_ci
263962306a36Sopenharmony_cistatic struct platform_driver edma_driver = {
264062306a36Sopenharmony_ci	.probe		= edma_probe,
264162306a36Sopenharmony_ci	.remove		= edma_remove,
264262306a36Sopenharmony_ci	.driver = {
264362306a36Sopenharmony_ci		.name	= "edma",
264462306a36Sopenharmony_ci		.pm	= &edma_pm_ops,
264562306a36Sopenharmony_ci		.of_match_table = edma_of_ids,
264662306a36Sopenharmony_ci	},
264762306a36Sopenharmony_ci};
264862306a36Sopenharmony_ci
264962306a36Sopenharmony_cistatic int edma_tptc_probe(struct platform_device *pdev)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
265262306a36Sopenharmony_ci	return pm_runtime_get_sync(&pdev->dev);
265362306a36Sopenharmony_ci}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_cistatic struct platform_driver edma_tptc_driver = {
265662306a36Sopenharmony_ci	.probe		= edma_tptc_probe,
265762306a36Sopenharmony_ci	.driver = {
265862306a36Sopenharmony_ci		.name	= "edma3-tptc",
265962306a36Sopenharmony_ci		.of_match_table = edma_tptc_of_ids,
266062306a36Sopenharmony_ci	},
266162306a36Sopenharmony_ci};
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_cistatic bool edma_filter_fn(struct dma_chan *chan, void *param)
266462306a36Sopenharmony_ci{
266562306a36Sopenharmony_ci	bool match = false;
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	if (chan->device->dev->driver == &edma_driver.driver) {
266862306a36Sopenharmony_ci		struct edma_chan *echan = to_edma_chan(chan);
266962306a36Sopenharmony_ci		unsigned ch_req = *(unsigned *)param;
267062306a36Sopenharmony_ci		if (ch_req == echan->ch_num) {
267162306a36Sopenharmony_ci			/* The channel is going to be used as HW synchronized */
267262306a36Sopenharmony_ci			echan->hw_triggered = true;
267362306a36Sopenharmony_ci			match = true;
267462306a36Sopenharmony_ci		}
267562306a36Sopenharmony_ci	}
267662306a36Sopenharmony_ci	return match;
267762306a36Sopenharmony_ci}
267862306a36Sopenharmony_ci
267962306a36Sopenharmony_cistatic int edma_init(void)
268062306a36Sopenharmony_ci{
268162306a36Sopenharmony_ci	int ret;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	ret = platform_driver_register(&edma_tptc_driver);
268462306a36Sopenharmony_ci	if (ret)
268562306a36Sopenharmony_ci		return ret;
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	return platform_driver_register(&edma_driver);
268862306a36Sopenharmony_ci}
268962306a36Sopenharmony_cisubsys_initcall(edma_init);
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_cistatic void __exit edma_exit(void)
269262306a36Sopenharmony_ci{
269362306a36Sopenharmony_ci	platform_driver_unregister(&edma_driver);
269462306a36Sopenharmony_ci	platform_driver_unregister(&edma_tptc_driver);
269562306a36Sopenharmony_ci}
269662306a36Sopenharmony_cimodule_exit(edma_exit);
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ciMODULE_AUTHOR("Matt Porter <matt.porter@linaro.org>");
269962306a36Sopenharmony_ciMODULE_DESCRIPTION("TI EDMA DMA engine driver");
270062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
2701