xref: /openbmc/linux/drivers/dma/sa11x0-dma.c (revision 07c609cc)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26365beadSRussell King /*
36365beadSRussell King  * SA11x0 DMAengine support
46365beadSRussell King  *
56365beadSRussell King  * Copyright (C) 2012 Russell King
66365beadSRussell King  *   Derived in part from arch/arm/mach-sa1100/dma.c,
76365beadSRussell King  *   Copyright (C) 2000, 2001 by Nicolas Pitre
86365beadSRussell King  */
96365beadSRussell King #include <linux/sched.h>
106365beadSRussell King #include <linux/device.h>
116365beadSRussell King #include <linux/dmaengine.h>
126365beadSRussell King #include <linux/init.h>
136365beadSRussell King #include <linux/interrupt.h>
146365beadSRussell King #include <linux/kernel.h>
156365beadSRussell King #include <linux/module.h>
166365beadSRussell King #include <linux/platform_device.h>
176365beadSRussell King #include <linux/slab.h>
186365beadSRussell King #include <linux/spinlock.h>
196365beadSRussell King 
2050437bffSRussell King #include "virt-dma.h"
2150437bffSRussell King 
226365beadSRussell King #define NR_PHY_CHAN	6
236365beadSRussell King #define DMA_ALIGN	3
246365beadSRussell King #define DMA_MAX_SIZE	0x1fff
256365beadSRussell King #define DMA_CHUNK_SIZE	0x1000
266365beadSRussell King 
276365beadSRussell King #define DMA_DDAR	0x00
286365beadSRussell King #define DMA_DCSR_S	0x04
296365beadSRussell King #define DMA_DCSR_C	0x08
306365beadSRussell King #define DMA_DCSR_R	0x0c
316365beadSRussell King #define DMA_DBSA	0x10
326365beadSRussell King #define DMA_DBTA	0x14
336365beadSRussell King #define DMA_DBSB	0x18
346365beadSRussell King #define DMA_DBTB	0x1c
356365beadSRussell King #define DMA_SIZE	0x20
366365beadSRussell King 
376365beadSRussell King #define DCSR_RUN	(1 << 0)
386365beadSRussell King #define DCSR_IE		(1 << 1)
396365beadSRussell King #define DCSR_ERROR	(1 << 2)
406365beadSRussell King #define DCSR_DONEA	(1 << 3)
416365beadSRussell King #define DCSR_STRTA	(1 << 4)
426365beadSRussell King #define DCSR_DONEB	(1 << 5)
436365beadSRussell King #define DCSR_STRTB	(1 << 6)
446365beadSRussell King #define DCSR_BIU	(1 << 7)
456365beadSRussell King 
466365beadSRussell King #define DDAR_RW		(1 << 0)	/* 0 = W, 1 = R */
476365beadSRussell King #define DDAR_E		(1 << 1)	/* 0 = LE, 1 = BE */
486365beadSRussell King #define DDAR_BS		(1 << 2)	/* 0 = BS4, 1 = BS8 */
496365beadSRussell King #define DDAR_DW		(1 << 3)	/* 0 = 8b, 1 = 16b */
506365beadSRussell King #define DDAR_Ser0UDCTr	(0x0 << 4)
516365beadSRussell King #define DDAR_Ser0UDCRc	(0x1 << 4)
526365beadSRussell King #define DDAR_Ser1SDLCTr	(0x2 << 4)
536365beadSRussell King #define DDAR_Ser1SDLCRc	(0x3 << 4)
546365beadSRussell King #define DDAR_Ser1UARTTr	(0x4 << 4)
556365beadSRussell King #define DDAR_Ser1UARTRc	(0x5 << 4)
566365beadSRussell King #define DDAR_Ser2ICPTr	(0x6 << 4)
576365beadSRussell King #define DDAR_Ser2ICPRc	(0x7 << 4)
586365beadSRussell King #define DDAR_Ser3UARTTr	(0x8 << 4)
596365beadSRussell King #define DDAR_Ser3UARTRc	(0x9 << 4)
606365beadSRussell King #define DDAR_Ser4MCP0Tr	(0xa << 4)
616365beadSRussell King #define DDAR_Ser4MCP0Rc	(0xb << 4)
626365beadSRussell King #define DDAR_Ser4MCP1Tr	(0xc << 4)
636365beadSRussell King #define DDAR_Ser4MCP1Rc	(0xd << 4)
646365beadSRussell King #define DDAR_Ser4SSPTr	(0xe << 4)
656365beadSRussell King #define DDAR_Ser4SSPRc	(0xf << 4)
666365beadSRussell King 
676365beadSRussell King struct sa11x0_dma_sg {
686365beadSRussell King 	u32			addr;
696365beadSRussell King 	u32			len;
706365beadSRussell King };
716365beadSRussell King 
726365beadSRussell King struct sa11x0_dma_desc {
7350437bffSRussell King 	struct virt_dma_desc	vd;
7450437bffSRussell King 
756365beadSRussell King 	u32			ddar;
766365beadSRussell King 	size_t			size;
77d9444325SRussell King 	unsigned		period;
78d9444325SRussell King 	bool			cyclic;
796365beadSRussell King 
806365beadSRussell King 	unsigned		sglen;
81bfb59d4aSGustavo A. R. Silva 	struct sa11x0_dma_sg	sg[];
826365beadSRussell King };
836365beadSRussell King 
846365beadSRussell King struct sa11x0_dma_phy;
856365beadSRussell King 
866365beadSRussell King struct sa11x0_dma_chan {
8750437bffSRussell King 	struct virt_dma_chan	vc;
886365beadSRussell King 
8950437bffSRussell King 	/* protected by c->vc.lock */
906365beadSRussell King 	struct sa11x0_dma_phy	*phy;
916365beadSRussell King 	enum dma_status		status;
926365beadSRussell King 
936365beadSRussell King 	/* protected by d->lock */
946365beadSRussell King 	struct list_head	node;
956365beadSRussell King 
966365beadSRussell King 	u32			ddar;
976365beadSRussell King 	const char		*name;
986365beadSRussell King };
996365beadSRussell King 
1006365beadSRussell King struct sa11x0_dma_phy {
1016365beadSRussell King 	void __iomem		*base;
1026365beadSRussell King 	struct sa11x0_dma_dev	*dev;
1036365beadSRussell King 	unsigned		num;
1046365beadSRussell King 
1056365beadSRussell King 	struct sa11x0_dma_chan	*vchan;
1066365beadSRussell King 
10750437bffSRussell King 	/* Protected by c->vc.lock */
1086365beadSRussell King 	unsigned		sg_load;
1096365beadSRussell King 	struct sa11x0_dma_desc	*txd_load;
1106365beadSRussell King 	unsigned		sg_done;
1116365beadSRussell King 	struct sa11x0_dma_desc	*txd_done;
1126365beadSRussell King 	u32			dbs[2];
1136365beadSRussell King 	u32			dbt[2];
1146365beadSRussell King 	u32			dcsr;
1156365beadSRussell King };
1166365beadSRussell King 
1176365beadSRussell King struct sa11x0_dma_dev {
1186365beadSRussell King 	struct dma_device	slave;
1196365beadSRussell King 	void __iomem		*base;
1206365beadSRussell King 	spinlock_t		lock;
1216365beadSRussell King 	struct tasklet_struct	task;
1226365beadSRussell King 	struct list_head	chan_pending;
1236365beadSRussell King 	struct sa11x0_dma_phy	phy[NR_PHY_CHAN];
1246365beadSRussell King };
1256365beadSRussell King 
to_sa11x0_dma_chan(struct dma_chan * chan)1266365beadSRussell King static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
1276365beadSRussell King {
12850437bffSRussell King 	return container_of(chan, struct sa11x0_dma_chan, vc.chan);
1296365beadSRussell King }
1306365beadSRussell King 
to_sa11x0_dma(struct dma_device * dmadev)1316365beadSRussell King static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
1326365beadSRussell King {
1336365beadSRussell King 	return container_of(dmadev, struct sa11x0_dma_dev, slave);
1346365beadSRussell King }
1356365beadSRussell King 
sa11x0_dma_next_desc(struct sa11x0_dma_chan * c)1366365beadSRussell King static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
1376365beadSRussell King {
13850437bffSRussell King 	struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
1396365beadSRussell King 
14050437bffSRussell King 	return vd ? container_of(vd, struct sa11x0_dma_desc, vd) : NULL;
14150437bffSRussell King }
14250437bffSRussell King 
sa11x0_dma_free_desc(struct virt_dma_desc * vd)14350437bffSRussell King static void sa11x0_dma_free_desc(struct virt_dma_desc *vd)
14450437bffSRussell King {
14550437bffSRussell King 	kfree(container_of(vd, struct sa11x0_dma_desc, vd));
1466365beadSRussell King }
1476365beadSRussell King 
sa11x0_dma_start_desc(struct sa11x0_dma_phy * p,struct sa11x0_dma_desc * txd)1486365beadSRussell King static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
1496365beadSRussell King {
15050437bffSRussell King 	list_del(&txd->vd.node);
1516365beadSRussell King 	p->txd_load = txd;
1526365beadSRussell King 	p->sg_load = 0;
1536365beadSRussell King 
1546365beadSRussell King 	dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
15550437bffSRussell King 		p->num, &txd->vd, txd->vd.tx.cookie, txd->ddar);
1566365beadSRussell King }
1576365beadSRussell King 
sa11x0_dma_start_sg(struct sa11x0_dma_phy * p,struct sa11x0_dma_chan * c)1586365beadSRussell King static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
1596365beadSRussell King 	struct sa11x0_dma_chan *c)
1606365beadSRussell King {
1616365beadSRussell King 	struct sa11x0_dma_desc *txd = p->txd_load;
1626365beadSRussell King 	struct sa11x0_dma_sg *sg;
1636365beadSRussell King 	void __iomem *base = p->base;
1646365beadSRussell King 	unsigned dbsx, dbtx;
1656365beadSRussell King 	u32 dcsr;
1666365beadSRussell King 
1676365beadSRussell King 	if (!txd)
1686365beadSRussell King 		return;
1696365beadSRussell King 
1706365beadSRussell King 	dcsr = readl_relaxed(base + DMA_DCSR_R);
1716365beadSRussell King 
1726365beadSRussell King 	/* Don't try to load the next transfer if both buffers are started */
1736365beadSRussell King 	if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
1746365beadSRussell King 		return;
1756365beadSRussell King 
1766365beadSRussell King 	if (p->sg_load == txd->sglen) {
177d9444325SRussell King 		if (!txd->cyclic) {
1786365beadSRussell King 			struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
1796365beadSRussell King 
1806365beadSRussell King 			/*
1816365beadSRussell King 			 * We have reached the end of the current descriptor.
1826365beadSRussell King 			 * Peek at the next descriptor, and if compatible with
1836365beadSRussell King 			 * the current, start processing it.
1846365beadSRussell King 			 */
1856365beadSRussell King 			if (txn && txn->ddar == txd->ddar) {
1866365beadSRussell King 				txd = txn;
1876365beadSRussell King 				sa11x0_dma_start_desc(p, txn);
1886365beadSRussell King 			} else {
1896365beadSRussell King 				p->txd_load = NULL;
1906365beadSRussell King 				return;
1916365beadSRussell King 			}
192d9444325SRussell King 		} else {
193d9444325SRussell King 			/* Cyclic: reset back to beginning */
194d9444325SRussell King 			p->sg_load = 0;
195d9444325SRussell King 		}
1966365beadSRussell King 	}
1976365beadSRussell King 
1986365beadSRussell King 	sg = &txd->sg[p->sg_load++];
1996365beadSRussell King 
2006365beadSRussell King 	/* Select buffer to load according to channel status */
2016365beadSRussell King 	if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
2026365beadSRussell King 	    ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
2036365beadSRussell King 		dbsx = DMA_DBSA;
2046365beadSRussell King 		dbtx = DMA_DBTA;
2056365beadSRussell King 		dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
2066365beadSRussell King 	} else {
2076365beadSRussell King 		dbsx = DMA_DBSB;
2086365beadSRussell King 		dbtx = DMA_DBTB;
2096365beadSRussell King 		dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
2106365beadSRussell King 	}
2116365beadSRussell King 
2126365beadSRussell King 	writel_relaxed(sg->addr, base + dbsx);
2136365beadSRussell King 	writel_relaxed(sg->len, base + dbtx);
2146365beadSRussell King 	writel(dcsr, base + DMA_DCSR_S);
2156365beadSRussell King 
2166365beadSRussell King 	dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
2176365beadSRussell King 		p->num, dcsr,
2186365beadSRussell King 		'A' + (dbsx == DMA_DBSB), sg->addr,
2196365beadSRussell King 		'A' + (dbtx == DMA_DBTB), sg->len);
2206365beadSRussell King }
2216365beadSRussell King 
sa11x0_dma_complete(struct sa11x0_dma_phy * p,struct sa11x0_dma_chan * c)2226365beadSRussell King static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
2236365beadSRussell King 	struct sa11x0_dma_chan *c)
2246365beadSRussell King {
2256365beadSRussell King 	struct sa11x0_dma_desc *txd = p->txd_done;
2266365beadSRussell King 
2276365beadSRussell King 	if (++p->sg_done == txd->sglen) {
228d9444325SRussell King 		if (!txd->cyclic) {
22950437bffSRussell King 			vchan_cookie_complete(&txd->vd);
2306365beadSRussell King 
2316365beadSRussell King 			p->sg_done = 0;
2326365beadSRussell King 			p->txd_done = p->txd_load;
2336365beadSRussell King 
23450437bffSRussell King 			if (!p->txd_done)
23550437bffSRussell King 				tasklet_schedule(&p->dev->task);
236d9444325SRussell King 		} else {
237d9444325SRussell King 			if ((p->sg_done % txd->period) == 0)
238d9444325SRussell King 				vchan_cyclic_callback(&txd->vd);
239d9444325SRussell King 
240d9444325SRussell King 			/* Cyclic: reset back to beginning */
241d9444325SRussell King 			p->sg_done = 0;
242d9444325SRussell King 		}
2436365beadSRussell King 	}
2446365beadSRussell King 
2456365beadSRussell King 	sa11x0_dma_start_sg(p, c);
2466365beadSRussell King }
2476365beadSRussell King 
sa11x0_dma_irq(int irq,void * dev_id)2486365beadSRussell King static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
2496365beadSRussell King {
2506365beadSRussell King 	struct sa11x0_dma_phy *p = dev_id;
2516365beadSRussell King 	struct sa11x0_dma_dev *d = p->dev;
2526365beadSRussell King 	struct sa11x0_dma_chan *c;
2536365beadSRussell King 	u32 dcsr;
2546365beadSRussell King 
2556365beadSRussell King 	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
2566365beadSRussell King 	if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
2576365beadSRussell King 		return IRQ_NONE;
2586365beadSRussell King 
2596365beadSRussell King 	/* Clear reported status bits */
2606365beadSRussell King 	writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
2616365beadSRussell King 		p->base + DMA_DCSR_C);
2626365beadSRussell King 
2636365beadSRussell King 	dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
2646365beadSRussell King 
2656365beadSRussell King 	if (dcsr & DCSR_ERROR) {
2666365beadSRussell King 		dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
2676365beadSRussell King 			p->num, dcsr,
2686365beadSRussell King 			readl_relaxed(p->base + DMA_DDAR),
2696365beadSRussell King 			readl_relaxed(p->base + DMA_DBSA),
2706365beadSRussell King 			readl_relaxed(p->base + DMA_DBTA),
2716365beadSRussell King 			readl_relaxed(p->base + DMA_DBSB),
2726365beadSRussell King 			readl_relaxed(p->base + DMA_DBTB));
2736365beadSRussell King 	}
2746365beadSRussell King 
2756365beadSRussell King 	c = p->vchan;
2766365beadSRussell King 	if (c) {
2776365beadSRussell King 		unsigned long flags;
2786365beadSRussell King 
27950437bffSRussell King 		spin_lock_irqsave(&c->vc.lock, flags);
2806365beadSRussell King 		/*
2816365beadSRussell King 		 * Now that we're holding the lock, check that the vchan
2826365beadSRussell King 		 * really is associated with this pchan before touching the
2836365beadSRussell King 		 * hardware.  This should always succeed, because we won't
2846365beadSRussell King 		 * change p->vchan or c->phy while the channel is actively
2856365beadSRussell King 		 * transferring.
2866365beadSRussell King 		 */
2876365beadSRussell King 		if (c->phy == p) {
2886365beadSRussell King 			if (dcsr & DCSR_DONEA)
2896365beadSRussell King 				sa11x0_dma_complete(p, c);
2906365beadSRussell King 			if (dcsr & DCSR_DONEB)
2916365beadSRussell King 				sa11x0_dma_complete(p, c);
2926365beadSRussell King 		}
29350437bffSRussell King 		spin_unlock_irqrestore(&c->vc.lock, flags);
2946365beadSRussell King 	}
2956365beadSRussell King 
2966365beadSRussell King 	return IRQ_HANDLED;
2976365beadSRussell King }
2986365beadSRussell King 
sa11x0_dma_start_txd(struct sa11x0_dma_chan * c)2996365beadSRussell King static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
3006365beadSRussell King {
3016365beadSRussell King 	struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
3026365beadSRussell King 
3036365beadSRussell King 	/* If the issued list is empty, we have no further txds to process */
3046365beadSRussell King 	if (txd) {
3056365beadSRussell King 		struct sa11x0_dma_phy *p = c->phy;
3066365beadSRussell King 
3076365beadSRussell King 		sa11x0_dma_start_desc(p, txd);
3086365beadSRussell King 		p->txd_done = txd;
3096365beadSRussell King 		p->sg_done = 0;
3106365beadSRussell King 
3116365beadSRussell King 		/* The channel should not have any transfers started */
3126365beadSRussell King 		WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
3136365beadSRussell King 				      (DCSR_STRTA | DCSR_STRTB));
3146365beadSRussell King 
3156365beadSRussell King 		/* Clear the run and start bits before changing DDAR */
3166365beadSRussell King 		writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
3176365beadSRussell King 			       p->base + DMA_DCSR_C);
3186365beadSRussell King 		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
3196365beadSRussell King 
3206365beadSRussell King 		/* Try to start both buffers */
3216365beadSRussell King 		sa11x0_dma_start_sg(p, c);
3226365beadSRussell King 		sa11x0_dma_start_sg(p, c);
3236365beadSRussell King 	}
3246365beadSRussell King }
3256365beadSRussell King 
sa11x0_dma_tasklet(struct tasklet_struct * t)3268a536883SAllen Pais static void sa11x0_dma_tasklet(struct tasklet_struct *t)
3276365beadSRussell King {
3288a536883SAllen Pais 	struct sa11x0_dma_dev *d = from_tasklet(d, t, task);
3296365beadSRussell King 	struct sa11x0_dma_phy *p;
3306365beadSRussell King 	struct sa11x0_dma_chan *c;
3316365beadSRussell King 	unsigned pch, pch_alloc = 0;
3326365beadSRussell King 
3336365beadSRussell King 	dev_dbg(d->slave.dev, "tasklet enter\n");
3346365beadSRussell King 
33550437bffSRussell King 	list_for_each_entry(c, &d->slave.channels, vc.chan.device_node) {
33650437bffSRussell King 		spin_lock_irq(&c->vc.lock);
3376365beadSRussell King 		p = c->phy;
33850437bffSRussell King 		if (p && !p->txd_done) {
3396365beadSRussell King 			sa11x0_dma_start_txd(c);
3406365beadSRussell King 			if (!p->txd_done) {
3416365beadSRussell King 				/* No current txd associated with this channel */
3426365beadSRussell King 				dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
3436365beadSRussell King 
3446365beadSRussell King 				/* Mark this channel free */
3456365beadSRussell King 				c->phy = NULL;
3466365beadSRussell King 				p->vchan = NULL;
3476365beadSRussell King 			}
3486365beadSRussell King 		}
34950437bffSRussell King 		spin_unlock_irq(&c->vc.lock);
3506365beadSRussell King 	}
3516365beadSRussell King 
3526365beadSRussell King 	spin_lock_irq(&d->lock);
3536365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
3546365beadSRussell King 		p = &d->phy[pch];
3556365beadSRussell King 
3566365beadSRussell King 		if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
3576365beadSRussell King 			c = list_first_entry(&d->chan_pending,
3586365beadSRussell King 				struct sa11x0_dma_chan, node);
3596365beadSRussell King 			list_del_init(&c->node);
3606365beadSRussell King 
3616365beadSRussell King 			pch_alloc |= 1 << pch;
3626365beadSRussell King 
3636365beadSRussell King 			/* Mark this channel allocated */
3646365beadSRussell King 			p->vchan = c;
3656365beadSRussell King 
36650437bffSRussell King 			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
3676365beadSRussell King 		}
3686365beadSRussell King 	}
3696365beadSRussell King 	spin_unlock_irq(&d->lock);
3706365beadSRussell King 
3716365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
3726365beadSRussell King 		if (pch_alloc & (1 << pch)) {
3736365beadSRussell King 			p = &d->phy[pch];
3746365beadSRussell King 			c = p->vchan;
3756365beadSRussell King 
37650437bffSRussell King 			spin_lock_irq(&c->vc.lock);
3776365beadSRussell King 			c->phy = p;
3786365beadSRussell King 
3796365beadSRussell King 			sa11x0_dma_start_txd(c);
38050437bffSRussell King 			spin_unlock_irq(&c->vc.lock);
3816365beadSRussell King 		}
3826365beadSRussell King 	}
3836365beadSRussell King 
3846365beadSRussell King 	dev_dbg(d->slave.dev, "tasklet exit\n");
3856365beadSRussell King }
3866365beadSRussell King 
3876365beadSRussell King 
sa11x0_dma_free_chan_resources(struct dma_chan * chan)3886365beadSRussell King static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
3896365beadSRussell King {
3906365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
3916365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
3926365beadSRussell King 	unsigned long flags;
3936365beadSRussell King 
39450437bffSRussell King 	spin_lock_irqsave(&d->lock, flags);
3956365beadSRussell King 	list_del_init(&c->node);
39650437bffSRussell King 	spin_unlock_irqrestore(&d->lock, flags);
3976365beadSRussell King 
39850437bffSRussell King 	vchan_free_chan_resources(&c->vc);
3996365beadSRussell King }
4006365beadSRussell King 
sa11x0_dma_pos(struct sa11x0_dma_phy * p)4016365beadSRussell King static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
4026365beadSRussell King {
4036365beadSRussell King 	unsigned reg;
4046365beadSRussell King 	u32 dcsr;
4056365beadSRussell King 
4066365beadSRussell King 	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
4076365beadSRussell King 
4086365beadSRussell King 	if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
4096365beadSRussell King 	    (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
4106365beadSRussell King 		reg = DMA_DBSA;
4116365beadSRussell King 	else
4126365beadSRussell King 		reg = DMA_DBSB;
4136365beadSRussell King 
4146365beadSRussell King 	return readl_relaxed(p->base + reg);
4156365beadSRussell King }
4166365beadSRussell King 
sa11x0_dma_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * state)4176365beadSRussell King static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
4186365beadSRussell King 	dma_cookie_t cookie, struct dma_tx_state *state)
4196365beadSRussell King {
4206365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
4216365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
4226365beadSRussell King 	struct sa11x0_dma_phy *p;
42363fe23c3SRussell King 	struct virt_dma_desc *vd;
4246365beadSRussell King 	unsigned long flags;
4256365beadSRussell King 	enum dma_status ret;
4266365beadSRussell King 
42750437bffSRussell King 	ret = dma_cookie_status(&c->vc.chan, cookie, state);
428fdebb768SVinod Koul 	if (ret == DMA_COMPLETE)
4296365beadSRussell King 		return ret;
4306365beadSRussell King 
43163fe23c3SRussell King 	if (!state)
43263fe23c3SRussell King 		return c->status;
43363fe23c3SRussell King 
43450437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
4356365beadSRussell King 	p = c->phy;
43663fe23c3SRussell King 
43763fe23c3SRussell King 	/*
43863fe23c3SRussell King 	 * If the cookie is on our issue queue, then the residue is
43963fe23c3SRussell King 	 * its total size.
44063fe23c3SRussell King 	 */
44163fe23c3SRussell King 	vd = vchan_find_desc(&c->vc, cookie);
44263fe23c3SRussell King 	if (vd) {
44363fe23c3SRussell King 		state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size;
44463fe23c3SRussell King 	} else if (!p) {
44563fe23c3SRussell King 		state->residue = 0;
44663fe23c3SRussell King 	} else {
44763fe23c3SRussell King 		struct sa11x0_dma_desc *txd;
44863fe23c3SRussell King 		size_t bytes = 0;
44963fe23c3SRussell King 
45063fe23c3SRussell King 		if (p->txd_done && p->txd_done->vd.tx.cookie == cookie)
45163fe23c3SRussell King 			txd = p->txd_done;
45263fe23c3SRussell King 		else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie)
45363fe23c3SRussell King 			txd = p->txd_load;
45463fe23c3SRussell King 		else
45563fe23c3SRussell King 			txd = NULL;
45663fe23c3SRussell King 
4576365beadSRussell King 		ret = c->status;
45863fe23c3SRussell King 		if (txd) {
4596365beadSRussell King 			dma_addr_t addr = sa11x0_dma_pos(p);
46063fe23c3SRussell King 			unsigned i;
4616365beadSRussell King 
462f92e934dSVinod Koul 			dev_vdbg(d->slave.dev, "tx_status: addr:%pad\n", &addr);
4636365beadSRussell King 
4646365beadSRussell King 			for (i = 0; i < txd->sglen; i++) {
4656365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
4666365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4676365beadSRussell King 				if (addr >= txd->sg[i].addr &&
4686365beadSRussell King 				    addr < txd->sg[i].addr + txd->sg[i].len) {
4696365beadSRussell King 					unsigned len;
4706365beadSRussell King 
4716365beadSRussell King 					len = txd->sg[i].len -
4726365beadSRussell King 						(addr - txd->sg[i].addr);
4736365beadSRussell King 					dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
4746365beadSRussell King 						i, len);
4756365beadSRussell King 					bytes += len;
4766365beadSRussell King 					i++;
4776365beadSRussell King 					break;
4786365beadSRussell King 				}
4796365beadSRussell King 			}
4806365beadSRussell King 			for (; i < txd->sglen; i++) {
4816365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
4826365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4836365beadSRussell King 				bytes += txd->sg[i].len;
4846365beadSRussell King 			}
4856365beadSRussell King 		}
48663fe23c3SRussell King 		state->residue = bytes;
4876365beadSRussell King 	}
48850437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
4896365beadSRussell King 
490872b4af4SVinod Koul 	dev_vdbg(d->slave.dev, "tx_status: bytes 0x%x\n", state->residue);
4916365beadSRussell King 
4926365beadSRussell King 	return ret;
4936365beadSRussell King }
4946365beadSRussell King 
4956365beadSRussell King /*
4966365beadSRussell King  * Move pending txds to the issued list, and re-init pending list.
4976365beadSRussell King  * If not already pending, add this channel to the list of pending
4986365beadSRussell King  * channels and trigger the tasklet to run.
4996365beadSRussell King  */
sa11x0_dma_issue_pending(struct dma_chan * chan)5006365beadSRussell King static void sa11x0_dma_issue_pending(struct dma_chan *chan)
5016365beadSRussell King {
5026365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5036365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
5046365beadSRussell King 	unsigned long flags;
5056365beadSRussell King 
50650437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
50750437bffSRussell King 	if (vchan_issue_pending(&c->vc)) {
50850437bffSRussell King 		if (!c->phy) {
5096365beadSRussell King 			spin_lock(&d->lock);
51050437bffSRussell King 			if (list_empty(&c->node)) {
5116365beadSRussell King 				list_add_tail(&c->node, &d->chan_pending);
5126365beadSRussell King 				tasklet_schedule(&d->task);
51350437bffSRussell King 				dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
5146365beadSRussell King 			}
5156365beadSRussell King 			spin_unlock(&d->lock);
5166365beadSRussell King 		}
51750437bffSRussell King 	} else
51850437bffSRussell King 		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
51950437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
5206365beadSRussell King }
5216365beadSRussell King 
sa11x0_dma_prep_slave_sg(struct dma_chan * chan,struct scatterlist * sg,unsigned int sglen,enum dma_transfer_direction dir,unsigned long flags,void * context)5226365beadSRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
5236365beadSRussell King 	struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
524d9d54540SRussell King 	enum dma_transfer_direction dir, unsigned long flags, void *context)
5256365beadSRussell King {
5266365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5276365beadSRussell King 	struct sa11x0_dma_desc *txd;
5286365beadSRussell King 	struct scatterlist *sgent;
5296365beadSRussell King 	unsigned i, j = sglen;
5306365beadSRussell King 	size_t size = 0;
5316365beadSRussell King 
5326365beadSRussell King 	/* SA11x0 channels can only operate in their native direction */
5336365beadSRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
5346365beadSRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
53550437bffSRussell King 			&c->vc, c->ddar, dir);
5366365beadSRussell King 		return NULL;
5376365beadSRussell King 	}
5386365beadSRussell King 
5396365beadSRussell King 	/* Do not allow zero-sized txds */
5406365beadSRussell King 	if (sglen == 0)
5416365beadSRussell King 		return NULL;
5426365beadSRussell King 
5436365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5446365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5456365beadSRussell King 		unsigned int len = sg_dma_len(sgent);
5466365beadSRussell King 
5476365beadSRussell King 		if (len > DMA_MAX_SIZE)
5486365beadSRussell King 			j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
5496365beadSRussell King 		if (addr & DMA_ALIGN) {
550f92e934dSVinod Koul 			dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %pad\n",
551f92e934dSVinod Koul 				&c->vc, &addr);
5526365beadSRussell King 			return NULL;
5536365beadSRussell King 		}
5546365beadSRussell King 	}
5556365beadSRussell King 
556acafe7e3SKees Cook 	txd = kzalloc(struct_size(txd, sg, j), GFP_ATOMIC);
5576365beadSRussell King 	if (!txd) {
55850437bffSRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
5596365beadSRussell King 		return NULL;
5606365beadSRussell King 	}
5616365beadSRussell King 
5626365beadSRussell King 	j = 0;
5636365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5646365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5656365beadSRussell King 		unsigned len = sg_dma_len(sgent);
5666365beadSRussell King 
5676365beadSRussell King 		size += len;
5686365beadSRussell King 
5696365beadSRussell King 		do {
5706365beadSRussell King 			unsigned tlen = len;
5716365beadSRussell King 
5726365beadSRussell King 			/*
5736365beadSRussell King 			 * Check whether the transfer will fit.  If not, try
5746365beadSRussell King 			 * to split the transfer up such that we end up with
5756365beadSRussell King 			 * equal chunks - but make sure that we preserve the
5766365beadSRussell King 			 * alignment.  This avoids small segments.
5776365beadSRussell King 			 */
5786365beadSRussell King 			if (tlen > DMA_MAX_SIZE) {
5796365beadSRussell King 				unsigned mult = DIV_ROUND_UP(tlen,
5806365beadSRussell King 					DMA_MAX_SIZE & ~DMA_ALIGN);
5816365beadSRussell King 
5826365beadSRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
5836365beadSRussell King 			}
5846365beadSRussell King 
5856365beadSRussell King 			txd->sg[j].addr = addr;
5866365beadSRussell King 			txd->sg[j].len = tlen;
5876365beadSRussell King 
5886365beadSRussell King 			addr += tlen;
5896365beadSRussell King 			len -= tlen;
5906365beadSRussell King 			j++;
5916365beadSRussell King 		} while (len);
5926365beadSRussell King 	}
5936365beadSRussell King 
5946365beadSRussell King 	txd->ddar = c->ddar;
5956365beadSRussell King 	txd->size = size;
5966365beadSRussell King 	txd->sglen = j;
5976365beadSRussell King 
598762ff31dSVinod Koul 	dev_dbg(chan->device->dev, "vchan %p: txd %p: size %zu nr %u\n",
59950437bffSRussell King 		&c->vc, &txd->vd, txd->size, txd->sglen);
6006365beadSRussell King 
60150437bffSRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, flags);
6026365beadSRussell King }
6036365beadSRussell King 
sa11x0_dma_prep_dma_cyclic(struct dma_chan * chan,dma_addr_t addr,size_t size,size_t period,enum dma_transfer_direction dir,unsigned long flags)604d9444325SRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(
605d9444325SRussell King 	struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period,
60631c1e5a1SLaurent Pinchart 	enum dma_transfer_direction dir, unsigned long flags)
607d9444325SRussell King {
608d9444325SRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
609d9444325SRussell King 	struct sa11x0_dma_desc *txd;
610d9444325SRussell King 	unsigned i, j, k, sglen, sgperiod;
611d9444325SRussell King 
612d9444325SRussell King 	/* SA11x0 channels can only operate in their native direction */
613d9444325SRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
614d9444325SRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
615d9444325SRussell King 			&c->vc, c->ddar, dir);
616d9444325SRussell King 		return NULL;
617d9444325SRussell King 	}
618d9444325SRussell King 
619d9444325SRussell King 	sgperiod = DIV_ROUND_UP(period, DMA_MAX_SIZE & ~DMA_ALIGN);
620d9444325SRussell King 	sglen = size * sgperiod / period;
621d9444325SRussell King 
622d9444325SRussell King 	/* Do not allow zero-sized txds */
623d9444325SRussell King 	if (sglen == 0)
624d9444325SRussell King 		return NULL;
625d9444325SRussell King 
626acafe7e3SKees Cook 	txd = kzalloc(struct_size(txd, sg, sglen), GFP_ATOMIC);
627d9444325SRussell King 	if (!txd) {
628d9444325SRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
629d9444325SRussell King 		return NULL;
630d9444325SRussell King 	}
631d9444325SRussell King 
632d9444325SRussell King 	for (i = k = 0; i < size / period; i++) {
633d9444325SRussell King 		size_t tlen, len = period;
634d9444325SRussell King 
635d9444325SRussell King 		for (j = 0; j < sgperiod; j++, k++) {
636d9444325SRussell King 			tlen = len;
637d9444325SRussell King 
638d9444325SRussell King 			if (tlen > DMA_MAX_SIZE) {
639d9444325SRussell King 				unsigned mult = DIV_ROUND_UP(tlen, DMA_MAX_SIZE & ~DMA_ALIGN);
640d9444325SRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
641d9444325SRussell King 			}
642d9444325SRussell King 
643d9444325SRussell King 			txd->sg[k].addr = addr;
644d9444325SRussell King 			txd->sg[k].len = tlen;
645d9444325SRussell King 			addr += tlen;
646d9444325SRussell King 			len -= tlen;
647d9444325SRussell King 		}
648d9444325SRussell King 
649d9444325SRussell King 		WARN_ON(len != 0);
650d9444325SRussell King 	}
651d9444325SRussell King 
652d9444325SRussell King 	WARN_ON(k != sglen);
653d9444325SRussell King 
654d9444325SRussell King 	txd->ddar = c->ddar;
655d9444325SRussell King 	txd->size = size;
656d9444325SRussell King 	txd->sglen = sglen;
657d9444325SRussell King 	txd->cyclic = 1;
658d9444325SRussell King 	txd->period = sgperiod;
659d9444325SRussell King 
660d9444325SRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
661d9444325SRussell King }
662d9444325SRussell King 
sa11x0_dma_device_config(struct dma_chan * chan,struct dma_slave_config * cfg)663a0a51a64SMaxime Ripard static int sa11x0_dma_device_config(struct dma_chan *chan,
6644a533218SMaxime Ripard 				    struct dma_slave_config *cfg)
6656365beadSRussell King {
6664a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
6676365beadSRussell King 	u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
6686365beadSRussell King 	dma_addr_t addr;
6696365beadSRussell King 	enum dma_slave_buswidth width;
6706365beadSRussell King 	u32 maxburst;
6716365beadSRussell King 
6726365beadSRussell King 	if (ddar & DDAR_RW) {
6736365beadSRussell King 		addr = cfg->src_addr;
6746365beadSRussell King 		width = cfg->src_addr_width;
6756365beadSRussell King 		maxburst = cfg->src_maxburst;
6766365beadSRussell King 	} else {
6776365beadSRussell King 		addr = cfg->dst_addr;
6786365beadSRussell King 		width = cfg->dst_addr_width;
6796365beadSRussell King 		maxburst = cfg->dst_maxburst;
6806365beadSRussell King 	}
6816365beadSRussell King 
6826365beadSRussell King 	if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
6836365beadSRussell King 	     width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
6846365beadSRussell King 	    (maxburst != 4 && maxburst != 8))
6856365beadSRussell King 		return -EINVAL;
6866365beadSRussell King 
6876365beadSRussell King 	if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
6886365beadSRussell King 		ddar |= DDAR_DW;
6896365beadSRussell King 	if (maxburst == 8)
6906365beadSRussell King 		ddar |= DDAR_BS;
6916365beadSRussell King 
692f92e934dSVinod Koul 	dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %pad width %u burst %u\n",
693f92e934dSVinod Koul 		&c->vc, &addr, width, maxburst);
6946365beadSRussell King 
6956365beadSRussell King 	c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
6966365beadSRussell King 
6976365beadSRussell King 	return 0;
6986365beadSRussell King }
6996365beadSRussell King 
sa11x0_dma_device_pause(struct dma_chan * chan)700a0a51a64SMaxime Ripard static int sa11x0_dma_device_pause(struct dma_chan *chan)
7016365beadSRussell King {
7026365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7036365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7046365beadSRussell King 	struct sa11x0_dma_phy *p;
7056365beadSRussell King 	unsigned long flags;
7066365beadSRussell King 
7074a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
7084a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7094a533218SMaxime Ripard 	if (c->status == DMA_IN_PROGRESS) {
7104a533218SMaxime Ripard 		c->status = DMA_PAUSED;
7116365beadSRussell King 
7124a533218SMaxime Ripard 		p = c->phy;
7134a533218SMaxime Ripard 		if (p) {
7144a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
7154a533218SMaxime Ripard 		} else {
7164a533218SMaxime Ripard 			spin_lock(&d->lock);
7174a533218SMaxime Ripard 			list_del_init(&c->node);
7184a533218SMaxime Ripard 			spin_unlock(&d->lock);
7194a533218SMaxime Ripard 		}
7204a533218SMaxime Ripard 	}
7214a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7224a533218SMaxime Ripard 
7234a533218SMaxime Ripard 	return 0;
7244a533218SMaxime Ripard }
7254a533218SMaxime Ripard 
sa11x0_dma_device_resume(struct dma_chan * chan)726a0a51a64SMaxime Ripard static int sa11x0_dma_device_resume(struct dma_chan *chan)
7274a533218SMaxime Ripard {
7284a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7294a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7304a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7314a533218SMaxime Ripard 	unsigned long flags;
7324a533218SMaxime Ripard 
7334a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
7344a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7354a533218SMaxime Ripard 	if (c->status == DMA_PAUSED) {
7364a533218SMaxime Ripard 		c->status = DMA_IN_PROGRESS;
7374a533218SMaxime Ripard 
7384a533218SMaxime Ripard 		p = c->phy;
7394a533218SMaxime Ripard 		if (p) {
7404a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
7414a533218SMaxime Ripard 		} else if (!list_empty(&c->vc.desc_issued)) {
7424a533218SMaxime Ripard 			spin_lock(&d->lock);
7434a533218SMaxime Ripard 			list_add_tail(&c->node, &d->chan_pending);
7444a533218SMaxime Ripard 			spin_unlock(&d->lock);
7454a533218SMaxime Ripard 		}
7464a533218SMaxime Ripard 	}
7474a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7484a533218SMaxime Ripard 
7494a533218SMaxime Ripard 	return 0;
7504a533218SMaxime Ripard }
7514a533218SMaxime Ripard 
sa11x0_dma_device_terminate_all(struct dma_chan * chan)752a0a51a64SMaxime Ripard static int sa11x0_dma_device_terminate_all(struct dma_chan *chan)
7534a533218SMaxime Ripard {
7544a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7554a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7564a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7574a533218SMaxime Ripard 	LIST_HEAD(head);
7584a533218SMaxime Ripard 	unsigned long flags;
7594a533218SMaxime Ripard 
76050437bffSRussell King 	dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
7616365beadSRussell King 	/* Clear the tx descriptor lists */
76250437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
76350437bffSRussell King 	vchan_get_all_descriptors(&c->vc, &head);
7646365beadSRussell King 
7656365beadSRussell King 	p = c->phy;
7666365beadSRussell King 	if (p) {
7676365beadSRussell King 		dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
7686365beadSRussell King 		/* vchan is assigned to a pchan - stop the channel */
7696365beadSRussell King 		writel(DCSR_RUN | DCSR_IE |
7706365beadSRussell King 		       DCSR_STRTA | DCSR_DONEA |
7716365beadSRussell King 		       DCSR_STRTB | DCSR_DONEB,
7726365beadSRussell King 		       p->base + DMA_DCSR_C);
7736365beadSRussell King 
7746365beadSRussell King 		if (p->txd_load) {
7756365beadSRussell King 			if (p->txd_load != p->txd_done)
77650437bffSRussell King 				list_add_tail(&p->txd_load->vd.node, &head);
7776365beadSRussell King 			p->txd_load = NULL;
7786365beadSRussell King 		}
7796365beadSRussell King 		if (p->txd_done) {
78050437bffSRussell King 			list_add_tail(&p->txd_done->vd.node, &head);
7816365beadSRussell King 			p->txd_done = NULL;
7826365beadSRussell King 		}
7836365beadSRussell King 		c->phy = NULL;
7846365beadSRussell King 		spin_lock(&d->lock);
7856365beadSRussell King 		p->vchan = NULL;
7866365beadSRussell King 		spin_unlock(&d->lock);
7876365beadSRussell King 		tasklet_schedule(&d->task);
7886365beadSRussell King 	}
78950437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
79050437bffSRussell King 	vchan_dma_desc_free_list(&c->vc, &head);
7916365beadSRussell King 
7924a533218SMaxime Ripard 	return 0;
7936365beadSRussell King }
7946365beadSRussell King 
7956365beadSRussell King struct sa11x0_dma_channel_desc {
7966365beadSRussell King 	u32 ddar;
7976365beadSRussell King 	const char *name;
7986365beadSRussell King };
7996365beadSRussell King 
8006365beadSRussell King #define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
8016365beadSRussell King static const struct sa11x0_dma_channel_desc chan_desc[] = {
8026365beadSRussell King 	CD(Ser0UDCTr, 0),
8036365beadSRussell King 	CD(Ser0UDCRc, DDAR_RW),
8046365beadSRussell King 	CD(Ser1SDLCTr, 0),
8056365beadSRussell King 	CD(Ser1SDLCRc, DDAR_RW),
8066365beadSRussell King 	CD(Ser1UARTTr, 0),
8076365beadSRussell King 	CD(Ser1UARTRc, DDAR_RW),
8086365beadSRussell King 	CD(Ser2ICPTr, 0),
8096365beadSRussell King 	CD(Ser2ICPRc, DDAR_RW),
8106365beadSRussell King 	CD(Ser3UARTTr, 0),
8116365beadSRussell King 	CD(Ser3UARTRc, DDAR_RW),
8126365beadSRussell King 	CD(Ser4MCP0Tr, 0),
8136365beadSRussell King 	CD(Ser4MCP0Rc, DDAR_RW),
8146365beadSRussell King 	CD(Ser4MCP1Tr, 0),
8156365beadSRussell King 	CD(Ser4MCP1Rc, DDAR_RW),
8166365beadSRussell King 	CD(Ser4SSPTr, 0),
8176365beadSRussell King 	CD(Ser4SSPRc, DDAR_RW),
8186365beadSRussell King };
8196365beadSRussell King 
82073d2a3ceSRussell King static const struct dma_slave_map sa11x0_dma_map[] = {
82173d2a3ceSRussell King 	{ "sa11x0-ir", "tx", "Ser2ICPTr" },
82273d2a3ceSRussell King 	{ "sa11x0-ir", "rx", "Ser2ICPRc" },
82373d2a3ceSRussell King 	{ "sa11x0-ssp", "tx", "Ser4SSPTr" },
82473d2a3ceSRussell King 	{ "sa11x0-ssp", "rx", "Ser4SSPRc" },
82573d2a3ceSRussell King };
82673d2a3ceSRussell King 
sa11x0_dma_filter_fn(struct dma_chan * chan,void * param)827bc822e80SRussell King static bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
828bc822e80SRussell King {
829bc822e80SRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
830bc822e80SRussell King 	const char *p = param;
831bc822e80SRussell King 
832bc822e80SRussell King 	return !strcmp(c->name, p);
833bc822e80SRussell King }
834bc822e80SRussell King 
sa11x0_dma_init_dmadev(struct dma_device * dmadev,struct device * dev)835463a1f8bSBill Pemberton static int sa11x0_dma_init_dmadev(struct dma_device *dmadev,
8366365beadSRussell King 	struct device *dev)
8376365beadSRussell King {
8386365beadSRussell King 	unsigned i;
8396365beadSRussell King 
8406365beadSRussell King 	INIT_LIST_HEAD(&dmadev->channels);
8416365beadSRussell King 	dmadev->dev = dev;
8426365beadSRussell King 	dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
843a0a51a64SMaxime Ripard 	dmadev->device_config = sa11x0_dma_device_config;
844a0a51a64SMaxime Ripard 	dmadev->device_pause = sa11x0_dma_device_pause;
845a0a51a64SMaxime Ripard 	dmadev->device_resume = sa11x0_dma_device_resume;
846a0a51a64SMaxime Ripard 	dmadev->device_terminate_all = sa11x0_dma_device_terminate_all;
8476365beadSRussell King 	dmadev->device_tx_status = sa11x0_dma_tx_status;
8486365beadSRussell King 	dmadev->device_issue_pending = sa11x0_dma_issue_pending;
8496365beadSRussell King 
8509aa71711SMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(chan_desc); i++) {
8516365beadSRussell King 		struct sa11x0_dma_chan *c;
8526365beadSRussell King 
8536365beadSRussell King 		c = kzalloc(sizeof(*c), GFP_KERNEL);
8546365beadSRussell King 		if (!c) {
8556365beadSRussell King 			dev_err(dev, "no memory for channel %u\n", i);
8566365beadSRussell King 			return -ENOMEM;
8576365beadSRussell King 		}
8586365beadSRussell King 
8596365beadSRussell King 		c->status = DMA_IN_PROGRESS;
8606365beadSRussell King 		c->ddar = chan_desc[i].ddar;
8616365beadSRussell King 		c->name = chan_desc[i].name;
8626365beadSRussell King 		INIT_LIST_HEAD(&c->node);
86350437bffSRussell King 
86450437bffSRussell King 		c->vc.desc_free = sa11x0_dma_free_desc;
86550437bffSRussell King 		vchan_init(&c->vc, dmadev);
8666365beadSRussell King 	}
8676365beadSRussell King 
8686365beadSRussell King 	return dma_async_device_register(dmadev);
8696365beadSRussell King }
8706365beadSRussell King 
sa11x0_dma_request_irq(struct platform_device * pdev,int nr,void * data)8716365beadSRussell King static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
8726365beadSRussell King 	void *data)
8736365beadSRussell King {
8746365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8756365beadSRussell King 
8766365beadSRussell King 	if (irq <= 0)
8776365beadSRussell King 		return -ENXIO;
8786365beadSRussell King 
8796365beadSRussell King 	return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
8806365beadSRussell King }
8816365beadSRussell King 
sa11x0_dma_free_irq(struct platform_device * pdev,int nr,void * data)8826365beadSRussell King static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
8836365beadSRussell King 	void *data)
8846365beadSRussell King {
8856365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8866365beadSRussell King 	if (irq > 0)
8876365beadSRussell King 		free_irq(irq, data);
8886365beadSRussell King }
8896365beadSRussell King 
sa11x0_dma_free_channels(struct dma_device * dmadev)8906365beadSRussell King static void sa11x0_dma_free_channels(struct dma_device *dmadev)
8916365beadSRussell King {
8926365beadSRussell King 	struct sa11x0_dma_chan *c, *cn;
8936365beadSRussell King 
89450437bffSRussell King 	list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
89550437bffSRussell King 		list_del(&c->vc.chan.device_node);
89650437bffSRussell King 		tasklet_kill(&c->vc.task);
8976365beadSRussell King 		kfree(c);
8986365beadSRussell King 	}
8996365beadSRussell King }
9006365beadSRussell King 
sa11x0_dma_probe(struct platform_device * pdev)901463a1f8bSBill Pemberton static int sa11x0_dma_probe(struct platform_device *pdev)
9026365beadSRussell King {
9036365beadSRussell King 	struct sa11x0_dma_dev *d;
9046365beadSRussell King 	struct resource *res;
9056365beadSRussell King 	unsigned i;
9066365beadSRussell King 	int ret;
9076365beadSRussell King 
9086365beadSRussell King 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9096365beadSRussell King 	if (!res)
9106365beadSRussell King 		return -ENXIO;
9116365beadSRussell King 
9126365beadSRussell King 	d = kzalloc(sizeof(*d), GFP_KERNEL);
9136365beadSRussell King 	if (!d) {
9146365beadSRussell King 		ret = -ENOMEM;
9156365beadSRussell King 		goto err_alloc;
9166365beadSRussell King 	}
9176365beadSRussell King 
9186365beadSRussell King 	spin_lock_init(&d->lock);
9196365beadSRussell King 	INIT_LIST_HEAD(&d->chan_pending);
9206365beadSRussell King 
92173d2a3ceSRussell King 	d->slave.filter.fn = sa11x0_dma_filter_fn;
92273d2a3ceSRussell King 	d->slave.filter.mapcnt = ARRAY_SIZE(sa11x0_dma_map);
92373d2a3ceSRussell King 	d->slave.filter.map = sa11x0_dma_map;
92473d2a3ceSRussell King 
9256365beadSRussell King 	d->base = ioremap(res->start, resource_size(res));
9266365beadSRussell King 	if (!d->base) {
9276365beadSRussell King 		ret = -ENOMEM;
9286365beadSRussell King 		goto err_ioremap;
9296365beadSRussell King 	}
9306365beadSRussell King 
9318a536883SAllen Pais 	tasklet_setup(&d->task, sa11x0_dma_tasklet);
9326365beadSRussell King 
9336365beadSRussell King 	for (i = 0; i < NR_PHY_CHAN; i++) {
9346365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[i];
9356365beadSRussell King 
9366365beadSRussell King 		p->dev = d;
9376365beadSRussell King 		p->num = i;
9386365beadSRussell King 		p->base = d->base + i * DMA_SIZE;
9396365beadSRussell King 		writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
9406365beadSRussell King 			DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
9416365beadSRussell King 			p->base + DMA_DCSR_C);
9426365beadSRussell King 		writel_relaxed(0, p->base + DMA_DDAR);
9436365beadSRussell King 
9446365beadSRussell King 		ret = sa11x0_dma_request_irq(pdev, i, p);
9456365beadSRussell King 		if (ret) {
9466365beadSRussell King 			while (i) {
9476365beadSRussell King 				i--;
9486365beadSRussell King 				sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
9496365beadSRussell King 			}
9506365beadSRussell King 			goto err_irq;
9516365beadSRussell King 		}
9526365beadSRussell King 	}
9536365beadSRussell King 
9546365beadSRussell King 	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
955d9444325SRussell King 	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
9566365beadSRussell King 	d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
957d9444325SRussell King 	d->slave.device_prep_dma_cyclic = sa11x0_dma_prep_dma_cyclic;
95828591dfdSDmitry Eremin-Solenikov 	d->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
95928591dfdSDmitry Eremin-Solenikov 	d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
96028591dfdSDmitry Eremin-Solenikov 	d->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
96128591dfdSDmitry Eremin-Solenikov 				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES);
96228591dfdSDmitry Eremin-Solenikov 	d->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
96328591dfdSDmitry Eremin-Solenikov 				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES);
9646365beadSRussell King 	ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
9656365beadSRussell King 	if (ret) {
9666365beadSRussell King 		dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
9676365beadSRussell King 			ret);
9686365beadSRussell King 		goto err_slave_reg;
9696365beadSRussell King 	}
9706365beadSRussell King 
9716365beadSRussell King 	platform_set_drvdata(pdev, d);
9726365beadSRussell King 	return 0;
9736365beadSRussell King 
9746365beadSRussell King  err_slave_reg:
9756365beadSRussell King 	sa11x0_dma_free_channels(&d->slave);
9766365beadSRussell King 	for (i = 0; i < NR_PHY_CHAN; i++)
9776365beadSRussell King 		sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
9786365beadSRussell King  err_irq:
9796365beadSRussell King 	tasklet_kill(&d->task);
9806365beadSRussell King 	iounmap(d->base);
9816365beadSRussell King  err_ioremap:
9826365beadSRussell King 	kfree(d);
9836365beadSRussell King  err_alloc:
9846365beadSRussell King 	return ret;
9856365beadSRussell King }
9866365beadSRussell King 
sa11x0_dma_remove(struct platform_device * pdev)9874bf27b8bSGreg Kroah-Hartman static int sa11x0_dma_remove(struct platform_device *pdev)
9886365beadSRussell King {
9896365beadSRussell King 	struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
9906365beadSRussell King 	unsigned pch;
9916365beadSRussell King 
9926365beadSRussell King 	dma_async_device_unregister(&d->slave);
9936365beadSRussell King 
9946365beadSRussell King 	sa11x0_dma_free_channels(&d->slave);
9956365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++)
9966365beadSRussell King 		sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
9976365beadSRussell King 	tasklet_kill(&d->task);
9986365beadSRussell King 	iounmap(d->base);
9996365beadSRussell King 	kfree(d);
10006365beadSRussell King 
10016365beadSRussell King 	return 0;
10026365beadSRussell King }
10036365beadSRussell King 
sa11x0_dma_suspend(struct device * dev)1004*07c609ccSCai Huoqing static __maybe_unused int sa11x0_dma_suspend(struct device *dev)
10056365beadSRussell King {
10066365beadSRussell King 	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
10076365beadSRussell King 	unsigned pch;
10086365beadSRussell King 
10096365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
10106365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[pch];
10116365beadSRussell King 		u32 dcsr, saved_dcsr;
10126365beadSRussell King 
10136365beadSRussell King 		dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10146365beadSRussell King 		if (dcsr & DCSR_RUN) {
10156365beadSRussell King 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
10166365beadSRussell King 			dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10176365beadSRussell King 		}
10186365beadSRussell King 
10196365beadSRussell King 		saved_dcsr &= DCSR_RUN | DCSR_IE;
10206365beadSRussell King 		if (dcsr & DCSR_BIU) {
10216365beadSRussell King 			p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
10226365beadSRussell King 			p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
10236365beadSRussell King 			p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
10246365beadSRussell King 			p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
10256365beadSRussell King 			saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
10266365beadSRussell King 				      (dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
10276365beadSRussell King 		} else {
10286365beadSRussell King 			p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
10296365beadSRussell King 			p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
10306365beadSRussell King 			p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
10316365beadSRussell King 			p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
10326365beadSRussell King 			saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
10336365beadSRussell King 		}
10346365beadSRussell King 		p->dcsr = saved_dcsr;
10356365beadSRussell King 
10366365beadSRussell King 		writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
10376365beadSRussell King 	}
10386365beadSRussell King 
10396365beadSRussell King 	return 0;
10406365beadSRussell King }
10416365beadSRussell King 
sa11x0_dma_resume(struct device * dev)1042*07c609ccSCai Huoqing static __maybe_unused int sa11x0_dma_resume(struct device *dev)
10436365beadSRussell King {
10446365beadSRussell King 	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
10456365beadSRussell King 	unsigned pch;
10466365beadSRussell King 
10476365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
10486365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[pch];
10496365beadSRussell King 		struct sa11x0_dma_desc *txd = NULL;
10506365beadSRussell King 		u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10516365beadSRussell King 
10526365beadSRussell King 		WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
10536365beadSRussell King 
10546365beadSRussell King 		if (p->txd_done)
10556365beadSRussell King 			txd = p->txd_done;
10566365beadSRussell King 		else if (p->txd_load)
10576365beadSRussell King 			txd = p->txd_load;
10586365beadSRussell King 
10596365beadSRussell King 		if (!txd)
10606365beadSRussell King 			continue;
10616365beadSRussell King 
10626365beadSRussell King 		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
10636365beadSRussell King 
10646365beadSRussell King 		writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
10656365beadSRussell King 		writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
10666365beadSRussell King 		writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
10676365beadSRussell King 		writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
10686365beadSRussell King 		writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
10696365beadSRussell King 	}
10706365beadSRussell King 
10716365beadSRussell King 	return 0;
10726365beadSRussell King }
10736365beadSRussell King 
10746365beadSRussell King static const struct dev_pm_ops sa11x0_dma_pm_ops = {
10757789e346SCai Huoqing 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sa11x0_dma_suspend, sa11x0_dma_resume)
10766365beadSRussell King };
10776365beadSRussell King 
10786365beadSRussell King static struct platform_driver sa11x0_dma_driver = {
10796365beadSRussell King 	.driver = {
10806365beadSRussell King 		.name	= "sa11x0-dma",
10816365beadSRussell King 		.pm	= &sa11x0_dma_pm_ops,
10826365beadSRussell King 	},
10836365beadSRussell King 	.probe		= sa11x0_dma_probe,
1084a7d6e3ecSBill Pemberton 	.remove		= sa11x0_dma_remove,
10856365beadSRussell King };
10866365beadSRussell King 
sa11x0_dma_init(void)10876365beadSRussell King static int __init sa11x0_dma_init(void)
10886365beadSRussell King {
10896365beadSRussell King 	return platform_driver_register(&sa11x0_dma_driver);
10906365beadSRussell King }
10916365beadSRussell King subsys_initcall(sa11x0_dma_init);
10926365beadSRussell King 
sa11x0_dma_exit(void)10936365beadSRussell King static void __exit sa11x0_dma_exit(void)
10946365beadSRussell King {
10956365beadSRussell King 	platform_driver_unregister(&sa11x0_dma_driver);
10966365beadSRussell King }
10976365beadSRussell King module_exit(sa11x0_dma_exit);
10986365beadSRussell King 
10996365beadSRussell King MODULE_AUTHOR("Russell King");
11006365beadSRussell King MODULE_DESCRIPTION("SA-11x0 DMA driver");
11016365beadSRussell King MODULE_LICENSE("GPL v2");
11026365beadSRussell King MODULE_ALIAS("platform:sa11x0-dma");
1103