162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com
462306a36Sopenharmony_ci *  Author: Peter Ujfalusi <peter.ujfalusi@ti.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/kernel.h>
862306a36Sopenharmony_ci#include <linux/module.h>
962306a36Sopenharmony_ci#include <linux/delay.h>
1062306a36Sopenharmony_ci#include <linux/dmaengine.h>
1162306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1262306a36Sopenharmony_ci#include <linux/dmapool.h>
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/init.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/list.h>
1762306a36Sopenharmony_ci#include <linux/platform_device.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/spinlock.h>
2062306a36Sopenharmony_ci#include <linux/sys_soc.h>
2162306a36Sopenharmony_ci#include <linux/of.h>
2262306a36Sopenharmony_ci#include <linux/of_dma.h>
2362306a36Sopenharmony_ci#include <linux/of_irq.h>
2462306a36Sopenharmony_ci#include <linux/workqueue.h>
2562306a36Sopenharmony_ci#include <linux/completion.h>
2662306a36Sopenharmony_ci#include <linux/soc/ti/k3-ringacc.h>
2762306a36Sopenharmony_ci#include <linux/soc/ti/ti_sci_protocol.h>
2862306a36Sopenharmony_ci#include <linux/soc/ti/ti_sci_inta_msi.h>
2962306a36Sopenharmony_ci#include <linux/dma/k3-event-router.h>
3062306a36Sopenharmony_ci#include <linux/dma/ti-cppi5.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include "../virt-dma.h"
3362306a36Sopenharmony_ci#include "k3-udma.h"
3462306a36Sopenharmony_ci#include "k3-psil-priv.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistruct udma_static_tr {
3762306a36Sopenharmony_ci	u8 elsize; /* RPSTR0 */
3862306a36Sopenharmony_ci	u16 elcnt; /* RPSTR0 */
3962306a36Sopenharmony_ci	u16 bstcnt; /* RPSTR1 */
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define K3_UDMA_MAX_RFLOWS		1024
4362306a36Sopenharmony_ci#define K3_UDMA_DEFAULT_RING_SIZE	16
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* How SRC/DST tag should be updated by UDMA in the descriptor's Word 3 */
4662306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_NONE		0
4762306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_CFG_TAG	1
4862306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_FLOW_ID	2
4962306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_SRC_TAG	4
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_NONE		0
5262306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_CFG_TAG	1
5362306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_FLOW_ID	2
5462306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_DST_TAG_LO	4
5562306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_DST_TAG_HI	5
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistruct udma_chan;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cienum k3_dma_type {
6062306a36Sopenharmony_ci	DMA_TYPE_UDMA = 0,
6162306a36Sopenharmony_ci	DMA_TYPE_BCDMA,
6262306a36Sopenharmony_ci	DMA_TYPE_PKTDMA,
6362306a36Sopenharmony_ci};
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cienum udma_mmr {
6662306a36Sopenharmony_ci	MMR_GCFG = 0,
6762306a36Sopenharmony_ci	MMR_BCHANRT,
6862306a36Sopenharmony_ci	MMR_RCHANRT,
6962306a36Sopenharmony_ci	MMR_TCHANRT,
7062306a36Sopenharmony_ci	MMR_LAST,
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic const char * const mmr_names[] = {
7462306a36Sopenharmony_ci	[MMR_GCFG] = "gcfg",
7562306a36Sopenharmony_ci	[MMR_BCHANRT] = "bchanrt",
7662306a36Sopenharmony_ci	[MMR_RCHANRT] = "rchanrt",
7762306a36Sopenharmony_ci	[MMR_TCHANRT] = "tchanrt",
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistruct udma_tchan {
8162306a36Sopenharmony_ci	void __iomem *reg_rt;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	int id;
8462306a36Sopenharmony_ci	struct k3_ring *t_ring; /* Transmit ring */
8562306a36Sopenharmony_ci	struct k3_ring *tc_ring; /* Transmit Completion ring */
8662306a36Sopenharmony_ci	int tflow_id; /* applicable only for PKTDMA */
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci#define udma_bchan udma_tchan
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cistruct udma_rflow {
9362306a36Sopenharmony_ci	int id;
9462306a36Sopenharmony_ci	struct k3_ring *fd_ring; /* Free Descriptor ring */
9562306a36Sopenharmony_ci	struct k3_ring *r_ring; /* Receive ring */
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistruct udma_rchan {
9962306a36Sopenharmony_ci	void __iomem *reg_rt;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	int id;
10262306a36Sopenharmony_ci};
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistruct udma_oes_offsets {
10562306a36Sopenharmony_ci	/* K3 UDMA Output Event Offset */
10662306a36Sopenharmony_ci	u32 udma_rchan;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	/* BCDMA Output Event Offsets */
10962306a36Sopenharmony_ci	u32 bcdma_bchan_data;
11062306a36Sopenharmony_ci	u32 bcdma_bchan_ring;
11162306a36Sopenharmony_ci	u32 bcdma_tchan_data;
11262306a36Sopenharmony_ci	u32 bcdma_tchan_ring;
11362306a36Sopenharmony_ci	u32 bcdma_rchan_data;
11462306a36Sopenharmony_ci	u32 bcdma_rchan_ring;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* PKTDMA Output Event Offsets */
11762306a36Sopenharmony_ci	u32 pktdma_tchan_flow;
11862306a36Sopenharmony_ci	u32 pktdma_rchan_flow;
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci#define UDMA_FLAG_PDMA_ACC32		BIT(0)
12262306a36Sopenharmony_ci#define UDMA_FLAG_PDMA_BURST		BIT(1)
12362306a36Sopenharmony_ci#define UDMA_FLAG_TDTYPE		BIT(2)
12462306a36Sopenharmony_ci#define UDMA_FLAG_BURST_SIZE		BIT(3)
12562306a36Sopenharmony_ci#define UDMA_FLAGS_J7_CLASS		(UDMA_FLAG_PDMA_ACC32 | \
12662306a36Sopenharmony_ci					 UDMA_FLAG_PDMA_BURST | \
12762306a36Sopenharmony_ci					 UDMA_FLAG_TDTYPE | \
12862306a36Sopenharmony_ci					 UDMA_FLAG_BURST_SIZE)
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistruct udma_match_data {
13162306a36Sopenharmony_ci	enum k3_dma_type type;
13262306a36Sopenharmony_ci	u32 psil_base;
13362306a36Sopenharmony_ci	bool enable_memcpy_support;
13462306a36Sopenharmony_ci	u32 flags;
13562306a36Sopenharmony_ci	u32 statictr_z_mask;
13662306a36Sopenharmony_ci	u8 burst_size[3];
13762306a36Sopenharmony_ci	struct udma_soc_data *soc_data;
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct udma_soc_data {
14162306a36Sopenharmony_ci	struct udma_oes_offsets oes;
14262306a36Sopenharmony_ci	u32 bcdma_trigger_event_offset;
14362306a36Sopenharmony_ci};
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_cistruct udma_hwdesc {
14662306a36Sopenharmony_ci	size_t cppi5_desc_size;
14762306a36Sopenharmony_ci	void *cppi5_desc_vaddr;
14862306a36Sopenharmony_ci	dma_addr_t cppi5_desc_paddr;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* TR descriptor internal pointers */
15162306a36Sopenharmony_ci	void *tr_req_base;
15262306a36Sopenharmony_ci	struct cppi5_tr_resp_t *tr_resp_base;
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistruct udma_rx_flush {
15662306a36Sopenharmony_ci	struct udma_hwdesc hwdescs[2];
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	size_t buffer_size;
15962306a36Sopenharmony_ci	void *buffer_vaddr;
16062306a36Sopenharmony_ci	dma_addr_t buffer_paddr;
16162306a36Sopenharmony_ci};
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistruct udma_tpl {
16462306a36Sopenharmony_ci	u8 levels;
16562306a36Sopenharmony_ci	u32 start_idx[3];
16662306a36Sopenharmony_ci};
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistruct udma_dev {
16962306a36Sopenharmony_ci	struct dma_device ddev;
17062306a36Sopenharmony_ci	struct device *dev;
17162306a36Sopenharmony_ci	void __iomem *mmrs[MMR_LAST];
17262306a36Sopenharmony_ci	const struct udma_match_data *match_data;
17362306a36Sopenharmony_ci	const struct udma_soc_data *soc_data;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	struct udma_tpl bchan_tpl;
17662306a36Sopenharmony_ci	struct udma_tpl tchan_tpl;
17762306a36Sopenharmony_ci	struct udma_tpl rchan_tpl;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	size_t desc_align; /* alignment to use for descriptors */
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	struct udma_tisci_rm tisci_rm;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	struct k3_ringacc *ringacc;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	struct work_struct purge_work;
18662306a36Sopenharmony_ci	struct list_head desc_to_purge;
18762306a36Sopenharmony_ci	spinlock_t lock;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	struct udma_rx_flush rx_flush;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	int bchan_cnt;
19262306a36Sopenharmony_ci	int tchan_cnt;
19362306a36Sopenharmony_ci	int echan_cnt;
19462306a36Sopenharmony_ci	int rchan_cnt;
19562306a36Sopenharmony_ci	int rflow_cnt;
19662306a36Sopenharmony_ci	int tflow_cnt;
19762306a36Sopenharmony_ci	unsigned long *bchan_map;
19862306a36Sopenharmony_ci	unsigned long *tchan_map;
19962306a36Sopenharmony_ci	unsigned long *rchan_map;
20062306a36Sopenharmony_ci	unsigned long *rflow_gp_map;
20162306a36Sopenharmony_ci	unsigned long *rflow_gp_map_allocated;
20262306a36Sopenharmony_ci	unsigned long *rflow_in_use;
20362306a36Sopenharmony_ci	unsigned long *tflow_map;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	struct udma_bchan *bchans;
20662306a36Sopenharmony_ci	struct udma_tchan *tchans;
20762306a36Sopenharmony_ci	struct udma_rchan *rchans;
20862306a36Sopenharmony_ci	struct udma_rflow *rflows;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	struct udma_chan *channels;
21162306a36Sopenharmony_ci	u32 psil_base;
21262306a36Sopenharmony_ci	u32 atype;
21362306a36Sopenharmony_ci	u32 asel;
21462306a36Sopenharmony_ci};
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistruct udma_desc {
21762306a36Sopenharmony_ci	struct virt_dma_desc vd;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	bool terminated;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	enum dma_transfer_direction dir;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	struct udma_static_tr static_tr;
22462306a36Sopenharmony_ci	u32 residue;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	unsigned int sglen;
22762306a36Sopenharmony_ci	unsigned int desc_idx; /* Only used for cyclic in packet mode */
22862306a36Sopenharmony_ci	unsigned int tr_idx;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	u32 metadata_size;
23162306a36Sopenharmony_ci	void *metadata; /* pointer to provided metadata buffer (EPIP, PSdata) */
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	unsigned int hwdesc_count;
23462306a36Sopenharmony_ci	struct udma_hwdesc hwdesc[];
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cienum udma_chan_state {
23862306a36Sopenharmony_ci	UDMA_CHAN_IS_IDLE = 0, /* not active, no teardown is in progress */
23962306a36Sopenharmony_ci	UDMA_CHAN_IS_ACTIVE, /* Normal operation */
24062306a36Sopenharmony_ci	UDMA_CHAN_IS_TERMINATING, /* channel is being terminated */
24162306a36Sopenharmony_ci};
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistruct udma_tx_drain {
24462306a36Sopenharmony_ci	struct delayed_work work;
24562306a36Sopenharmony_ci	ktime_t tstamp;
24662306a36Sopenharmony_ci	u32 residue;
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistruct udma_chan_config {
25062306a36Sopenharmony_ci	bool pkt_mode; /* TR or packet */
25162306a36Sopenharmony_ci	bool needs_epib; /* EPIB is needed for the communication or not */
25262306a36Sopenharmony_ci	u32 psd_size; /* size of Protocol Specific Data */
25362306a36Sopenharmony_ci	u32 metadata_size; /* (needs_epib ? 16:0) + psd_size */
25462306a36Sopenharmony_ci	u32 hdesc_size; /* Size of a packet descriptor in packet mode */
25562306a36Sopenharmony_ci	bool notdpkt; /* Suppress sending TDC packet */
25662306a36Sopenharmony_ci	int remote_thread_id;
25762306a36Sopenharmony_ci	u32 atype;
25862306a36Sopenharmony_ci	u32 asel;
25962306a36Sopenharmony_ci	u32 src_thread;
26062306a36Sopenharmony_ci	u32 dst_thread;
26162306a36Sopenharmony_ci	enum psil_endpoint_type ep_type;
26262306a36Sopenharmony_ci	bool enable_acc32;
26362306a36Sopenharmony_ci	bool enable_burst;
26462306a36Sopenharmony_ci	enum udma_tp_level channel_tpl; /* Channel Throughput Level */
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	u32 tr_trigger_type;
26762306a36Sopenharmony_ci	unsigned long tx_flags;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* PKDMA mapped channel */
27062306a36Sopenharmony_ci	int mapped_channel_id;
27162306a36Sopenharmony_ci	/* PKTDMA default tflow or rflow for mapped channel */
27262306a36Sopenharmony_ci	int default_flow_id;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	enum dma_transfer_direction dir;
27562306a36Sopenharmony_ci};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_cistruct udma_chan {
27862306a36Sopenharmony_ci	struct virt_dma_chan vc;
27962306a36Sopenharmony_ci	struct dma_slave_config	cfg;
28062306a36Sopenharmony_ci	struct udma_dev *ud;
28162306a36Sopenharmony_ci	struct device *dma_dev;
28262306a36Sopenharmony_ci	struct udma_desc *desc;
28362306a36Sopenharmony_ci	struct udma_desc *terminated_desc;
28462306a36Sopenharmony_ci	struct udma_static_tr static_tr;
28562306a36Sopenharmony_ci	char *name;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	struct udma_bchan *bchan;
28862306a36Sopenharmony_ci	struct udma_tchan *tchan;
28962306a36Sopenharmony_ci	struct udma_rchan *rchan;
29062306a36Sopenharmony_ci	struct udma_rflow *rflow;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	bool psil_paired;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	int irq_num_ring;
29562306a36Sopenharmony_ci	int irq_num_udma;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	bool cyclic;
29862306a36Sopenharmony_ci	bool paused;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	enum udma_chan_state state;
30162306a36Sopenharmony_ci	struct completion teardown_completed;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	struct udma_tx_drain tx_drain;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Channel configuration parameters */
30662306a36Sopenharmony_ci	struct udma_chan_config config;
30762306a36Sopenharmony_ci	/* Channel configuration parameters (backup) */
30862306a36Sopenharmony_ci	struct udma_chan_config backup_config;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/* dmapool for packet mode descriptors */
31162306a36Sopenharmony_ci	bool use_dma_pool;
31262306a36Sopenharmony_ci	struct dma_pool *hdesc_pool;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	u32 id;
31562306a36Sopenharmony_ci};
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic inline struct udma_dev *to_udma_dev(struct dma_device *d)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	return container_of(d, struct udma_dev, ddev);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic inline struct udma_chan *to_udma_chan(struct dma_chan *c)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	return container_of(c, struct udma_chan, vc.chan);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic inline struct udma_desc *to_udma_desc(struct dma_async_tx_descriptor *t)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	return container_of(t, struct udma_desc, vd.tx);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/* Generic register access functions */
33362306a36Sopenharmony_cistatic inline u32 udma_read(void __iomem *base, int reg)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	return readl(base + reg);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_cistatic inline void udma_write(void __iomem *base, int reg, u32 val)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	writel(val, base + reg);
34162306a36Sopenharmony_ci}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_cistatic inline void udma_update_bits(void __iomem *base, int reg,
34462306a36Sopenharmony_ci				    u32 mask, u32 val)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	u32 tmp, orig;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	orig = readl(base + reg);
34962306a36Sopenharmony_ci	tmp = orig & ~mask;
35062306a36Sopenharmony_ci	tmp |= (val & mask);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (tmp != orig)
35362306a36Sopenharmony_ci		writel(tmp, base + reg);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci/* TCHANRT */
35762306a36Sopenharmony_cistatic inline u32 udma_tchanrt_read(struct udma_chan *uc, int reg)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	if (!uc->tchan)
36062306a36Sopenharmony_ci		return 0;
36162306a36Sopenharmony_ci	return udma_read(uc->tchan->reg_rt, reg);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic inline void udma_tchanrt_write(struct udma_chan *uc, int reg, u32 val)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	if (!uc->tchan)
36762306a36Sopenharmony_ci		return;
36862306a36Sopenharmony_ci	udma_write(uc->tchan->reg_rt, reg, val);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic inline void udma_tchanrt_update_bits(struct udma_chan *uc, int reg,
37262306a36Sopenharmony_ci					    u32 mask, u32 val)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	if (!uc->tchan)
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	udma_update_bits(uc->tchan->reg_rt, reg, mask, val);
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci/* RCHANRT */
38062306a36Sopenharmony_cistatic inline u32 udma_rchanrt_read(struct udma_chan *uc, int reg)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	if (!uc->rchan)
38362306a36Sopenharmony_ci		return 0;
38462306a36Sopenharmony_ci	return udma_read(uc->rchan->reg_rt, reg);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic inline void udma_rchanrt_write(struct udma_chan *uc, int reg, u32 val)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	if (!uc->rchan)
39062306a36Sopenharmony_ci		return;
39162306a36Sopenharmony_ci	udma_write(uc->rchan->reg_rt, reg, val);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic inline void udma_rchanrt_update_bits(struct udma_chan *uc, int reg,
39562306a36Sopenharmony_ci					    u32 mask, u32 val)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	if (!uc->rchan)
39862306a36Sopenharmony_ci		return;
39962306a36Sopenharmony_ci	udma_update_bits(uc->rchan->reg_rt, reg, mask, val);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int navss_psil_pair(struct udma_dev *ud, u32 src_thread, u32 dst_thread)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
40762306a36Sopenharmony_ci	return tisci_rm->tisci_psil_ops->pair(tisci_rm->tisci,
40862306a36Sopenharmony_ci					      tisci_rm->tisci_navss_dev_id,
40962306a36Sopenharmony_ci					      src_thread, dst_thread);
41062306a36Sopenharmony_ci}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic int navss_psil_unpair(struct udma_dev *ud, u32 src_thread,
41362306a36Sopenharmony_ci			     u32 dst_thread)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
41862306a36Sopenharmony_ci	return tisci_rm->tisci_psil_ops->unpair(tisci_rm->tisci,
41962306a36Sopenharmony_ci						tisci_rm->tisci_navss_dev_id,
42062306a36Sopenharmony_ci						src_thread, dst_thread);
42162306a36Sopenharmony_ci}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic void k3_configure_chan_coherency(struct dma_chan *chan, u32 asel)
42462306a36Sopenharmony_ci{
42562306a36Sopenharmony_ci	struct device *chan_dev = &chan->dev->device;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	if (asel == 0) {
42862306a36Sopenharmony_ci		/* No special handling for the channel */
42962306a36Sopenharmony_ci		chan->dev->chan_dma_dev = false;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		chan_dev->dma_coherent = false;
43262306a36Sopenharmony_ci		chan_dev->dma_parms = NULL;
43362306a36Sopenharmony_ci	} else if (asel == 14 || asel == 15) {
43462306a36Sopenharmony_ci		chan->dev->chan_dma_dev = true;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		chan_dev->dma_coherent = true;
43762306a36Sopenharmony_ci		dma_coerce_mask_and_coherent(chan_dev, DMA_BIT_MASK(48));
43862306a36Sopenharmony_ci		chan_dev->dma_parms = chan_dev->parent->dma_parms;
43962306a36Sopenharmony_ci	} else {
44062306a36Sopenharmony_ci		dev_warn(chan->device->dev, "Invalid ASEL value: %u\n", asel);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci		chan_dev->dma_coherent = false;
44362306a36Sopenharmony_ci		chan_dev->dma_parms = NULL;
44462306a36Sopenharmony_ci	}
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic u8 udma_get_chan_tpl_index(struct udma_tpl *tpl_map, int chan_id)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	int i;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	for (i = 0; i < tpl_map->levels; i++) {
45262306a36Sopenharmony_ci		if (chan_id >= tpl_map->start_idx[i])
45362306a36Sopenharmony_ci			return i;
45462306a36Sopenharmony_ci	}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	return 0;
45762306a36Sopenharmony_ci}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_cistatic void udma_reset_uchan(struct udma_chan *uc)
46062306a36Sopenharmony_ci{
46162306a36Sopenharmony_ci	memset(&uc->config, 0, sizeof(uc->config));
46262306a36Sopenharmony_ci	uc->config.remote_thread_id = -1;
46362306a36Sopenharmony_ci	uc->config.mapped_channel_id = -1;
46462306a36Sopenharmony_ci	uc->config.default_flow_id = -1;
46562306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_IDLE;
46662306a36Sopenharmony_ci}
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_cistatic void udma_dump_chan_stdata(struct udma_chan *uc)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	struct device *dev = uc->ud->dev;
47162306a36Sopenharmony_ci	u32 offset;
47262306a36Sopenharmony_ci	int i;
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (uc->config.dir == DMA_MEM_TO_DEV || uc->config.dir == DMA_MEM_TO_MEM) {
47562306a36Sopenharmony_ci		dev_dbg(dev, "TCHAN State data:\n");
47662306a36Sopenharmony_ci		for (i = 0; i < 32; i++) {
47762306a36Sopenharmony_ci			offset = UDMA_CHAN_RT_STDATA_REG + i * 4;
47862306a36Sopenharmony_ci			dev_dbg(dev, "TRT_STDATA[%02d]: 0x%08x\n", i,
47962306a36Sopenharmony_ci				udma_tchanrt_read(uc, offset));
48062306a36Sopenharmony_ci		}
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (uc->config.dir == DMA_DEV_TO_MEM || uc->config.dir == DMA_MEM_TO_MEM) {
48462306a36Sopenharmony_ci		dev_dbg(dev, "RCHAN State data:\n");
48562306a36Sopenharmony_ci		for (i = 0; i < 32; i++) {
48662306a36Sopenharmony_ci			offset = UDMA_CHAN_RT_STDATA_REG + i * 4;
48762306a36Sopenharmony_ci			dev_dbg(dev, "RRT_STDATA[%02d]: 0x%08x\n", i,
48862306a36Sopenharmony_ci				udma_rchanrt_read(uc, offset));
48962306a36Sopenharmony_ci		}
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic inline dma_addr_t udma_curr_cppi5_desc_paddr(struct udma_desc *d,
49462306a36Sopenharmony_ci						    int idx)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	return d->hwdesc[idx].cppi5_desc_paddr;
49762306a36Sopenharmony_ci}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_cistatic inline void *udma_curr_cppi5_desc_vaddr(struct udma_desc *d, int idx)
50062306a36Sopenharmony_ci{
50162306a36Sopenharmony_ci	return d->hwdesc[idx].cppi5_desc_vaddr;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic struct udma_desc *udma_udma_desc_from_paddr(struct udma_chan *uc,
50562306a36Sopenharmony_ci						   dma_addr_t paddr)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	struct udma_desc *d = uc->terminated_desc;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (d) {
51062306a36Sopenharmony_ci		dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d,
51162306a36Sopenharmony_ci								   d->desc_idx);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci		if (desc_paddr != paddr)
51462306a36Sopenharmony_ci			d = NULL;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if (!d) {
51862306a36Sopenharmony_ci		d = uc->desc;
51962306a36Sopenharmony_ci		if (d) {
52062306a36Sopenharmony_ci			dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d,
52162306a36Sopenharmony_ci								d->desc_idx);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci			if (desc_paddr != paddr)
52462306a36Sopenharmony_ci				d = NULL;
52562306a36Sopenharmony_ci		}
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return d;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistatic void udma_free_hwdesc(struct udma_chan *uc, struct udma_desc *d)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	if (uc->use_dma_pool) {
53462306a36Sopenharmony_ci		int i;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		for (i = 0; i < d->hwdesc_count; i++) {
53762306a36Sopenharmony_ci			if (!d->hwdesc[i].cppi5_desc_vaddr)
53862306a36Sopenharmony_ci				continue;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci			dma_pool_free(uc->hdesc_pool,
54162306a36Sopenharmony_ci				      d->hwdesc[i].cppi5_desc_vaddr,
54262306a36Sopenharmony_ci				      d->hwdesc[i].cppi5_desc_paddr);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci			d->hwdesc[i].cppi5_desc_vaddr = NULL;
54562306a36Sopenharmony_ci		}
54662306a36Sopenharmony_ci	} else if (d->hwdesc[0].cppi5_desc_vaddr) {
54762306a36Sopenharmony_ci		dma_free_coherent(uc->dma_dev, d->hwdesc[0].cppi5_desc_size,
54862306a36Sopenharmony_ci				  d->hwdesc[0].cppi5_desc_vaddr,
54962306a36Sopenharmony_ci				  d->hwdesc[0].cppi5_desc_paddr);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		d->hwdesc[0].cppi5_desc_vaddr = NULL;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci}
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_cistatic void udma_purge_desc_work(struct work_struct *work)
55662306a36Sopenharmony_ci{
55762306a36Sopenharmony_ci	struct udma_dev *ud = container_of(work, typeof(*ud), purge_work);
55862306a36Sopenharmony_ci	struct virt_dma_desc *vd, *_vd;
55962306a36Sopenharmony_ci	unsigned long flags;
56062306a36Sopenharmony_ci	LIST_HEAD(head);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	spin_lock_irqsave(&ud->lock, flags);
56362306a36Sopenharmony_ci	list_splice_tail_init(&ud->desc_to_purge, &head);
56462306a36Sopenharmony_ci	spin_unlock_irqrestore(&ud->lock, flags);
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	list_for_each_entry_safe(vd, _vd, &head, node) {
56762306a36Sopenharmony_ci		struct udma_chan *uc = to_udma_chan(vd->tx.chan);
56862306a36Sopenharmony_ci		struct udma_desc *d = to_udma_desc(&vd->tx);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci		udma_free_hwdesc(uc, d);
57162306a36Sopenharmony_ci		list_del(&vd->node);
57262306a36Sopenharmony_ci		kfree(d);
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* If more to purge, schedule the work again */
57662306a36Sopenharmony_ci	if (!list_empty(&ud->desc_to_purge))
57762306a36Sopenharmony_ci		schedule_work(&ud->purge_work);
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void udma_desc_free(struct virt_dma_desc *vd)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct udma_dev *ud = to_udma_dev(vd->tx.chan->device);
58362306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(vd->tx.chan);
58462306a36Sopenharmony_ci	struct udma_desc *d = to_udma_desc(&vd->tx);
58562306a36Sopenharmony_ci	unsigned long flags;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (uc->terminated_desc == d)
58862306a36Sopenharmony_ci		uc->terminated_desc = NULL;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (uc->use_dma_pool) {
59162306a36Sopenharmony_ci		udma_free_hwdesc(uc, d);
59262306a36Sopenharmony_ci		kfree(d);
59362306a36Sopenharmony_ci		return;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	spin_lock_irqsave(&ud->lock, flags);
59762306a36Sopenharmony_ci	list_add_tail(&vd->node, &ud->desc_to_purge);
59862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ud->lock, flags);
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	schedule_work(&ud->purge_work);
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic bool udma_is_chan_running(struct udma_chan *uc)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	u32 trt_ctl = 0;
60662306a36Sopenharmony_ci	u32 rrt_ctl = 0;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (uc->tchan)
60962306a36Sopenharmony_ci		trt_ctl = udma_tchanrt_read(uc, UDMA_CHAN_RT_CTL_REG);
61062306a36Sopenharmony_ci	if (uc->rchan)
61162306a36Sopenharmony_ci		rrt_ctl = udma_rchanrt_read(uc, UDMA_CHAN_RT_CTL_REG);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	if (trt_ctl & UDMA_CHAN_RT_CTL_EN || rrt_ctl & UDMA_CHAN_RT_CTL_EN)
61462306a36Sopenharmony_ci		return true;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	return false;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic bool udma_is_chan_paused(struct udma_chan *uc)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	u32 val, pause_mask;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	switch (uc->config.dir) {
62462306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
62562306a36Sopenharmony_ci		val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PEER_RT_EN_REG);
62662306a36Sopenharmony_ci		pause_mask = UDMA_PEER_RT_EN_PAUSE;
62762306a36Sopenharmony_ci		break;
62862306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
62962306a36Sopenharmony_ci		val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_RT_EN_REG);
63062306a36Sopenharmony_ci		pause_mask = UDMA_PEER_RT_EN_PAUSE;
63162306a36Sopenharmony_ci		break;
63262306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
63362306a36Sopenharmony_ci		val = udma_tchanrt_read(uc, UDMA_CHAN_RT_CTL_REG);
63462306a36Sopenharmony_ci		pause_mask = UDMA_CHAN_RT_CTL_PAUSE;
63562306a36Sopenharmony_ci		break;
63662306a36Sopenharmony_ci	default:
63762306a36Sopenharmony_ci		return false;
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	if (val & pause_mask)
64162306a36Sopenharmony_ci		return true;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	return false;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistatic inline dma_addr_t udma_get_rx_flush_hwdesc_paddr(struct udma_chan *uc)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	return uc->ud->rx_flush.hwdescs[uc->config.pkt_mode].cppi5_desc_paddr;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int udma_push_to_ring(struct udma_chan *uc, int idx)
65262306a36Sopenharmony_ci{
65362306a36Sopenharmony_ci	struct udma_desc *d = uc->desc;
65462306a36Sopenharmony_ci	struct k3_ring *ring = NULL;
65562306a36Sopenharmony_ci	dma_addr_t paddr;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	switch (uc->config.dir) {
65862306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
65962306a36Sopenharmony_ci		ring = uc->rflow->fd_ring;
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
66262306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
66362306a36Sopenharmony_ci		ring = uc->tchan->t_ring;
66462306a36Sopenharmony_ci		break;
66562306a36Sopenharmony_ci	default:
66662306a36Sopenharmony_ci		return -EINVAL;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/* RX flush packet: idx == -1 is only passed in case of DEV_TO_MEM */
67062306a36Sopenharmony_ci	if (idx == -1) {
67162306a36Sopenharmony_ci		paddr = udma_get_rx_flush_hwdesc_paddr(uc);
67262306a36Sopenharmony_ci	} else {
67362306a36Sopenharmony_ci		paddr = udma_curr_cppi5_desc_paddr(d, idx);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		wmb(); /* Ensure that writes are not moved over this point */
67662306a36Sopenharmony_ci	}
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	return k3_ringacc_ring_push(ring, &paddr);
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic bool udma_desc_is_rx_flush(struct udma_chan *uc, dma_addr_t addr)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	if (uc->config.dir != DMA_DEV_TO_MEM)
68462306a36Sopenharmony_ci		return false;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	if (addr == udma_get_rx_flush_hwdesc_paddr(uc))
68762306a36Sopenharmony_ci		return true;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	return false;
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	struct k3_ring *ring = NULL;
69562306a36Sopenharmony_ci	int ret;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	switch (uc->config.dir) {
69862306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
69962306a36Sopenharmony_ci		ring = uc->rflow->r_ring;
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
70262306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
70362306a36Sopenharmony_ci		ring = uc->tchan->tc_ring;
70462306a36Sopenharmony_ci		break;
70562306a36Sopenharmony_ci	default:
70662306a36Sopenharmony_ci		return -ENOENT;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	ret = k3_ringacc_ring_pop(ring, addr);
71062306a36Sopenharmony_ci	if (ret)
71162306a36Sopenharmony_ci		return ret;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	rmb(); /* Ensure that reads are not moved before this point */
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/* Teardown completion */
71662306a36Sopenharmony_ci	if (cppi5_desc_is_tdcm(*addr))
71762306a36Sopenharmony_ci		return 0;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	/* Check for flush descriptor */
72062306a36Sopenharmony_ci	if (udma_desc_is_rx_flush(uc, *addr))
72162306a36Sopenharmony_ci		return -ENOENT;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	return 0;
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_cistatic void udma_reset_rings(struct udma_chan *uc)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct k3_ring *ring1 = NULL;
72962306a36Sopenharmony_ci	struct k3_ring *ring2 = NULL;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	switch (uc->config.dir) {
73262306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
73362306a36Sopenharmony_ci		if (uc->rchan) {
73462306a36Sopenharmony_ci			ring1 = uc->rflow->fd_ring;
73562306a36Sopenharmony_ci			ring2 = uc->rflow->r_ring;
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci		break;
73862306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
73962306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
74062306a36Sopenharmony_ci		if (uc->tchan) {
74162306a36Sopenharmony_ci			ring1 = uc->tchan->t_ring;
74262306a36Sopenharmony_ci			ring2 = uc->tchan->tc_ring;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci		break;
74562306a36Sopenharmony_ci	default:
74662306a36Sopenharmony_ci		break;
74762306a36Sopenharmony_ci	}
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	if (ring1)
75062306a36Sopenharmony_ci		k3_ringacc_ring_reset_dma(ring1,
75162306a36Sopenharmony_ci					  k3_ringacc_ring_get_occ(ring1));
75262306a36Sopenharmony_ci	if (ring2)
75362306a36Sopenharmony_ci		k3_ringacc_ring_reset(ring2);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* make sure we are not leaking memory by stalled descriptor */
75662306a36Sopenharmony_ci	if (uc->terminated_desc) {
75762306a36Sopenharmony_ci		udma_desc_free(&uc->terminated_desc->vd);
75862306a36Sopenharmony_ci		uc->terminated_desc = NULL;
75962306a36Sopenharmony_ci	}
76062306a36Sopenharmony_ci}
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_cistatic void udma_decrement_byte_counters(struct udma_chan *uc, u32 val)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	if (uc->desc->dir == DMA_DEV_TO_MEM) {
76562306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
76662306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
76762306a36Sopenharmony_ci		if (uc->config.ep_type != PSIL_EP_NATIVE)
76862306a36Sopenharmony_ci			udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
76962306a36Sopenharmony_ci	} else {
77062306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
77162306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
77262306a36Sopenharmony_ci		if (!uc->bchan && uc->config.ep_type != PSIL_EP_NATIVE)
77362306a36Sopenharmony_ci			udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
77462306a36Sopenharmony_ci	}
77562306a36Sopenharmony_ci}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_cistatic void udma_reset_counters(struct udma_chan *uc)
77862306a36Sopenharmony_ci{
77962306a36Sopenharmony_ci	u32 val;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	if (uc->tchan) {
78262306a36Sopenharmony_ci		val = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG);
78362306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci		val = udma_tchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG);
78662306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci		val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PCNT_REG);
78962306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_PCNT_REG, val);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci		if (!uc->bchan) {
79262306a36Sopenharmony_ci			val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG);
79362306a36Sopenharmony_ci			udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
79462306a36Sopenharmony_ci		}
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci	if (uc->rchan) {
79862306a36Sopenharmony_ci		val = udma_rchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG);
79962306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci		val = udma_rchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG);
80262306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci		val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PCNT_REG);
80562306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_PCNT_REG, val);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG);
80862306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci}
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_cistatic int udma_reset_chan(struct udma_chan *uc, bool hard)
81362306a36Sopenharmony_ci{
81462306a36Sopenharmony_ci	switch (uc->config.dir) {
81562306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
81662306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 0);
81762306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0);
81862306a36Sopenharmony_ci		break;
81962306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
82062306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0);
82162306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 0);
82262306a36Sopenharmony_ci		break;
82362306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
82462306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0);
82562306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0);
82662306a36Sopenharmony_ci		break;
82762306a36Sopenharmony_ci	default:
82862306a36Sopenharmony_ci		return -EINVAL;
82962306a36Sopenharmony_ci	}
83062306a36Sopenharmony_ci
83162306a36Sopenharmony_ci	/* Reset all counters */
83262306a36Sopenharmony_ci	udma_reset_counters(uc);
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	/* Hard reset: re-initialize the channel to reset */
83562306a36Sopenharmony_ci	if (hard) {
83662306a36Sopenharmony_ci		struct udma_chan_config ucc_backup;
83762306a36Sopenharmony_ci		int ret;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		memcpy(&ucc_backup, &uc->config, sizeof(uc->config));
84062306a36Sopenharmony_ci		uc->ud->ddev.device_free_chan_resources(&uc->vc.chan);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		/* restore the channel configuration */
84362306a36Sopenharmony_ci		memcpy(&uc->config, &ucc_backup, sizeof(uc->config));
84462306a36Sopenharmony_ci		ret = uc->ud->ddev.device_alloc_chan_resources(&uc->vc.chan);
84562306a36Sopenharmony_ci		if (ret)
84662306a36Sopenharmony_ci			return ret;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		/*
84962306a36Sopenharmony_ci		 * Setting forced teardown after forced reset helps recovering
85062306a36Sopenharmony_ci		 * the rchan.
85162306a36Sopenharmony_ci		 */
85262306a36Sopenharmony_ci		if (uc->config.dir == DMA_DEV_TO_MEM)
85362306a36Sopenharmony_ci			udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
85462306a36Sopenharmony_ci					   UDMA_CHAN_RT_CTL_EN |
85562306a36Sopenharmony_ci					   UDMA_CHAN_RT_CTL_TDOWN |
85662306a36Sopenharmony_ci					   UDMA_CHAN_RT_CTL_FTDOWN);
85762306a36Sopenharmony_ci	}
85862306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_IDLE;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	return 0;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_cistatic void udma_start_desc(struct udma_chan *uc)
86462306a36Sopenharmony_ci{
86562306a36Sopenharmony_ci	struct udma_chan_config *ucc = &uc->config;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (uc->ud->match_data->type == DMA_TYPE_UDMA && ucc->pkt_mode &&
86862306a36Sopenharmony_ci	    (uc->cyclic || ucc->dir == DMA_DEV_TO_MEM)) {
86962306a36Sopenharmony_ci		int i;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		/*
87262306a36Sopenharmony_ci		 * UDMA only: Push all descriptors to ring for packet mode
87362306a36Sopenharmony_ci		 * cyclic or RX
87462306a36Sopenharmony_ci		 * PKTDMA supports pre-linked descriptor and cyclic is not
87562306a36Sopenharmony_ci		 * supported
87662306a36Sopenharmony_ci		 */
87762306a36Sopenharmony_ci		for (i = 0; i < uc->desc->sglen; i++)
87862306a36Sopenharmony_ci			udma_push_to_ring(uc, i);
87962306a36Sopenharmony_ci	} else {
88062306a36Sopenharmony_ci		udma_push_to_ring(uc, 0);
88162306a36Sopenharmony_ci	}
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_cistatic bool udma_chan_needs_reconfiguration(struct udma_chan *uc)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	/* Only PDMAs have staticTR */
88762306a36Sopenharmony_ci	if (uc->config.ep_type == PSIL_EP_NATIVE)
88862306a36Sopenharmony_ci		return false;
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	/* Check if the staticTR configuration has changed for TX */
89162306a36Sopenharmony_ci	if (memcmp(&uc->static_tr, &uc->desc->static_tr, sizeof(uc->static_tr)))
89262306a36Sopenharmony_ci		return true;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	return false;
89562306a36Sopenharmony_ci}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_cistatic int udma_start(struct udma_chan *uc)
89862306a36Sopenharmony_ci{
89962306a36Sopenharmony_ci	struct virt_dma_desc *vd = vchan_next_desc(&uc->vc);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (!vd) {
90262306a36Sopenharmony_ci		uc->desc = NULL;
90362306a36Sopenharmony_ci		return -ENOENT;
90462306a36Sopenharmony_ci	}
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	list_del(&vd->node);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	uc->desc = to_udma_desc(&vd->tx);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	/* Channel is already running and does not need reconfiguration */
91162306a36Sopenharmony_ci	if (udma_is_chan_running(uc) && !udma_chan_needs_reconfiguration(uc)) {
91262306a36Sopenharmony_ci		udma_start_desc(uc);
91362306a36Sopenharmony_ci		goto out;
91462306a36Sopenharmony_ci	}
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* Make sure that we clear the teardown bit, if it is set */
91762306a36Sopenharmony_ci	udma_reset_chan(uc, false);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	/* Push descriptors before we start the channel */
92062306a36Sopenharmony_ci	udma_start_desc(uc);
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	switch (uc->desc->dir) {
92362306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
92462306a36Sopenharmony_ci		/* Config remote TR */
92562306a36Sopenharmony_ci		if (uc->config.ep_type == PSIL_EP_PDMA_XY) {
92662306a36Sopenharmony_ci			u32 val = PDMA_STATIC_TR_Y(uc->desc->static_tr.elcnt) |
92762306a36Sopenharmony_ci				  PDMA_STATIC_TR_X(uc->desc->static_tr.elsize);
92862306a36Sopenharmony_ci			const struct udma_match_data *match_data =
92962306a36Sopenharmony_ci							uc->ud->match_data;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci			if (uc->config.enable_acc32)
93262306a36Sopenharmony_ci				val |= PDMA_STATIC_TR_XY_ACC32;
93362306a36Sopenharmony_ci			if (uc->config.enable_burst)
93462306a36Sopenharmony_ci				val |= PDMA_STATIC_TR_XY_BURST;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci			udma_rchanrt_write(uc,
93762306a36Sopenharmony_ci					   UDMA_CHAN_RT_PEER_STATIC_TR_XY_REG,
93862306a36Sopenharmony_ci					   val);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci			udma_rchanrt_write(uc,
94162306a36Sopenharmony_ci				UDMA_CHAN_RT_PEER_STATIC_TR_Z_REG,
94262306a36Sopenharmony_ci				PDMA_STATIC_TR_Z(uc->desc->static_tr.bstcnt,
94362306a36Sopenharmony_ci						 match_data->statictr_z_mask));
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci			/* save the current staticTR configuration */
94662306a36Sopenharmony_ci			memcpy(&uc->static_tr, &uc->desc->static_tr,
94762306a36Sopenharmony_ci			       sizeof(uc->static_tr));
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
95162306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci		/* Enable remote */
95462306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
95562306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_ENABLE);
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci		break;
95862306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
95962306a36Sopenharmony_ci		/* Config remote TR */
96062306a36Sopenharmony_ci		if (uc->config.ep_type == PSIL_EP_PDMA_XY) {
96162306a36Sopenharmony_ci			u32 val = PDMA_STATIC_TR_Y(uc->desc->static_tr.elcnt) |
96262306a36Sopenharmony_ci				  PDMA_STATIC_TR_X(uc->desc->static_tr.elsize);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci			if (uc->config.enable_acc32)
96562306a36Sopenharmony_ci				val |= PDMA_STATIC_TR_XY_ACC32;
96662306a36Sopenharmony_ci			if (uc->config.enable_burst)
96762306a36Sopenharmony_ci				val |= PDMA_STATIC_TR_XY_BURST;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci			udma_tchanrt_write(uc,
97062306a36Sopenharmony_ci					   UDMA_CHAN_RT_PEER_STATIC_TR_XY_REG,
97162306a36Sopenharmony_ci					   val);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci			/* save the current staticTR configuration */
97462306a36Sopenharmony_ci			memcpy(&uc->static_tr, &uc->desc->static_tr,
97562306a36Sopenharmony_ci			       sizeof(uc->static_tr));
97662306a36Sopenharmony_ci		}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci		/* Enable remote */
97962306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
98062306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_ENABLE);
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
98362306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci		break;
98662306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
98762306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
98862306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN);
98962306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
99062306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		break;
99362306a36Sopenharmony_ci	default:
99462306a36Sopenharmony_ci		return -EINVAL;
99562306a36Sopenharmony_ci	}
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_ACTIVE;
99862306a36Sopenharmony_ciout:
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_cistatic int udma_stop(struct udma_chan *uc)
100462306a36Sopenharmony_ci{
100562306a36Sopenharmony_ci	enum udma_chan_state old_state = uc->state;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_TERMINATING;
100862306a36Sopenharmony_ci	reinit_completion(&uc->teardown_completed);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	switch (uc->config.dir) {
101162306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
101262306a36Sopenharmony_ci		if (!uc->cyclic && !uc->desc)
101362306a36Sopenharmony_ci			udma_push_to_ring(uc, -1);
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci		udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
101662306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_ENABLE |
101762306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_TEARDOWN);
101862306a36Sopenharmony_ci		break;
101962306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
102062306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
102162306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_ENABLE |
102262306a36Sopenharmony_ci				   UDMA_PEER_RT_EN_FLUSH);
102362306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
102462306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN |
102562306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_TDOWN);
102662306a36Sopenharmony_ci		break;
102762306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
102862306a36Sopenharmony_ci		udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG,
102962306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_EN |
103062306a36Sopenharmony_ci				   UDMA_CHAN_RT_CTL_TDOWN);
103162306a36Sopenharmony_ci		break;
103262306a36Sopenharmony_ci	default:
103362306a36Sopenharmony_ci		uc->state = old_state;
103462306a36Sopenharmony_ci		complete_all(&uc->teardown_completed);
103562306a36Sopenharmony_ci		return -EINVAL;
103662306a36Sopenharmony_ci	}
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	return 0;
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic void udma_cyclic_packet_elapsed(struct udma_chan *uc)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct udma_desc *d = uc->desc;
104462306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	h_desc = d->hwdesc[d->desc_idx].cppi5_desc_vaddr;
104762306a36Sopenharmony_ci	cppi5_hdesc_reset_to_original(h_desc);
104862306a36Sopenharmony_ci	udma_push_to_ring(uc, d->desc_idx);
104962306a36Sopenharmony_ci	d->desc_idx = (d->desc_idx + 1) % d->sglen;
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic inline void udma_fetch_epib(struct udma_chan *uc, struct udma_desc *d)
105362306a36Sopenharmony_ci{
105462306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc = d->hwdesc[0].cppi5_desc_vaddr;
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	memcpy(d->metadata, h_desc->epib, d->metadata_size);
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_cistatic bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d)
106062306a36Sopenharmony_ci{
106162306a36Sopenharmony_ci	u32 peer_bcnt, bcnt;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	/*
106462306a36Sopenharmony_ci	 * Only TX towards PDMA is affected.
106562306a36Sopenharmony_ci	 * If DMA_PREP_INTERRUPT is not set by consumer then skip the transfer
106662306a36Sopenharmony_ci	 * completion calculation, consumer must ensure that there is no stale
106762306a36Sopenharmony_ci	 * data in DMA fabric in this case.
106862306a36Sopenharmony_ci	 */
106962306a36Sopenharmony_ci	if (uc->config.ep_type == PSIL_EP_NATIVE ||
107062306a36Sopenharmony_ci	    uc->config.dir != DMA_MEM_TO_DEV || !(uc->config.tx_flags & DMA_PREP_INTERRUPT))
107162306a36Sopenharmony_ci		return true;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	peer_bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG);
107462306a36Sopenharmony_ci	bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* Transfer is incomplete, store current residue and time stamp */
107762306a36Sopenharmony_ci	if (peer_bcnt < bcnt) {
107862306a36Sopenharmony_ci		uc->tx_drain.residue = bcnt - peer_bcnt;
107962306a36Sopenharmony_ci		uc->tx_drain.tstamp = ktime_get();
108062306a36Sopenharmony_ci		return false;
108162306a36Sopenharmony_ci	}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	return true;
108462306a36Sopenharmony_ci}
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic void udma_check_tx_completion(struct work_struct *work)
108762306a36Sopenharmony_ci{
108862306a36Sopenharmony_ci	struct udma_chan *uc = container_of(work, typeof(*uc),
108962306a36Sopenharmony_ci					    tx_drain.work.work);
109062306a36Sopenharmony_ci	bool desc_done = true;
109162306a36Sopenharmony_ci	u32 residue_diff;
109262306a36Sopenharmony_ci	ktime_t time_diff;
109362306a36Sopenharmony_ci	unsigned long delay;
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	while (1) {
109662306a36Sopenharmony_ci		if (uc->desc) {
109762306a36Sopenharmony_ci			/* Get previous residue and time stamp */
109862306a36Sopenharmony_ci			residue_diff = uc->tx_drain.residue;
109962306a36Sopenharmony_ci			time_diff = uc->tx_drain.tstamp;
110062306a36Sopenharmony_ci			/*
110162306a36Sopenharmony_ci			 * Get current residue and time stamp or see if
110262306a36Sopenharmony_ci			 * transfer is complete
110362306a36Sopenharmony_ci			 */
110462306a36Sopenharmony_ci			desc_done = udma_is_desc_really_done(uc, uc->desc);
110562306a36Sopenharmony_ci		}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci		if (!desc_done) {
110862306a36Sopenharmony_ci			/*
110962306a36Sopenharmony_ci			 * Find the time delta and residue delta w.r.t
111062306a36Sopenharmony_ci			 * previous poll
111162306a36Sopenharmony_ci			 */
111262306a36Sopenharmony_ci			time_diff = ktime_sub(uc->tx_drain.tstamp,
111362306a36Sopenharmony_ci					      time_diff) + 1;
111462306a36Sopenharmony_ci			residue_diff -= uc->tx_drain.residue;
111562306a36Sopenharmony_ci			if (residue_diff) {
111662306a36Sopenharmony_ci				/*
111762306a36Sopenharmony_ci				 * Try to guess when we should check
111862306a36Sopenharmony_ci				 * next time by calculating rate at
111962306a36Sopenharmony_ci				 * which data is being drained at the
112062306a36Sopenharmony_ci				 * peer device
112162306a36Sopenharmony_ci				 */
112262306a36Sopenharmony_ci				delay = (time_diff / residue_diff) *
112362306a36Sopenharmony_ci					uc->tx_drain.residue;
112462306a36Sopenharmony_ci			} else {
112562306a36Sopenharmony_ci				/* No progress, check again in 1 second  */
112662306a36Sopenharmony_ci				schedule_delayed_work(&uc->tx_drain.work, HZ);
112762306a36Sopenharmony_ci				break;
112862306a36Sopenharmony_ci			}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci			usleep_range(ktime_to_us(delay),
113162306a36Sopenharmony_ci				     ktime_to_us(delay) + 10);
113262306a36Sopenharmony_ci			continue;
113362306a36Sopenharmony_ci		}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		if (uc->desc) {
113662306a36Sopenharmony_ci			struct udma_desc *d = uc->desc;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci			udma_decrement_byte_counters(uc, d->residue);
113962306a36Sopenharmony_ci			udma_start(uc);
114062306a36Sopenharmony_ci			vchan_cookie_complete(&d->vd);
114162306a36Sopenharmony_ci			break;
114262306a36Sopenharmony_ci		}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci		break;
114562306a36Sopenharmony_ci	}
114662306a36Sopenharmony_ci}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_cistatic irqreturn_t udma_ring_irq_handler(int irq, void *data)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	struct udma_chan *uc = data;
115162306a36Sopenharmony_ci	struct udma_desc *d;
115262306a36Sopenharmony_ci	dma_addr_t paddr = 0;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	if (udma_pop_from_ring(uc, &paddr) || !paddr)
115562306a36Sopenharmony_ci		return IRQ_HANDLED;
115662306a36Sopenharmony_ci
115762306a36Sopenharmony_ci	spin_lock(&uc->vc.lock);
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci	/* Teardown completion message */
116062306a36Sopenharmony_ci	if (cppi5_desc_is_tdcm(paddr)) {
116162306a36Sopenharmony_ci		complete_all(&uc->teardown_completed);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci		if (uc->terminated_desc) {
116462306a36Sopenharmony_ci			udma_desc_free(&uc->terminated_desc->vd);
116562306a36Sopenharmony_ci			uc->terminated_desc = NULL;
116662306a36Sopenharmony_ci		}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci		if (!uc->desc)
116962306a36Sopenharmony_ci			udma_start(uc);
117062306a36Sopenharmony_ci
117162306a36Sopenharmony_ci		goto out;
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	d = udma_udma_desc_from_paddr(uc, paddr);
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	if (d) {
117762306a36Sopenharmony_ci		dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d,
117862306a36Sopenharmony_ci								   d->desc_idx);
117962306a36Sopenharmony_ci		if (desc_paddr != paddr) {
118062306a36Sopenharmony_ci			dev_err(uc->ud->dev, "not matching descriptors!\n");
118162306a36Sopenharmony_ci			goto out;
118262306a36Sopenharmony_ci		}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci		if (d == uc->desc) {
118562306a36Sopenharmony_ci			/* active descriptor */
118662306a36Sopenharmony_ci			if (uc->cyclic) {
118762306a36Sopenharmony_ci				udma_cyclic_packet_elapsed(uc);
118862306a36Sopenharmony_ci				vchan_cyclic_callback(&d->vd);
118962306a36Sopenharmony_ci			} else {
119062306a36Sopenharmony_ci				if (udma_is_desc_really_done(uc, d)) {
119162306a36Sopenharmony_ci					udma_decrement_byte_counters(uc, d->residue);
119262306a36Sopenharmony_ci					udma_start(uc);
119362306a36Sopenharmony_ci					vchan_cookie_complete(&d->vd);
119462306a36Sopenharmony_ci				} else {
119562306a36Sopenharmony_ci					schedule_delayed_work(&uc->tx_drain.work,
119662306a36Sopenharmony_ci							      0);
119762306a36Sopenharmony_ci				}
119862306a36Sopenharmony_ci			}
119962306a36Sopenharmony_ci		} else {
120062306a36Sopenharmony_ci			/*
120162306a36Sopenharmony_ci			 * terminated descriptor, mark the descriptor as
120262306a36Sopenharmony_ci			 * completed to update the channel's cookie marker
120362306a36Sopenharmony_ci			 */
120462306a36Sopenharmony_ci			dma_cookie_complete(&d->vd.tx);
120562306a36Sopenharmony_ci		}
120662306a36Sopenharmony_ci	}
120762306a36Sopenharmony_ciout:
120862306a36Sopenharmony_ci	spin_unlock(&uc->vc.lock);
120962306a36Sopenharmony_ci
121062306a36Sopenharmony_ci	return IRQ_HANDLED;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic irqreturn_t udma_udma_irq_handler(int irq, void *data)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	struct udma_chan *uc = data;
121662306a36Sopenharmony_ci	struct udma_desc *d;
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci	spin_lock(&uc->vc.lock);
121962306a36Sopenharmony_ci	d = uc->desc;
122062306a36Sopenharmony_ci	if (d) {
122162306a36Sopenharmony_ci		d->tr_idx = (d->tr_idx + 1) % d->sglen;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		if (uc->cyclic) {
122462306a36Sopenharmony_ci			vchan_cyclic_callback(&d->vd);
122562306a36Sopenharmony_ci		} else {
122662306a36Sopenharmony_ci			/* TODO: figure out the real amount of data */
122762306a36Sopenharmony_ci			udma_decrement_byte_counters(uc, d->residue);
122862306a36Sopenharmony_ci			udma_start(uc);
122962306a36Sopenharmony_ci			vchan_cookie_complete(&d->vd);
123062306a36Sopenharmony_ci		}
123162306a36Sopenharmony_ci	}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	spin_unlock(&uc->vc.lock);
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	return IRQ_HANDLED;
123662306a36Sopenharmony_ci}
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci/**
123962306a36Sopenharmony_ci * __udma_alloc_gp_rflow_range - alloc range of GP RX flows
124062306a36Sopenharmony_ci * @ud: UDMA device
124162306a36Sopenharmony_ci * @from: Start the search from this flow id number
124262306a36Sopenharmony_ci * @cnt: Number of consecutive flow ids to allocate
124362306a36Sopenharmony_ci *
124462306a36Sopenharmony_ci * Allocate range of RX flow ids for future use, those flows can be requested
124562306a36Sopenharmony_ci * only using explicit flow id number. if @from is set to -1 it will try to find
124662306a36Sopenharmony_ci * first free range. if @from is positive value it will force allocation only
124762306a36Sopenharmony_ci * of the specified range of flows.
124862306a36Sopenharmony_ci *
124962306a36Sopenharmony_ci * Returns -ENOMEM if can't find free range.
125062306a36Sopenharmony_ci * -EEXIST if requested range is busy.
125162306a36Sopenharmony_ci * -EINVAL if wrong input values passed.
125262306a36Sopenharmony_ci * Returns flow id on success.
125362306a36Sopenharmony_ci */
125462306a36Sopenharmony_cistatic int __udma_alloc_gp_rflow_range(struct udma_dev *ud, int from, int cnt)
125562306a36Sopenharmony_ci{
125662306a36Sopenharmony_ci	int start, tmp_from;
125762306a36Sopenharmony_ci	DECLARE_BITMAP(tmp, K3_UDMA_MAX_RFLOWS);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	tmp_from = from;
126062306a36Sopenharmony_ci	if (tmp_from < 0)
126162306a36Sopenharmony_ci		tmp_from = ud->rchan_cnt;
126262306a36Sopenharmony_ci	/* default flows can't be allocated and accessible only by id */
126362306a36Sopenharmony_ci	if (tmp_from < ud->rchan_cnt)
126462306a36Sopenharmony_ci		return -EINVAL;
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (tmp_from + cnt > ud->rflow_cnt)
126762306a36Sopenharmony_ci		return -EINVAL;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	bitmap_or(tmp, ud->rflow_gp_map, ud->rflow_gp_map_allocated,
127062306a36Sopenharmony_ci		  ud->rflow_cnt);
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci	start = bitmap_find_next_zero_area(tmp,
127362306a36Sopenharmony_ci					   ud->rflow_cnt,
127462306a36Sopenharmony_ci					   tmp_from, cnt, 0);
127562306a36Sopenharmony_ci	if (start >= ud->rflow_cnt)
127662306a36Sopenharmony_ci		return -ENOMEM;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	if (from >= 0 && start != from)
127962306a36Sopenharmony_ci		return -EEXIST;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	bitmap_set(ud->rflow_gp_map_allocated, start, cnt);
128262306a36Sopenharmony_ci	return start;
128362306a36Sopenharmony_ci}
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_cistatic int __udma_free_gp_rflow_range(struct udma_dev *ud, int from, int cnt)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	if (from < ud->rchan_cnt)
128862306a36Sopenharmony_ci		return -EINVAL;
128962306a36Sopenharmony_ci	if (from + cnt > ud->rflow_cnt)
129062306a36Sopenharmony_ci		return -EINVAL;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	bitmap_clear(ud->rflow_gp_map_allocated, from, cnt);
129362306a36Sopenharmony_ci	return 0;
129462306a36Sopenharmony_ci}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_cistatic struct udma_rflow *__udma_get_rflow(struct udma_dev *ud, int id)
129762306a36Sopenharmony_ci{
129862306a36Sopenharmony_ci	/*
129962306a36Sopenharmony_ci	 * Attempt to request rflow by ID can be made for any rflow
130062306a36Sopenharmony_ci	 * if not in use with assumption that caller knows what's doing.
130162306a36Sopenharmony_ci	 * TI-SCI FW will perform additional permission check ant way, it's
130262306a36Sopenharmony_ci	 * safe
130362306a36Sopenharmony_ci	 */
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	if (id < 0 || id >= ud->rflow_cnt)
130662306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	if (test_bit(id, ud->rflow_in_use))
130962306a36Sopenharmony_ci		return ERR_PTR(-ENOENT);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	if (ud->rflow_gp_map) {
131262306a36Sopenharmony_ci		/* GP rflow has to be allocated first */
131362306a36Sopenharmony_ci		if (!test_bit(id, ud->rflow_gp_map) &&
131462306a36Sopenharmony_ci		    !test_bit(id, ud->rflow_gp_map_allocated))
131562306a36Sopenharmony_ci			return ERR_PTR(-EINVAL);
131662306a36Sopenharmony_ci	}
131762306a36Sopenharmony_ci
131862306a36Sopenharmony_ci	dev_dbg(ud->dev, "get rflow%d\n", id);
131962306a36Sopenharmony_ci	set_bit(id, ud->rflow_in_use);
132062306a36Sopenharmony_ci	return &ud->rflows[id];
132162306a36Sopenharmony_ci}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_cistatic void __udma_put_rflow(struct udma_dev *ud, struct udma_rflow *rflow)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	if (!test_bit(rflow->id, ud->rflow_in_use)) {
132662306a36Sopenharmony_ci		dev_err(ud->dev, "attempt to put unused rflow%d\n", rflow->id);
132762306a36Sopenharmony_ci		return;
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	dev_dbg(ud->dev, "put rflow%d\n", rflow->id);
133162306a36Sopenharmony_ci	clear_bit(rflow->id, ud->rflow_in_use);
133262306a36Sopenharmony_ci}
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci#define UDMA_RESERVE_RESOURCE(res)					\
133562306a36Sopenharmony_cistatic struct udma_##res *__udma_reserve_##res(struct udma_dev *ud,	\
133662306a36Sopenharmony_ci					       enum udma_tp_level tpl,	\
133762306a36Sopenharmony_ci					       int id)			\
133862306a36Sopenharmony_ci{									\
133962306a36Sopenharmony_ci	if (id >= 0) {							\
134062306a36Sopenharmony_ci		if (test_bit(id, ud->res##_map)) {			\
134162306a36Sopenharmony_ci			dev_err(ud->dev, "res##%d is in use\n", id);	\
134262306a36Sopenharmony_ci			return ERR_PTR(-ENOENT);			\
134362306a36Sopenharmony_ci		}							\
134462306a36Sopenharmony_ci	} else {							\
134562306a36Sopenharmony_ci		int start;						\
134662306a36Sopenharmony_ci									\
134762306a36Sopenharmony_ci		if (tpl >= ud->res##_tpl.levels)			\
134862306a36Sopenharmony_ci			tpl = ud->res##_tpl.levels - 1;			\
134962306a36Sopenharmony_ci									\
135062306a36Sopenharmony_ci		start = ud->res##_tpl.start_idx[tpl];			\
135162306a36Sopenharmony_ci									\
135262306a36Sopenharmony_ci		id = find_next_zero_bit(ud->res##_map, ud->res##_cnt,	\
135362306a36Sopenharmony_ci					start);				\
135462306a36Sopenharmony_ci		if (id == ud->res##_cnt) {				\
135562306a36Sopenharmony_ci			return ERR_PTR(-ENOENT);			\
135662306a36Sopenharmony_ci		}							\
135762306a36Sopenharmony_ci	}								\
135862306a36Sopenharmony_ci									\
135962306a36Sopenharmony_ci	set_bit(id, ud->res##_map);					\
136062306a36Sopenharmony_ci	return &ud->res##s[id];						\
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(bchan);
136462306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(tchan);
136562306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(rchan);
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_cistatic int bcdma_get_bchan(struct udma_chan *uc)
136862306a36Sopenharmony_ci{
136962306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
137062306a36Sopenharmony_ci	enum udma_tp_level tpl;
137162306a36Sopenharmony_ci	int ret;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	if (uc->bchan) {
137462306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: already have bchan%d allocated\n",
137562306a36Sopenharmony_ci			uc->id, uc->bchan->id);
137662306a36Sopenharmony_ci		return 0;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/*
138062306a36Sopenharmony_ci	 * Use normal channels for peripherals, and highest TPL channel for
138162306a36Sopenharmony_ci	 * mem2mem
138262306a36Sopenharmony_ci	 */
138362306a36Sopenharmony_ci	if (uc->config.tr_trigger_type)
138462306a36Sopenharmony_ci		tpl = 0;
138562306a36Sopenharmony_ci	else
138662306a36Sopenharmony_ci		tpl = ud->bchan_tpl.levels - 1;
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci	uc->bchan = __udma_reserve_bchan(ud, tpl, -1);
138962306a36Sopenharmony_ci	if (IS_ERR(uc->bchan)) {
139062306a36Sopenharmony_ci		ret = PTR_ERR(uc->bchan);
139162306a36Sopenharmony_ci		uc->bchan = NULL;
139262306a36Sopenharmony_ci		return ret;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	uc->tchan = uc->bchan;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	return 0;
139862306a36Sopenharmony_ci}
139962306a36Sopenharmony_ci
140062306a36Sopenharmony_cistatic int udma_get_tchan(struct udma_chan *uc)
140162306a36Sopenharmony_ci{
140262306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
140362306a36Sopenharmony_ci	int ret;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (uc->tchan) {
140662306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: already have tchan%d allocated\n",
140762306a36Sopenharmony_ci			uc->id, uc->tchan->id);
140862306a36Sopenharmony_ci		return 0;
140962306a36Sopenharmony_ci	}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	/*
141262306a36Sopenharmony_ci	 * mapped_channel_id is -1 for UDMA, BCDMA and PKTDMA unmapped channels.
141362306a36Sopenharmony_ci	 * For PKTDMA mapped channels it is configured to a channel which must
141462306a36Sopenharmony_ci	 * be used to service the peripheral.
141562306a36Sopenharmony_ci	 */
141662306a36Sopenharmony_ci	uc->tchan = __udma_reserve_tchan(ud, uc->config.channel_tpl,
141762306a36Sopenharmony_ci					 uc->config.mapped_channel_id);
141862306a36Sopenharmony_ci	if (IS_ERR(uc->tchan)) {
141962306a36Sopenharmony_ci		ret = PTR_ERR(uc->tchan);
142062306a36Sopenharmony_ci		uc->tchan = NULL;
142162306a36Sopenharmony_ci		return ret;
142262306a36Sopenharmony_ci	}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (ud->tflow_cnt) {
142562306a36Sopenharmony_ci		int tflow_id;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		/* Only PKTDMA have support for tx flows */
142862306a36Sopenharmony_ci		if (uc->config.default_flow_id >= 0)
142962306a36Sopenharmony_ci			tflow_id = uc->config.default_flow_id;
143062306a36Sopenharmony_ci		else
143162306a36Sopenharmony_ci			tflow_id = uc->tchan->id;
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci		if (test_bit(tflow_id, ud->tflow_map)) {
143462306a36Sopenharmony_ci			dev_err(ud->dev, "tflow%d is in use\n", tflow_id);
143562306a36Sopenharmony_ci			clear_bit(uc->tchan->id, ud->tchan_map);
143662306a36Sopenharmony_ci			uc->tchan = NULL;
143762306a36Sopenharmony_ci			return -ENOENT;
143862306a36Sopenharmony_ci		}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci		uc->tchan->tflow_id = tflow_id;
144162306a36Sopenharmony_ci		set_bit(tflow_id, ud->tflow_map);
144262306a36Sopenharmony_ci	} else {
144362306a36Sopenharmony_ci		uc->tchan->tflow_id = -1;
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	return 0;
144762306a36Sopenharmony_ci}
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_cistatic int udma_get_rchan(struct udma_chan *uc)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
145262306a36Sopenharmony_ci	int ret;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	if (uc->rchan) {
145562306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: already have rchan%d allocated\n",
145662306a36Sopenharmony_ci			uc->id, uc->rchan->id);
145762306a36Sopenharmony_ci		return 0;
145862306a36Sopenharmony_ci	}
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	/*
146162306a36Sopenharmony_ci	 * mapped_channel_id is -1 for UDMA, BCDMA and PKTDMA unmapped channels.
146262306a36Sopenharmony_ci	 * For PKTDMA mapped channels it is configured to a channel which must
146362306a36Sopenharmony_ci	 * be used to service the peripheral.
146462306a36Sopenharmony_ci	 */
146562306a36Sopenharmony_ci	uc->rchan = __udma_reserve_rchan(ud, uc->config.channel_tpl,
146662306a36Sopenharmony_ci					 uc->config.mapped_channel_id);
146762306a36Sopenharmony_ci	if (IS_ERR(uc->rchan)) {
146862306a36Sopenharmony_ci		ret = PTR_ERR(uc->rchan);
146962306a36Sopenharmony_ci		uc->rchan = NULL;
147062306a36Sopenharmony_ci		return ret;
147162306a36Sopenharmony_ci	}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic int udma_get_chan_pair(struct udma_chan *uc)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
147962306a36Sopenharmony_ci	int chan_id, end;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	if ((uc->tchan && uc->rchan) && uc->tchan->id == uc->rchan->id) {
148262306a36Sopenharmony_ci		dev_info(ud->dev, "chan%d: already have %d pair allocated\n",
148362306a36Sopenharmony_ci			 uc->id, uc->tchan->id);
148462306a36Sopenharmony_ci		return 0;
148562306a36Sopenharmony_ci	}
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	if (uc->tchan) {
148862306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: already have tchan%d allocated\n",
148962306a36Sopenharmony_ci			uc->id, uc->tchan->id);
149062306a36Sopenharmony_ci		return -EBUSY;
149162306a36Sopenharmony_ci	} else if (uc->rchan) {
149262306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: already have rchan%d allocated\n",
149362306a36Sopenharmony_ci			uc->id, uc->rchan->id);
149462306a36Sopenharmony_ci		return -EBUSY;
149562306a36Sopenharmony_ci	}
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	/* Can be optimized, but let's have it like this for now */
149862306a36Sopenharmony_ci	end = min(ud->tchan_cnt, ud->rchan_cnt);
149962306a36Sopenharmony_ci	/*
150062306a36Sopenharmony_ci	 * Try to use the highest TPL channel pair for MEM_TO_MEM channels
150162306a36Sopenharmony_ci	 * Note: in UDMAP the channel TPL is symmetric between tchan and rchan
150262306a36Sopenharmony_ci	 */
150362306a36Sopenharmony_ci	chan_id = ud->tchan_tpl.start_idx[ud->tchan_tpl.levels - 1];
150462306a36Sopenharmony_ci	for (; chan_id < end; chan_id++) {
150562306a36Sopenharmony_ci		if (!test_bit(chan_id, ud->tchan_map) &&
150662306a36Sopenharmony_ci		    !test_bit(chan_id, ud->rchan_map))
150762306a36Sopenharmony_ci			break;
150862306a36Sopenharmony_ci	}
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (chan_id == end)
151162306a36Sopenharmony_ci		return -ENOENT;
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	set_bit(chan_id, ud->tchan_map);
151462306a36Sopenharmony_ci	set_bit(chan_id, ud->rchan_map);
151562306a36Sopenharmony_ci	uc->tchan = &ud->tchans[chan_id];
151662306a36Sopenharmony_ci	uc->rchan = &ud->rchans[chan_id];
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci	/* UDMA does not use tx flows */
151962306a36Sopenharmony_ci	uc->tchan->tflow_id = -1;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	return 0;
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistatic int udma_get_rflow(struct udma_chan *uc, int flow_id)
152562306a36Sopenharmony_ci{
152662306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
152762306a36Sopenharmony_ci	int ret;
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	if (!uc->rchan) {
153062306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: does not have rchan??\n", uc->id);
153162306a36Sopenharmony_ci		return -EINVAL;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (uc->rflow) {
153562306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: already have rflow%d allocated\n",
153662306a36Sopenharmony_ci			uc->id, uc->rflow->id);
153762306a36Sopenharmony_ci		return 0;
153862306a36Sopenharmony_ci	}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci	uc->rflow = __udma_get_rflow(ud, flow_id);
154162306a36Sopenharmony_ci	if (IS_ERR(uc->rflow)) {
154262306a36Sopenharmony_ci		ret = PTR_ERR(uc->rflow);
154362306a36Sopenharmony_ci		uc->rflow = NULL;
154462306a36Sopenharmony_ci		return ret;
154562306a36Sopenharmony_ci	}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci	return 0;
154862306a36Sopenharmony_ci}
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_cistatic void bcdma_put_bchan(struct udma_chan *uc)
155162306a36Sopenharmony_ci{
155262306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	if (uc->bchan) {
155562306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: put bchan%d\n", uc->id,
155662306a36Sopenharmony_ci			uc->bchan->id);
155762306a36Sopenharmony_ci		clear_bit(uc->bchan->id, ud->bchan_map);
155862306a36Sopenharmony_ci		uc->bchan = NULL;
155962306a36Sopenharmony_ci		uc->tchan = NULL;
156062306a36Sopenharmony_ci	}
156162306a36Sopenharmony_ci}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_cistatic void udma_put_rchan(struct udma_chan *uc)
156462306a36Sopenharmony_ci{
156562306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_ci	if (uc->rchan) {
156862306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: put rchan%d\n", uc->id,
156962306a36Sopenharmony_ci			uc->rchan->id);
157062306a36Sopenharmony_ci		clear_bit(uc->rchan->id, ud->rchan_map);
157162306a36Sopenharmony_ci		uc->rchan = NULL;
157262306a36Sopenharmony_ci	}
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic void udma_put_tchan(struct udma_chan *uc)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	if (uc->tchan) {
158062306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: put tchan%d\n", uc->id,
158162306a36Sopenharmony_ci			uc->tchan->id);
158262306a36Sopenharmony_ci		clear_bit(uc->tchan->id, ud->tchan_map);
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci		if (uc->tchan->tflow_id >= 0)
158562306a36Sopenharmony_ci			clear_bit(uc->tchan->tflow_id, ud->tflow_map);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci		uc->tchan = NULL;
158862306a36Sopenharmony_ci	}
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic void udma_put_rflow(struct udma_chan *uc)
159262306a36Sopenharmony_ci{
159362306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (uc->rflow) {
159662306a36Sopenharmony_ci		dev_dbg(ud->dev, "chan%d: put rflow%d\n", uc->id,
159762306a36Sopenharmony_ci			uc->rflow->id);
159862306a36Sopenharmony_ci		__udma_put_rflow(ud, uc->rflow);
159962306a36Sopenharmony_ci		uc->rflow = NULL;
160062306a36Sopenharmony_ci	}
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic void bcdma_free_bchan_resources(struct udma_chan *uc)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	if (!uc->bchan)
160662306a36Sopenharmony_ci		return;
160762306a36Sopenharmony_ci
160862306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->bchan->tc_ring);
160962306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->bchan->t_ring);
161062306a36Sopenharmony_ci	uc->bchan->tc_ring = NULL;
161162306a36Sopenharmony_ci	uc->bchan->t_ring = NULL;
161262306a36Sopenharmony_ci	k3_configure_chan_coherency(&uc->vc.chan, 0);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	bcdma_put_bchan(uc);
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_cistatic int bcdma_alloc_bchan_resources(struct udma_chan *uc)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	struct k3_ring_cfg ring_cfg;
162062306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
162162306a36Sopenharmony_ci	int ret;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	ret = bcdma_get_bchan(uc);
162462306a36Sopenharmony_ci	if (ret)
162562306a36Sopenharmony_ci		return ret;
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	ret = k3_ringacc_request_rings_pair(ud->ringacc, uc->bchan->id, -1,
162862306a36Sopenharmony_ci					    &uc->bchan->t_ring,
162962306a36Sopenharmony_ci					    &uc->bchan->tc_ring);
163062306a36Sopenharmony_ci	if (ret) {
163162306a36Sopenharmony_ci		ret = -EBUSY;
163262306a36Sopenharmony_ci		goto err_ring;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	memset(&ring_cfg, 0, sizeof(ring_cfg));
163662306a36Sopenharmony_ci	ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE;
163762306a36Sopenharmony_ci	ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8;
163862306a36Sopenharmony_ci	ring_cfg.mode = K3_RINGACC_RING_MODE_RING;
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci	k3_configure_chan_coherency(&uc->vc.chan, ud->asel);
164162306a36Sopenharmony_ci	ring_cfg.asel = ud->asel;
164262306a36Sopenharmony_ci	ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan);
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	ret = k3_ringacc_ring_cfg(uc->bchan->t_ring, &ring_cfg);
164562306a36Sopenharmony_ci	if (ret)
164662306a36Sopenharmony_ci		goto err_ringcfg;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	return 0;
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cierr_ringcfg:
165162306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->bchan->tc_ring);
165262306a36Sopenharmony_ci	uc->bchan->tc_ring = NULL;
165362306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->bchan->t_ring);
165462306a36Sopenharmony_ci	uc->bchan->t_ring = NULL;
165562306a36Sopenharmony_ci	k3_configure_chan_coherency(&uc->vc.chan, 0);
165662306a36Sopenharmony_cierr_ring:
165762306a36Sopenharmony_ci	bcdma_put_bchan(uc);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	return ret;
166062306a36Sopenharmony_ci}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_cistatic void udma_free_tx_resources(struct udma_chan *uc)
166362306a36Sopenharmony_ci{
166462306a36Sopenharmony_ci	if (!uc->tchan)
166562306a36Sopenharmony_ci		return;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->tchan->t_ring);
166862306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->tchan->tc_ring);
166962306a36Sopenharmony_ci	uc->tchan->t_ring = NULL;
167062306a36Sopenharmony_ci	uc->tchan->tc_ring = NULL;
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_ci	udma_put_tchan(uc);
167362306a36Sopenharmony_ci}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_cistatic int udma_alloc_tx_resources(struct udma_chan *uc)
167662306a36Sopenharmony_ci{
167762306a36Sopenharmony_ci	struct k3_ring_cfg ring_cfg;
167862306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
167962306a36Sopenharmony_ci	struct udma_tchan *tchan;
168062306a36Sopenharmony_ci	int ring_idx, ret;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	ret = udma_get_tchan(uc);
168362306a36Sopenharmony_ci	if (ret)
168462306a36Sopenharmony_ci		return ret;
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	tchan = uc->tchan;
168762306a36Sopenharmony_ci	if (tchan->tflow_id >= 0)
168862306a36Sopenharmony_ci		ring_idx = tchan->tflow_id;
168962306a36Sopenharmony_ci	else
169062306a36Sopenharmony_ci		ring_idx = ud->bchan_cnt + tchan->id;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	ret = k3_ringacc_request_rings_pair(ud->ringacc, ring_idx, -1,
169362306a36Sopenharmony_ci					    &tchan->t_ring,
169462306a36Sopenharmony_ci					    &tchan->tc_ring);
169562306a36Sopenharmony_ci	if (ret) {
169662306a36Sopenharmony_ci		ret = -EBUSY;
169762306a36Sopenharmony_ci		goto err_ring;
169862306a36Sopenharmony_ci	}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	memset(&ring_cfg, 0, sizeof(ring_cfg));
170162306a36Sopenharmony_ci	ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE;
170262306a36Sopenharmony_ci	ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8;
170362306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_UDMA) {
170462306a36Sopenharmony_ci		ring_cfg.mode = K3_RINGACC_RING_MODE_MESSAGE;
170562306a36Sopenharmony_ci	} else {
170662306a36Sopenharmony_ci		ring_cfg.mode = K3_RINGACC_RING_MODE_RING;
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci		k3_configure_chan_coherency(&uc->vc.chan, uc->config.asel);
170962306a36Sopenharmony_ci		ring_cfg.asel = uc->config.asel;
171062306a36Sopenharmony_ci		ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan);
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	ret = k3_ringacc_ring_cfg(tchan->t_ring, &ring_cfg);
171462306a36Sopenharmony_ci	ret |= k3_ringacc_ring_cfg(tchan->tc_ring, &ring_cfg);
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci	if (ret)
171762306a36Sopenharmony_ci		goto err_ringcfg;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return 0;
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_cierr_ringcfg:
172262306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->tchan->tc_ring);
172362306a36Sopenharmony_ci	uc->tchan->tc_ring = NULL;
172462306a36Sopenharmony_ci	k3_ringacc_ring_free(uc->tchan->t_ring);
172562306a36Sopenharmony_ci	uc->tchan->t_ring = NULL;
172662306a36Sopenharmony_cierr_ring:
172762306a36Sopenharmony_ci	udma_put_tchan(uc);
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	return ret;
173062306a36Sopenharmony_ci}
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_cistatic void udma_free_rx_resources(struct udma_chan *uc)
173362306a36Sopenharmony_ci{
173462306a36Sopenharmony_ci	if (!uc->rchan)
173562306a36Sopenharmony_ci		return;
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	if (uc->rflow) {
173862306a36Sopenharmony_ci		struct udma_rflow *rflow = uc->rflow;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci		k3_ringacc_ring_free(rflow->fd_ring);
174162306a36Sopenharmony_ci		k3_ringacc_ring_free(rflow->r_ring);
174262306a36Sopenharmony_ci		rflow->fd_ring = NULL;
174362306a36Sopenharmony_ci		rflow->r_ring = NULL;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci		udma_put_rflow(uc);
174662306a36Sopenharmony_ci	}
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	udma_put_rchan(uc);
174962306a36Sopenharmony_ci}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_cistatic int udma_alloc_rx_resources(struct udma_chan *uc)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
175462306a36Sopenharmony_ci	struct k3_ring_cfg ring_cfg;
175562306a36Sopenharmony_ci	struct udma_rflow *rflow;
175662306a36Sopenharmony_ci	int fd_ring_id;
175762306a36Sopenharmony_ci	int ret;
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_ci	ret = udma_get_rchan(uc);
176062306a36Sopenharmony_ci	if (ret)
176162306a36Sopenharmony_ci		return ret;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	/* For MEM_TO_MEM we don't need rflow or rings */
176462306a36Sopenharmony_ci	if (uc->config.dir == DMA_MEM_TO_MEM)
176562306a36Sopenharmony_ci		return 0;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	if (uc->config.default_flow_id >= 0)
176862306a36Sopenharmony_ci		ret = udma_get_rflow(uc, uc->config.default_flow_id);
176962306a36Sopenharmony_ci	else
177062306a36Sopenharmony_ci		ret = udma_get_rflow(uc, uc->rchan->id);
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	if (ret) {
177362306a36Sopenharmony_ci		ret = -EBUSY;
177462306a36Sopenharmony_ci		goto err_rflow;
177562306a36Sopenharmony_ci	}
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	rflow = uc->rflow;
177862306a36Sopenharmony_ci	if (ud->tflow_cnt)
177962306a36Sopenharmony_ci		fd_ring_id = ud->tflow_cnt + rflow->id;
178062306a36Sopenharmony_ci	else
178162306a36Sopenharmony_ci		fd_ring_id = ud->bchan_cnt + ud->tchan_cnt + ud->echan_cnt +
178262306a36Sopenharmony_ci			     uc->rchan->id;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	ret = k3_ringacc_request_rings_pair(ud->ringacc, fd_ring_id, -1,
178562306a36Sopenharmony_ci					    &rflow->fd_ring, &rflow->r_ring);
178662306a36Sopenharmony_ci	if (ret) {
178762306a36Sopenharmony_ci		ret = -EBUSY;
178862306a36Sopenharmony_ci		goto err_ring;
178962306a36Sopenharmony_ci	}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	memset(&ring_cfg, 0, sizeof(ring_cfg));
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8;
179462306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_UDMA) {
179562306a36Sopenharmony_ci		if (uc->config.pkt_mode)
179662306a36Sopenharmony_ci			ring_cfg.size = SG_MAX_SEGMENTS;
179762306a36Sopenharmony_ci		else
179862306a36Sopenharmony_ci			ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE;
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci		ring_cfg.mode = K3_RINGACC_RING_MODE_MESSAGE;
180162306a36Sopenharmony_ci	} else {
180262306a36Sopenharmony_ci		ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE;
180362306a36Sopenharmony_ci		ring_cfg.mode = K3_RINGACC_RING_MODE_RING;
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci		k3_configure_chan_coherency(&uc->vc.chan, uc->config.asel);
180662306a36Sopenharmony_ci		ring_cfg.asel = uc->config.asel;
180762306a36Sopenharmony_ci		ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan);
180862306a36Sopenharmony_ci	}
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	ret = k3_ringacc_ring_cfg(rflow->fd_ring, &ring_cfg);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE;
181362306a36Sopenharmony_ci	ret |= k3_ringacc_ring_cfg(rflow->r_ring, &ring_cfg);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	if (ret)
181662306a36Sopenharmony_ci		goto err_ringcfg;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	return 0;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_cierr_ringcfg:
182162306a36Sopenharmony_ci	k3_ringacc_ring_free(rflow->r_ring);
182262306a36Sopenharmony_ci	rflow->r_ring = NULL;
182362306a36Sopenharmony_ci	k3_ringacc_ring_free(rflow->fd_ring);
182462306a36Sopenharmony_ci	rflow->fd_ring = NULL;
182562306a36Sopenharmony_cierr_ring:
182662306a36Sopenharmony_ci	udma_put_rflow(uc);
182762306a36Sopenharmony_cierr_rflow:
182862306a36Sopenharmony_ci	udma_put_rchan(uc);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	return ret;
183162306a36Sopenharmony_ci}
183262306a36Sopenharmony_ci
183362306a36Sopenharmony_ci#define TISCI_BCDMA_BCHAN_VALID_PARAMS (			\
183462306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID |	\
183562306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_EXTENDED_CH_TYPE_VALID)
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_ci#define TISCI_BCDMA_TCHAN_VALID_PARAMS (			\
183862306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID |	\
183962306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID)
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci#define TISCI_BCDMA_RCHAN_VALID_PARAMS (			\
184262306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID)
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci#define TISCI_UDMA_TCHAN_VALID_PARAMS (				\
184562306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID |	\
184662306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_EINFO_VALID |	\
184762306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_PSWORDS_VALID |	\
184862306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID |		\
184962306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID |	\
185062306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID |		\
185162306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID |		\
185262306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID)
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ci#define TISCI_UDMA_RCHAN_VALID_PARAMS (				\
185562306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID |	\
185662306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID |		\
185762306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID |		\
185862306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID |		\
185962306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_SHORT_VALID |	\
186062306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_LONG_VALID |	\
186162306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID |	\
186262306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID |	\
186362306a36Sopenharmony_ci	TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID)
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_cistatic int udma_tisci_m2m_channel_config(struct udma_chan *uc)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
186862306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
186962306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
187062306a36Sopenharmony_ci	struct udma_tchan *tchan = uc->tchan;
187162306a36Sopenharmony_ci	struct udma_rchan *rchan = uc->rchan;
187262306a36Sopenharmony_ci	u8 burst_size = 0;
187362306a36Sopenharmony_ci	int ret;
187462306a36Sopenharmony_ci	u8 tpl;
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	/* Non synchronized - mem to mem type of transfer */
187762306a36Sopenharmony_ci	int tc_ring = k3_ringacc_get_ring_id(tchan->tc_ring);
187862306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 };
187962306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 };
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	if (ud->match_data->flags & UDMA_FLAG_BURST_SIZE) {
188262306a36Sopenharmony_ci		tpl = udma_get_chan_tpl_index(&ud->tchan_tpl, tchan->id);
188362306a36Sopenharmony_ci
188462306a36Sopenharmony_ci		burst_size = ud->match_data->burst_size[tpl];
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	req_tx.valid_params = TISCI_UDMA_TCHAN_VALID_PARAMS;
188862306a36Sopenharmony_ci	req_tx.nav_id = tisci_rm->tisci_dev_id;
188962306a36Sopenharmony_ci	req_tx.index = tchan->id;
189062306a36Sopenharmony_ci	req_tx.tx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR;
189162306a36Sopenharmony_ci	req_tx.tx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2;
189262306a36Sopenharmony_ci	req_tx.txcq_qnum = tc_ring;
189362306a36Sopenharmony_ci	req_tx.tx_atype = ud->atype;
189462306a36Sopenharmony_ci	if (burst_size) {
189562306a36Sopenharmony_ci		req_tx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID;
189662306a36Sopenharmony_ci		req_tx.tx_burst_size = burst_size;
189762306a36Sopenharmony_ci	}
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx);
190062306a36Sopenharmony_ci	if (ret) {
190162306a36Sopenharmony_ci		dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret);
190262306a36Sopenharmony_ci		return ret;
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	req_rx.valid_params = TISCI_UDMA_RCHAN_VALID_PARAMS;
190662306a36Sopenharmony_ci	req_rx.nav_id = tisci_rm->tisci_dev_id;
190762306a36Sopenharmony_ci	req_rx.index = rchan->id;
190862306a36Sopenharmony_ci	req_rx.rx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2;
190962306a36Sopenharmony_ci	req_rx.rxcq_qnum = tc_ring;
191062306a36Sopenharmony_ci	req_rx.rx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR;
191162306a36Sopenharmony_ci	req_rx.rx_atype = ud->atype;
191262306a36Sopenharmony_ci	if (burst_size) {
191362306a36Sopenharmony_ci		req_rx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID;
191462306a36Sopenharmony_ci		req_rx.rx_burst_size = burst_size;
191562306a36Sopenharmony_ci	}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx);
191862306a36Sopenharmony_ci	if (ret)
191962306a36Sopenharmony_ci		dev_err(ud->dev, "rchan%d alloc failed %d\n", rchan->id, ret);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	return ret;
192262306a36Sopenharmony_ci}
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_cistatic int bcdma_tisci_m2m_channel_config(struct udma_chan *uc)
192562306a36Sopenharmony_ci{
192662306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
192762306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
192862306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
192962306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 };
193062306a36Sopenharmony_ci	struct udma_bchan *bchan = uc->bchan;
193162306a36Sopenharmony_ci	u8 burst_size = 0;
193262306a36Sopenharmony_ci	int ret;
193362306a36Sopenharmony_ci	u8 tpl;
193462306a36Sopenharmony_ci
193562306a36Sopenharmony_ci	if (ud->match_data->flags & UDMA_FLAG_BURST_SIZE) {
193662306a36Sopenharmony_ci		tpl = udma_get_chan_tpl_index(&ud->bchan_tpl, bchan->id);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci		burst_size = ud->match_data->burst_size[tpl];
193962306a36Sopenharmony_ci	}
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	req_tx.valid_params = TISCI_BCDMA_BCHAN_VALID_PARAMS;
194262306a36Sopenharmony_ci	req_tx.nav_id = tisci_rm->tisci_dev_id;
194362306a36Sopenharmony_ci	req_tx.extended_ch_type = TI_SCI_RM_BCDMA_EXTENDED_CH_TYPE_BCHAN;
194462306a36Sopenharmony_ci	req_tx.index = bchan->id;
194562306a36Sopenharmony_ci	if (burst_size) {
194662306a36Sopenharmony_ci		req_tx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID;
194762306a36Sopenharmony_ci		req_tx.tx_burst_size = burst_size;
194862306a36Sopenharmony_ci	}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci	ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx);
195162306a36Sopenharmony_ci	if (ret)
195262306a36Sopenharmony_ci		dev_err(ud->dev, "bchan%d cfg failed %d\n", bchan->id, ret);
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	return ret;
195562306a36Sopenharmony_ci}
195662306a36Sopenharmony_ci
195762306a36Sopenharmony_cistatic int udma_tisci_tx_channel_config(struct udma_chan *uc)
195862306a36Sopenharmony_ci{
195962306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
196062306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
196162306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
196262306a36Sopenharmony_ci	struct udma_tchan *tchan = uc->tchan;
196362306a36Sopenharmony_ci	int tc_ring = k3_ringacc_get_ring_id(tchan->tc_ring);
196462306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 };
196562306a36Sopenharmony_ci	u32 mode, fetch_size;
196662306a36Sopenharmony_ci	int ret;
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	if (uc->config.pkt_mode) {
196962306a36Sopenharmony_ci		mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR;
197062306a36Sopenharmony_ci		fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib,
197162306a36Sopenharmony_ci						   uc->config.psd_size, 0);
197262306a36Sopenharmony_ci	} else {
197362306a36Sopenharmony_ci		mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR;
197462306a36Sopenharmony_ci		fetch_size = sizeof(struct cppi5_desc_hdr_t);
197562306a36Sopenharmony_ci	}
197662306a36Sopenharmony_ci
197762306a36Sopenharmony_ci	req_tx.valid_params = TISCI_UDMA_TCHAN_VALID_PARAMS;
197862306a36Sopenharmony_ci	req_tx.nav_id = tisci_rm->tisci_dev_id;
197962306a36Sopenharmony_ci	req_tx.index = tchan->id;
198062306a36Sopenharmony_ci	req_tx.tx_chan_type = mode;
198162306a36Sopenharmony_ci	req_tx.tx_supr_tdpkt = uc->config.notdpkt;
198262306a36Sopenharmony_ci	req_tx.tx_fetch_size = fetch_size >> 2;
198362306a36Sopenharmony_ci	req_tx.txcq_qnum = tc_ring;
198462306a36Sopenharmony_ci	req_tx.tx_atype = uc->config.atype;
198562306a36Sopenharmony_ci	if (uc->config.ep_type == PSIL_EP_PDMA_XY &&
198662306a36Sopenharmony_ci	    ud->match_data->flags & UDMA_FLAG_TDTYPE) {
198762306a36Sopenharmony_ci		/* wait for peer to complete the teardown for PDMAs */
198862306a36Sopenharmony_ci		req_tx.valid_params |=
198962306a36Sopenharmony_ci				TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_TDTYPE_VALID;
199062306a36Sopenharmony_ci		req_tx.tx_tdtype = 1;
199162306a36Sopenharmony_ci	}
199262306a36Sopenharmony_ci
199362306a36Sopenharmony_ci	ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx);
199462306a36Sopenharmony_ci	if (ret)
199562306a36Sopenharmony_ci		dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret);
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	return ret;
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_cistatic int bcdma_tisci_tx_channel_config(struct udma_chan *uc)
200162306a36Sopenharmony_ci{
200262306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
200362306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
200462306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
200562306a36Sopenharmony_ci	struct udma_tchan *tchan = uc->tchan;
200662306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 };
200762306a36Sopenharmony_ci	int ret;
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci	req_tx.valid_params = TISCI_BCDMA_TCHAN_VALID_PARAMS;
201062306a36Sopenharmony_ci	req_tx.nav_id = tisci_rm->tisci_dev_id;
201162306a36Sopenharmony_ci	req_tx.index = tchan->id;
201262306a36Sopenharmony_ci	req_tx.tx_supr_tdpkt = uc->config.notdpkt;
201362306a36Sopenharmony_ci	if (ud->match_data->flags & UDMA_FLAG_TDTYPE) {
201462306a36Sopenharmony_ci		/* wait for peer to complete the teardown for PDMAs */
201562306a36Sopenharmony_ci		req_tx.valid_params |=
201662306a36Sopenharmony_ci				TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_TDTYPE_VALID;
201762306a36Sopenharmony_ci		req_tx.tx_tdtype = 1;
201862306a36Sopenharmony_ci	}
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci	ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx);
202162306a36Sopenharmony_ci	if (ret)
202262306a36Sopenharmony_ci		dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret);
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	return ret;
202562306a36Sopenharmony_ci}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci#define pktdma_tisci_tx_channel_config bcdma_tisci_tx_channel_config
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_cistatic int udma_tisci_rx_channel_config(struct udma_chan *uc)
203062306a36Sopenharmony_ci{
203162306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
203262306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
203362306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
203462306a36Sopenharmony_ci	struct udma_rchan *rchan = uc->rchan;
203562306a36Sopenharmony_ci	int fd_ring = k3_ringacc_get_ring_id(uc->rflow->fd_ring);
203662306a36Sopenharmony_ci	int rx_ring = k3_ringacc_get_ring_id(uc->rflow->r_ring);
203762306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 };
203862306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 };
203962306a36Sopenharmony_ci	u32 mode, fetch_size;
204062306a36Sopenharmony_ci	int ret;
204162306a36Sopenharmony_ci
204262306a36Sopenharmony_ci	if (uc->config.pkt_mode) {
204362306a36Sopenharmony_ci		mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR;
204462306a36Sopenharmony_ci		fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib,
204562306a36Sopenharmony_ci						   uc->config.psd_size, 0);
204662306a36Sopenharmony_ci	} else {
204762306a36Sopenharmony_ci		mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR;
204862306a36Sopenharmony_ci		fetch_size = sizeof(struct cppi5_desc_hdr_t);
204962306a36Sopenharmony_ci	}
205062306a36Sopenharmony_ci
205162306a36Sopenharmony_ci	req_rx.valid_params = TISCI_UDMA_RCHAN_VALID_PARAMS;
205262306a36Sopenharmony_ci	req_rx.nav_id = tisci_rm->tisci_dev_id;
205362306a36Sopenharmony_ci	req_rx.index = rchan->id;
205462306a36Sopenharmony_ci	req_rx.rx_fetch_size =  fetch_size >> 2;
205562306a36Sopenharmony_ci	req_rx.rxcq_qnum = rx_ring;
205662306a36Sopenharmony_ci	req_rx.rx_chan_type = mode;
205762306a36Sopenharmony_ci	req_rx.rx_atype = uc->config.atype;
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx);
206062306a36Sopenharmony_ci	if (ret) {
206162306a36Sopenharmony_ci		dev_err(ud->dev, "rchan%d cfg failed %d\n", rchan->id, ret);
206262306a36Sopenharmony_ci		return ret;
206362306a36Sopenharmony_ci	}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	flow_req.valid_params =
206662306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID |
206762306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID |
206862306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID |
206962306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DESC_TYPE_VALID |
207062306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID |
207162306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_SEL_VALID |
207262306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_SEL_VALID |
207362306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_SEL_VALID |
207462306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_SEL_VALID |
207562306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID |
207662306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID |
207762306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID |
207862306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	flow_req.nav_id = tisci_rm->tisci_dev_id;
208162306a36Sopenharmony_ci	flow_req.flow_index = rchan->id;
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	if (uc->config.needs_epib)
208462306a36Sopenharmony_ci		flow_req.rx_einfo_present = 1;
208562306a36Sopenharmony_ci	else
208662306a36Sopenharmony_ci		flow_req.rx_einfo_present = 0;
208762306a36Sopenharmony_ci	if (uc->config.psd_size)
208862306a36Sopenharmony_ci		flow_req.rx_psinfo_present = 1;
208962306a36Sopenharmony_ci	else
209062306a36Sopenharmony_ci		flow_req.rx_psinfo_present = 0;
209162306a36Sopenharmony_ci	flow_req.rx_error_handling = 1;
209262306a36Sopenharmony_ci	flow_req.rx_dest_qnum = rx_ring;
209362306a36Sopenharmony_ci	flow_req.rx_src_tag_hi_sel = UDMA_RFLOW_SRCTAG_NONE;
209462306a36Sopenharmony_ci	flow_req.rx_src_tag_lo_sel = UDMA_RFLOW_SRCTAG_SRC_TAG;
209562306a36Sopenharmony_ci	flow_req.rx_dest_tag_hi_sel = UDMA_RFLOW_DSTTAG_DST_TAG_HI;
209662306a36Sopenharmony_ci	flow_req.rx_dest_tag_lo_sel = UDMA_RFLOW_DSTTAG_DST_TAG_LO;
209762306a36Sopenharmony_ci	flow_req.rx_fdq0_sz0_qnum = fd_ring;
209862306a36Sopenharmony_ci	flow_req.rx_fdq1_qnum = fd_ring;
209962306a36Sopenharmony_ci	flow_req.rx_fdq2_qnum = fd_ring;
210062306a36Sopenharmony_ci	flow_req.rx_fdq3_qnum = fd_ring;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	ret = tisci_ops->rx_flow_cfg(tisci_rm->tisci, &flow_req);
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	if (ret)
210562306a36Sopenharmony_ci		dev_err(ud->dev, "flow%d config failed: %d\n", rchan->id, ret);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	return 0;
210862306a36Sopenharmony_ci}
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_cistatic int bcdma_tisci_rx_channel_config(struct udma_chan *uc)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
211362306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
211462306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
211562306a36Sopenharmony_ci	struct udma_rchan *rchan = uc->rchan;
211662306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 };
211762306a36Sopenharmony_ci	int ret;
211862306a36Sopenharmony_ci
211962306a36Sopenharmony_ci	req_rx.valid_params = TISCI_BCDMA_RCHAN_VALID_PARAMS;
212062306a36Sopenharmony_ci	req_rx.nav_id = tisci_rm->tisci_dev_id;
212162306a36Sopenharmony_ci	req_rx.index = rchan->id;
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx);
212462306a36Sopenharmony_ci	if (ret)
212562306a36Sopenharmony_ci		dev_err(ud->dev, "rchan%d cfg failed %d\n", rchan->id, ret);
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	return ret;
212862306a36Sopenharmony_ci}
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_cistatic int pktdma_tisci_rx_channel_config(struct udma_chan *uc)
213162306a36Sopenharmony_ci{
213262306a36Sopenharmony_ci	struct udma_dev *ud = uc->ud;
213362306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
213462306a36Sopenharmony_ci	const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops;
213562306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 };
213662306a36Sopenharmony_ci	struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 };
213762306a36Sopenharmony_ci	int ret;
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ci	req_rx.valid_params = TISCI_BCDMA_RCHAN_VALID_PARAMS;
214062306a36Sopenharmony_ci	req_rx.nav_id = tisci_rm->tisci_dev_id;
214162306a36Sopenharmony_ci	req_rx.index = uc->rchan->id;
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_ci	ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx);
214462306a36Sopenharmony_ci	if (ret) {
214562306a36Sopenharmony_ci		dev_err(ud->dev, "rchan%d cfg failed %d\n", uc->rchan->id, ret);
214662306a36Sopenharmony_ci		return ret;
214762306a36Sopenharmony_ci	}
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	flow_req.valid_params =
215062306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID |
215162306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID |
215262306a36Sopenharmony_ci		TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID;
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_ci	flow_req.nav_id = tisci_rm->tisci_dev_id;
215562306a36Sopenharmony_ci	flow_req.flow_index = uc->rflow->id;
215662306a36Sopenharmony_ci
215762306a36Sopenharmony_ci	if (uc->config.needs_epib)
215862306a36Sopenharmony_ci		flow_req.rx_einfo_present = 1;
215962306a36Sopenharmony_ci	else
216062306a36Sopenharmony_ci		flow_req.rx_einfo_present = 0;
216162306a36Sopenharmony_ci	if (uc->config.psd_size)
216262306a36Sopenharmony_ci		flow_req.rx_psinfo_present = 1;
216362306a36Sopenharmony_ci	else
216462306a36Sopenharmony_ci		flow_req.rx_psinfo_present = 0;
216562306a36Sopenharmony_ci	flow_req.rx_error_handling = 1;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	ret = tisci_ops->rx_flow_cfg(tisci_rm->tisci, &flow_req);
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	if (ret)
217062306a36Sopenharmony_ci		dev_err(ud->dev, "flow%d config failed: %d\n", uc->rflow->id,
217162306a36Sopenharmony_ci			ret);
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	return ret;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_cistatic int udma_alloc_chan_resources(struct dma_chan *chan)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
217962306a36Sopenharmony_ci	struct udma_dev *ud = to_udma_dev(chan->device);
218062306a36Sopenharmony_ci	const struct udma_soc_data *soc_data = ud->soc_data;
218162306a36Sopenharmony_ci	struct k3_ring *irq_ring;
218262306a36Sopenharmony_ci	u32 irq_udma_idx;
218362306a36Sopenharmony_ci	int ret;
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	uc->dma_dev = ud->dev;
218662306a36Sopenharmony_ci
218762306a36Sopenharmony_ci	if (uc->config.pkt_mode || uc->config.dir == DMA_MEM_TO_MEM) {
218862306a36Sopenharmony_ci		uc->use_dma_pool = true;
218962306a36Sopenharmony_ci		/* in case of MEM_TO_MEM we have maximum of two TRs */
219062306a36Sopenharmony_ci		if (uc->config.dir == DMA_MEM_TO_MEM) {
219162306a36Sopenharmony_ci			uc->config.hdesc_size = cppi5_trdesc_calc_size(
219262306a36Sopenharmony_ci					sizeof(struct cppi5_tr_type15_t), 2);
219362306a36Sopenharmony_ci			uc->config.pkt_mode = false;
219462306a36Sopenharmony_ci		}
219562306a36Sopenharmony_ci	}
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	if (uc->use_dma_pool) {
219862306a36Sopenharmony_ci		uc->hdesc_pool = dma_pool_create(uc->name, ud->ddev.dev,
219962306a36Sopenharmony_ci						 uc->config.hdesc_size,
220062306a36Sopenharmony_ci						 ud->desc_align,
220162306a36Sopenharmony_ci						 0);
220262306a36Sopenharmony_ci		if (!uc->hdesc_pool) {
220362306a36Sopenharmony_ci			dev_err(ud->ddev.dev,
220462306a36Sopenharmony_ci				"Descriptor pool allocation failed\n");
220562306a36Sopenharmony_ci			uc->use_dma_pool = false;
220662306a36Sopenharmony_ci			ret = -ENOMEM;
220762306a36Sopenharmony_ci			goto err_cleanup;
220862306a36Sopenharmony_ci		}
220962306a36Sopenharmony_ci	}
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	/*
221262306a36Sopenharmony_ci	 * Make sure that the completion is in a known state:
221362306a36Sopenharmony_ci	 * No teardown, the channel is idle
221462306a36Sopenharmony_ci	 */
221562306a36Sopenharmony_ci	reinit_completion(&uc->teardown_completed);
221662306a36Sopenharmony_ci	complete_all(&uc->teardown_completed);
221762306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_IDLE;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	switch (uc->config.dir) {
222062306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
222162306a36Sopenharmony_ci		/* Non synchronized - mem to mem type of transfer */
222262306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-MEM\n", __func__,
222362306a36Sopenharmony_ci			uc->id);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci		ret = udma_get_chan_pair(uc);
222662306a36Sopenharmony_ci		if (ret)
222762306a36Sopenharmony_ci			goto err_cleanup;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci		ret = udma_alloc_tx_resources(uc);
223062306a36Sopenharmony_ci		if (ret) {
223162306a36Sopenharmony_ci			udma_put_rchan(uc);
223262306a36Sopenharmony_ci			goto err_cleanup;
223362306a36Sopenharmony_ci		}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci		ret = udma_alloc_rx_resources(uc);
223662306a36Sopenharmony_ci		if (ret) {
223762306a36Sopenharmony_ci			udma_free_tx_resources(uc);
223862306a36Sopenharmony_ci			goto err_cleanup;
223962306a36Sopenharmony_ci		}
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci		uc->config.src_thread = ud->psil_base + uc->tchan->id;
224262306a36Sopenharmony_ci		uc->config.dst_thread = (ud->psil_base + uc->rchan->id) |
224362306a36Sopenharmony_ci					K3_PSIL_DST_THREAD_ID_OFFSET;
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_ci		irq_ring = uc->tchan->tc_ring;
224662306a36Sopenharmony_ci		irq_udma_idx = uc->tchan->id;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci		ret = udma_tisci_m2m_channel_config(uc);
224962306a36Sopenharmony_ci		break;
225062306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
225162306a36Sopenharmony_ci		/* Slave transfer synchronized - mem to dev (TX) trasnfer */
225262306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__,
225362306a36Sopenharmony_ci			uc->id);
225462306a36Sopenharmony_ci
225562306a36Sopenharmony_ci		ret = udma_alloc_tx_resources(uc);
225662306a36Sopenharmony_ci		if (ret)
225762306a36Sopenharmony_ci			goto err_cleanup;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci		uc->config.src_thread = ud->psil_base + uc->tchan->id;
226062306a36Sopenharmony_ci		uc->config.dst_thread = uc->config.remote_thread_id;
226162306a36Sopenharmony_ci		uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
226262306a36Sopenharmony_ci
226362306a36Sopenharmony_ci		irq_ring = uc->tchan->tc_ring;
226462306a36Sopenharmony_ci		irq_udma_idx = uc->tchan->id;
226562306a36Sopenharmony_ci
226662306a36Sopenharmony_ci		ret = udma_tisci_tx_channel_config(uc);
226762306a36Sopenharmony_ci		break;
226862306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
226962306a36Sopenharmony_ci		/* Slave transfer synchronized - dev to mem (RX) trasnfer */
227062306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__,
227162306a36Sopenharmony_ci			uc->id);
227262306a36Sopenharmony_ci
227362306a36Sopenharmony_ci		ret = udma_alloc_rx_resources(uc);
227462306a36Sopenharmony_ci		if (ret)
227562306a36Sopenharmony_ci			goto err_cleanup;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci		uc->config.src_thread = uc->config.remote_thread_id;
227862306a36Sopenharmony_ci		uc->config.dst_thread = (ud->psil_base + uc->rchan->id) |
227962306a36Sopenharmony_ci					K3_PSIL_DST_THREAD_ID_OFFSET;
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_ci		irq_ring = uc->rflow->r_ring;
228262306a36Sopenharmony_ci		irq_udma_idx = soc_data->oes.udma_rchan + uc->rchan->id;
228362306a36Sopenharmony_ci
228462306a36Sopenharmony_ci		ret = udma_tisci_rx_channel_config(uc);
228562306a36Sopenharmony_ci		break;
228662306a36Sopenharmony_ci	default:
228762306a36Sopenharmony_ci		/* Can not happen */
228862306a36Sopenharmony_ci		dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n",
228962306a36Sopenharmony_ci			__func__, uc->id, uc->config.dir);
229062306a36Sopenharmony_ci		ret = -EINVAL;
229162306a36Sopenharmony_ci		goto err_cleanup;
229262306a36Sopenharmony_ci
229362306a36Sopenharmony_ci	}
229462306a36Sopenharmony_ci
229562306a36Sopenharmony_ci	/* check if the channel configuration was successful */
229662306a36Sopenharmony_ci	if (ret)
229762306a36Sopenharmony_ci		goto err_res_free;
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci	if (udma_is_chan_running(uc)) {
230062306a36Sopenharmony_ci		dev_warn(ud->dev, "chan%d: is running!\n", uc->id);
230162306a36Sopenharmony_ci		udma_reset_chan(uc, false);
230262306a36Sopenharmony_ci		if (udma_is_chan_running(uc)) {
230362306a36Sopenharmony_ci			dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
230462306a36Sopenharmony_ci			ret = -EBUSY;
230562306a36Sopenharmony_ci			goto err_res_free;
230662306a36Sopenharmony_ci		}
230762306a36Sopenharmony_ci	}
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	/* PSI-L pairing */
231062306a36Sopenharmony_ci	ret = navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread);
231162306a36Sopenharmony_ci	if (ret) {
231262306a36Sopenharmony_ci		dev_err(ud->dev, "PSI-L pairing failed: 0x%04x -> 0x%04x\n",
231362306a36Sopenharmony_ci			uc->config.src_thread, uc->config.dst_thread);
231462306a36Sopenharmony_ci		goto err_res_free;
231562306a36Sopenharmony_ci	}
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	uc->psil_paired = true;
231862306a36Sopenharmony_ci
231962306a36Sopenharmony_ci	uc->irq_num_ring = k3_ringacc_get_ring_irq_num(irq_ring);
232062306a36Sopenharmony_ci	if (uc->irq_num_ring <= 0) {
232162306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to get ring irq (index: %u)\n",
232262306a36Sopenharmony_ci			k3_ringacc_get_ring_id(irq_ring));
232362306a36Sopenharmony_ci		ret = -EINVAL;
232462306a36Sopenharmony_ci		goto err_psi_free;
232562306a36Sopenharmony_ci	}
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler,
232862306a36Sopenharmony_ci			  IRQF_TRIGGER_HIGH, uc->name, uc);
232962306a36Sopenharmony_ci	if (ret) {
233062306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id);
233162306a36Sopenharmony_ci		goto err_irq_free;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	/* Event from UDMA (TR events) only needed for slave TR mode channels */
233562306a36Sopenharmony_ci	if (is_slave_direction(uc->config.dir) && !uc->config.pkt_mode) {
233662306a36Sopenharmony_ci		uc->irq_num_udma = msi_get_virq(ud->dev, irq_udma_idx);
233762306a36Sopenharmony_ci		if (uc->irq_num_udma <= 0) {
233862306a36Sopenharmony_ci			dev_err(ud->dev, "Failed to get udma irq (index: %u)\n",
233962306a36Sopenharmony_ci				irq_udma_idx);
234062306a36Sopenharmony_ci			free_irq(uc->irq_num_ring, uc);
234162306a36Sopenharmony_ci			ret = -EINVAL;
234262306a36Sopenharmony_ci			goto err_irq_free;
234362306a36Sopenharmony_ci		}
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci		ret = request_irq(uc->irq_num_udma, udma_udma_irq_handler, 0,
234662306a36Sopenharmony_ci				  uc->name, uc);
234762306a36Sopenharmony_ci		if (ret) {
234862306a36Sopenharmony_ci			dev_err(ud->dev, "chan%d: UDMA irq request failed\n",
234962306a36Sopenharmony_ci				uc->id);
235062306a36Sopenharmony_ci			free_irq(uc->irq_num_ring, uc);
235162306a36Sopenharmony_ci			goto err_irq_free;
235262306a36Sopenharmony_ci		}
235362306a36Sopenharmony_ci	} else {
235462306a36Sopenharmony_ci		uc->irq_num_udma = 0;
235562306a36Sopenharmony_ci	}
235662306a36Sopenharmony_ci
235762306a36Sopenharmony_ci	udma_reset_rings(uc);
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	return 0;
236062306a36Sopenharmony_ci
236162306a36Sopenharmony_cierr_irq_free:
236262306a36Sopenharmony_ci	uc->irq_num_ring = 0;
236362306a36Sopenharmony_ci	uc->irq_num_udma = 0;
236462306a36Sopenharmony_cierr_psi_free:
236562306a36Sopenharmony_ci	navss_psil_unpair(ud, uc->config.src_thread, uc->config.dst_thread);
236662306a36Sopenharmony_ci	uc->psil_paired = false;
236762306a36Sopenharmony_cierr_res_free:
236862306a36Sopenharmony_ci	udma_free_tx_resources(uc);
236962306a36Sopenharmony_ci	udma_free_rx_resources(uc);
237062306a36Sopenharmony_cierr_cleanup:
237162306a36Sopenharmony_ci	udma_reset_uchan(uc);
237262306a36Sopenharmony_ci
237362306a36Sopenharmony_ci	if (uc->use_dma_pool) {
237462306a36Sopenharmony_ci		dma_pool_destroy(uc->hdesc_pool);
237562306a36Sopenharmony_ci		uc->use_dma_pool = false;
237662306a36Sopenharmony_ci	}
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	return ret;
237962306a36Sopenharmony_ci}
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_cistatic int bcdma_alloc_chan_resources(struct dma_chan *chan)
238262306a36Sopenharmony_ci{
238362306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
238462306a36Sopenharmony_ci	struct udma_dev *ud = to_udma_dev(chan->device);
238562306a36Sopenharmony_ci	const struct udma_oes_offsets *oes = &ud->soc_data->oes;
238662306a36Sopenharmony_ci	u32 irq_udma_idx, irq_ring_idx;
238762306a36Sopenharmony_ci	int ret;
238862306a36Sopenharmony_ci
238962306a36Sopenharmony_ci	/* Only TR mode is supported */
239062306a36Sopenharmony_ci	uc->config.pkt_mode = false;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	/*
239362306a36Sopenharmony_ci	 * Make sure that the completion is in a known state:
239462306a36Sopenharmony_ci	 * No teardown, the channel is idle
239562306a36Sopenharmony_ci	 */
239662306a36Sopenharmony_ci	reinit_completion(&uc->teardown_completed);
239762306a36Sopenharmony_ci	complete_all(&uc->teardown_completed);
239862306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_IDLE;
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_ci	switch (uc->config.dir) {
240162306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
240262306a36Sopenharmony_ci		/* Non synchronized - mem to mem type of transfer */
240362306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-MEM\n", __func__,
240462306a36Sopenharmony_ci			uc->id);
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci		ret = bcdma_alloc_bchan_resources(uc);
240762306a36Sopenharmony_ci		if (ret)
240862306a36Sopenharmony_ci			return ret;
240962306a36Sopenharmony_ci
241062306a36Sopenharmony_ci		irq_ring_idx = uc->bchan->id + oes->bcdma_bchan_ring;
241162306a36Sopenharmony_ci		irq_udma_idx = uc->bchan->id + oes->bcdma_bchan_data;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci		ret = bcdma_tisci_m2m_channel_config(uc);
241462306a36Sopenharmony_ci		break;
241562306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
241662306a36Sopenharmony_ci		/* Slave transfer synchronized - mem to dev (TX) trasnfer */
241762306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__,
241862306a36Sopenharmony_ci			uc->id);
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci		ret = udma_alloc_tx_resources(uc);
242162306a36Sopenharmony_ci		if (ret) {
242262306a36Sopenharmony_ci			uc->config.remote_thread_id = -1;
242362306a36Sopenharmony_ci			return ret;
242462306a36Sopenharmony_ci		}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci		uc->config.src_thread = ud->psil_base + uc->tchan->id;
242762306a36Sopenharmony_ci		uc->config.dst_thread = uc->config.remote_thread_id;
242862306a36Sopenharmony_ci		uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ci		irq_ring_idx = uc->tchan->id + oes->bcdma_tchan_ring;
243162306a36Sopenharmony_ci		irq_udma_idx = uc->tchan->id + oes->bcdma_tchan_data;
243262306a36Sopenharmony_ci
243362306a36Sopenharmony_ci		ret = bcdma_tisci_tx_channel_config(uc);
243462306a36Sopenharmony_ci		break;
243562306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
243662306a36Sopenharmony_ci		/* Slave transfer synchronized - dev to mem (RX) trasnfer */
243762306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__,
243862306a36Sopenharmony_ci			uc->id);
243962306a36Sopenharmony_ci
244062306a36Sopenharmony_ci		ret = udma_alloc_rx_resources(uc);
244162306a36Sopenharmony_ci		if (ret) {
244262306a36Sopenharmony_ci			uc->config.remote_thread_id = -1;
244362306a36Sopenharmony_ci			return ret;
244462306a36Sopenharmony_ci		}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci		uc->config.src_thread = uc->config.remote_thread_id;
244762306a36Sopenharmony_ci		uc->config.dst_thread = (ud->psil_base + uc->rchan->id) |
244862306a36Sopenharmony_ci					K3_PSIL_DST_THREAD_ID_OFFSET;
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci		irq_ring_idx = uc->rchan->id + oes->bcdma_rchan_ring;
245162306a36Sopenharmony_ci		irq_udma_idx = uc->rchan->id + oes->bcdma_rchan_data;
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci		ret = bcdma_tisci_rx_channel_config(uc);
245462306a36Sopenharmony_ci		break;
245562306a36Sopenharmony_ci	default:
245662306a36Sopenharmony_ci		/* Can not happen */
245762306a36Sopenharmony_ci		dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n",
245862306a36Sopenharmony_ci			__func__, uc->id, uc->config.dir);
245962306a36Sopenharmony_ci		return -EINVAL;
246062306a36Sopenharmony_ci	}
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	/* check if the channel configuration was successful */
246362306a36Sopenharmony_ci	if (ret)
246462306a36Sopenharmony_ci		goto err_res_free;
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci	if (udma_is_chan_running(uc)) {
246762306a36Sopenharmony_ci		dev_warn(ud->dev, "chan%d: is running!\n", uc->id);
246862306a36Sopenharmony_ci		udma_reset_chan(uc, false);
246962306a36Sopenharmony_ci		if (udma_is_chan_running(uc)) {
247062306a36Sopenharmony_ci			dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
247162306a36Sopenharmony_ci			ret = -EBUSY;
247262306a36Sopenharmony_ci			goto err_res_free;
247362306a36Sopenharmony_ci		}
247462306a36Sopenharmony_ci	}
247562306a36Sopenharmony_ci
247662306a36Sopenharmony_ci	uc->dma_dev = dmaengine_get_dma_device(chan);
247762306a36Sopenharmony_ci	if (uc->config.dir == DMA_MEM_TO_MEM  && !uc->config.tr_trigger_type) {
247862306a36Sopenharmony_ci		uc->config.hdesc_size = cppi5_trdesc_calc_size(
247962306a36Sopenharmony_ci					sizeof(struct cppi5_tr_type15_t), 2);
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci		uc->hdesc_pool = dma_pool_create(uc->name, ud->ddev.dev,
248262306a36Sopenharmony_ci						 uc->config.hdesc_size,
248362306a36Sopenharmony_ci						 ud->desc_align,
248462306a36Sopenharmony_ci						 0);
248562306a36Sopenharmony_ci		if (!uc->hdesc_pool) {
248662306a36Sopenharmony_ci			dev_err(ud->ddev.dev,
248762306a36Sopenharmony_ci				"Descriptor pool allocation failed\n");
248862306a36Sopenharmony_ci			uc->use_dma_pool = false;
248962306a36Sopenharmony_ci			ret = -ENOMEM;
249062306a36Sopenharmony_ci			goto err_res_free;
249162306a36Sopenharmony_ci		}
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci		uc->use_dma_pool = true;
249462306a36Sopenharmony_ci	} else if (uc->config.dir != DMA_MEM_TO_MEM) {
249562306a36Sopenharmony_ci		/* PSI-L pairing */
249662306a36Sopenharmony_ci		ret = navss_psil_pair(ud, uc->config.src_thread,
249762306a36Sopenharmony_ci				      uc->config.dst_thread);
249862306a36Sopenharmony_ci		if (ret) {
249962306a36Sopenharmony_ci			dev_err(ud->dev,
250062306a36Sopenharmony_ci				"PSI-L pairing failed: 0x%04x -> 0x%04x\n",
250162306a36Sopenharmony_ci				uc->config.src_thread, uc->config.dst_thread);
250262306a36Sopenharmony_ci			goto err_res_free;
250362306a36Sopenharmony_ci		}
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci		uc->psil_paired = true;
250662306a36Sopenharmony_ci	}
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	uc->irq_num_ring = msi_get_virq(ud->dev, irq_ring_idx);
250962306a36Sopenharmony_ci	if (uc->irq_num_ring <= 0) {
251062306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to get ring irq (index: %u)\n",
251162306a36Sopenharmony_ci			irq_ring_idx);
251262306a36Sopenharmony_ci		ret = -EINVAL;
251362306a36Sopenharmony_ci		goto err_psi_free;
251462306a36Sopenharmony_ci	}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler,
251762306a36Sopenharmony_ci			  IRQF_TRIGGER_HIGH, uc->name, uc);
251862306a36Sopenharmony_ci	if (ret) {
251962306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id);
252062306a36Sopenharmony_ci		goto err_irq_free;
252162306a36Sopenharmony_ci	}
252262306a36Sopenharmony_ci
252362306a36Sopenharmony_ci	/* Event from BCDMA (TR events) only needed for slave channels */
252462306a36Sopenharmony_ci	if (is_slave_direction(uc->config.dir)) {
252562306a36Sopenharmony_ci		uc->irq_num_udma = msi_get_virq(ud->dev, irq_udma_idx);
252662306a36Sopenharmony_ci		if (uc->irq_num_udma <= 0) {
252762306a36Sopenharmony_ci			dev_err(ud->dev, "Failed to get bcdma irq (index: %u)\n",
252862306a36Sopenharmony_ci				irq_udma_idx);
252962306a36Sopenharmony_ci			free_irq(uc->irq_num_ring, uc);
253062306a36Sopenharmony_ci			ret = -EINVAL;
253162306a36Sopenharmony_ci			goto err_irq_free;
253262306a36Sopenharmony_ci		}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		ret = request_irq(uc->irq_num_udma, udma_udma_irq_handler, 0,
253562306a36Sopenharmony_ci				  uc->name, uc);
253662306a36Sopenharmony_ci		if (ret) {
253762306a36Sopenharmony_ci			dev_err(ud->dev, "chan%d: BCDMA irq request failed\n",
253862306a36Sopenharmony_ci				uc->id);
253962306a36Sopenharmony_ci			free_irq(uc->irq_num_ring, uc);
254062306a36Sopenharmony_ci			goto err_irq_free;
254162306a36Sopenharmony_ci		}
254262306a36Sopenharmony_ci	} else {
254362306a36Sopenharmony_ci		uc->irq_num_udma = 0;
254462306a36Sopenharmony_ci	}
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ci	udma_reset_rings(uc);
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work,
254962306a36Sopenharmony_ci				  udma_check_tx_completion);
255062306a36Sopenharmony_ci	return 0;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_cierr_irq_free:
255362306a36Sopenharmony_ci	uc->irq_num_ring = 0;
255462306a36Sopenharmony_ci	uc->irq_num_udma = 0;
255562306a36Sopenharmony_cierr_psi_free:
255662306a36Sopenharmony_ci	if (uc->psil_paired)
255762306a36Sopenharmony_ci		navss_psil_unpair(ud, uc->config.src_thread,
255862306a36Sopenharmony_ci				  uc->config.dst_thread);
255962306a36Sopenharmony_ci	uc->psil_paired = false;
256062306a36Sopenharmony_cierr_res_free:
256162306a36Sopenharmony_ci	bcdma_free_bchan_resources(uc);
256262306a36Sopenharmony_ci	udma_free_tx_resources(uc);
256362306a36Sopenharmony_ci	udma_free_rx_resources(uc);
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	udma_reset_uchan(uc);
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci	if (uc->use_dma_pool) {
256862306a36Sopenharmony_ci		dma_pool_destroy(uc->hdesc_pool);
256962306a36Sopenharmony_ci		uc->use_dma_pool = false;
257062306a36Sopenharmony_ci	}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	return ret;
257362306a36Sopenharmony_ci}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_cistatic int bcdma_router_config(struct dma_chan *chan)
257662306a36Sopenharmony_ci{
257762306a36Sopenharmony_ci	struct k3_event_route_data *router_data = chan->route_data;
257862306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
257962306a36Sopenharmony_ci	u32 trigger_event;
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_ci	if (!uc->bchan)
258262306a36Sopenharmony_ci		return -EINVAL;
258362306a36Sopenharmony_ci
258462306a36Sopenharmony_ci	if (uc->config.tr_trigger_type != 1 && uc->config.tr_trigger_type != 2)
258562306a36Sopenharmony_ci		return -EINVAL;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	trigger_event = uc->ud->soc_data->bcdma_trigger_event_offset;
258862306a36Sopenharmony_ci	trigger_event += (uc->bchan->id * 2) + uc->config.tr_trigger_type - 1;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	return router_data->set_event(router_data->priv, trigger_event);
259162306a36Sopenharmony_ci}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_cistatic int pktdma_alloc_chan_resources(struct dma_chan *chan)
259462306a36Sopenharmony_ci{
259562306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
259662306a36Sopenharmony_ci	struct udma_dev *ud = to_udma_dev(chan->device);
259762306a36Sopenharmony_ci	const struct udma_oes_offsets *oes = &ud->soc_data->oes;
259862306a36Sopenharmony_ci	u32 irq_ring_idx;
259962306a36Sopenharmony_ci	int ret;
260062306a36Sopenharmony_ci
260162306a36Sopenharmony_ci	/*
260262306a36Sopenharmony_ci	 * Make sure that the completion is in a known state:
260362306a36Sopenharmony_ci	 * No teardown, the channel is idle
260462306a36Sopenharmony_ci	 */
260562306a36Sopenharmony_ci	reinit_completion(&uc->teardown_completed);
260662306a36Sopenharmony_ci	complete_all(&uc->teardown_completed);
260762306a36Sopenharmony_ci	uc->state = UDMA_CHAN_IS_IDLE;
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	switch (uc->config.dir) {
261062306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
261162306a36Sopenharmony_ci		/* Slave transfer synchronized - mem to dev (TX) trasnfer */
261262306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__,
261362306a36Sopenharmony_ci			uc->id);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci		ret = udma_alloc_tx_resources(uc);
261662306a36Sopenharmony_ci		if (ret) {
261762306a36Sopenharmony_ci			uc->config.remote_thread_id = -1;
261862306a36Sopenharmony_ci			return ret;
261962306a36Sopenharmony_ci		}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci		uc->config.src_thread = ud->psil_base + uc->tchan->id;
262262306a36Sopenharmony_ci		uc->config.dst_thread = uc->config.remote_thread_id;
262362306a36Sopenharmony_ci		uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci		irq_ring_idx = uc->tchan->tflow_id + oes->pktdma_tchan_flow;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci		ret = pktdma_tisci_tx_channel_config(uc);
262862306a36Sopenharmony_ci		break;
262962306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
263062306a36Sopenharmony_ci		/* Slave transfer synchronized - dev to mem (RX) trasnfer */
263162306a36Sopenharmony_ci		dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__,
263262306a36Sopenharmony_ci			uc->id);
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci		ret = udma_alloc_rx_resources(uc);
263562306a36Sopenharmony_ci		if (ret) {
263662306a36Sopenharmony_ci			uc->config.remote_thread_id = -1;
263762306a36Sopenharmony_ci			return ret;
263862306a36Sopenharmony_ci		}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci		uc->config.src_thread = uc->config.remote_thread_id;
264162306a36Sopenharmony_ci		uc->config.dst_thread = (ud->psil_base + uc->rchan->id) |
264262306a36Sopenharmony_ci					K3_PSIL_DST_THREAD_ID_OFFSET;
264362306a36Sopenharmony_ci
264462306a36Sopenharmony_ci		irq_ring_idx = uc->rflow->id + oes->pktdma_rchan_flow;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci		ret = pktdma_tisci_rx_channel_config(uc);
264762306a36Sopenharmony_ci		break;
264862306a36Sopenharmony_ci	default:
264962306a36Sopenharmony_ci		/* Can not happen */
265062306a36Sopenharmony_ci		dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n",
265162306a36Sopenharmony_ci			__func__, uc->id, uc->config.dir);
265262306a36Sopenharmony_ci		return -EINVAL;
265362306a36Sopenharmony_ci	}
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	/* check if the channel configuration was successful */
265662306a36Sopenharmony_ci	if (ret)
265762306a36Sopenharmony_ci		goto err_res_free;
265862306a36Sopenharmony_ci
265962306a36Sopenharmony_ci	if (udma_is_chan_running(uc)) {
266062306a36Sopenharmony_ci		dev_warn(ud->dev, "chan%d: is running!\n", uc->id);
266162306a36Sopenharmony_ci		udma_reset_chan(uc, false);
266262306a36Sopenharmony_ci		if (udma_is_chan_running(uc)) {
266362306a36Sopenharmony_ci			dev_err(ud->dev, "chan%d: won't stop!\n", uc->id);
266462306a36Sopenharmony_ci			ret = -EBUSY;
266562306a36Sopenharmony_ci			goto err_res_free;
266662306a36Sopenharmony_ci		}
266762306a36Sopenharmony_ci	}
266862306a36Sopenharmony_ci
266962306a36Sopenharmony_ci	uc->dma_dev = dmaengine_get_dma_device(chan);
267062306a36Sopenharmony_ci	uc->hdesc_pool = dma_pool_create(uc->name, uc->dma_dev,
267162306a36Sopenharmony_ci					 uc->config.hdesc_size, ud->desc_align,
267262306a36Sopenharmony_ci					 0);
267362306a36Sopenharmony_ci	if (!uc->hdesc_pool) {
267462306a36Sopenharmony_ci		dev_err(ud->ddev.dev,
267562306a36Sopenharmony_ci			"Descriptor pool allocation failed\n");
267662306a36Sopenharmony_ci		uc->use_dma_pool = false;
267762306a36Sopenharmony_ci		ret = -ENOMEM;
267862306a36Sopenharmony_ci		goto err_res_free;
267962306a36Sopenharmony_ci	}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_ci	uc->use_dma_pool = true;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	/* PSI-L pairing */
268462306a36Sopenharmony_ci	ret = navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread);
268562306a36Sopenharmony_ci	if (ret) {
268662306a36Sopenharmony_ci		dev_err(ud->dev, "PSI-L pairing failed: 0x%04x -> 0x%04x\n",
268762306a36Sopenharmony_ci			uc->config.src_thread, uc->config.dst_thread);
268862306a36Sopenharmony_ci		goto err_res_free;
268962306a36Sopenharmony_ci	}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	uc->psil_paired = true;
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	uc->irq_num_ring = msi_get_virq(ud->dev, irq_ring_idx);
269462306a36Sopenharmony_ci	if (uc->irq_num_ring <= 0) {
269562306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to get ring irq (index: %u)\n",
269662306a36Sopenharmony_ci			irq_ring_idx);
269762306a36Sopenharmony_ci		ret = -EINVAL;
269862306a36Sopenharmony_ci		goto err_psi_free;
269962306a36Sopenharmony_ci	}
270062306a36Sopenharmony_ci
270162306a36Sopenharmony_ci	ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler,
270262306a36Sopenharmony_ci			  IRQF_TRIGGER_HIGH, uc->name, uc);
270362306a36Sopenharmony_ci	if (ret) {
270462306a36Sopenharmony_ci		dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id);
270562306a36Sopenharmony_ci		goto err_irq_free;
270662306a36Sopenharmony_ci	}
270762306a36Sopenharmony_ci
270862306a36Sopenharmony_ci	uc->irq_num_udma = 0;
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	udma_reset_rings(uc);
271162306a36Sopenharmony_ci
271262306a36Sopenharmony_ci	INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work,
271362306a36Sopenharmony_ci				  udma_check_tx_completion);
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	if (uc->tchan)
271662306a36Sopenharmony_ci		dev_dbg(ud->dev,
271762306a36Sopenharmony_ci			"chan%d: tchan%d, tflow%d, Remote thread: 0x%04x\n",
271862306a36Sopenharmony_ci			uc->id, uc->tchan->id, uc->tchan->tflow_id,
271962306a36Sopenharmony_ci			uc->config.remote_thread_id);
272062306a36Sopenharmony_ci	else if (uc->rchan)
272162306a36Sopenharmony_ci		dev_dbg(ud->dev,
272262306a36Sopenharmony_ci			"chan%d: rchan%d, rflow%d, Remote thread: 0x%04x\n",
272362306a36Sopenharmony_ci			uc->id, uc->rchan->id, uc->rflow->id,
272462306a36Sopenharmony_ci			uc->config.remote_thread_id);
272562306a36Sopenharmony_ci	return 0;
272662306a36Sopenharmony_ci
272762306a36Sopenharmony_cierr_irq_free:
272862306a36Sopenharmony_ci	uc->irq_num_ring = 0;
272962306a36Sopenharmony_cierr_psi_free:
273062306a36Sopenharmony_ci	navss_psil_unpair(ud, uc->config.src_thread, uc->config.dst_thread);
273162306a36Sopenharmony_ci	uc->psil_paired = false;
273262306a36Sopenharmony_cierr_res_free:
273362306a36Sopenharmony_ci	udma_free_tx_resources(uc);
273462306a36Sopenharmony_ci	udma_free_rx_resources(uc);
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	udma_reset_uchan(uc);
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	dma_pool_destroy(uc->hdesc_pool);
273962306a36Sopenharmony_ci	uc->use_dma_pool = false;
274062306a36Sopenharmony_ci
274162306a36Sopenharmony_ci	return ret;
274262306a36Sopenharmony_ci}
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_cistatic int udma_slave_config(struct dma_chan *chan,
274562306a36Sopenharmony_ci			     struct dma_slave_config *cfg)
274662306a36Sopenharmony_ci{
274762306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	memcpy(&uc->cfg, cfg, sizeof(uc->cfg));
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	return 0;
275262306a36Sopenharmony_ci}
275362306a36Sopenharmony_ci
275462306a36Sopenharmony_cistatic struct udma_desc *udma_alloc_tr_desc(struct udma_chan *uc,
275562306a36Sopenharmony_ci					    size_t tr_size, int tr_count,
275662306a36Sopenharmony_ci					    enum dma_transfer_direction dir)
275762306a36Sopenharmony_ci{
275862306a36Sopenharmony_ci	struct udma_hwdesc *hwdesc;
275962306a36Sopenharmony_ci	struct cppi5_desc_hdr_t *tr_desc;
276062306a36Sopenharmony_ci	struct udma_desc *d;
276162306a36Sopenharmony_ci	u32 reload_count = 0;
276262306a36Sopenharmony_ci	u32 ring_id;
276362306a36Sopenharmony_ci
276462306a36Sopenharmony_ci	switch (tr_size) {
276562306a36Sopenharmony_ci	case 16:
276662306a36Sopenharmony_ci	case 32:
276762306a36Sopenharmony_ci	case 64:
276862306a36Sopenharmony_ci	case 128:
276962306a36Sopenharmony_ci		break;
277062306a36Sopenharmony_ci	default:
277162306a36Sopenharmony_ci		dev_err(uc->ud->dev, "Unsupported TR size of %zu\n", tr_size);
277262306a36Sopenharmony_ci		return NULL;
277362306a36Sopenharmony_ci	}
277462306a36Sopenharmony_ci
277562306a36Sopenharmony_ci	/* We have only one descriptor containing multiple TRs */
277662306a36Sopenharmony_ci	d = kzalloc(sizeof(*d) + sizeof(d->hwdesc[0]), GFP_NOWAIT);
277762306a36Sopenharmony_ci	if (!d)
277862306a36Sopenharmony_ci		return NULL;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	d->sglen = tr_count;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci	d->hwdesc_count = 1;
278362306a36Sopenharmony_ci	hwdesc = &d->hwdesc[0];
278462306a36Sopenharmony_ci
278562306a36Sopenharmony_ci	/* Allocate memory for DMA ring descriptor */
278662306a36Sopenharmony_ci	if (uc->use_dma_pool) {
278762306a36Sopenharmony_ci		hwdesc->cppi5_desc_size = uc->config.hdesc_size;
278862306a36Sopenharmony_ci		hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool,
278962306a36Sopenharmony_ci						GFP_NOWAIT,
279062306a36Sopenharmony_ci						&hwdesc->cppi5_desc_paddr);
279162306a36Sopenharmony_ci	} else {
279262306a36Sopenharmony_ci		hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size,
279362306a36Sopenharmony_ci								 tr_count);
279462306a36Sopenharmony_ci		hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size,
279562306a36Sopenharmony_ci						uc->ud->desc_align);
279662306a36Sopenharmony_ci		hwdesc->cppi5_desc_vaddr = dma_alloc_coherent(uc->ud->dev,
279762306a36Sopenharmony_ci						hwdesc->cppi5_desc_size,
279862306a36Sopenharmony_ci						&hwdesc->cppi5_desc_paddr,
279962306a36Sopenharmony_ci						GFP_NOWAIT);
280062306a36Sopenharmony_ci	}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_ci	if (!hwdesc->cppi5_desc_vaddr) {
280362306a36Sopenharmony_ci		kfree(d);
280462306a36Sopenharmony_ci		return NULL;
280562306a36Sopenharmony_ci	}
280662306a36Sopenharmony_ci
280762306a36Sopenharmony_ci	/* Start of the TR req records */
280862306a36Sopenharmony_ci	hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size;
280962306a36Sopenharmony_ci	/* Start address of the TR response array */
281062306a36Sopenharmony_ci	hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size * tr_count;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	tr_desc = hwdesc->cppi5_desc_vaddr;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	if (uc->cyclic)
281562306a36Sopenharmony_ci		reload_count = CPPI5_INFO0_TRDESC_RLDCNT_INFINITE;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM)
281862306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring);
281962306a36Sopenharmony_ci	else
282062306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring);
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	cppi5_trdesc_init(tr_desc, tr_count, tr_size, 0, reload_count);
282362306a36Sopenharmony_ci	cppi5_desc_set_pktids(tr_desc, uc->id,
282462306a36Sopenharmony_ci			      CPPI5_INFO1_DESC_FLOWID_DEFAULT);
282562306a36Sopenharmony_ci	cppi5_desc_set_retpolicy(tr_desc, 0, ring_id);
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	return d;
282862306a36Sopenharmony_ci}
282962306a36Sopenharmony_ci
283062306a36Sopenharmony_ci/**
283162306a36Sopenharmony_ci * udma_get_tr_counters - calculate TR counters for a given length
283262306a36Sopenharmony_ci * @len: Length of the trasnfer
283362306a36Sopenharmony_ci * @align_to: Preferred alignment
283462306a36Sopenharmony_ci * @tr0_cnt0: First TR icnt0
283562306a36Sopenharmony_ci * @tr0_cnt1: First TR icnt1
283662306a36Sopenharmony_ci * @tr1_cnt0: Second (if used) TR icnt0
283762306a36Sopenharmony_ci *
283862306a36Sopenharmony_ci * For len < SZ_64K only one TR is enough, tr1_cnt0 is not updated
283962306a36Sopenharmony_ci * For len >= SZ_64K two TRs are used in a simple way:
284062306a36Sopenharmony_ci * First TR: SZ_64K-alignment blocks (tr0_cnt0, tr0_cnt1)
284162306a36Sopenharmony_ci * Second TR: the remaining length (tr1_cnt0)
284262306a36Sopenharmony_ci *
284362306a36Sopenharmony_ci * Returns the number of TRs the length needs (1 or 2)
284462306a36Sopenharmony_ci * -EINVAL if the length can not be supported
284562306a36Sopenharmony_ci */
284662306a36Sopenharmony_cistatic int udma_get_tr_counters(size_t len, unsigned long align_to,
284762306a36Sopenharmony_ci				u16 *tr0_cnt0, u16 *tr0_cnt1, u16 *tr1_cnt0)
284862306a36Sopenharmony_ci{
284962306a36Sopenharmony_ci	if (len < SZ_64K) {
285062306a36Sopenharmony_ci		*tr0_cnt0 = len;
285162306a36Sopenharmony_ci		*tr0_cnt1 = 1;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci		return 1;
285462306a36Sopenharmony_ci	}
285562306a36Sopenharmony_ci
285662306a36Sopenharmony_ci	if (align_to > 3)
285762306a36Sopenharmony_ci		align_to = 3;
285862306a36Sopenharmony_ci
285962306a36Sopenharmony_cirealign:
286062306a36Sopenharmony_ci	*tr0_cnt0 = SZ_64K - BIT(align_to);
286162306a36Sopenharmony_ci	if (len / *tr0_cnt0 >= SZ_64K) {
286262306a36Sopenharmony_ci		if (align_to) {
286362306a36Sopenharmony_ci			align_to--;
286462306a36Sopenharmony_ci			goto realign;
286562306a36Sopenharmony_ci		}
286662306a36Sopenharmony_ci		return -EINVAL;
286762306a36Sopenharmony_ci	}
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci	*tr0_cnt1 = len / *tr0_cnt0;
287062306a36Sopenharmony_ci	*tr1_cnt0 = len % *tr0_cnt0;
287162306a36Sopenharmony_ci
287262306a36Sopenharmony_ci	return 2;
287362306a36Sopenharmony_ci}
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_cistatic struct udma_desc *
287662306a36Sopenharmony_ciudma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl,
287762306a36Sopenharmony_ci		      unsigned int sglen, enum dma_transfer_direction dir,
287862306a36Sopenharmony_ci		      unsigned long tx_flags, void *context)
287962306a36Sopenharmony_ci{
288062306a36Sopenharmony_ci	struct scatterlist *sgent;
288162306a36Sopenharmony_ci	struct udma_desc *d;
288262306a36Sopenharmony_ci	struct cppi5_tr_type1_t *tr_req = NULL;
288362306a36Sopenharmony_ci	u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
288462306a36Sopenharmony_ci	unsigned int i;
288562306a36Sopenharmony_ci	size_t tr_size;
288662306a36Sopenharmony_ci	int num_tr = 0;
288762306a36Sopenharmony_ci	int tr_idx = 0;
288862306a36Sopenharmony_ci	u64 asel;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	/* estimate the number of TRs we will need */
289162306a36Sopenharmony_ci	for_each_sg(sgl, sgent, sglen, i) {
289262306a36Sopenharmony_ci		if (sg_dma_len(sgent) < SZ_64K)
289362306a36Sopenharmony_ci			num_tr++;
289462306a36Sopenharmony_ci		else
289562306a36Sopenharmony_ci			num_tr += 2;
289662306a36Sopenharmony_ci	}
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	/* Now allocate and setup the descriptor. */
289962306a36Sopenharmony_ci	tr_size = sizeof(struct cppi5_tr_type1_t);
290062306a36Sopenharmony_ci	d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir);
290162306a36Sopenharmony_ci	if (!d)
290262306a36Sopenharmony_ci		return NULL;
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	d->sglen = sglen;
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	if (uc->ud->match_data->type == DMA_TYPE_UDMA)
290762306a36Sopenharmony_ci		asel = 0;
290862306a36Sopenharmony_ci	else
290962306a36Sopenharmony_ci		asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT;
291062306a36Sopenharmony_ci
291162306a36Sopenharmony_ci	tr_req = d->hwdesc[0].tr_req_base;
291262306a36Sopenharmony_ci	for_each_sg(sgl, sgent, sglen, i) {
291362306a36Sopenharmony_ci		dma_addr_t sg_addr = sg_dma_address(sgent);
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci		num_tr = udma_get_tr_counters(sg_dma_len(sgent), __ffs(sg_addr),
291662306a36Sopenharmony_ci					      &tr0_cnt0, &tr0_cnt1, &tr1_cnt0);
291762306a36Sopenharmony_ci		if (num_tr < 0) {
291862306a36Sopenharmony_ci			dev_err(uc->ud->dev, "size %u is not supported\n",
291962306a36Sopenharmony_ci				sg_dma_len(sgent));
292062306a36Sopenharmony_ci			udma_free_hwdesc(uc, d);
292162306a36Sopenharmony_ci			kfree(d);
292262306a36Sopenharmony_ci			return NULL;
292362306a36Sopenharmony_ci		}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci		cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false,
292662306a36Sopenharmony_ci			      false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
292762306a36Sopenharmony_ci		cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT);
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_ci		sg_addr |= asel;
293062306a36Sopenharmony_ci		tr_req[tr_idx].addr = sg_addr;
293162306a36Sopenharmony_ci		tr_req[tr_idx].icnt0 = tr0_cnt0;
293262306a36Sopenharmony_ci		tr_req[tr_idx].icnt1 = tr0_cnt1;
293362306a36Sopenharmony_ci		tr_req[tr_idx].dim1 = tr0_cnt0;
293462306a36Sopenharmony_ci		tr_idx++;
293562306a36Sopenharmony_ci
293662306a36Sopenharmony_ci		if (num_tr == 2) {
293762306a36Sopenharmony_ci			cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
293862306a36Sopenharmony_ci				      false, false,
293962306a36Sopenharmony_ci				      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
294062306a36Sopenharmony_ci			cppi5_tr_csf_set(&tr_req[tr_idx].flags,
294162306a36Sopenharmony_ci					 CPPI5_TR_CSF_SUPR_EVT);
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci			tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0;
294462306a36Sopenharmony_ci			tr_req[tr_idx].icnt0 = tr1_cnt0;
294562306a36Sopenharmony_ci			tr_req[tr_idx].icnt1 = 1;
294662306a36Sopenharmony_ci			tr_req[tr_idx].dim1 = tr1_cnt0;
294762306a36Sopenharmony_ci			tr_idx++;
294862306a36Sopenharmony_ci		}
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci		d->residue += sg_dma_len(sgent);
295162306a36Sopenharmony_ci	}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags,
295462306a36Sopenharmony_ci			 CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP);
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	return d;
295762306a36Sopenharmony_ci}
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_cistatic struct udma_desc *
296062306a36Sopenharmony_ciudma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl,
296162306a36Sopenharmony_ci				unsigned int sglen,
296262306a36Sopenharmony_ci				enum dma_transfer_direction dir,
296362306a36Sopenharmony_ci				unsigned long tx_flags, void *context)
296462306a36Sopenharmony_ci{
296562306a36Sopenharmony_ci	struct scatterlist *sgent;
296662306a36Sopenharmony_ci	struct cppi5_tr_type15_t *tr_req = NULL;
296762306a36Sopenharmony_ci	enum dma_slave_buswidth dev_width;
296862306a36Sopenharmony_ci	u32 csf = CPPI5_TR_CSF_SUPR_EVT;
296962306a36Sopenharmony_ci	u16 tr_cnt0, tr_cnt1;
297062306a36Sopenharmony_ci	dma_addr_t dev_addr;
297162306a36Sopenharmony_ci	struct udma_desc *d;
297262306a36Sopenharmony_ci	unsigned int i;
297362306a36Sopenharmony_ci	size_t tr_size, sg_len;
297462306a36Sopenharmony_ci	int num_tr = 0;
297562306a36Sopenharmony_ci	int tr_idx = 0;
297662306a36Sopenharmony_ci	u32 burst, trigger_size, port_window;
297762306a36Sopenharmony_ci	u64 asel;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM) {
298062306a36Sopenharmony_ci		dev_addr = uc->cfg.src_addr;
298162306a36Sopenharmony_ci		dev_width = uc->cfg.src_addr_width;
298262306a36Sopenharmony_ci		burst = uc->cfg.src_maxburst;
298362306a36Sopenharmony_ci		port_window = uc->cfg.src_port_window_size;
298462306a36Sopenharmony_ci	} else if (dir == DMA_MEM_TO_DEV) {
298562306a36Sopenharmony_ci		dev_addr = uc->cfg.dst_addr;
298662306a36Sopenharmony_ci		dev_width = uc->cfg.dst_addr_width;
298762306a36Sopenharmony_ci		burst = uc->cfg.dst_maxburst;
298862306a36Sopenharmony_ci		port_window = uc->cfg.dst_port_window_size;
298962306a36Sopenharmony_ci	} else {
299062306a36Sopenharmony_ci		dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
299162306a36Sopenharmony_ci		return NULL;
299262306a36Sopenharmony_ci	}
299362306a36Sopenharmony_ci
299462306a36Sopenharmony_ci	if (!burst)
299562306a36Sopenharmony_ci		burst = 1;
299662306a36Sopenharmony_ci
299762306a36Sopenharmony_ci	if (port_window) {
299862306a36Sopenharmony_ci		if (port_window != burst) {
299962306a36Sopenharmony_ci			dev_err(uc->ud->dev,
300062306a36Sopenharmony_ci				"The burst must be equal to port_window\n");
300162306a36Sopenharmony_ci			return NULL;
300262306a36Sopenharmony_ci		}
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci		tr_cnt0 = dev_width * port_window;
300562306a36Sopenharmony_ci		tr_cnt1 = 1;
300662306a36Sopenharmony_ci	} else {
300762306a36Sopenharmony_ci		tr_cnt0 = dev_width;
300862306a36Sopenharmony_ci		tr_cnt1 = burst;
300962306a36Sopenharmony_ci	}
301062306a36Sopenharmony_ci	trigger_size = tr_cnt0 * tr_cnt1;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	/* estimate the number of TRs we will need */
301362306a36Sopenharmony_ci	for_each_sg(sgl, sgent, sglen, i) {
301462306a36Sopenharmony_ci		sg_len = sg_dma_len(sgent);
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci		if (sg_len % trigger_size) {
301762306a36Sopenharmony_ci			dev_err(uc->ud->dev,
301862306a36Sopenharmony_ci				"Not aligned SG entry (%zu for %u)\n", sg_len,
301962306a36Sopenharmony_ci				trigger_size);
302062306a36Sopenharmony_ci			return NULL;
302162306a36Sopenharmony_ci		}
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci		if (sg_len / trigger_size < SZ_64K)
302462306a36Sopenharmony_ci			num_tr++;
302562306a36Sopenharmony_ci		else
302662306a36Sopenharmony_ci			num_tr += 2;
302762306a36Sopenharmony_ci	}
302862306a36Sopenharmony_ci
302962306a36Sopenharmony_ci	/* Now allocate and setup the descriptor. */
303062306a36Sopenharmony_ci	tr_size = sizeof(struct cppi5_tr_type15_t);
303162306a36Sopenharmony_ci	d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir);
303262306a36Sopenharmony_ci	if (!d)
303362306a36Sopenharmony_ci		return NULL;
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	d->sglen = sglen;
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_ci	if (uc->ud->match_data->type == DMA_TYPE_UDMA) {
303862306a36Sopenharmony_ci		asel = 0;
303962306a36Sopenharmony_ci		csf |= CPPI5_TR_CSF_EOL_ICNT0;
304062306a36Sopenharmony_ci	} else {
304162306a36Sopenharmony_ci		asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT;
304262306a36Sopenharmony_ci		dev_addr |= asel;
304362306a36Sopenharmony_ci	}
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci	tr_req = d->hwdesc[0].tr_req_base;
304662306a36Sopenharmony_ci	for_each_sg(sgl, sgent, sglen, i) {
304762306a36Sopenharmony_ci		u16 tr0_cnt2, tr0_cnt3, tr1_cnt2;
304862306a36Sopenharmony_ci		dma_addr_t sg_addr = sg_dma_address(sgent);
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci		sg_len = sg_dma_len(sgent);
305162306a36Sopenharmony_ci		num_tr = udma_get_tr_counters(sg_len / trigger_size, 0,
305262306a36Sopenharmony_ci					      &tr0_cnt2, &tr0_cnt3, &tr1_cnt2);
305362306a36Sopenharmony_ci		if (num_tr < 0) {
305462306a36Sopenharmony_ci			dev_err(uc->ud->dev, "size %zu is not supported\n",
305562306a36Sopenharmony_ci				sg_len);
305662306a36Sopenharmony_ci			udma_free_hwdesc(uc, d);
305762306a36Sopenharmony_ci			kfree(d);
305862306a36Sopenharmony_ci			return NULL;
305962306a36Sopenharmony_ci		}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci		cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false,
306262306a36Sopenharmony_ci			      true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
306362306a36Sopenharmony_ci		cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf);
306462306a36Sopenharmony_ci		cppi5_tr_set_trigger(&tr_req[tr_idx].flags,
306562306a36Sopenharmony_ci				     uc->config.tr_trigger_type,
306662306a36Sopenharmony_ci				     CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0);
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci		sg_addr |= asel;
306962306a36Sopenharmony_ci		if (dir == DMA_DEV_TO_MEM) {
307062306a36Sopenharmony_ci			tr_req[tr_idx].addr = dev_addr;
307162306a36Sopenharmony_ci			tr_req[tr_idx].icnt0 = tr_cnt0;
307262306a36Sopenharmony_ci			tr_req[tr_idx].icnt1 = tr_cnt1;
307362306a36Sopenharmony_ci			tr_req[tr_idx].icnt2 = tr0_cnt2;
307462306a36Sopenharmony_ci			tr_req[tr_idx].icnt3 = tr0_cnt3;
307562306a36Sopenharmony_ci			tr_req[tr_idx].dim1 = (-1) * tr_cnt0;
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci			tr_req[tr_idx].daddr = sg_addr;
307862306a36Sopenharmony_ci			tr_req[tr_idx].dicnt0 = tr_cnt0;
307962306a36Sopenharmony_ci			tr_req[tr_idx].dicnt1 = tr_cnt1;
308062306a36Sopenharmony_ci			tr_req[tr_idx].dicnt2 = tr0_cnt2;
308162306a36Sopenharmony_ci			tr_req[tr_idx].dicnt3 = tr0_cnt3;
308262306a36Sopenharmony_ci			tr_req[tr_idx].ddim1 = tr_cnt0;
308362306a36Sopenharmony_ci			tr_req[tr_idx].ddim2 = trigger_size;
308462306a36Sopenharmony_ci			tr_req[tr_idx].ddim3 = trigger_size * tr0_cnt2;
308562306a36Sopenharmony_ci		} else {
308662306a36Sopenharmony_ci			tr_req[tr_idx].addr = sg_addr;
308762306a36Sopenharmony_ci			tr_req[tr_idx].icnt0 = tr_cnt0;
308862306a36Sopenharmony_ci			tr_req[tr_idx].icnt1 = tr_cnt1;
308962306a36Sopenharmony_ci			tr_req[tr_idx].icnt2 = tr0_cnt2;
309062306a36Sopenharmony_ci			tr_req[tr_idx].icnt3 = tr0_cnt3;
309162306a36Sopenharmony_ci			tr_req[tr_idx].dim1 = tr_cnt0;
309262306a36Sopenharmony_ci			tr_req[tr_idx].dim2 = trigger_size;
309362306a36Sopenharmony_ci			tr_req[tr_idx].dim3 = trigger_size * tr0_cnt2;
309462306a36Sopenharmony_ci
309562306a36Sopenharmony_ci			tr_req[tr_idx].daddr = dev_addr;
309662306a36Sopenharmony_ci			tr_req[tr_idx].dicnt0 = tr_cnt0;
309762306a36Sopenharmony_ci			tr_req[tr_idx].dicnt1 = tr_cnt1;
309862306a36Sopenharmony_ci			tr_req[tr_idx].dicnt2 = tr0_cnt2;
309962306a36Sopenharmony_ci			tr_req[tr_idx].dicnt3 = tr0_cnt3;
310062306a36Sopenharmony_ci			tr_req[tr_idx].ddim1 = (-1) * tr_cnt0;
310162306a36Sopenharmony_ci		}
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci		tr_idx++;
310462306a36Sopenharmony_ci
310562306a36Sopenharmony_ci		if (num_tr == 2) {
310662306a36Sopenharmony_ci			cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15,
310762306a36Sopenharmony_ci				      false, true,
310862306a36Sopenharmony_ci				      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
310962306a36Sopenharmony_ci			cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf);
311062306a36Sopenharmony_ci			cppi5_tr_set_trigger(&tr_req[tr_idx].flags,
311162306a36Sopenharmony_ci					     uc->config.tr_trigger_type,
311262306a36Sopenharmony_ci					     CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC,
311362306a36Sopenharmony_ci					     0, 0);
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci			sg_addr += trigger_size * tr0_cnt2 * tr0_cnt3;
311662306a36Sopenharmony_ci			if (dir == DMA_DEV_TO_MEM) {
311762306a36Sopenharmony_ci				tr_req[tr_idx].addr = dev_addr;
311862306a36Sopenharmony_ci				tr_req[tr_idx].icnt0 = tr_cnt0;
311962306a36Sopenharmony_ci				tr_req[tr_idx].icnt1 = tr_cnt1;
312062306a36Sopenharmony_ci				tr_req[tr_idx].icnt2 = tr1_cnt2;
312162306a36Sopenharmony_ci				tr_req[tr_idx].icnt3 = 1;
312262306a36Sopenharmony_ci				tr_req[tr_idx].dim1 = (-1) * tr_cnt0;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci				tr_req[tr_idx].daddr = sg_addr;
312562306a36Sopenharmony_ci				tr_req[tr_idx].dicnt0 = tr_cnt0;
312662306a36Sopenharmony_ci				tr_req[tr_idx].dicnt1 = tr_cnt1;
312762306a36Sopenharmony_ci				tr_req[tr_idx].dicnt2 = tr1_cnt2;
312862306a36Sopenharmony_ci				tr_req[tr_idx].dicnt3 = 1;
312962306a36Sopenharmony_ci				tr_req[tr_idx].ddim1 = tr_cnt0;
313062306a36Sopenharmony_ci				tr_req[tr_idx].ddim2 = trigger_size;
313162306a36Sopenharmony_ci			} else {
313262306a36Sopenharmony_ci				tr_req[tr_idx].addr = sg_addr;
313362306a36Sopenharmony_ci				tr_req[tr_idx].icnt0 = tr_cnt0;
313462306a36Sopenharmony_ci				tr_req[tr_idx].icnt1 = tr_cnt1;
313562306a36Sopenharmony_ci				tr_req[tr_idx].icnt2 = tr1_cnt2;
313662306a36Sopenharmony_ci				tr_req[tr_idx].icnt3 = 1;
313762306a36Sopenharmony_ci				tr_req[tr_idx].dim1 = tr_cnt0;
313862306a36Sopenharmony_ci				tr_req[tr_idx].dim2 = trigger_size;
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci				tr_req[tr_idx].daddr = dev_addr;
314162306a36Sopenharmony_ci				tr_req[tr_idx].dicnt0 = tr_cnt0;
314262306a36Sopenharmony_ci				tr_req[tr_idx].dicnt1 = tr_cnt1;
314362306a36Sopenharmony_ci				tr_req[tr_idx].dicnt2 = tr1_cnt2;
314462306a36Sopenharmony_ci				tr_req[tr_idx].dicnt3 = 1;
314562306a36Sopenharmony_ci				tr_req[tr_idx].ddim1 = (-1) * tr_cnt0;
314662306a36Sopenharmony_ci			}
314762306a36Sopenharmony_ci			tr_idx++;
314862306a36Sopenharmony_ci		}
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci		d->residue += sg_len;
315162306a36Sopenharmony_ci	}
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_ci	cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP);
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	return d;
315662306a36Sopenharmony_ci}
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cistatic int udma_configure_statictr(struct udma_chan *uc, struct udma_desc *d,
315962306a36Sopenharmony_ci				   enum dma_slave_buswidth dev_width,
316062306a36Sopenharmony_ci				   u16 elcnt)
316162306a36Sopenharmony_ci{
316262306a36Sopenharmony_ci	if (uc->config.ep_type != PSIL_EP_PDMA_XY)
316362306a36Sopenharmony_ci		return 0;
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_ci	/* Bus width translates to the element size (ES) */
316662306a36Sopenharmony_ci	switch (dev_width) {
316762306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_1_BYTE:
316862306a36Sopenharmony_ci		d->static_tr.elsize = 0;
316962306a36Sopenharmony_ci		break;
317062306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_2_BYTES:
317162306a36Sopenharmony_ci		d->static_tr.elsize = 1;
317262306a36Sopenharmony_ci		break;
317362306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_3_BYTES:
317462306a36Sopenharmony_ci		d->static_tr.elsize = 2;
317562306a36Sopenharmony_ci		break;
317662306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_4_BYTES:
317762306a36Sopenharmony_ci		d->static_tr.elsize = 3;
317862306a36Sopenharmony_ci		break;
317962306a36Sopenharmony_ci	case DMA_SLAVE_BUSWIDTH_8_BYTES:
318062306a36Sopenharmony_ci		d->static_tr.elsize = 4;
318162306a36Sopenharmony_ci		break;
318262306a36Sopenharmony_ci	default: /* not reached */
318362306a36Sopenharmony_ci		return -EINVAL;
318462306a36Sopenharmony_ci	}
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ci	d->static_tr.elcnt = elcnt;
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci	/*
318962306a36Sopenharmony_ci	 * PDMA must to close the packet when the channel is in packet mode.
319062306a36Sopenharmony_ci	 * For TR mode when the channel is not cyclic we also need PDMA to close
319162306a36Sopenharmony_ci	 * the packet otherwise the transfer will stall because PDMA holds on
319262306a36Sopenharmony_ci	 * the data it has received from the peripheral.
319362306a36Sopenharmony_ci	 */
319462306a36Sopenharmony_ci	if (uc->config.pkt_mode || !uc->cyclic) {
319562306a36Sopenharmony_ci		unsigned int div = dev_width * elcnt;
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci		if (uc->cyclic)
319862306a36Sopenharmony_ci			d->static_tr.bstcnt = d->residue / d->sglen / div;
319962306a36Sopenharmony_ci		else
320062306a36Sopenharmony_ci			d->static_tr.bstcnt = d->residue / div;
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci		if (uc->config.dir == DMA_DEV_TO_MEM &&
320362306a36Sopenharmony_ci		    d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask)
320462306a36Sopenharmony_ci			return -EINVAL;
320562306a36Sopenharmony_ci	} else {
320662306a36Sopenharmony_ci		d->static_tr.bstcnt = 0;
320762306a36Sopenharmony_ci	}
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	return 0;
321062306a36Sopenharmony_ci}
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_cistatic struct udma_desc *
321362306a36Sopenharmony_ciudma_prep_slave_sg_pkt(struct udma_chan *uc, struct scatterlist *sgl,
321462306a36Sopenharmony_ci		       unsigned int sglen, enum dma_transfer_direction dir,
321562306a36Sopenharmony_ci		       unsigned long tx_flags, void *context)
321662306a36Sopenharmony_ci{
321762306a36Sopenharmony_ci	struct scatterlist *sgent;
321862306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc = NULL;
321962306a36Sopenharmony_ci	struct udma_desc *d;
322062306a36Sopenharmony_ci	u32 ring_id;
322162306a36Sopenharmony_ci	unsigned int i;
322262306a36Sopenharmony_ci	u64 asel;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci	d = kzalloc(struct_size(d, hwdesc, sglen), GFP_NOWAIT);
322562306a36Sopenharmony_ci	if (!d)
322662306a36Sopenharmony_ci		return NULL;
322762306a36Sopenharmony_ci
322862306a36Sopenharmony_ci	d->sglen = sglen;
322962306a36Sopenharmony_ci	d->hwdesc_count = sglen;
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM)
323262306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring);
323362306a36Sopenharmony_ci	else
323462306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring);
323562306a36Sopenharmony_ci
323662306a36Sopenharmony_ci	if (uc->ud->match_data->type == DMA_TYPE_UDMA)
323762306a36Sopenharmony_ci		asel = 0;
323862306a36Sopenharmony_ci	else
323962306a36Sopenharmony_ci		asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT;
324062306a36Sopenharmony_ci
324162306a36Sopenharmony_ci	for_each_sg(sgl, sgent, sglen, i) {
324262306a36Sopenharmony_ci		struct udma_hwdesc *hwdesc = &d->hwdesc[i];
324362306a36Sopenharmony_ci		dma_addr_t sg_addr = sg_dma_address(sgent);
324462306a36Sopenharmony_ci		struct cppi5_host_desc_t *desc;
324562306a36Sopenharmony_ci		size_t sg_len = sg_dma_len(sgent);
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci		hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool,
324862306a36Sopenharmony_ci						GFP_NOWAIT,
324962306a36Sopenharmony_ci						&hwdesc->cppi5_desc_paddr);
325062306a36Sopenharmony_ci		if (!hwdesc->cppi5_desc_vaddr) {
325162306a36Sopenharmony_ci			dev_err(uc->ud->dev,
325262306a36Sopenharmony_ci				"descriptor%d allocation failed\n", i);
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci			udma_free_hwdesc(uc, d);
325562306a36Sopenharmony_ci			kfree(d);
325662306a36Sopenharmony_ci			return NULL;
325762306a36Sopenharmony_ci		}
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci		d->residue += sg_len;
326062306a36Sopenharmony_ci		hwdesc->cppi5_desc_size = uc->config.hdesc_size;
326162306a36Sopenharmony_ci		desc = hwdesc->cppi5_desc_vaddr;
326262306a36Sopenharmony_ci
326362306a36Sopenharmony_ci		if (i == 0) {
326462306a36Sopenharmony_ci			cppi5_hdesc_init(desc, 0, 0);
326562306a36Sopenharmony_ci			/* Flow and Packed ID */
326662306a36Sopenharmony_ci			cppi5_desc_set_pktids(&desc->hdr, uc->id,
326762306a36Sopenharmony_ci					      CPPI5_INFO1_DESC_FLOWID_DEFAULT);
326862306a36Sopenharmony_ci			cppi5_desc_set_retpolicy(&desc->hdr, 0, ring_id);
326962306a36Sopenharmony_ci		} else {
327062306a36Sopenharmony_ci			cppi5_hdesc_reset_hbdesc(desc);
327162306a36Sopenharmony_ci			cppi5_desc_set_retpolicy(&desc->hdr, 0, 0xffff);
327262306a36Sopenharmony_ci		}
327362306a36Sopenharmony_ci
327462306a36Sopenharmony_ci		/* attach the sg buffer to the descriptor */
327562306a36Sopenharmony_ci		sg_addr |= asel;
327662306a36Sopenharmony_ci		cppi5_hdesc_attach_buf(desc, sg_addr, sg_len, sg_addr, sg_len);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci		/* Attach link as host buffer descriptor */
327962306a36Sopenharmony_ci		if (h_desc)
328062306a36Sopenharmony_ci			cppi5_hdesc_link_hbdesc(h_desc,
328162306a36Sopenharmony_ci						hwdesc->cppi5_desc_paddr | asel);
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci		if (uc->ud->match_data->type == DMA_TYPE_PKTDMA ||
328462306a36Sopenharmony_ci		    dir == DMA_MEM_TO_DEV)
328562306a36Sopenharmony_ci			h_desc = desc;
328662306a36Sopenharmony_ci	}
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci	if (d->residue >= SZ_4M) {
328962306a36Sopenharmony_ci		dev_err(uc->ud->dev,
329062306a36Sopenharmony_ci			"%s: Transfer size %u is over the supported 4M range\n",
329162306a36Sopenharmony_ci			__func__, d->residue);
329262306a36Sopenharmony_ci		udma_free_hwdesc(uc, d);
329362306a36Sopenharmony_ci		kfree(d);
329462306a36Sopenharmony_ci		return NULL;
329562306a36Sopenharmony_ci	}
329662306a36Sopenharmony_ci
329762306a36Sopenharmony_ci	h_desc = d->hwdesc[0].cppi5_desc_vaddr;
329862306a36Sopenharmony_ci	cppi5_hdesc_set_pktlen(h_desc, d->residue);
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	return d;
330162306a36Sopenharmony_ci}
330262306a36Sopenharmony_ci
330362306a36Sopenharmony_cistatic int udma_attach_metadata(struct dma_async_tx_descriptor *desc,
330462306a36Sopenharmony_ci				void *data, size_t len)
330562306a36Sopenharmony_ci{
330662306a36Sopenharmony_ci	struct udma_desc *d = to_udma_desc(desc);
330762306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(desc->chan);
330862306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc;
330962306a36Sopenharmony_ci	u32 psd_size = len;
331062306a36Sopenharmony_ci	u32 flags = 0;
331162306a36Sopenharmony_ci
331262306a36Sopenharmony_ci	if (!uc->config.pkt_mode || !uc->config.metadata_size)
331362306a36Sopenharmony_ci		return -ENOTSUPP;
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_ci	if (!data || len > uc->config.metadata_size)
331662306a36Sopenharmony_ci		return -EINVAL;
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_ci	if (uc->config.needs_epib && len < CPPI5_INFO0_HDESC_EPIB_SIZE)
331962306a36Sopenharmony_ci		return -EINVAL;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	h_desc = d->hwdesc[0].cppi5_desc_vaddr;
332262306a36Sopenharmony_ci	if (d->dir == DMA_MEM_TO_DEV)
332362306a36Sopenharmony_ci		memcpy(h_desc->epib, data, len);
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	if (uc->config.needs_epib)
332662306a36Sopenharmony_ci		psd_size -= CPPI5_INFO0_HDESC_EPIB_SIZE;
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci	d->metadata = data;
332962306a36Sopenharmony_ci	d->metadata_size = len;
333062306a36Sopenharmony_ci	if (uc->config.needs_epib)
333162306a36Sopenharmony_ci		flags |= CPPI5_INFO0_HDESC_EPIB_PRESENT;
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	cppi5_hdesc_update_flags(h_desc, flags);
333462306a36Sopenharmony_ci	cppi5_hdesc_update_psdata_size(h_desc, psd_size);
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	return 0;
333762306a36Sopenharmony_ci}
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_cistatic void *udma_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
334062306a36Sopenharmony_ci				   size_t *payload_len, size_t *max_len)
334162306a36Sopenharmony_ci{
334262306a36Sopenharmony_ci	struct udma_desc *d = to_udma_desc(desc);
334362306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(desc->chan);
334462306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	if (!uc->config.pkt_mode || !uc->config.metadata_size)
334762306a36Sopenharmony_ci		return ERR_PTR(-ENOTSUPP);
334862306a36Sopenharmony_ci
334962306a36Sopenharmony_ci	h_desc = d->hwdesc[0].cppi5_desc_vaddr;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	*max_len = uc->config.metadata_size;
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci	*payload_len = cppi5_hdesc_epib_present(&h_desc->hdr) ?
335462306a36Sopenharmony_ci		       CPPI5_INFO0_HDESC_EPIB_SIZE : 0;
335562306a36Sopenharmony_ci	*payload_len += cppi5_hdesc_get_psdata_size(h_desc);
335662306a36Sopenharmony_ci
335762306a36Sopenharmony_ci	return h_desc->epib;
335862306a36Sopenharmony_ci}
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_cistatic int udma_set_metadata_len(struct dma_async_tx_descriptor *desc,
336162306a36Sopenharmony_ci				 size_t payload_len)
336262306a36Sopenharmony_ci{
336362306a36Sopenharmony_ci	struct udma_desc *d = to_udma_desc(desc);
336462306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(desc->chan);
336562306a36Sopenharmony_ci	struct cppi5_host_desc_t *h_desc;
336662306a36Sopenharmony_ci	u32 psd_size = payload_len;
336762306a36Sopenharmony_ci	u32 flags = 0;
336862306a36Sopenharmony_ci
336962306a36Sopenharmony_ci	if (!uc->config.pkt_mode || !uc->config.metadata_size)
337062306a36Sopenharmony_ci		return -ENOTSUPP;
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	if (payload_len > uc->config.metadata_size)
337362306a36Sopenharmony_ci		return -EINVAL;
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	if (uc->config.needs_epib && payload_len < CPPI5_INFO0_HDESC_EPIB_SIZE)
337662306a36Sopenharmony_ci		return -EINVAL;
337762306a36Sopenharmony_ci
337862306a36Sopenharmony_ci	h_desc = d->hwdesc[0].cppi5_desc_vaddr;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	if (uc->config.needs_epib) {
338162306a36Sopenharmony_ci		psd_size -= CPPI5_INFO0_HDESC_EPIB_SIZE;
338262306a36Sopenharmony_ci		flags |= CPPI5_INFO0_HDESC_EPIB_PRESENT;
338362306a36Sopenharmony_ci	}
338462306a36Sopenharmony_ci
338562306a36Sopenharmony_ci	cppi5_hdesc_update_flags(h_desc, flags);
338662306a36Sopenharmony_ci	cppi5_hdesc_update_psdata_size(h_desc, psd_size);
338762306a36Sopenharmony_ci
338862306a36Sopenharmony_ci	return 0;
338962306a36Sopenharmony_ci}
339062306a36Sopenharmony_ci
339162306a36Sopenharmony_cistatic struct dma_descriptor_metadata_ops metadata_ops = {
339262306a36Sopenharmony_ci	.attach = udma_attach_metadata,
339362306a36Sopenharmony_ci	.get_ptr = udma_get_metadata_ptr,
339462306a36Sopenharmony_ci	.set_len = udma_set_metadata_len,
339562306a36Sopenharmony_ci};
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
339862306a36Sopenharmony_ciudma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
339962306a36Sopenharmony_ci		   unsigned int sglen, enum dma_transfer_direction dir,
340062306a36Sopenharmony_ci		   unsigned long tx_flags, void *context)
340162306a36Sopenharmony_ci{
340262306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
340362306a36Sopenharmony_ci	enum dma_slave_buswidth dev_width;
340462306a36Sopenharmony_ci	struct udma_desc *d;
340562306a36Sopenharmony_ci	u32 burst;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	if (dir != uc->config.dir &&
340862306a36Sopenharmony_ci	    (uc->config.dir == DMA_MEM_TO_MEM && !uc->config.tr_trigger_type)) {
340962306a36Sopenharmony_ci		dev_err(chan->device->dev,
341062306a36Sopenharmony_ci			"%s: chan%d is for %s, not supporting %s\n",
341162306a36Sopenharmony_ci			__func__, uc->id,
341262306a36Sopenharmony_ci			dmaengine_get_direction_text(uc->config.dir),
341362306a36Sopenharmony_ci			dmaengine_get_direction_text(dir));
341462306a36Sopenharmony_ci		return NULL;
341562306a36Sopenharmony_ci	}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM) {
341862306a36Sopenharmony_ci		dev_width = uc->cfg.src_addr_width;
341962306a36Sopenharmony_ci		burst = uc->cfg.src_maxburst;
342062306a36Sopenharmony_ci	} else if (dir == DMA_MEM_TO_DEV) {
342162306a36Sopenharmony_ci		dev_width = uc->cfg.dst_addr_width;
342262306a36Sopenharmony_ci		burst = uc->cfg.dst_maxburst;
342362306a36Sopenharmony_ci	} else {
342462306a36Sopenharmony_ci		dev_err(chan->device->dev, "%s: bad direction?\n", __func__);
342562306a36Sopenharmony_ci		return NULL;
342662306a36Sopenharmony_ci	}
342762306a36Sopenharmony_ci
342862306a36Sopenharmony_ci	if (!burst)
342962306a36Sopenharmony_ci		burst = 1;
343062306a36Sopenharmony_ci
343162306a36Sopenharmony_ci	uc->config.tx_flags = tx_flags;
343262306a36Sopenharmony_ci
343362306a36Sopenharmony_ci	if (uc->config.pkt_mode)
343462306a36Sopenharmony_ci		d = udma_prep_slave_sg_pkt(uc, sgl, sglen, dir, tx_flags,
343562306a36Sopenharmony_ci					   context);
343662306a36Sopenharmony_ci	else if (is_slave_direction(uc->config.dir))
343762306a36Sopenharmony_ci		d = udma_prep_slave_sg_tr(uc, sgl, sglen, dir, tx_flags,
343862306a36Sopenharmony_ci					  context);
343962306a36Sopenharmony_ci	else
344062306a36Sopenharmony_ci		d = udma_prep_slave_sg_triggered_tr(uc, sgl, sglen, dir,
344162306a36Sopenharmony_ci						    tx_flags, context);
344262306a36Sopenharmony_ci
344362306a36Sopenharmony_ci	if (!d)
344462306a36Sopenharmony_ci		return NULL;
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci	d->dir = dir;
344762306a36Sopenharmony_ci	d->desc_idx = 0;
344862306a36Sopenharmony_ci	d->tr_idx = 0;
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_ci	/* static TR for remote PDMA */
345162306a36Sopenharmony_ci	if (udma_configure_statictr(uc, d, dev_width, burst)) {
345262306a36Sopenharmony_ci		dev_err(uc->ud->dev,
345362306a36Sopenharmony_ci			"%s: StaticTR Z is limited to maximum 4095 (%u)\n",
345462306a36Sopenharmony_ci			__func__, d->static_tr.bstcnt);
345562306a36Sopenharmony_ci
345662306a36Sopenharmony_ci		udma_free_hwdesc(uc, d);
345762306a36Sopenharmony_ci		kfree(d);
345862306a36Sopenharmony_ci		return NULL;
345962306a36Sopenharmony_ci	}
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	if (uc->config.metadata_size)
346262306a36Sopenharmony_ci		d->vd.tx.metadata_ops = &metadata_ops;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	return vchan_tx_prep(&uc->vc, &d->vd, tx_flags);
346562306a36Sopenharmony_ci}
346662306a36Sopenharmony_ci
346762306a36Sopenharmony_cistatic struct udma_desc *
346862306a36Sopenharmony_ciudma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr,
346962306a36Sopenharmony_ci			size_t buf_len, size_t period_len,
347062306a36Sopenharmony_ci			enum dma_transfer_direction dir, unsigned long flags)
347162306a36Sopenharmony_ci{
347262306a36Sopenharmony_ci	struct udma_desc *d;
347362306a36Sopenharmony_ci	size_t tr_size, period_addr;
347462306a36Sopenharmony_ci	struct cppi5_tr_type1_t *tr_req;
347562306a36Sopenharmony_ci	unsigned int periods = buf_len / period_len;
347662306a36Sopenharmony_ci	u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
347762306a36Sopenharmony_ci	unsigned int i;
347862306a36Sopenharmony_ci	int num_tr;
347962306a36Sopenharmony_ci
348062306a36Sopenharmony_ci	num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0,
348162306a36Sopenharmony_ci				      &tr0_cnt1, &tr1_cnt0);
348262306a36Sopenharmony_ci	if (num_tr < 0) {
348362306a36Sopenharmony_ci		dev_err(uc->ud->dev, "size %zu is not supported\n",
348462306a36Sopenharmony_ci			period_len);
348562306a36Sopenharmony_ci		return NULL;
348662306a36Sopenharmony_ci	}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	/* Now allocate and setup the descriptor. */
348962306a36Sopenharmony_ci	tr_size = sizeof(struct cppi5_tr_type1_t);
349062306a36Sopenharmony_ci	d = udma_alloc_tr_desc(uc, tr_size, periods * num_tr, dir);
349162306a36Sopenharmony_ci	if (!d)
349262306a36Sopenharmony_ci		return NULL;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	tr_req = d->hwdesc[0].tr_req_base;
349562306a36Sopenharmony_ci	if (uc->ud->match_data->type == DMA_TYPE_UDMA)
349662306a36Sopenharmony_ci		period_addr = buf_addr;
349762306a36Sopenharmony_ci	else
349862306a36Sopenharmony_ci		period_addr = buf_addr |
349962306a36Sopenharmony_ci			((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT);
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	for (i = 0; i < periods; i++) {
350262306a36Sopenharmony_ci		int tr_idx = i * num_tr;
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci		cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false,
350562306a36Sopenharmony_ci			      false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
350662306a36Sopenharmony_ci
350762306a36Sopenharmony_ci		tr_req[tr_idx].addr = period_addr;
350862306a36Sopenharmony_ci		tr_req[tr_idx].icnt0 = tr0_cnt0;
350962306a36Sopenharmony_ci		tr_req[tr_idx].icnt1 = tr0_cnt1;
351062306a36Sopenharmony_ci		tr_req[tr_idx].dim1 = tr0_cnt0;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci		if (num_tr == 2) {
351362306a36Sopenharmony_ci			cppi5_tr_csf_set(&tr_req[tr_idx].flags,
351462306a36Sopenharmony_ci					 CPPI5_TR_CSF_SUPR_EVT);
351562306a36Sopenharmony_ci			tr_idx++;
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci			cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1,
351862306a36Sopenharmony_ci				      false, false,
351962306a36Sopenharmony_ci				      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci			tr_req[tr_idx].addr = period_addr + tr0_cnt1 * tr0_cnt0;
352262306a36Sopenharmony_ci			tr_req[tr_idx].icnt0 = tr1_cnt0;
352362306a36Sopenharmony_ci			tr_req[tr_idx].icnt1 = 1;
352462306a36Sopenharmony_ci			tr_req[tr_idx].dim1 = tr1_cnt0;
352562306a36Sopenharmony_ci		}
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci		if (!(flags & DMA_PREP_INTERRUPT))
352862306a36Sopenharmony_ci			cppi5_tr_csf_set(&tr_req[tr_idx].flags,
352962306a36Sopenharmony_ci					 CPPI5_TR_CSF_SUPR_EVT);
353062306a36Sopenharmony_ci
353162306a36Sopenharmony_ci		period_addr += period_len;
353262306a36Sopenharmony_ci	}
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	return d;
353562306a36Sopenharmony_ci}
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_cistatic struct udma_desc *
353862306a36Sopenharmony_ciudma_prep_dma_cyclic_pkt(struct udma_chan *uc, dma_addr_t buf_addr,
353962306a36Sopenharmony_ci			 size_t buf_len, size_t period_len,
354062306a36Sopenharmony_ci			 enum dma_transfer_direction dir, unsigned long flags)
354162306a36Sopenharmony_ci{
354262306a36Sopenharmony_ci	struct udma_desc *d;
354362306a36Sopenharmony_ci	u32 ring_id;
354462306a36Sopenharmony_ci	int i;
354562306a36Sopenharmony_ci	int periods = buf_len / period_len;
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	if (periods > (K3_UDMA_DEFAULT_RING_SIZE - 1))
354862306a36Sopenharmony_ci		return NULL;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	if (period_len >= SZ_4M)
355162306a36Sopenharmony_ci		return NULL;
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	d = kzalloc(struct_size(d, hwdesc, periods), GFP_NOWAIT);
355462306a36Sopenharmony_ci	if (!d)
355562306a36Sopenharmony_ci		return NULL;
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci	d->hwdesc_count = periods;
355862306a36Sopenharmony_ci
355962306a36Sopenharmony_ci	/* TODO: re-check this... */
356062306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM)
356162306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring);
356262306a36Sopenharmony_ci	else
356362306a36Sopenharmony_ci		ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring);
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci	if (uc->ud->match_data->type != DMA_TYPE_UDMA)
356662306a36Sopenharmony_ci		buf_addr |= (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_ci	for (i = 0; i < periods; i++) {
356962306a36Sopenharmony_ci		struct udma_hwdesc *hwdesc = &d->hwdesc[i];
357062306a36Sopenharmony_ci		dma_addr_t period_addr = buf_addr + (period_len * i);
357162306a36Sopenharmony_ci		struct cppi5_host_desc_t *h_desc;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci		hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool,
357462306a36Sopenharmony_ci						GFP_NOWAIT,
357562306a36Sopenharmony_ci						&hwdesc->cppi5_desc_paddr);
357662306a36Sopenharmony_ci		if (!hwdesc->cppi5_desc_vaddr) {
357762306a36Sopenharmony_ci			dev_err(uc->ud->dev,
357862306a36Sopenharmony_ci				"descriptor%d allocation failed\n", i);
357962306a36Sopenharmony_ci
358062306a36Sopenharmony_ci			udma_free_hwdesc(uc, d);
358162306a36Sopenharmony_ci			kfree(d);
358262306a36Sopenharmony_ci			return NULL;
358362306a36Sopenharmony_ci		}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_ci		hwdesc->cppi5_desc_size = uc->config.hdesc_size;
358662306a36Sopenharmony_ci		h_desc = hwdesc->cppi5_desc_vaddr;
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci		cppi5_hdesc_init(h_desc, 0, 0);
358962306a36Sopenharmony_ci		cppi5_hdesc_set_pktlen(h_desc, period_len);
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci		/* Flow and Packed ID */
359262306a36Sopenharmony_ci		cppi5_desc_set_pktids(&h_desc->hdr, uc->id,
359362306a36Sopenharmony_ci				      CPPI5_INFO1_DESC_FLOWID_DEFAULT);
359462306a36Sopenharmony_ci		cppi5_desc_set_retpolicy(&h_desc->hdr, 0, ring_id);
359562306a36Sopenharmony_ci
359662306a36Sopenharmony_ci		/* attach each period to a new descriptor */
359762306a36Sopenharmony_ci		cppi5_hdesc_attach_buf(h_desc,
359862306a36Sopenharmony_ci				       period_addr, period_len,
359962306a36Sopenharmony_ci				       period_addr, period_len);
360062306a36Sopenharmony_ci	}
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	return d;
360362306a36Sopenharmony_ci}
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
360662306a36Sopenharmony_ciudma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
360762306a36Sopenharmony_ci		     size_t period_len, enum dma_transfer_direction dir,
360862306a36Sopenharmony_ci		     unsigned long flags)
360962306a36Sopenharmony_ci{
361062306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
361162306a36Sopenharmony_ci	enum dma_slave_buswidth dev_width;
361262306a36Sopenharmony_ci	struct udma_desc *d;
361362306a36Sopenharmony_ci	u32 burst;
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	if (dir != uc->config.dir) {
361662306a36Sopenharmony_ci		dev_err(chan->device->dev,
361762306a36Sopenharmony_ci			"%s: chan%d is for %s, not supporting %s\n",
361862306a36Sopenharmony_ci			__func__, uc->id,
361962306a36Sopenharmony_ci			dmaengine_get_direction_text(uc->config.dir),
362062306a36Sopenharmony_ci			dmaengine_get_direction_text(dir));
362162306a36Sopenharmony_ci		return NULL;
362262306a36Sopenharmony_ci	}
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci	uc->cyclic = true;
362562306a36Sopenharmony_ci
362662306a36Sopenharmony_ci	if (dir == DMA_DEV_TO_MEM) {
362762306a36Sopenharmony_ci		dev_width = uc->cfg.src_addr_width;
362862306a36Sopenharmony_ci		burst = uc->cfg.src_maxburst;
362962306a36Sopenharmony_ci	} else if (dir == DMA_MEM_TO_DEV) {
363062306a36Sopenharmony_ci		dev_width = uc->cfg.dst_addr_width;
363162306a36Sopenharmony_ci		burst = uc->cfg.dst_maxburst;
363262306a36Sopenharmony_ci	} else {
363362306a36Sopenharmony_ci		dev_err(uc->ud->dev, "%s: bad direction?\n", __func__);
363462306a36Sopenharmony_ci		return NULL;
363562306a36Sopenharmony_ci	}
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci	if (!burst)
363862306a36Sopenharmony_ci		burst = 1;
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	if (uc->config.pkt_mode)
364162306a36Sopenharmony_ci		d = udma_prep_dma_cyclic_pkt(uc, buf_addr, buf_len, period_len,
364262306a36Sopenharmony_ci					     dir, flags);
364362306a36Sopenharmony_ci	else
364462306a36Sopenharmony_ci		d = udma_prep_dma_cyclic_tr(uc, buf_addr, buf_len, period_len,
364562306a36Sopenharmony_ci					    dir, flags);
364662306a36Sopenharmony_ci
364762306a36Sopenharmony_ci	if (!d)
364862306a36Sopenharmony_ci		return NULL;
364962306a36Sopenharmony_ci
365062306a36Sopenharmony_ci	d->sglen = buf_len / period_len;
365162306a36Sopenharmony_ci
365262306a36Sopenharmony_ci	d->dir = dir;
365362306a36Sopenharmony_ci	d->residue = buf_len;
365462306a36Sopenharmony_ci
365562306a36Sopenharmony_ci	/* static TR for remote PDMA */
365662306a36Sopenharmony_ci	if (udma_configure_statictr(uc, d, dev_width, burst)) {
365762306a36Sopenharmony_ci		dev_err(uc->ud->dev,
365862306a36Sopenharmony_ci			"%s: StaticTR Z is limited to maximum 4095 (%u)\n",
365962306a36Sopenharmony_ci			__func__, d->static_tr.bstcnt);
366062306a36Sopenharmony_ci
366162306a36Sopenharmony_ci		udma_free_hwdesc(uc, d);
366262306a36Sopenharmony_ci		kfree(d);
366362306a36Sopenharmony_ci		return NULL;
366462306a36Sopenharmony_ci	}
366562306a36Sopenharmony_ci
366662306a36Sopenharmony_ci	if (uc->config.metadata_size)
366762306a36Sopenharmony_ci		d->vd.tx.metadata_ops = &metadata_ops;
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci	return vchan_tx_prep(&uc->vc, &d->vd, flags);
367062306a36Sopenharmony_ci}
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *
367362306a36Sopenharmony_ciudma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
367462306a36Sopenharmony_ci		     size_t len, unsigned long tx_flags)
367562306a36Sopenharmony_ci{
367662306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
367762306a36Sopenharmony_ci	struct udma_desc *d;
367862306a36Sopenharmony_ci	struct cppi5_tr_type15_t *tr_req;
367962306a36Sopenharmony_ci	int num_tr;
368062306a36Sopenharmony_ci	size_t tr_size = sizeof(struct cppi5_tr_type15_t);
368162306a36Sopenharmony_ci	u16 tr0_cnt0, tr0_cnt1, tr1_cnt0;
368262306a36Sopenharmony_ci	u32 csf = CPPI5_TR_CSF_SUPR_EVT;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	if (uc->config.dir != DMA_MEM_TO_MEM) {
368562306a36Sopenharmony_ci		dev_err(chan->device->dev,
368662306a36Sopenharmony_ci			"%s: chan%d is for %s, not supporting %s\n",
368762306a36Sopenharmony_ci			__func__, uc->id,
368862306a36Sopenharmony_ci			dmaengine_get_direction_text(uc->config.dir),
368962306a36Sopenharmony_ci			dmaengine_get_direction_text(DMA_MEM_TO_MEM));
369062306a36Sopenharmony_ci		return NULL;
369162306a36Sopenharmony_ci	}
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	num_tr = udma_get_tr_counters(len, __ffs(src | dest), &tr0_cnt0,
369462306a36Sopenharmony_ci				      &tr0_cnt1, &tr1_cnt0);
369562306a36Sopenharmony_ci	if (num_tr < 0) {
369662306a36Sopenharmony_ci		dev_err(uc->ud->dev, "size %zu is not supported\n",
369762306a36Sopenharmony_ci			len);
369862306a36Sopenharmony_ci		return NULL;
369962306a36Sopenharmony_ci	}
370062306a36Sopenharmony_ci
370162306a36Sopenharmony_ci	d = udma_alloc_tr_desc(uc, tr_size, num_tr, DMA_MEM_TO_MEM);
370262306a36Sopenharmony_ci	if (!d)
370362306a36Sopenharmony_ci		return NULL;
370462306a36Sopenharmony_ci
370562306a36Sopenharmony_ci	d->dir = DMA_MEM_TO_MEM;
370662306a36Sopenharmony_ci	d->desc_idx = 0;
370762306a36Sopenharmony_ci	d->tr_idx = 0;
370862306a36Sopenharmony_ci	d->residue = len;
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	if (uc->ud->match_data->type != DMA_TYPE_UDMA) {
371162306a36Sopenharmony_ci		src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT;
371262306a36Sopenharmony_ci		dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT;
371362306a36Sopenharmony_ci	} else {
371462306a36Sopenharmony_ci		csf |= CPPI5_TR_CSF_EOL_ICNT0;
371562306a36Sopenharmony_ci	}
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	tr_req = d->hwdesc[0].tr_req_base;
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci	cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true,
372062306a36Sopenharmony_ci		      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
372162306a36Sopenharmony_ci	cppi5_tr_csf_set(&tr_req[0].flags, csf);
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	tr_req[0].addr = src;
372462306a36Sopenharmony_ci	tr_req[0].icnt0 = tr0_cnt0;
372562306a36Sopenharmony_ci	tr_req[0].icnt1 = tr0_cnt1;
372662306a36Sopenharmony_ci	tr_req[0].icnt2 = 1;
372762306a36Sopenharmony_ci	tr_req[0].icnt3 = 1;
372862306a36Sopenharmony_ci	tr_req[0].dim1 = tr0_cnt0;
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	tr_req[0].daddr = dest;
373162306a36Sopenharmony_ci	tr_req[0].dicnt0 = tr0_cnt0;
373262306a36Sopenharmony_ci	tr_req[0].dicnt1 = tr0_cnt1;
373362306a36Sopenharmony_ci	tr_req[0].dicnt2 = 1;
373462306a36Sopenharmony_ci	tr_req[0].dicnt3 = 1;
373562306a36Sopenharmony_ci	tr_req[0].ddim1 = tr0_cnt0;
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci	if (num_tr == 2) {
373862306a36Sopenharmony_ci		cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true,
373962306a36Sopenharmony_ci			      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
374062306a36Sopenharmony_ci		cppi5_tr_csf_set(&tr_req[1].flags, csf);
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ci		tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0;
374362306a36Sopenharmony_ci		tr_req[1].icnt0 = tr1_cnt0;
374462306a36Sopenharmony_ci		tr_req[1].icnt1 = 1;
374562306a36Sopenharmony_ci		tr_req[1].icnt2 = 1;
374662306a36Sopenharmony_ci		tr_req[1].icnt3 = 1;
374762306a36Sopenharmony_ci
374862306a36Sopenharmony_ci		tr_req[1].daddr = dest + tr0_cnt1 * tr0_cnt0;
374962306a36Sopenharmony_ci		tr_req[1].dicnt0 = tr1_cnt0;
375062306a36Sopenharmony_ci		tr_req[1].dicnt1 = 1;
375162306a36Sopenharmony_ci		tr_req[1].dicnt2 = 1;
375262306a36Sopenharmony_ci		tr_req[1].dicnt3 = 1;
375362306a36Sopenharmony_ci	}
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci	cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP);
375662306a36Sopenharmony_ci
375762306a36Sopenharmony_ci	if (uc->config.metadata_size)
375862306a36Sopenharmony_ci		d->vd.tx.metadata_ops = &metadata_ops;
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	return vchan_tx_prep(&uc->vc, &d->vd, tx_flags);
376162306a36Sopenharmony_ci}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_cistatic void udma_issue_pending(struct dma_chan *chan)
376462306a36Sopenharmony_ci{
376562306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
376662306a36Sopenharmony_ci	unsigned long flags;
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	spin_lock_irqsave(&uc->vc.lock, flags);
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	/* If we have something pending and no active descriptor, then */
377162306a36Sopenharmony_ci	if (vchan_issue_pending(&uc->vc) && !uc->desc) {
377262306a36Sopenharmony_ci		/*
377362306a36Sopenharmony_ci		 * start a descriptor if the channel is NOT [marked as
377462306a36Sopenharmony_ci		 * terminating _and_ it is still running (teardown has not
377562306a36Sopenharmony_ci		 * completed yet)].
377662306a36Sopenharmony_ci		 */
377762306a36Sopenharmony_ci		if (!(uc->state == UDMA_CHAN_IS_TERMINATING &&
377862306a36Sopenharmony_ci		      udma_is_chan_running(uc)))
377962306a36Sopenharmony_ci			udma_start(uc);
378062306a36Sopenharmony_ci	}
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci	spin_unlock_irqrestore(&uc->vc.lock, flags);
378362306a36Sopenharmony_ci}
378462306a36Sopenharmony_ci
378562306a36Sopenharmony_cistatic enum dma_status udma_tx_status(struct dma_chan *chan,
378662306a36Sopenharmony_ci				      dma_cookie_t cookie,
378762306a36Sopenharmony_ci				      struct dma_tx_state *txstate)
378862306a36Sopenharmony_ci{
378962306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
379062306a36Sopenharmony_ci	enum dma_status ret;
379162306a36Sopenharmony_ci	unsigned long flags;
379262306a36Sopenharmony_ci
379362306a36Sopenharmony_ci	spin_lock_irqsave(&uc->vc.lock, flags);
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	if (!udma_is_chan_running(uc))
379862306a36Sopenharmony_ci		ret = DMA_COMPLETE;
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci	if (ret == DMA_IN_PROGRESS && udma_is_chan_paused(uc))
380162306a36Sopenharmony_ci		ret = DMA_PAUSED;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	if (ret == DMA_COMPLETE || !txstate)
380462306a36Sopenharmony_ci		goto out;
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	if (uc->desc && uc->desc->vd.tx.cookie == cookie) {
380762306a36Sopenharmony_ci		u32 peer_bcnt = 0;
380862306a36Sopenharmony_ci		u32 bcnt = 0;
380962306a36Sopenharmony_ci		u32 residue = uc->desc->residue;
381062306a36Sopenharmony_ci		u32 delay = 0;
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci		if (uc->desc->dir == DMA_MEM_TO_DEV) {
381362306a36Sopenharmony_ci			bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG);
381462306a36Sopenharmony_ci
381562306a36Sopenharmony_ci			if (uc->config.ep_type != PSIL_EP_NATIVE) {
381662306a36Sopenharmony_ci				peer_bcnt = udma_tchanrt_read(uc,
381762306a36Sopenharmony_ci						UDMA_CHAN_RT_PEER_BCNT_REG);
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci				if (bcnt > peer_bcnt)
382062306a36Sopenharmony_ci					delay = bcnt - peer_bcnt;
382162306a36Sopenharmony_ci			}
382262306a36Sopenharmony_ci		} else if (uc->desc->dir == DMA_DEV_TO_MEM) {
382362306a36Sopenharmony_ci			bcnt = udma_rchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG);
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci			if (uc->config.ep_type != PSIL_EP_NATIVE) {
382662306a36Sopenharmony_ci				peer_bcnt = udma_rchanrt_read(uc,
382762306a36Sopenharmony_ci						UDMA_CHAN_RT_PEER_BCNT_REG);
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci				if (peer_bcnt > bcnt)
383062306a36Sopenharmony_ci					delay = peer_bcnt - bcnt;
383162306a36Sopenharmony_ci			}
383262306a36Sopenharmony_ci		} else {
383362306a36Sopenharmony_ci			bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG);
383462306a36Sopenharmony_ci		}
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci		if (bcnt && !(bcnt % uc->desc->residue))
383762306a36Sopenharmony_ci			residue = 0;
383862306a36Sopenharmony_ci		else
383962306a36Sopenharmony_ci			residue -= bcnt % uc->desc->residue;
384062306a36Sopenharmony_ci
384162306a36Sopenharmony_ci		if (!residue && (uc->config.dir == DMA_DEV_TO_MEM || !delay)) {
384262306a36Sopenharmony_ci			ret = DMA_COMPLETE;
384362306a36Sopenharmony_ci			delay = 0;
384462306a36Sopenharmony_ci		}
384562306a36Sopenharmony_ci
384662306a36Sopenharmony_ci		dma_set_residue(txstate, residue);
384762306a36Sopenharmony_ci		dma_set_in_flight_bytes(txstate, delay);
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_ci	} else {
385062306a36Sopenharmony_ci		ret = DMA_COMPLETE;
385162306a36Sopenharmony_ci	}
385262306a36Sopenharmony_ci
385362306a36Sopenharmony_ciout:
385462306a36Sopenharmony_ci	spin_unlock_irqrestore(&uc->vc.lock, flags);
385562306a36Sopenharmony_ci	return ret;
385662306a36Sopenharmony_ci}
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_cistatic int udma_pause(struct dma_chan *chan)
385962306a36Sopenharmony_ci{
386062306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	/* pause the channel */
386362306a36Sopenharmony_ci	switch (uc->config.dir) {
386462306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
386562306a36Sopenharmony_ci		udma_rchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
386662306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE,
386762306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE);
386862306a36Sopenharmony_ci		break;
386962306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
387062306a36Sopenharmony_ci		udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
387162306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE,
387262306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE);
387362306a36Sopenharmony_ci		break;
387462306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
387562306a36Sopenharmony_ci		udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_CTL_REG,
387662306a36Sopenharmony_ci					 UDMA_CHAN_RT_CTL_PAUSE,
387762306a36Sopenharmony_ci					 UDMA_CHAN_RT_CTL_PAUSE);
387862306a36Sopenharmony_ci		break;
387962306a36Sopenharmony_ci	default:
388062306a36Sopenharmony_ci		return -EINVAL;
388162306a36Sopenharmony_ci	}
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_ci	return 0;
388462306a36Sopenharmony_ci}
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_cistatic int udma_resume(struct dma_chan *chan)
388762306a36Sopenharmony_ci{
388862306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
388962306a36Sopenharmony_ci
389062306a36Sopenharmony_ci	/* resume the channel */
389162306a36Sopenharmony_ci	switch (uc->config.dir) {
389262306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
389362306a36Sopenharmony_ci		udma_rchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
389462306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE, 0);
389562306a36Sopenharmony_ci
389662306a36Sopenharmony_ci		break;
389762306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
389862306a36Sopenharmony_ci		udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG,
389962306a36Sopenharmony_ci					 UDMA_PEER_RT_EN_PAUSE, 0);
390062306a36Sopenharmony_ci		break;
390162306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
390262306a36Sopenharmony_ci		udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_CTL_REG,
390362306a36Sopenharmony_ci					 UDMA_CHAN_RT_CTL_PAUSE, 0);
390462306a36Sopenharmony_ci		break;
390562306a36Sopenharmony_ci	default:
390662306a36Sopenharmony_ci		return -EINVAL;
390762306a36Sopenharmony_ci	}
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	return 0;
391062306a36Sopenharmony_ci}
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_cistatic int udma_terminate_all(struct dma_chan *chan)
391362306a36Sopenharmony_ci{
391462306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
391562306a36Sopenharmony_ci	unsigned long flags;
391662306a36Sopenharmony_ci	LIST_HEAD(head);
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_ci	spin_lock_irqsave(&uc->vc.lock, flags);
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	if (udma_is_chan_running(uc))
392162306a36Sopenharmony_ci		udma_stop(uc);
392262306a36Sopenharmony_ci
392362306a36Sopenharmony_ci	if (uc->desc) {
392462306a36Sopenharmony_ci		uc->terminated_desc = uc->desc;
392562306a36Sopenharmony_ci		uc->desc = NULL;
392662306a36Sopenharmony_ci		uc->terminated_desc->terminated = true;
392762306a36Sopenharmony_ci		cancel_delayed_work(&uc->tx_drain.work);
392862306a36Sopenharmony_ci	}
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci	uc->paused = false;
393162306a36Sopenharmony_ci
393262306a36Sopenharmony_ci	vchan_get_all_descriptors(&uc->vc, &head);
393362306a36Sopenharmony_ci	spin_unlock_irqrestore(&uc->vc.lock, flags);
393462306a36Sopenharmony_ci	vchan_dma_desc_free_list(&uc->vc, &head);
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	return 0;
393762306a36Sopenharmony_ci}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_cistatic void udma_synchronize(struct dma_chan *chan)
394062306a36Sopenharmony_ci{
394162306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
394262306a36Sopenharmony_ci	unsigned long timeout = msecs_to_jiffies(1000);
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	vchan_synchronize(&uc->vc);
394562306a36Sopenharmony_ci
394662306a36Sopenharmony_ci	if (uc->state == UDMA_CHAN_IS_TERMINATING) {
394762306a36Sopenharmony_ci		timeout = wait_for_completion_timeout(&uc->teardown_completed,
394862306a36Sopenharmony_ci						      timeout);
394962306a36Sopenharmony_ci		if (!timeout) {
395062306a36Sopenharmony_ci			dev_warn(uc->ud->dev, "chan%d teardown timeout!\n",
395162306a36Sopenharmony_ci				 uc->id);
395262306a36Sopenharmony_ci			udma_dump_chan_stdata(uc);
395362306a36Sopenharmony_ci			udma_reset_chan(uc, true);
395462306a36Sopenharmony_ci		}
395562306a36Sopenharmony_ci	}
395662306a36Sopenharmony_ci
395762306a36Sopenharmony_ci	udma_reset_chan(uc, false);
395862306a36Sopenharmony_ci	if (udma_is_chan_running(uc))
395962306a36Sopenharmony_ci		dev_warn(uc->ud->dev, "chan%d refused to stop!\n", uc->id);
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	cancel_delayed_work_sync(&uc->tx_drain.work);
396262306a36Sopenharmony_ci	udma_reset_rings(uc);
396362306a36Sopenharmony_ci}
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_cistatic void udma_desc_pre_callback(struct virt_dma_chan *vc,
396662306a36Sopenharmony_ci				   struct virt_dma_desc *vd,
396762306a36Sopenharmony_ci				   struct dmaengine_result *result)
396862306a36Sopenharmony_ci{
396962306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(&vc->chan);
397062306a36Sopenharmony_ci	struct udma_desc *d;
397162306a36Sopenharmony_ci	u8 status;
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	if (!vd)
397462306a36Sopenharmony_ci		return;
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_ci	d = to_udma_desc(&vd->tx);
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	if (d->metadata_size)
397962306a36Sopenharmony_ci		udma_fetch_epib(uc, d);
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	if (result) {
398262306a36Sopenharmony_ci		void *desc_vaddr = udma_curr_cppi5_desc_vaddr(d, d->desc_idx);
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci		if (cppi5_desc_get_type(desc_vaddr) ==
398562306a36Sopenharmony_ci		    CPPI5_INFO0_DESC_TYPE_VAL_HOST) {
398662306a36Sopenharmony_ci			/* Provide residue information for the client */
398762306a36Sopenharmony_ci			result->residue = d->residue -
398862306a36Sopenharmony_ci					  cppi5_hdesc_get_pktlen(desc_vaddr);
398962306a36Sopenharmony_ci			if (result->residue)
399062306a36Sopenharmony_ci				result->result = DMA_TRANS_ABORTED;
399162306a36Sopenharmony_ci			else
399262306a36Sopenharmony_ci				result->result = DMA_TRANS_NOERROR;
399362306a36Sopenharmony_ci		} else {
399462306a36Sopenharmony_ci			result->residue = 0;
399562306a36Sopenharmony_ci			/* Propagate TR Response errors to the client */
399662306a36Sopenharmony_ci			status = d->hwdesc[0].tr_resp_base->status;
399762306a36Sopenharmony_ci			if (status)
399862306a36Sopenharmony_ci				result->result = DMA_TRANS_ABORTED;
399962306a36Sopenharmony_ci			else
400062306a36Sopenharmony_ci				result->result = DMA_TRANS_NOERROR;
400162306a36Sopenharmony_ci		}
400262306a36Sopenharmony_ci	}
400362306a36Sopenharmony_ci}
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci/*
400662306a36Sopenharmony_ci * This tasklet handles the completion of a DMA descriptor by
400762306a36Sopenharmony_ci * calling its callback and freeing it.
400862306a36Sopenharmony_ci */
400962306a36Sopenharmony_cistatic void udma_vchan_complete(struct tasklet_struct *t)
401062306a36Sopenharmony_ci{
401162306a36Sopenharmony_ci	struct virt_dma_chan *vc = from_tasklet(vc, t, task);
401262306a36Sopenharmony_ci	struct virt_dma_desc *vd, *_vd;
401362306a36Sopenharmony_ci	struct dmaengine_desc_callback cb;
401462306a36Sopenharmony_ci	LIST_HEAD(head);
401562306a36Sopenharmony_ci
401662306a36Sopenharmony_ci	spin_lock_irq(&vc->lock);
401762306a36Sopenharmony_ci	list_splice_tail_init(&vc->desc_completed, &head);
401862306a36Sopenharmony_ci	vd = vc->cyclic;
401962306a36Sopenharmony_ci	if (vd) {
402062306a36Sopenharmony_ci		vc->cyclic = NULL;
402162306a36Sopenharmony_ci		dmaengine_desc_get_callback(&vd->tx, &cb);
402262306a36Sopenharmony_ci	} else {
402362306a36Sopenharmony_ci		memset(&cb, 0, sizeof(cb));
402462306a36Sopenharmony_ci	}
402562306a36Sopenharmony_ci	spin_unlock_irq(&vc->lock);
402662306a36Sopenharmony_ci
402762306a36Sopenharmony_ci	udma_desc_pre_callback(vc, vd, NULL);
402862306a36Sopenharmony_ci	dmaengine_desc_callback_invoke(&cb, NULL);
402962306a36Sopenharmony_ci
403062306a36Sopenharmony_ci	list_for_each_entry_safe(vd, _vd, &head, node) {
403162306a36Sopenharmony_ci		struct dmaengine_result result;
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci		dmaengine_desc_get_callback(&vd->tx, &cb);
403462306a36Sopenharmony_ci
403562306a36Sopenharmony_ci		list_del(&vd->node);
403662306a36Sopenharmony_ci
403762306a36Sopenharmony_ci		udma_desc_pre_callback(vc, vd, &result);
403862306a36Sopenharmony_ci		dmaengine_desc_callback_invoke(&cb, &result);
403962306a36Sopenharmony_ci
404062306a36Sopenharmony_ci		vchan_vdesc_fini(vd);
404162306a36Sopenharmony_ci	}
404262306a36Sopenharmony_ci}
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_cistatic void udma_free_chan_resources(struct dma_chan *chan)
404562306a36Sopenharmony_ci{
404662306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
404762306a36Sopenharmony_ci	struct udma_dev *ud = to_udma_dev(chan->device);
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci	udma_terminate_all(chan);
405062306a36Sopenharmony_ci	if (uc->terminated_desc) {
405162306a36Sopenharmony_ci		udma_reset_chan(uc, false);
405262306a36Sopenharmony_ci		udma_reset_rings(uc);
405362306a36Sopenharmony_ci	}
405462306a36Sopenharmony_ci
405562306a36Sopenharmony_ci	cancel_delayed_work_sync(&uc->tx_drain.work);
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	if (uc->irq_num_ring > 0) {
405862306a36Sopenharmony_ci		free_irq(uc->irq_num_ring, uc);
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci		uc->irq_num_ring = 0;
406162306a36Sopenharmony_ci	}
406262306a36Sopenharmony_ci	if (uc->irq_num_udma > 0) {
406362306a36Sopenharmony_ci		free_irq(uc->irq_num_udma, uc);
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci		uc->irq_num_udma = 0;
406662306a36Sopenharmony_ci	}
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	/* Release PSI-L pairing */
406962306a36Sopenharmony_ci	if (uc->psil_paired) {
407062306a36Sopenharmony_ci		navss_psil_unpair(ud, uc->config.src_thread,
407162306a36Sopenharmony_ci				  uc->config.dst_thread);
407262306a36Sopenharmony_ci		uc->psil_paired = false;
407362306a36Sopenharmony_ci	}
407462306a36Sopenharmony_ci
407562306a36Sopenharmony_ci	vchan_free_chan_resources(&uc->vc);
407662306a36Sopenharmony_ci	tasklet_kill(&uc->vc.task);
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ci	bcdma_free_bchan_resources(uc);
407962306a36Sopenharmony_ci	udma_free_tx_resources(uc);
408062306a36Sopenharmony_ci	udma_free_rx_resources(uc);
408162306a36Sopenharmony_ci	udma_reset_uchan(uc);
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	if (uc->use_dma_pool) {
408462306a36Sopenharmony_ci		dma_pool_destroy(uc->hdesc_pool);
408562306a36Sopenharmony_ci		uc->use_dma_pool = false;
408662306a36Sopenharmony_ci	}
408762306a36Sopenharmony_ci}
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_cistatic struct platform_driver udma_driver;
409062306a36Sopenharmony_cistatic struct platform_driver bcdma_driver;
409162306a36Sopenharmony_cistatic struct platform_driver pktdma_driver;
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_cistruct udma_filter_param {
409462306a36Sopenharmony_ci	int remote_thread_id;
409562306a36Sopenharmony_ci	u32 atype;
409662306a36Sopenharmony_ci	u32 asel;
409762306a36Sopenharmony_ci	u32 tr_trigger_type;
409862306a36Sopenharmony_ci};
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_cistatic bool udma_dma_filter_fn(struct dma_chan *chan, void *param)
410162306a36Sopenharmony_ci{
410262306a36Sopenharmony_ci	struct udma_chan_config *ucc;
410362306a36Sopenharmony_ci	struct psil_endpoint_config *ep_config;
410462306a36Sopenharmony_ci	struct udma_filter_param *filter_param;
410562306a36Sopenharmony_ci	struct udma_chan *uc;
410662306a36Sopenharmony_ci	struct udma_dev *ud;
410762306a36Sopenharmony_ci
410862306a36Sopenharmony_ci	if (chan->device->dev->driver != &udma_driver.driver &&
410962306a36Sopenharmony_ci	    chan->device->dev->driver != &bcdma_driver.driver &&
411062306a36Sopenharmony_ci	    chan->device->dev->driver != &pktdma_driver.driver)
411162306a36Sopenharmony_ci		return false;
411262306a36Sopenharmony_ci
411362306a36Sopenharmony_ci	uc = to_udma_chan(chan);
411462306a36Sopenharmony_ci	ucc = &uc->config;
411562306a36Sopenharmony_ci	ud = uc->ud;
411662306a36Sopenharmony_ci	filter_param = param;
411762306a36Sopenharmony_ci
411862306a36Sopenharmony_ci	if (filter_param->atype > 2) {
411962306a36Sopenharmony_ci		dev_err(ud->dev, "Invalid channel atype: %u\n",
412062306a36Sopenharmony_ci			filter_param->atype);
412162306a36Sopenharmony_ci		return false;
412262306a36Sopenharmony_ci	}
412362306a36Sopenharmony_ci
412462306a36Sopenharmony_ci	if (filter_param->asel > 15) {
412562306a36Sopenharmony_ci		dev_err(ud->dev, "Invalid channel asel: %u\n",
412662306a36Sopenharmony_ci			filter_param->asel);
412762306a36Sopenharmony_ci		return false;
412862306a36Sopenharmony_ci	}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_ci	ucc->remote_thread_id = filter_param->remote_thread_id;
413162306a36Sopenharmony_ci	ucc->atype = filter_param->atype;
413262306a36Sopenharmony_ci	ucc->asel = filter_param->asel;
413362306a36Sopenharmony_ci	ucc->tr_trigger_type = filter_param->tr_trigger_type;
413462306a36Sopenharmony_ci
413562306a36Sopenharmony_ci	if (ucc->tr_trigger_type) {
413662306a36Sopenharmony_ci		ucc->dir = DMA_MEM_TO_MEM;
413762306a36Sopenharmony_ci		goto triggered_bchan;
413862306a36Sopenharmony_ci	} else if (ucc->remote_thread_id & K3_PSIL_DST_THREAD_ID_OFFSET) {
413962306a36Sopenharmony_ci		ucc->dir = DMA_MEM_TO_DEV;
414062306a36Sopenharmony_ci	} else {
414162306a36Sopenharmony_ci		ucc->dir = DMA_DEV_TO_MEM;
414262306a36Sopenharmony_ci	}
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_ci	ep_config = psil_get_ep_config(ucc->remote_thread_id);
414562306a36Sopenharmony_ci	if (IS_ERR(ep_config)) {
414662306a36Sopenharmony_ci		dev_err(ud->dev, "No configuration for psi-l thread 0x%04x\n",
414762306a36Sopenharmony_ci			ucc->remote_thread_id);
414862306a36Sopenharmony_ci		ucc->dir = DMA_MEM_TO_MEM;
414962306a36Sopenharmony_ci		ucc->remote_thread_id = -1;
415062306a36Sopenharmony_ci		ucc->atype = 0;
415162306a36Sopenharmony_ci		ucc->asel = 0;
415262306a36Sopenharmony_ci		return false;
415362306a36Sopenharmony_ci	}
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_BCDMA &&
415662306a36Sopenharmony_ci	    ep_config->pkt_mode) {
415762306a36Sopenharmony_ci		dev_err(ud->dev,
415862306a36Sopenharmony_ci			"Only TR mode is supported (psi-l thread 0x%04x)\n",
415962306a36Sopenharmony_ci			ucc->remote_thread_id);
416062306a36Sopenharmony_ci		ucc->dir = DMA_MEM_TO_MEM;
416162306a36Sopenharmony_ci		ucc->remote_thread_id = -1;
416262306a36Sopenharmony_ci		ucc->atype = 0;
416362306a36Sopenharmony_ci		ucc->asel = 0;
416462306a36Sopenharmony_ci		return false;
416562306a36Sopenharmony_ci	}
416662306a36Sopenharmony_ci
416762306a36Sopenharmony_ci	ucc->pkt_mode = ep_config->pkt_mode;
416862306a36Sopenharmony_ci	ucc->channel_tpl = ep_config->channel_tpl;
416962306a36Sopenharmony_ci	ucc->notdpkt = ep_config->notdpkt;
417062306a36Sopenharmony_ci	ucc->ep_type = ep_config->ep_type;
417162306a36Sopenharmony_ci
417262306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_PKTDMA &&
417362306a36Sopenharmony_ci	    ep_config->mapped_channel_id >= 0) {
417462306a36Sopenharmony_ci		ucc->mapped_channel_id = ep_config->mapped_channel_id;
417562306a36Sopenharmony_ci		ucc->default_flow_id = ep_config->default_flow_id;
417662306a36Sopenharmony_ci	} else {
417762306a36Sopenharmony_ci		ucc->mapped_channel_id = -1;
417862306a36Sopenharmony_ci		ucc->default_flow_id = -1;
417962306a36Sopenharmony_ci	}
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	if (ucc->ep_type != PSIL_EP_NATIVE) {
418262306a36Sopenharmony_ci		const struct udma_match_data *match_data = ud->match_data;
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ci		if (match_data->flags & UDMA_FLAG_PDMA_ACC32)
418562306a36Sopenharmony_ci			ucc->enable_acc32 = ep_config->pdma_acc32;
418662306a36Sopenharmony_ci		if (match_data->flags & UDMA_FLAG_PDMA_BURST)
418762306a36Sopenharmony_ci			ucc->enable_burst = ep_config->pdma_burst;
418862306a36Sopenharmony_ci	}
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci	ucc->needs_epib = ep_config->needs_epib;
419162306a36Sopenharmony_ci	ucc->psd_size = ep_config->psd_size;
419262306a36Sopenharmony_ci	ucc->metadata_size =
419362306a36Sopenharmony_ci			(ucc->needs_epib ? CPPI5_INFO0_HDESC_EPIB_SIZE : 0) +
419462306a36Sopenharmony_ci			ucc->psd_size;
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci	if (ucc->pkt_mode)
419762306a36Sopenharmony_ci		ucc->hdesc_size = ALIGN(sizeof(struct cppi5_host_desc_t) +
419862306a36Sopenharmony_ci				 ucc->metadata_size, ud->desc_align);
419962306a36Sopenharmony_ci
420062306a36Sopenharmony_ci	dev_dbg(ud->dev, "chan%d: Remote thread: 0x%04x (%s)\n", uc->id,
420162306a36Sopenharmony_ci		ucc->remote_thread_id, dmaengine_get_direction_text(ucc->dir));
420262306a36Sopenharmony_ci
420362306a36Sopenharmony_ci	return true;
420462306a36Sopenharmony_ci
420562306a36Sopenharmony_citriggered_bchan:
420662306a36Sopenharmony_ci	dev_dbg(ud->dev, "chan%d: triggered channel (type: %u)\n", uc->id,
420762306a36Sopenharmony_ci		ucc->tr_trigger_type);
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	return true;
421062306a36Sopenharmony_ci
421162306a36Sopenharmony_ci}
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_cistatic struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec,
421462306a36Sopenharmony_ci				      struct of_dma *ofdma)
421562306a36Sopenharmony_ci{
421662306a36Sopenharmony_ci	struct udma_dev *ud = ofdma->of_dma_data;
421762306a36Sopenharmony_ci	dma_cap_mask_t mask = ud->ddev.cap_mask;
421862306a36Sopenharmony_ci	struct udma_filter_param filter_param;
421962306a36Sopenharmony_ci	struct dma_chan *chan;
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_BCDMA) {
422262306a36Sopenharmony_ci		if (dma_spec->args_count != 3)
422362306a36Sopenharmony_ci			return NULL;
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_ci		filter_param.tr_trigger_type = dma_spec->args[0];
422662306a36Sopenharmony_ci		filter_param.remote_thread_id = dma_spec->args[1];
422762306a36Sopenharmony_ci		filter_param.asel = dma_spec->args[2];
422862306a36Sopenharmony_ci		filter_param.atype = 0;
422962306a36Sopenharmony_ci	} else {
423062306a36Sopenharmony_ci		if (dma_spec->args_count != 1 && dma_spec->args_count != 2)
423162306a36Sopenharmony_ci			return NULL;
423262306a36Sopenharmony_ci
423362306a36Sopenharmony_ci		filter_param.remote_thread_id = dma_spec->args[0];
423462306a36Sopenharmony_ci		filter_param.tr_trigger_type = 0;
423562306a36Sopenharmony_ci		if (dma_spec->args_count == 2) {
423662306a36Sopenharmony_ci			if (ud->match_data->type == DMA_TYPE_UDMA) {
423762306a36Sopenharmony_ci				filter_param.atype = dma_spec->args[1];
423862306a36Sopenharmony_ci				filter_param.asel = 0;
423962306a36Sopenharmony_ci			} else {
424062306a36Sopenharmony_ci				filter_param.atype = 0;
424162306a36Sopenharmony_ci				filter_param.asel = dma_spec->args[1];
424262306a36Sopenharmony_ci			}
424362306a36Sopenharmony_ci		} else {
424462306a36Sopenharmony_ci			filter_param.atype = 0;
424562306a36Sopenharmony_ci			filter_param.asel = 0;
424662306a36Sopenharmony_ci		}
424762306a36Sopenharmony_ci	}
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	chan = __dma_request_channel(&mask, udma_dma_filter_fn, &filter_param,
425062306a36Sopenharmony_ci				     ofdma->of_node);
425162306a36Sopenharmony_ci	if (!chan) {
425262306a36Sopenharmony_ci		dev_err(ud->dev, "get channel fail in %s.\n", __func__);
425362306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
425462306a36Sopenharmony_ci	}
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	return chan;
425762306a36Sopenharmony_ci}
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_cistatic struct udma_match_data am654_main_data = {
426062306a36Sopenharmony_ci	.type = DMA_TYPE_UDMA,
426162306a36Sopenharmony_ci	.psil_base = 0x1000,
426262306a36Sopenharmony_ci	.enable_memcpy_support = true,
426362306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(11, 0),
426462306a36Sopenharmony_ci	.burst_size = {
426562306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
426662306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* H Channels */
426762306a36Sopenharmony_ci		0, /* No UH Channels */
426862306a36Sopenharmony_ci	},
426962306a36Sopenharmony_ci};
427062306a36Sopenharmony_ci
427162306a36Sopenharmony_cistatic struct udma_match_data am654_mcu_data = {
427262306a36Sopenharmony_ci	.type = DMA_TYPE_UDMA,
427362306a36Sopenharmony_ci	.psil_base = 0x6000,
427462306a36Sopenharmony_ci	.enable_memcpy_support = false,
427562306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(11, 0),
427662306a36Sopenharmony_ci	.burst_size = {
427762306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
427862306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* H Channels */
427962306a36Sopenharmony_ci		0, /* No UH Channels */
428062306a36Sopenharmony_ci	},
428162306a36Sopenharmony_ci};
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_cistatic struct udma_match_data j721e_main_data = {
428462306a36Sopenharmony_ci	.type = DMA_TYPE_UDMA,
428562306a36Sopenharmony_ci	.psil_base = 0x1000,
428662306a36Sopenharmony_ci	.enable_memcpy_support = true,
428762306a36Sopenharmony_ci	.flags = UDMA_FLAGS_J7_CLASS,
428862306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(23, 0),
428962306a36Sopenharmony_ci	.burst_size = {
429062306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
429162306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES, /* H Channels */
429262306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES, /* UH Channels */
429362306a36Sopenharmony_ci	},
429462306a36Sopenharmony_ci};
429562306a36Sopenharmony_ci
429662306a36Sopenharmony_cistatic struct udma_match_data j721e_mcu_data = {
429762306a36Sopenharmony_ci	.type = DMA_TYPE_UDMA,
429862306a36Sopenharmony_ci	.psil_base = 0x6000,
429962306a36Sopenharmony_ci	.enable_memcpy_support = false, /* MEM_TO_MEM is slow via MCU UDMA */
430062306a36Sopenharmony_ci	.flags = UDMA_FLAGS_J7_CLASS,
430162306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(23, 0),
430262306a36Sopenharmony_ci	.burst_size = {
430362306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
430462306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES, /* H Channels */
430562306a36Sopenharmony_ci		0, /* No UH Channels */
430662306a36Sopenharmony_ci	},
430762306a36Sopenharmony_ci};
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_cistatic struct udma_soc_data am62a_dmss_csi_soc_data = {
431062306a36Sopenharmony_ci	.oes = {
431162306a36Sopenharmony_ci		.bcdma_rchan_data = 0xe00,
431262306a36Sopenharmony_ci		.bcdma_rchan_ring = 0x1000,
431362306a36Sopenharmony_ci	},
431462306a36Sopenharmony_ci};
431562306a36Sopenharmony_ci
431662306a36Sopenharmony_cistatic struct udma_soc_data j721s2_bcdma_csi_soc_data = {
431762306a36Sopenharmony_ci	.oes = {
431862306a36Sopenharmony_ci		.bcdma_tchan_data = 0x800,
431962306a36Sopenharmony_ci		.bcdma_tchan_ring = 0xa00,
432062306a36Sopenharmony_ci		.bcdma_rchan_data = 0xe00,
432162306a36Sopenharmony_ci		.bcdma_rchan_ring = 0x1000,
432262306a36Sopenharmony_ci	},
432362306a36Sopenharmony_ci};
432462306a36Sopenharmony_ci
432562306a36Sopenharmony_cistatic struct udma_match_data am62a_bcdma_csirx_data = {
432662306a36Sopenharmony_ci	.type = DMA_TYPE_BCDMA,
432762306a36Sopenharmony_ci	.psil_base = 0x3100,
432862306a36Sopenharmony_ci	.enable_memcpy_support = false,
432962306a36Sopenharmony_ci	.burst_size = {
433062306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
433162306a36Sopenharmony_ci		0, /* No H Channels */
433262306a36Sopenharmony_ci		0, /* No UH Channels */
433362306a36Sopenharmony_ci	},
433462306a36Sopenharmony_ci	.soc_data = &am62a_dmss_csi_soc_data,
433562306a36Sopenharmony_ci};
433662306a36Sopenharmony_ci
433762306a36Sopenharmony_cistatic struct udma_match_data am64_bcdma_data = {
433862306a36Sopenharmony_ci	.type = DMA_TYPE_BCDMA,
433962306a36Sopenharmony_ci	.psil_base = 0x2000, /* for tchan and rchan, not applicable to bchan */
434062306a36Sopenharmony_ci	.enable_memcpy_support = true, /* Supported via bchan */
434162306a36Sopenharmony_ci	.flags = UDMA_FLAGS_J7_CLASS,
434262306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(23, 0),
434362306a36Sopenharmony_ci	.burst_size = {
434462306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
434562306a36Sopenharmony_ci		0, /* No H Channels */
434662306a36Sopenharmony_ci		0, /* No UH Channels */
434762306a36Sopenharmony_ci	},
434862306a36Sopenharmony_ci};
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_cistatic struct udma_match_data am64_pktdma_data = {
435162306a36Sopenharmony_ci	.type = DMA_TYPE_PKTDMA,
435262306a36Sopenharmony_ci	.psil_base = 0x1000,
435362306a36Sopenharmony_ci	.enable_memcpy_support = false, /* PKTDMA does not support MEM_TO_MEM */
435462306a36Sopenharmony_ci	.flags = UDMA_FLAGS_J7_CLASS,
435562306a36Sopenharmony_ci	.statictr_z_mask = GENMASK(23, 0),
435662306a36Sopenharmony_ci	.burst_size = {
435762306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
435862306a36Sopenharmony_ci		0, /* No H Channels */
435962306a36Sopenharmony_ci		0, /* No UH Channels */
436062306a36Sopenharmony_ci	},
436162306a36Sopenharmony_ci};
436262306a36Sopenharmony_ci
436362306a36Sopenharmony_cistatic struct udma_match_data j721s2_bcdma_csi_data = {
436462306a36Sopenharmony_ci	.type = DMA_TYPE_BCDMA,
436562306a36Sopenharmony_ci	.psil_base = 0x2000,
436662306a36Sopenharmony_ci	.enable_memcpy_support = false,
436762306a36Sopenharmony_ci	.burst_size = {
436862306a36Sopenharmony_ci		TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */
436962306a36Sopenharmony_ci		0, /* No H Channels */
437062306a36Sopenharmony_ci		0, /* No UH Channels */
437162306a36Sopenharmony_ci	},
437262306a36Sopenharmony_ci	.soc_data = &j721s2_bcdma_csi_soc_data,
437362306a36Sopenharmony_ci};
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_cistatic const struct of_device_id udma_of_match[] = {
437662306a36Sopenharmony_ci	{
437762306a36Sopenharmony_ci		.compatible = "ti,am654-navss-main-udmap",
437862306a36Sopenharmony_ci		.data = &am654_main_data,
437962306a36Sopenharmony_ci	},
438062306a36Sopenharmony_ci	{
438162306a36Sopenharmony_ci		.compatible = "ti,am654-navss-mcu-udmap",
438262306a36Sopenharmony_ci		.data = &am654_mcu_data,
438362306a36Sopenharmony_ci	}, {
438462306a36Sopenharmony_ci		.compatible = "ti,j721e-navss-main-udmap",
438562306a36Sopenharmony_ci		.data = &j721e_main_data,
438662306a36Sopenharmony_ci	}, {
438762306a36Sopenharmony_ci		.compatible = "ti,j721e-navss-mcu-udmap",
438862306a36Sopenharmony_ci		.data = &j721e_mcu_data,
438962306a36Sopenharmony_ci	},
439062306a36Sopenharmony_ci	{
439162306a36Sopenharmony_ci		.compatible = "ti,am64-dmss-bcdma",
439262306a36Sopenharmony_ci		.data = &am64_bcdma_data,
439362306a36Sopenharmony_ci	},
439462306a36Sopenharmony_ci	{
439562306a36Sopenharmony_ci		.compatible = "ti,am64-dmss-pktdma",
439662306a36Sopenharmony_ci		.data = &am64_pktdma_data,
439762306a36Sopenharmony_ci	},
439862306a36Sopenharmony_ci	{
439962306a36Sopenharmony_ci		.compatible = "ti,am62a-dmss-bcdma-csirx",
440062306a36Sopenharmony_ci		.data = &am62a_bcdma_csirx_data,
440162306a36Sopenharmony_ci	},
440262306a36Sopenharmony_ci	{
440362306a36Sopenharmony_ci		.compatible = "ti,j721s2-dmss-bcdma-csi",
440462306a36Sopenharmony_ci		.data = &j721s2_bcdma_csi_data,
440562306a36Sopenharmony_ci	},
440662306a36Sopenharmony_ci	{ /* Sentinel */ },
440762306a36Sopenharmony_ci};
440862306a36Sopenharmony_ci
440962306a36Sopenharmony_cistatic struct udma_soc_data am654_soc_data = {
441062306a36Sopenharmony_ci	.oes = {
441162306a36Sopenharmony_ci		.udma_rchan = 0x200,
441262306a36Sopenharmony_ci	},
441362306a36Sopenharmony_ci};
441462306a36Sopenharmony_ci
441562306a36Sopenharmony_cistatic struct udma_soc_data j721e_soc_data = {
441662306a36Sopenharmony_ci	.oes = {
441762306a36Sopenharmony_ci		.udma_rchan = 0x400,
441862306a36Sopenharmony_ci	},
441962306a36Sopenharmony_ci};
442062306a36Sopenharmony_ci
442162306a36Sopenharmony_cistatic struct udma_soc_data j7200_soc_data = {
442262306a36Sopenharmony_ci	.oes = {
442362306a36Sopenharmony_ci		.udma_rchan = 0x80,
442462306a36Sopenharmony_ci	},
442562306a36Sopenharmony_ci};
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_cistatic struct udma_soc_data am64_soc_data = {
442862306a36Sopenharmony_ci	.oes = {
442962306a36Sopenharmony_ci		.bcdma_bchan_data = 0x2200,
443062306a36Sopenharmony_ci		.bcdma_bchan_ring = 0x2400,
443162306a36Sopenharmony_ci		.bcdma_tchan_data = 0x2800,
443262306a36Sopenharmony_ci		.bcdma_tchan_ring = 0x2a00,
443362306a36Sopenharmony_ci		.bcdma_rchan_data = 0x2e00,
443462306a36Sopenharmony_ci		.bcdma_rchan_ring = 0x3000,
443562306a36Sopenharmony_ci		.pktdma_tchan_flow = 0x1200,
443662306a36Sopenharmony_ci		.pktdma_rchan_flow = 0x1600,
443762306a36Sopenharmony_ci	},
443862306a36Sopenharmony_ci	.bcdma_trigger_event_offset = 0xc400,
443962306a36Sopenharmony_ci};
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_cistatic const struct soc_device_attribute k3_soc_devices[] = {
444262306a36Sopenharmony_ci	{ .family = "AM65X", .data = &am654_soc_data },
444362306a36Sopenharmony_ci	{ .family = "J721E", .data = &j721e_soc_data },
444462306a36Sopenharmony_ci	{ .family = "J7200", .data = &j7200_soc_data },
444562306a36Sopenharmony_ci	{ .family = "AM64X", .data = &am64_soc_data },
444662306a36Sopenharmony_ci	{ .family = "J721S2", .data = &j721e_soc_data},
444762306a36Sopenharmony_ci	{ .family = "AM62X", .data = &am64_soc_data },
444862306a36Sopenharmony_ci	{ .family = "AM62AX", .data = &am64_soc_data },
444962306a36Sopenharmony_ci	{ .family = "J784S4", .data = &j721e_soc_data },
445062306a36Sopenharmony_ci	{ /* sentinel */ }
445162306a36Sopenharmony_ci};
445262306a36Sopenharmony_ci
445362306a36Sopenharmony_cistatic int udma_get_mmrs(struct platform_device *pdev, struct udma_dev *ud)
445462306a36Sopenharmony_ci{
445562306a36Sopenharmony_ci	u32 cap2, cap3, cap4;
445662306a36Sopenharmony_ci	int i;
445762306a36Sopenharmony_ci
445862306a36Sopenharmony_ci	ud->mmrs[MMR_GCFG] = devm_platform_ioremap_resource_byname(pdev, mmr_names[MMR_GCFG]);
445962306a36Sopenharmony_ci	if (IS_ERR(ud->mmrs[MMR_GCFG]))
446062306a36Sopenharmony_ci		return PTR_ERR(ud->mmrs[MMR_GCFG]);
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_ci	cap2 = udma_read(ud->mmrs[MMR_GCFG], 0x28);
446362306a36Sopenharmony_ci	cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c);
446462306a36Sopenharmony_ci
446562306a36Sopenharmony_ci	switch (ud->match_data->type) {
446662306a36Sopenharmony_ci	case DMA_TYPE_UDMA:
446762306a36Sopenharmony_ci		ud->rflow_cnt = UDMA_CAP3_RFLOW_CNT(cap3);
446862306a36Sopenharmony_ci		ud->tchan_cnt = UDMA_CAP2_TCHAN_CNT(cap2);
446962306a36Sopenharmony_ci		ud->echan_cnt = UDMA_CAP2_ECHAN_CNT(cap2);
447062306a36Sopenharmony_ci		ud->rchan_cnt = UDMA_CAP2_RCHAN_CNT(cap2);
447162306a36Sopenharmony_ci		break;
447262306a36Sopenharmony_ci	case DMA_TYPE_BCDMA:
447362306a36Sopenharmony_ci		ud->bchan_cnt = BCDMA_CAP2_BCHAN_CNT(cap2);
447462306a36Sopenharmony_ci		ud->tchan_cnt = BCDMA_CAP2_TCHAN_CNT(cap2);
447562306a36Sopenharmony_ci		ud->rchan_cnt = BCDMA_CAP2_RCHAN_CNT(cap2);
447662306a36Sopenharmony_ci		ud->rflow_cnt = ud->rchan_cnt;
447762306a36Sopenharmony_ci		break;
447862306a36Sopenharmony_ci	case DMA_TYPE_PKTDMA:
447962306a36Sopenharmony_ci		cap4 = udma_read(ud->mmrs[MMR_GCFG], 0x30);
448062306a36Sopenharmony_ci		ud->tchan_cnt = UDMA_CAP2_TCHAN_CNT(cap2);
448162306a36Sopenharmony_ci		ud->rchan_cnt = UDMA_CAP2_RCHAN_CNT(cap2);
448262306a36Sopenharmony_ci		ud->rflow_cnt = UDMA_CAP3_RFLOW_CNT(cap3);
448362306a36Sopenharmony_ci		ud->tflow_cnt = PKTDMA_CAP4_TFLOW_CNT(cap4);
448462306a36Sopenharmony_ci		break;
448562306a36Sopenharmony_ci	default:
448662306a36Sopenharmony_ci		return -EINVAL;
448762306a36Sopenharmony_ci	}
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	for (i = 1; i < MMR_LAST; i++) {
449062306a36Sopenharmony_ci		if (i == MMR_BCHANRT && ud->bchan_cnt == 0)
449162306a36Sopenharmony_ci			continue;
449262306a36Sopenharmony_ci		if (i == MMR_TCHANRT && ud->tchan_cnt == 0)
449362306a36Sopenharmony_ci			continue;
449462306a36Sopenharmony_ci		if (i == MMR_RCHANRT && ud->rchan_cnt == 0)
449562306a36Sopenharmony_ci			continue;
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci		ud->mmrs[i] = devm_platform_ioremap_resource_byname(pdev, mmr_names[i]);
449862306a36Sopenharmony_ci		if (IS_ERR(ud->mmrs[i]))
449962306a36Sopenharmony_ci			return PTR_ERR(ud->mmrs[i]);
450062306a36Sopenharmony_ci	}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci	return 0;
450362306a36Sopenharmony_ci}
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_cistatic void udma_mark_resource_ranges(struct udma_dev *ud, unsigned long *map,
450662306a36Sopenharmony_ci				      struct ti_sci_resource_desc *rm_desc,
450762306a36Sopenharmony_ci				      char *name)
450862306a36Sopenharmony_ci{
450962306a36Sopenharmony_ci	bitmap_clear(map, rm_desc->start, rm_desc->num);
451062306a36Sopenharmony_ci	bitmap_clear(map, rm_desc->start_sec, rm_desc->num_sec);
451162306a36Sopenharmony_ci	dev_dbg(ud->dev, "ti_sci resource range for %s: %d:%d | %d:%d\n", name,
451262306a36Sopenharmony_ci		rm_desc->start, rm_desc->num, rm_desc->start_sec,
451362306a36Sopenharmony_ci		rm_desc->num_sec);
451462306a36Sopenharmony_ci}
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_cistatic const char * const range_names[] = {
451762306a36Sopenharmony_ci	[RM_RANGE_BCHAN] = "ti,sci-rm-range-bchan",
451862306a36Sopenharmony_ci	[RM_RANGE_TCHAN] = "ti,sci-rm-range-tchan",
451962306a36Sopenharmony_ci	[RM_RANGE_RCHAN] = "ti,sci-rm-range-rchan",
452062306a36Sopenharmony_ci	[RM_RANGE_RFLOW] = "ti,sci-rm-range-rflow",
452162306a36Sopenharmony_ci	[RM_RANGE_TFLOW] = "ti,sci-rm-range-tflow",
452262306a36Sopenharmony_ci};
452362306a36Sopenharmony_ci
452462306a36Sopenharmony_cistatic int udma_setup_resources(struct udma_dev *ud)
452562306a36Sopenharmony_ci{
452662306a36Sopenharmony_ci	int ret, i, j;
452762306a36Sopenharmony_ci	struct device *dev = ud->dev;
452862306a36Sopenharmony_ci	struct ti_sci_resource *rm_res, irq_res;
452962306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
453062306a36Sopenharmony_ci	u32 cap3;
453162306a36Sopenharmony_ci
453262306a36Sopenharmony_ci	/* Set up the throughput level start indexes */
453362306a36Sopenharmony_ci	cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c);
453462306a36Sopenharmony_ci	if (of_device_is_compatible(dev->of_node,
453562306a36Sopenharmony_ci				    "ti,am654-navss-main-udmap")) {
453662306a36Sopenharmony_ci		ud->tchan_tpl.levels = 2;
453762306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = 8;
453862306a36Sopenharmony_ci	} else if (of_device_is_compatible(dev->of_node,
453962306a36Sopenharmony_ci					   "ti,am654-navss-mcu-udmap")) {
454062306a36Sopenharmony_ci		ud->tchan_tpl.levels = 2;
454162306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = 2;
454262306a36Sopenharmony_ci	} else if (UDMA_CAP3_UCHAN_CNT(cap3)) {
454362306a36Sopenharmony_ci		ud->tchan_tpl.levels = 3;
454462306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[1] = UDMA_CAP3_UCHAN_CNT(cap3);
454562306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3);
454662306a36Sopenharmony_ci	} else if (UDMA_CAP3_HCHAN_CNT(cap3)) {
454762306a36Sopenharmony_ci		ud->tchan_tpl.levels = 2;
454862306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3);
454962306a36Sopenharmony_ci	} else {
455062306a36Sopenharmony_ci		ud->tchan_tpl.levels = 1;
455162306a36Sopenharmony_ci	}
455262306a36Sopenharmony_ci
455362306a36Sopenharmony_ci	ud->rchan_tpl.levels = ud->tchan_tpl.levels;
455462306a36Sopenharmony_ci	ud->rchan_tpl.start_idx[0] = ud->tchan_tpl.start_idx[0];
455562306a36Sopenharmony_ci	ud->rchan_tpl.start_idx[1] = ud->tchan_tpl.start_idx[1];
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_ci	ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt),
455862306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
455962306a36Sopenharmony_ci	ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans),
456062306a36Sopenharmony_ci				  GFP_KERNEL);
456162306a36Sopenharmony_ci	ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt),
456262306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
456362306a36Sopenharmony_ci	ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans),
456462306a36Sopenharmony_ci				  GFP_KERNEL);
456562306a36Sopenharmony_ci	ud->rflow_gp_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rflow_cnt),
456662306a36Sopenharmony_ci					      sizeof(unsigned long),
456762306a36Sopenharmony_ci					      GFP_KERNEL);
456862306a36Sopenharmony_ci	ud->rflow_gp_map_allocated = devm_kcalloc(dev,
456962306a36Sopenharmony_ci						  BITS_TO_LONGS(ud->rflow_cnt),
457062306a36Sopenharmony_ci						  sizeof(unsigned long),
457162306a36Sopenharmony_ci						  GFP_KERNEL);
457262306a36Sopenharmony_ci	ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rflow_cnt),
457362306a36Sopenharmony_ci					sizeof(unsigned long),
457462306a36Sopenharmony_ci					GFP_KERNEL);
457562306a36Sopenharmony_ci	ud->rflows = devm_kcalloc(dev, ud->rflow_cnt, sizeof(*ud->rflows),
457662306a36Sopenharmony_ci				  GFP_KERNEL);
457762306a36Sopenharmony_ci
457862306a36Sopenharmony_ci	if (!ud->tchan_map || !ud->rchan_map || !ud->rflow_gp_map ||
457962306a36Sopenharmony_ci	    !ud->rflow_gp_map_allocated || !ud->tchans || !ud->rchans ||
458062306a36Sopenharmony_ci	    !ud->rflows || !ud->rflow_in_use)
458162306a36Sopenharmony_ci		return -ENOMEM;
458262306a36Sopenharmony_ci
458362306a36Sopenharmony_ci	/*
458462306a36Sopenharmony_ci	 * RX flows with the same Ids as RX channels are reserved to be used
458562306a36Sopenharmony_ci	 * as default flows if remote HW can't generate flow_ids. Those
458662306a36Sopenharmony_ci	 * RX flows can be requested only explicitly by id.
458762306a36Sopenharmony_ci	 */
458862306a36Sopenharmony_ci	bitmap_set(ud->rflow_gp_map_allocated, 0, ud->rchan_cnt);
458962306a36Sopenharmony_ci
459062306a36Sopenharmony_ci	/* by default no GP rflows are assigned to Linux */
459162306a36Sopenharmony_ci	bitmap_set(ud->rflow_gp_map, 0, ud->rflow_cnt);
459262306a36Sopenharmony_ci
459362306a36Sopenharmony_ci	/* Get resource ranges from tisci */
459462306a36Sopenharmony_ci	for (i = 0; i < RM_RANGE_LAST; i++) {
459562306a36Sopenharmony_ci		if (i == RM_RANGE_BCHAN || i == RM_RANGE_TFLOW)
459662306a36Sopenharmony_ci			continue;
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci		tisci_rm->rm_ranges[i] =
459962306a36Sopenharmony_ci			devm_ti_sci_get_of_resource(tisci_rm->tisci, dev,
460062306a36Sopenharmony_ci						    tisci_rm->tisci_dev_id,
460162306a36Sopenharmony_ci						    (char *)range_names[i]);
460262306a36Sopenharmony_ci	}
460362306a36Sopenharmony_ci
460462306a36Sopenharmony_ci	/* tchan ranges */
460562306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
460662306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
460762306a36Sopenharmony_ci		bitmap_zero(ud->tchan_map, ud->tchan_cnt);
460862306a36Sopenharmony_ci		irq_res.sets = 1;
460962306a36Sopenharmony_ci	} else {
461062306a36Sopenharmony_ci		bitmap_fill(ud->tchan_map, ud->tchan_cnt);
461162306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
461262306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->tchan_map,
461362306a36Sopenharmony_ci						  &rm_res->desc[i], "tchan");
461462306a36Sopenharmony_ci		irq_res.sets = rm_res->sets;
461562306a36Sopenharmony_ci	}
461662306a36Sopenharmony_ci
461762306a36Sopenharmony_ci	/* rchan and matching default flow ranges */
461862306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
461962306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
462062306a36Sopenharmony_ci		bitmap_zero(ud->rchan_map, ud->rchan_cnt);
462162306a36Sopenharmony_ci		irq_res.sets++;
462262306a36Sopenharmony_ci	} else {
462362306a36Sopenharmony_ci		bitmap_fill(ud->rchan_map, ud->rchan_cnt);
462462306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
462562306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->rchan_map,
462662306a36Sopenharmony_ci						  &rm_res->desc[i], "rchan");
462762306a36Sopenharmony_ci		irq_res.sets += rm_res->sets;
462862306a36Sopenharmony_ci	}
462962306a36Sopenharmony_ci
463062306a36Sopenharmony_ci	irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
463162306a36Sopenharmony_ci	if (!irq_res.desc)
463262306a36Sopenharmony_ci		return -ENOMEM;
463362306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
463462306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
463562306a36Sopenharmony_ci		irq_res.desc[0].start = 0;
463662306a36Sopenharmony_ci		irq_res.desc[0].num = ud->tchan_cnt;
463762306a36Sopenharmony_ci		i = 1;
463862306a36Sopenharmony_ci	} else {
463962306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++) {
464062306a36Sopenharmony_ci			irq_res.desc[i].start = rm_res->desc[i].start;
464162306a36Sopenharmony_ci			irq_res.desc[i].num = rm_res->desc[i].num;
464262306a36Sopenharmony_ci			irq_res.desc[i].start_sec = rm_res->desc[i].start_sec;
464362306a36Sopenharmony_ci			irq_res.desc[i].num_sec = rm_res->desc[i].num_sec;
464462306a36Sopenharmony_ci		}
464562306a36Sopenharmony_ci	}
464662306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
464762306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
464862306a36Sopenharmony_ci		irq_res.desc[i].start = 0;
464962306a36Sopenharmony_ci		irq_res.desc[i].num = ud->rchan_cnt;
465062306a36Sopenharmony_ci	} else {
465162306a36Sopenharmony_ci		for (j = 0; j < rm_res->sets; j++, i++) {
465262306a36Sopenharmony_ci			if (rm_res->desc[j].num) {
465362306a36Sopenharmony_ci				irq_res.desc[i].start = rm_res->desc[j].start +
465462306a36Sopenharmony_ci						ud->soc_data->oes.udma_rchan;
465562306a36Sopenharmony_ci				irq_res.desc[i].num = rm_res->desc[j].num;
465662306a36Sopenharmony_ci			}
465762306a36Sopenharmony_ci			if (rm_res->desc[j].num_sec) {
465862306a36Sopenharmony_ci				irq_res.desc[i].start_sec = rm_res->desc[j].start_sec +
465962306a36Sopenharmony_ci						ud->soc_data->oes.udma_rchan;
466062306a36Sopenharmony_ci				irq_res.desc[i].num_sec = rm_res->desc[j].num_sec;
466162306a36Sopenharmony_ci			}
466262306a36Sopenharmony_ci		}
466362306a36Sopenharmony_ci	}
466462306a36Sopenharmony_ci	ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
466562306a36Sopenharmony_ci	kfree(irq_res.desc);
466662306a36Sopenharmony_ci	if (ret) {
466762306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to allocate MSI interrupts\n");
466862306a36Sopenharmony_ci		return ret;
466962306a36Sopenharmony_ci	}
467062306a36Sopenharmony_ci
467162306a36Sopenharmony_ci	/* GP rflow ranges */
467262306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW];
467362306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
467462306a36Sopenharmony_ci		/* all gp flows are assigned exclusively to Linux */
467562306a36Sopenharmony_ci		bitmap_clear(ud->rflow_gp_map, ud->rchan_cnt,
467662306a36Sopenharmony_ci			     ud->rflow_cnt - ud->rchan_cnt);
467762306a36Sopenharmony_ci	} else {
467862306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
467962306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->rflow_gp_map,
468062306a36Sopenharmony_ci						  &rm_res->desc[i], "gp-rflow");
468162306a36Sopenharmony_ci	}
468262306a36Sopenharmony_ci
468362306a36Sopenharmony_ci	return 0;
468462306a36Sopenharmony_ci}
468562306a36Sopenharmony_ci
468662306a36Sopenharmony_cistatic int bcdma_setup_resources(struct udma_dev *ud)
468762306a36Sopenharmony_ci{
468862306a36Sopenharmony_ci	int ret, i, j;
468962306a36Sopenharmony_ci	struct device *dev = ud->dev;
469062306a36Sopenharmony_ci	struct ti_sci_resource *rm_res, irq_res;
469162306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
469262306a36Sopenharmony_ci	const struct udma_oes_offsets *oes = &ud->soc_data->oes;
469362306a36Sopenharmony_ci	u32 cap;
469462306a36Sopenharmony_ci
469562306a36Sopenharmony_ci	/* Set up the throughput level start indexes */
469662306a36Sopenharmony_ci	cap = udma_read(ud->mmrs[MMR_GCFG], 0x2c);
469762306a36Sopenharmony_ci	if (BCDMA_CAP3_UBCHAN_CNT(cap)) {
469862306a36Sopenharmony_ci		ud->bchan_tpl.levels = 3;
469962306a36Sopenharmony_ci		ud->bchan_tpl.start_idx[1] = BCDMA_CAP3_UBCHAN_CNT(cap);
470062306a36Sopenharmony_ci		ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap);
470162306a36Sopenharmony_ci	} else if (BCDMA_CAP3_HBCHAN_CNT(cap)) {
470262306a36Sopenharmony_ci		ud->bchan_tpl.levels = 2;
470362306a36Sopenharmony_ci		ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap);
470462306a36Sopenharmony_ci	} else {
470562306a36Sopenharmony_ci		ud->bchan_tpl.levels = 1;
470662306a36Sopenharmony_ci	}
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci	cap = udma_read(ud->mmrs[MMR_GCFG], 0x30);
470962306a36Sopenharmony_ci	if (BCDMA_CAP4_URCHAN_CNT(cap)) {
471062306a36Sopenharmony_ci		ud->rchan_tpl.levels = 3;
471162306a36Sopenharmony_ci		ud->rchan_tpl.start_idx[1] = BCDMA_CAP4_URCHAN_CNT(cap);
471262306a36Sopenharmony_ci		ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap);
471362306a36Sopenharmony_ci	} else if (BCDMA_CAP4_HRCHAN_CNT(cap)) {
471462306a36Sopenharmony_ci		ud->rchan_tpl.levels = 2;
471562306a36Sopenharmony_ci		ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap);
471662306a36Sopenharmony_ci	} else {
471762306a36Sopenharmony_ci		ud->rchan_tpl.levels = 1;
471862306a36Sopenharmony_ci	}
471962306a36Sopenharmony_ci
472062306a36Sopenharmony_ci	if (BCDMA_CAP4_UTCHAN_CNT(cap)) {
472162306a36Sopenharmony_ci		ud->tchan_tpl.levels = 3;
472262306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[1] = BCDMA_CAP4_UTCHAN_CNT(cap);
472362306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap);
472462306a36Sopenharmony_ci	} else if (BCDMA_CAP4_HTCHAN_CNT(cap)) {
472562306a36Sopenharmony_ci		ud->tchan_tpl.levels = 2;
472662306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap);
472762306a36Sopenharmony_ci	} else {
472862306a36Sopenharmony_ci		ud->tchan_tpl.levels = 1;
472962306a36Sopenharmony_ci	}
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci	ud->bchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->bchan_cnt),
473262306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
473362306a36Sopenharmony_ci	ud->bchans = devm_kcalloc(dev, ud->bchan_cnt, sizeof(*ud->bchans),
473462306a36Sopenharmony_ci				  GFP_KERNEL);
473562306a36Sopenharmony_ci	ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt),
473662306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
473762306a36Sopenharmony_ci	ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans),
473862306a36Sopenharmony_ci				  GFP_KERNEL);
473962306a36Sopenharmony_ci	ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt),
474062306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
474162306a36Sopenharmony_ci	ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans),
474262306a36Sopenharmony_ci				  GFP_KERNEL);
474362306a36Sopenharmony_ci	/* BCDMA do not really have flows, but the driver expect it */
474462306a36Sopenharmony_ci	ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rchan_cnt),
474562306a36Sopenharmony_ci					sizeof(unsigned long),
474662306a36Sopenharmony_ci					GFP_KERNEL);
474762306a36Sopenharmony_ci	ud->rflows = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rflows),
474862306a36Sopenharmony_ci				  GFP_KERNEL);
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	if (!ud->bchan_map || !ud->tchan_map || !ud->rchan_map ||
475162306a36Sopenharmony_ci	    !ud->rflow_in_use || !ud->bchans || !ud->tchans || !ud->rchans ||
475262306a36Sopenharmony_ci	    !ud->rflows)
475362306a36Sopenharmony_ci		return -ENOMEM;
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci	/* Get resource ranges from tisci */
475662306a36Sopenharmony_ci	for (i = 0; i < RM_RANGE_LAST; i++) {
475762306a36Sopenharmony_ci		if (i == RM_RANGE_RFLOW || i == RM_RANGE_TFLOW)
475862306a36Sopenharmony_ci			continue;
475962306a36Sopenharmony_ci		if (i == RM_RANGE_BCHAN && ud->bchan_cnt == 0)
476062306a36Sopenharmony_ci			continue;
476162306a36Sopenharmony_ci		if (i == RM_RANGE_TCHAN && ud->tchan_cnt == 0)
476262306a36Sopenharmony_ci			continue;
476362306a36Sopenharmony_ci		if (i == RM_RANGE_RCHAN && ud->rchan_cnt == 0)
476462306a36Sopenharmony_ci			continue;
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci		tisci_rm->rm_ranges[i] =
476762306a36Sopenharmony_ci			devm_ti_sci_get_of_resource(tisci_rm->tisci, dev,
476862306a36Sopenharmony_ci						    tisci_rm->tisci_dev_id,
476962306a36Sopenharmony_ci						    (char *)range_names[i]);
477062306a36Sopenharmony_ci	}
477162306a36Sopenharmony_ci
477262306a36Sopenharmony_ci	irq_res.sets = 0;
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci	/* bchan ranges */
477562306a36Sopenharmony_ci	if (ud->bchan_cnt) {
477662306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
477762306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
477862306a36Sopenharmony_ci			bitmap_zero(ud->bchan_map, ud->bchan_cnt);
477962306a36Sopenharmony_ci			irq_res.sets++;
478062306a36Sopenharmony_ci		} else {
478162306a36Sopenharmony_ci			bitmap_fill(ud->bchan_map, ud->bchan_cnt);
478262306a36Sopenharmony_ci			for (i = 0; i < rm_res->sets; i++)
478362306a36Sopenharmony_ci				udma_mark_resource_ranges(ud, ud->bchan_map,
478462306a36Sopenharmony_ci							  &rm_res->desc[i],
478562306a36Sopenharmony_ci							  "bchan");
478662306a36Sopenharmony_ci			irq_res.sets += rm_res->sets;
478762306a36Sopenharmony_ci		}
478862306a36Sopenharmony_ci	}
478962306a36Sopenharmony_ci
479062306a36Sopenharmony_ci	/* tchan ranges */
479162306a36Sopenharmony_ci	if (ud->tchan_cnt) {
479262306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
479362306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
479462306a36Sopenharmony_ci			bitmap_zero(ud->tchan_map, ud->tchan_cnt);
479562306a36Sopenharmony_ci			irq_res.sets += 2;
479662306a36Sopenharmony_ci		} else {
479762306a36Sopenharmony_ci			bitmap_fill(ud->tchan_map, ud->tchan_cnt);
479862306a36Sopenharmony_ci			for (i = 0; i < rm_res->sets; i++)
479962306a36Sopenharmony_ci				udma_mark_resource_ranges(ud, ud->tchan_map,
480062306a36Sopenharmony_ci							  &rm_res->desc[i],
480162306a36Sopenharmony_ci							  "tchan");
480262306a36Sopenharmony_ci			irq_res.sets += rm_res->sets * 2;
480362306a36Sopenharmony_ci		}
480462306a36Sopenharmony_ci	}
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	/* rchan ranges */
480762306a36Sopenharmony_ci	if (ud->rchan_cnt) {
480862306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
480962306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
481062306a36Sopenharmony_ci			bitmap_zero(ud->rchan_map, ud->rchan_cnt);
481162306a36Sopenharmony_ci			irq_res.sets += 2;
481262306a36Sopenharmony_ci		} else {
481362306a36Sopenharmony_ci			bitmap_fill(ud->rchan_map, ud->rchan_cnt);
481462306a36Sopenharmony_ci			for (i = 0; i < rm_res->sets; i++)
481562306a36Sopenharmony_ci				udma_mark_resource_ranges(ud, ud->rchan_map,
481662306a36Sopenharmony_ci							  &rm_res->desc[i],
481762306a36Sopenharmony_ci							  "rchan");
481862306a36Sopenharmony_ci			irq_res.sets += rm_res->sets * 2;
481962306a36Sopenharmony_ci		}
482062306a36Sopenharmony_ci	}
482162306a36Sopenharmony_ci
482262306a36Sopenharmony_ci	irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
482362306a36Sopenharmony_ci	if (!irq_res.desc)
482462306a36Sopenharmony_ci		return -ENOMEM;
482562306a36Sopenharmony_ci	if (ud->bchan_cnt) {
482662306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN];
482762306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
482862306a36Sopenharmony_ci			irq_res.desc[0].start = oes->bcdma_bchan_ring;
482962306a36Sopenharmony_ci			irq_res.desc[0].num = ud->bchan_cnt;
483062306a36Sopenharmony_ci			i = 1;
483162306a36Sopenharmony_ci		} else {
483262306a36Sopenharmony_ci			for (i = 0; i < rm_res->sets; i++) {
483362306a36Sopenharmony_ci				irq_res.desc[i].start = rm_res->desc[i].start +
483462306a36Sopenharmony_ci							oes->bcdma_bchan_ring;
483562306a36Sopenharmony_ci				irq_res.desc[i].num = rm_res->desc[i].num;
483662306a36Sopenharmony_ci			}
483762306a36Sopenharmony_ci		}
483862306a36Sopenharmony_ci	} else {
483962306a36Sopenharmony_ci		i = 0;
484062306a36Sopenharmony_ci	}
484162306a36Sopenharmony_ci
484262306a36Sopenharmony_ci	if (ud->tchan_cnt) {
484362306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
484462306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
484562306a36Sopenharmony_ci			irq_res.desc[i].start = oes->bcdma_tchan_data;
484662306a36Sopenharmony_ci			irq_res.desc[i].num = ud->tchan_cnt;
484762306a36Sopenharmony_ci			irq_res.desc[i + 1].start = oes->bcdma_tchan_ring;
484862306a36Sopenharmony_ci			irq_res.desc[i + 1].num = ud->tchan_cnt;
484962306a36Sopenharmony_ci			i += 2;
485062306a36Sopenharmony_ci		} else {
485162306a36Sopenharmony_ci			for (j = 0; j < rm_res->sets; j++, i += 2) {
485262306a36Sopenharmony_ci				irq_res.desc[i].start = rm_res->desc[j].start +
485362306a36Sopenharmony_ci							oes->bcdma_tchan_data;
485462306a36Sopenharmony_ci				irq_res.desc[i].num = rm_res->desc[j].num;
485562306a36Sopenharmony_ci
485662306a36Sopenharmony_ci				irq_res.desc[i + 1].start = rm_res->desc[j].start +
485762306a36Sopenharmony_ci							oes->bcdma_tchan_ring;
485862306a36Sopenharmony_ci				irq_res.desc[i + 1].num = rm_res->desc[j].num;
485962306a36Sopenharmony_ci			}
486062306a36Sopenharmony_ci		}
486162306a36Sopenharmony_ci	}
486262306a36Sopenharmony_ci	if (ud->rchan_cnt) {
486362306a36Sopenharmony_ci		rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
486462306a36Sopenharmony_ci		if (IS_ERR(rm_res)) {
486562306a36Sopenharmony_ci			irq_res.desc[i].start = oes->bcdma_rchan_data;
486662306a36Sopenharmony_ci			irq_res.desc[i].num = ud->rchan_cnt;
486762306a36Sopenharmony_ci			irq_res.desc[i + 1].start = oes->bcdma_rchan_ring;
486862306a36Sopenharmony_ci			irq_res.desc[i + 1].num = ud->rchan_cnt;
486962306a36Sopenharmony_ci			i += 2;
487062306a36Sopenharmony_ci		} else {
487162306a36Sopenharmony_ci			for (j = 0; j < rm_res->sets; j++, i += 2) {
487262306a36Sopenharmony_ci				irq_res.desc[i].start = rm_res->desc[j].start +
487362306a36Sopenharmony_ci							oes->bcdma_rchan_data;
487462306a36Sopenharmony_ci				irq_res.desc[i].num = rm_res->desc[j].num;
487562306a36Sopenharmony_ci
487662306a36Sopenharmony_ci				irq_res.desc[i + 1].start = rm_res->desc[j].start +
487762306a36Sopenharmony_ci							oes->bcdma_rchan_ring;
487862306a36Sopenharmony_ci				irq_res.desc[i + 1].num = rm_res->desc[j].num;
487962306a36Sopenharmony_ci			}
488062306a36Sopenharmony_ci		}
488162306a36Sopenharmony_ci	}
488262306a36Sopenharmony_ci
488362306a36Sopenharmony_ci	ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
488462306a36Sopenharmony_ci	kfree(irq_res.desc);
488562306a36Sopenharmony_ci	if (ret) {
488662306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to allocate MSI interrupts\n");
488762306a36Sopenharmony_ci		return ret;
488862306a36Sopenharmony_ci	}
488962306a36Sopenharmony_ci
489062306a36Sopenharmony_ci	return 0;
489162306a36Sopenharmony_ci}
489262306a36Sopenharmony_ci
489362306a36Sopenharmony_cistatic int pktdma_setup_resources(struct udma_dev *ud)
489462306a36Sopenharmony_ci{
489562306a36Sopenharmony_ci	int ret, i, j;
489662306a36Sopenharmony_ci	struct device *dev = ud->dev;
489762306a36Sopenharmony_ci	struct ti_sci_resource *rm_res, irq_res;
489862306a36Sopenharmony_ci	struct udma_tisci_rm *tisci_rm = &ud->tisci_rm;
489962306a36Sopenharmony_ci	const struct udma_oes_offsets *oes = &ud->soc_data->oes;
490062306a36Sopenharmony_ci	u32 cap3;
490162306a36Sopenharmony_ci
490262306a36Sopenharmony_ci	/* Set up the throughput level start indexes */
490362306a36Sopenharmony_ci	cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c);
490462306a36Sopenharmony_ci	if (UDMA_CAP3_UCHAN_CNT(cap3)) {
490562306a36Sopenharmony_ci		ud->tchan_tpl.levels = 3;
490662306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[1] = UDMA_CAP3_UCHAN_CNT(cap3);
490762306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3);
490862306a36Sopenharmony_ci	} else if (UDMA_CAP3_HCHAN_CNT(cap3)) {
490962306a36Sopenharmony_ci		ud->tchan_tpl.levels = 2;
491062306a36Sopenharmony_ci		ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3);
491162306a36Sopenharmony_ci	} else {
491262306a36Sopenharmony_ci		ud->tchan_tpl.levels = 1;
491362306a36Sopenharmony_ci	}
491462306a36Sopenharmony_ci
491562306a36Sopenharmony_ci	ud->rchan_tpl.levels = ud->tchan_tpl.levels;
491662306a36Sopenharmony_ci	ud->rchan_tpl.start_idx[0] = ud->tchan_tpl.start_idx[0];
491762306a36Sopenharmony_ci	ud->rchan_tpl.start_idx[1] = ud->tchan_tpl.start_idx[1];
491862306a36Sopenharmony_ci
491962306a36Sopenharmony_ci	ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt),
492062306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
492162306a36Sopenharmony_ci	ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans),
492262306a36Sopenharmony_ci				  GFP_KERNEL);
492362306a36Sopenharmony_ci	ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt),
492462306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
492562306a36Sopenharmony_ci	ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans),
492662306a36Sopenharmony_ci				  GFP_KERNEL);
492762306a36Sopenharmony_ci	ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rflow_cnt),
492862306a36Sopenharmony_ci					sizeof(unsigned long),
492962306a36Sopenharmony_ci					GFP_KERNEL);
493062306a36Sopenharmony_ci	ud->rflows = devm_kcalloc(dev, ud->rflow_cnt, sizeof(*ud->rflows),
493162306a36Sopenharmony_ci				  GFP_KERNEL);
493262306a36Sopenharmony_ci	ud->tflow_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tflow_cnt),
493362306a36Sopenharmony_ci					   sizeof(unsigned long), GFP_KERNEL);
493462306a36Sopenharmony_ci
493562306a36Sopenharmony_ci	if (!ud->tchan_map || !ud->rchan_map || !ud->tflow_map || !ud->tchans ||
493662306a36Sopenharmony_ci	    !ud->rchans || !ud->rflows || !ud->rflow_in_use)
493762306a36Sopenharmony_ci		return -ENOMEM;
493862306a36Sopenharmony_ci
493962306a36Sopenharmony_ci	/* Get resource ranges from tisci */
494062306a36Sopenharmony_ci	for (i = 0; i < RM_RANGE_LAST; i++) {
494162306a36Sopenharmony_ci		if (i == RM_RANGE_BCHAN)
494262306a36Sopenharmony_ci			continue;
494362306a36Sopenharmony_ci
494462306a36Sopenharmony_ci		tisci_rm->rm_ranges[i] =
494562306a36Sopenharmony_ci			devm_ti_sci_get_of_resource(tisci_rm->tisci, dev,
494662306a36Sopenharmony_ci						    tisci_rm->tisci_dev_id,
494762306a36Sopenharmony_ci						    (char *)range_names[i]);
494862306a36Sopenharmony_ci	}
494962306a36Sopenharmony_ci
495062306a36Sopenharmony_ci	/* tchan ranges */
495162306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN];
495262306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
495362306a36Sopenharmony_ci		bitmap_zero(ud->tchan_map, ud->tchan_cnt);
495462306a36Sopenharmony_ci	} else {
495562306a36Sopenharmony_ci		bitmap_fill(ud->tchan_map, ud->tchan_cnt);
495662306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
495762306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->tchan_map,
495862306a36Sopenharmony_ci						  &rm_res->desc[i], "tchan");
495962306a36Sopenharmony_ci	}
496062306a36Sopenharmony_ci
496162306a36Sopenharmony_ci	/* rchan ranges */
496262306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN];
496362306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
496462306a36Sopenharmony_ci		bitmap_zero(ud->rchan_map, ud->rchan_cnt);
496562306a36Sopenharmony_ci	} else {
496662306a36Sopenharmony_ci		bitmap_fill(ud->rchan_map, ud->rchan_cnt);
496762306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
496862306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->rchan_map,
496962306a36Sopenharmony_ci						  &rm_res->desc[i], "rchan");
497062306a36Sopenharmony_ci	}
497162306a36Sopenharmony_ci
497262306a36Sopenharmony_ci	/* rflow ranges */
497362306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW];
497462306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
497562306a36Sopenharmony_ci		/* all rflows are assigned exclusively to Linux */
497662306a36Sopenharmony_ci		bitmap_zero(ud->rflow_in_use, ud->rflow_cnt);
497762306a36Sopenharmony_ci		irq_res.sets = 1;
497862306a36Sopenharmony_ci	} else {
497962306a36Sopenharmony_ci		bitmap_fill(ud->rflow_in_use, ud->rflow_cnt);
498062306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
498162306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->rflow_in_use,
498262306a36Sopenharmony_ci						  &rm_res->desc[i], "rflow");
498362306a36Sopenharmony_ci		irq_res.sets = rm_res->sets;
498462306a36Sopenharmony_ci	}
498562306a36Sopenharmony_ci
498662306a36Sopenharmony_ci	/* tflow ranges */
498762306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW];
498862306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
498962306a36Sopenharmony_ci		/* all tflows are assigned exclusively to Linux */
499062306a36Sopenharmony_ci		bitmap_zero(ud->tflow_map, ud->tflow_cnt);
499162306a36Sopenharmony_ci		irq_res.sets++;
499262306a36Sopenharmony_ci	} else {
499362306a36Sopenharmony_ci		bitmap_fill(ud->tflow_map, ud->tflow_cnt);
499462306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++)
499562306a36Sopenharmony_ci			udma_mark_resource_ranges(ud, ud->tflow_map,
499662306a36Sopenharmony_ci						  &rm_res->desc[i], "tflow");
499762306a36Sopenharmony_ci		irq_res.sets += rm_res->sets;
499862306a36Sopenharmony_ci	}
499962306a36Sopenharmony_ci
500062306a36Sopenharmony_ci	irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL);
500162306a36Sopenharmony_ci	if (!irq_res.desc)
500262306a36Sopenharmony_ci		return -ENOMEM;
500362306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW];
500462306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
500562306a36Sopenharmony_ci		irq_res.desc[0].start = oes->pktdma_tchan_flow;
500662306a36Sopenharmony_ci		irq_res.desc[0].num = ud->tflow_cnt;
500762306a36Sopenharmony_ci		i = 1;
500862306a36Sopenharmony_ci	} else {
500962306a36Sopenharmony_ci		for (i = 0; i < rm_res->sets; i++) {
501062306a36Sopenharmony_ci			irq_res.desc[i].start = rm_res->desc[i].start +
501162306a36Sopenharmony_ci						oes->pktdma_tchan_flow;
501262306a36Sopenharmony_ci			irq_res.desc[i].num = rm_res->desc[i].num;
501362306a36Sopenharmony_ci		}
501462306a36Sopenharmony_ci	}
501562306a36Sopenharmony_ci	rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW];
501662306a36Sopenharmony_ci	if (IS_ERR(rm_res)) {
501762306a36Sopenharmony_ci		irq_res.desc[i].start = oes->pktdma_rchan_flow;
501862306a36Sopenharmony_ci		irq_res.desc[i].num = ud->rflow_cnt;
501962306a36Sopenharmony_ci	} else {
502062306a36Sopenharmony_ci		for (j = 0; j < rm_res->sets; j++, i++) {
502162306a36Sopenharmony_ci			irq_res.desc[i].start = rm_res->desc[j].start +
502262306a36Sopenharmony_ci						oes->pktdma_rchan_flow;
502362306a36Sopenharmony_ci			irq_res.desc[i].num = rm_res->desc[j].num;
502462306a36Sopenharmony_ci		}
502562306a36Sopenharmony_ci	}
502662306a36Sopenharmony_ci	ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res);
502762306a36Sopenharmony_ci	kfree(irq_res.desc);
502862306a36Sopenharmony_ci	if (ret) {
502962306a36Sopenharmony_ci		dev_err(ud->dev, "Failed to allocate MSI interrupts\n");
503062306a36Sopenharmony_ci		return ret;
503162306a36Sopenharmony_ci	}
503262306a36Sopenharmony_ci
503362306a36Sopenharmony_ci	return 0;
503462306a36Sopenharmony_ci}
503562306a36Sopenharmony_ci
503662306a36Sopenharmony_cistatic int setup_resources(struct udma_dev *ud)
503762306a36Sopenharmony_ci{
503862306a36Sopenharmony_ci	struct device *dev = ud->dev;
503962306a36Sopenharmony_ci	int ch_count, ret;
504062306a36Sopenharmony_ci
504162306a36Sopenharmony_ci	switch (ud->match_data->type) {
504262306a36Sopenharmony_ci	case DMA_TYPE_UDMA:
504362306a36Sopenharmony_ci		ret = udma_setup_resources(ud);
504462306a36Sopenharmony_ci		break;
504562306a36Sopenharmony_ci	case DMA_TYPE_BCDMA:
504662306a36Sopenharmony_ci		ret = bcdma_setup_resources(ud);
504762306a36Sopenharmony_ci		break;
504862306a36Sopenharmony_ci	case DMA_TYPE_PKTDMA:
504962306a36Sopenharmony_ci		ret = pktdma_setup_resources(ud);
505062306a36Sopenharmony_ci		break;
505162306a36Sopenharmony_ci	default:
505262306a36Sopenharmony_ci		return -EINVAL;
505362306a36Sopenharmony_ci	}
505462306a36Sopenharmony_ci
505562306a36Sopenharmony_ci	if (ret)
505662306a36Sopenharmony_ci		return ret;
505762306a36Sopenharmony_ci
505862306a36Sopenharmony_ci	ch_count  = ud->bchan_cnt + ud->tchan_cnt + ud->rchan_cnt;
505962306a36Sopenharmony_ci	if (ud->bchan_cnt)
506062306a36Sopenharmony_ci		ch_count -= bitmap_weight(ud->bchan_map, ud->bchan_cnt);
506162306a36Sopenharmony_ci	ch_count -= bitmap_weight(ud->tchan_map, ud->tchan_cnt);
506262306a36Sopenharmony_ci	ch_count -= bitmap_weight(ud->rchan_map, ud->rchan_cnt);
506362306a36Sopenharmony_ci	if (!ch_count)
506462306a36Sopenharmony_ci		return -ENODEV;
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	ud->channels = devm_kcalloc(dev, ch_count, sizeof(*ud->channels),
506762306a36Sopenharmony_ci				    GFP_KERNEL);
506862306a36Sopenharmony_ci	if (!ud->channels)
506962306a36Sopenharmony_ci		return -ENOMEM;
507062306a36Sopenharmony_ci
507162306a36Sopenharmony_ci	switch (ud->match_data->type) {
507262306a36Sopenharmony_ci	case DMA_TYPE_UDMA:
507362306a36Sopenharmony_ci		dev_info(dev,
507462306a36Sopenharmony_ci			 "Channels: %d (tchan: %u, rchan: %u, gp-rflow: %u)\n",
507562306a36Sopenharmony_ci			 ch_count,
507662306a36Sopenharmony_ci			 ud->tchan_cnt - bitmap_weight(ud->tchan_map,
507762306a36Sopenharmony_ci						       ud->tchan_cnt),
507862306a36Sopenharmony_ci			 ud->rchan_cnt - bitmap_weight(ud->rchan_map,
507962306a36Sopenharmony_ci						       ud->rchan_cnt),
508062306a36Sopenharmony_ci			 ud->rflow_cnt - bitmap_weight(ud->rflow_gp_map,
508162306a36Sopenharmony_ci						       ud->rflow_cnt));
508262306a36Sopenharmony_ci		break;
508362306a36Sopenharmony_ci	case DMA_TYPE_BCDMA:
508462306a36Sopenharmony_ci		dev_info(dev,
508562306a36Sopenharmony_ci			 "Channels: %d (bchan: %u, tchan: %u, rchan: %u)\n",
508662306a36Sopenharmony_ci			 ch_count,
508762306a36Sopenharmony_ci			 ud->bchan_cnt - bitmap_weight(ud->bchan_map,
508862306a36Sopenharmony_ci						       ud->bchan_cnt),
508962306a36Sopenharmony_ci			 ud->tchan_cnt - bitmap_weight(ud->tchan_map,
509062306a36Sopenharmony_ci						       ud->tchan_cnt),
509162306a36Sopenharmony_ci			 ud->rchan_cnt - bitmap_weight(ud->rchan_map,
509262306a36Sopenharmony_ci						       ud->rchan_cnt));
509362306a36Sopenharmony_ci		break;
509462306a36Sopenharmony_ci	case DMA_TYPE_PKTDMA:
509562306a36Sopenharmony_ci		dev_info(dev,
509662306a36Sopenharmony_ci			 "Channels: %d (tchan: %u, rchan: %u)\n",
509762306a36Sopenharmony_ci			 ch_count,
509862306a36Sopenharmony_ci			 ud->tchan_cnt - bitmap_weight(ud->tchan_map,
509962306a36Sopenharmony_ci						       ud->tchan_cnt),
510062306a36Sopenharmony_ci			 ud->rchan_cnt - bitmap_weight(ud->rchan_map,
510162306a36Sopenharmony_ci						       ud->rchan_cnt));
510262306a36Sopenharmony_ci		break;
510362306a36Sopenharmony_ci	default:
510462306a36Sopenharmony_ci		break;
510562306a36Sopenharmony_ci	}
510662306a36Sopenharmony_ci
510762306a36Sopenharmony_ci	return ch_count;
510862306a36Sopenharmony_ci}
510962306a36Sopenharmony_ci
511062306a36Sopenharmony_cistatic int udma_setup_rx_flush(struct udma_dev *ud)
511162306a36Sopenharmony_ci{
511262306a36Sopenharmony_ci	struct udma_rx_flush *rx_flush = &ud->rx_flush;
511362306a36Sopenharmony_ci	struct cppi5_desc_hdr_t *tr_desc;
511462306a36Sopenharmony_ci	struct cppi5_tr_type1_t *tr_req;
511562306a36Sopenharmony_ci	struct cppi5_host_desc_t *desc;
511662306a36Sopenharmony_ci	struct device *dev = ud->dev;
511762306a36Sopenharmony_ci	struct udma_hwdesc *hwdesc;
511862306a36Sopenharmony_ci	size_t tr_size;
511962306a36Sopenharmony_ci
512062306a36Sopenharmony_ci	/* Allocate 1K buffer for discarded data on RX channel teardown */
512162306a36Sopenharmony_ci	rx_flush->buffer_size = SZ_1K;
512262306a36Sopenharmony_ci	rx_flush->buffer_vaddr = devm_kzalloc(dev, rx_flush->buffer_size,
512362306a36Sopenharmony_ci					      GFP_KERNEL);
512462306a36Sopenharmony_ci	if (!rx_flush->buffer_vaddr)
512562306a36Sopenharmony_ci		return -ENOMEM;
512662306a36Sopenharmony_ci
512762306a36Sopenharmony_ci	rx_flush->buffer_paddr = dma_map_single(dev, rx_flush->buffer_vaddr,
512862306a36Sopenharmony_ci						rx_flush->buffer_size,
512962306a36Sopenharmony_ci						DMA_TO_DEVICE);
513062306a36Sopenharmony_ci	if (dma_mapping_error(dev, rx_flush->buffer_paddr))
513162306a36Sopenharmony_ci		return -ENOMEM;
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_ci	/* Set up descriptor to be used for TR mode */
513462306a36Sopenharmony_ci	hwdesc = &rx_flush->hwdescs[0];
513562306a36Sopenharmony_ci	tr_size = sizeof(struct cppi5_tr_type1_t);
513662306a36Sopenharmony_ci	hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size, 1);
513762306a36Sopenharmony_ci	hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size,
513862306a36Sopenharmony_ci					ud->desc_align);
513962306a36Sopenharmony_ci
514062306a36Sopenharmony_ci	hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
514162306a36Sopenharmony_ci						GFP_KERNEL);
514262306a36Sopenharmony_ci	if (!hwdesc->cppi5_desc_vaddr)
514362306a36Sopenharmony_ci		return -ENOMEM;
514462306a36Sopenharmony_ci
514562306a36Sopenharmony_ci	hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
514662306a36Sopenharmony_ci						  hwdesc->cppi5_desc_size,
514762306a36Sopenharmony_ci						  DMA_TO_DEVICE);
514862306a36Sopenharmony_ci	if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
514962306a36Sopenharmony_ci		return -ENOMEM;
515062306a36Sopenharmony_ci
515162306a36Sopenharmony_ci	/* Start of the TR req records */
515262306a36Sopenharmony_ci	hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size;
515362306a36Sopenharmony_ci	/* Start address of the TR response array */
515462306a36Sopenharmony_ci	hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size;
515562306a36Sopenharmony_ci
515662306a36Sopenharmony_ci	tr_desc = hwdesc->cppi5_desc_vaddr;
515762306a36Sopenharmony_ci	cppi5_trdesc_init(tr_desc, 1, tr_size, 0, 0);
515862306a36Sopenharmony_ci	cppi5_desc_set_pktids(tr_desc, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
515962306a36Sopenharmony_ci	cppi5_desc_set_retpolicy(tr_desc, 0, 0);
516062306a36Sopenharmony_ci
516162306a36Sopenharmony_ci	tr_req = hwdesc->tr_req_base;
516262306a36Sopenharmony_ci	cppi5_tr_init(&tr_req->flags, CPPI5_TR_TYPE1, false, false,
516362306a36Sopenharmony_ci		      CPPI5_TR_EVENT_SIZE_COMPLETION, 0);
516462306a36Sopenharmony_ci	cppi5_tr_csf_set(&tr_req->flags, CPPI5_TR_CSF_SUPR_EVT);
516562306a36Sopenharmony_ci
516662306a36Sopenharmony_ci	tr_req->addr = rx_flush->buffer_paddr;
516762306a36Sopenharmony_ci	tr_req->icnt0 = rx_flush->buffer_size;
516862306a36Sopenharmony_ci	tr_req->icnt1 = 1;
516962306a36Sopenharmony_ci
517062306a36Sopenharmony_ci	dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr,
517162306a36Sopenharmony_ci				   hwdesc->cppi5_desc_size, DMA_TO_DEVICE);
517262306a36Sopenharmony_ci
517362306a36Sopenharmony_ci	/* Set up descriptor to be used for packet mode */
517462306a36Sopenharmony_ci	hwdesc = &rx_flush->hwdescs[1];
517562306a36Sopenharmony_ci	hwdesc->cppi5_desc_size = ALIGN(sizeof(struct cppi5_host_desc_t) +
517662306a36Sopenharmony_ci					CPPI5_INFO0_HDESC_EPIB_SIZE +
517762306a36Sopenharmony_ci					CPPI5_INFO0_HDESC_PSDATA_MAX_SIZE,
517862306a36Sopenharmony_ci					ud->desc_align);
517962306a36Sopenharmony_ci
518062306a36Sopenharmony_ci	hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size,
518162306a36Sopenharmony_ci						GFP_KERNEL);
518262306a36Sopenharmony_ci	if (!hwdesc->cppi5_desc_vaddr)
518362306a36Sopenharmony_ci		return -ENOMEM;
518462306a36Sopenharmony_ci
518562306a36Sopenharmony_ci	hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr,
518662306a36Sopenharmony_ci						  hwdesc->cppi5_desc_size,
518762306a36Sopenharmony_ci						  DMA_TO_DEVICE);
518862306a36Sopenharmony_ci	if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr))
518962306a36Sopenharmony_ci		return -ENOMEM;
519062306a36Sopenharmony_ci
519162306a36Sopenharmony_ci	desc = hwdesc->cppi5_desc_vaddr;
519262306a36Sopenharmony_ci	cppi5_hdesc_init(desc, 0, 0);
519362306a36Sopenharmony_ci	cppi5_desc_set_pktids(&desc->hdr, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT);
519462306a36Sopenharmony_ci	cppi5_desc_set_retpolicy(&desc->hdr, 0, 0);
519562306a36Sopenharmony_ci
519662306a36Sopenharmony_ci	cppi5_hdesc_attach_buf(desc,
519762306a36Sopenharmony_ci			       rx_flush->buffer_paddr, rx_flush->buffer_size,
519862306a36Sopenharmony_ci			       rx_flush->buffer_paddr, rx_flush->buffer_size);
519962306a36Sopenharmony_ci
520062306a36Sopenharmony_ci	dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr,
520162306a36Sopenharmony_ci				   hwdesc->cppi5_desc_size, DMA_TO_DEVICE);
520262306a36Sopenharmony_ci	return 0;
520362306a36Sopenharmony_ci}
520462306a36Sopenharmony_ci
520562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
520662306a36Sopenharmony_cistatic void udma_dbg_summary_show_chan(struct seq_file *s,
520762306a36Sopenharmony_ci				       struct dma_chan *chan)
520862306a36Sopenharmony_ci{
520962306a36Sopenharmony_ci	struct udma_chan *uc = to_udma_chan(chan);
521062306a36Sopenharmony_ci	struct udma_chan_config *ucc = &uc->config;
521162306a36Sopenharmony_ci
521262306a36Sopenharmony_ci	seq_printf(s, " %-13s| %s", dma_chan_name(chan),
521362306a36Sopenharmony_ci		   chan->dbg_client_name ?: "in-use");
521462306a36Sopenharmony_ci	if (ucc->tr_trigger_type)
521562306a36Sopenharmony_ci		seq_puts(s, " (triggered, ");
521662306a36Sopenharmony_ci	else
521762306a36Sopenharmony_ci		seq_printf(s, " (%s, ",
521862306a36Sopenharmony_ci			   dmaengine_get_direction_text(uc->config.dir));
521962306a36Sopenharmony_ci
522062306a36Sopenharmony_ci	switch (uc->config.dir) {
522162306a36Sopenharmony_ci	case DMA_MEM_TO_MEM:
522262306a36Sopenharmony_ci		if (uc->ud->match_data->type == DMA_TYPE_BCDMA) {
522362306a36Sopenharmony_ci			seq_printf(s, "bchan%d)\n", uc->bchan->id);
522462306a36Sopenharmony_ci			return;
522562306a36Sopenharmony_ci		}
522662306a36Sopenharmony_ci
522762306a36Sopenharmony_ci		seq_printf(s, "chan%d pair [0x%04x -> 0x%04x], ", uc->tchan->id,
522862306a36Sopenharmony_ci			   ucc->src_thread, ucc->dst_thread);
522962306a36Sopenharmony_ci		break;
523062306a36Sopenharmony_ci	case DMA_DEV_TO_MEM:
523162306a36Sopenharmony_ci		seq_printf(s, "rchan%d [0x%04x -> 0x%04x], ", uc->rchan->id,
523262306a36Sopenharmony_ci			   ucc->src_thread, ucc->dst_thread);
523362306a36Sopenharmony_ci		if (uc->ud->match_data->type == DMA_TYPE_PKTDMA)
523462306a36Sopenharmony_ci			seq_printf(s, "rflow%d, ", uc->rflow->id);
523562306a36Sopenharmony_ci		break;
523662306a36Sopenharmony_ci	case DMA_MEM_TO_DEV:
523762306a36Sopenharmony_ci		seq_printf(s, "tchan%d [0x%04x -> 0x%04x], ", uc->tchan->id,
523862306a36Sopenharmony_ci			   ucc->src_thread, ucc->dst_thread);
523962306a36Sopenharmony_ci		if (uc->ud->match_data->type == DMA_TYPE_PKTDMA)
524062306a36Sopenharmony_ci			seq_printf(s, "tflow%d, ", uc->tchan->tflow_id);
524162306a36Sopenharmony_ci		break;
524262306a36Sopenharmony_ci	default:
524362306a36Sopenharmony_ci		seq_printf(s, ")\n");
524462306a36Sopenharmony_ci		return;
524562306a36Sopenharmony_ci	}
524662306a36Sopenharmony_ci
524762306a36Sopenharmony_ci	if (ucc->ep_type == PSIL_EP_NATIVE) {
524862306a36Sopenharmony_ci		seq_printf(s, "PSI-L Native");
524962306a36Sopenharmony_ci		if (ucc->metadata_size) {
525062306a36Sopenharmony_ci			seq_printf(s, "[%s", ucc->needs_epib ? " EPIB" : "");
525162306a36Sopenharmony_ci			if (ucc->psd_size)
525262306a36Sopenharmony_ci				seq_printf(s, " PSDsize:%u", ucc->psd_size);
525362306a36Sopenharmony_ci			seq_printf(s, " ]");
525462306a36Sopenharmony_ci		}
525562306a36Sopenharmony_ci	} else {
525662306a36Sopenharmony_ci		seq_printf(s, "PDMA");
525762306a36Sopenharmony_ci		if (ucc->enable_acc32 || ucc->enable_burst)
525862306a36Sopenharmony_ci			seq_printf(s, "[%s%s ]",
525962306a36Sopenharmony_ci				   ucc->enable_acc32 ? " ACC32" : "",
526062306a36Sopenharmony_ci				   ucc->enable_burst ? " BURST" : "");
526162306a36Sopenharmony_ci	}
526262306a36Sopenharmony_ci
526362306a36Sopenharmony_ci	seq_printf(s, ", %s)\n", ucc->pkt_mode ? "Packet mode" : "TR mode");
526462306a36Sopenharmony_ci}
526562306a36Sopenharmony_ci
526662306a36Sopenharmony_cistatic void udma_dbg_summary_show(struct seq_file *s,
526762306a36Sopenharmony_ci				  struct dma_device *dma_dev)
526862306a36Sopenharmony_ci{
526962306a36Sopenharmony_ci	struct dma_chan *chan;
527062306a36Sopenharmony_ci
527162306a36Sopenharmony_ci	list_for_each_entry(chan, &dma_dev->channels, device_node) {
527262306a36Sopenharmony_ci		if (chan->client_count)
527362306a36Sopenharmony_ci			udma_dbg_summary_show_chan(s, chan);
527462306a36Sopenharmony_ci	}
527562306a36Sopenharmony_ci}
527662306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_cistatic enum dmaengine_alignment udma_get_copy_align(struct udma_dev *ud)
527962306a36Sopenharmony_ci{
528062306a36Sopenharmony_ci	const struct udma_match_data *match_data = ud->match_data;
528162306a36Sopenharmony_ci	u8 tpl;
528262306a36Sopenharmony_ci
528362306a36Sopenharmony_ci	if (!match_data->enable_memcpy_support)
528462306a36Sopenharmony_ci		return DMAENGINE_ALIGN_8_BYTES;
528562306a36Sopenharmony_ci
528662306a36Sopenharmony_ci	/* Get the highest TPL level the device supports for memcpy */
528762306a36Sopenharmony_ci	if (ud->bchan_cnt)
528862306a36Sopenharmony_ci		tpl = udma_get_chan_tpl_index(&ud->bchan_tpl, 0);
528962306a36Sopenharmony_ci	else if (ud->tchan_cnt)
529062306a36Sopenharmony_ci		tpl = udma_get_chan_tpl_index(&ud->tchan_tpl, 0);
529162306a36Sopenharmony_ci	else
529262306a36Sopenharmony_ci		return DMAENGINE_ALIGN_8_BYTES;
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci	switch (match_data->burst_size[tpl]) {
529562306a36Sopenharmony_ci	case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES:
529662306a36Sopenharmony_ci		return DMAENGINE_ALIGN_256_BYTES;
529762306a36Sopenharmony_ci	case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES:
529862306a36Sopenharmony_ci		return DMAENGINE_ALIGN_128_BYTES;
529962306a36Sopenharmony_ci	case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES:
530062306a36Sopenharmony_ci	fallthrough;
530162306a36Sopenharmony_ci	default:
530262306a36Sopenharmony_ci		return DMAENGINE_ALIGN_64_BYTES;
530362306a36Sopenharmony_ci	}
530462306a36Sopenharmony_ci}
530562306a36Sopenharmony_ci
530662306a36Sopenharmony_ci#define TI_UDMAC_BUSWIDTHS	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
530762306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
530862306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
530962306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
531062306a36Sopenharmony_ci				 BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
531162306a36Sopenharmony_ci
531262306a36Sopenharmony_cistatic int udma_probe(struct platform_device *pdev)
531362306a36Sopenharmony_ci{
531462306a36Sopenharmony_ci	struct device_node *navss_node = pdev->dev.parent->of_node;
531562306a36Sopenharmony_ci	const struct soc_device_attribute *soc;
531662306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
531762306a36Sopenharmony_ci	struct udma_dev *ud;
531862306a36Sopenharmony_ci	const struct of_device_id *match;
531962306a36Sopenharmony_ci	int i, ret;
532062306a36Sopenharmony_ci	int ch_count;
532162306a36Sopenharmony_ci
532262306a36Sopenharmony_ci	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(48));
532362306a36Sopenharmony_ci	if (ret)
532462306a36Sopenharmony_ci		dev_err(dev, "failed to set dma mask stuff\n");
532562306a36Sopenharmony_ci
532662306a36Sopenharmony_ci	ud = devm_kzalloc(dev, sizeof(*ud), GFP_KERNEL);
532762306a36Sopenharmony_ci	if (!ud)
532862306a36Sopenharmony_ci		return -ENOMEM;
532962306a36Sopenharmony_ci
533062306a36Sopenharmony_ci	match = of_match_node(udma_of_match, dev->of_node);
533162306a36Sopenharmony_ci	if (!match) {
533262306a36Sopenharmony_ci		dev_err(dev, "No compatible match found\n");
533362306a36Sopenharmony_ci		return -ENODEV;
533462306a36Sopenharmony_ci	}
533562306a36Sopenharmony_ci	ud->match_data = match->data;
533662306a36Sopenharmony_ci
533762306a36Sopenharmony_ci	ud->soc_data = ud->match_data->soc_data;
533862306a36Sopenharmony_ci	if (!ud->soc_data) {
533962306a36Sopenharmony_ci		soc = soc_device_match(k3_soc_devices);
534062306a36Sopenharmony_ci		if (!soc) {
534162306a36Sopenharmony_ci			dev_err(dev, "No compatible SoC found\n");
534262306a36Sopenharmony_ci			return -ENODEV;
534362306a36Sopenharmony_ci		}
534462306a36Sopenharmony_ci		ud->soc_data = soc->data;
534562306a36Sopenharmony_ci	}
534662306a36Sopenharmony_ci
534762306a36Sopenharmony_ci	ret = udma_get_mmrs(pdev, ud);
534862306a36Sopenharmony_ci	if (ret)
534962306a36Sopenharmony_ci		return ret;
535062306a36Sopenharmony_ci
535162306a36Sopenharmony_ci	ud->tisci_rm.tisci = ti_sci_get_by_phandle(dev->of_node, "ti,sci");
535262306a36Sopenharmony_ci	if (IS_ERR(ud->tisci_rm.tisci))
535362306a36Sopenharmony_ci		return PTR_ERR(ud->tisci_rm.tisci);
535462306a36Sopenharmony_ci
535562306a36Sopenharmony_ci	ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id",
535662306a36Sopenharmony_ci				   &ud->tisci_rm.tisci_dev_id);
535762306a36Sopenharmony_ci	if (ret) {
535862306a36Sopenharmony_ci		dev_err(dev, "ti,sci-dev-id read failure %d\n", ret);
535962306a36Sopenharmony_ci		return ret;
536062306a36Sopenharmony_ci	}
536162306a36Sopenharmony_ci	pdev->id = ud->tisci_rm.tisci_dev_id;
536262306a36Sopenharmony_ci
536362306a36Sopenharmony_ci	ret = of_property_read_u32(navss_node, "ti,sci-dev-id",
536462306a36Sopenharmony_ci				   &ud->tisci_rm.tisci_navss_dev_id);
536562306a36Sopenharmony_ci	if (ret) {
536662306a36Sopenharmony_ci		dev_err(dev, "NAVSS ti,sci-dev-id read failure %d\n", ret);
536762306a36Sopenharmony_ci		return ret;
536862306a36Sopenharmony_ci	}
536962306a36Sopenharmony_ci
537062306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_UDMA) {
537162306a36Sopenharmony_ci		ret = of_property_read_u32(dev->of_node, "ti,udma-atype",
537262306a36Sopenharmony_ci					   &ud->atype);
537362306a36Sopenharmony_ci		if (!ret && ud->atype > 2) {
537462306a36Sopenharmony_ci			dev_err(dev, "Invalid atype: %u\n", ud->atype);
537562306a36Sopenharmony_ci			return -EINVAL;
537662306a36Sopenharmony_ci		}
537762306a36Sopenharmony_ci	} else {
537862306a36Sopenharmony_ci		ret = of_property_read_u32(dev->of_node, "ti,asel",
537962306a36Sopenharmony_ci					   &ud->asel);
538062306a36Sopenharmony_ci		if (!ret && ud->asel > 15) {
538162306a36Sopenharmony_ci			dev_err(dev, "Invalid asel: %u\n", ud->asel);
538262306a36Sopenharmony_ci			return -EINVAL;
538362306a36Sopenharmony_ci		}
538462306a36Sopenharmony_ci	}
538562306a36Sopenharmony_ci
538662306a36Sopenharmony_ci	ud->tisci_rm.tisci_udmap_ops = &ud->tisci_rm.tisci->ops.rm_udmap_ops;
538762306a36Sopenharmony_ci	ud->tisci_rm.tisci_psil_ops = &ud->tisci_rm.tisci->ops.rm_psil_ops;
538862306a36Sopenharmony_ci
538962306a36Sopenharmony_ci	if (ud->match_data->type == DMA_TYPE_UDMA) {
539062306a36Sopenharmony_ci		ud->ringacc = of_k3_ringacc_get_by_phandle(dev->of_node, "ti,ringacc");
539162306a36Sopenharmony_ci	} else {
539262306a36Sopenharmony_ci		struct k3_ringacc_init_data ring_init_data;
539362306a36Sopenharmony_ci
539462306a36Sopenharmony_ci		ring_init_data.tisci = ud->tisci_rm.tisci;
539562306a36Sopenharmony_ci		ring_init_data.tisci_dev_id = ud->tisci_rm.tisci_dev_id;
539662306a36Sopenharmony_ci		if (ud->match_data->type == DMA_TYPE_BCDMA) {
539762306a36Sopenharmony_ci			ring_init_data.num_rings = ud->bchan_cnt +
539862306a36Sopenharmony_ci						   ud->tchan_cnt +
539962306a36Sopenharmony_ci						   ud->rchan_cnt;
540062306a36Sopenharmony_ci		} else {
540162306a36Sopenharmony_ci			ring_init_data.num_rings = ud->rflow_cnt +
540262306a36Sopenharmony_ci						   ud->tflow_cnt;
540362306a36Sopenharmony_ci		}
540462306a36Sopenharmony_ci
540562306a36Sopenharmony_ci		ud->ringacc = k3_ringacc_dmarings_init(pdev, &ring_init_data);
540662306a36Sopenharmony_ci	}
540762306a36Sopenharmony_ci
540862306a36Sopenharmony_ci	if (IS_ERR(ud->ringacc))
540962306a36Sopenharmony_ci		return PTR_ERR(ud->ringacc);
541062306a36Sopenharmony_ci
541162306a36Sopenharmony_ci	dev->msi.domain = of_msi_get_domain(dev, dev->of_node,
541262306a36Sopenharmony_ci					    DOMAIN_BUS_TI_SCI_INTA_MSI);
541362306a36Sopenharmony_ci	if (!dev->msi.domain) {
541462306a36Sopenharmony_ci		return -EPROBE_DEFER;
541562306a36Sopenharmony_ci	}
541662306a36Sopenharmony_ci
541762306a36Sopenharmony_ci	dma_cap_set(DMA_SLAVE, ud->ddev.cap_mask);
541862306a36Sopenharmony_ci	/* cyclic operation is not supported via PKTDMA */
541962306a36Sopenharmony_ci	if (ud->match_data->type != DMA_TYPE_PKTDMA) {
542062306a36Sopenharmony_ci		dma_cap_set(DMA_CYCLIC, ud->ddev.cap_mask);
542162306a36Sopenharmony_ci		ud->ddev.device_prep_dma_cyclic = udma_prep_dma_cyclic;
542262306a36Sopenharmony_ci	}
542362306a36Sopenharmony_ci
542462306a36Sopenharmony_ci	ud->ddev.device_config = udma_slave_config;
542562306a36Sopenharmony_ci	ud->ddev.device_prep_slave_sg = udma_prep_slave_sg;
542662306a36Sopenharmony_ci	ud->ddev.device_issue_pending = udma_issue_pending;
542762306a36Sopenharmony_ci	ud->ddev.device_tx_status = udma_tx_status;
542862306a36Sopenharmony_ci	ud->ddev.device_pause = udma_pause;
542962306a36Sopenharmony_ci	ud->ddev.device_resume = udma_resume;
543062306a36Sopenharmony_ci	ud->ddev.device_terminate_all = udma_terminate_all;
543162306a36Sopenharmony_ci	ud->ddev.device_synchronize = udma_synchronize;
543262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
543362306a36Sopenharmony_ci	ud->ddev.dbg_summary_show = udma_dbg_summary_show;
543462306a36Sopenharmony_ci#endif
543562306a36Sopenharmony_ci
543662306a36Sopenharmony_ci	switch (ud->match_data->type) {
543762306a36Sopenharmony_ci	case DMA_TYPE_UDMA:
543862306a36Sopenharmony_ci		ud->ddev.device_alloc_chan_resources =
543962306a36Sopenharmony_ci					udma_alloc_chan_resources;
544062306a36Sopenharmony_ci		break;
544162306a36Sopenharmony_ci	case DMA_TYPE_BCDMA:
544262306a36Sopenharmony_ci		ud->ddev.device_alloc_chan_resources =
544362306a36Sopenharmony_ci					bcdma_alloc_chan_resources;
544462306a36Sopenharmony_ci		ud->ddev.device_router_config = bcdma_router_config;
544562306a36Sopenharmony_ci		break;
544662306a36Sopenharmony_ci	case DMA_TYPE_PKTDMA:
544762306a36Sopenharmony_ci		ud->ddev.device_alloc_chan_resources =
544862306a36Sopenharmony_ci					pktdma_alloc_chan_resources;
544962306a36Sopenharmony_ci		break;
545062306a36Sopenharmony_ci	default:
545162306a36Sopenharmony_ci		return -EINVAL;
545262306a36Sopenharmony_ci	}
545362306a36Sopenharmony_ci	ud->ddev.device_free_chan_resources = udma_free_chan_resources;
545462306a36Sopenharmony_ci
545562306a36Sopenharmony_ci	ud->ddev.src_addr_widths = TI_UDMAC_BUSWIDTHS;
545662306a36Sopenharmony_ci	ud->ddev.dst_addr_widths = TI_UDMAC_BUSWIDTHS;
545762306a36Sopenharmony_ci	ud->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
545862306a36Sopenharmony_ci	ud->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
545962306a36Sopenharmony_ci	ud->ddev.desc_metadata_modes = DESC_METADATA_CLIENT |
546062306a36Sopenharmony_ci				       DESC_METADATA_ENGINE;
546162306a36Sopenharmony_ci	if (ud->match_data->enable_memcpy_support &&
546262306a36Sopenharmony_ci	    !(ud->match_data->type == DMA_TYPE_BCDMA && ud->bchan_cnt == 0)) {
546362306a36Sopenharmony_ci		dma_cap_set(DMA_MEMCPY, ud->ddev.cap_mask);
546462306a36Sopenharmony_ci		ud->ddev.device_prep_dma_memcpy = udma_prep_dma_memcpy;
546562306a36Sopenharmony_ci		ud->ddev.directions |= BIT(DMA_MEM_TO_MEM);
546662306a36Sopenharmony_ci	}
546762306a36Sopenharmony_ci
546862306a36Sopenharmony_ci	ud->ddev.dev = dev;
546962306a36Sopenharmony_ci	ud->dev = dev;
547062306a36Sopenharmony_ci	ud->psil_base = ud->match_data->psil_base;
547162306a36Sopenharmony_ci
547262306a36Sopenharmony_ci	INIT_LIST_HEAD(&ud->ddev.channels);
547362306a36Sopenharmony_ci	INIT_LIST_HEAD(&ud->desc_to_purge);
547462306a36Sopenharmony_ci
547562306a36Sopenharmony_ci	ch_count = setup_resources(ud);
547662306a36Sopenharmony_ci	if (ch_count <= 0)
547762306a36Sopenharmony_ci		return ch_count;
547862306a36Sopenharmony_ci
547962306a36Sopenharmony_ci	spin_lock_init(&ud->lock);
548062306a36Sopenharmony_ci	INIT_WORK(&ud->purge_work, udma_purge_desc_work);
548162306a36Sopenharmony_ci
548262306a36Sopenharmony_ci	ud->desc_align = 64;
548362306a36Sopenharmony_ci	if (ud->desc_align < dma_get_cache_alignment())
548462306a36Sopenharmony_ci		ud->desc_align = dma_get_cache_alignment();
548562306a36Sopenharmony_ci
548662306a36Sopenharmony_ci	ret = udma_setup_rx_flush(ud);
548762306a36Sopenharmony_ci	if (ret)
548862306a36Sopenharmony_ci		return ret;
548962306a36Sopenharmony_ci
549062306a36Sopenharmony_ci	for (i = 0; i < ud->bchan_cnt; i++) {
549162306a36Sopenharmony_ci		struct udma_bchan *bchan = &ud->bchans[i];
549262306a36Sopenharmony_ci
549362306a36Sopenharmony_ci		bchan->id = i;
549462306a36Sopenharmony_ci		bchan->reg_rt = ud->mmrs[MMR_BCHANRT] + i * 0x1000;
549562306a36Sopenharmony_ci	}
549662306a36Sopenharmony_ci
549762306a36Sopenharmony_ci	for (i = 0; i < ud->tchan_cnt; i++) {
549862306a36Sopenharmony_ci		struct udma_tchan *tchan = &ud->tchans[i];
549962306a36Sopenharmony_ci
550062306a36Sopenharmony_ci		tchan->id = i;
550162306a36Sopenharmony_ci		tchan->reg_rt = ud->mmrs[MMR_TCHANRT] + i * 0x1000;
550262306a36Sopenharmony_ci	}
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_ci	for (i = 0; i < ud->rchan_cnt; i++) {
550562306a36Sopenharmony_ci		struct udma_rchan *rchan = &ud->rchans[i];
550662306a36Sopenharmony_ci
550762306a36Sopenharmony_ci		rchan->id = i;
550862306a36Sopenharmony_ci		rchan->reg_rt = ud->mmrs[MMR_RCHANRT] + i * 0x1000;
550962306a36Sopenharmony_ci	}
551062306a36Sopenharmony_ci
551162306a36Sopenharmony_ci	for (i = 0; i < ud->rflow_cnt; i++) {
551262306a36Sopenharmony_ci		struct udma_rflow *rflow = &ud->rflows[i];
551362306a36Sopenharmony_ci
551462306a36Sopenharmony_ci		rflow->id = i;
551562306a36Sopenharmony_ci	}
551662306a36Sopenharmony_ci
551762306a36Sopenharmony_ci	for (i = 0; i < ch_count; i++) {
551862306a36Sopenharmony_ci		struct udma_chan *uc = &ud->channels[i];
551962306a36Sopenharmony_ci
552062306a36Sopenharmony_ci		uc->ud = ud;
552162306a36Sopenharmony_ci		uc->vc.desc_free = udma_desc_free;
552262306a36Sopenharmony_ci		uc->id = i;
552362306a36Sopenharmony_ci		uc->bchan = NULL;
552462306a36Sopenharmony_ci		uc->tchan = NULL;
552562306a36Sopenharmony_ci		uc->rchan = NULL;
552662306a36Sopenharmony_ci		uc->config.remote_thread_id = -1;
552762306a36Sopenharmony_ci		uc->config.mapped_channel_id = -1;
552862306a36Sopenharmony_ci		uc->config.default_flow_id = -1;
552962306a36Sopenharmony_ci		uc->config.dir = DMA_MEM_TO_MEM;
553062306a36Sopenharmony_ci		uc->name = devm_kasprintf(dev, GFP_KERNEL, "%s chan%d",
553162306a36Sopenharmony_ci					  dev_name(dev), i);
553262306a36Sopenharmony_ci
553362306a36Sopenharmony_ci		vchan_init(&uc->vc, &ud->ddev);
553462306a36Sopenharmony_ci		/* Use custom vchan completion handling */
553562306a36Sopenharmony_ci		tasklet_setup(&uc->vc.task, udma_vchan_complete);
553662306a36Sopenharmony_ci		init_completion(&uc->teardown_completed);
553762306a36Sopenharmony_ci		INIT_DELAYED_WORK(&uc->tx_drain.work, udma_check_tx_completion);
553862306a36Sopenharmony_ci	}
553962306a36Sopenharmony_ci
554062306a36Sopenharmony_ci	/* Configure the copy_align to the maximum burst size the device supports */
554162306a36Sopenharmony_ci	ud->ddev.copy_align = udma_get_copy_align(ud);
554262306a36Sopenharmony_ci
554362306a36Sopenharmony_ci	ret = dma_async_device_register(&ud->ddev);
554462306a36Sopenharmony_ci	if (ret) {
554562306a36Sopenharmony_ci		dev_err(dev, "failed to register slave DMA engine: %d\n", ret);
554662306a36Sopenharmony_ci		return ret;
554762306a36Sopenharmony_ci	}
554862306a36Sopenharmony_ci
554962306a36Sopenharmony_ci	platform_set_drvdata(pdev, ud);
555062306a36Sopenharmony_ci
555162306a36Sopenharmony_ci	ret = of_dma_controller_register(dev->of_node, udma_of_xlate, ud);
555262306a36Sopenharmony_ci	if (ret) {
555362306a36Sopenharmony_ci		dev_err(dev, "failed to register of_dma controller\n");
555462306a36Sopenharmony_ci		dma_async_device_unregister(&ud->ddev);
555562306a36Sopenharmony_ci	}
555662306a36Sopenharmony_ci
555762306a36Sopenharmony_ci	return ret;
555862306a36Sopenharmony_ci}
555962306a36Sopenharmony_ci
556062306a36Sopenharmony_cistatic int __maybe_unused udma_pm_suspend(struct device *dev)
556162306a36Sopenharmony_ci{
556262306a36Sopenharmony_ci	struct udma_dev *ud = dev_get_drvdata(dev);
556362306a36Sopenharmony_ci	struct dma_device *dma_dev = &ud->ddev;
556462306a36Sopenharmony_ci	struct dma_chan *chan;
556562306a36Sopenharmony_ci	struct udma_chan *uc;
556662306a36Sopenharmony_ci
556762306a36Sopenharmony_ci	list_for_each_entry(chan, &dma_dev->channels, device_node) {
556862306a36Sopenharmony_ci		if (chan->client_count) {
556962306a36Sopenharmony_ci			uc = to_udma_chan(chan);
557062306a36Sopenharmony_ci			/* backup the channel configuration */
557162306a36Sopenharmony_ci			memcpy(&uc->backup_config, &uc->config,
557262306a36Sopenharmony_ci			       sizeof(struct udma_chan_config));
557362306a36Sopenharmony_ci			dev_dbg(dev, "Suspending channel %s\n",
557462306a36Sopenharmony_ci				dma_chan_name(chan));
557562306a36Sopenharmony_ci			ud->ddev.device_free_chan_resources(chan);
557662306a36Sopenharmony_ci		}
557762306a36Sopenharmony_ci	}
557862306a36Sopenharmony_ci
557962306a36Sopenharmony_ci	return 0;
558062306a36Sopenharmony_ci}
558162306a36Sopenharmony_ci
558262306a36Sopenharmony_cistatic int __maybe_unused udma_pm_resume(struct device *dev)
558362306a36Sopenharmony_ci{
558462306a36Sopenharmony_ci	struct udma_dev *ud = dev_get_drvdata(dev);
558562306a36Sopenharmony_ci	struct dma_device *dma_dev = &ud->ddev;
558662306a36Sopenharmony_ci	struct dma_chan *chan;
558762306a36Sopenharmony_ci	struct udma_chan *uc;
558862306a36Sopenharmony_ci	int ret;
558962306a36Sopenharmony_ci
559062306a36Sopenharmony_ci	list_for_each_entry(chan, &dma_dev->channels, device_node) {
559162306a36Sopenharmony_ci		if (chan->client_count) {
559262306a36Sopenharmony_ci			uc = to_udma_chan(chan);
559362306a36Sopenharmony_ci			/* restore the channel configuration */
559462306a36Sopenharmony_ci			memcpy(&uc->config, &uc->backup_config,
559562306a36Sopenharmony_ci			       sizeof(struct udma_chan_config));
559662306a36Sopenharmony_ci			dev_dbg(dev, "Resuming channel %s\n",
559762306a36Sopenharmony_ci				dma_chan_name(chan));
559862306a36Sopenharmony_ci			ret = ud->ddev.device_alloc_chan_resources(chan);
559962306a36Sopenharmony_ci			if (ret)
560062306a36Sopenharmony_ci				return ret;
560162306a36Sopenharmony_ci		}
560262306a36Sopenharmony_ci	}
560362306a36Sopenharmony_ci
560462306a36Sopenharmony_ci	return 0;
560562306a36Sopenharmony_ci}
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_cistatic const struct dev_pm_ops udma_pm_ops = {
560862306a36Sopenharmony_ci	SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume)
560962306a36Sopenharmony_ci};
561062306a36Sopenharmony_ci
561162306a36Sopenharmony_cistatic struct platform_driver udma_driver = {
561262306a36Sopenharmony_ci	.driver = {
561362306a36Sopenharmony_ci		.name	= "ti-udma",
561462306a36Sopenharmony_ci		.of_match_table = udma_of_match,
561562306a36Sopenharmony_ci		.suppress_bind_attrs = true,
561662306a36Sopenharmony_ci		.pm = &udma_pm_ops,
561762306a36Sopenharmony_ci	},
561862306a36Sopenharmony_ci	.probe		= udma_probe,
561962306a36Sopenharmony_ci};
562062306a36Sopenharmony_ci
562162306a36Sopenharmony_cimodule_platform_driver(udma_driver);
562262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
562362306a36Sopenharmony_ci
562462306a36Sopenharmony_ci/* Private interfaces to UDMA */
562562306a36Sopenharmony_ci#include "k3-udma-private.c"
5626