xref: /openbmc/linux/drivers/dma/k3dma.c (revision 8be98d2f2a0a262f8bf8a0bc1fdf522b3c7aab17)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
28e6152bcSZhangfei Gao /*
3a7e08fa6SAndy Green  * Copyright (c) 2013 - 2015 Linaro Ltd.
4*1b6216a6SHao Fang  * Copyright (c) 2013 HiSilicon Limited.
58e6152bcSZhangfei Gao  */
68e6152bcSZhangfei Gao #include <linux/sched.h>
78e6152bcSZhangfei Gao #include <linux/device.h>
8b77f262aSJohn Stultz #include <linux/dma-mapping.h>
9b77f262aSJohn Stultz #include <linux/dmapool.h>
108e6152bcSZhangfei Gao #include <linux/dmaengine.h>
118e6152bcSZhangfei Gao #include <linux/init.h>
128e6152bcSZhangfei Gao #include <linux/interrupt.h>
138e6152bcSZhangfei Gao #include <linux/kernel.h>
148e6152bcSZhangfei Gao #include <linux/module.h>
158e6152bcSZhangfei Gao #include <linux/platform_device.h>
168e6152bcSZhangfei Gao #include <linux/slab.h>
178e6152bcSZhangfei Gao #include <linux/spinlock.h>
188e6152bcSZhangfei Gao #include <linux/of_device.h>
198e6152bcSZhangfei Gao #include <linux/of.h>
208e6152bcSZhangfei Gao #include <linux/clk.h>
218e6152bcSZhangfei Gao #include <linux/of_dma.h>
228e6152bcSZhangfei Gao 
238e6152bcSZhangfei Gao #include "virt-dma.h"
248e6152bcSZhangfei Gao 
258e6152bcSZhangfei Gao #define DRIVER_NAME		"k3-dma"
268e6152bcSZhangfei Gao #define DMA_MAX_SIZE		0x1ffc
27a7e08fa6SAndy Green #define DMA_CYCLIC_MAX_PERIOD	0x1000
28b77f262aSJohn Stultz #define LLI_BLOCK_SIZE		(4 * PAGE_SIZE)
298e6152bcSZhangfei Gao 
308e6152bcSZhangfei Gao #define INT_STAT		0x00
318e6152bcSZhangfei Gao #define INT_TC1			0x04
32a7e08fa6SAndy Green #define INT_TC2			0x08
338e6152bcSZhangfei Gao #define INT_ERR1		0x0c
348e6152bcSZhangfei Gao #define INT_ERR2		0x10
358e6152bcSZhangfei Gao #define INT_TC1_MASK		0x18
36a7e08fa6SAndy Green #define INT_TC2_MASK		0x1c
378e6152bcSZhangfei Gao #define INT_ERR1_MASK		0x20
388e6152bcSZhangfei Gao #define INT_ERR2_MASK		0x24
398e6152bcSZhangfei Gao #define INT_TC1_RAW		0x600
40a7e08fa6SAndy Green #define INT_TC2_RAW		0x608
41aceaaa17SAndy Green #define INT_ERR1_RAW		0x610
42aceaaa17SAndy Green #define INT_ERR2_RAW		0x618
438e6152bcSZhangfei Gao #define CH_PRI			0x688
448e6152bcSZhangfei Gao #define CH_STAT			0x690
458e6152bcSZhangfei Gao #define CX_CUR_CNT		0x704
468e6152bcSZhangfei Gao #define CX_LLI			0x800
47a7e08fa6SAndy Green #define CX_CNT1			0x80c
48a7e08fa6SAndy Green #define CX_CNT0			0x810
498e6152bcSZhangfei Gao #define CX_SRC			0x814
508e6152bcSZhangfei Gao #define CX_DST			0x818
518e6152bcSZhangfei Gao #define CX_CFG			0x81c
528e6152bcSZhangfei Gao 
538e6152bcSZhangfei Gao #define CX_LLI_CHAIN_EN		0x2
548e6152bcSZhangfei Gao #define CX_CFG_EN		0x1
55a7e08fa6SAndy Green #define CX_CFG_NODEIRQ		BIT(1)
568e6152bcSZhangfei Gao #define CX_CFG_MEM2PER		(0x1 << 2)
578e6152bcSZhangfei Gao #define CX_CFG_PER2MEM		(0x2 << 2)
588e6152bcSZhangfei Gao #define CX_CFG_SRCINCR		(0x1 << 31)
598e6152bcSZhangfei Gao #define CX_CFG_DSTINCR		(0x1 << 30)
608e6152bcSZhangfei Gao 
618e6152bcSZhangfei Gao struct k3_desc_hw {
628e6152bcSZhangfei Gao 	u32 lli;
638e6152bcSZhangfei Gao 	u32 reserved[3];
648e6152bcSZhangfei Gao 	u32 count;
658e6152bcSZhangfei Gao 	u32 saddr;
668e6152bcSZhangfei Gao 	u32 daddr;
678e6152bcSZhangfei Gao 	u32 config;
688e6152bcSZhangfei Gao } __aligned(32);
698e6152bcSZhangfei Gao 
708e6152bcSZhangfei Gao struct k3_dma_desc_sw {
718e6152bcSZhangfei Gao 	struct virt_dma_desc	vd;
728e6152bcSZhangfei Gao 	dma_addr_t		desc_hw_lli;
738e6152bcSZhangfei Gao 	size_t			desc_num;
748e6152bcSZhangfei Gao 	size_t			size;
75b77f262aSJohn Stultz 	struct k3_desc_hw	*desc_hw;
768e6152bcSZhangfei Gao };
778e6152bcSZhangfei Gao 
788e6152bcSZhangfei Gao struct k3_dma_phy;
798e6152bcSZhangfei Gao 
808e6152bcSZhangfei Gao struct k3_dma_chan {
818e6152bcSZhangfei Gao 	u32			ccfg;
828e6152bcSZhangfei Gao 	struct virt_dma_chan	vc;
838e6152bcSZhangfei Gao 	struct k3_dma_phy	*phy;
848e6152bcSZhangfei Gao 	struct list_head	node;
858e6152bcSZhangfei Gao 	dma_addr_t		dev_addr;
868e6152bcSZhangfei Gao 	enum dma_status		status;
87a7e08fa6SAndy Green 	bool			cyclic;
882ae1a237SVinod Koul 	struct dma_slave_config	slave_config;
898e6152bcSZhangfei Gao };
908e6152bcSZhangfei Gao 
918e6152bcSZhangfei Gao struct k3_dma_phy {
928e6152bcSZhangfei Gao 	u32			idx;
938e6152bcSZhangfei Gao 	void __iomem		*base;
948e6152bcSZhangfei Gao 	struct k3_dma_chan	*vchan;
958e6152bcSZhangfei Gao 	struct k3_dma_desc_sw	*ds_run;
968e6152bcSZhangfei Gao 	struct k3_dma_desc_sw	*ds_done;
978e6152bcSZhangfei Gao };
988e6152bcSZhangfei Gao 
998e6152bcSZhangfei Gao struct k3_dma_dev {
1008e6152bcSZhangfei Gao 	struct dma_device	slave;
1018e6152bcSZhangfei Gao 	void __iomem		*base;
1028e6152bcSZhangfei Gao 	struct tasklet_struct	task;
1038e6152bcSZhangfei Gao 	spinlock_t		lock;
1048e6152bcSZhangfei Gao 	struct list_head	chan_pending;
1058e6152bcSZhangfei Gao 	struct k3_dma_phy	*phy;
1068e6152bcSZhangfei Gao 	struct k3_dma_chan	*chans;
1078e6152bcSZhangfei Gao 	struct clk		*clk;
108b77f262aSJohn Stultz 	struct dma_pool		*pool;
1098e6152bcSZhangfei Gao 	u32			dma_channels;
1108e6152bcSZhangfei Gao 	u32			dma_requests;
111c4994a98SLi Yu 	u32			dma_channel_mask;
112486b10a2SVinod Koul 	unsigned int		irq;
1138e6152bcSZhangfei Gao };
1148e6152bcSZhangfei Gao 
115d4bdc39fSYoulin Wang 
116d4bdc39fSYoulin Wang #define K3_FLAG_NOCLK	BIT(1)
117d4bdc39fSYoulin Wang 
118d4bdc39fSYoulin Wang struct k3dma_soc_data {
119d4bdc39fSYoulin Wang 	unsigned long flags;
120d4bdc39fSYoulin Wang };
121d4bdc39fSYoulin Wang 
122d4bdc39fSYoulin Wang 
1238e6152bcSZhangfei Gao #define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
1248e6152bcSZhangfei Gao 
1252ae1a237SVinod Koul static int k3_dma_config_write(struct dma_chan *chan,
1262ae1a237SVinod Koul 			       enum dma_transfer_direction dir,
1272ae1a237SVinod Koul 			       struct dma_slave_config *cfg);
1282ae1a237SVinod Koul 
to_k3_chan(struct dma_chan * chan)1298e6152bcSZhangfei Gao static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
1308e6152bcSZhangfei Gao {
1318e6152bcSZhangfei Gao 	return container_of(chan, struct k3_dma_chan, vc.chan);
1328e6152bcSZhangfei Gao }
1338e6152bcSZhangfei Gao 
k3_dma_pause_dma(struct k3_dma_phy * phy,bool on)1348e6152bcSZhangfei Gao static void k3_dma_pause_dma(struct k3_dma_phy *phy, bool on)
1358e6152bcSZhangfei Gao {
1368e6152bcSZhangfei Gao 	u32 val = 0;
1378e6152bcSZhangfei Gao 
1388e6152bcSZhangfei Gao 	if (on) {
1398e6152bcSZhangfei Gao 		val = readl_relaxed(phy->base + CX_CFG);
1408e6152bcSZhangfei Gao 		val |= CX_CFG_EN;
1418e6152bcSZhangfei Gao 		writel_relaxed(val, phy->base + CX_CFG);
1428e6152bcSZhangfei Gao 	} else {
1438e6152bcSZhangfei Gao 		val = readl_relaxed(phy->base + CX_CFG);
1448e6152bcSZhangfei Gao 		val &= ~CX_CFG_EN;
1458e6152bcSZhangfei Gao 		writel_relaxed(val, phy->base + CX_CFG);
1468e6152bcSZhangfei Gao 	}
1478e6152bcSZhangfei Gao }
1488e6152bcSZhangfei Gao 
k3_dma_terminate_chan(struct k3_dma_phy * phy,struct k3_dma_dev * d)1498e6152bcSZhangfei Gao static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
1508e6152bcSZhangfei Gao {
1518e6152bcSZhangfei Gao 	u32 val = 0;
1528e6152bcSZhangfei Gao 
1538e6152bcSZhangfei Gao 	k3_dma_pause_dma(phy, false);
1548e6152bcSZhangfei Gao 
1558e6152bcSZhangfei Gao 	val = 0x1 << phy->idx;
1568e6152bcSZhangfei Gao 	writel_relaxed(val, d->base + INT_TC1_RAW);
157a7e08fa6SAndy Green 	writel_relaxed(val, d->base + INT_TC2_RAW);
1588e6152bcSZhangfei Gao 	writel_relaxed(val, d->base + INT_ERR1_RAW);
1598e6152bcSZhangfei Gao 	writel_relaxed(val, d->base + INT_ERR2_RAW);
1608e6152bcSZhangfei Gao }
1618e6152bcSZhangfei Gao 
k3_dma_set_desc(struct k3_dma_phy * phy,struct k3_desc_hw * hw)1628e6152bcSZhangfei Gao static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw)
1638e6152bcSZhangfei Gao {
1648e6152bcSZhangfei Gao 	writel_relaxed(hw->lli, phy->base + CX_LLI);
165a7e08fa6SAndy Green 	writel_relaxed(hw->count, phy->base + CX_CNT0);
1668e6152bcSZhangfei Gao 	writel_relaxed(hw->saddr, phy->base + CX_SRC);
1678e6152bcSZhangfei Gao 	writel_relaxed(hw->daddr, phy->base + CX_DST);
1688e6152bcSZhangfei Gao 	writel_relaxed(hw->config, phy->base + CX_CFG);
1698e6152bcSZhangfei Gao }
1708e6152bcSZhangfei Gao 
k3_dma_get_curr_cnt(struct k3_dma_dev * d,struct k3_dma_phy * phy)1718e6152bcSZhangfei Gao static u32 k3_dma_get_curr_cnt(struct k3_dma_dev *d, struct k3_dma_phy *phy)
1728e6152bcSZhangfei Gao {
1738e6152bcSZhangfei Gao 	u32 cnt = 0;
1748e6152bcSZhangfei Gao 
1758e6152bcSZhangfei Gao 	cnt = readl_relaxed(d->base + CX_CUR_CNT + phy->idx * 0x10);
1768e6152bcSZhangfei Gao 	cnt &= 0xffff;
1778e6152bcSZhangfei Gao 	return cnt;
1788e6152bcSZhangfei Gao }
1798e6152bcSZhangfei Gao 
k3_dma_get_curr_lli(struct k3_dma_phy * phy)1808e6152bcSZhangfei Gao static u32 k3_dma_get_curr_lli(struct k3_dma_phy *phy)
1818e6152bcSZhangfei Gao {
1828e6152bcSZhangfei Gao 	return readl_relaxed(phy->base + CX_LLI);
1838e6152bcSZhangfei Gao }
1848e6152bcSZhangfei Gao 
k3_dma_get_chan_stat(struct k3_dma_dev * d)1858e6152bcSZhangfei Gao static u32 k3_dma_get_chan_stat(struct k3_dma_dev *d)
1868e6152bcSZhangfei Gao {
1878e6152bcSZhangfei Gao 	return readl_relaxed(d->base + CH_STAT);
1888e6152bcSZhangfei Gao }
1898e6152bcSZhangfei Gao 
k3_dma_enable_dma(struct k3_dma_dev * d,bool on)1908e6152bcSZhangfei Gao static void k3_dma_enable_dma(struct k3_dma_dev *d, bool on)
1918e6152bcSZhangfei Gao {
1928e6152bcSZhangfei Gao 	if (on) {
1938e6152bcSZhangfei Gao 		/* set same priority */
1948e6152bcSZhangfei Gao 		writel_relaxed(0x0, d->base + CH_PRI);
1958e6152bcSZhangfei Gao 
1968e6152bcSZhangfei Gao 		/* unmask irq */
1978e6152bcSZhangfei Gao 		writel_relaxed(0xffff, d->base + INT_TC1_MASK);
198a7e08fa6SAndy Green 		writel_relaxed(0xffff, d->base + INT_TC2_MASK);
1998e6152bcSZhangfei Gao 		writel_relaxed(0xffff, d->base + INT_ERR1_MASK);
2008e6152bcSZhangfei Gao 		writel_relaxed(0xffff, d->base + INT_ERR2_MASK);
2018e6152bcSZhangfei Gao 	} else {
2028e6152bcSZhangfei Gao 		/* mask irq */
2038e6152bcSZhangfei Gao 		writel_relaxed(0x0, d->base + INT_TC1_MASK);
204a7e08fa6SAndy Green 		writel_relaxed(0x0, d->base + INT_TC2_MASK);
2058e6152bcSZhangfei Gao 		writel_relaxed(0x0, d->base + INT_ERR1_MASK);
2068e6152bcSZhangfei Gao 		writel_relaxed(0x0, d->base + INT_ERR2_MASK);
2078e6152bcSZhangfei Gao 	}
2088e6152bcSZhangfei Gao }
2098e6152bcSZhangfei Gao 
k3_dma_int_handler(int irq,void * dev_id)2108e6152bcSZhangfei Gao static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
2118e6152bcSZhangfei Gao {
2128e6152bcSZhangfei Gao 	struct k3_dma_dev *d = (struct k3_dma_dev *)dev_id;
2138e6152bcSZhangfei Gao 	struct k3_dma_phy *p;
2148e6152bcSZhangfei Gao 	struct k3_dma_chan *c;
2158e6152bcSZhangfei Gao 	u32 stat = readl_relaxed(d->base + INT_STAT);
2168e6152bcSZhangfei Gao 	u32 tc1  = readl_relaxed(d->base + INT_TC1);
217a7e08fa6SAndy Green 	u32 tc2  = readl_relaxed(d->base + INT_TC2);
2188e6152bcSZhangfei Gao 	u32 err1 = readl_relaxed(d->base + INT_ERR1);
2198e6152bcSZhangfei Gao 	u32 err2 = readl_relaxed(d->base + INT_ERR2);
2208e6152bcSZhangfei Gao 	u32 i, irq_chan = 0;
2218e6152bcSZhangfei Gao 
2228e6152bcSZhangfei Gao 	while (stat) {
2238e6152bcSZhangfei Gao 		i = __ffs(stat);
224a7e08fa6SAndy Green 		stat &= ~BIT(i);
225a7e08fa6SAndy Green 		if (likely(tc1 & BIT(i)) || (tc2 & BIT(i))) {
2268e6152bcSZhangfei Gao 
227a7e08fa6SAndy Green 			p = &d->phy[i];
228a7e08fa6SAndy Green 			c = p->vchan;
229a7e08fa6SAndy Green 			if (c && (tc1 & BIT(i))) {
2301ff20656SBarry Song 				spin_lock(&c->vc.lock);
2312f42e05bSJohn Stultz 				if (p->ds_run != NULL) {
2328e6152bcSZhangfei Gao 					vchan_cookie_complete(&p->ds_run->vd);
2338e6152bcSZhangfei Gao 					p->ds_done = p->ds_run;
23436387a2bSJohn Stultz 					p->ds_run = NULL;
2352f42e05bSJohn Stultz 				}
2361ff20656SBarry Song 				spin_unlock(&c->vc.lock);
2378e6152bcSZhangfei Gao 			}
238a7e08fa6SAndy Green 			if (c && (tc2 & BIT(i))) {
2391ff20656SBarry Song 				spin_lock(&c->vc.lock);
240a7e08fa6SAndy Green 				if (p->ds_run != NULL)
241a7e08fa6SAndy Green 					vchan_cyclic_callback(&p->ds_run->vd);
2421ff20656SBarry Song 				spin_unlock(&c->vc.lock);
243a7e08fa6SAndy Green 			}
2448e6152bcSZhangfei Gao 			irq_chan |= BIT(i);
2458e6152bcSZhangfei Gao 		}
2468e6152bcSZhangfei Gao 		if (unlikely((err1 & BIT(i)) || (err2 & BIT(i))))
2478e6152bcSZhangfei Gao 			dev_warn(d->slave.dev, "DMA ERR\n");
2488e6152bcSZhangfei Gao 	}
2498e6152bcSZhangfei Gao 
2508e6152bcSZhangfei Gao 	writel_relaxed(irq_chan, d->base + INT_TC1_RAW);
251a7e08fa6SAndy Green 	writel_relaxed(irq_chan, d->base + INT_TC2_RAW);
2528e6152bcSZhangfei Gao 	writel_relaxed(err1, d->base + INT_ERR1_RAW);
2538e6152bcSZhangfei Gao 	writel_relaxed(err2, d->base + INT_ERR2_RAW);
2548e6152bcSZhangfei Gao 
2550173c895SAndy Green 	if (irq_chan)
2568e6152bcSZhangfei Gao 		tasklet_schedule(&d->task);
2570173c895SAndy Green 
2580173c895SAndy Green 	if (irq_chan || err1 || err2)
2598e6152bcSZhangfei Gao 		return IRQ_HANDLED;
2600173c895SAndy Green 
2618e6152bcSZhangfei Gao 	return IRQ_NONE;
2628e6152bcSZhangfei Gao }
2638e6152bcSZhangfei Gao 
k3_dma_start_txd(struct k3_dma_chan * c)2648e6152bcSZhangfei Gao static int k3_dma_start_txd(struct k3_dma_chan *c)
2658e6152bcSZhangfei Gao {
2668e6152bcSZhangfei Gao 	struct k3_dma_dev *d = to_k3_dma(c->vc.chan.device);
2678e6152bcSZhangfei Gao 	struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
2688e6152bcSZhangfei Gao 
2698e6152bcSZhangfei Gao 	if (!c->phy)
2708e6152bcSZhangfei Gao 		return -EAGAIN;
2718e6152bcSZhangfei Gao 
2728e6152bcSZhangfei Gao 	if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d))
2738e6152bcSZhangfei Gao 		return -EAGAIN;
2748e6152bcSZhangfei Gao 
2752f42e05bSJohn Stultz 	/* Avoid losing track of  ds_run if a transaction is in flight */
2762f42e05bSJohn Stultz 	if (c->phy->ds_run)
2772f42e05bSJohn Stultz 		return -EAGAIN;
2782f42e05bSJohn Stultz 
2798e6152bcSZhangfei Gao 	if (vd) {
2808e6152bcSZhangfei Gao 		struct k3_dma_desc_sw *ds =
2818e6152bcSZhangfei Gao 			container_of(vd, struct k3_dma_desc_sw, vd);
2828e6152bcSZhangfei Gao 		/*
2838e6152bcSZhangfei Gao 		 * fetch and remove request from vc->desc_issued
2848e6152bcSZhangfei Gao 		 * so vc->desc_issued only contains desc pending
2858e6152bcSZhangfei Gao 		 */
2868e6152bcSZhangfei Gao 		list_del(&ds->vd.node);
28736387a2bSJohn Stultz 
2888e6152bcSZhangfei Gao 		c->phy->ds_run = ds;
289626c4e85SAntonio Borneo 		c->phy->ds_done = NULL;
2908e6152bcSZhangfei Gao 		/* start dma */
2918e6152bcSZhangfei Gao 		k3_dma_set_desc(c->phy, &ds->desc_hw[0]);
2928e6152bcSZhangfei Gao 		return 0;
2938e6152bcSZhangfei Gao 	}
294626c4e85SAntonio Borneo 	c->phy->ds_run = NULL;
295626c4e85SAntonio Borneo 	c->phy->ds_done = NULL;
2968e6152bcSZhangfei Gao 	return -EAGAIN;
2978e6152bcSZhangfei Gao }
2988e6152bcSZhangfei Gao 
k3_dma_tasklet(struct tasklet_struct * t)299881bd142SAllen Pais static void k3_dma_tasklet(struct tasklet_struct *t)
3008e6152bcSZhangfei Gao {
301881bd142SAllen Pais 	struct k3_dma_dev *d = from_tasklet(d, t, task);
3028e6152bcSZhangfei Gao 	struct k3_dma_phy *p;
3038e6152bcSZhangfei Gao 	struct k3_dma_chan *c, *cn;
3048e6152bcSZhangfei Gao 	unsigned pch, pch_alloc = 0;
3058e6152bcSZhangfei Gao 
3068e6152bcSZhangfei Gao 	/* check new dma request of running channel in vc->desc_issued */
3078e6152bcSZhangfei Gao 	list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
3088e6152bcSZhangfei Gao 		spin_lock_irq(&c->vc.lock);
3098e6152bcSZhangfei Gao 		p = c->phy;
3108e6152bcSZhangfei Gao 		if (p && p->ds_done) {
3118e6152bcSZhangfei Gao 			if (k3_dma_start_txd(c)) {
3128e6152bcSZhangfei Gao 				/* No current txd associated with this channel */
3138e6152bcSZhangfei Gao 				dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
3148e6152bcSZhangfei Gao 				/* Mark this channel free */
3158e6152bcSZhangfei Gao 				c->phy = NULL;
3168e6152bcSZhangfei Gao 				p->vchan = NULL;
3178e6152bcSZhangfei Gao 			}
3188e6152bcSZhangfei Gao 		}
3198e6152bcSZhangfei Gao 		spin_unlock_irq(&c->vc.lock);
3208e6152bcSZhangfei Gao 	}
3218e6152bcSZhangfei Gao 
3228e6152bcSZhangfei Gao 	/* check new channel request in d->chan_pending */
3238e6152bcSZhangfei Gao 	spin_lock_irq(&d->lock);
3248e6152bcSZhangfei Gao 	for (pch = 0; pch < d->dma_channels; pch++) {
325c4994a98SLi Yu 		if (!(d->dma_channel_mask & (1 << pch)))
326c4994a98SLi Yu 			continue;
327c4994a98SLi Yu 
3288e6152bcSZhangfei Gao 		p = &d->phy[pch];
3298e6152bcSZhangfei Gao 
3308e6152bcSZhangfei Gao 		if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
3318e6152bcSZhangfei Gao 			c = list_first_entry(&d->chan_pending,
3328e6152bcSZhangfei Gao 				struct k3_dma_chan, node);
3338e6152bcSZhangfei Gao 			/* remove from d->chan_pending */
3348e6152bcSZhangfei Gao 			list_del_init(&c->node);
3358e6152bcSZhangfei Gao 			pch_alloc |= 1 << pch;
3368e6152bcSZhangfei Gao 			/* Mark this channel allocated */
3378e6152bcSZhangfei Gao 			p->vchan = c;
3388e6152bcSZhangfei Gao 			c->phy = p;
3398e6152bcSZhangfei Gao 			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
3408e6152bcSZhangfei Gao 		}
3418e6152bcSZhangfei Gao 	}
3428e6152bcSZhangfei Gao 	spin_unlock_irq(&d->lock);
3438e6152bcSZhangfei Gao 
3448e6152bcSZhangfei Gao 	for (pch = 0; pch < d->dma_channels; pch++) {
345c4994a98SLi Yu 		if (!(d->dma_channel_mask & (1 << pch)))
346c4994a98SLi Yu 			continue;
347c4994a98SLi Yu 
3488e6152bcSZhangfei Gao 		if (pch_alloc & (1 << pch)) {
3498e6152bcSZhangfei Gao 			p = &d->phy[pch];
3508e6152bcSZhangfei Gao 			c = p->vchan;
3518e6152bcSZhangfei Gao 			if (c) {
3528e6152bcSZhangfei Gao 				spin_lock_irq(&c->vc.lock);
3538e6152bcSZhangfei Gao 				k3_dma_start_txd(c);
3548e6152bcSZhangfei Gao 				spin_unlock_irq(&c->vc.lock);
3558e6152bcSZhangfei Gao 			}
3568e6152bcSZhangfei Gao 		}
3578e6152bcSZhangfei Gao 	}
3588e6152bcSZhangfei Gao }
3598e6152bcSZhangfei Gao 
k3_dma_free_chan_resources(struct dma_chan * chan)3608e6152bcSZhangfei Gao static void k3_dma_free_chan_resources(struct dma_chan *chan)
3618e6152bcSZhangfei Gao {
3628e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
3638e6152bcSZhangfei Gao 	struct k3_dma_dev *d = to_k3_dma(chan->device);
3648e6152bcSZhangfei Gao 	unsigned long flags;
3658e6152bcSZhangfei Gao 
3668e6152bcSZhangfei Gao 	spin_lock_irqsave(&d->lock, flags);
3678e6152bcSZhangfei Gao 	list_del_init(&c->node);
3688e6152bcSZhangfei Gao 	spin_unlock_irqrestore(&d->lock, flags);
3698e6152bcSZhangfei Gao 
3708e6152bcSZhangfei Gao 	vchan_free_chan_resources(&c->vc);
3718e6152bcSZhangfei Gao 	c->ccfg = 0;
3728e6152bcSZhangfei Gao }
3738e6152bcSZhangfei Gao 
k3_dma_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * state)3748e6152bcSZhangfei Gao static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
3758e6152bcSZhangfei Gao 	dma_cookie_t cookie, struct dma_tx_state *state)
3768e6152bcSZhangfei Gao {
3778e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
3788e6152bcSZhangfei Gao 	struct k3_dma_dev *d = to_k3_dma(chan->device);
3798e6152bcSZhangfei Gao 	struct k3_dma_phy *p;
3808e6152bcSZhangfei Gao 	struct virt_dma_desc *vd;
3818e6152bcSZhangfei Gao 	unsigned long flags;
3828e6152bcSZhangfei Gao 	enum dma_status ret;
3838e6152bcSZhangfei Gao 	size_t bytes = 0;
3848e6152bcSZhangfei Gao 
3858e6152bcSZhangfei Gao 	ret = dma_cookie_status(&c->vc.chan, cookie, state);
386bd2c348eSVinod Koul 	if (ret == DMA_COMPLETE)
3878e6152bcSZhangfei Gao 		return ret;
3888e6152bcSZhangfei Gao 
3898e6152bcSZhangfei Gao 	spin_lock_irqsave(&c->vc.lock, flags);
3908e6152bcSZhangfei Gao 	p = c->phy;
3918e6152bcSZhangfei Gao 	ret = c->status;
3928e6152bcSZhangfei Gao 
3938e6152bcSZhangfei Gao 	/*
3948e6152bcSZhangfei Gao 	 * If the cookie is on our issue queue, then the residue is
3958e6152bcSZhangfei Gao 	 * its total size.
3968e6152bcSZhangfei Gao 	 */
3978e6152bcSZhangfei Gao 	vd = vchan_find_desc(&c->vc, cookie);
398a7e08fa6SAndy Green 	if (vd && !c->cyclic) {
3998e6152bcSZhangfei Gao 		bytes = container_of(vd, struct k3_dma_desc_sw, vd)->size;
4008e6152bcSZhangfei Gao 	} else if ((!p) || (!p->ds_run)) {
4018e6152bcSZhangfei Gao 		bytes = 0;
4028e6152bcSZhangfei Gao 	} else {
4038e6152bcSZhangfei Gao 		struct k3_dma_desc_sw *ds = p->ds_run;
4048e6152bcSZhangfei Gao 		u32 clli = 0, index = 0;
4058e6152bcSZhangfei Gao 
4068e6152bcSZhangfei Gao 		bytes = k3_dma_get_curr_cnt(d, p);
4078e6152bcSZhangfei Gao 		clli = k3_dma_get_curr_lli(p);
408a7e08fa6SAndy Green 		index = ((clli - ds->desc_hw_lli) /
409a7e08fa6SAndy Green 				sizeof(struct k3_desc_hw)) + 1;
4108e6152bcSZhangfei Gao 		for (; index < ds->desc_num; index++) {
4118e6152bcSZhangfei Gao 			bytes += ds->desc_hw[index].count;
4128e6152bcSZhangfei Gao 			/* end of lli */
4138e6152bcSZhangfei Gao 			if (!ds->desc_hw[index].lli)
4148e6152bcSZhangfei Gao 				break;
4158e6152bcSZhangfei Gao 		}
4168e6152bcSZhangfei Gao 	}
4178e6152bcSZhangfei Gao 	spin_unlock_irqrestore(&c->vc.lock, flags);
4188e6152bcSZhangfei Gao 	dma_set_residue(state, bytes);
4198e6152bcSZhangfei Gao 	return ret;
4208e6152bcSZhangfei Gao }
4218e6152bcSZhangfei Gao 
k3_dma_issue_pending(struct dma_chan * chan)4228e6152bcSZhangfei Gao static void k3_dma_issue_pending(struct dma_chan *chan)
4238e6152bcSZhangfei Gao {
4248e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
4258e6152bcSZhangfei Gao 	struct k3_dma_dev *d = to_k3_dma(chan->device);
4268e6152bcSZhangfei Gao 	unsigned long flags;
4278e6152bcSZhangfei Gao 
4288e6152bcSZhangfei Gao 	spin_lock_irqsave(&c->vc.lock, flags);
4298e6152bcSZhangfei Gao 	/* add request to vc->desc_issued */
4308e6152bcSZhangfei Gao 	if (vchan_issue_pending(&c->vc)) {
4318e6152bcSZhangfei Gao 		spin_lock(&d->lock);
4328e6152bcSZhangfei Gao 		if (!c->phy) {
4338e6152bcSZhangfei Gao 			if (list_empty(&c->node)) {
4348e6152bcSZhangfei Gao 				/* if new channel, add chan_pending */
4358e6152bcSZhangfei Gao 				list_add_tail(&c->node, &d->chan_pending);
4368e6152bcSZhangfei Gao 				/* check in tasklet */
4378e6152bcSZhangfei Gao 				tasklet_schedule(&d->task);
4388e6152bcSZhangfei Gao 				dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
4398e6152bcSZhangfei Gao 			}
4408e6152bcSZhangfei Gao 		}
4418e6152bcSZhangfei Gao 		spin_unlock(&d->lock);
4428e6152bcSZhangfei Gao 	} else
4438e6152bcSZhangfei Gao 		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
4448e6152bcSZhangfei Gao 	spin_unlock_irqrestore(&c->vc.lock, flags);
4458e6152bcSZhangfei Gao }
4468e6152bcSZhangfei Gao 
k3_dma_fill_desc(struct k3_dma_desc_sw * ds,dma_addr_t dst,dma_addr_t src,size_t len,u32 num,u32 ccfg)4478e6152bcSZhangfei Gao static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
4488e6152bcSZhangfei Gao 			dma_addr_t src, size_t len, u32 num, u32 ccfg)
4498e6152bcSZhangfei Gao {
450a7e08fa6SAndy Green 	if (num != ds->desc_num - 1)
4518e6152bcSZhangfei Gao 		ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
4528e6152bcSZhangfei Gao 			sizeof(struct k3_desc_hw);
453a7e08fa6SAndy Green 
4548e6152bcSZhangfei Gao 	ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN;
4558e6152bcSZhangfei Gao 	ds->desc_hw[num].count = len;
4568e6152bcSZhangfei Gao 	ds->desc_hw[num].saddr = src;
4578e6152bcSZhangfei Gao 	ds->desc_hw[num].daddr = dst;
4588e6152bcSZhangfei Gao 	ds->desc_hw[num].config = ccfg;
4598e6152bcSZhangfei Gao }
4608e6152bcSZhangfei Gao 
k3_dma_alloc_desc_resource(int num,struct dma_chan * chan)461b77f262aSJohn Stultz static struct k3_dma_desc_sw *k3_dma_alloc_desc_resource(int num,
462b77f262aSJohn Stultz 							struct dma_chan *chan)
463b77f262aSJohn Stultz {
464b77f262aSJohn Stultz 	struct k3_dma_chan *c = to_k3_chan(chan);
465b77f262aSJohn Stultz 	struct k3_dma_desc_sw *ds;
466b77f262aSJohn Stultz 	struct k3_dma_dev *d = to_k3_dma(chan->device);
467b77f262aSJohn Stultz 	int lli_limit = LLI_BLOCK_SIZE / sizeof(struct k3_desc_hw);
468b77f262aSJohn Stultz 
469b77f262aSJohn Stultz 	if (num > lli_limit) {
470b77f262aSJohn Stultz 		dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n",
471b77f262aSJohn Stultz 			&c->vc, num, lli_limit);
472b77f262aSJohn Stultz 		return NULL;
473b77f262aSJohn Stultz 	}
474b77f262aSJohn Stultz 
475b77f262aSJohn Stultz 	ds = kzalloc(sizeof(*ds), GFP_NOWAIT);
476b77f262aSJohn Stultz 	if (!ds)
477b77f262aSJohn Stultz 		return NULL;
478b77f262aSJohn Stultz 
479646b3b56SVinod Koul 	ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli);
480b77f262aSJohn Stultz 	if (!ds->desc_hw) {
481b77f262aSJohn Stultz 		dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc);
482b77f262aSJohn Stultz 		kfree(ds);
483b77f262aSJohn Stultz 		return NULL;
484b77f262aSJohn Stultz 	}
485b77f262aSJohn Stultz 	ds->desc_num = num;
486b77f262aSJohn Stultz 	return ds;
487b77f262aSJohn Stultz }
488b77f262aSJohn Stultz 
k3_dma_prep_memcpy(struct dma_chan * chan,dma_addr_t dst,dma_addr_t src,size_t len,unsigned long flags)4898e6152bcSZhangfei Gao static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
4908e6152bcSZhangfei Gao 	struct dma_chan *chan,	dma_addr_t dst, dma_addr_t src,
4918e6152bcSZhangfei Gao 	size_t len, unsigned long flags)
4928e6152bcSZhangfei Gao {
4938e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
4948e6152bcSZhangfei Gao 	struct k3_dma_desc_sw *ds;
4958e6152bcSZhangfei Gao 	size_t copy = 0;
4968e6152bcSZhangfei Gao 	int num = 0;
4978e6152bcSZhangfei Gao 
4988e6152bcSZhangfei Gao 	if (!len)
4998e6152bcSZhangfei Gao 		return NULL;
5008e6152bcSZhangfei Gao 
5018e6152bcSZhangfei Gao 	num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
502b77f262aSJohn Stultz 
503b77f262aSJohn Stultz 	ds = k3_dma_alloc_desc_resource(num, chan);
504aef94feaSPeter Griffin 	if (!ds)
5058e6152bcSZhangfei Gao 		return NULL;
506aef94feaSPeter Griffin 
507a7e08fa6SAndy Green 	c->cyclic = 0;
5088e6152bcSZhangfei Gao 	ds->size = len;
5098e6152bcSZhangfei Gao 	num = 0;
5108e6152bcSZhangfei Gao 
5118e6152bcSZhangfei Gao 	if (!c->ccfg) {
512db08425eSMaxime Ripard 		/* default is memtomem, without calling device_config */
5138e6152bcSZhangfei Gao 		c->ccfg = CX_CFG_SRCINCR | CX_CFG_DSTINCR | CX_CFG_EN;
5148e6152bcSZhangfei Gao 		c->ccfg |= (0xf << 20) | (0xf << 24);	/* burst = 16 */
5158e6152bcSZhangfei Gao 		c->ccfg |= (0x3 << 12) | (0x3 << 16);	/* width = 64 bit */
5168e6152bcSZhangfei Gao 	}
5178e6152bcSZhangfei Gao 
5188e6152bcSZhangfei Gao 	do {
5198e6152bcSZhangfei Gao 		copy = min_t(size_t, len, DMA_MAX_SIZE);
5208e6152bcSZhangfei Gao 		k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
5218e6152bcSZhangfei Gao 
5228e6152bcSZhangfei Gao 		src += copy;
5238e6152bcSZhangfei Gao 		dst += copy;
5248e6152bcSZhangfei Gao 		len -= copy;
5258e6152bcSZhangfei Gao 	} while (len);
5268e6152bcSZhangfei Gao 
5278e6152bcSZhangfei Gao 	ds->desc_hw[num-1].lli = 0;	/* end of link */
5288e6152bcSZhangfei Gao 	return vchan_tx_prep(&c->vc, &ds->vd, flags);
5298e6152bcSZhangfei Gao }
5308e6152bcSZhangfei Gao 
k3_dma_prep_slave_sg(struct dma_chan * chan,struct scatterlist * sgl,unsigned int sglen,enum dma_transfer_direction dir,unsigned long flags,void * context)5318e6152bcSZhangfei Gao static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
5328e6152bcSZhangfei Gao 	struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
5338e6152bcSZhangfei Gao 	enum dma_transfer_direction dir, unsigned long flags, void *context)
5348e6152bcSZhangfei Gao {
5358e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
5368e6152bcSZhangfei Gao 	struct k3_dma_desc_sw *ds;
5378e6152bcSZhangfei Gao 	size_t len, avail, total = 0;
5388e6152bcSZhangfei Gao 	struct scatterlist *sg;
5398e6152bcSZhangfei Gao 	dma_addr_t addr, src = 0, dst = 0;
5408e6152bcSZhangfei Gao 	int num = sglen, i;
5418e6152bcSZhangfei Gao 
542c61177c5SZhangfei Gao 	if (sgl == NULL)
5438e6152bcSZhangfei Gao 		return NULL;
5448e6152bcSZhangfei Gao 
545a7e08fa6SAndy Green 	c->cyclic = 0;
546a7e08fa6SAndy Green 
5478e6152bcSZhangfei Gao 	for_each_sg(sgl, sg, sglen, i) {
5488e6152bcSZhangfei Gao 		avail = sg_dma_len(sg);
5498e6152bcSZhangfei Gao 		if (avail > DMA_MAX_SIZE)
5508e6152bcSZhangfei Gao 			num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
5518e6152bcSZhangfei Gao 	}
5528e6152bcSZhangfei Gao 
553b77f262aSJohn Stultz 	ds = k3_dma_alloc_desc_resource(num, chan);
554aef94feaSPeter Griffin 	if (!ds)
5558e6152bcSZhangfei Gao 		return NULL;
5568e6152bcSZhangfei Gao 	num = 0;
5572ae1a237SVinod Koul 	k3_dma_config_write(chan, dir, &c->slave_config);
5588e6152bcSZhangfei Gao 
5598e6152bcSZhangfei Gao 	for_each_sg(sgl, sg, sglen, i) {
5608e6152bcSZhangfei Gao 		addr = sg_dma_address(sg);
5618e6152bcSZhangfei Gao 		avail = sg_dma_len(sg);
5628e6152bcSZhangfei Gao 		total += avail;
5638e6152bcSZhangfei Gao 
5648e6152bcSZhangfei Gao 		do {
5658e6152bcSZhangfei Gao 			len = min_t(size_t, avail, DMA_MAX_SIZE);
5668e6152bcSZhangfei Gao 
5678e6152bcSZhangfei Gao 			if (dir == DMA_MEM_TO_DEV) {
5688e6152bcSZhangfei Gao 				src = addr;
5698e6152bcSZhangfei Gao 				dst = c->dev_addr;
5708e6152bcSZhangfei Gao 			} else if (dir == DMA_DEV_TO_MEM) {
5718e6152bcSZhangfei Gao 				src = c->dev_addr;
5728e6152bcSZhangfei Gao 				dst = addr;
5738e6152bcSZhangfei Gao 			}
5748e6152bcSZhangfei Gao 
5758e6152bcSZhangfei Gao 			k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
5768e6152bcSZhangfei Gao 
5778e6152bcSZhangfei Gao 			addr += len;
5788e6152bcSZhangfei Gao 			avail -= len;
5798e6152bcSZhangfei Gao 		} while (avail);
5808e6152bcSZhangfei Gao 	}
5818e6152bcSZhangfei Gao 
5828e6152bcSZhangfei Gao 	ds->desc_hw[num-1].lli = 0;	/* end of link */
5838e6152bcSZhangfei Gao 	ds->size = total;
5848e6152bcSZhangfei Gao 	return vchan_tx_prep(&c->vc, &ds->vd, flags);
5858e6152bcSZhangfei Gao }
5868e6152bcSZhangfei Gao 
587a7e08fa6SAndy Green static struct dma_async_tx_descriptor *
k3_dma_prep_dma_cyclic(struct dma_chan * chan,dma_addr_t buf_addr,size_t buf_len,size_t period_len,enum dma_transfer_direction dir,unsigned long flags)588a7e08fa6SAndy Green k3_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
589a7e08fa6SAndy Green 		       size_t buf_len, size_t period_len,
590a7e08fa6SAndy Green 		       enum dma_transfer_direction dir,
591a7e08fa6SAndy Green 		       unsigned long flags)
592a7e08fa6SAndy Green {
593a7e08fa6SAndy Green 	struct k3_dma_chan *c = to_k3_chan(chan);
594a7e08fa6SAndy Green 	struct k3_dma_desc_sw *ds;
595a7e08fa6SAndy Green 	size_t len, avail, total = 0;
596a7e08fa6SAndy Green 	dma_addr_t addr, src = 0, dst = 0;
597a7e08fa6SAndy Green 	int num = 1, since = 0;
598a7e08fa6SAndy Green 	size_t modulo = DMA_CYCLIC_MAX_PERIOD;
599a7e08fa6SAndy Green 	u32 en_tc2 = 0;
600a7e08fa6SAndy Green 
6015f03c399SArnd Bergmann 	dev_dbg(chan->device->dev, "%s: buf %pad, dst %pad, buf len %zu, period_len = %zu, dir %d\n",
6025f03c399SArnd Bergmann 	       __func__, &buf_addr, &to_k3_chan(chan)->dev_addr,
6035f03c399SArnd Bergmann 	       buf_len, period_len, (int)dir);
604a7e08fa6SAndy Green 
605a7e08fa6SAndy Green 	avail = buf_len;
606a7e08fa6SAndy Green 	if (avail > modulo)
607a7e08fa6SAndy Green 		num += DIV_ROUND_UP(avail, modulo) - 1;
608a7e08fa6SAndy Green 
609a7e08fa6SAndy Green 	ds = k3_dma_alloc_desc_resource(num, chan);
610a7e08fa6SAndy Green 	if (!ds)
611a7e08fa6SAndy Green 		return NULL;
612a7e08fa6SAndy Green 
613a7e08fa6SAndy Green 	c->cyclic = 1;
614a7e08fa6SAndy Green 	addr = buf_addr;
615a7e08fa6SAndy Green 	avail = buf_len;
616a7e08fa6SAndy Green 	total = avail;
617a7e08fa6SAndy Green 	num = 0;
6182ae1a237SVinod Koul 	k3_dma_config_write(chan, dir, &c->slave_config);
619a7e08fa6SAndy Green 
620a7e08fa6SAndy Green 	if (period_len < modulo)
621a7e08fa6SAndy Green 		modulo = period_len;
622a7e08fa6SAndy Green 
623a7e08fa6SAndy Green 	do {
624a7e08fa6SAndy Green 		len = min_t(size_t, avail, modulo);
625a7e08fa6SAndy Green 
626a7e08fa6SAndy Green 		if (dir == DMA_MEM_TO_DEV) {
627a7e08fa6SAndy Green 			src = addr;
628a7e08fa6SAndy Green 			dst = c->dev_addr;
629a7e08fa6SAndy Green 		} else if (dir == DMA_DEV_TO_MEM) {
630a7e08fa6SAndy Green 			src = c->dev_addr;
631a7e08fa6SAndy Green 			dst = addr;
632a7e08fa6SAndy Green 		}
633a7e08fa6SAndy Green 		since += len;
634a7e08fa6SAndy Green 		if (since >= period_len) {
635a7e08fa6SAndy Green 			/* descriptor asks for TC2 interrupt on completion */
636a7e08fa6SAndy Green 			en_tc2 = CX_CFG_NODEIRQ;
637a7e08fa6SAndy Green 			since -= period_len;
638a7e08fa6SAndy Green 		} else
639a7e08fa6SAndy Green 			en_tc2 = 0;
640a7e08fa6SAndy Green 
641a7e08fa6SAndy Green 		k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg | en_tc2);
642a7e08fa6SAndy Green 
643a7e08fa6SAndy Green 		addr += len;
644a7e08fa6SAndy Green 		avail -= len;
645a7e08fa6SAndy Green 	} while (avail);
646a7e08fa6SAndy Green 
647a7e08fa6SAndy Green 	/* "Cyclic" == end of link points back to start of link */
648a7e08fa6SAndy Green 	ds->desc_hw[num - 1].lli |= ds->desc_hw_lli;
649a7e08fa6SAndy Green 
650a7e08fa6SAndy Green 	ds->size = total;
651a7e08fa6SAndy Green 
652a7e08fa6SAndy Green 	return vchan_tx_prep(&c->vc, &ds->vd, flags);
653a7e08fa6SAndy Green }
654a7e08fa6SAndy Green 
k3_dma_config(struct dma_chan * chan,struct dma_slave_config * cfg)655db08425eSMaxime Ripard static int k3_dma_config(struct dma_chan *chan,
656db08425eSMaxime Ripard 			 struct dma_slave_config *cfg)
6578e6152bcSZhangfei Gao {
6588e6152bcSZhangfei Gao 	struct k3_dma_chan *c = to_k3_chan(chan);
6592ae1a237SVinod Koul 
6602ae1a237SVinod Koul 	memcpy(&c->slave_config, cfg, sizeof(*cfg));
6612ae1a237SVinod Koul 
6622ae1a237SVinod Koul 	return 0;
6632ae1a237SVinod Koul }
6642ae1a237SVinod Koul 
k3_dma_config_write(struct dma_chan * chan,enum dma_transfer_direction dir,struct dma_slave_config * cfg)6652ae1a237SVinod Koul static int k3_dma_config_write(struct dma_chan *chan,
6662ae1a237SVinod Koul 			       enum dma_transfer_direction dir,
6672ae1a237SVinod Koul 			       struct dma_slave_config *cfg)
6682ae1a237SVinod Koul {
6692ae1a237SVinod Koul 	struct k3_dma_chan *c = to_k3_chan(chan);
6708e6152bcSZhangfei Gao 	u32 maxburst = 0, val = 0;
6718e6152bcSZhangfei Gao 	enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
6728e6152bcSZhangfei Gao 
6732ae1a237SVinod Koul 	if (dir == DMA_DEV_TO_MEM) {
6748e6152bcSZhangfei Gao 		c->ccfg = CX_CFG_DSTINCR;
6758e6152bcSZhangfei Gao 		c->dev_addr = cfg->src_addr;
6768e6152bcSZhangfei Gao 		maxburst = cfg->src_maxburst;
6778e6152bcSZhangfei Gao 		width = cfg->src_addr_width;
6782ae1a237SVinod Koul 	} else if (dir == DMA_MEM_TO_DEV) {
6798e6152bcSZhangfei Gao 		c->ccfg = CX_CFG_SRCINCR;
6808e6152bcSZhangfei Gao 		c->dev_addr = cfg->dst_addr;
6818e6152bcSZhangfei Gao 		maxburst = cfg->dst_maxburst;
6828e6152bcSZhangfei Gao 		width = cfg->dst_addr_width;
6838e6152bcSZhangfei Gao 	}
6848e6152bcSZhangfei Gao 	switch (width) {
6858e6152bcSZhangfei Gao 	case DMA_SLAVE_BUSWIDTH_1_BYTE:
6868e6152bcSZhangfei Gao 	case DMA_SLAVE_BUSWIDTH_2_BYTES:
6878e6152bcSZhangfei Gao 	case DMA_SLAVE_BUSWIDTH_4_BYTES:
6888e6152bcSZhangfei Gao 	case DMA_SLAVE_BUSWIDTH_8_BYTES:
6898e6152bcSZhangfei Gao 		val =  __ffs(width);
6908e6152bcSZhangfei Gao 		break;
6918e6152bcSZhangfei Gao 	default:
6928e6152bcSZhangfei Gao 		val = 3;
6938e6152bcSZhangfei Gao 		break;
6948e6152bcSZhangfei Gao 	}
6958e6152bcSZhangfei Gao 	c->ccfg |= (val << 12) | (val << 16);
6968e6152bcSZhangfei Gao 
6978e6152bcSZhangfei Gao 	if ((maxburst == 0) || (maxburst > 16))
6986c28a90fSAndy Green 		val = 15;
6998e6152bcSZhangfei Gao 	else
7008e6152bcSZhangfei Gao 		val = maxburst - 1;
7018e6152bcSZhangfei Gao 	c->ccfg |= (val << 20) | (val << 24);
7028e6152bcSZhangfei Gao 	c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
7038e6152bcSZhangfei Gao 
7048e6152bcSZhangfei Gao 	/* specific request line */
7058e6152bcSZhangfei Gao 	c->ccfg |= c->vc.chan.chan_id << 4;
7068e6152bcSZhangfei Gao 
707db08425eSMaxime Ripard 	return 0;
708db08425eSMaxime Ripard }
709db08425eSMaxime Ripard 
k3_dma_free_desc(struct virt_dma_desc * vd)71036387a2bSJohn Stultz static void k3_dma_free_desc(struct virt_dma_desc *vd)
71136387a2bSJohn Stultz {
71236387a2bSJohn Stultz 	struct k3_dma_desc_sw *ds =
71336387a2bSJohn Stultz 		container_of(vd, struct k3_dma_desc_sw, vd);
71436387a2bSJohn Stultz 	struct k3_dma_dev *d = to_k3_dma(vd->tx.chan->device);
71536387a2bSJohn Stultz 
71636387a2bSJohn Stultz 	dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli);
71736387a2bSJohn Stultz 	kfree(ds);
71836387a2bSJohn Stultz }
71936387a2bSJohn Stultz 
k3_dma_terminate_all(struct dma_chan * chan)720db08425eSMaxime Ripard static int k3_dma_terminate_all(struct dma_chan *chan)
721db08425eSMaxime Ripard {
722db08425eSMaxime Ripard 	struct k3_dma_chan *c = to_k3_chan(chan);
723db08425eSMaxime Ripard 	struct k3_dma_dev *d = to_k3_dma(chan->device);
724db08425eSMaxime Ripard 	struct k3_dma_phy *p = c->phy;
725db08425eSMaxime Ripard 	unsigned long flags;
726db08425eSMaxime Ripard 	LIST_HEAD(head);
727db08425eSMaxime Ripard 
7288e6152bcSZhangfei Gao 	dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
7298e6152bcSZhangfei Gao 
7308e6152bcSZhangfei Gao 	/* Prevent this channel being scheduled */
7318e6152bcSZhangfei Gao 	spin_lock(&d->lock);
7328e6152bcSZhangfei Gao 	list_del_init(&c->node);
7338e6152bcSZhangfei Gao 	spin_unlock(&d->lock);
7348e6152bcSZhangfei Gao 
7358e6152bcSZhangfei Gao 	/* Clear the tx descriptor lists */
7368e6152bcSZhangfei Gao 	spin_lock_irqsave(&c->vc.lock, flags);
7378e6152bcSZhangfei Gao 	vchan_get_all_descriptors(&c->vc, &head);
7388e6152bcSZhangfei Gao 	if (p) {
7398e6152bcSZhangfei Gao 		/* vchan is assigned to a pchan - stop the channel */
7408e6152bcSZhangfei Gao 		k3_dma_terminate_chan(p, d);
7418e6152bcSZhangfei Gao 		c->phy = NULL;
7428e6152bcSZhangfei Gao 		p->vchan = NULL;
74336387a2bSJohn Stultz 		if (p->ds_run) {
7443ee7e42fSPeter Ujfalusi 			vchan_terminate_vdesc(&p->ds_run->vd);
74536387a2bSJohn Stultz 			p->ds_run = NULL;
74636387a2bSJohn Stultz 		}
74736387a2bSJohn Stultz 		p->ds_done = NULL;
74836387a2bSJohn Stultz 	}
7498e6152bcSZhangfei Gao 	spin_unlock_irqrestore(&c->vc.lock, flags);
7508e6152bcSZhangfei Gao 	vchan_dma_desc_free_list(&c->vc, &head);
7518e6152bcSZhangfei Gao 
752db08425eSMaxime Ripard 	return 0;
753db08425eSMaxime Ripard }
754db08425eSMaxime Ripard 
k3_dma_synchronize(struct dma_chan * chan)7553ee7e42fSPeter Ujfalusi static void k3_dma_synchronize(struct dma_chan *chan)
7563ee7e42fSPeter Ujfalusi {
7573ee7e42fSPeter Ujfalusi 	struct k3_dma_chan *c = to_k3_chan(chan);
7583ee7e42fSPeter Ujfalusi 
7593ee7e42fSPeter Ujfalusi 	vchan_synchronize(&c->vc);
7603ee7e42fSPeter Ujfalusi }
7613ee7e42fSPeter Ujfalusi 
k3_dma_transfer_pause(struct dma_chan * chan)762a1a9becbSKrzysztof Kozlowski static int k3_dma_transfer_pause(struct dma_chan *chan)
763db08425eSMaxime Ripard {
764db08425eSMaxime Ripard 	struct k3_dma_chan *c = to_k3_chan(chan);
765db08425eSMaxime Ripard 	struct k3_dma_dev *d = to_k3_dma(chan->device);
766db08425eSMaxime Ripard 	struct k3_dma_phy *p = c->phy;
767db08425eSMaxime Ripard 
7688e6152bcSZhangfei Gao 	dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
7698e6152bcSZhangfei Gao 	if (c->status == DMA_IN_PROGRESS) {
7708e6152bcSZhangfei Gao 		c->status = DMA_PAUSED;
7718e6152bcSZhangfei Gao 		if (p) {
7728e6152bcSZhangfei Gao 			k3_dma_pause_dma(p, false);
7738e6152bcSZhangfei Gao 		} else {
7748e6152bcSZhangfei Gao 			spin_lock(&d->lock);
7758e6152bcSZhangfei Gao 			list_del_init(&c->node);
7768e6152bcSZhangfei Gao 			spin_unlock(&d->lock);
7778e6152bcSZhangfei Gao 		}
7788e6152bcSZhangfei Gao 	}
7798e6152bcSZhangfei Gao 
780db08425eSMaxime Ripard 	return 0;
781db08425eSMaxime Ripard }
782db08425eSMaxime Ripard 
k3_dma_transfer_resume(struct dma_chan * chan)783a1a9becbSKrzysztof Kozlowski static int k3_dma_transfer_resume(struct dma_chan *chan)
784db08425eSMaxime Ripard {
785db08425eSMaxime Ripard 	struct k3_dma_chan *c = to_k3_chan(chan);
786db08425eSMaxime Ripard 	struct k3_dma_dev *d = to_k3_dma(chan->device);
787db08425eSMaxime Ripard 	struct k3_dma_phy *p = c->phy;
788db08425eSMaxime Ripard 	unsigned long flags;
789db08425eSMaxime Ripard 
7908e6152bcSZhangfei Gao 	dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
7918e6152bcSZhangfei Gao 	spin_lock_irqsave(&c->vc.lock, flags);
7928e6152bcSZhangfei Gao 	if (c->status == DMA_PAUSED) {
7938e6152bcSZhangfei Gao 		c->status = DMA_IN_PROGRESS;
7948e6152bcSZhangfei Gao 		if (p) {
7958e6152bcSZhangfei Gao 			k3_dma_pause_dma(p, true);
7968e6152bcSZhangfei Gao 		} else if (!list_empty(&c->vc.desc_issued)) {
7978e6152bcSZhangfei Gao 			spin_lock(&d->lock);
7988e6152bcSZhangfei Gao 			list_add_tail(&c->node, &d->chan_pending);
7998e6152bcSZhangfei Gao 			spin_unlock(&d->lock);
8008e6152bcSZhangfei Gao 		}
8018e6152bcSZhangfei Gao 	}
8028e6152bcSZhangfei Gao 	spin_unlock_irqrestore(&c->vc.lock, flags);
803db08425eSMaxime Ripard 
8048e6152bcSZhangfei Gao 	return 0;
8058e6152bcSZhangfei Gao }
8068e6152bcSZhangfei Gao 
807d4bdc39fSYoulin Wang static const struct k3dma_soc_data k3_v1_dma_data = {
808d4bdc39fSYoulin Wang 	.flags = 0,
809d4bdc39fSYoulin Wang };
810d4bdc39fSYoulin Wang 
811d4bdc39fSYoulin Wang static const struct k3dma_soc_data asp_v1_dma_data = {
812d4bdc39fSYoulin Wang 	.flags = K3_FLAG_NOCLK,
813d4bdc39fSYoulin Wang };
814d4bdc39fSYoulin Wang 
81557c03422SFabian Frederick static const struct of_device_id k3_pdma_dt_ids[] = {
816d4bdc39fSYoulin Wang 	{ .compatible = "hisilicon,k3-dma-1.0",
817d4bdc39fSYoulin Wang 	  .data = &k3_v1_dma_data
818d4bdc39fSYoulin Wang 	},
819d4bdc39fSYoulin Wang 	{ .compatible = "hisilicon,hisi-pcm-asp-dma-1.0",
820d4bdc39fSYoulin Wang 	  .data = &asp_v1_dma_data
821d4bdc39fSYoulin Wang 	},
8228e6152bcSZhangfei Gao 	{}
8238e6152bcSZhangfei Gao };
8248e6152bcSZhangfei Gao MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
8258e6152bcSZhangfei Gao 
k3_of_dma_simple_xlate(struct of_phandle_args * dma_spec,struct of_dma * ofdma)8268e6152bcSZhangfei Gao static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
8278e6152bcSZhangfei Gao 						struct of_dma *ofdma)
8288e6152bcSZhangfei Gao {
8298e6152bcSZhangfei Gao 	struct k3_dma_dev *d = ofdma->of_dma_data;
8308e6152bcSZhangfei Gao 	unsigned int request = dma_spec->args[0];
8318e6152bcSZhangfei Gao 
832c4c2b764SDan Carpenter 	if (request >= d->dma_requests)
8338e6152bcSZhangfei Gao 		return NULL;
8348e6152bcSZhangfei Gao 
8358e6152bcSZhangfei Gao 	return dma_get_slave_channel(&(d->chans[request].vc.chan));
8368e6152bcSZhangfei Gao }
8378e6152bcSZhangfei Gao 
k3_dma_probe(struct platform_device * op)8388e6152bcSZhangfei Gao static int k3_dma_probe(struct platform_device *op)
8398e6152bcSZhangfei Gao {
840d4bdc39fSYoulin Wang 	const struct k3dma_soc_data *soc_data;
8418e6152bcSZhangfei Gao 	struct k3_dma_dev *d;
8428e6152bcSZhangfei Gao 	const struct of_device_id *of_id;
8438e6152bcSZhangfei Gao 	int i, ret, irq = 0;
8448e6152bcSZhangfei Gao 
8458e6152bcSZhangfei Gao 	d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
8468e6152bcSZhangfei Gao 	if (!d)
8478e6152bcSZhangfei Gao 		return -ENOMEM;
8488e6152bcSZhangfei Gao 
849d4bdc39fSYoulin Wang 	soc_data = device_get_match_data(&op->dev);
850d4bdc39fSYoulin Wang 	if (!soc_data)
851d4bdc39fSYoulin Wang 		return -EINVAL;
852d4bdc39fSYoulin Wang 
8533d4d6c27SMarkus Elfring 	d->base = devm_platform_ioremap_resource(op, 0);
854a576b7feSJingoo Han 	if (IS_ERR(d->base))
855a576b7feSJingoo Han 		return PTR_ERR(d->base);
8568e6152bcSZhangfei Gao 
8578e6152bcSZhangfei Gao 	of_id = of_match_device(k3_pdma_dt_ids, &op->dev);
8588e6152bcSZhangfei Gao 	if (of_id) {
8598e6152bcSZhangfei Gao 		of_property_read_u32((&op->dev)->of_node,
8608e6152bcSZhangfei Gao 				"dma-channels", &d->dma_channels);
8618e6152bcSZhangfei Gao 		of_property_read_u32((&op->dev)->of_node,
8628e6152bcSZhangfei Gao 				"dma-requests", &d->dma_requests);
863c4994a98SLi Yu 		ret = of_property_read_u32((&op->dev)->of_node,
864c4994a98SLi Yu 				"dma-channel-mask", &d->dma_channel_mask);
865c4994a98SLi Yu 		if (ret) {
866c4994a98SLi Yu 			dev_warn(&op->dev,
867c4994a98SLi Yu 				 "dma-channel-mask doesn't exist, considering all as available.\n");
868c4994a98SLi Yu 			d->dma_channel_mask = (u32)~0UL;
869c4994a98SLi Yu 		}
8708e6152bcSZhangfei Gao 	}
8718e6152bcSZhangfei Gao 
872d4bdc39fSYoulin Wang 	if (!(soc_data->flags & K3_FLAG_NOCLK)) {
8738e6152bcSZhangfei Gao 		d->clk = devm_clk_get(&op->dev, NULL);
8748e6152bcSZhangfei Gao 		if (IS_ERR(d->clk)) {
8758e6152bcSZhangfei Gao 			dev_err(&op->dev, "no dma clk\n");
8768e6152bcSZhangfei Gao 			return PTR_ERR(d->clk);
8778e6152bcSZhangfei Gao 		}
878d4bdc39fSYoulin Wang 	}
8798e6152bcSZhangfei Gao 
8808e6152bcSZhangfei Gao 	irq = platform_get_irq(op, 0);
8818e6152bcSZhangfei Gao 	ret = devm_request_irq(&op->dev, irq,
882174b537aSMichael Opdenacker 			k3_dma_int_handler, 0, DRIVER_NAME, d);
8838e6152bcSZhangfei Gao 	if (ret)
8848e6152bcSZhangfei Gao 		return ret;
8858e6152bcSZhangfei Gao 
886486b10a2SVinod Koul 	d->irq = irq;
887486b10a2SVinod Koul 
888b77f262aSJohn Stultz 	/* A DMA memory pool for LLIs, align on 32-byte boundary */
889b77f262aSJohn Stultz 	d->pool = dmam_pool_create(DRIVER_NAME, &op->dev,
890b77f262aSJohn Stultz 					LLI_BLOCK_SIZE, 32, 0);
891b77f262aSJohn Stultz 	if (!d->pool)
892b77f262aSJohn Stultz 		return -ENOMEM;
893b77f262aSJohn Stultz 
8948e6152bcSZhangfei Gao 	/* init phy channel */
895a86854d0SKees Cook 	d->phy = devm_kcalloc(&op->dev,
896a86854d0SKees Cook 		d->dma_channels, sizeof(struct k3_dma_phy), GFP_KERNEL);
8978e6152bcSZhangfei Gao 	if (d->phy == NULL)
8988e6152bcSZhangfei Gao 		return -ENOMEM;
8998e6152bcSZhangfei Gao 
9008e6152bcSZhangfei Gao 	for (i = 0; i < d->dma_channels; i++) {
901c4994a98SLi Yu 		struct k3_dma_phy *p;
9028e6152bcSZhangfei Gao 
903c4994a98SLi Yu 		if (!(d->dma_channel_mask & BIT(i)))
904c4994a98SLi Yu 			continue;
905c4994a98SLi Yu 
906c4994a98SLi Yu 		p = &d->phy[i];
9078e6152bcSZhangfei Gao 		p->idx = i;
9088e6152bcSZhangfei Gao 		p->base = d->base + i * 0x40;
9098e6152bcSZhangfei Gao 	}
9108e6152bcSZhangfei Gao 
9118e6152bcSZhangfei Gao 	INIT_LIST_HEAD(&d->slave.channels);
9128e6152bcSZhangfei Gao 	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
9138e6152bcSZhangfei Gao 	dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
914a7e08fa6SAndy Green 	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
9158e6152bcSZhangfei Gao 	d->slave.dev = &op->dev;
9168e6152bcSZhangfei Gao 	d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
9178e6152bcSZhangfei Gao 	d->slave.device_tx_status = k3_dma_tx_status;
9188e6152bcSZhangfei Gao 	d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
9198e6152bcSZhangfei Gao 	d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
920a7e08fa6SAndy Green 	d->slave.device_prep_dma_cyclic = k3_dma_prep_dma_cyclic;
9218e6152bcSZhangfei Gao 	d->slave.device_issue_pending = k3_dma_issue_pending;
922db08425eSMaxime Ripard 	d->slave.device_config = k3_dma_config;
923a1a9becbSKrzysztof Kozlowski 	d->slave.device_pause = k3_dma_transfer_pause;
924a1a9becbSKrzysztof Kozlowski 	d->slave.device_resume = k3_dma_transfer_resume;
925db08425eSMaxime Ripard 	d->slave.device_terminate_all = k3_dma_terminate_all;
9263ee7e42fSPeter Ujfalusi 	d->slave.device_synchronize = k3_dma_synchronize;
92777a68e56SMaxime Ripard 	d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES;
9288e6152bcSZhangfei Gao 
9298e6152bcSZhangfei Gao 	/* init virtual channel */
930a86854d0SKees Cook 	d->chans = devm_kcalloc(&op->dev,
931a86854d0SKees Cook 		d->dma_requests, sizeof(struct k3_dma_chan), GFP_KERNEL);
9328e6152bcSZhangfei Gao 	if (d->chans == NULL)
9338e6152bcSZhangfei Gao 		return -ENOMEM;
9348e6152bcSZhangfei Gao 
9358e6152bcSZhangfei Gao 	for (i = 0; i < d->dma_requests; i++) {
9368e6152bcSZhangfei Gao 		struct k3_dma_chan *c = &d->chans[i];
9378e6152bcSZhangfei Gao 
9388e6152bcSZhangfei Gao 		c->status = DMA_IN_PROGRESS;
9398e6152bcSZhangfei Gao 		INIT_LIST_HEAD(&c->node);
9408e6152bcSZhangfei Gao 		c->vc.desc_free = k3_dma_free_desc;
9418e6152bcSZhangfei Gao 		vchan_init(&c->vc, &d->slave);
9428e6152bcSZhangfei Gao 	}
9438e6152bcSZhangfei Gao 
9448e6152bcSZhangfei Gao 	/* Enable clock before accessing registers */
9458e6152bcSZhangfei Gao 	ret = clk_prepare_enable(d->clk);
9468e6152bcSZhangfei Gao 	if (ret < 0) {
9478e6152bcSZhangfei Gao 		dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
9488e6152bcSZhangfei Gao 		return ret;
9498e6152bcSZhangfei Gao 	}
9508e6152bcSZhangfei Gao 
9518e6152bcSZhangfei Gao 	k3_dma_enable_dma(d, true);
9528e6152bcSZhangfei Gao 
9538e6152bcSZhangfei Gao 	ret = dma_async_device_register(&d->slave);
9548e6152bcSZhangfei Gao 	if (ret)
95589b90c09SWei Yongjun 		goto dma_async_register_fail;
9568e6152bcSZhangfei Gao 
9578e6152bcSZhangfei Gao 	ret = of_dma_controller_register((&op->dev)->of_node,
9588e6152bcSZhangfei Gao 					k3_of_dma_simple_xlate, d);
9598e6152bcSZhangfei Gao 	if (ret)
9608e6152bcSZhangfei Gao 		goto of_dma_register_fail;
9618e6152bcSZhangfei Gao 
9628e6152bcSZhangfei Gao 	spin_lock_init(&d->lock);
9638e6152bcSZhangfei Gao 	INIT_LIST_HEAD(&d->chan_pending);
964881bd142SAllen Pais 	tasklet_setup(&d->task, k3_dma_tasklet);
9658e6152bcSZhangfei Gao 	platform_set_drvdata(op, d);
9668e6152bcSZhangfei Gao 	dev_info(&op->dev, "initialized\n");
9678e6152bcSZhangfei Gao 
9688e6152bcSZhangfei Gao 	return 0;
9698e6152bcSZhangfei Gao 
9708e6152bcSZhangfei Gao of_dma_register_fail:
9718e6152bcSZhangfei Gao 	dma_async_device_unregister(&d->slave);
97289b90c09SWei Yongjun dma_async_register_fail:
97389b90c09SWei Yongjun 	clk_disable_unprepare(d->clk);
9748e6152bcSZhangfei Gao 	return ret;
9758e6152bcSZhangfei Gao }
9768e6152bcSZhangfei Gao 
k3_dma_remove(struct platform_device * op)9778e6152bcSZhangfei Gao static int k3_dma_remove(struct platform_device *op)
9788e6152bcSZhangfei Gao {
9798e6152bcSZhangfei Gao 	struct k3_dma_chan *c, *cn;
9808e6152bcSZhangfei Gao 	struct k3_dma_dev *d = platform_get_drvdata(op);
9818e6152bcSZhangfei Gao 
9828e6152bcSZhangfei Gao 	dma_async_device_unregister(&d->slave);
9838e6152bcSZhangfei Gao 	of_dma_controller_free((&op->dev)->of_node);
9848e6152bcSZhangfei Gao 
985486b10a2SVinod Koul 	devm_free_irq(&op->dev, d->irq, d);
986486b10a2SVinod Koul 
9878e6152bcSZhangfei Gao 	list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
9888e6152bcSZhangfei Gao 		list_del(&c->vc.chan.device_node);
9898e6152bcSZhangfei Gao 		tasklet_kill(&c->vc.task);
9908e6152bcSZhangfei Gao 	}
9918e6152bcSZhangfei Gao 	tasklet_kill(&d->task);
9928e6152bcSZhangfei Gao 	clk_disable_unprepare(d->clk);
9938e6152bcSZhangfei Gao 	return 0;
9948e6152bcSZhangfei Gao }
9958e6152bcSZhangfei Gao 
996af2d3139SJingoo Han #ifdef CONFIG_PM_SLEEP
k3_dma_suspend_dev(struct device * dev)99710b3e223SArnd Bergmann static int k3_dma_suspend_dev(struct device *dev)
9988e6152bcSZhangfei Gao {
9998e6152bcSZhangfei Gao 	struct k3_dma_dev *d = dev_get_drvdata(dev);
10008e6152bcSZhangfei Gao 	u32 stat = 0;
10018e6152bcSZhangfei Gao 
10028e6152bcSZhangfei Gao 	stat = k3_dma_get_chan_stat(d);
10038e6152bcSZhangfei Gao 	if (stat) {
10048e6152bcSZhangfei Gao 		dev_warn(d->slave.dev,
10058e6152bcSZhangfei Gao 			"chan %d is running fail to suspend\n", stat);
10068e6152bcSZhangfei Gao 		return -1;
10078e6152bcSZhangfei Gao 	}
10088e6152bcSZhangfei Gao 	k3_dma_enable_dma(d, false);
10098e6152bcSZhangfei Gao 	clk_disable_unprepare(d->clk);
10108e6152bcSZhangfei Gao 	return 0;
10118e6152bcSZhangfei Gao }
10128e6152bcSZhangfei Gao 
k3_dma_resume_dev(struct device * dev)101310b3e223SArnd Bergmann static int k3_dma_resume_dev(struct device *dev)
10148e6152bcSZhangfei Gao {
10158e6152bcSZhangfei Gao 	struct k3_dma_dev *d = dev_get_drvdata(dev);
10168e6152bcSZhangfei Gao 	int ret = 0;
10178e6152bcSZhangfei Gao 
10188e6152bcSZhangfei Gao 	ret = clk_prepare_enable(d->clk);
10198e6152bcSZhangfei Gao 	if (ret < 0) {
10208e6152bcSZhangfei Gao 		dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
10218e6152bcSZhangfei Gao 		return ret;
10228e6152bcSZhangfei Gao 	}
10238e6152bcSZhangfei Gao 	k3_dma_enable_dma(d, true);
10248e6152bcSZhangfei Gao 	return 0;
10258e6152bcSZhangfei Gao }
1026af2d3139SJingoo Han #endif
10278e6152bcSZhangfei Gao 
102810b3e223SArnd Bergmann static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend_dev, k3_dma_resume_dev);
10298e6152bcSZhangfei Gao 
10308e6152bcSZhangfei Gao static struct platform_driver k3_pdma_driver = {
10318e6152bcSZhangfei Gao 	.driver		= {
10328e6152bcSZhangfei Gao 		.name	= DRIVER_NAME,
10338e6152bcSZhangfei Gao 		.pm	= &k3_dma_pmops,
10348e6152bcSZhangfei Gao 		.of_match_table = k3_pdma_dt_ids,
10358e6152bcSZhangfei Gao 	},
10368e6152bcSZhangfei Gao 	.probe		= k3_dma_probe,
10378e6152bcSZhangfei Gao 	.remove		= k3_dma_remove,
10388e6152bcSZhangfei Gao };
10398e6152bcSZhangfei Gao 
10408e6152bcSZhangfei Gao module_platform_driver(k3_pdma_driver);
10418e6152bcSZhangfei Gao 
1042*1b6216a6SHao Fang MODULE_DESCRIPTION("HiSilicon k3 DMA Driver");
10438e6152bcSZhangfei Gao MODULE_ALIAS("platform:k3dma");
10448e6152bcSZhangfei Gao MODULE_LICENSE("GPL v2");
1045