Lines Matching +full:uniphier +full:- +full:mio +full:- +full:dmac
1 // SPDX-License-Identifier: GPL-2.0
8 #include <linux/dma-mapping.h>
20 #include "virt-dma.h"
26 /* per-channel registers */
86 /* mc->vc.lock must be held by caller */
92 vd = vchan_next_desc(&mc->vc); in uniphier_mdmac_next_desc()
94 mc->md = NULL; in uniphier_mdmac_next_desc()
98 list_del(&vd->node); in uniphier_mdmac_next_desc()
100 mc->md = to_uniphier_mdmac_desc(vd); in uniphier_mdmac_next_desc()
102 return mc->md; in uniphier_mdmac_next_desc()
105 /* mc->vc.lock must be held by caller */
109 struct uniphier_mdmac_device *mdev = mc->mdev; in uniphier_mdmac_handle()
114 sg = &md->sgl[md->sg_cur]; in uniphier_mdmac_handle()
116 if (md->dir == DMA_MEM_TO_DEV) { in uniphier_mdmac_handle()
130 writel(src_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_MODE); in uniphier_mdmac_handle()
131 writel(dest_mode, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_MODE); in uniphier_mdmac_handle()
132 writel(src_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SRC_ADDR); in uniphier_mdmac_handle()
133 writel(dest_addr, mc->reg_ch_base + UNIPHIER_MDMAC_CH_DEST_ADDR); in uniphier_mdmac_handle()
134 writel(chunk_size, mc->reg_ch_base + UNIPHIER_MDMAC_CH_SIZE); in uniphier_mdmac_handle()
137 writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ); in uniphier_mdmac_handle()
139 writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_EN); in uniphier_mdmac_handle()
141 writel(BIT(mc->chan_id), mdev->reg_base + UNIPHIER_MDMAC_CMD); in uniphier_mdmac_handle()
144 /* mc->vc.lock must be held by caller */
154 /* mc->vc.lock must be held by caller */
157 struct uniphier_mdmac_device *mdev = mc->mdev; in uniphier_mdmac_abort()
162 writel(irq_flag, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ); in uniphier_mdmac_abort()
164 writel(UNIPHIER_MDMAC_CMD_ABORT | BIT(mc->chan_id), in uniphier_mdmac_abort()
165 mdev->reg_base + UNIPHIER_MDMAC_CMD); in uniphier_mdmac_abort()
171 return readl_poll_timeout(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ, in uniphier_mdmac_abort()
182 spin_lock(&mc->vc.lock); in uniphier_mdmac_interrupt()
184 irq_stat = readl(mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_DET); in uniphier_mdmac_interrupt()
196 writel(irq_stat, mc->reg_ch_base + UNIPHIER_MDMAC_CH_IRQ_REQ); in uniphier_mdmac_interrupt()
201 * check mc->md. If it is NULL, we are aborting. in uniphier_mdmac_interrupt()
203 md = mc->md; in uniphier_mdmac_interrupt()
207 md->sg_cur++; in uniphier_mdmac_interrupt()
209 if (md->sg_cur >= md->sg_len) { in uniphier_mdmac_interrupt()
210 vchan_cookie_complete(&md->vd); in uniphier_mdmac_interrupt()
219 spin_unlock(&mc->vc.lock); in uniphier_mdmac_interrupt()
245 md->sgl = sgl; in uniphier_mdmac_prep_slave_sg()
246 md->sg_len = sg_len; in uniphier_mdmac_prep_slave_sg()
247 md->dir = direction; in uniphier_mdmac_prep_slave_sg()
249 return vchan_tx_prep(vc, &md->vd, flags); in uniphier_mdmac_prep_slave_sg()
260 spin_lock_irqsave(&vc->lock, flags); in uniphier_mdmac_terminate_all()
262 if (mc->md) { in uniphier_mdmac_terminate_all()
263 vchan_terminate_vdesc(&mc->md->vd); in uniphier_mdmac_terminate_all()
264 mc->md = NULL; in uniphier_mdmac_terminate_all()
269 spin_unlock_irqrestore(&vc->lock, flags); in uniphier_mdmac_terminate_all()
300 spin_lock_irqsave(&vc->lock, flags); in uniphier_mdmac_tx_status()
304 if (mc->md && mc->md->vd.tx.cookie == cookie) { in uniphier_mdmac_tx_status()
305 /* residue from the on-flight chunk */ in uniphier_mdmac_tx_status()
306 txstate->residue = readl(mc->reg_ch_base + in uniphier_mdmac_tx_status()
308 md = mc->md; in uniphier_mdmac_tx_status()
319 for (i = md->sg_cur; i < md->sg_len; i++) in uniphier_mdmac_tx_status()
320 txstate->residue += sg_dma_len(&md->sgl[i]); in uniphier_mdmac_tx_status()
323 spin_unlock_irqrestore(&vc->lock, flags); in uniphier_mdmac_tx_status()
334 spin_lock_irqsave(&vc->lock, flags); in uniphier_mdmac_issue_pending()
336 if (vchan_issue_pending(vc) && !mc->md) in uniphier_mdmac_issue_pending()
339 spin_unlock_irqrestore(&vc->lock, flags); in uniphier_mdmac_issue_pending()
351 struct device *dev = &pdev->dev; in uniphier_mdmac_chan_init()
352 struct uniphier_mdmac_chan *mc = &mdev->channels[chan_id]; in uniphier_mdmac_chan_init()
360 irq_name = devm_kasprintf(dev, GFP_KERNEL, "uniphier-mio-dmac-ch%d", in uniphier_mdmac_chan_init()
363 return -ENOMEM; in uniphier_mdmac_chan_init()
370 mc->mdev = mdev; in uniphier_mdmac_chan_init()
371 mc->reg_ch_base = mdev->reg_base + UNIPHIER_MDMAC_CH_OFFSET + in uniphier_mdmac_chan_init()
373 mc->chan_id = chan_id; in uniphier_mdmac_chan_init()
374 mc->vc.desc_free = uniphier_mdmac_desc_free; in uniphier_mdmac_chan_init()
375 vchan_init(&mc->vc, &mdev->ddev); in uniphier_mdmac_chan_init()
382 struct device *dev = &pdev->dev; in uniphier_mdmac_probe()
398 return -ENOMEM; in uniphier_mdmac_probe()
400 mdev->reg_base = devm_platform_ioremap_resource(pdev, 0); in uniphier_mdmac_probe()
401 if (IS_ERR(mdev->reg_base)) in uniphier_mdmac_probe()
402 return PTR_ERR(mdev->reg_base); in uniphier_mdmac_probe()
404 mdev->clk = devm_clk_get(dev, NULL); in uniphier_mdmac_probe()
405 if (IS_ERR(mdev->clk)) { in uniphier_mdmac_probe()
407 return PTR_ERR(mdev->clk); in uniphier_mdmac_probe()
410 ret = clk_prepare_enable(mdev->clk); in uniphier_mdmac_probe()
414 ddev = &mdev->ddev; in uniphier_mdmac_probe()
415 ddev->dev = dev; in uniphier_mdmac_probe()
416 dma_cap_set(DMA_PRIVATE, ddev->cap_mask); in uniphier_mdmac_probe()
417 ddev->src_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS; in uniphier_mdmac_probe()
418 ddev->dst_addr_widths = UNIPHIER_MDMAC_SLAVE_BUSWIDTHS; in uniphier_mdmac_probe()
419 ddev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); in uniphier_mdmac_probe()
420 ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; in uniphier_mdmac_probe()
421 ddev->device_free_chan_resources = uniphier_mdmac_free_chan_resources; in uniphier_mdmac_probe()
422 ddev->device_prep_slave_sg = uniphier_mdmac_prep_slave_sg; in uniphier_mdmac_probe()
423 ddev->device_terminate_all = uniphier_mdmac_terminate_all; in uniphier_mdmac_probe()
424 ddev->device_synchronize = uniphier_mdmac_synchronize; in uniphier_mdmac_probe()
425 ddev->device_tx_status = uniphier_mdmac_tx_status; in uniphier_mdmac_probe()
426 ddev->device_issue_pending = uniphier_mdmac_issue_pending; in uniphier_mdmac_probe()
427 INIT_LIST_HEAD(&ddev->channels); in uniphier_mdmac_probe()
439 ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id, in uniphier_mdmac_probe()
451 clk_disable_unprepare(mdev->clk); in uniphier_mdmac_probe()
464 * ->device_free_chan_resources() hook. However, each channel might in uniphier_mdmac_remove()
465 * be still holding one descriptor that was on-flight at that moment. in uniphier_mdmac_remove()
469 list_for_each_entry(chan, &mdev->ddev.channels, device_node) { in uniphier_mdmac_remove()
476 of_dma_controller_free(pdev->dev.of_node); in uniphier_mdmac_remove()
477 dma_async_device_unregister(&mdev->ddev); in uniphier_mdmac_remove()
478 clk_disable_unprepare(mdev->clk); in uniphier_mdmac_remove()
484 { .compatible = "socionext,uniphier-mio-dmac" },
493 .name = "uniphier-mio-dmac",
500 MODULE_DESCRIPTION("UniPhier MIO DMAC driver");