xref: /openbmc/linux/drivers/dma/sa11x0-dma.c (revision 28591dfdd96c6289aebbf12d8eb4e5dc5ddbde97)
16365beadSRussell King /*
26365beadSRussell King  * SA11x0 DMAengine support
36365beadSRussell King  *
46365beadSRussell King  * Copyright (C) 2012 Russell King
56365beadSRussell King  *   Derived in part from arch/arm/mach-sa1100/dma.c,
66365beadSRussell King  *   Copyright (C) 2000, 2001 by Nicolas Pitre
76365beadSRussell King  *
86365beadSRussell King  * This program is free software; you can redistribute it and/or modify
96365beadSRussell King  * it under the terms of the GNU General Public License version 2 as
106365beadSRussell King  * published by the Free Software Foundation.
116365beadSRussell King  */
126365beadSRussell King #include <linux/sched.h>
136365beadSRussell King #include <linux/device.h>
146365beadSRussell King #include <linux/dmaengine.h>
156365beadSRussell King #include <linux/init.h>
166365beadSRussell King #include <linux/interrupt.h>
176365beadSRussell King #include <linux/kernel.h>
186365beadSRussell King #include <linux/module.h>
196365beadSRussell King #include <linux/platform_device.h>
206365beadSRussell King #include <linux/sa11x0-dma.h>
216365beadSRussell King #include <linux/slab.h>
226365beadSRussell King #include <linux/spinlock.h>
236365beadSRussell King 
2450437bffSRussell King #include "virt-dma.h"
2550437bffSRussell King 
266365beadSRussell King #define NR_PHY_CHAN	6
276365beadSRussell King #define DMA_ALIGN	3
286365beadSRussell King #define DMA_MAX_SIZE	0x1fff
296365beadSRussell King #define DMA_CHUNK_SIZE	0x1000
306365beadSRussell King 
316365beadSRussell King #define DMA_DDAR	0x00
326365beadSRussell King #define DMA_DCSR_S	0x04
336365beadSRussell King #define DMA_DCSR_C	0x08
346365beadSRussell King #define DMA_DCSR_R	0x0c
356365beadSRussell King #define DMA_DBSA	0x10
366365beadSRussell King #define DMA_DBTA	0x14
376365beadSRussell King #define DMA_DBSB	0x18
386365beadSRussell King #define DMA_DBTB	0x1c
396365beadSRussell King #define DMA_SIZE	0x20
406365beadSRussell King 
416365beadSRussell King #define DCSR_RUN	(1 << 0)
426365beadSRussell King #define DCSR_IE		(1 << 1)
436365beadSRussell King #define DCSR_ERROR	(1 << 2)
446365beadSRussell King #define DCSR_DONEA	(1 << 3)
456365beadSRussell King #define DCSR_STRTA	(1 << 4)
466365beadSRussell King #define DCSR_DONEB	(1 << 5)
476365beadSRussell King #define DCSR_STRTB	(1 << 6)
486365beadSRussell King #define DCSR_BIU	(1 << 7)
496365beadSRussell King 
506365beadSRussell King #define DDAR_RW		(1 << 0)	/* 0 = W, 1 = R */
516365beadSRussell King #define DDAR_E		(1 << 1)	/* 0 = LE, 1 = BE */
526365beadSRussell King #define DDAR_BS		(1 << 2)	/* 0 = BS4, 1 = BS8 */
536365beadSRussell King #define DDAR_DW		(1 << 3)	/* 0 = 8b, 1 = 16b */
546365beadSRussell King #define DDAR_Ser0UDCTr	(0x0 << 4)
556365beadSRussell King #define DDAR_Ser0UDCRc	(0x1 << 4)
566365beadSRussell King #define DDAR_Ser1SDLCTr	(0x2 << 4)
576365beadSRussell King #define DDAR_Ser1SDLCRc	(0x3 << 4)
586365beadSRussell King #define DDAR_Ser1UARTTr	(0x4 << 4)
596365beadSRussell King #define DDAR_Ser1UARTRc	(0x5 << 4)
606365beadSRussell King #define DDAR_Ser2ICPTr	(0x6 << 4)
616365beadSRussell King #define DDAR_Ser2ICPRc	(0x7 << 4)
626365beadSRussell King #define DDAR_Ser3UARTTr	(0x8 << 4)
636365beadSRussell King #define DDAR_Ser3UARTRc	(0x9 << 4)
646365beadSRussell King #define DDAR_Ser4MCP0Tr	(0xa << 4)
656365beadSRussell King #define DDAR_Ser4MCP0Rc	(0xb << 4)
666365beadSRussell King #define DDAR_Ser4MCP1Tr	(0xc << 4)
676365beadSRussell King #define DDAR_Ser4MCP1Rc	(0xd << 4)
686365beadSRussell King #define DDAR_Ser4SSPTr	(0xe << 4)
696365beadSRussell King #define DDAR_Ser4SSPRc	(0xf << 4)
706365beadSRussell King 
716365beadSRussell King struct sa11x0_dma_sg {
726365beadSRussell King 	u32			addr;
736365beadSRussell King 	u32			len;
746365beadSRussell King };
756365beadSRussell King 
766365beadSRussell King struct sa11x0_dma_desc {
7750437bffSRussell King 	struct virt_dma_desc	vd;
7850437bffSRussell King 
796365beadSRussell King 	u32			ddar;
806365beadSRussell King 	size_t			size;
81d9444325SRussell King 	unsigned		period;
82d9444325SRussell King 	bool			cyclic;
836365beadSRussell King 
846365beadSRussell King 	unsigned		sglen;
856365beadSRussell King 	struct sa11x0_dma_sg	sg[0];
866365beadSRussell King };
876365beadSRussell King 
886365beadSRussell King struct sa11x0_dma_phy;
896365beadSRussell King 
906365beadSRussell King struct sa11x0_dma_chan {
9150437bffSRussell King 	struct virt_dma_chan	vc;
926365beadSRussell King 
9350437bffSRussell King 	/* protected by c->vc.lock */
946365beadSRussell King 	struct sa11x0_dma_phy	*phy;
956365beadSRussell King 	enum dma_status		status;
966365beadSRussell King 
976365beadSRussell King 	/* protected by d->lock */
986365beadSRussell King 	struct list_head	node;
996365beadSRussell King 
1006365beadSRussell King 	u32			ddar;
1016365beadSRussell King 	const char		*name;
1026365beadSRussell King };
1036365beadSRussell King 
1046365beadSRussell King struct sa11x0_dma_phy {
1056365beadSRussell King 	void __iomem		*base;
1066365beadSRussell King 	struct sa11x0_dma_dev	*dev;
1076365beadSRussell King 	unsigned		num;
1086365beadSRussell King 
1096365beadSRussell King 	struct sa11x0_dma_chan	*vchan;
1106365beadSRussell King 
11150437bffSRussell King 	/* Protected by c->vc.lock */
1126365beadSRussell King 	unsigned		sg_load;
1136365beadSRussell King 	struct sa11x0_dma_desc	*txd_load;
1146365beadSRussell King 	unsigned		sg_done;
1156365beadSRussell King 	struct sa11x0_dma_desc	*txd_done;
1166365beadSRussell King 	u32			dbs[2];
1176365beadSRussell King 	u32			dbt[2];
1186365beadSRussell King 	u32			dcsr;
1196365beadSRussell King };
1206365beadSRussell King 
1216365beadSRussell King struct sa11x0_dma_dev {
1226365beadSRussell King 	struct dma_device	slave;
1236365beadSRussell King 	void __iomem		*base;
1246365beadSRussell King 	spinlock_t		lock;
1256365beadSRussell King 	struct tasklet_struct	task;
1266365beadSRussell King 	struct list_head	chan_pending;
1276365beadSRussell King 	struct sa11x0_dma_phy	phy[NR_PHY_CHAN];
1286365beadSRussell King };
1296365beadSRussell King 
1306365beadSRussell King static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
1316365beadSRussell King {
13250437bffSRussell King 	return container_of(chan, struct sa11x0_dma_chan, vc.chan);
1336365beadSRussell King }
1346365beadSRussell King 
1356365beadSRussell King static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
1366365beadSRussell King {
1376365beadSRussell King 	return container_of(dmadev, struct sa11x0_dma_dev, slave);
1386365beadSRussell King }
1396365beadSRussell King 
1406365beadSRussell King static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
1416365beadSRussell King {
14250437bffSRussell King 	struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
1436365beadSRussell King 
14450437bffSRussell King 	return vd ? container_of(vd, struct sa11x0_dma_desc, vd) : NULL;
14550437bffSRussell King }
14650437bffSRussell King 
14750437bffSRussell King static void sa11x0_dma_free_desc(struct virt_dma_desc *vd)
14850437bffSRussell King {
14950437bffSRussell King 	kfree(container_of(vd, struct sa11x0_dma_desc, vd));
1506365beadSRussell King }
1516365beadSRussell King 
1526365beadSRussell King static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
1536365beadSRussell King {
15450437bffSRussell King 	list_del(&txd->vd.node);
1556365beadSRussell King 	p->txd_load = txd;
1566365beadSRussell King 	p->sg_load = 0;
1576365beadSRussell King 
1586365beadSRussell King 	dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
15950437bffSRussell King 		p->num, &txd->vd, txd->vd.tx.cookie, txd->ddar);
1606365beadSRussell King }
1616365beadSRussell King 
1626365beadSRussell King static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
1636365beadSRussell King 	struct sa11x0_dma_chan *c)
1646365beadSRussell King {
1656365beadSRussell King 	struct sa11x0_dma_desc *txd = p->txd_load;
1666365beadSRussell King 	struct sa11x0_dma_sg *sg;
1676365beadSRussell King 	void __iomem *base = p->base;
1686365beadSRussell King 	unsigned dbsx, dbtx;
1696365beadSRussell King 	u32 dcsr;
1706365beadSRussell King 
1716365beadSRussell King 	if (!txd)
1726365beadSRussell King 		return;
1736365beadSRussell King 
1746365beadSRussell King 	dcsr = readl_relaxed(base + DMA_DCSR_R);
1756365beadSRussell King 
1766365beadSRussell King 	/* Don't try to load the next transfer if both buffers are started */
1776365beadSRussell King 	if ((dcsr & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB))
1786365beadSRussell King 		return;
1796365beadSRussell King 
1806365beadSRussell King 	if (p->sg_load == txd->sglen) {
181d9444325SRussell King 		if (!txd->cyclic) {
1826365beadSRussell King 			struct sa11x0_dma_desc *txn = sa11x0_dma_next_desc(c);
1836365beadSRussell King 
1846365beadSRussell King 			/*
1856365beadSRussell King 			 * We have reached the end of the current descriptor.
1866365beadSRussell King 			 * Peek at the next descriptor, and if compatible with
1876365beadSRussell King 			 * the current, start processing it.
1886365beadSRussell King 			 */
1896365beadSRussell King 			if (txn && txn->ddar == txd->ddar) {
1906365beadSRussell King 				txd = txn;
1916365beadSRussell King 				sa11x0_dma_start_desc(p, txn);
1926365beadSRussell King 			} else {
1936365beadSRussell King 				p->txd_load = NULL;
1946365beadSRussell King 				return;
1956365beadSRussell King 			}
196d9444325SRussell King 		} else {
197d9444325SRussell King 			/* Cyclic: reset back to beginning */
198d9444325SRussell King 			p->sg_load = 0;
199d9444325SRussell King 		}
2006365beadSRussell King 	}
2016365beadSRussell King 
2026365beadSRussell King 	sg = &txd->sg[p->sg_load++];
2036365beadSRussell King 
2046365beadSRussell King 	/* Select buffer to load according to channel status */
2056365beadSRussell King 	if (((dcsr & (DCSR_BIU | DCSR_STRTB)) == (DCSR_BIU | DCSR_STRTB)) ||
2066365beadSRussell King 	    ((dcsr & (DCSR_BIU | DCSR_STRTA)) == 0)) {
2076365beadSRussell King 		dbsx = DMA_DBSA;
2086365beadSRussell King 		dbtx = DMA_DBTA;
2096365beadSRussell King 		dcsr = DCSR_STRTA | DCSR_IE | DCSR_RUN;
2106365beadSRussell King 	} else {
2116365beadSRussell King 		dbsx = DMA_DBSB;
2126365beadSRussell King 		dbtx = DMA_DBTB;
2136365beadSRussell King 		dcsr = DCSR_STRTB | DCSR_IE | DCSR_RUN;
2146365beadSRussell King 	}
2156365beadSRussell King 
2166365beadSRussell King 	writel_relaxed(sg->addr, base + dbsx);
2176365beadSRussell King 	writel_relaxed(sg->len, base + dbtx);
2186365beadSRussell King 	writel(dcsr, base + DMA_DCSR_S);
2196365beadSRussell King 
2206365beadSRussell King 	dev_dbg(p->dev->slave.dev, "pchan %u: load: DCSR:%02x DBS%c:%08x DBT%c:%08x\n",
2216365beadSRussell King 		p->num, dcsr,
2226365beadSRussell King 		'A' + (dbsx == DMA_DBSB), sg->addr,
2236365beadSRussell King 		'A' + (dbtx == DMA_DBTB), sg->len);
2246365beadSRussell King }
2256365beadSRussell King 
2266365beadSRussell King static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
2276365beadSRussell King 	struct sa11x0_dma_chan *c)
2286365beadSRussell King {
2296365beadSRussell King 	struct sa11x0_dma_desc *txd = p->txd_done;
2306365beadSRussell King 
2316365beadSRussell King 	if (++p->sg_done == txd->sglen) {
232d9444325SRussell King 		if (!txd->cyclic) {
23350437bffSRussell King 			vchan_cookie_complete(&txd->vd);
2346365beadSRussell King 
2356365beadSRussell King 			p->sg_done = 0;
2366365beadSRussell King 			p->txd_done = p->txd_load;
2376365beadSRussell King 
23850437bffSRussell King 			if (!p->txd_done)
23950437bffSRussell King 				tasklet_schedule(&p->dev->task);
240d9444325SRussell King 		} else {
241d9444325SRussell King 			if ((p->sg_done % txd->period) == 0)
242d9444325SRussell King 				vchan_cyclic_callback(&txd->vd);
243d9444325SRussell King 
244d9444325SRussell King 			/* Cyclic: reset back to beginning */
245d9444325SRussell King 			p->sg_done = 0;
246d9444325SRussell King 		}
2476365beadSRussell King 	}
2486365beadSRussell King 
2496365beadSRussell King 	sa11x0_dma_start_sg(p, c);
2506365beadSRussell King }
2516365beadSRussell King 
2526365beadSRussell King static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
2536365beadSRussell King {
2546365beadSRussell King 	struct sa11x0_dma_phy *p = dev_id;
2556365beadSRussell King 	struct sa11x0_dma_dev *d = p->dev;
2566365beadSRussell King 	struct sa11x0_dma_chan *c;
2576365beadSRussell King 	u32 dcsr;
2586365beadSRussell King 
2596365beadSRussell King 	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
2606365beadSRussell King 	if (!(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB)))
2616365beadSRussell King 		return IRQ_NONE;
2626365beadSRussell King 
2636365beadSRussell King 	/* Clear reported status bits */
2646365beadSRussell King 	writel_relaxed(dcsr & (DCSR_ERROR | DCSR_DONEA | DCSR_DONEB),
2656365beadSRussell King 		p->base + DMA_DCSR_C);
2666365beadSRussell King 
2676365beadSRussell King 	dev_dbg(d->slave.dev, "pchan %u: irq: DCSR:%02x\n", p->num, dcsr);
2686365beadSRussell King 
2696365beadSRussell King 	if (dcsr & DCSR_ERROR) {
2706365beadSRussell King 		dev_err(d->slave.dev, "pchan %u: error. DCSR:%02x DDAR:%08x DBSA:%08x DBTA:%08x DBSB:%08x DBTB:%08x\n",
2716365beadSRussell King 			p->num, dcsr,
2726365beadSRussell King 			readl_relaxed(p->base + DMA_DDAR),
2736365beadSRussell King 			readl_relaxed(p->base + DMA_DBSA),
2746365beadSRussell King 			readl_relaxed(p->base + DMA_DBTA),
2756365beadSRussell King 			readl_relaxed(p->base + DMA_DBSB),
2766365beadSRussell King 			readl_relaxed(p->base + DMA_DBTB));
2776365beadSRussell King 	}
2786365beadSRussell King 
2796365beadSRussell King 	c = p->vchan;
2806365beadSRussell King 	if (c) {
2816365beadSRussell King 		unsigned long flags;
2826365beadSRussell King 
28350437bffSRussell King 		spin_lock_irqsave(&c->vc.lock, flags);
2846365beadSRussell King 		/*
2856365beadSRussell King 		 * Now that we're holding the lock, check that the vchan
2866365beadSRussell King 		 * really is associated with this pchan before touching the
2876365beadSRussell King 		 * hardware.  This should always succeed, because we won't
2886365beadSRussell King 		 * change p->vchan or c->phy while the channel is actively
2896365beadSRussell King 		 * transferring.
2906365beadSRussell King 		 */
2916365beadSRussell King 		if (c->phy == p) {
2926365beadSRussell King 			if (dcsr & DCSR_DONEA)
2936365beadSRussell King 				sa11x0_dma_complete(p, c);
2946365beadSRussell King 			if (dcsr & DCSR_DONEB)
2956365beadSRussell King 				sa11x0_dma_complete(p, c);
2966365beadSRussell King 		}
29750437bffSRussell King 		spin_unlock_irqrestore(&c->vc.lock, flags);
2986365beadSRussell King 	}
2996365beadSRussell King 
3006365beadSRussell King 	return IRQ_HANDLED;
3016365beadSRussell King }
3026365beadSRussell King 
3036365beadSRussell King static void sa11x0_dma_start_txd(struct sa11x0_dma_chan *c)
3046365beadSRussell King {
3056365beadSRussell King 	struct sa11x0_dma_desc *txd = sa11x0_dma_next_desc(c);
3066365beadSRussell King 
3076365beadSRussell King 	/* If the issued list is empty, we have no further txds to process */
3086365beadSRussell King 	if (txd) {
3096365beadSRussell King 		struct sa11x0_dma_phy *p = c->phy;
3106365beadSRussell King 
3116365beadSRussell King 		sa11x0_dma_start_desc(p, txd);
3126365beadSRussell King 		p->txd_done = txd;
3136365beadSRussell King 		p->sg_done = 0;
3146365beadSRussell King 
3156365beadSRussell King 		/* The channel should not have any transfers started */
3166365beadSRussell King 		WARN_ON(readl_relaxed(p->base + DMA_DCSR_R) &
3176365beadSRussell King 				      (DCSR_STRTA | DCSR_STRTB));
3186365beadSRussell King 
3196365beadSRussell King 		/* Clear the run and start bits before changing DDAR */
3206365beadSRussell King 		writel_relaxed(DCSR_RUN | DCSR_STRTA | DCSR_STRTB,
3216365beadSRussell King 			       p->base + DMA_DCSR_C);
3226365beadSRussell King 		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
3236365beadSRussell King 
3246365beadSRussell King 		/* Try to start both buffers */
3256365beadSRussell King 		sa11x0_dma_start_sg(p, c);
3266365beadSRussell King 		sa11x0_dma_start_sg(p, c);
3276365beadSRussell King 	}
3286365beadSRussell King }
3296365beadSRussell King 
3306365beadSRussell King static void sa11x0_dma_tasklet(unsigned long arg)
3316365beadSRussell King {
3326365beadSRussell King 	struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
3336365beadSRussell King 	struct sa11x0_dma_phy *p;
3346365beadSRussell King 	struct sa11x0_dma_chan *c;
3356365beadSRussell King 	unsigned pch, pch_alloc = 0;
3366365beadSRussell King 
3376365beadSRussell King 	dev_dbg(d->slave.dev, "tasklet enter\n");
3386365beadSRussell King 
33950437bffSRussell King 	list_for_each_entry(c, &d->slave.channels, vc.chan.device_node) {
34050437bffSRussell King 		spin_lock_irq(&c->vc.lock);
3416365beadSRussell King 		p = c->phy;
34250437bffSRussell King 		if (p && !p->txd_done) {
3436365beadSRussell King 			sa11x0_dma_start_txd(c);
3446365beadSRussell King 			if (!p->txd_done) {
3456365beadSRussell King 				/* No current txd associated with this channel */
3466365beadSRussell King 				dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
3476365beadSRussell King 
3486365beadSRussell King 				/* Mark this channel free */
3496365beadSRussell King 				c->phy = NULL;
3506365beadSRussell King 				p->vchan = NULL;
3516365beadSRussell King 			}
3526365beadSRussell King 		}
35350437bffSRussell King 		spin_unlock_irq(&c->vc.lock);
3546365beadSRussell King 	}
3556365beadSRussell King 
3566365beadSRussell King 	spin_lock_irq(&d->lock);
3576365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
3586365beadSRussell King 		p = &d->phy[pch];
3596365beadSRussell King 
3606365beadSRussell King 		if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
3616365beadSRussell King 			c = list_first_entry(&d->chan_pending,
3626365beadSRussell King 				struct sa11x0_dma_chan, node);
3636365beadSRussell King 			list_del_init(&c->node);
3646365beadSRussell King 
3656365beadSRussell King 			pch_alloc |= 1 << pch;
3666365beadSRussell King 
3676365beadSRussell King 			/* Mark this channel allocated */
3686365beadSRussell King 			p->vchan = c;
3696365beadSRussell King 
37050437bffSRussell King 			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
3716365beadSRussell King 		}
3726365beadSRussell King 	}
3736365beadSRussell King 	spin_unlock_irq(&d->lock);
3746365beadSRussell King 
3756365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
3766365beadSRussell King 		if (pch_alloc & (1 << pch)) {
3776365beadSRussell King 			p = &d->phy[pch];
3786365beadSRussell King 			c = p->vchan;
3796365beadSRussell King 
38050437bffSRussell King 			spin_lock_irq(&c->vc.lock);
3816365beadSRussell King 			c->phy = p;
3826365beadSRussell King 
3836365beadSRussell King 			sa11x0_dma_start_txd(c);
38450437bffSRussell King 			spin_unlock_irq(&c->vc.lock);
3856365beadSRussell King 		}
3866365beadSRussell King 	}
3876365beadSRussell King 
3886365beadSRussell King 	dev_dbg(d->slave.dev, "tasklet exit\n");
3896365beadSRussell King }
3906365beadSRussell King 
3916365beadSRussell King 
3926365beadSRussell King static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
3936365beadSRussell King {
3946365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
3956365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
3966365beadSRussell King 	unsigned long flags;
3976365beadSRussell King 
39850437bffSRussell King 	spin_lock_irqsave(&d->lock, flags);
3996365beadSRussell King 	list_del_init(&c->node);
40050437bffSRussell King 	spin_unlock_irqrestore(&d->lock, flags);
4016365beadSRussell King 
40250437bffSRussell King 	vchan_free_chan_resources(&c->vc);
4036365beadSRussell King }
4046365beadSRussell King 
4056365beadSRussell King static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
4066365beadSRussell King {
4076365beadSRussell King 	unsigned reg;
4086365beadSRussell King 	u32 dcsr;
4096365beadSRussell King 
4106365beadSRussell King 	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
4116365beadSRussell King 
4126365beadSRussell King 	if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
4136365beadSRussell King 	    (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
4146365beadSRussell King 		reg = DMA_DBSA;
4156365beadSRussell King 	else
4166365beadSRussell King 		reg = DMA_DBSB;
4176365beadSRussell King 
4186365beadSRussell King 	return readl_relaxed(p->base + reg);
4196365beadSRussell King }
4206365beadSRussell King 
4216365beadSRussell King static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
4226365beadSRussell King 	dma_cookie_t cookie, struct dma_tx_state *state)
4236365beadSRussell King {
4246365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
4256365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
4266365beadSRussell King 	struct sa11x0_dma_phy *p;
42763fe23c3SRussell King 	struct virt_dma_desc *vd;
4286365beadSRussell King 	unsigned long flags;
4296365beadSRussell King 	enum dma_status ret;
4306365beadSRussell King 
43150437bffSRussell King 	ret = dma_cookie_status(&c->vc.chan, cookie, state);
432fdebb768SVinod Koul 	if (ret == DMA_COMPLETE)
4336365beadSRussell King 		return ret;
4346365beadSRussell King 
43563fe23c3SRussell King 	if (!state)
43663fe23c3SRussell King 		return c->status;
43763fe23c3SRussell King 
43850437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
4396365beadSRussell King 	p = c->phy;
44063fe23c3SRussell King 
44163fe23c3SRussell King 	/*
44263fe23c3SRussell King 	 * If the cookie is on our issue queue, then the residue is
44363fe23c3SRussell King 	 * its total size.
44463fe23c3SRussell King 	 */
44563fe23c3SRussell King 	vd = vchan_find_desc(&c->vc, cookie);
44663fe23c3SRussell King 	if (vd) {
44763fe23c3SRussell King 		state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size;
44863fe23c3SRussell King 	} else if (!p) {
44963fe23c3SRussell King 		state->residue = 0;
45063fe23c3SRussell King 	} else {
45163fe23c3SRussell King 		struct sa11x0_dma_desc *txd;
45263fe23c3SRussell King 		size_t bytes = 0;
45363fe23c3SRussell King 
45463fe23c3SRussell King 		if (p->txd_done && p->txd_done->vd.tx.cookie == cookie)
45563fe23c3SRussell King 			txd = p->txd_done;
45663fe23c3SRussell King 		else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie)
45763fe23c3SRussell King 			txd = p->txd_load;
45863fe23c3SRussell King 		else
45963fe23c3SRussell King 			txd = NULL;
46063fe23c3SRussell King 
4616365beadSRussell King 		ret = c->status;
46263fe23c3SRussell King 		if (txd) {
4636365beadSRussell King 			dma_addr_t addr = sa11x0_dma_pos(p);
46463fe23c3SRussell King 			unsigned i;
4656365beadSRussell King 
4666365beadSRussell King 			dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
4676365beadSRussell King 
4686365beadSRussell King 			for (i = 0; i < txd->sglen; i++) {
4696365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
4706365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4716365beadSRussell King 				if (addr >= txd->sg[i].addr &&
4726365beadSRussell King 				    addr < txd->sg[i].addr + txd->sg[i].len) {
4736365beadSRussell King 					unsigned len;
4746365beadSRussell King 
4756365beadSRussell King 					len = txd->sg[i].len -
4766365beadSRussell King 						(addr - txd->sg[i].addr);
4776365beadSRussell King 					dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
4786365beadSRussell King 						i, len);
4796365beadSRussell King 					bytes += len;
4806365beadSRussell King 					i++;
4816365beadSRussell King 					break;
4826365beadSRussell King 				}
4836365beadSRussell King 			}
4846365beadSRussell King 			for (; i < txd->sglen; i++) {
4856365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
4866365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4876365beadSRussell King 				bytes += txd->sg[i].len;
4886365beadSRussell King 			}
4896365beadSRussell King 		}
49063fe23c3SRussell King 		state->residue = bytes;
4916365beadSRussell King 	}
49250437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
4936365beadSRussell King 
49463fe23c3SRussell King 	dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
4956365beadSRussell King 
4966365beadSRussell King 	return ret;
4976365beadSRussell King }
4986365beadSRussell King 
4996365beadSRussell King /*
5006365beadSRussell King  * Move pending txds to the issued list, and re-init pending list.
5016365beadSRussell King  * If not already pending, add this channel to the list of pending
5026365beadSRussell King  * channels and trigger the tasklet to run.
5036365beadSRussell King  */
5046365beadSRussell King static void sa11x0_dma_issue_pending(struct dma_chan *chan)
5056365beadSRussell King {
5066365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5076365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
5086365beadSRussell King 	unsigned long flags;
5096365beadSRussell King 
51050437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
51150437bffSRussell King 	if (vchan_issue_pending(&c->vc)) {
51250437bffSRussell King 		if (!c->phy) {
5136365beadSRussell King 			spin_lock(&d->lock);
51450437bffSRussell King 			if (list_empty(&c->node)) {
5156365beadSRussell King 				list_add_tail(&c->node, &d->chan_pending);
5166365beadSRussell King 				tasklet_schedule(&d->task);
51750437bffSRussell King 				dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
5186365beadSRussell King 			}
5196365beadSRussell King 			spin_unlock(&d->lock);
5206365beadSRussell King 		}
52150437bffSRussell King 	} else
52250437bffSRussell King 		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
52350437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
5246365beadSRussell King }
5256365beadSRussell King 
5266365beadSRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
5276365beadSRussell King 	struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
528d9d54540SRussell King 	enum dma_transfer_direction dir, unsigned long flags, void *context)
5296365beadSRussell King {
5306365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5316365beadSRussell King 	struct sa11x0_dma_desc *txd;
5326365beadSRussell King 	struct scatterlist *sgent;
5336365beadSRussell King 	unsigned i, j = sglen;
5346365beadSRussell King 	size_t size = 0;
5356365beadSRussell King 
5366365beadSRussell King 	/* SA11x0 channels can only operate in their native direction */
5376365beadSRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
5386365beadSRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
53950437bffSRussell King 			&c->vc, c->ddar, dir);
5406365beadSRussell King 		return NULL;
5416365beadSRussell King 	}
5426365beadSRussell King 
5436365beadSRussell King 	/* Do not allow zero-sized txds */
5446365beadSRussell King 	if (sglen == 0)
5456365beadSRussell King 		return NULL;
5466365beadSRussell King 
5476365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5486365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5496365beadSRussell King 		unsigned int len = sg_dma_len(sgent);
5506365beadSRussell King 
5516365beadSRussell King 		if (len > DMA_MAX_SIZE)
5526365beadSRussell King 			j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
5536365beadSRussell King 		if (addr & DMA_ALIGN) {
5546365beadSRussell King 			dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
55550437bffSRussell King 				&c->vc, addr);
5566365beadSRussell King 			return NULL;
5576365beadSRussell King 		}
5586365beadSRussell King 	}
5596365beadSRussell King 
5606365beadSRussell King 	txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
5616365beadSRussell King 	if (!txd) {
56250437bffSRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
5636365beadSRussell King 		return NULL;
5646365beadSRussell King 	}
5656365beadSRussell King 
5666365beadSRussell King 	j = 0;
5676365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5686365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5696365beadSRussell King 		unsigned len = sg_dma_len(sgent);
5706365beadSRussell King 
5716365beadSRussell King 		size += len;
5726365beadSRussell King 
5736365beadSRussell King 		do {
5746365beadSRussell King 			unsigned tlen = len;
5756365beadSRussell King 
5766365beadSRussell King 			/*
5776365beadSRussell King 			 * Check whether the transfer will fit.  If not, try
5786365beadSRussell King 			 * to split the transfer up such that we end up with
5796365beadSRussell King 			 * equal chunks - but make sure that we preserve the
5806365beadSRussell King 			 * alignment.  This avoids small segments.
5816365beadSRussell King 			 */
5826365beadSRussell King 			if (tlen > DMA_MAX_SIZE) {
5836365beadSRussell King 				unsigned mult = DIV_ROUND_UP(tlen,
5846365beadSRussell King 					DMA_MAX_SIZE & ~DMA_ALIGN);
5856365beadSRussell King 
5866365beadSRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
5876365beadSRussell King 			}
5886365beadSRussell King 
5896365beadSRussell King 			txd->sg[j].addr = addr;
5906365beadSRussell King 			txd->sg[j].len = tlen;
5916365beadSRussell King 
5926365beadSRussell King 			addr += tlen;
5936365beadSRussell King 			len -= tlen;
5946365beadSRussell King 			j++;
5956365beadSRussell King 		} while (len);
5966365beadSRussell King 	}
5976365beadSRussell King 
5986365beadSRussell King 	txd->ddar = c->ddar;
5996365beadSRussell King 	txd->size = size;
6006365beadSRussell King 	txd->sglen = j;
6016365beadSRussell King 
6026365beadSRussell King 	dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
60350437bffSRussell King 		&c->vc, &txd->vd, txd->size, txd->sglen);
6046365beadSRussell King 
60550437bffSRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, flags);
6066365beadSRussell King }
6076365beadSRussell King 
608d9444325SRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(
609d9444325SRussell King 	struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period,
61031c1e5a1SLaurent Pinchart 	enum dma_transfer_direction dir, unsigned long flags)
611d9444325SRussell King {
612d9444325SRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
613d9444325SRussell King 	struct sa11x0_dma_desc *txd;
614d9444325SRussell King 	unsigned i, j, k, sglen, sgperiod;
615d9444325SRussell King 
616d9444325SRussell King 	/* SA11x0 channels can only operate in their native direction */
617d9444325SRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
618d9444325SRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
619d9444325SRussell King 			&c->vc, c->ddar, dir);
620d9444325SRussell King 		return NULL;
621d9444325SRussell King 	}
622d9444325SRussell King 
623d9444325SRussell King 	sgperiod = DIV_ROUND_UP(period, DMA_MAX_SIZE & ~DMA_ALIGN);
624d9444325SRussell King 	sglen = size * sgperiod / period;
625d9444325SRussell King 
626d9444325SRussell King 	/* Do not allow zero-sized txds */
627d9444325SRussell King 	if (sglen == 0)
628d9444325SRussell King 		return NULL;
629d9444325SRussell King 
630d9444325SRussell King 	txd = kzalloc(sizeof(*txd) + sglen * sizeof(txd->sg[0]), GFP_ATOMIC);
631d9444325SRussell King 	if (!txd) {
632d9444325SRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
633d9444325SRussell King 		return NULL;
634d9444325SRussell King 	}
635d9444325SRussell King 
636d9444325SRussell King 	for (i = k = 0; i < size / period; i++) {
637d9444325SRussell King 		size_t tlen, len = period;
638d9444325SRussell King 
639d9444325SRussell King 		for (j = 0; j < sgperiod; j++, k++) {
640d9444325SRussell King 			tlen = len;
641d9444325SRussell King 
642d9444325SRussell King 			if (tlen > DMA_MAX_SIZE) {
643d9444325SRussell King 				unsigned mult = DIV_ROUND_UP(tlen, DMA_MAX_SIZE & ~DMA_ALIGN);
644d9444325SRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
645d9444325SRussell King 			}
646d9444325SRussell King 
647d9444325SRussell King 			txd->sg[k].addr = addr;
648d9444325SRussell King 			txd->sg[k].len = tlen;
649d9444325SRussell King 			addr += tlen;
650d9444325SRussell King 			len -= tlen;
651d9444325SRussell King 		}
652d9444325SRussell King 
653d9444325SRussell King 		WARN_ON(len != 0);
654d9444325SRussell King 	}
655d9444325SRussell King 
656d9444325SRussell King 	WARN_ON(k != sglen);
657d9444325SRussell King 
658d9444325SRussell King 	txd->ddar = c->ddar;
659d9444325SRussell King 	txd->size = size;
660d9444325SRussell King 	txd->sglen = sglen;
661d9444325SRussell King 	txd->cyclic = 1;
662d9444325SRussell King 	txd->period = sgperiod;
663d9444325SRussell King 
664d9444325SRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
665d9444325SRussell King }
666d9444325SRussell King 
667a0a51a64SMaxime Ripard static int sa11x0_dma_device_config(struct dma_chan *chan,
6684a533218SMaxime Ripard 				    struct dma_slave_config *cfg)
6696365beadSRussell King {
6704a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
6716365beadSRussell King 	u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
6726365beadSRussell King 	dma_addr_t addr;
6736365beadSRussell King 	enum dma_slave_buswidth width;
6746365beadSRussell King 	u32 maxburst;
6756365beadSRussell King 
6766365beadSRussell King 	if (ddar & DDAR_RW) {
6776365beadSRussell King 		addr = cfg->src_addr;
6786365beadSRussell King 		width = cfg->src_addr_width;
6796365beadSRussell King 		maxburst = cfg->src_maxburst;
6806365beadSRussell King 	} else {
6816365beadSRussell King 		addr = cfg->dst_addr;
6826365beadSRussell King 		width = cfg->dst_addr_width;
6836365beadSRussell King 		maxburst = cfg->dst_maxburst;
6846365beadSRussell King 	}
6856365beadSRussell King 
6866365beadSRussell King 	if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
6876365beadSRussell King 	     width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
6886365beadSRussell King 	    (maxburst != 4 && maxburst != 8))
6896365beadSRussell King 		return -EINVAL;
6906365beadSRussell King 
6916365beadSRussell King 	if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
6926365beadSRussell King 		ddar |= DDAR_DW;
6936365beadSRussell King 	if (maxburst == 8)
6946365beadSRussell King 		ddar |= DDAR_BS;
6956365beadSRussell King 
69650437bffSRussell King 	dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
69750437bffSRussell King 		&c->vc, addr, width, maxburst);
6986365beadSRussell King 
6996365beadSRussell King 	c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
7006365beadSRussell King 
7016365beadSRussell King 	return 0;
7026365beadSRussell King }
7036365beadSRussell King 
704a0a51a64SMaxime Ripard static int sa11x0_dma_device_pause(struct dma_chan *chan)
7056365beadSRussell King {
7066365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7076365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7086365beadSRussell King 	struct sa11x0_dma_phy *p;
7096365beadSRussell King 	LIST_HEAD(head);
7106365beadSRussell King 	unsigned long flags;
7116365beadSRussell King 
7124a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
7134a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7144a533218SMaxime Ripard 	if (c->status == DMA_IN_PROGRESS) {
7154a533218SMaxime Ripard 		c->status = DMA_PAUSED;
7166365beadSRussell King 
7174a533218SMaxime Ripard 		p = c->phy;
7184a533218SMaxime Ripard 		if (p) {
7194a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
7204a533218SMaxime Ripard 		} else {
7214a533218SMaxime Ripard 			spin_lock(&d->lock);
7224a533218SMaxime Ripard 			list_del_init(&c->node);
7234a533218SMaxime Ripard 			spin_unlock(&d->lock);
7244a533218SMaxime Ripard 		}
7254a533218SMaxime Ripard 	}
7264a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7274a533218SMaxime Ripard 
7284a533218SMaxime Ripard 	return 0;
7294a533218SMaxime Ripard }
7304a533218SMaxime Ripard 
731a0a51a64SMaxime Ripard static int sa11x0_dma_device_resume(struct dma_chan *chan)
7324a533218SMaxime Ripard {
7334a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7344a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7354a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7364a533218SMaxime Ripard 	LIST_HEAD(head);
7374a533218SMaxime Ripard 	unsigned long flags;
7384a533218SMaxime Ripard 
7394a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
7404a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7414a533218SMaxime Ripard 	if (c->status == DMA_PAUSED) {
7424a533218SMaxime Ripard 		c->status = DMA_IN_PROGRESS;
7434a533218SMaxime Ripard 
7444a533218SMaxime Ripard 		p = c->phy;
7454a533218SMaxime Ripard 		if (p) {
7464a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
7474a533218SMaxime Ripard 		} else if (!list_empty(&c->vc.desc_issued)) {
7484a533218SMaxime Ripard 			spin_lock(&d->lock);
7494a533218SMaxime Ripard 			list_add_tail(&c->node, &d->chan_pending);
7504a533218SMaxime Ripard 			spin_unlock(&d->lock);
7514a533218SMaxime Ripard 		}
7524a533218SMaxime Ripard 	}
7534a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7544a533218SMaxime Ripard 
7554a533218SMaxime Ripard 	return 0;
7564a533218SMaxime Ripard }
7574a533218SMaxime Ripard 
758a0a51a64SMaxime Ripard static int sa11x0_dma_device_terminate_all(struct dma_chan *chan)
7594a533218SMaxime Ripard {
7604a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7614a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7624a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7634a533218SMaxime Ripard 	LIST_HEAD(head);
7644a533218SMaxime Ripard 	unsigned long flags;
7654a533218SMaxime Ripard 
76650437bffSRussell King 	dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
7676365beadSRussell King 	/* Clear the tx descriptor lists */
76850437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
76950437bffSRussell King 	vchan_get_all_descriptors(&c->vc, &head);
7706365beadSRussell King 
7716365beadSRussell King 	p = c->phy;
7726365beadSRussell King 	if (p) {
7736365beadSRussell King 		dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
7746365beadSRussell King 		/* vchan is assigned to a pchan - stop the channel */
7756365beadSRussell King 		writel(DCSR_RUN | DCSR_IE |
7766365beadSRussell King 		       DCSR_STRTA | DCSR_DONEA |
7776365beadSRussell King 		       DCSR_STRTB | DCSR_DONEB,
7786365beadSRussell King 		       p->base + DMA_DCSR_C);
7796365beadSRussell King 
7806365beadSRussell King 		if (p->txd_load) {
7816365beadSRussell King 			if (p->txd_load != p->txd_done)
78250437bffSRussell King 				list_add_tail(&p->txd_load->vd.node, &head);
7836365beadSRussell King 			p->txd_load = NULL;
7846365beadSRussell King 		}
7856365beadSRussell King 		if (p->txd_done) {
78650437bffSRussell King 			list_add_tail(&p->txd_done->vd.node, &head);
7876365beadSRussell King 			p->txd_done = NULL;
7886365beadSRussell King 		}
7896365beadSRussell King 		c->phy = NULL;
7906365beadSRussell King 		spin_lock(&d->lock);
7916365beadSRussell King 		p->vchan = NULL;
7926365beadSRussell King 		spin_unlock(&d->lock);
7936365beadSRussell King 		tasklet_schedule(&d->task);
7946365beadSRussell King 	}
79550437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
79650437bffSRussell King 	vchan_dma_desc_free_list(&c->vc, &head);
7976365beadSRussell King 
7984a533218SMaxime Ripard 	return 0;
7996365beadSRussell King }
8006365beadSRussell King 
8016365beadSRussell King struct sa11x0_dma_channel_desc {
8026365beadSRussell King 	u32 ddar;
8036365beadSRussell King 	const char *name;
8046365beadSRussell King };
8056365beadSRussell King 
8066365beadSRussell King #define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
8076365beadSRussell King static const struct sa11x0_dma_channel_desc chan_desc[] = {
8086365beadSRussell King 	CD(Ser0UDCTr, 0),
8096365beadSRussell King 	CD(Ser0UDCRc, DDAR_RW),
8106365beadSRussell King 	CD(Ser1SDLCTr, 0),
8116365beadSRussell King 	CD(Ser1SDLCRc, DDAR_RW),
8126365beadSRussell King 	CD(Ser1UARTTr, 0),
8136365beadSRussell King 	CD(Ser1UARTRc, DDAR_RW),
8146365beadSRussell King 	CD(Ser2ICPTr, 0),
8156365beadSRussell King 	CD(Ser2ICPRc, DDAR_RW),
8166365beadSRussell King 	CD(Ser3UARTTr, 0),
8176365beadSRussell King 	CD(Ser3UARTRc, DDAR_RW),
8186365beadSRussell King 	CD(Ser4MCP0Tr, 0),
8196365beadSRussell King 	CD(Ser4MCP0Rc, DDAR_RW),
8206365beadSRussell King 	CD(Ser4MCP1Tr, 0),
8216365beadSRussell King 	CD(Ser4MCP1Rc, DDAR_RW),
8226365beadSRussell King 	CD(Ser4SSPTr, 0),
8236365beadSRussell King 	CD(Ser4SSPRc, DDAR_RW),
8246365beadSRussell King };
8256365beadSRussell King 
826463a1f8bSBill Pemberton static int sa11x0_dma_init_dmadev(struct dma_device *dmadev,
8276365beadSRussell King 	struct device *dev)
8286365beadSRussell King {
8296365beadSRussell King 	unsigned i;
8306365beadSRussell King 
8316365beadSRussell King 	INIT_LIST_HEAD(&dmadev->channels);
8326365beadSRussell King 	dmadev->dev = dev;
8336365beadSRussell King 	dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
834a0a51a64SMaxime Ripard 	dmadev->device_config = sa11x0_dma_device_config;
835a0a51a64SMaxime Ripard 	dmadev->device_pause = sa11x0_dma_device_pause;
836a0a51a64SMaxime Ripard 	dmadev->device_resume = sa11x0_dma_device_resume;
837a0a51a64SMaxime Ripard 	dmadev->device_terminate_all = sa11x0_dma_device_terminate_all;
8386365beadSRussell King 	dmadev->device_tx_status = sa11x0_dma_tx_status;
8396365beadSRussell King 	dmadev->device_issue_pending = sa11x0_dma_issue_pending;
8406365beadSRussell King 
8419aa71711SMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(chan_desc); i++) {
8426365beadSRussell King 		struct sa11x0_dma_chan *c;
8436365beadSRussell King 
8446365beadSRussell King 		c = kzalloc(sizeof(*c), GFP_KERNEL);
8456365beadSRussell King 		if (!c) {
8466365beadSRussell King 			dev_err(dev, "no memory for channel %u\n", i);
8476365beadSRussell King 			return -ENOMEM;
8486365beadSRussell King 		}
8496365beadSRussell King 
8506365beadSRussell King 		c->status = DMA_IN_PROGRESS;
8516365beadSRussell King 		c->ddar = chan_desc[i].ddar;
8526365beadSRussell King 		c->name = chan_desc[i].name;
8536365beadSRussell King 		INIT_LIST_HEAD(&c->node);
85450437bffSRussell King 
85550437bffSRussell King 		c->vc.desc_free = sa11x0_dma_free_desc;
85650437bffSRussell King 		vchan_init(&c->vc, dmadev);
8576365beadSRussell King 	}
8586365beadSRussell King 
8596365beadSRussell King 	return dma_async_device_register(dmadev);
8606365beadSRussell King }
8616365beadSRussell King 
8626365beadSRussell King static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
8636365beadSRussell King 	void *data)
8646365beadSRussell King {
8656365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8666365beadSRussell King 
8676365beadSRussell King 	if (irq <= 0)
8686365beadSRussell King 		return -ENXIO;
8696365beadSRussell King 
8706365beadSRussell King 	return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
8716365beadSRussell King }
8726365beadSRussell King 
8736365beadSRussell King static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
8746365beadSRussell King 	void *data)
8756365beadSRussell King {
8766365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8776365beadSRussell King 	if (irq > 0)
8786365beadSRussell King 		free_irq(irq, data);
8796365beadSRussell King }
8806365beadSRussell King 
8816365beadSRussell King static void sa11x0_dma_free_channels(struct dma_device *dmadev)
8826365beadSRussell King {
8836365beadSRussell King 	struct sa11x0_dma_chan *c, *cn;
8846365beadSRussell King 
88550437bffSRussell King 	list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
88650437bffSRussell King 		list_del(&c->vc.chan.device_node);
88750437bffSRussell King 		tasklet_kill(&c->vc.task);
8886365beadSRussell King 		kfree(c);
8896365beadSRussell King 	}
8906365beadSRussell King }
8916365beadSRussell King 
892463a1f8bSBill Pemberton static int sa11x0_dma_probe(struct platform_device *pdev)
8936365beadSRussell King {
8946365beadSRussell King 	struct sa11x0_dma_dev *d;
8956365beadSRussell King 	struct resource *res;
8966365beadSRussell King 	unsigned i;
8976365beadSRussell King 	int ret;
8986365beadSRussell King 
8996365beadSRussell King 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9006365beadSRussell King 	if (!res)
9016365beadSRussell King 		return -ENXIO;
9026365beadSRussell King 
9036365beadSRussell King 	d = kzalloc(sizeof(*d), GFP_KERNEL);
9046365beadSRussell King 	if (!d) {
9056365beadSRussell King 		ret = -ENOMEM;
9066365beadSRussell King 		goto err_alloc;
9076365beadSRussell King 	}
9086365beadSRussell King 
9096365beadSRussell King 	spin_lock_init(&d->lock);
9106365beadSRussell King 	INIT_LIST_HEAD(&d->chan_pending);
9116365beadSRussell King 
9126365beadSRussell King 	d->base = ioremap(res->start, resource_size(res));
9136365beadSRussell King 	if (!d->base) {
9146365beadSRussell King 		ret = -ENOMEM;
9156365beadSRussell King 		goto err_ioremap;
9166365beadSRussell King 	}
9176365beadSRussell King 
9186365beadSRussell King 	tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
9196365beadSRussell King 
9206365beadSRussell King 	for (i = 0; i < NR_PHY_CHAN; i++) {
9216365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[i];
9226365beadSRussell King 
9236365beadSRussell King 		p->dev = d;
9246365beadSRussell King 		p->num = i;
9256365beadSRussell King 		p->base = d->base + i * DMA_SIZE;
9266365beadSRussell King 		writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
9276365beadSRussell King 			DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
9286365beadSRussell King 			p->base + DMA_DCSR_C);
9296365beadSRussell King 		writel_relaxed(0, p->base + DMA_DDAR);
9306365beadSRussell King 
9316365beadSRussell King 		ret = sa11x0_dma_request_irq(pdev, i, p);
9326365beadSRussell King 		if (ret) {
9336365beadSRussell King 			while (i) {
9346365beadSRussell King 				i--;
9356365beadSRussell King 				sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
9366365beadSRussell King 			}
9376365beadSRussell King 			goto err_irq;
9386365beadSRussell King 		}
9396365beadSRussell King 	}
9406365beadSRussell King 
9416365beadSRussell King 	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
942d9444325SRussell King 	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
9436365beadSRussell King 	d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
944d9444325SRussell King 	d->slave.device_prep_dma_cyclic = sa11x0_dma_prep_dma_cyclic;
945*28591dfdSDmitry Eremin-Solenikov 	d->slave.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
946*28591dfdSDmitry Eremin-Solenikov 	d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
947*28591dfdSDmitry Eremin-Solenikov 	d->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
948*28591dfdSDmitry Eremin-Solenikov 				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES);
949*28591dfdSDmitry Eremin-Solenikov 	d->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
950*28591dfdSDmitry Eremin-Solenikov 				   BIT(DMA_SLAVE_BUSWIDTH_2_BYTES);
9516365beadSRussell King 	ret = sa11x0_dma_init_dmadev(&d->slave, &pdev->dev);
9526365beadSRussell King 	if (ret) {
9536365beadSRussell King 		dev_warn(d->slave.dev, "failed to register slave async device: %d\n",
9546365beadSRussell King 			ret);
9556365beadSRussell King 		goto err_slave_reg;
9566365beadSRussell King 	}
9576365beadSRussell King 
9586365beadSRussell King 	platform_set_drvdata(pdev, d);
9596365beadSRussell King 	return 0;
9606365beadSRussell King 
9616365beadSRussell King  err_slave_reg:
9626365beadSRussell King 	sa11x0_dma_free_channels(&d->slave);
9636365beadSRussell King 	for (i = 0; i < NR_PHY_CHAN; i++)
9646365beadSRussell King 		sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
9656365beadSRussell King  err_irq:
9666365beadSRussell King 	tasklet_kill(&d->task);
9676365beadSRussell King 	iounmap(d->base);
9686365beadSRussell King  err_ioremap:
9696365beadSRussell King 	kfree(d);
9706365beadSRussell King  err_alloc:
9716365beadSRussell King 	return ret;
9726365beadSRussell King }
9736365beadSRussell King 
9744bf27b8bSGreg Kroah-Hartman static int sa11x0_dma_remove(struct platform_device *pdev)
9756365beadSRussell King {
9766365beadSRussell King 	struct sa11x0_dma_dev *d = platform_get_drvdata(pdev);
9776365beadSRussell King 	unsigned pch;
9786365beadSRussell King 
9796365beadSRussell King 	dma_async_device_unregister(&d->slave);
9806365beadSRussell King 
9816365beadSRussell King 	sa11x0_dma_free_channels(&d->slave);
9826365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++)
9836365beadSRussell King 		sa11x0_dma_free_irq(pdev, pch, &d->phy[pch]);
9846365beadSRussell King 	tasklet_kill(&d->task);
9856365beadSRussell King 	iounmap(d->base);
9866365beadSRussell King 	kfree(d);
9876365beadSRussell King 
9886365beadSRussell King 	return 0;
9896365beadSRussell King }
9906365beadSRussell King 
9916365beadSRussell King static int sa11x0_dma_suspend(struct device *dev)
9926365beadSRussell King {
9936365beadSRussell King 	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
9946365beadSRussell King 	unsigned pch;
9956365beadSRussell King 
9966365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
9976365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[pch];
9986365beadSRussell King 		u32 dcsr, saved_dcsr;
9996365beadSRussell King 
10006365beadSRussell King 		dcsr = saved_dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10016365beadSRussell King 		if (dcsr & DCSR_RUN) {
10026365beadSRussell King 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
10036365beadSRussell King 			dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10046365beadSRussell King 		}
10056365beadSRussell King 
10066365beadSRussell King 		saved_dcsr &= DCSR_RUN | DCSR_IE;
10076365beadSRussell King 		if (dcsr & DCSR_BIU) {
10086365beadSRussell King 			p->dbs[0] = readl_relaxed(p->base + DMA_DBSB);
10096365beadSRussell King 			p->dbt[0] = readl_relaxed(p->base + DMA_DBTB);
10106365beadSRussell King 			p->dbs[1] = readl_relaxed(p->base + DMA_DBSA);
10116365beadSRussell King 			p->dbt[1] = readl_relaxed(p->base + DMA_DBTA);
10126365beadSRussell King 			saved_dcsr |= (dcsr & DCSR_STRTA ? DCSR_STRTB : 0) |
10136365beadSRussell King 				      (dcsr & DCSR_STRTB ? DCSR_STRTA : 0);
10146365beadSRussell King 		} else {
10156365beadSRussell King 			p->dbs[0] = readl_relaxed(p->base + DMA_DBSA);
10166365beadSRussell King 			p->dbt[0] = readl_relaxed(p->base + DMA_DBTA);
10176365beadSRussell King 			p->dbs[1] = readl_relaxed(p->base + DMA_DBSB);
10186365beadSRussell King 			p->dbt[1] = readl_relaxed(p->base + DMA_DBTB);
10196365beadSRussell King 			saved_dcsr |= dcsr & (DCSR_STRTA | DCSR_STRTB);
10206365beadSRussell King 		}
10216365beadSRussell King 		p->dcsr = saved_dcsr;
10226365beadSRussell King 
10236365beadSRussell King 		writel(DCSR_STRTA | DCSR_STRTB, p->base + DMA_DCSR_C);
10246365beadSRussell King 	}
10256365beadSRussell King 
10266365beadSRussell King 	return 0;
10276365beadSRussell King }
10286365beadSRussell King 
10296365beadSRussell King static int sa11x0_dma_resume(struct device *dev)
10306365beadSRussell King {
10316365beadSRussell King 	struct sa11x0_dma_dev *d = dev_get_drvdata(dev);
10326365beadSRussell King 	unsigned pch;
10336365beadSRussell King 
10346365beadSRussell King 	for (pch = 0; pch < NR_PHY_CHAN; pch++) {
10356365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[pch];
10366365beadSRussell King 		struct sa11x0_dma_desc *txd = NULL;
10376365beadSRussell King 		u32 dcsr = readl_relaxed(p->base + DMA_DCSR_R);
10386365beadSRussell King 
10396365beadSRussell King 		WARN_ON(dcsr & (DCSR_BIU | DCSR_STRTA | DCSR_STRTB | DCSR_RUN));
10406365beadSRussell King 
10416365beadSRussell King 		if (p->txd_done)
10426365beadSRussell King 			txd = p->txd_done;
10436365beadSRussell King 		else if (p->txd_load)
10446365beadSRussell King 			txd = p->txd_load;
10456365beadSRussell King 
10466365beadSRussell King 		if (!txd)
10476365beadSRussell King 			continue;
10486365beadSRussell King 
10496365beadSRussell King 		writel_relaxed(txd->ddar, p->base + DMA_DDAR);
10506365beadSRussell King 
10516365beadSRussell King 		writel_relaxed(p->dbs[0], p->base + DMA_DBSA);
10526365beadSRussell King 		writel_relaxed(p->dbt[0], p->base + DMA_DBTA);
10536365beadSRussell King 		writel_relaxed(p->dbs[1], p->base + DMA_DBSB);
10546365beadSRussell King 		writel_relaxed(p->dbt[1], p->base + DMA_DBTB);
10556365beadSRussell King 		writel_relaxed(p->dcsr, p->base + DMA_DCSR_S);
10566365beadSRussell King 	}
10576365beadSRussell King 
10586365beadSRussell King 	return 0;
10596365beadSRussell King }
10606365beadSRussell King 
10616365beadSRussell King static const struct dev_pm_ops sa11x0_dma_pm_ops = {
10626365beadSRussell King 	.suspend_noirq = sa11x0_dma_suspend,
10636365beadSRussell King 	.resume_noirq = sa11x0_dma_resume,
10646365beadSRussell King 	.freeze_noirq = sa11x0_dma_suspend,
10656365beadSRussell King 	.thaw_noirq = sa11x0_dma_resume,
10666365beadSRussell King 	.poweroff_noirq = sa11x0_dma_suspend,
10676365beadSRussell King 	.restore_noirq = sa11x0_dma_resume,
10686365beadSRussell King };
10696365beadSRussell King 
10706365beadSRussell King static struct platform_driver sa11x0_dma_driver = {
10716365beadSRussell King 	.driver = {
10726365beadSRussell King 		.name	= "sa11x0-dma",
10736365beadSRussell King 		.pm	= &sa11x0_dma_pm_ops,
10746365beadSRussell King 	},
10756365beadSRussell King 	.probe		= sa11x0_dma_probe,
1076a7d6e3ecSBill Pemberton 	.remove		= sa11x0_dma_remove,
10776365beadSRussell King };
10786365beadSRussell King 
10796365beadSRussell King bool sa11x0_dma_filter_fn(struct dma_chan *chan, void *param)
10806365beadSRussell King {
10816365beadSRussell King 	if (chan->device->dev->driver == &sa11x0_dma_driver.driver) {
10826365beadSRussell King 		struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
10836365beadSRussell King 		const char *p = param;
10846365beadSRussell King 
10856365beadSRussell King 		return !strcmp(c->name, p);
10866365beadSRussell King 	}
10876365beadSRussell King 	return false;
10886365beadSRussell King }
10896365beadSRussell King EXPORT_SYMBOL(sa11x0_dma_filter_fn);
10906365beadSRussell King 
10916365beadSRussell King static int __init sa11x0_dma_init(void)
10926365beadSRussell King {
10936365beadSRussell King 	return platform_driver_register(&sa11x0_dma_driver);
10946365beadSRussell King }
10956365beadSRussell King subsys_initcall(sa11x0_dma_init);
10966365beadSRussell King 
10976365beadSRussell King static void __exit sa11x0_dma_exit(void)
10986365beadSRussell King {
10996365beadSRussell King 	platform_driver_unregister(&sa11x0_dma_driver);
11006365beadSRussell King }
11016365beadSRussell King module_exit(sa11x0_dma_exit);
11026365beadSRussell King 
11036365beadSRussell King MODULE_AUTHOR("Russell King");
11046365beadSRussell King MODULE_DESCRIPTION("SA-11x0 DMA driver");
11056365beadSRussell King MODULE_LICENSE("GPL v2");
11066365beadSRussell King MODULE_ALIAS("platform:sa11x0-dma");
1107