xref: /openbmc/linux/drivers/dma/mcf-edma-main.c (revision 66aac8ea)
1*66aac8eaSFrank Li // SPDX-License-Identifier: GPL-2.0+
2*66aac8eaSFrank Li //
3*66aac8eaSFrank Li // Copyright (c) 2013-2014 Freescale Semiconductor, Inc
4*66aac8eaSFrank Li // Copyright (c) 2017 Sysam, Angelo Dureghello  <angelo@sysam.it>
5*66aac8eaSFrank Li 
6*66aac8eaSFrank Li #include <linux/module.h>
7*66aac8eaSFrank Li #include <linux/interrupt.h>
8*66aac8eaSFrank Li #include <linux/dmaengine.h>
9*66aac8eaSFrank Li #include <linux/platform_device.h>
10*66aac8eaSFrank Li #include <linux/platform_data/dma-mcf-edma.h>
11*66aac8eaSFrank Li 
12*66aac8eaSFrank Li #include "fsl-edma-common.h"
13*66aac8eaSFrank Li 
14*66aac8eaSFrank Li #define EDMA_CHANNELS		64
15*66aac8eaSFrank Li #define EDMA_MASK_CH(x)		((x) & GENMASK(5, 0))
16*66aac8eaSFrank Li 
17*66aac8eaSFrank Li static irqreturn_t mcf_edma_tx_handler(int irq, void *dev_id)
18*66aac8eaSFrank Li {
19*66aac8eaSFrank Li 	struct fsl_edma_engine *mcf_edma = dev_id;
20*66aac8eaSFrank Li 	struct edma_regs *regs = &mcf_edma->regs;
21*66aac8eaSFrank Li 	unsigned int ch;
22*66aac8eaSFrank Li 	struct fsl_edma_chan *mcf_chan;
23*66aac8eaSFrank Li 	u64 intmap;
24*66aac8eaSFrank Li 
25*66aac8eaSFrank Li 	intmap = ioread32(regs->inth);
26*66aac8eaSFrank Li 	intmap <<= 32;
27*66aac8eaSFrank Li 	intmap |= ioread32(regs->intl);
28*66aac8eaSFrank Li 	if (!intmap)
29*66aac8eaSFrank Li 		return IRQ_NONE;
30*66aac8eaSFrank Li 
31*66aac8eaSFrank Li 	for (ch = 0; ch < mcf_edma->n_chans; ch++) {
32*66aac8eaSFrank Li 		if (intmap & BIT(ch)) {
33*66aac8eaSFrank Li 			iowrite8(EDMA_MASK_CH(ch), regs->cint);
34*66aac8eaSFrank Li 
35*66aac8eaSFrank Li 			mcf_chan = &mcf_edma->chans[ch];
36*66aac8eaSFrank Li 
37*66aac8eaSFrank Li 			spin_lock(&mcf_chan->vchan.lock);
38*66aac8eaSFrank Li 
39*66aac8eaSFrank Li 			if (!mcf_chan->edesc) {
40*66aac8eaSFrank Li 				/* terminate_all called before */
41*66aac8eaSFrank Li 				spin_unlock(&mcf_chan->vchan.lock);
42*66aac8eaSFrank Li 				continue;
43*66aac8eaSFrank Li 			}
44*66aac8eaSFrank Li 
45*66aac8eaSFrank Li 			if (!mcf_chan->edesc->iscyclic) {
46*66aac8eaSFrank Li 				list_del(&mcf_chan->edesc->vdesc.node);
47*66aac8eaSFrank Li 				vchan_cookie_complete(&mcf_chan->edesc->vdesc);
48*66aac8eaSFrank Li 				mcf_chan->edesc = NULL;
49*66aac8eaSFrank Li 				mcf_chan->status = DMA_COMPLETE;
50*66aac8eaSFrank Li 				mcf_chan->idle = true;
51*66aac8eaSFrank Li 			} else {
52*66aac8eaSFrank Li 				vchan_cyclic_callback(&mcf_chan->edesc->vdesc);
53*66aac8eaSFrank Li 			}
54*66aac8eaSFrank Li 
55*66aac8eaSFrank Li 			if (!mcf_chan->edesc)
56*66aac8eaSFrank Li 				fsl_edma_xfer_desc(mcf_chan);
57*66aac8eaSFrank Li 
58*66aac8eaSFrank Li 			spin_unlock(&mcf_chan->vchan.lock);
59*66aac8eaSFrank Li 		}
60*66aac8eaSFrank Li 	}
61*66aac8eaSFrank Li 
62*66aac8eaSFrank Li 	return IRQ_HANDLED;
63*66aac8eaSFrank Li }
64*66aac8eaSFrank Li 
65*66aac8eaSFrank Li static irqreturn_t mcf_edma_err_handler(int irq, void *dev_id)
66*66aac8eaSFrank Li {
67*66aac8eaSFrank Li 	struct fsl_edma_engine *mcf_edma = dev_id;
68*66aac8eaSFrank Li 	struct edma_regs *regs = &mcf_edma->regs;
69*66aac8eaSFrank Li 	unsigned int err, ch;
70*66aac8eaSFrank Li 
71*66aac8eaSFrank Li 	err = ioread32(regs->errl);
72*66aac8eaSFrank Li 	if (!err)
73*66aac8eaSFrank Li 		return IRQ_NONE;
74*66aac8eaSFrank Li 
75*66aac8eaSFrank Li 	for (ch = 0; ch < (EDMA_CHANNELS / 2); ch++) {
76*66aac8eaSFrank Li 		if (err & BIT(ch)) {
77*66aac8eaSFrank Li 			fsl_edma_disable_request(&mcf_edma->chans[ch]);
78*66aac8eaSFrank Li 			iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
79*66aac8eaSFrank Li 			mcf_edma->chans[ch].status = DMA_ERROR;
80*66aac8eaSFrank Li 			mcf_edma->chans[ch].idle = true;
81*66aac8eaSFrank Li 		}
82*66aac8eaSFrank Li 	}
83*66aac8eaSFrank Li 
84*66aac8eaSFrank Li 	err = ioread32(regs->errh);
85*66aac8eaSFrank Li 	if (!err)
86*66aac8eaSFrank Li 		return IRQ_NONE;
87*66aac8eaSFrank Li 
88*66aac8eaSFrank Li 	for (ch = (EDMA_CHANNELS / 2); ch < EDMA_CHANNELS; ch++) {
89*66aac8eaSFrank Li 		if (err & (BIT(ch - (EDMA_CHANNELS / 2)))) {
90*66aac8eaSFrank Li 			fsl_edma_disable_request(&mcf_edma->chans[ch]);
91*66aac8eaSFrank Li 			iowrite8(EDMA_CERR_CERR(ch), regs->cerr);
92*66aac8eaSFrank Li 			mcf_edma->chans[ch].status = DMA_ERROR;
93*66aac8eaSFrank Li 			mcf_edma->chans[ch].idle = true;
94*66aac8eaSFrank Li 		}
95*66aac8eaSFrank Li 	}
96*66aac8eaSFrank Li 
97*66aac8eaSFrank Li 	return IRQ_HANDLED;
98*66aac8eaSFrank Li }
99*66aac8eaSFrank Li 
100*66aac8eaSFrank Li static int mcf_edma_irq_init(struct platform_device *pdev,
101*66aac8eaSFrank Li 				struct fsl_edma_engine *mcf_edma)
102*66aac8eaSFrank Li {
103*66aac8eaSFrank Li 	int ret = 0, i;
104*66aac8eaSFrank Li 	struct resource *res;
105*66aac8eaSFrank Li 
106*66aac8eaSFrank Li 	res = platform_get_resource_byname(pdev,
107*66aac8eaSFrank Li 				IORESOURCE_IRQ, "edma-tx-00-15");
108*66aac8eaSFrank Li 	if (!res)
109*66aac8eaSFrank Li 		return -1;
110*66aac8eaSFrank Li 
111*66aac8eaSFrank Li 	for (ret = 0, i = res->start; i <= res->end; ++i)
112*66aac8eaSFrank Li 		ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
113*66aac8eaSFrank Li 	if (ret)
114*66aac8eaSFrank Li 		return ret;
115*66aac8eaSFrank Li 
116*66aac8eaSFrank Li 	res = platform_get_resource_byname(pdev,
117*66aac8eaSFrank Li 			IORESOURCE_IRQ, "edma-tx-16-55");
118*66aac8eaSFrank Li 	if (!res)
119*66aac8eaSFrank Li 		return -1;
120*66aac8eaSFrank Li 
121*66aac8eaSFrank Li 	for (ret = 0, i = res->start; i <= res->end; ++i)
122*66aac8eaSFrank Li 		ret |= request_irq(i, mcf_edma_tx_handler, 0, "eDMA", mcf_edma);
123*66aac8eaSFrank Li 	if (ret)
124*66aac8eaSFrank Li 		return ret;
125*66aac8eaSFrank Li 
126*66aac8eaSFrank Li 	ret = platform_get_irq_byname(pdev, "edma-tx-56-63");
127*66aac8eaSFrank Li 	if (ret != -ENXIO) {
128*66aac8eaSFrank Li 		ret = request_irq(ret, mcf_edma_tx_handler,
129*66aac8eaSFrank Li 				  0, "eDMA", mcf_edma);
130*66aac8eaSFrank Li 		if (ret)
131*66aac8eaSFrank Li 			return ret;
132*66aac8eaSFrank Li 	}
133*66aac8eaSFrank Li 
134*66aac8eaSFrank Li 	ret = platform_get_irq_byname(pdev, "edma-err");
135*66aac8eaSFrank Li 	if (ret != -ENXIO) {
136*66aac8eaSFrank Li 		ret = request_irq(ret, mcf_edma_err_handler,
137*66aac8eaSFrank Li 				  0, "eDMA", mcf_edma);
138*66aac8eaSFrank Li 		if (ret)
139*66aac8eaSFrank Li 			return ret;
140*66aac8eaSFrank Li 	}
141*66aac8eaSFrank Li 
142*66aac8eaSFrank Li 	return 0;
143*66aac8eaSFrank Li }
144*66aac8eaSFrank Li 
145*66aac8eaSFrank Li static void mcf_edma_irq_free(struct platform_device *pdev,
146*66aac8eaSFrank Li 				struct fsl_edma_engine *mcf_edma)
147*66aac8eaSFrank Li {
148*66aac8eaSFrank Li 	int irq;
149*66aac8eaSFrank Li 	struct resource *res;
150*66aac8eaSFrank Li 
151*66aac8eaSFrank Li 	res = platform_get_resource_byname(pdev,
152*66aac8eaSFrank Li 			IORESOURCE_IRQ, "edma-tx-00-15");
153*66aac8eaSFrank Li 	if (res) {
154*66aac8eaSFrank Li 		for (irq = res->start; irq <= res->end; irq++)
155*66aac8eaSFrank Li 			free_irq(irq, mcf_edma);
156*66aac8eaSFrank Li 	}
157*66aac8eaSFrank Li 
158*66aac8eaSFrank Li 	res = platform_get_resource_byname(pdev,
159*66aac8eaSFrank Li 			IORESOURCE_IRQ, "edma-tx-16-55");
160*66aac8eaSFrank Li 	if (res) {
161*66aac8eaSFrank Li 		for (irq = res->start; irq <= res->end; irq++)
162*66aac8eaSFrank Li 			free_irq(irq, mcf_edma);
163*66aac8eaSFrank Li 	}
164*66aac8eaSFrank Li 
165*66aac8eaSFrank Li 	irq = platform_get_irq_byname(pdev, "edma-tx-56-63");
166*66aac8eaSFrank Li 	if (irq != -ENXIO)
167*66aac8eaSFrank Li 		free_irq(irq, mcf_edma);
168*66aac8eaSFrank Li 
169*66aac8eaSFrank Li 	irq = platform_get_irq_byname(pdev, "edma-err");
170*66aac8eaSFrank Li 	if (irq != -ENXIO)
171*66aac8eaSFrank Li 		free_irq(irq, mcf_edma);
172*66aac8eaSFrank Li }
173*66aac8eaSFrank Li 
174*66aac8eaSFrank Li static struct fsl_edma_drvdata mcf_data = {
175*66aac8eaSFrank Li 	.version = v2,
176*66aac8eaSFrank Li 	.setup_irq = mcf_edma_irq_init,
177*66aac8eaSFrank Li };
178*66aac8eaSFrank Li 
179*66aac8eaSFrank Li static int mcf_edma_probe(struct platform_device *pdev)
180*66aac8eaSFrank Li {
181*66aac8eaSFrank Li 	struct mcf_edma_platform_data *pdata;
182*66aac8eaSFrank Li 	struct fsl_edma_engine *mcf_edma;
183*66aac8eaSFrank Li 	struct edma_regs *regs;
184*66aac8eaSFrank Li 	int ret, i, chans;
185*66aac8eaSFrank Li 
186*66aac8eaSFrank Li 	pdata = dev_get_platdata(&pdev->dev);
187*66aac8eaSFrank Li 	if (!pdata) {
188*66aac8eaSFrank Li 		dev_err(&pdev->dev, "no platform data supplied\n");
189*66aac8eaSFrank Li 		return -EINVAL;
190*66aac8eaSFrank Li 	}
191*66aac8eaSFrank Li 
192*66aac8eaSFrank Li 	chans = pdata->dma_channels;
193*66aac8eaSFrank Li 	mcf_edma = devm_kzalloc(&pdev->dev, struct_size(mcf_edma, chans, chans),
194*66aac8eaSFrank Li 				GFP_KERNEL);
195*66aac8eaSFrank Li 	if (!mcf_edma)
196*66aac8eaSFrank Li 		return -ENOMEM;
197*66aac8eaSFrank Li 
198*66aac8eaSFrank Li 	mcf_edma->n_chans = chans;
199*66aac8eaSFrank Li 
200*66aac8eaSFrank Li 	/* Set up drvdata for ColdFire edma */
201*66aac8eaSFrank Li 	mcf_edma->drvdata = &mcf_data;
202*66aac8eaSFrank Li 	mcf_edma->big_endian = 1;
203*66aac8eaSFrank Li 
204*66aac8eaSFrank Li 	if (!mcf_edma->n_chans) {
205*66aac8eaSFrank Li 		dev_info(&pdev->dev, "setting default channel number to 64");
206*66aac8eaSFrank Li 		mcf_edma->n_chans = 64;
207*66aac8eaSFrank Li 	}
208*66aac8eaSFrank Li 
209*66aac8eaSFrank Li 	mutex_init(&mcf_edma->fsl_edma_mutex);
210*66aac8eaSFrank Li 
211*66aac8eaSFrank Li 	mcf_edma->membase = devm_platform_ioremap_resource(pdev, 0);
212*66aac8eaSFrank Li 	if (IS_ERR(mcf_edma->membase))
213*66aac8eaSFrank Li 		return PTR_ERR(mcf_edma->membase);
214*66aac8eaSFrank Li 
215*66aac8eaSFrank Li 	fsl_edma_setup_regs(mcf_edma);
216*66aac8eaSFrank Li 	regs = &mcf_edma->regs;
217*66aac8eaSFrank Li 
218*66aac8eaSFrank Li 	INIT_LIST_HEAD(&mcf_edma->dma_dev.channels);
219*66aac8eaSFrank Li 	for (i = 0; i < mcf_edma->n_chans; i++) {
220*66aac8eaSFrank Li 		struct fsl_edma_chan *mcf_chan = &mcf_edma->chans[i];
221*66aac8eaSFrank Li 
222*66aac8eaSFrank Li 		mcf_chan->edma = mcf_edma;
223*66aac8eaSFrank Li 		mcf_chan->slave_id = i;
224*66aac8eaSFrank Li 		mcf_chan->idle = true;
225*66aac8eaSFrank Li 		mcf_chan->dma_dir = DMA_NONE;
226*66aac8eaSFrank Li 		mcf_chan->vchan.desc_free = fsl_edma_free_desc;
227*66aac8eaSFrank Li 		vchan_init(&mcf_chan->vchan, &mcf_edma->dma_dev);
228*66aac8eaSFrank Li 		iowrite32(0x0, &regs->tcd[i].csr);
229*66aac8eaSFrank Li 	}
230*66aac8eaSFrank Li 
231*66aac8eaSFrank Li 	iowrite32(~0, regs->inth);
232*66aac8eaSFrank Li 	iowrite32(~0, regs->intl);
233*66aac8eaSFrank Li 
234*66aac8eaSFrank Li 	ret = mcf_edma->drvdata->setup_irq(pdev, mcf_edma);
235*66aac8eaSFrank Li 	if (ret)
236*66aac8eaSFrank Li 		return ret;
237*66aac8eaSFrank Li 
238*66aac8eaSFrank Li 	dma_cap_set(DMA_PRIVATE, mcf_edma->dma_dev.cap_mask);
239*66aac8eaSFrank Li 	dma_cap_set(DMA_SLAVE, mcf_edma->dma_dev.cap_mask);
240*66aac8eaSFrank Li 	dma_cap_set(DMA_CYCLIC, mcf_edma->dma_dev.cap_mask);
241*66aac8eaSFrank Li 
242*66aac8eaSFrank Li 	mcf_edma->dma_dev.dev = &pdev->dev;
243*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_alloc_chan_resources =
244*66aac8eaSFrank Li 			fsl_edma_alloc_chan_resources;
245*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_free_chan_resources =
246*66aac8eaSFrank Li 			fsl_edma_free_chan_resources;
247*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_config = fsl_edma_slave_config;
248*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_prep_dma_cyclic =
249*66aac8eaSFrank Li 			fsl_edma_prep_dma_cyclic;
250*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
251*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
252*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_pause = fsl_edma_pause;
253*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_resume = fsl_edma_resume;
254*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
255*66aac8eaSFrank Li 	mcf_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
256*66aac8eaSFrank Li 
257*66aac8eaSFrank Li 	mcf_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
258*66aac8eaSFrank Li 	mcf_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
259*66aac8eaSFrank Li 	mcf_edma->dma_dev.directions =
260*66aac8eaSFrank Li 			BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
261*66aac8eaSFrank Li 
262*66aac8eaSFrank Li 	mcf_edma->dma_dev.filter.fn = mcf_edma_filter_fn;
263*66aac8eaSFrank Li 	mcf_edma->dma_dev.filter.map = pdata->slave_map;
264*66aac8eaSFrank Li 	mcf_edma->dma_dev.filter.mapcnt = pdata->slavecnt;
265*66aac8eaSFrank Li 
266*66aac8eaSFrank Li 	platform_set_drvdata(pdev, mcf_edma);
267*66aac8eaSFrank Li 
268*66aac8eaSFrank Li 	ret = dma_async_device_register(&mcf_edma->dma_dev);
269*66aac8eaSFrank Li 	if (ret) {
270*66aac8eaSFrank Li 		dev_err(&pdev->dev,
271*66aac8eaSFrank Li 			"Can't register Freescale eDMA engine. (%d)\n", ret);
272*66aac8eaSFrank Li 		return ret;
273*66aac8eaSFrank Li 	}
274*66aac8eaSFrank Li 
275*66aac8eaSFrank Li 	/* Enable round robin arbitration */
276*66aac8eaSFrank Li 	iowrite32(EDMA_CR_ERGA | EDMA_CR_ERCA, regs->cr);
277*66aac8eaSFrank Li 
278*66aac8eaSFrank Li 	return 0;
279*66aac8eaSFrank Li }
280*66aac8eaSFrank Li 
281*66aac8eaSFrank Li static int mcf_edma_remove(struct platform_device *pdev)
282*66aac8eaSFrank Li {
283*66aac8eaSFrank Li 	struct fsl_edma_engine *mcf_edma = platform_get_drvdata(pdev);
284*66aac8eaSFrank Li 
285*66aac8eaSFrank Li 	mcf_edma_irq_free(pdev, mcf_edma);
286*66aac8eaSFrank Li 	fsl_edma_cleanup_vchan(&mcf_edma->dma_dev);
287*66aac8eaSFrank Li 	dma_async_device_unregister(&mcf_edma->dma_dev);
288*66aac8eaSFrank Li 
289*66aac8eaSFrank Li 	return 0;
290*66aac8eaSFrank Li }
291*66aac8eaSFrank Li 
292*66aac8eaSFrank Li static struct platform_driver mcf_edma_driver = {
293*66aac8eaSFrank Li 	.driver		= {
294*66aac8eaSFrank Li 		.name	= "mcf-edma",
295*66aac8eaSFrank Li 	},
296*66aac8eaSFrank Li 	.probe		= mcf_edma_probe,
297*66aac8eaSFrank Li 	.remove		= mcf_edma_remove,
298*66aac8eaSFrank Li };
299*66aac8eaSFrank Li 
300*66aac8eaSFrank Li bool mcf_edma_filter_fn(struct dma_chan *chan, void *param)
301*66aac8eaSFrank Li {
302*66aac8eaSFrank Li 	if (chan->device->dev->driver == &mcf_edma_driver.driver) {
303*66aac8eaSFrank Li 		struct fsl_edma_chan *mcf_chan = to_fsl_edma_chan(chan);
304*66aac8eaSFrank Li 
305*66aac8eaSFrank Li 		return (mcf_chan->slave_id == (uintptr_t)param);
306*66aac8eaSFrank Li 	}
307*66aac8eaSFrank Li 
308*66aac8eaSFrank Li 	return false;
309*66aac8eaSFrank Li }
310*66aac8eaSFrank Li EXPORT_SYMBOL(mcf_edma_filter_fn);
311*66aac8eaSFrank Li 
312*66aac8eaSFrank Li static int __init mcf_edma_init(void)
313*66aac8eaSFrank Li {
314*66aac8eaSFrank Li 	return platform_driver_register(&mcf_edma_driver);
315*66aac8eaSFrank Li }
316*66aac8eaSFrank Li subsys_initcall(mcf_edma_init);
317*66aac8eaSFrank Li 
318*66aac8eaSFrank Li static void __exit mcf_edma_exit(void)
319*66aac8eaSFrank Li {
320*66aac8eaSFrank Li 	platform_driver_unregister(&mcf_edma_driver);
321*66aac8eaSFrank Li }
322*66aac8eaSFrank Li module_exit(mcf_edma_exit);
323*66aac8eaSFrank Li 
324*66aac8eaSFrank Li MODULE_ALIAS("platform:mcf-edma");
325*66aac8eaSFrank Li MODULE_DESCRIPTION("Freescale eDMA engine driver, ColdFire family");
326*66aac8eaSFrank Li MODULE_LICENSE("GPL v2");
327