xref: /openbmc/linux/drivers/dma/sa11x0-dma.c (revision a0a51a64f6a3e718e6d461f11d72d9ce41c706d6)
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 int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
3936365beadSRussell King {
3946365beadSRussell King 	return 0;
3956365beadSRussell King }
3966365beadSRussell King 
3976365beadSRussell King static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
3986365beadSRussell King {
3996365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
4006365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
4016365beadSRussell King 	unsigned long flags;
4026365beadSRussell King 
40350437bffSRussell King 	spin_lock_irqsave(&d->lock, flags);
4046365beadSRussell King 	list_del_init(&c->node);
40550437bffSRussell King 	spin_unlock_irqrestore(&d->lock, flags);
4066365beadSRussell King 
40750437bffSRussell King 	vchan_free_chan_resources(&c->vc);
4086365beadSRussell King }
4096365beadSRussell King 
4106365beadSRussell King static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
4116365beadSRussell King {
4126365beadSRussell King 	unsigned reg;
4136365beadSRussell King 	u32 dcsr;
4146365beadSRussell King 
4156365beadSRussell King 	dcsr = readl_relaxed(p->base + DMA_DCSR_R);
4166365beadSRussell King 
4176365beadSRussell King 	if ((dcsr & (DCSR_BIU | DCSR_STRTA)) == DCSR_STRTA ||
4186365beadSRussell King 	    (dcsr & (DCSR_BIU | DCSR_STRTB)) == DCSR_BIU)
4196365beadSRussell King 		reg = DMA_DBSA;
4206365beadSRussell King 	else
4216365beadSRussell King 		reg = DMA_DBSB;
4226365beadSRussell King 
4236365beadSRussell King 	return readl_relaxed(p->base + reg);
4246365beadSRussell King }
4256365beadSRussell King 
4266365beadSRussell King static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
4276365beadSRussell King 	dma_cookie_t cookie, struct dma_tx_state *state)
4286365beadSRussell King {
4296365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
4306365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
4316365beadSRussell King 	struct sa11x0_dma_phy *p;
43263fe23c3SRussell King 	struct virt_dma_desc *vd;
4336365beadSRussell King 	unsigned long flags;
4346365beadSRussell King 	enum dma_status ret;
4356365beadSRussell King 
43650437bffSRussell King 	ret = dma_cookie_status(&c->vc.chan, cookie, state);
437fdebb768SVinod Koul 	if (ret == DMA_COMPLETE)
4386365beadSRussell King 		return ret;
4396365beadSRussell King 
44063fe23c3SRussell King 	if (!state)
44163fe23c3SRussell King 		return c->status;
44263fe23c3SRussell King 
44350437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
4446365beadSRussell King 	p = c->phy;
44563fe23c3SRussell King 
44663fe23c3SRussell King 	/*
44763fe23c3SRussell King 	 * If the cookie is on our issue queue, then the residue is
44863fe23c3SRussell King 	 * its total size.
44963fe23c3SRussell King 	 */
45063fe23c3SRussell King 	vd = vchan_find_desc(&c->vc, cookie);
45163fe23c3SRussell King 	if (vd) {
45263fe23c3SRussell King 		state->residue = container_of(vd, struct sa11x0_dma_desc, vd)->size;
45363fe23c3SRussell King 	} else if (!p) {
45463fe23c3SRussell King 		state->residue = 0;
45563fe23c3SRussell King 	} else {
45663fe23c3SRussell King 		struct sa11x0_dma_desc *txd;
45763fe23c3SRussell King 		size_t bytes = 0;
45863fe23c3SRussell King 
45963fe23c3SRussell King 		if (p->txd_done && p->txd_done->vd.tx.cookie == cookie)
46063fe23c3SRussell King 			txd = p->txd_done;
46163fe23c3SRussell King 		else if (p->txd_load && p->txd_load->vd.tx.cookie == cookie)
46263fe23c3SRussell King 			txd = p->txd_load;
46363fe23c3SRussell King 		else
46463fe23c3SRussell King 			txd = NULL;
46563fe23c3SRussell King 
4666365beadSRussell King 		ret = c->status;
46763fe23c3SRussell King 		if (txd) {
4686365beadSRussell King 			dma_addr_t addr = sa11x0_dma_pos(p);
46963fe23c3SRussell King 			unsigned i;
4706365beadSRussell King 
4716365beadSRussell King 			dev_vdbg(d->slave.dev, "tx_status: addr:%x\n", addr);
4726365beadSRussell King 
4736365beadSRussell King 			for (i = 0; i < txd->sglen; i++) {
4746365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x\n",
4756365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4766365beadSRussell King 				if (addr >= txd->sg[i].addr &&
4776365beadSRussell King 				    addr < txd->sg[i].addr + txd->sg[i].len) {
4786365beadSRussell King 					unsigned len;
4796365beadSRussell King 
4806365beadSRussell King 					len = txd->sg[i].len -
4816365beadSRussell King 						(addr - txd->sg[i].addr);
4826365beadSRussell King 					dev_vdbg(d->slave.dev, "tx_status: [%u] +%x\n",
4836365beadSRussell King 						i, len);
4846365beadSRussell King 					bytes += len;
4856365beadSRussell King 					i++;
4866365beadSRussell King 					break;
4876365beadSRussell King 				}
4886365beadSRussell King 			}
4896365beadSRussell King 			for (; i < txd->sglen; i++) {
4906365beadSRussell King 				dev_vdbg(d->slave.dev, "tx_status: [%u] %x+%x ++\n",
4916365beadSRussell King 					i, txd->sg[i].addr, txd->sg[i].len);
4926365beadSRussell King 				bytes += txd->sg[i].len;
4936365beadSRussell King 			}
4946365beadSRussell King 		}
49563fe23c3SRussell King 		state->residue = bytes;
4966365beadSRussell King 	}
49750437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
4986365beadSRussell King 
49963fe23c3SRussell King 	dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", state->residue);
5006365beadSRussell King 
5016365beadSRussell King 	return ret;
5026365beadSRussell King }
5036365beadSRussell King 
5046365beadSRussell King /*
5056365beadSRussell King  * Move pending txds to the issued list, and re-init pending list.
5066365beadSRussell King  * If not already pending, add this channel to the list of pending
5076365beadSRussell King  * channels and trigger the tasklet to run.
5086365beadSRussell King  */
5096365beadSRussell King static void sa11x0_dma_issue_pending(struct dma_chan *chan)
5106365beadSRussell King {
5116365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5126365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
5136365beadSRussell King 	unsigned long flags;
5146365beadSRussell King 
51550437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
51650437bffSRussell King 	if (vchan_issue_pending(&c->vc)) {
51750437bffSRussell King 		if (!c->phy) {
5186365beadSRussell King 			spin_lock(&d->lock);
51950437bffSRussell King 			if (list_empty(&c->node)) {
5206365beadSRussell King 				list_add_tail(&c->node, &d->chan_pending);
5216365beadSRussell King 				tasklet_schedule(&d->task);
52250437bffSRussell King 				dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
5236365beadSRussell King 			}
5246365beadSRussell King 			spin_unlock(&d->lock);
5256365beadSRussell King 		}
52650437bffSRussell King 	} else
52750437bffSRussell King 		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
52850437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
5296365beadSRussell King }
5306365beadSRussell King 
5316365beadSRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
5326365beadSRussell King 	struct dma_chan *chan, struct scatterlist *sg, unsigned int sglen,
533d9d54540SRussell King 	enum dma_transfer_direction dir, unsigned long flags, void *context)
5346365beadSRussell King {
5356365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
5366365beadSRussell King 	struct sa11x0_dma_desc *txd;
5376365beadSRussell King 	struct scatterlist *sgent;
5386365beadSRussell King 	unsigned i, j = sglen;
5396365beadSRussell King 	size_t size = 0;
5406365beadSRussell King 
5416365beadSRussell King 	/* SA11x0 channels can only operate in their native direction */
5426365beadSRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
5436365beadSRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
54450437bffSRussell King 			&c->vc, c->ddar, dir);
5456365beadSRussell King 		return NULL;
5466365beadSRussell King 	}
5476365beadSRussell King 
5486365beadSRussell King 	/* Do not allow zero-sized txds */
5496365beadSRussell King 	if (sglen == 0)
5506365beadSRussell King 		return NULL;
5516365beadSRussell King 
5526365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5536365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5546365beadSRussell King 		unsigned int len = sg_dma_len(sgent);
5556365beadSRussell King 
5566365beadSRussell King 		if (len > DMA_MAX_SIZE)
5576365beadSRussell King 			j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
5586365beadSRussell King 		if (addr & DMA_ALIGN) {
5596365beadSRussell King 			dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
56050437bffSRussell King 				&c->vc, addr);
5616365beadSRussell King 			return NULL;
5626365beadSRussell King 		}
5636365beadSRussell King 	}
5646365beadSRussell King 
5656365beadSRussell King 	txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
5666365beadSRussell King 	if (!txd) {
56750437bffSRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
5686365beadSRussell King 		return NULL;
5696365beadSRussell King 	}
5706365beadSRussell King 
5716365beadSRussell King 	j = 0;
5726365beadSRussell King 	for_each_sg(sg, sgent, sglen, i) {
5736365beadSRussell King 		dma_addr_t addr = sg_dma_address(sgent);
5746365beadSRussell King 		unsigned len = sg_dma_len(sgent);
5756365beadSRussell King 
5766365beadSRussell King 		size += len;
5776365beadSRussell King 
5786365beadSRussell King 		do {
5796365beadSRussell King 			unsigned tlen = len;
5806365beadSRussell King 
5816365beadSRussell King 			/*
5826365beadSRussell King 			 * Check whether the transfer will fit.  If not, try
5836365beadSRussell King 			 * to split the transfer up such that we end up with
5846365beadSRussell King 			 * equal chunks - but make sure that we preserve the
5856365beadSRussell King 			 * alignment.  This avoids small segments.
5866365beadSRussell King 			 */
5876365beadSRussell King 			if (tlen > DMA_MAX_SIZE) {
5886365beadSRussell King 				unsigned mult = DIV_ROUND_UP(tlen,
5896365beadSRussell King 					DMA_MAX_SIZE & ~DMA_ALIGN);
5906365beadSRussell King 
5916365beadSRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
5926365beadSRussell King 			}
5936365beadSRussell King 
5946365beadSRussell King 			txd->sg[j].addr = addr;
5956365beadSRussell King 			txd->sg[j].len = tlen;
5966365beadSRussell King 
5976365beadSRussell King 			addr += tlen;
5986365beadSRussell King 			len -= tlen;
5996365beadSRussell King 			j++;
6006365beadSRussell King 		} while (len);
6016365beadSRussell King 	}
6026365beadSRussell King 
6036365beadSRussell King 	txd->ddar = c->ddar;
6046365beadSRussell King 	txd->size = size;
6056365beadSRussell King 	txd->sglen = j;
6066365beadSRussell King 
6076365beadSRussell King 	dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
60850437bffSRussell King 		&c->vc, &txd->vd, txd->size, txd->sglen);
6096365beadSRussell King 
61050437bffSRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, flags);
6116365beadSRussell King }
6126365beadSRussell King 
613d9444325SRussell King static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(
614d9444325SRussell King 	struct dma_chan *chan, dma_addr_t addr, size_t size, size_t period,
61531c1e5a1SLaurent Pinchart 	enum dma_transfer_direction dir, unsigned long flags)
616d9444325SRussell King {
617d9444325SRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
618d9444325SRussell King 	struct sa11x0_dma_desc *txd;
619d9444325SRussell King 	unsigned i, j, k, sglen, sgperiod;
620d9444325SRussell King 
621d9444325SRussell King 	/* SA11x0 channels can only operate in their native direction */
622d9444325SRussell King 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
623d9444325SRussell King 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
624d9444325SRussell King 			&c->vc, c->ddar, dir);
625d9444325SRussell King 		return NULL;
626d9444325SRussell King 	}
627d9444325SRussell King 
628d9444325SRussell King 	sgperiod = DIV_ROUND_UP(period, DMA_MAX_SIZE & ~DMA_ALIGN);
629d9444325SRussell King 	sglen = size * sgperiod / period;
630d9444325SRussell King 
631d9444325SRussell King 	/* Do not allow zero-sized txds */
632d9444325SRussell King 	if (sglen == 0)
633d9444325SRussell King 		return NULL;
634d9444325SRussell King 
635d9444325SRussell King 	txd = kzalloc(sizeof(*txd) + sglen * sizeof(txd->sg[0]), GFP_ATOMIC);
636d9444325SRussell King 	if (!txd) {
637d9444325SRussell King 		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
638d9444325SRussell King 		return NULL;
639d9444325SRussell King 	}
640d9444325SRussell King 
641d9444325SRussell King 	for (i = k = 0; i < size / period; i++) {
642d9444325SRussell King 		size_t tlen, len = period;
643d9444325SRussell King 
644d9444325SRussell King 		for (j = 0; j < sgperiod; j++, k++) {
645d9444325SRussell King 			tlen = len;
646d9444325SRussell King 
647d9444325SRussell King 			if (tlen > DMA_MAX_SIZE) {
648d9444325SRussell King 				unsigned mult = DIV_ROUND_UP(tlen, DMA_MAX_SIZE & ~DMA_ALIGN);
649d9444325SRussell King 				tlen = (tlen / mult) & ~DMA_ALIGN;
650d9444325SRussell King 			}
651d9444325SRussell King 
652d9444325SRussell King 			txd->sg[k].addr = addr;
653d9444325SRussell King 			txd->sg[k].len = tlen;
654d9444325SRussell King 			addr += tlen;
655d9444325SRussell King 			len -= tlen;
656d9444325SRussell King 		}
657d9444325SRussell King 
658d9444325SRussell King 		WARN_ON(len != 0);
659d9444325SRussell King 	}
660d9444325SRussell King 
661d9444325SRussell King 	WARN_ON(k != sglen);
662d9444325SRussell King 
663d9444325SRussell King 	txd->ddar = c->ddar;
664d9444325SRussell King 	txd->size = size;
665d9444325SRussell King 	txd->sglen = sglen;
666d9444325SRussell King 	txd->cyclic = 1;
667d9444325SRussell King 	txd->period = sgperiod;
668d9444325SRussell King 
669d9444325SRussell King 	return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
670d9444325SRussell King }
671d9444325SRussell King 
672*a0a51a64SMaxime Ripard static int sa11x0_dma_device_config(struct dma_chan *chan,
6734a533218SMaxime Ripard 				    struct dma_slave_config *cfg)
6746365beadSRussell King {
6754a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
6766365beadSRussell King 	u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
6776365beadSRussell King 	dma_addr_t addr;
6786365beadSRussell King 	enum dma_slave_buswidth width;
6796365beadSRussell King 	u32 maxburst;
6806365beadSRussell King 
6816365beadSRussell King 	if (ddar & DDAR_RW) {
6826365beadSRussell King 		addr = cfg->src_addr;
6836365beadSRussell King 		width = cfg->src_addr_width;
6846365beadSRussell King 		maxburst = cfg->src_maxburst;
6856365beadSRussell King 	} else {
6866365beadSRussell King 		addr = cfg->dst_addr;
6876365beadSRussell King 		width = cfg->dst_addr_width;
6886365beadSRussell King 		maxburst = cfg->dst_maxburst;
6896365beadSRussell King 	}
6906365beadSRussell King 
6916365beadSRussell King 	if ((width != DMA_SLAVE_BUSWIDTH_1_BYTE &&
6926365beadSRussell King 	     width != DMA_SLAVE_BUSWIDTH_2_BYTES) ||
6936365beadSRussell King 	    (maxburst != 4 && maxburst != 8))
6946365beadSRussell King 		return -EINVAL;
6956365beadSRussell King 
6966365beadSRussell King 	if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
6976365beadSRussell King 		ddar |= DDAR_DW;
6986365beadSRussell King 	if (maxburst == 8)
6996365beadSRussell King 		ddar |= DDAR_BS;
7006365beadSRussell King 
70150437bffSRussell King 	dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
70250437bffSRussell King 		&c->vc, addr, width, maxburst);
7036365beadSRussell King 
7046365beadSRussell King 	c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
7056365beadSRussell King 
7066365beadSRussell King 	return 0;
7076365beadSRussell King }
7086365beadSRussell King 
709*a0a51a64SMaxime Ripard static int sa11x0_dma_device_pause(struct dma_chan *chan)
7106365beadSRussell King {
7116365beadSRussell King 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7126365beadSRussell King 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7136365beadSRussell King 	struct sa11x0_dma_phy *p;
7146365beadSRussell King 	LIST_HEAD(head);
7156365beadSRussell King 	unsigned long flags;
7166365beadSRussell King 
7174a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
7184a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7194a533218SMaxime Ripard 	if (c->status == DMA_IN_PROGRESS) {
7204a533218SMaxime Ripard 		c->status = DMA_PAUSED;
7216365beadSRussell King 
7224a533218SMaxime Ripard 		p = c->phy;
7234a533218SMaxime Ripard 		if (p) {
7244a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
7254a533218SMaxime Ripard 		} else {
7264a533218SMaxime Ripard 			spin_lock(&d->lock);
7274a533218SMaxime Ripard 			list_del_init(&c->node);
7284a533218SMaxime Ripard 			spin_unlock(&d->lock);
7294a533218SMaxime Ripard 		}
7304a533218SMaxime Ripard 	}
7314a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7324a533218SMaxime Ripard 
7334a533218SMaxime Ripard 	return 0;
7344a533218SMaxime Ripard }
7354a533218SMaxime Ripard 
736*a0a51a64SMaxime Ripard static int sa11x0_dma_device_resume(struct dma_chan *chan)
7374a533218SMaxime Ripard {
7384a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7394a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7404a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7414a533218SMaxime Ripard 	LIST_HEAD(head);
7424a533218SMaxime Ripard 	unsigned long flags;
7434a533218SMaxime Ripard 
7444a533218SMaxime Ripard 	dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
7454a533218SMaxime Ripard 	spin_lock_irqsave(&c->vc.lock, flags);
7464a533218SMaxime Ripard 	if (c->status == DMA_PAUSED) {
7474a533218SMaxime Ripard 		c->status = DMA_IN_PROGRESS;
7484a533218SMaxime Ripard 
7494a533218SMaxime Ripard 		p = c->phy;
7504a533218SMaxime Ripard 		if (p) {
7514a533218SMaxime Ripard 			writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
7524a533218SMaxime Ripard 		} else if (!list_empty(&c->vc.desc_issued)) {
7534a533218SMaxime Ripard 			spin_lock(&d->lock);
7544a533218SMaxime Ripard 			list_add_tail(&c->node, &d->chan_pending);
7554a533218SMaxime Ripard 			spin_unlock(&d->lock);
7564a533218SMaxime Ripard 		}
7574a533218SMaxime Ripard 	}
7584a533218SMaxime Ripard 	spin_unlock_irqrestore(&c->vc.lock, flags);
7594a533218SMaxime Ripard 
7604a533218SMaxime Ripard 	return 0;
7614a533218SMaxime Ripard }
7624a533218SMaxime Ripard 
763*a0a51a64SMaxime Ripard static int sa11x0_dma_device_terminate_all(struct dma_chan *chan)
7644a533218SMaxime Ripard {
7654a533218SMaxime Ripard 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
7664a533218SMaxime Ripard 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
7674a533218SMaxime Ripard 	struct sa11x0_dma_phy *p;
7684a533218SMaxime Ripard 	LIST_HEAD(head);
7694a533218SMaxime Ripard 	unsigned long flags;
7704a533218SMaxime Ripard 
77150437bffSRussell King 	dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
7726365beadSRussell King 	/* Clear the tx descriptor lists */
77350437bffSRussell King 	spin_lock_irqsave(&c->vc.lock, flags);
77450437bffSRussell King 	vchan_get_all_descriptors(&c->vc, &head);
7756365beadSRussell King 
7766365beadSRussell King 	p = c->phy;
7776365beadSRussell King 	if (p) {
7786365beadSRussell King 		dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
7796365beadSRussell King 		/* vchan is assigned to a pchan - stop the channel */
7806365beadSRussell King 		writel(DCSR_RUN | DCSR_IE |
7816365beadSRussell King 		       DCSR_STRTA | DCSR_DONEA |
7826365beadSRussell King 		       DCSR_STRTB | DCSR_DONEB,
7836365beadSRussell King 		       p->base + DMA_DCSR_C);
7846365beadSRussell King 
7856365beadSRussell King 		if (p->txd_load) {
7866365beadSRussell King 			if (p->txd_load != p->txd_done)
78750437bffSRussell King 				list_add_tail(&p->txd_load->vd.node, &head);
7886365beadSRussell King 			p->txd_load = NULL;
7896365beadSRussell King 		}
7906365beadSRussell King 		if (p->txd_done) {
79150437bffSRussell King 			list_add_tail(&p->txd_done->vd.node, &head);
7926365beadSRussell King 			p->txd_done = NULL;
7936365beadSRussell King 		}
7946365beadSRussell King 		c->phy = NULL;
7956365beadSRussell King 		spin_lock(&d->lock);
7966365beadSRussell King 		p->vchan = NULL;
7976365beadSRussell King 		spin_unlock(&d->lock);
7986365beadSRussell King 		tasklet_schedule(&d->task);
7996365beadSRussell King 	}
80050437bffSRussell King 	spin_unlock_irqrestore(&c->vc.lock, flags);
80150437bffSRussell King 	vchan_dma_desc_free_list(&c->vc, &head);
8026365beadSRussell King 
8034a533218SMaxime Ripard 	return 0;
8046365beadSRussell King }
8056365beadSRussell King 
8066365beadSRussell King struct sa11x0_dma_channel_desc {
8076365beadSRussell King 	u32 ddar;
8086365beadSRussell King 	const char *name;
8096365beadSRussell King };
8106365beadSRussell King 
8116365beadSRussell King #define CD(d1, d2) { .ddar = DDAR_##d1 | d2, .name = #d1 }
8126365beadSRussell King static const struct sa11x0_dma_channel_desc chan_desc[] = {
8136365beadSRussell King 	CD(Ser0UDCTr, 0),
8146365beadSRussell King 	CD(Ser0UDCRc, DDAR_RW),
8156365beadSRussell King 	CD(Ser1SDLCTr, 0),
8166365beadSRussell King 	CD(Ser1SDLCRc, DDAR_RW),
8176365beadSRussell King 	CD(Ser1UARTTr, 0),
8186365beadSRussell King 	CD(Ser1UARTRc, DDAR_RW),
8196365beadSRussell King 	CD(Ser2ICPTr, 0),
8206365beadSRussell King 	CD(Ser2ICPRc, DDAR_RW),
8216365beadSRussell King 	CD(Ser3UARTTr, 0),
8226365beadSRussell King 	CD(Ser3UARTRc, DDAR_RW),
8236365beadSRussell King 	CD(Ser4MCP0Tr, 0),
8246365beadSRussell King 	CD(Ser4MCP0Rc, DDAR_RW),
8256365beadSRussell King 	CD(Ser4MCP1Tr, 0),
8266365beadSRussell King 	CD(Ser4MCP1Rc, DDAR_RW),
8276365beadSRussell King 	CD(Ser4SSPTr, 0),
8286365beadSRussell King 	CD(Ser4SSPRc, DDAR_RW),
8296365beadSRussell King };
8306365beadSRussell King 
831463a1f8bSBill Pemberton static int sa11x0_dma_init_dmadev(struct dma_device *dmadev,
8326365beadSRussell King 	struct device *dev)
8336365beadSRussell King {
8346365beadSRussell King 	unsigned i;
8356365beadSRussell King 
8366365beadSRussell King 	INIT_LIST_HEAD(&dmadev->channels);
8376365beadSRussell King 	dmadev->dev = dev;
8386365beadSRussell King 	dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
8396365beadSRussell King 	dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
840*a0a51a64SMaxime Ripard 	dmadev->device_config = sa11x0_dma_device_config;
841*a0a51a64SMaxime Ripard 	dmadev->device_pause = sa11x0_dma_device_pause;
842*a0a51a64SMaxime Ripard 	dmadev->device_resume = sa11x0_dma_device_resume;
843*a0a51a64SMaxime Ripard 	dmadev->device_terminate_all = sa11x0_dma_device_terminate_all;
8446365beadSRussell King 	dmadev->device_tx_status = sa11x0_dma_tx_status;
8456365beadSRussell King 	dmadev->device_issue_pending = sa11x0_dma_issue_pending;
8466365beadSRussell King 
8479aa71711SMaxime Ripard 	for (i = 0; i < ARRAY_SIZE(chan_desc); i++) {
8486365beadSRussell King 		struct sa11x0_dma_chan *c;
8496365beadSRussell King 
8506365beadSRussell King 		c = kzalloc(sizeof(*c), GFP_KERNEL);
8516365beadSRussell King 		if (!c) {
8526365beadSRussell King 			dev_err(dev, "no memory for channel %u\n", i);
8536365beadSRussell King 			return -ENOMEM;
8546365beadSRussell King 		}
8556365beadSRussell King 
8566365beadSRussell King 		c->status = DMA_IN_PROGRESS;
8576365beadSRussell King 		c->ddar = chan_desc[i].ddar;
8586365beadSRussell King 		c->name = chan_desc[i].name;
8596365beadSRussell King 		INIT_LIST_HEAD(&c->node);
86050437bffSRussell King 
86150437bffSRussell King 		c->vc.desc_free = sa11x0_dma_free_desc;
86250437bffSRussell King 		vchan_init(&c->vc, dmadev);
8636365beadSRussell King 	}
8646365beadSRussell King 
8656365beadSRussell King 	return dma_async_device_register(dmadev);
8666365beadSRussell King }
8676365beadSRussell King 
8686365beadSRussell King static int sa11x0_dma_request_irq(struct platform_device *pdev, int nr,
8696365beadSRussell King 	void *data)
8706365beadSRussell King {
8716365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8726365beadSRussell King 
8736365beadSRussell King 	if (irq <= 0)
8746365beadSRussell King 		return -ENXIO;
8756365beadSRussell King 
8766365beadSRussell King 	return request_irq(irq, sa11x0_dma_irq, 0, dev_name(&pdev->dev), data);
8776365beadSRussell King }
8786365beadSRussell King 
8796365beadSRussell King static void sa11x0_dma_free_irq(struct platform_device *pdev, int nr,
8806365beadSRussell King 	void *data)
8816365beadSRussell King {
8826365beadSRussell King 	int irq = platform_get_irq(pdev, nr);
8836365beadSRussell King 	if (irq > 0)
8846365beadSRussell King 		free_irq(irq, data);
8856365beadSRussell King }
8866365beadSRussell King 
8876365beadSRussell King static void sa11x0_dma_free_channels(struct dma_device *dmadev)
8886365beadSRussell King {
8896365beadSRussell King 	struct sa11x0_dma_chan *c, *cn;
8906365beadSRussell King 
89150437bffSRussell King 	list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
89250437bffSRussell King 		list_del(&c->vc.chan.device_node);
89350437bffSRussell King 		tasklet_kill(&c->vc.task);
8946365beadSRussell King 		kfree(c);
8956365beadSRussell King 	}
8966365beadSRussell King }
8976365beadSRussell King 
898463a1f8bSBill Pemberton static int sa11x0_dma_probe(struct platform_device *pdev)
8996365beadSRussell King {
9006365beadSRussell King 	struct sa11x0_dma_dev *d;
9016365beadSRussell King 	struct resource *res;
9026365beadSRussell King 	unsigned i;
9036365beadSRussell King 	int ret;
9046365beadSRussell King 
9056365beadSRussell King 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9066365beadSRussell King 	if (!res)
9076365beadSRussell King 		return -ENXIO;
9086365beadSRussell King 
9096365beadSRussell King 	d = kzalloc(sizeof(*d), GFP_KERNEL);
9106365beadSRussell King 	if (!d) {
9116365beadSRussell King 		ret = -ENOMEM;
9126365beadSRussell King 		goto err_alloc;
9136365beadSRussell King 	}
9146365beadSRussell King 
9156365beadSRussell King 	spin_lock_init(&d->lock);
9166365beadSRussell King 	INIT_LIST_HEAD(&d->chan_pending);
9176365beadSRussell King 
9186365beadSRussell King 	d->base = ioremap(res->start, resource_size(res));
9196365beadSRussell King 	if (!d->base) {
9206365beadSRussell King 		ret = -ENOMEM;
9216365beadSRussell King 		goto err_ioremap;
9226365beadSRussell King 	}
9236365beadSRussell King 
9246365beadSRussell King 	tasklet_init(&d->task, sa11x0_dma_tasklet, (unsigned long)d);
9256365beadSRussell King 
9266365beadSRussell King 	for (i = 0; i < NR_PHY_CHAN; i++) {
9276365beadSRussell King 		struct sa11x0_dma_phy *p = &d->phy[i];
9286365beadSRussell King 
9296365beadSRussell King 		p->dev = d;
9306365beadSRussell King 		p->num = i;
9316365beadSRussell King 		p->base = d->base + i * DMA_SIZE;
9326365beadSRussell King 		writel_relaxed(DCSR_RUN | DCSR_IE | DCSR_ERROR |
9336365beadSRussell King 			DCSR_DONEA | DCSR_STRTA | DCSR_DONEB | DCSR_STRTB,
9346365beadSRussell King 			p->base + DMA_DCSR_C);
9356365beadSRussell King 		writel_relaxed(0, p->base + DMA_DDAR);
9366365beadSRussell King 
9376365beadSRussell King 		ret = sa11x0_dma_request_irq(pdev, i, p);
9386365beadSRussell King 		if (ret) {
9396365beadSRussell King 			while (i) {
9406365beadSRussell King 				i--;
9416365beadSRussell King 				sa11x0_dma_free_irq(pdev, i, &d->phy[i]);
9426365beadSRussell King 			}
9436365beadSRussell King 			goto err_irq;
9446365beadSRussell King 		}
9456365beadSRussell King 	}
9466365beadSRussell King 
9476365beadSRussell King 	dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
948d9444325SRussell King 	dma_cap_set(DMA_CYCLIC, d->slave.cap_mask);
9496365beadSRussell King 	d->slave.device_prep_slave_sg = sa11x0_dma_prep_slave_sg;
950d9444325SRussell King 	d->slave.device_prep_dma_cyclic = sa11x0_dma_prep_dma_cyclic;
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