Lines Matching +full:dma +full:- +full:maxburst

1 // SPDX-License-Identifier: GPL-2.0
3 * External DMA controller driver for UniPhier SoCs
18 #include "virt-dma.h"
115 /* xc->vc.lock must be held by caller */
121 vd = vchan_next_desc(&xc->vc); in uniphier_xdmac_next_desc()
125 list_del(&vd->node); in uniphier_xdmac_next_desc()
130 /* xc->vc.lock must be held by caller */
140 src_addr = xd->nodes[xd->cur_node].src; in uniphier_xdmac_chan_start()
141 dst_addr = xd->nodes[xd->cur_node].dst; in uniphier_xdmac_chan_start()
142 its = xd->nodes[xd->cur_node].burst_size; in uniphier_xdmac_chan_start()
143 tnum = xd->nodes[xd->cur_node].nr_burst; in uniphier_xdmac_chan_start()
149 if (xd->dir == DMA_DEV_TO_MEM) { in uniphier_xdmac_chan_start()
151 buswidth = xc->sconfig.src_addr_width; in uniphier_xdmac_chan_start()
158 if (xd->dir == DMA_MEM_TO_DEV) { in uniphier_xdmac_chan_start()
160 buswidth = xc->sconfig.dst_addr_width; in uniphier_xdmac_chan_start()
169 val |= FIELD_PREP(XDMAC_TFA_MASK, xc->req_factor); in uniphier_xdmac_chan_start()
170 writel(val, xc->reg_ch_base + XDMAC_TFA); in uniphier_xdmac_chan_start()
173 writel(lower_32_bits(src_addr), xc->reg_ch_base + XDMAC_SAD); in uniphier_xdmac_chan_start()
174 writel(upper_32_bits(src_addr), xc->reg_ch_base + XDMAC_EXSAD); in uniphier_xdmac_chan_start()
176 writel(lower_32_bits(dst_addr), xc->reg_ch_base + XDMAC_DAD); in uniphier_xdmac_chan_start()
177 writel(upper_32_bits(dst_addr), xc->reg_ch_base + XDMAC_EXDAD); in uniphier_xdmac_chan_start()
181 writel(src_mode, xc->reg_ch_base + XDMAC_SADM); in uniphier_xdmac_chan_start()
182 writel(dst_mode, xc->reg_ch_base + XDMAC_DADM); in uniphier_xdmac_chan_start()
184 writel(its, xc->reg_ch_base + XDMAC_ITS); in uniphier_xdmac_chan_start()
185 writel(tnum, xc->reg_ch_base + XDMAC_TNUM); in uniphier_xdmac_chan_start()
189 xc->reg_ch_base + XDMAC_IEN); in uniphier_xdmac_chan_start()
192 val = readl(xc->reg_ch_base + XDMAC_TSS); in uniphier_xdmac_chan_start()
194 writel(val, xc->reg_ch_base + XDMAC_TSS); in uniphier_xdmac_chan_start()
197 /* xc->vc.lock must be held by caller */
203 val = readl(xc->reg_ch_base + XDMAC_IEN); in uniphier_xdmac_chan_stop()
205 writel(val, xc->reg_ch_base + XDMAC_IEN); in uniphier_xdmac_chan_stop()
208 val = readl(xc->reg_ch_base + XDMAC_TSS); in uniphier_xdmac_chan_stop()
210 writel(0, xc->reg_ch_base + XDMAC_TSS); in uniphier_xdmac_chan_stop()
213 return readl_poll_timeout_atomic(xc->reg_ch_base + XDMAC_STAT, val, in uniphier_xdmac_chan_stop()
217 /* xc->vc.lock must be held by caller */
227 xc->xd = xd; in uniphier_xdmac_start()
235 spin_lock(&xc->vc.lock); in uniphier_xdmac_chan_irq()
237 stat = readl(xc->reg_ch_base + XDMAC_ID); in uniphier_xdmac_chan_irq()
242 dev_err(xc->xdev->ddev.dev, in uniphier_xdmac_chan_irq()
243 "DMA transfer error with aborting issue\n"); in uniphier_xdmac_chan_irq()
245 dev_err(xc->xdev->ddev.dev, in uniphier_xdmac_chan_irq()
246 "DMA transfer error\n"); in uniphier_xdmac_chan_irq()
248 } else if ((stat & XDMAC_ID_ENDIDF) && xc->xd) { in uniphier_xdmac_chan_irq()
249 xc->xd->cur_node++; in uniphier_xdmac_chan_irq()
250 if (xc->xd->cur_node >= xc->xd->nr_node) { in uniphier_xdmac_chan_irq()
251 vchan_cookie_complete(&xc->xd->vd); in uniphier_xdmac_chan_irq()
254 uniphier_xdmac_chan_start(xc, xc->xd); in uniphier_xdmac_chan_irq()
259 writel(stat, xc->reg_ch_base + XDMAC_IR); in uniphier_xdmac_chan_irq()
261 spin_unlock(&xc->vc.lock); in uniphier_xdmac_chan_irq()
269 for (i = 0; i < xdev->nr_chans; i++) in uniphier_xdmac_irq_handler()
270 uniphier_xdmac_chan_irq(&xdev->channels[i]); in uniphier_xdmac_irq_handler()
301 xd->nodes[i].src = src; in uniphier_xdmac_prep_dma_memcpy()
302 xd->nodes[i].dst = dst; in uniphier_xdmac_prep_dma_memcpy()
303 xd->nodes[i].burst_size = burst_size; in uniphier_xdmac_prep_dma_memcpy()
304 xd->nodes[i].nr_burst = len / burst_size; in uniphier_xdmac_prep_dma_memcpy()
308 len -= tlen; in uniphier_xdmac_prep_dma_memcpy()
311 xd->dir = DMA_MEM_TO_MEM; in uniphier_xdmac_prep_dma_memcpy()
312 xd->nr_node = nr; in uniphier_xdmac_prep_dma_memcpy()
313 xd->cur_node = 0; in uniphier_xdmac_prep_dma_memcpy()
315 return vchan_tx_prep(vc, &xd->vd, flags); in uniphier_xdmac_prep_dma_memcpy()
329 u32 maxburst; in uniphier_xdmac_prep_slave_sg() local
336 buswidth = xc->sconfig.src_addr_width; in uniphier_xdmac_prep_slave_sg()
337 maxburst = xc->sconfig.src_maxburst; in uniphier_xdmac_prep_slave_sg()
339 buswidth = xc->sconfig.dst_addr_width; in uniphier_xdmac_prep_slave_sg()
340 maxburst = xc->sconfig.dst_maxburst; in uniphier_xdmac_prep_slave_sg()
343 if (!maxburst) in uniphier_xdmac_prep_slave_sg()
344 maxburst = 1; in uniphier_xdmac_prep_slave_sg()
345 if (maxburst > xc->xdev->ddev.max_burst) { in uniphier_xdmac_prep_slave_sg()
346 dev_err(xc->xdev->ddev.dev, in uniphier_xdmac_prep_slave_sg()
356 xd->nodes[i].src = (direction == DMA_DEV_TO_MEM) in uniphier_xdmac_prep_slave_sg()
357 ? xc->sconfig.src_addr : sg_dma_address(sg); in uniphier_xdmac_prep_slave_sg()
358 xd->nodes[i].dst = (direction == DMA_MEM_TO_DEV) in uniphier_xdmac_prep_slave_sg()
359 ? xc->sconfig.dst_addr : sg_dma_address(sg); in uniphier_xdmac_prep_slave_sg()
360 xd->nodes[i].burst_size = maxburst * buswidth; in uniphier_xdmac_prep_slave_sg()
361 xd->nodes[i].nr_burst = in uniphier_xdmac_prep_slave_sg()
362 sg_dma_len(sg) / xd->nodes[i].burst_size; in uniphier_xdmac_prep_slave_sg()
366 * (the number of burst words * bus-width) is not allowed, in uniphier_xdmac_prep_slave_sg()
372 if (sg_dma_len(sg) % xd->nodes[i].burst_size) { in uniphier_xdmac_prep_slave_sg()
373 dev_err(xc->xdev->ddev.dev, in uniphier_xdmac_prep_slave_sg()
379 if (xd->nodes[i].nr_burst > XDMAC_MAX_WORDS) { in uniphier_xdmac_prep_slave_sg()
380 dev_err(xc->xdev->ddev.dev, in uniphier_xdmac_prep_slave_sg()
387 xd->dir = direction; in uniphier_xdmac_prep_slave_sg()
388 xd->nr_node = sg_len; in uniphier_xdmac_prep_slave_sg()
389 xd->cur_node = 0; in uniphier_xdmac_prep_slave_sg()
391 return vchan_tx_prep(vc, &xd->vd, flags); in uniphier_xdmac_prep_slave_sg()
400 memcpy(&xc->sconfig, config, sizeof(*config)); in uniphier_xdmac_slave_config()
413 spin_lock_irqsave(&vc->lock, flags); in uniphier_xdmac_terminate_all()
415 if (xc->xd) { in uniphier_xdmac_terminate_all()
416 vchan_terminate_vdesc(&xc->xd->vd); in uniphier_xdmac_terminate_all()
417 xc->xd = NULL; in uniphier_xdmac_terminate_all()
423 spin_unlock_irqrestore(&vc->lock, flags); in uniphier_xdmac_terminate_all()
441 spin_lock_irqsave(&vc->lock, flags); in uniphier_xdmac_issue_pending()
443 if (vchan_issue_pending(vc) && !xc->xd) in uniphier_xdmac_issue_pending()
446 spin_unlock_irqrestore(&vc->lock, flags); in uniphier_xdmac_issue_pending()
457 struct uniphier_xdmac_chan *xc = &xdev->channels[ch]; in uniphier_xdmac_chan_init()
459 xc->xdev = xdev; in uniphier_xdmac_chan_init()
460 xc->reg_ch_base = xdev->reg_base + XDMAC_CH_WIDTH * ch; in uniphier_xdmac_chan_init()
461 xc->vc.desc_free = uniphier_xdmac_desc_free; in uniphier_xdmac_chan_init()
463 vchan_init(&xc->vc, &xdev->ddev); in uniphier_xdmac_chan_init()
469 struct uniphier_xdmac_device *xdev = ofdma->of_dma_data; in of_dma_uniphier_xlate()
470 int chan_id = dma_spec->args[0]; in of_dma_uniphier_xlate()
472 if (chan_id >= xdev->nr_chans) in of_dma_uniphier_xlate()
475 xdev->channels[chan_id].id = chan_id; in of_dma_uniphier_xlate()
476 xdev->channels[chan_id].req_factor = dma_spec->args[1]; in of_dma_uniphier_xlate()
478 return dma_get_slave_channel(&xdev->channels[chan_id].vc.chan); in of_dma_uniphier_xlate()
484 struct device *dev = &pdev->dev; in uniphier_xdmac_probe()
490 if (of_property_read_u32(dev->of_node, "dma-channels", &nr_chans)) in uniphier_xdmac_probe()
491 return -EINVAL; in uniphier_xdmac_probe()
498 return -ENOMEM; in uniphier_xdmac_probe()
500 xdev->nr_chans = nr_chans; in uniphier_xdmac_probe()
501 xdev->reg_base = devm_platform_ioremap_resource(pdev, 0); in uniphier_xdmac_probe()
502 if (IS_ERR(xdev->reg_base)) in uniphier_xdmac_probe()
503 return PTR_ERR(xdev->reg_base); in uniphier_xdmac_probe()
505 ddev = &xdev->ddev; in uniphier_xdmac_probe()
506 ddev->dev = dev; in uniphier_xdmac_probe()
507 dma_cap_zero(ddev->cap_mask); in uniphier_xdmac_probe()
508 dma_cap_set(DMA_MEMCPY, ddev->cap_mask); in uniphier_xdmac_probe()
509 dma_cap_set(DMA_SLAVE, ddev->cap_mask); in uniphier_xdmac_probe()
510 ddev->src_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS; in uniphier_xdmac_probe()
511 ddev->dst_addr_widths = UNIPHIER_XDMAC_BUSWIDTHS; in uniphier_xdmac_probe()
512 ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) | in uniphier_xdmac_probe()
514 ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; in uniphier_xdmac_probe()
515 ddev->max_burst = XDMAC_MAX_WORDS; in uniphier_xdmac_probe()
516 ddev->device_free_chan_resources = uniphier_xdmac_free_chan_resources; in uniphier_xdmac_probe()
517 ddev->device_prep_dma_memcpy = uniphier_xdmac_prep_dma_memcpy; in uniphier_xdmac_probe()
518 ddev->device_prep_slave_sg = uniphier_xdmac_prep_slave_sg; in uniphier_xdmac_probe()
519 ddev->device_config = uniphier_xdmac_slave_config; in uniphier_xdmac_probe()
520 ddev->device_terminate_all = uniphier_xdmac_terminate_all; in uniphier_xdmac_probe()
521 ddev->device_synchronize = uniphier_xdmac_synchronize; in uniphier_xdmac_probe()
522 ddev->device_tx_status = dma_cookie_status; in uniphier_xdmac_probe()
523 ddev->device_issue_pending = uniphier_xdmac_issue_pending; in uniphier_xdmac_probe()
524 INIT_LIST_HEAD(&ddev->channels); in uniphier_xdmac_probe()
546 ret = of_dma_controller_register(dev->of_node, in uniphier_xdmac_probe()
555 dev_info(&pdev->dev, "UniPhier XDMAC driver (%d channels)\n", in uniphier_xdmac_probe()
569 struct dma_device *ddev = &xdev->ddev; in uniphier_xdmac_remove()
575 * ->device_free_chan_resources() hook. However, each channel might in uniphier_xdmac_remove()
576 * be still holding one descriptor that was on-flight at that moment. in uniphier_xdmac_remove()
580 list_for_each_entry(chan, &ddev->channels, device_node) { in uniphier_xdmac_remove()
587 of_dma_controller_free(pdev->dev.of_node); in uniphier_xdmac_remove()
594 { .compatible = "socionext,uniphier-xdmac" },
603 .name = "uniphier-xdmac",
610 MODULE_DESCRIPTION("UniPhier external DMA controller driver");