Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

dmaengine: stm32-mdma: add support to be triggered by STM32 DMA

STM32 MDMA can be triggered by STM32 DMA channels transfer complete.

In case of non-null struct dma_slave_config .peripheral_size, it means the
DMA client wants the DMA to trigger the MDMA.

stm32-mdma driver gets the request id, the mask_addr, and the mask_data in
struct stm32_mdma_dma_config passed by DMA with struct dma_slave_config
.peripheral_config/.peripheral_size.

Then, as DMA is configured in Double-Buffer mode, and MDMA channel will
transfer data from/to SRAM to/from DDR, then bursts are optimized.

Signed-off-by: Amelie Delaunay <amelie.delaunay@foss.st.com>
Link: https://lore.kernel.org/r/20220829154646.29867-7-amelie.delaunay@foss.st.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Amelie Delaunay and committed by
Vinod Koul
69687432 72379517

+69 -1
+69 -1
drivers/dma/stm32-mdma.c
··· 199 199 u32 transfer_config; 200 200 u32 mask_addr; 201 201 u32 mask_data; 202 + bool m2m_hw; /* True when MDMA is triggered by STM32 DMA */ 202 203 }; 203 204 204 205 struct stm32_mdma_hwdesc { ··· 226 225 bool cyclic; 227 226 u32 count; 228 227 struct stm32_mdma_desc_node node[]; 228 + }; 229 + 230 + struct stm32_mdma_dma_config { 231 + u32 request; /* STM32 DMA channel stream id, triggering MDMA */ 232 + u32 cmar; /* STM32 DMA interrupt flag clear register address */ 233 + u32 cmdr; /* STM32 DMA Transfer Complete flag */ 229 234 }; 230 235 231 236 struct stm32_mdma_chan { ··· 546 539 dst_addr = chan->dma_config.dst_addr; 547 540 548 541 /* Set device data size */ 542 + if (chan_config->m2m_hw) 543 + dst_addr_width = stm32_mdma_get_max_width(dst_addr, buf_len, 544 + STM32_MDMA_MAX_BUF_LEN); 549 545 dst_bus_width = stm32_mdma_get_width(chan, dst_addr_width); 550 546 if (dst_bus_width < 0) 551 547 return dst_bus_width; 552 548 ctcr &= ~STM32_MDMA_CTCR_DSIZE_MASK; 553 549 ctcr |= STM32_MDMA_CTCR_DSIZE(dst_bus_width); 550 + if (chan_config->m2m_hw) { 551 + ctcr &= ~STM32_MDMA_CTCR_DINCOS_MASK; 552 + ctcr |= STM32_MDMA_CTCR_DINCOS(dst_bus_width); 553 + } 554 554 555 555 /* Set device burst value */ 556 + if (chan_config->m2m_hw) 557 + dst_maxburst = STM32_MDMA_MAX_BUF_LEN / dst_addr_width; 558 + 556 559 dst_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, 557 560 dst_maxburst, 558 561 dst_addr_width); ··· 605 588 src_addr = chan->dma_config.src_addr; 606 589 607 590 /* Set device data size */ 591 + if (chan_config->m2m_hw) 592 + src_addr_width = stm32_mdma_get_max_width(src_addr, buf_len, 593 + STM32_MDMA_MAX_BUF_LEN); 594 + 608 595 src_bus_width = stm32_mdma_get_width(chan, src_addr_width); 609 596 if (src_bus_width < 0) 610 597 return src_bus_width; 611 598 ctcr &= ~STM32_MDMA_CTCR_SSIZE_MASK; 612 599 ctcr |= STM32_MDMA_CTCR_SSIZE(src_bus_width); 600 + if (chan_config->m2m_hw) { 601 + ctcr &= ~STM32_MDMA_CTCR_SINCOS_MASK; 602 + ctcr |= STM32_MDMA_CTCR_SINCOS(src_bus_width); 603 + } 613 604 614 605 /* Set device burst value */ 606 + if (chan_config->m2m_hw) 607 + src_maxburst = STM32_MDMA_MAX_BUF_LEN / src_addr_width; 608 + 615 609 src_best_burst = stm32_mdma_get_best_burst(buf_len, tlen, 616 610 src_maxburst, 617 611 src_addr_width); ··· 730 702 { 731 703 struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); 732 704 struct dma_slave_config *dma_config = &chan->dma_config; 705 + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; 733 706 struct scatterlist *sg; 734 707 dma_addr_t src_addr, dst_addr; 735 - u32 ccr, ctcr, ctbr; 708 + u32 m2m_hw_period, ccr, ctcr, ctbr; 736 709 int i, ret = 0; 710 + 711 + if (chan_config->m2m_hw) 712 + m2m_hw_period = sg_dma_len(sgl); 737 713 738 714 for_each_sg(sgl, sg, sg_len, i) { 739 715 if (sg_dma_len(sg) > STM32_MDMA_MAX_BLOCK_LEN) { ··· 748 716 if (direction == DMA_MEM_TO_DEV) { 749 717 src_addr = sg_dma_address(sg); 750 718 dst_addr = dma_config->dst_addr; 719 + if (chan_config->m2m_hw && (i & 1)) 720 + dst_addr += m2m_hw_period; 751 721 ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, 752 722 &ctcr, &ctbr, src_addr, 753 723 sg_dma_len(sg)); ··· 757 723 src_addr); 758 724 } else { 759 725 src_addr = dma_config->src_addr; 726 + if (chan_config->m2m_hw && (i & 1)) 727 + src_addr += m2m_hw_period; 760 728 dst_addr = sg_dma_address(sg); 761 729 ret = stm32_mdma_set_xfer_param(chan, direction, &ccr, 762 730 &ctcr, &ctbr, dst_addr, ··· 791 755 unsigned long flags, void *context) 792 756 { 793 757 struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); 758 + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; 794 759 struct stm32_mdma_desc *desc; 795 760 int i, ret; 796 761 ··· 814 777 if (ret < 0) 815 778 goto xfer_setup_err; 816 779 780 + /* 781 + * In case of M2M HW transfer triggered by STM32 DMA, we do not have to clear the 782 + * transfer complete flag by hardware in order to let the CPU rearm the STM32 DMA 783 + * with the next sg element and update some data in dmaengine framework. 784 + */ 785 + if (chan_config->m2m_hw && direction == DMA_MEM_TO_DEV) { 786 + struct stm32_mdma_hwdesc *hwdesc; 787 + 788 + for (i = 0; i < sg_len; i++) { 789 + hwdesc = desc->node[i].hwdesc; 790 + hwdesc->cmar = 0; 791 + hwdesc->cmdr = 0; 792 + } 793 + } 794 + 817 795 desc->cyclic = false; 818 796 819 797 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); ··· 850 798 struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); 851 799 struct stm32_mdma_device *dmadev = stm32_mdma_get_dev(chan); 852 800 struct dma_slave_config *dma_config = &chan->dma_config; 801 + struct stm32_mdma_chan_config *chan_config = &chan->chan_config; 853 802 struct stm32_mdma_desc *desc; 854 803 dma_addr_t src_addr, dst_addr; 855 804 u32 ccr, ctcr, ctbr, count; ··· 911 858 if (direction == DMA_MEM_TO_DEV) { 912 859 src_addr = buf_addr + i * period_len; 913 860 dst_addr = dma_config->dst_addr; 861 + if (chan_config->m2m_hw && (i & 1)) 862 + dst_addr += period_len; 914 863 } else { 915 864 src_addr = dma_config->src_addr; 865 + if (chan_config->m2m_hw && (i & 1)) 866 + src_addr += period_len; 916 867 dst_addr = buf_addr + i * period_len; 917 868 } 918 869 ··· 1300 1243 struct stm32_mdma_chan *chan = to_stm32_mdma_chan(c); 1301 1244 1302 1245 memcpy(&chan->dma_config, config, sizeof(*config)); 1246 + 1247 + /* Check if user is requesting STM32 DMA to trigger MDMA */ 1248 + if (config->peripheral_size) { 1249 + struct stm32_mdma_dma_config *mdma_config; 1250 + 1251 + mdma_config = (struct stm32_mdma_dma_config *)chan->dma_config.peripheral_config; 1252 + chan->chan_config.request = mdma_config->request; 1253 + chan->chan_config.mask_addr = mdma_config->cmar; 1254 + chan->chan_config.mask_data = mdma_config->cmdr; 1255 + chan->chan_config.m2m_hw = true; 1256 + } 1303 1257 1304 1258 return 0; 1305 1259 }