Lines Matching +full:ls2k1000 +full:- +full:apbdma
1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2017-2023 Loongson Corporation
9 #include <linux/dma-mapping.h>
13 #include <linux/io-64-nonatomic-lo-hi.h>
21 #include "virt-dma.h"
49 /*-- descriptors -----------------------------------------------------*/
52 * struct ls2x_dma_hw_desc - DMA HW descriptor
80 * struct ls2x_dma_sg - ls2x dma scatter gather entry
94 * struct ls2x_dma_desc - software descriptor
113 /*-- Channels --------------------------------------------------------*/
116 * struct ls2x_dma_chan - internal representation of an LS2X APB DMA channel
131 /*-- Controller ------------------------------------------------------*/
134 * struct ls2x_dma_priv - LS2X APB DMAC specific information
147 /*-- Helper functions ------------------------------------------------*/
166 return &chan->dev->device; in chan2dev()
171 struct ls2x_dma_chan *lchan = to_ldma_chan(vdesc->tx.chan); in ls2x_dma_desc_free()
175 for (i = 0; i < desc->desc_num; i++) { in ls2x_dma_desc_free()
176 if (desc->sg[i].hw) in ls2x_dma_desc_free()
177 dma_pool_free(lchan->pool, desc->sg[i].hw, in ls2x_dma_desc_free()
178 desc->sg[i].llp); in ls2x_dma_desc_free()
186 struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); in ls2x_dma_write_cmd()
189 val = lo_hi_readq(priv->regs + LDMA_ORDER_ERG) & ~LDMA_CONFIG_MASK; in ls2x_dma_write_cmd()
191 lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); in ls2x_dma_write_cmd()
196 struct ls2x_dma_priv *priv = to_ldma_priv(lchan->vchan.chan.device); in ls2x_dma_start_transfer()
202 vdesc = vchan_next_desc(&lchan->vchan); in ls2x_dma_start_transfer()
204 lchan->desc = NULL; in ls2x_dma_start_transfer()
208 list_del(&vdesc->node); in ls2x_dma_start_transfer()
209 lchan->desc = to_ldma_desc(vdesc); in ls2x_dma_start_transfer()
210 ldma_sg = &lchan->desc->sg[0]; in ls2x_dma_start_transfer()
213 lo_hi_writeq(0, priv->regs + LDMA_ORDER_ERG); in ls2x_dma_start_transfer()
214 val = (ldma_sg->llp & ~LDMA_CONFIG_MASK) | LDMA_64BIT_EN | LDMA_START; in ls2x_dma_start_transfer()
215 lo_hi_writeq(val, priv->regs + LDMA_ORDER_ERG); in ls2x_dma_start_transfer()
223 if ((lchan->sconfig.src_addr_width & LDMA_SLAVE_BUSWIDTHS) && in ls2x_dmac_detect_burst()
224 (lchan->sconfig.dst_addr_width & LDMA_SLAVE_BUSWIDTHS)) in ls2x_dmac_detect_burst()
227 if (lchan->sconfig.direction == DMA_MEM_TO_DEV) { in ls2x_dmac_detect_burst()
228 maxburst = lchan->sconfig.dst_maxburst; in ls2x_dmac_detect_burst()
229 buswidth = lchan->sconfig.dst_addr_width; in ls2x_dmac_detect_burst()
231 maxburst = lchan->sconfig.src_maxburst; in ls2x_dmac_detect_burst()
232 buswidth = lchan->sconfig.src_addr_width; in ls2x_dmac_detect_burst()
242 struct ls2x_dma_sg *ldma_sg = &desc->sg[sg_index]; in ls2x_dma_fill_desc()
245 if (desc->direction == DMA_MEM_TO_DEV) { in ls2x_dma_fill_desc()
246 ldma_sg->hw->cmd = LDMA_INT | LDMA_DATA_DIRECTION; in ls2x_dma_fill_desc()
247 ldma_sg->hw->apb_addr = lchan->sconfig.dst_addr; in ls2x_dma_fill_desc()
249 ldma_sg->hw->cmd = LDMA_INT; in ls2x_dma_fill_desc()
250 ldma_sg->hw->apb_addr = lchan->sconfig.src_addr; in ls2x_dma_fill_desc()
253 ldma_sg->hw->mem_addr = lower_32_bits(ldma_sg->phys); in ls2x_dma_fill_desc()
254 ldma_sg->hw->high_mem_addr = upper_32_bits(ldma_sg->phys); in ls2x_dma_fill_desc()
257 num_segments = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, desc->burst_size); in ls2x_dma_fill_desc()
258 segment_size = DIV_ROUND_UP((ldma_sg->len + 3) >> 2, num_segments); in ls2x_dma_fill_desc()
261 ldma_sg->hw->len = segment_size; in ls2x_dma_fill_desc()
262 ldma_sg->hw->step_times = num_segments; in ls2x_dma_fill_desc()
263 ldma_sg->hw->step_len = 0; in ls2x_dma_fill_desc()
267 desc->sg[sg_index - 1].hw->ndesc_addr = ldma_sg->llp | LDMA_DESC_EN; in ls2x_dma_fill_desc()
268 desc->sg[sg_index - 1].hw->high_ndesc_addr = upper_32_bits(ldma_sg->llp); in ls2x_dma_fill_desc()
272 /*-- DMA Engine API --------------------------------------------------*/
275 * ls2x_dma_alloc_chan_resources - allocate resources for DMA channel
278 * return - the number of allocated descriptors
285 lchan->pool = dma_pool_create(dev_name(chan2dev(chan)), in ls2x_dma_alloc_chan_resources()
286 chan->device->dev, PAGE_SIZE, in ls2x_dma_alloc_chan_resources()
288 if (!lchan->pool) { in ls2x_dma_alloc_chan_resources()
290 return -ENOMEM; in ls2x_dma_alloc_chan_resources()
297 * ls2x_dma_free_chan_resources - free all channel resources
305 dma_pool_destroy(lchan->pool); in ls2x_dma_free_chan_resources()
306 lchan->pool = NULL; in ls2x_dma_free_chan_resources()
310 * ls2x_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
342 desc->desc_num = sg_len; in ls2x_dma_prep_slave_sg()
343 desc->direction = direction; in ls2x_dma_prep_slave_sg()
344 desc->burst_size = burst_size; in ls2x_dma_prep_slave_sg()
347 struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; in ls2x_dma_prep_slave_sg()
350 ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); in ls2x_dma_prep_slave_sg()
351 if (!ldma_sg->hw) { in ls2x_dma_prep_slave_sg()
352 desc->desc_num = i; in ls2x_dma_prep_slave_sg()
353 ls2x_dma_desc_free(&desc->vdesc); in ls2x_dma_prep_slave_sg()
357 ldma_sg->phys = sg_dma_address(sg); in ls2x_dma_prep_slave_sg()
358 ldma_sg->len = sg_dma_len(sg); in ls2x_dma_prep_slave_sg()
364 desc->sg[sg_len - 1].hw->ndesc_addr &= ~LDMA_DESC_EN; in ls2x_dma_prep_slave_sg()
365 desc->status = DMA_IN_PROGRESS; in ls2x_dma_prep_slave_sg()
367 return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); in ls2x_dma_prep_slave_sg()
371 * ls2x_dma_prep_dma_cyclic - prepare the cyclic DMA transfer
407 desc->desc_num = num_periods; in ls2x_dma_prep_dma_cyclic()
408 desc->direction = direction; in ls2x_dma_prep_dma_cyclic()
409 desc->burst_size = burst_size; in ls2x_dma_prep_dma_cyclic()
413 struct ls2x_dma_sg *ldma_sg = &desc->sg[i]; in ls2x_dma_prep_dma_cyclic()
416 ldma_sg->hw = dma_pool_alloc(lchan->pool, GFP_NOWAIT, &ldma_sg->llp); in ls2x_dma_prep_dma_cyclic()
417 if (!ldma_sg->hw) { in ls2x_dma_prep_dma_cyclic()
418 desc->desc_num = i; in ls2x_dma_prep_dma_cyclic()
419 ls2x_dma_desc_free(&desc->vdesc); in ls2x_dma_prep_dma_cyclic()
423 ldma_sg->phys = buf_addr + period_len * i; in ls2x_dma_prep_dma_cyclic()
424 ldma_sg->len = period_len; in ls2x_dma_prep_dma_cyclic()
430 desc->sg[num_periods - 1].hw->ndesc_addr = desc->sg[0].llp | LDMA_DESC_EN; in ls2x_dma_prep_dma_cyclic()
431 desc->sg[num_periods - 1].hw->high_ndesc_addr = upper_32_bits(desc->sg[0].llp); in ls2x_dma_prep_dma_cyclic()
432 desc->cyclic = true; in ls2x_dma_prep_dma_cyclic()
433 desc->status = DMA_IN_PROGRESS; in ls2x_dma_prep_dma_cyclic()
435 return vchan_tx_prep(&lchan->vchan, &desc->vdesc, flags); in ls2x_dma_prep_dma_cyclic()
439 * ls2x_slave_config - set slave configuration for channel
450 memcpy(&lchan->sconfig, config, sizeof(*config)); in ls2x_dma_slave_config()
455 * ls2x_dma_issue_pending - push pending transactions to the hardware
466 spin_lock_irqsave(&lchan->vchan.lock, flags); in ls2x_dma_issue_pending()
467 if (vchan_issue_pending(&lchan->vchan) && !lchan->desc) in ls2x_dma_issue_pending()
469 spin_unlock_irqrestore(&lchan->vchan.lock, flags); in ls2x_dma_issue_pending()
473 * ls2x_dma_terminate_all - terminate all transactions
484 spin_lock_irqsave(&lchan->vchan.lock, flags); in ls2x_dma_terminate_all()
487 if (lchan->desc) { in ls2x_dma_terminate_all()
488 vchan_terminate_vdesc(&lchan->desc->vdesc); in ls2x_dma_terminate_all()
489 lchan->desc = NULL; in ls2x_dma_terminate_all()
492 vchan_get_all_descriptors(&lchan->vchan, &head); in ls2x_dma_terminate_all()
493 spin_unlock_irqrestore(&lchan->vchan.lock, flags); in ls2x_dma_terminate_all()
495 vchan_dma_desc_free_list(&lchan->vchan, &head); in ls2x_dma_terminate_all()
500 * ls2x_dma_synchronize - Synchronizes the termination of transfers to the
508 vchan_synchronize(&lchan->vchan); in ls2x_dma_synchronize()
516 spin_lock_irqsave(&lchan->vchan.lock, flags); in ls2x_dma_pause()
517 if (lchan->desc && lchan->desc->status == DMA_IN_PROGRESS) { in ls2x_dma_pause()
519 lchan->desc->status = DMA_PAUSED; in ls2x_dma_pause()
521 spin_unlock_irqrestore(&lchan->vchan.lock, flags); in ls2x_dma_pause()
531 spin_lock_irqsave(&lchan->vchan.lock, flags); in ls2x_dma_resume()
532 if (lchan->desc && lchan->desc->status == DMA_PAUSED) { in ls2x_dma_resume()
533 lchan->desc->status = DMA_IN_PROGRESS; in ls2x_dma_resume()
536 spin_unlock_irqrestore(&lchan->vchan.lock, flags); in ls2x_dma_resume()
542 * ls2x_dma_isr - LS2X DMA Interrupt handler
553 spin_lock(&lchan->vchan.lock); in ls2x_dma_isr()
554 desc = lchan->desc; in ls2x_dma_isr()
556 if (desc->cyclic) { in ls2x_dma_isr()
557 vchan_cyclic_callback(&desc->vdesc); in ls2x_dma_isr()
559 desc->status = DMA_COMPLETE; in ls2x_dma_isr()
560 vchan_cookie_complete(&desc->vdesc); in ls2x_dma_isr()
564 /* ls2x_dma_start_transfer() updates lchan->desc */ in ls2x_dma_isr()
565 if (!lchan->desc) in ls2x_dma_isr()
568 spin_unlock(&lchan->vchan.lock); in ls2x_dma_isr()
576 struct ls2x_dma_chan *lchan = &priv->lchan; in ls2x_dma_chan_init()
577 struct device *dev = &pdev->dev; in ls2x_dma_chan_init()
580 lchan->irq = platform_get_irq(pdev, 0); in ls2x_dma_chan_init()
581 if (lchan->irq < 0) in ls2x_dma_chan_init()
582 return lchan->irq; in ls2x_dma_chan_init()
584 ret = devm_request_irq(dev, lchan->irq, ls2x_dma_isr, IRQF_TRIGGER_RISING, in ls2x_dma_chan_init()
585 dev_name(&pdev->dev), lchan); in ls2x_dma_chan_init()
590 INIT_LIST_HEAD(&priv->ddev.channels); in ls2x_dma_chan_init()
591 lchan->vchan.desc_free = ls2x_dma_desc_free; in ls2x_dma_chan_init()
592 vchan_init(&lchan->vchan, &priv->ddev); in ls2x_dma_chan_init()
598 * ls2x_dma_probe - Driver probe function
605 struct device *dev = &pdev->dev; in ls2x_dma_probe()
612 return -ENOMEM; in ls2x_dma_probe()
614 priv->regs = devm_platform_ioremap_resource(pdev, 0); in ls2x_dma_probe()
615 if (IS_ERR(priv->regs)) in ls2x_dma_probe()
616 return dev_err_probe(dev, PTR_ERR(priv->regs), in ls2x_dma_probe()
619 priv->dma_clk = devm_clk_get(&pdev->dev, NULL); in ls2x_dma_probe()
620 if (IS_ERR(priv->dma_clk)) in ls2x_dma_probe()
621 return dev_err_probe(dev, PTR_ERR(priv->dma_clk), "devm_clk_get failed.\n"); in ls2x_dma_probe()
623 ret = clk_prepare_enable(priv->dma_clk); in ls2x_dma_probe()
631 ddev = &priv->ddev; in ls2x_dma_probe()
632 ddev->dev = dev; in ls2x_dma_probe()
633 dma_cap_zero(ddev->cap_mask); in ls2x_dma_probe()
634 dma_cap_set(DMA_SLAVE, ddev->cap_mask); in ls2x_dma_probe()
635 dma_cap_set(DMA_CYCLIC, ddev->cap_mask); in ls2x_dma_probe()
637 ddev->device_alloc_chan_resources = ls2x_dma_alloc_chan_resources; in ls2x_dma_probe()
638 ddev->device_free_chan_resources = ls2x_dma_free_chan_resources; in ls2x_dma_probe()
639 ddev->device_tx_status = dma_cookie_status; in ls2x_dma_probe()
640 ddev->device_issue_pending = ls2x_dma_issue_pending; in ls2x_dma_probe()
641 ddev->device_prep_slave_sg = ls2x_dma_prep_slave_sg; in ls2x_dma_probe()
642 ddev->device_prep_dma_cyclic = ls2x_dma_prep_dma_cyclic; in ls2x_dma_probe()
643 ddev->device_config = ls2x_dma_slave_config; in ls2x_dma_probe()
644 ddev->device_terminate_all = ls2x_dma_terminate_all; in ls2x_dma_probe()
645 ddev->device_synchronize = ls2x_dma_synchronize; in ls2x_dma_probe()
646 ddev->device_pause = ls2x_dma_pause; in ls2x_dma_probe()
647 ddev->device_resume = ls2x_dma_resume; in ls2x_dma_probe()
649 ddev->src_addr_widths = LDMA_SLAVE_BUSWIDTHS; in ls2x_dma_probe()
650 ddev->dst_addr_widths = LDMA_SLAVE_BUSWIDTHS; in ls2x_dma_probe()
651 ddev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); in ls2x_dma_probe()
653 ret = dma_async_device_register(&priv->ddev); in ls2x_dma_probe()
657 ret = of_dma_controller_register(dev->of_node, of_dma_xlate_by_chan_id, priv); in ls2x_dma_probe()
667 dma_async_device_unregister(&priv->ddev); in ls2x_dma_probe()
669 clk_disable_unprepare(priv->dma_clk); in ls2x_dma_probe()
675 * ls2x_dma_remove - Driver remove function
682 of_dma_controller_free(pdev->dev.of_node); in ls2x_dma_remove()
683 dma_async_device_unregister(&priv->ddev); in ls2x_dma_remove()
684 clk_disable_unprepare(priv->dma_clk); in ls2x_dma_remove()
688 { .compatible = "loongson,ls2k1000-apbdma" },
697 .name = "ls2x-apbdma",