• Home
  • Raw
  • Download

Lines Matching +full:imx28 +full:- +full:dma +full:- +full:apbh

1 // SPDX-License-Identifier: GPL-2.0
5 // Refer to drivers/dma/imx-sdma.c
16 #include <linux/dma-mapping.h>
27 #include <linux/dma/mxs-dma.h>
34 * NOTE: The term "PIO" throughout the mxs-dma implementation means
35 * PIO mode of mxs apbh-dma and apbx-dma. With this working mode,
36 * dma can program the controller registers of peripheral devices.
39 #define dma_is_apbh(mxs_dma) ((mxs_dma)->type == MXS_DMA_APBH)
40 #define apbh_is_old(mxs_dma) ((mxs_dma)->dev_id == IMX23_DMA)
51 * The offset of NXTCMDAR register is different per both dma type and version,
68 * NAND_LOCK: 4 (1) - not implemented
69 * NAND_WAIT4READY: 5 (1) - not implemented
171 { .compatible = "fsl,imx23-dma-apbh", .data = &mxs_dma_types[0], },
172 { .compatible = "fsl,imx23-dma-apbx", .data = &mxs_dma_types[1], },
173 { .compatible = "fsl,imx28-dma-apbh", .data = &mxs_dma_types[2], },
174 { .compatible = "fsl,imx28-dma-apbx", .data = &mxs_dma_types[3], },
187 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_reset_chan()
188 int chan_id = mxs_chan->chan.chan_id; in mxs_dma_reset_chan()
191 * mxs dma channel resets can cause a channel stall. To recover from a in mxs_dma_reset_chan()
192 * channel stall, we have to reset the whole DMA engine. To avoid this, in mxs_dma_reset_chan()
193 * we use cyclic DMA with semaphores, that are enhanced in in mxs_dma_reset_chan()
197 if (mxs_chan->flags & MXS_DMA_USE_SEMAPHORE && in mxs_dma_reset_chan()
198 mxs_chan->flags & MXS_DMA_SG_LOOP) { in mxs_dma_reset_chan()
199 mxs_chan->reset = true; in mxs_dma_reset_chan()
202 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET); in mxs_dma_reset_chan()
206 void __iomem *reg_dbg1 = mxs_dma->base + in mxs_dma_reset_chan()
210 * On i.MX28 APBX, the DMA channel can stop working if we reset in mxs_dma_reset_chan()
222 dev_err(&mxs_chan->mxs_dma->pdev->dev, in mxs_dma_reset_chan()
223 …"Failed waiting for the DMA channel %d to leave state READ_FLUSH, trying to reset channel in READ_… in mxs_dma_reset_chan()
227 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET); in mxs_dma_reset_chan()
230 mxs_chan->status = DMA_COMPLETE; in mxs_dma_reset_chan()
236 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_enable_chan()
237 int chan_id = mxs_chan->chan.chan_id; in mxs_dma_enable_chan()
240 writel(mxs_chan->ccw_phys, in mxs_dma_enable_chan()
241 mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(mxs_dma, chan_id)); in mxs_dma_enable_chan()
244 if (mxs_chan->flags & MXS_DMA_USE_SEMAPHORE && in mxs_dma_enable_chan()
245 mxs_chan->flags & MXS_DMA_SG_LOOP) { in mxs_dma_enable_chan()
246 /* A cyclic DMA consists of at least 2 segments, so initialize in mxs_dma_enable_chan()
249 writel(2, mxs_dma->base + HW_APBHX_CHn_SEMA(mxs_dma, chan_id)); in mxs_dma_enable_chan()
251 writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(mxs_dma, chan_id)); in mxs_dma_enable_chan()
253 mxs_chan->reset = false; in mxs_dma_enable_chan()
260 mxs_chan->status = DMA_COMPLETE; in mxs_dma_disable_chan()
266 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_pause_chan()
267 int chan_id = mxs_chan->chan.chan_id; in mxs_dma_pause_chan()
272 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET); in mxs_dma_pause_chan()
275 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET); in mxs_dma_pause_chan()
277 mxs_chan->status = DMA_PAUSED; in mxs_dma_pause_chan()
284 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_resume_chan()
285 int chan_id = mxs_chan->chan.chan_id; in mxs_dma_resume_chan()
290 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_CLR); in mxs_dma_resume_chan()
293 mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_CLR); in mxs_dma_resume_chan()
295 mxs_chan->status = DMA_IN_PROGRESS; in mxs_dma_resume_chan()
308 dmaengine_desc_get_callback_invoke(&mxs_chan->desc, NULL); in mxs_dma_tasklet()
315 for (i = 0; i != mxs_dma->nr_channels; ++i) in mxs_dma_irq_to_chan()
316 if (mxs_dma->mxs_chans[i].chan_irq == irq) in mxs_dma_irq_to_chan()
319 return -EINVAL; in mxs_dma_irq_to_chan()
334 completed = readl(mxs_dma->base + HW_APBHX_CTRL1); in mxs_dma_int_handler()
339 mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_CLR); in mxs_dma_int_handler()
342 err = readl(mxs_dma->base + HW_APBHX_CTRL2); in mxs_dma_int_handler()
354 mxs_dma->base + HW_APBHX_CTRL2 + STMP_OFFSET_REG_CLR); in mxs_dma_int_handler()
363 err -= err & completed; in mxs_dma_int_handler()
365 mxs_chan = &mxs_dma->mxs_chans[chan]; in mxs_dma_int_handler()
368 dev_dbg(mxs_dma->dma_device.dev, in mxs_dma_int_handler()
371 mxs_chan->status = DMA_ERROR; in mxs_dma_int_handler()
372 mxs_dma_reset_chan(&mxs_chan->chan); in mxs_dma_int_handler()
373 } else if (mxs_chan->status != DMA_COMPLETE) { in mxs_dma_int_handler()
374 if (mxs_chan->flags & MXS_DMA_SG_LOOP) { in mxs_dma_int_handler()
375 mxs_chan->status = DMA_IN_PROGRESS; in mxs_dma_int_handler()
376 if (mxs_chan->flags & MXS_DMA_USE_SEMAPHORE) in mxs_dma_int_handler()
377 writel(1, mxs_dma->base + in mxs_dma_int_handler()
380 mxs_chan->status = DMA_COMPLETE; in mxs_dma_int_handler()
384 if (mxs_chan->status == DMA_COMPLETE) { in mxs_dma_int_handler()
385 if (mxs_chan->reset) in mxs_dma_int_handler()
387 dma_cookie_complete(&mxs_chan->desc); in mxs_dma_int_handler()
391 tasklet_schedule(&mxs_chan->tasklet); in mxs_dma_int_handler()
399 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_alloc_chan_resources()
402 mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, in mxs_dma_alloc_chan_resources()
404 &mxs_chan->ccw_phys, GFP_KERNEL); in mxs_dma_alloc_chan_resources()
405 if (!mxs_chan->ccw) { in mxs_dma_alloc_chan_resources()
406 ret = -ENOMEM; in mxs_dma_alloc_chan_resources()
410 ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler, in mxs_dma_alloc_chan_resources()
411 0, "mxs-dma", mxs_dma); in mxs_dma_alloc_chan_resources()
415 ret = clk_prepare_enable(mxs_dma->clk); in mxs_dma_alloc_chan_resources()
421 dma_async_tx_descriptor_init(&mxs_chan->desc, chan); in mxs_dma_alloc_chan_resources()
422 mxs_chan->desc.tx_submit = mxs_dma_tx_submit; in mxs_dma_alloc_chan_resources()
425 async_tx_ack(&mxs_chan->desc); in mxs_dma_alloc_chan_resources()
430 free_irq(mxs_chan->chan_irq, mxs_dma); in mxs_dma_alloc_chan_resources()
432 dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE, in mxs_dma_alloc_chan_resources()
433 mxs_chan->ccw, mxs_chan->ccw_phys); in mxs_dma_alloc_chan_resources()
441 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_free_chan_resources()
445 free_irq(mxs_chan->chan_irq, mxs_dma); in mxs_dma_free_chan_resources()
447 dma_free_coherent(mxs_dma->dma_device.dev, CCW_BLOCK_SIZE, in mxs_dma_free_chan_resources()
448 mxs_chan->ccw, mxs_chan->ccw_phys); in mxs_dma_free_chan_resources()
450 clk_disable_unprepare(mxs_dma->clk); in mxs_dma_free_chan_resources()
454 * How to use the flags for ->device_prep_slave_sg() :
455 * [1] If there is only one DMA command in the DMA chain, the code should be:
457 * ->device_prep_slave_sg(DMA_CTRL_ACK);
459 * [2] If there are two DMA commands in the DMA chain, the code should be
461 * ->device_prep_slave_sg(0);
463 * ->device_prep_slave_sg(DMA_CTRL_ACK);
465 * [3] If there are more than two DMA commands in the DMA chain, the code
468 * ->device_prep_slave_sg(0); // First
470 * ->device_prep_slave_sg(DMA_CTRL_ACK]);
472 * ->device_prep_slave_sg(DMA_CTRL_ACK); // Last
481 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_prep_slave_sg()
488 if (mxs_chan->status == DMA_IN_PROGRESS) in mxs_dma_prep_slave_sg()
489 idx = mxs_chan->desc_count; in mxs_dma_prep_slave_sg()
492 dev_err(mxs_dma->dma_device.dev, in mxs_dma_prep_slave_sg()
498 mxs_chan->status = DMA_IN_PROGRESS; in mxs_dma_prep_slave_sg()
499 mxs_chan->flags = 0; in mxs_dma_prep_slave_sg()
507 ccw = &mxs_chan->ccw[idx - 1]; in mxs_dma_prep_slave_sg()
508 ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx; in mxs_dma_prep_slave_sg()
509 ccw->bits |= CCW_CHAIN; in mxs_dma_prep_slave_sg()
510 ccw->bits &= ~CCW_IRQ; in mxs_dma_prep_slave_sg()
511 ccw->bits &= ~CCW_DEC_SEM; in mxs_dma_prep_slave_sg()
517 ccw = &mxs_chan->ccw[idx++]; in mxs_dma_prep_slave_sg()
521 ccw->pio_words[j++] = *pio++; in mxs_dma_prep_slave_sg()
523 ccw->bits = 0; in mxs_dma_prep_slave_sg()
524 ccw->bits |= CCW_IRQ; in mxs_dma_prep_slave_sg()
525 ccw->bits |= CCW_DEC_SEM; in mxs_dma_prep_slave_sg()
527 ccw->bits |= CCW_WAIT4END; in mxs_dma_prep_slave_sg()
528 ccw->bits |= CCW_HALT_ON_TERM; in mxs_dma_prep_slave_sg()
529 ccw->bits |= CCW_TERM_FLUSH; in mxs_dma_prep_slave_sg()
530 ccw->bits |= BF_CCW(sg_len, PIO_NUM); in mxs_dma_prep_slave_sg()
531 ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND); in mxs_dma_prep_slave_sg()
533 ccw->bits |= CCW_WAIT4RDY; in mxs_dma_prep_slave_sg()
537 dev_err(mxs_dma->dma_device.dev, "maximum bytes for sg entry exceeded: %d > %d\n", in mxs_dma_prep_slave_sg()
542 ccw = &mxs_chan->ccw[idx++]; in mxs_dma_prep_slave_sg()
544 ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx; in mxs_dma_prep_slave_sg()
545 ccw->bufaddr = sg->dma_address; in mxs_dma_prep_slave_sg()
546 ccw->xfer_bytes = sg_dma_len(sg); in mxs_dma_prep_slave_sg()
548 ccw->bits = 0; in mxs_dma_prep_slave_sg()
549 ccw->bits |= CCW_CHAIN; in mxs_dma_prep_slave_sg()
550 ccw->bits |= CCW_HALT_ON_TERM; in mxs_dma_prep_slave_sg()
551 ccw->bits |= CCW_TERM_FLUSH; in mxs_dma_prep_slave_sg()
552 ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ? in mxs_dma_prep_slave_sg()
557 ccw->bits &= ~CCW_CHAIN; in mxs_dma_prep_slave_sg()
558 ccw->bits |= CCW_IRQ; in mxs_dma_prep_slave_sg()
559 ccw->bits |= CCW_DEC_SEM; in mxs_dma_prep_slave_sg()
561 ccw->bits |= CCW_WAIT4END; in mxs_dma_prep_slave_sg()
565 mxs_chan->desc_count = idx; in mxs_dma_prep_slave_sg()
567 return &mxs_chan->desc; in mxs_dma_prep_slave_sg()
570 mxs_chan->status = DMA_ERROR; in mxs_dma_prep_slave_sg()
580 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_prep_dma_cyclic()
584 if (mxs_chan->status == DMA_IN_PROGRESS) in mxs_dma_prep_dma_cyclic()
587 mxs_chan->status = DMA_IN_PROGRESS; in mxs_dma_prep_dma_cyclic()
588 mxs_chan->flags |= MXS_DMA_SG_LOOP; in mxs_dma_prep_dma_cyclic()
589 mxs_chan->flags |= MXS_DMA_USE_SEMAPHORE; in mxs_dma_prep_dma_cyclic()
592 dev_err(mxs_dma->dma_device.dev, in mxs_dma_prep_dma_cyclic()
599 dev_err(mxs_dma->dma_device.dev, in mxs_dma_prep_dma_cyclic()
606 struct mxs_dma_ccw *ccw = &mxs_chan->ccw[i]; in mxs_dma_prep_dma_cyclic()
609 ccw->next = mxs_chan->ccw_phys; in mxs_dma_prep_dma_cyclic()
611 ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * (i + 1); in mxs_dma_prep_dma_cyclic()
613 ccw->bufaddr = dma_addr; in mxs_dma_prep_dma_cyclic()
614 ccw->xfer_bytes = period_len; in mxs_dma_prep_dma_cyclic()
616 ccw->bits = 0; in mxs_dma_prep_dma_cyclic()
617 ccw->bits |= CCW_CHAIN; in mxs_dma_prep_dma_cyclic()
618 ccw->bits |= CCW_IRQ; in mxs_dma_prep_dma_cyclic()
619 ccw->bits |= CCW_HALT_ON_TERM; in mxs_dma_prep_dma_cyclic()
620 ccw->bits |= CCW_TERM_FLUSH; in mxs_dma_prep_dma_cyclic()
621 ccw->bits |= CCW_DEC_SEM; in mxs_dma_prep_dma_cyclic()
622 ccw->bits |= BF_CCW(direction == DMA_DEV_TO_MEM ? in mxs_dma_prep_dma_cyclic()
630 mxs_chan->desc_count = i; in mxs_dma_prep_dma_cyclic()
632 return &mxs_chan->desc; in mxs_dma_prep_dma_cyclic()
635 mxs_chan->status = DMA_ERROR; in mxs_dma_prep_dma_cyclic()
651 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_tx_status()
654 if (mxs_chan->status == DMA_IN_PROGRESS && in mxs_dma_tx_status()
655 mxs_chan->flags & MXS_DMA_SG_LOOP) { in mxs_dma_tx_status()
659 last_ccw = &mxs_chan->ccw[mxs_chan->desc_count - 1]; in mxs_dma_tx_status()
660 residue = last_ccw->xfer_bytes + last_ccw->bufaddr; in mxs_dma_tx_status()
662 bar = readl(mxs_dma->base + in mxs_dma_tx_status()
663 HW_APBHX_CHn_BAR(mxs_dma, chan->chan_id)); in mxs_dma_tx_status()
664 residue -= bar; in mxs_dma_tx_status()
667 dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, in mxs_dma_tx_status()
670 return mxs_chan->status; in mxs_dma_tx_status()
677 ret = clk_prepare_enable(mxs_dma->clk); in mxs_dma_init()
681 ret = stmp_reset_block(mxs_dma->base); in mxs_dma_init()
685 /* enable apbh burst */ in mxs_dma_init()
688 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET); in mxs_dma_init()
690 mxs_dma->base + HW_APBHX_CTRL0 + STMP_OFFSET_REG_SET); in mxs_dma_init()
695 mxs_dma->base + HW_APBHX_CTRL1 + STMP_OFFSET_REG_SET); in mxs_dma_init()
698 clk_disable_unprepare(mxs_dma->clk); in mxs_dma_init()
710 struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma; in mxs_dma_filter_fn()
713 if (chan->chan_id != param->chan_id) in mxs_dma_filter_fn()
716 chan_irq = platform_get_irq(mxs_dma->pdev, param->chan_id); in mxs_dma_filter_fn()
720 mxs_chan->chan_irq = chan_irq; in mxs_dma_filter_fn()
728 struct mxs_dma_engine *mxs_dma = ofdma->of_dma_data; in mxs_dma_xlate()
729 dma_cap_mask_t mask = mxs_dma->dma_device.cap_mask; in mxs_dma_xlate()
732 if (dma_spec->args_count != 1) in mxs_dma_xlate()
735 param.chan_id = dma_spec->args[0]; in mxs_dma_xlate()
737 if (param.chan_id >= mxs_dma->nr_channels) in mxs_dma_xlate()
741 ofdma->of_node); in mxs_dma_xlate()
746 struct device_node *np = pdev->dev.of_node; in mxs_dma_probe()
752 mxs_dma = devm_kzalloc(&pdev->dev, sizeof(*mxs_dma), GFP_KERNEL); in mxs_dma_probe()
754 return -ENOMEM; in mxs_dma_probe()
756 ret = of_property_read_u32(np, "dma-channels", &mxs_dma->nr_channels); in mxs_dma_probe()
758 dev_err(&pdev->dev, "failed to read dma-channels\n"); in mxs_dma_probe()
762 dma_type = (struct mxs_dma_type *)of_device_get_match_data(&pdev->dev); in mxs_dma_probe()
763 mxs_dma->type = dma_type->type; in mxs_dma_probe()
764 mxs_dma->dev_id = dma_type->id; in mxs_dma_probe()
767 mxs_dma->base = devm_ioremap_resource(&pdev->dev, iores); in mxs_dma_probe()
768 if (IS_ERR(mxs_dma->base)) in mxs_dma_probe()
769 return PTR_ERR(mxs_dma->base); in mxs_dma_probe()
771 mxs_dma->clk = devm_clk_get(&pdev->dev, NULL); in mxs_dma_probe()
772 if (IS_ERR(mxs_dma->clk)) in mxs_dma_probe()
773 return PTR_ERR(mxs_dma->clk); in mxs_dma_probe()
775 dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask); in mxs_dma_probe()
776 dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask); in mxs_dma_probe()
778 INIT_LIST_HEAD(&mxs_dma->dma_device.channels); in mxs_dma_probe()
782 struct mxs_dma_chan *mxs_chan = &mxs_dma->mxs_chans[i]; in mxs_dma_probe()
784 mxs_chan->mxs_dma = mxs_dma; in mxs_dma_probe()
785 mxs_chan->chan.device = &mxs_dma->dma_device; in mxs_dma_probe()
786 dma_cookie_init(&mxs_chan->chan); in mxs_dma_probe()
788 tasklet_setup(&mxs_chan->tasklet, mxs_dma_tasklet); in mxs_dma_probe()
792 list_add_tail(&mxs_chan->chan.device_node, in mxs_dma_probe()
793 &mxs_dma->dma_device.channels); in mxs_dma_probe()
800 mxs_dma->pdev = pdev; in mxs_dma_probe()
801 mxs_dma->dma_device.dev = &pdev->dev; in mxs_dma_probe()
804 dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES); in mxs_dma_probe()
806 mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources; in mxs_dma_probe()
807 mxs_dma->dma_device.device_free_chan_resources = mxs_dma_free_chan_resources; in mxs_dma_probe()
808 mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status; in mxs_dma_probe()
809 mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg; in mxs_dma_probe()
810 mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic; in mxs_dma_probe()
811 mxs_dma->dma_device.device_pause = mxs_dma_pause_chan; in mxs_dma_probe()
812 mxs_dma->dma_device.device_resume = mxs_dma_resume_chan; in mxs_dma_probe()
813 mxs_dma->dma_device.device_terminate_all = mxs_dma_terminate_all; in mxs_dma_probe()
814 mxs_dma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); in mxs_dma_probe()
815 mxs_dma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); in mxs_dma_probe()
816 mxs_dma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); in mxs_dma_probe()
817 mxs_dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; in mxs_dma_probe()
818 mxs_dma->dma_device.device_issue_pending = mxs_dma_enable_chan; in mxs_dma_probe()
820 ret = dmaenginem_async_device_register(&mxs_dma->dma_device); in mxs_dma_probe()
822 dev_err(mxs_dma->dma_device.dev, "unable to register\n"); in mxs_dma_probe()
828 dev_err(mxs_dma->dma_device.dev, in mxs_dma_probe()
832 dev_info(mxs_dma->dma_device.dev, "initialized\n"); in mxs_dma_probe()
839 .name = "mxs-dma",