xref: /openbmc/linux/drivers/dma/uniphier-mdmac.c (revision ead5d1f4d877e92c051e1a1ade623d0d30e71619)
132e74aabSMasahiro Yamada // SPDX-License-Identifier: GPL-2.0
232e74aabSMasahiro Yamada //
332e74aabSMasahiro Yamada // Copyright (C) 2018 Socionext Inc.
432e74aabSMasahiro Yamada //   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
532e74aabSMasahiro Yamada 
632e74aabSMasahiro Yamada #include <linux/bits.h>
732e74aabSMasahiro Yamada #include <linux/clk.h>
832e74aabSMasahiro Yamada #include <linux/dma-mapping.h>
932e74aabSMasahiro Yamada #include <linux/dmaengine.h>
1032e74aabSMasahiro Yamada #include <linux/interrupt.h>
1132e74aabSMasahiro Yamada #include <linux/iopoll.h>
1232e74aabSMasahiro Yamada #include <linux/list.h>
1332e74aabSMasahiro Yamada #include <linux/module.h>
1432e74aabSMasahiro Yamada #include <linux/of.h>
1532e74aabSMasahiro Yamada #include <linux/of_dma.h>
1632e74aabSMasahiro Yamada #include <linux/platform_device.h>
1732e74aabSMasahiro Yamada #include <linux/slab.h>
1832e74aabSMasahiro Yamada #include <linux/types.h>
1932e74aabSMasahiro Yamada 
2032e74aabSMasahiro Yamada #include "virt-dma.h"
2132e74aabSMasahiro Yamada 
2232e74aabSMasahiro Yamada /* registers common for all channels */
2332e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CMD		0x000	/* issue DMA start/abort */
2432e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CMD_ABORT		BIT(31) /* 1: abort, 0: start */
2532e74aabSMasahiro Yamada 
2632e74aabSMasahiro Yamada /* per-channel registers */
2732e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_OFFSET	0x100
2832e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_STRIDE	0x040
2932e74aabSMasahiro Yamada 
3032e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_IRQ_STAT	0x010	/* current hw status (RO) */
3132e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_IRQ_REQ	0x014	/* latched STAT (WOC) */
3232e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_IRQ_EN	0x018	/* IRQ enable mask */
3332e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_IRQ_DET	0x01c	/* REQ & EN (RO) */
3432e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CH_IRQ__ABORT		BIT(13)
3532e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CH_IRQ__DONE		BIT(1)
3632e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_SRC_MODE	0x020	/* mode of source */
3732e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_DEST_MODE	0x024	/* mode of destination */
3832e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CH_MODE__ADDR_INC	(0 << 4)
3932e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CH_MODE__ADDR_DEC	(1 << 4)
4032e74aabSMasahiro Yamada #define   UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED	(2 << 4)
4132e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_SRC_ADDR	0x028	/* source address */
4232e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_DEST_ADDR	0x02c	/* destination address */
4332e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_CH_SIZE		0x030	/* transfer bytes */
4432e74aabSMasahiro Yamada 
4532e74aabSMasahiro Yamada #define UNIPHIER_MDMAC_SLAVE_BUSWIDTHS \
4632e74aabSMasahiro Yamada 	(BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
4732e74aabSMasahiro Yamada 	 BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
4832e74aabSMasahiro Yamada 	 BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
4932e74aabSMasahiro Yamada 	 BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
5032e74aabSMasahiro Yamada 
5132e74aabSMasahiro Yamada struct uniphier_mdmac_desc {
5232e74aabSMasahiro Yamada 	struct virt_dma_desc vd;
5332e74aabSMasahiro Yamada 	struct scatterlist *sgl;
5432e74aabSMasahiro Yamada 	unsigned int sg_len;
5532e74aabSMasahiro Yamada 	unsigned int sg_cur;
5632e74aabSMasahiro Yamada 	enum dma_transfer_direction dir;
5732e74aabSMasahiro Yamada };
5832e74aabSMasahiro Yamada 
5932e74aabSMasahiro Yamada struct uniphier_mdmac_chan {
6032e74aabSMasahiro Yamada 	struct virt_dma_chan vc;
6132e74aabSMasahiro Yamada 	struct uniphier_mdmac_device *mdev;
6232e74aabSMasahiro Yamada 	struct uniphier_mdmac_desc *md;
6332e74aabSMasahiro Yamada 	void __iomem *reg_ch_base;
6432e74aabSMasahiro Yamada 	unsigned int chan_id;
6532e74aabSMasahiro Yamada };
6632e74aabSMasahiro Yamada 
6732e74aabSMasahiro Yamada struct uniphier_mdmac_device {
6832e74aabSMasahiro Yamada 	struct dma_device ddev;
6932e74aabSMasahiro Yamada 	struct clk *clk;
7032e74aabSMasahiro Yamada 	void __iomem *reg_base;
71*6a878508SGustavo A. R. Silva 	struct uniphier_mdmac_chan channels[];
7232e74aabSMasahiro Yamada };
7332e74aabSMasahiro Yamada 
7432e74aabSMasahiro Yamada static struct uniphier_mdmac_chan *
to_uniphier_mdmac_chan(struct virt_dma_chan * vc)7532e74aabSMasahiro Yamada to_uniphier_mdmac_chan(struct virt_dma_chan *vc)
7632e74aabSMasahiro Yamada {
7732e74aabSMasahiro Yamada 	return container_of(vc, struct uniphier_mdmac_chan, vc);
7832e74aabSMasahiro Yamada }
7932e74aabSMasahiro Yamada 
8032e74aabSMasahiro Yamada static struct uniphier_mdmac_desc *
to_uniphier_mdmac_desc(struct virt_dma_desc * vd)8132e74aabSMasahiro Yamada to_uniphier_mdmac_desc(struct virt_dma_desc *vd)
8232e74aabSMasahiro Yamada {
8332e74aabSMasahiro Yamada 	return container_of(vd, struct uniphier_mdmac_desc, vd);
8432e74aabSMasahiro Yamada }
8532e74aabSMasahiro Yamada 
8632e74aabSMasahiro Yamada /* mc->vc.lock must be held by caller */
8732e74aabSMasahiro Yamada static struct uniphier_mdmac_desc *
uniphier_mdmac_next_desc(struct uniphier_mdmac_chan * mc)8832e74aabSMasahiro Yamada uniphier_mdmac_next_desc(struct uniphier_mdmac_chan *mc)
8932e74aabSMasahiro Yamada {
9032e74aabSMasahiro Yamada 	struct virt_dma_desc *vd;
9132e74aabSMasahiro Yamada 
9232e74aabSMasahiro Yamada 	vd = vchan_next_desc(&mc->vc);
9332e74aabSMasahiro Yamada 	if (!vd) {
9432e74aabSMasahiro Yamada 		mc->md = NULL;
9532e74aabSMasahiro Yamada 		return NULL;
9632e74aabSMasahiro Yamada 	}
9732e74aabSMasahiro Yamada 
9832e74aabSMasahiro Yamada 	list_del(&vd->node);
9932e74aabSMasahiro Yamada 
10032e74aabSMasahiro Yamada 	mc->md = to_uniphier_mdmac_desc(vd);
10132e74aabSMasahiro Yamada 
10232e74aabSMasahiro Yamada 	return mc->md;
10332e74aabSMasahiro Yamada }
10432e74aabSMasahiro Yamada 
10532e74aabSMasahiro Yamada /* mc->vc.lock must be held by caller */
uniphier_mdmac_handle(struct uniphier_mdmac_chan * mc,struct uniphier_mdmac_desc * md)10632e74aabSMasahiro Yamada static void uniphier_mdmac_handle(struct uniphier_mdmac_chan *mc,
10732e74aabSMasahiro Yamada 				  struct uniphier_mdmac_desc *md)
10832e74aabSMasahiro Yamada {
10932e74aabSMasahiro Yamada 	struct uniphier_mdmac_device *mdev = mc->mdev;
11032e74aabSMasahiro Yamada 	struct scatterlist *sg;
11132e74aabSMasahiro Yamada 	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__DONE;
11232e74aabSMasahiro Yamada 	u32 src_mode, src_addr, dest_mode, dest_addr, chunk_size;
11332e74aabSMasahiro Yamada 
11432e74aabSMasahiro Yamada 	sg = &md->sgl[md->sg_cur];
11532e74aabSMasahiro Yamada 
11632e74aabSMasahiro Yamada 	if (md->dir == DMA_MEM_TO_DEV) {
11732e74aabSMasahiro Yamada 		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
11832e74aabSMasahiro Yamada 		src_addr = sg_dma_address(sg);
11932e74aabSMasahiro Yamada 		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
12032e74aabSMasahiro Yamada 		dest_addr = 0;
12132e74aabSMasahiro Yamada 	} else {
12232e74aabSMasahiro Yamada 		src_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_FIXED;
12332e74aabSMasahiro Yamada 		src_addr = 0;
12432e74aabSMasahiro Yamada 		dest_mode = UNIPHIER_MDMAC_CH_MODE__ADDR_INC;
12532e74aabSMasahiro Yamada 		dest_addr = sg_dma_address(sg);
12632e74aabSMasahiro Yamada 	}
12732e74aabSMasahiro Yamada 
12832e74aabSMasahiro Yamada 	chunk_size = sg_dma_len(sg);
12932e74aabSMasahiro Yamada 
13032e74aabSMasahiro Yamada 	writel(src_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_MODE);
13132e74aabSMasahiro Yamada 	writel(dest_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_MODE);
13232e74aabSMasahiro Yamada 	writel(src_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_ADDR);
13332e74aabSMasahiro Yamada 	writel(dest_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_ADDR);
13432e74aabSMasahiro Yamada 	writel(chunk_size, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SIZE);
13532e74aabSMasahiro Yamada 
13632e74aabSMasahiro Yamada 	/* write 1 to clear */
13732e74aabSMasahiro Yamada 	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
13832e74aabSMasahiro Yamada 
13932e74aabSMasahiro Yamada 	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_EN);
14032e74aabSMasahiro Yamada 
14132e74aabSMasahiro Yamada 	writel(BIT(mc->chan_id), mdev->reg_base + UNIPHIER_MDMAC_CMD);
14232e74aabSMasahiro Yamada }
14332e74aabSMasahiro Yamada 
14432e74aabSMasahiro Yamada /* mc->vc.lock must be held by caller */
uniphier_mdmac_start(struct uniphier_mdmac_chan * mc)14532e74aabSMasahiro Yamada static void uniphier_mdmac_start(struct uniphier_mdmac_chan *mc)
14632e74aabSMasahiro Yamada {
14732e74aabSMasahiro Yamada 	struct uniphier_mdmac_desc *md;
14832e74aabSMasahiro Yamada 
14932e74aabSMasahiro Yamada 	md = uniphier_mdmac_next_desc(mc);
15032e74aabSMasahiro Yamada 	if (md)
15132e74aabSMasahiro Yamada 		uniphier_mdmac_handle(mc, md);
15232e74aabSMasahiro Yamada }
15332e74aabSMasahiro Yamada 
15432e74aabSMasahiro Yamada /* mc->vc.lock must be held by caller */
uniphier_mdmac_abort(struct uniphier_mdmac_chan * mc)15532e74aabSMasahiro Yamada static int uniphier_mdmac_abort(struct uniphier_mdmac_chan *mc)
15632e74aabSMasahiro Yamada {
15732e74aabSMasahiro Yamada 	struct uniphier_mdmac_device *mdev = mc->mdev;
15832e74aabSMasahiro Yamada 	u32 irq_flag = UNIPHIER_MDMAC_CH_IRQ__ABORT;
15932e74aabSMasahiro Yamada 	u32 val;
16032e74aabSMasahiro Yamada 
16132e74aabSMasahiro Yamada 	/* write 1 to clear */
16232e74aabSMasahiro Yamada 	writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
16332e74aabSMasahiro Yamada 
16432e74aabSMasahiro Yamada 	writel(UNIPHIER_MDMAC_CMD_ABORT | BIT(mc->chan_id),
16532e74aabSMasahiro Yamada 	       mdev->reg_base + UNIPHIER_MDMAC_CMD);
16632e74aabSMasahiro Yamada 
16732e74aabSMasahiro Yamada 	/*
16832e74aabSMasahiro Yamada 	 * Abort should be accepted soon. We poll the bit here instead of
16932e74aabSMasahiro Yamada 	 * waiting for the interrupt.
17032e74aabSMasahiro Yamada 	 */
17132e74aabSMasahiro Yamada 	return readl_poll_timeout(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ,
17232e74aabSMasahiro Yamada 				  val, val & irq_flag, 0, 20);
17332e74aabSMasahiro Yamada }
17432e74aabSMasahiro Yamada 
uniphier_mdmac_interrupt(int irq,void * dev_id)17532e74aabSMasahiro Yamada static irqreturn_t uniphier_mdmac_interrupt(int irq, void *dev_id)
17632e74aabSMasahiro Yamada {
17732e74aabSMasahiro Yamada 	struct uniphier_mdmac_chan *mc = dev_id;
17832e74aabSMasahiro Yamada 	struct uniphier_mdmac_desc *md;
17932e74aabSMasahiro Yamada 	irqreturn_t ret = IRQ_HANDLED;
18032e74aabSMasahiro Yamada 	u32 irq_stat;
18132e74aabSMasahiro Yamada 
18232e74aabSMasahiro Yamada 	spin_lock(&mc->vc.lock);
18332e74aabSMasahiro Yamada 
18432e74aabSMasahiro Yamada 	irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET);
18532e74aabSMasahiro Yamada 
18632e74aabSMasahiro Yamada 	/*
18732e74aabSMasahiro Yamada 	 * Some channels share a single interrupt line. If the IRQ status is 0,
18832e74aabSMasahiro Yamada 	 * this is probably triggered by a different channel.
18932e74aabSMasahiro Yamada 	 */
19032e74aabSMasahiro Yamada 	if (!irq_stat) {
19132e74aabSMasahiro Yamada 		ret = IRQ_NONE;
19232e74aabSMasahiro Yamada 		goto out;
19332e74aabSMasahiro Yamada 	}
19432e74aabSMasahiro Yamada 
19532e74aabSMasahiro Yamada 	/* write 1 to clear */
19632e74aabSMasahiro Yamada 	writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ);
19732e74aabSMasahiro Yamada 
19832e74aabSMasahiro Yamada 	/*
19932e74aabSMasahiro Yamada 	 * UNIPHIER_MDMAC_CH_IRQ__DONE interrupt is asserted even when the DMA
20032e74aabSMasahiro Yamada 	 * is aborted. To distinguish the normal completion and the abort,
20132e74aabSMasahiro Yamada 	 * check mc->md. If it is NULL, we are aborting.
20232e74aabSMasahiro Yamada 	 */
20332e74aabSMasahiro Yamada 	md = mc->md;
20432e74aabSMasahiro Yamada 	if (!md)
20532e74aabSMasahiro Yamada 		goto out;
20632e74aabSMasahiro Yamada 
20732e74aabSMasahiro Yamada 	md->sg_cur++;
20832e74aabSMasahiro Yamada 
20932e74aabSMasahiro Yamada 	if (md->sg_cur >= md->sg_len) {
21032e74aabSMasahiro Yamada 		vchan_cookie_complete(&md->vd);
21132e74aabSMasahiro Yamada 		md = uniphier_mdmac_next_desc(mc);
21232e74aabSMasahiro Yamada 		if (!md)
21332e74aabSMasahiro Yamada 			goto out;
21432e74aabSMasahiro Yamada 	}
21532e74aabSMasahiro Yamada 
21632e74aabSMasahiro Yamada 	uniphier_mdmac_handle(mc, md);
21732e74aabSMasahiro Yamada 
21832e74aabSMasahiro Yamada out:
21932e74aabSMasahiro Yamada 	spin_unlock(&mc->vc.lock);
22032e74aabSMasahiro Yamada 
22132e74aabSMasahiro Yamada 	return ret;
22232e74aabSMasahiro Yamada }
22332e74aabSMasahiro Yamada 
uniphier_mdmac_free_chan_resources(struct dma_chan * chan)22432e74aabSMasahiro Yamada static void uniphier_mdmac_free_chan_resources(struct dma_chan *chan)
22532e74aabSMasahiro Yamada {
22632e74aabSMasahiro Yamada 	vchan_free_chan_resources(to_virt_chan(chan));
22732e74aabSMasahiro Yamada }
22832e74aabSMasahiro Yamada 
22932e74aabSMasahiro Yamada static struct dma_async_tx_descriptor *
uniphier_mdmac_prep_slave_sg(struct dma_chan * chan,struct scatterlist * sgl,unsigned int sg_len,enum dma_transfer_direction direction,unsigned long flags,void * context)23032e74aabSMasahiro Yamada uniphier_mdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
23132e74aabSMasahiro Yamada 			     unsigned int sg_len,
23232e74aabSMasahiro Yamada 			     enum dma_transfer_direction direction,
23332e74aabSMasahiro Yamada 			     unsigned long flags, void *context)
23432e74aabSMasahiro Yamada {
23532e74aabSMasahiro Yamada 	struct virt_dma_chan *vc = to_virt_chan(chan);
23632e74aabSMasahiro Yamada 	struct uniphier_mdmac_desc *md;
23732e74aabSMasahiro Yamada 
23832e74aabSMasahiro Yamada 	if (!is_slave_direction(direction))
23932e74aabSMasahiro Yamada 		return NULL;
24032e74aabSMasahiro Yamada 
24132e74aabSMasahiro Yamada 	md = kzalloc(sizeof(*md), GFP_NOWAIT);
24232e74aabSMasahiro Yamada 	if (!md)
24332e74aabSMasahiro Yamada 		return NULL;
24432e74aabSMasahiro Yamada 
24532e74aabSMasahiro Yamada 	md->sgl = sgl;
24632e74aabSMasahiro Yamada 	md->sg_len = sg_len;
24732e74aabSMasahiro Yamada 	md->dir = direction;
24832e74aabSMasahiro Yamada 
24932e74aabSMasahiro Yamada 	return vchan_tx_prep(vc, &md->vd, flags);
25032e74aabSMasahiro Yamada }
25132e74aabSMasahiro Yamada 
uniphier_mdmac_terminate_all(struct dma_chan * chan)25232e74aabSMasahiro Yamada static int uniphier_mdmac_terminate_all(struct dma_chan *chan)
25332e74aabSMasahiro Yamada {
25432e74aabSMasahiro Yamada 	struct virt_dma_chan *vc = to_virt_chan(chan);
25532e74aabSMasahiro Yamada 	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
25632e74aabSMasahiro Yamada 	unsigned long flags;
25732e74aabSMasahiro Yamada 	int ret = 0;
25832e74aabSMasahiro Yamada 	LIST_HEAD(head);
25932e74aabSMasahiro Yamada 
26032e74aabSMasahiro Yamada 	spin_lock_irqsave(&vc->lock, flags);
26132e74aabSMasahiro Yamada 
26232e74aabSMasahiro Yamada 	if (mc->md) {
26332e74aabSMasahiro Yamada 		vchan_terminate_vdesc(&mc->md->vd);
26432e74aabSMasahiro Yamada 		mc->md = NULL;
26532e74aabSMasahiro Yamada 		ret = uniphier_mdmac_abort(mc);
26632e74aabSMasahiro Yamada 	}
26732e74aabSMasahiro Yamada 	vchan_get_all_descriptors(vc, &head);
26832e74aabSMasahiro Yamada 
26932e74aabSMasahiro Yamada 	spin_unlock_irqrestore(&vc->lock, flags);
27032e74aabSMasahiro Yamada 
27132e74aabSMasahiro Yamada 	vchan_dma_desc_free_list(vc, &head);
27232e74aabSMasahiro Yamada 
27332e74aabSMasahiro Yamada 	return ret;
27432e74aabSMasahiro Yamada }
27532e74aabSMasahiro Yamada 
uniphier_mdmac_synchronize(struct dma_chan * chan)27632e74aabSMasahiro Yamada static void uniphier_mdmac_synchronize(struct dma_chan *chan)
27732e74aabSMasahiro Yamada {
27832e74aabSMasahiro Yamada 	vchan_synchronize(to_virt_chan(chan));
27932e74aabSMasahiro Yamada }
28032e74aabSMasahiro Yamada 
uniphier_mdmac_tx_status(struct dma_chan * chan,dma_cookie_t cookie,struct dma_tx_state * txstate)28132e74aabSMasahiro Yamada static enum dma_status uniphier_mdmac_tx_status(struct dma_chan *chan,
28232e74aabSMasahiro Yamada 						dma_cookie_t cookie,
28332e74aabSMasahiro Yamada 						struct dma_tx_state *txstate)
28432e74aabSMasahiro Yamada {
28532e74aabSMasahiro Yamada 	struct virt_dma_chan *vc;
28632e74aabSMasahiro Yamada 	struct virt_dma_desc *vd;
28732e74aabSMasahiro Yamada 	struct uniphier_mdmac_chan *mc;
28832e74aabSMasahiro Yamada 	struct uniphier_mdmac_desc *md = NULL;
28932e74aabSMasahiro Yamada 	enum dma_status stat;
29032e74aabSMasahiro Yamada 	unsigned long flags;
29132e74aabSMasahiro Yamada 	int i;
29232e74aabSMasahiro Yamada 
29332e74aabSMasahiro Yamada 	stat = dma_cookie_status(chan, cookie, txstate);
29432e74aabSMasahiro Yamada 	/* Return immediately if we do not need to compute the residue. */
29532e74aabSMasahiro Yamada 	if (stat == DMA_COMPLETE || !txstate)
29632e74aabSMasahiro Yamada 		return stat;
29732e74aabSMasahiro Yamada 
29832e74aabSMasahiro Yamada 	vc = to_virt_chan(chan);
29932e74aabSMasahiro Yamada 
30032e74aabSMasahiro Yamada 	spin_lock_irqsave(&vc->lock, flags);
30132e74aabSMasahiro Yamada 
30232e74aabSMasahiro Yamada 	mc = to_uniphier_mdmac_chan(vc);
30332e74aabSMasahiro Yamada 
30432e74aabSMasahiro Yamada 	if (mc->md && mc->md->vd.tx.cookie == cookie) {
30532e74aabSMasahiro Yamada 		/* residue from the on-flight chunk */
30632e74aabSMasahiro Yamada 		txstate->residue = readl(mc->reg_ch_base +
30732e74aabSMasahiro Yamada 					 UNIPHIER_MDMAC_CH_SIZE);
30832e74aabSMasahiro Yamada 		md = mc->md;
30932e74aabSMasahiro Yamada 	}
31032e74aabSMasahiro Yamada 
31132e74aabSMasahiro Yamada 	if (!md) {
31232e74aabSMasahiro Yamada 		vd = vchan_find_desc(vc, cookie);
31332e74aabSMasahiro Yamada 		if (vd)
31432e74aabSMasahiro Yamada 			md = to_uniphier_mdmac_desc(vd);
31532e74aabSMasahiro Yamada 	}
31632e74aabSMasahiro Yamada 
31732e74aabSMasahiro Yamada 	if (md) {
31832e74aabSMasahiro Yamada 		/* residue from the queued chunks */
31932e74aabSMasahiro Yamada 		for (i = md->sg_cur; i < md->sg_len; i++)
32032e74aabSMasahiro Yamada 			txstate->residue += sg_dma_len(&md->sgl[i]);
32132e74aabSMasahiro Yamada 	}
32232e74aabSMasahiro Yamada 
32332e74aabSMasahiro Yamada 	spin_unlock_irqrestore(&vc->lock, flags);
32432e74aabSMasahiro Yamada 
32532e74aabSMasahiro Yamada 	return stat;
32632e74aabSMasahiro Yamada }
32732e74aabSMasahiro Yamada 
uniphier_mdmac_issue_pending(struct dma_chan * chan)32832e74aabSMasahiro Yamada static void uniphier_mdmac_issue_pending(struct dma_chan *chan)
32932e74aabSMasahiro Yamada {
33032e74aabSMasahiro Yamada 	struct virt_dma_chan *vc = to_virt_chan(chan);
33132e74aabSMasahiro Yamada 	struct uniphier_mdmac_chan *mc = to_uniphier_mdmac_chan(vc);
33232e74aabSMasahiro Yamada 	unsigned long flags;
33332e74aabSMasahiro Yamada 
33432e74aabSMasahiro Yamada 	spin_lock_irqsave(&vc->lock, flags);
33532e74aabSMasahiro Yamada 
33632e74aabSMasahiro Yamada 	if (vchan_issue_pending(vc) && !mc->md)
33732e74aabSMasahiro Yamada 		uniphier_mdmac_start(mc);
33832e74aabSMasahiro Yamada 
33932e74aabSMasahiro Yamada 	spin_unlock_irqrestore(&vc->lock, flags);
34032e74aabSMasahiro Yamada }
34132e74aabSMasahiro Yamada 
uniphier_mdmac_desc_free(struct virt_dma_desc * vd)34232e74aabSMasahiro Yamada static void uniphier_mdmac_desc_free(struct virt_dma_desc *vd)
34332e74aabSMasahiro Yamada {
34432e74aabSMasahiro Yamada 	kfree(to_uniphier_mdmac_desc(vd));
34532e74aabSMasahiro Yamada }
34632e74aabSMasahiro Yamada 
uniphier_mdmac_chan_init(struct platform_device * pdev,struct uniphier_mdmac_device * mdev,int chan_id)34732e74aabSMasahiro Yamada static int uniphier_mdmac_chan_init(struct platform_device *pdev,
34832e74aabSMasahiro Yamada 				    struct uniphier_mdmac_device *mdev,
34932e74aabSMasahiro Yamada 				    int chan_id)
35032e74aabSMasahiro Yamada {
35132e74aabSMasahiro Yamada 	struct device *dev = &pdev->dev;
35232e74aabSMasahiro Yamada 	struct uniphier_mdmac_chan *mc = &mdev->channels[chan_id];
35332e74aabSMasahiro Yamada 	char *irq_name;
35432e74aabSMasahiro Yamada 	int irq, ret;
35532e74aabSMasahiro Yamada 
35632e74aabSMasahiro Yamada 	irq = platform_get_irq(pdev, chan_id);
357e17be6e1SStephen Boyd 	if (irq < 0)
35832e74aabSMasahiro Yamada 		return irq;
35932e74aabSMasahiro Yamada 
36032e74aabSMasahiro Yamada 	irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d",
36132e74aabSMasahiro Yamada 				  chan_id);
36232e74aabSMasahiro Yamada 	if (!irq_name)
36332e74aabSMasahiro Yamada 		return -ENOMEM;
36432e74aabSMasahiro Yamada 
36532e74aabSMasahiro Yamada 	ret = devm_request_irq(dev, irq, uniphier_mdmac_interrupt,
36632e74aabSMasahiro Yamada 			       IRQF_SHARED, irq_name, mc);
36732e74aabSMasahiro Yamada 	if (ret)
36832e74aabSMasahiro Yamada 		return ret;
36932e74aabSMasahiro Yamada 
37032e74aabSMasahiro Yamada 	mc->mdev = mdev;
37132e74aabSMasahiro Yamada 	mc->reg_ch_base = mdev->reg_base + UNIPHIER_MDMAC_CH_OFFSET +
37232e74aabSMasahiro Yamada 					UNIPHIER_MDMAC_CH_STRIDE * chan_id;
37332e74aabSMasahiro Yamada 	mc->chan_id = chan_id;
37432e74aabSMasahiro Yamada 	mc->vc.desc_free = uniphier_mdmac_desc_free;
37532e74aabSMasahiro Yamada 	vchan_init(&mc->vc, &mdev->ddev);
37632e74aabSMasahiro Yamada 
37732e74aabSMasahiro Yamada 	return 0;
37832e74aabSMasahiro Yamada }
37932e74aabSMasahiro Yamada 
uniphier_mdmac_probe(struct platform_device * pdev)38032e74aabSMasahiro Yamada static int uniphier_mdmac_probe(struct platform_device *pdev)
38132e74aabSMasahiro Yamada {
38232e74aabSMasahiro Yamada 	struct device *dev = &pdev->dev;
38332e74aabSMasahiro Yamada 	struct uniphier_mdmac_device *mdev;
38432e74aabSMasahiro Yamada 	struct dma_device *ddev;
38532e74aabSMasahiro Yamada 	int nr_chans, ret, i;
38632e74aabSMasahiro Yamada 
38732e74aabSMasahiro Yamada 	nr_chans = platform_irq_count(pdev);
38832e74aabSMasahiro Yamada 	if (nr_chans < 0)
38932e74aabSMasahiro Yamada 		return nr_chans;
39032e74aabSMasahiro Yamada 
39132e74aabSMasahiro Yamada 	ret = dma_set_mask(dev, DMA_BIT_MASK(32));
39232e74aabSMasahiro Yamada 	if (ret)
39332e74aabSMasahiro Yamada 		return ret;
39432e74aabSMasahiro Yamada 
39532e74aabSMasahiro Yamada 	mdev = devm_kzalloc(dev, struct_size(mdev, channels, nr_chans),
39632e74aabSMasahiro Yamada 			    GFP_KERNEL);
39732e74aabSMasahiro Yamada 	if (!mdev)
39832e74aabSMasahiro Yamada 		return -ENOMEM;
39932e74aabSMasahiro Yamada 
4005b3e3606SMasahiro Yamada 	mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
40132e74aabSMasahiro Yamada 	if (IS_ERR(mdev->reg_base))
40232e74aabSMasahiro Yamada 		return PTR_ERR(mdev->reg_base);
40332e74aabSMasahiro Yamada 
40432e74aabSMasahiro Yamada 	mdev->clk = devm_clk_get(dev, NULL);
40532e74aabSMasahiro Yamada 	if (IS_ERR(mdev->clk)) {
40632e74aabSMasahiro Yamada 		dev_err(dev, "failed to get clock\n");
40732e74aabSMasahiro Yamada 		return PTR_ERR(mdev->clk);
40832e74aabSMasahiro Yamada 	}
40932e74aabSMasahiro Yamada 
41032e74aabSMasahiro Yamada 	ret = clk_prepare_enable(mdev->clk);
41132e74aabSMasahiro Yamada 	if (ret)
41232e74aabSMasahiro Yamada 		return ret;
41332e74aabSMasahiro Yamada 
41432e74aabSMasahiro Yamada 	ddev = &mdev->ddev;
41532e74aabSMasahiro Yamada 	ddev->dev = dev;
41632e74aabSMasahiro Yamada 	dma_cap_set(DMA_PRIVATE, ddev->cap_mask);
41732e74aabSMasahiro Yamada 	ddev->src_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS;
41832e74aabSMasahiro Yamada 	ddev->dst_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS;
41932e74aabSMasahiro Yamada 	ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
42032e74aabSMasahiro Yamada 	ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
42132e74aabSMasahiro Yamada 	ddev->device_free_chan_resources = uniphier_mdmac_free_chan_resources;
42232e74aabSMasahiro Yamada 	ddev->device_prep_slave_sg = uniphier_mdmac_prep_slave_sg;
42332e74aabSMasahiro Yamada 	ddev->device_terminate_all = uniphier_mdmac_terminate_all;
42432e74aabSMasahiro Yamada 	ddev->device_synchronize = uniphier_mdmac_synchronize;
42532e74aabSMasahiro Yamada 	ddev->device_tx_status = uniphier_mdmac_tx_status;
42632e74aabSMasahiro Yamada 	ddev->device_issue_pending = uniphier_mdmac_issue_pending;
42732e74aabSMasahiro Yamada 	INIT_LIST_HEAD(&ddev->channels);
42832e74aabSMasahiro Yamada 
42932e74aabSMasahiro Yamada 	for (i = 0; i < nr_chans; i++) {
43032e74aabSMasahiro Yamada 		ret = uniphier_mdmac_chan_init(pdev, mdev, i);
43132e74aabSMasahiro Yamada 		if (ret)
43232e74aabSMasahiro Yamada 			goto disable_clk;
43332e74aabSMasahiro Yamada 	}
43432e74aabSMasahiro Yamada 
43532e74aabSMasahiro Yamada 	ret = dma_async_device_register(ddev);
43632e74aabSMasahiro Yamada 	if (ret)
43732e74aabSMasahiro Yamada 		goto disable_clk;
43832e74aabSMasahiro Yamada 
43932e74aabSMasahiro Yamada 	ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id,
44032e74aabSMasahiro Yamada 					 ddev);
44132e74aabSMasahiro Yamada 	if (ret)
44232e74aabSMasahiro Yamada 		goto unregister_dmac;
44332e74aabSMasahiro Yamada 
44432e74aabSMasahiro Yamada 	platform_set_drvdata(pdev, mdev);
44532e74aabSMasahiro Yamada 
44632e74aabSMasahiro Yamada 	return 0;
44732e74aabSMasahiro Yamada 
44832e74aabSMasahiro Yamada unregister_dmac:
44932e74aabSMasahiro Yamada 	dma_async_device_unregister(ddev);
45032e74aabSMasahiro Yamada disable_clk:
45132e74aabSMasahiro Yamada 	clk_disable_unprepare(mdev->clk);
45232e74aabSMasahiro Yamada 
45332e74aabSMasahiro Yamada 	return ret;
45432e74aabSMasahiro Yamada }
45532e74aabSMasahiro Yamada 
uniphier_mdmac_remove(struct platform_device * pdev)45632e74aabSMasahiro Yamada static int uniphier_mdmac_remove(struct platform_device *pdev)
45732e74aabSMasahiro Yamada {
45832e74aabSMasahiro Yamada 	struct uniphier_mdmac_device *mdev = platform_get_drvdata(pdev);
45932e74aabSMasahiro Yamada 	struct dma_chan *chan;
46032e74aabSMasahiro Yamada 	int ret;
46132e74aabSMasahiro Yamada 
46232e74aabSMasahiro Yamada 	/*
46332e74aabSMasahiro Yamada 	 * Before reaching here, almost all descriptors have been freed by the
46432e74aabSMasahiro Yamada 	 * ->device_free_chan_resources() hook. However, each channel might
46532e74aabSMasahiro Yamada 	 * be still holding one descriptor that was on-flight at that moment.
46632e74aabSMasahiro Yamada 	 * Terminate it to make sure this hardware is no longer running. Then,
46732e74aabSMasahiro Yamada 	 * free the channel resources once again to avoid memory leak.
46832e74aabSMasahiro Yamada 	 */
46932e74aabSMasahiro Yamada 	list_for_each_entry(chan, &mdev->ddev.channels, device_node) {
47032e74aabSMasahiro Yamada 		ret = dmaengine_terminate_sync(chan);
47132e74aabSMasahiro Yamada 		if (ret)
47232e74aabSMasahiro Yamada 			return ret;
47332e74aabSMasahiro Yamada 		uniphier_mdmac_free_chan_resources(chan);
47432e74aabSMasahiro Yamada 	}
47532e74aabSMasahiro Yamada 
47632e74aabSMasahiro Yamada 	of_dma_controller_free(pdev->dev.of_node);
47732e74aabSMasahiro Yamada 	dma_async_device_unregister(&mdev->ddev);
47832e74aabSMasahiro Yamada 	clk_disable_unprepare(mdev->clk);
47932e74aabSMasahiro Yamada 
48032e74aabSMasahiro Yamada 	return 0;
48132e74aabSMasahiro Yamada }
48232e74aabSMasahiro Yamada 
48332e74aabSMasahiro Yamada static const struct of_device_id uniphier_mdmac_match[] = {
48432e74aabSMasahiro Yamada 	{ .compatible = "socionext,uniphier-mio-dmac" },
48532e74aabSMasahiro Yamada 	{ /* sentinel */ }
48632e74aabSMasahiro Yamada };
48732e74aabSMasahiro Yamada MODULE_DEVICE_TABLE(of, uniphier_mdmac_match);
48832e74aabSMasahiro Yamada 
48932e74aabSMasahiro Yamada static struct platform_driver uniphier_mdmac_driver = {
49032e74aabSMasahiro Yamada 	.probe = uniphier_mdmac_probe,
49132e74aabSMasahiro Yamada 	.remove = uniphier_mdmac_remove,
49232e74aabSMasahiro Yamada 	.driver = {
49332e74aabSMasahiro Yamada 		.name = "uniphier-mio-dmac",
49432e74aabSMasahiro Yamada 		.of_match_table = uniphier_mdmac_match,
49532e74aabSMasahiro Yamada 	},
49632e74aabSMasahiro Yamada };
49732e74aabSMasahiro Yamada module_platform_driver(uniphier_mdmac_driver);
49832e74aabSMasahiro Yamada 
49932e74aabSMasahiro Yamada MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
50032e74aabSMasahiro Yamada MODULE_DESCRIPTION("UniPhier MIO DMAC driver");
50132e74aabSMasahiro Yamada MODULE_LICENSE("GPL v2");
502