162306a36Sopenharmony_ci.. SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci 362306a36Sopenharmony_ci======================= 462306a36Sopenharmony_ciSTM32 DMA-MDMA chaining 562306a36Sopenharmony_ci======================= 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 862306a36Sopenharmony_ciIntroduction 962306a36Sopenharmony_ci------------ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci This document describes the STM32 DMA-MDMA chaining feature. But before going 1262306a36Sopenharmony_ci further, let's introduce the peripherals involved. 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci To offload data transfers from the CPU, STM32 microprocessors (MPUs) embed 1562306a36Sopenharmony_ci direct memory access controllers (DMA). 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci STM32MP1 SoCs embed both STM32 DMA and STM32 MDMA controllers. STM32 DMA 1862306a36Sopenharmony_ci request routing capabilities are enhanced by a DMA request multiplexer 1962306a36Sopenharmony_ci (STM32 DMAMUX). 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci **STM32 DMAMUX** 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci STM32 DMAMUX routes any DMA request from a given peripheral to any STM32 DMA 2462306a36Sopenharmony_ci controller (STM32MP1 counts two STM32 DMA controllers) channels. 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci **STM32 DMA** 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci STM32 DMA is mainly used to implement central data buffer storage (usually in 2962306a36Sopenharmony_ci the system SRAM) for different peripheral. It can access external RAMs but 3062306a36Sopenharmony_ci without the ability to generate convenient burst transfer ensuring the best 3162306a36Sopenharmony_ci load of the AXI. 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci **STM32 MDMA** 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci STM32 MDMA (Master DMA) is mainly used to manage direct data transfers between 3662306a36Sopenharmony_ci RAM data buffers without CPU intervention. It can also be used in a 3762306a36Sopenharmony_ci hierarchical structure that uses STM32 DMA as first level data buffer 3862306a36Sopenharmony_ci interfaces for AHB peripherals, while the STM32 MDMA acts as a second level 3962306a36Sopenharmony_ci DMA with better performance. As a AXI/AHB master, STM32 MDMA can take control 4062306a36Sopenharmony_ci of the AXI/AHB bus. 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciPrinciples 4462306a36Sopenharmony_ci---------- 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci STM32 DMA-MDMA chaining feature relies on the strengths of STM32 DMA and 4762306a36Sopenharmony_ci STM32 MDMA controllers. 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci STM32 DMA has a circular Double Buffer Mode (DBM). At each end of transaction 5062306a36Sopenharmony_ci (when DMA data counter - DMA_SxNDTR - reaches 0), the memory pointers 5162306a36Sopenharmony_ci (configured with DMA_SxSM0AR and DMA_SxM1AR) are swapped and the DMA data 5262306a36Sopenharmony_ci counter is automatically reloaded. This allows the SW or the STM32 MDMA to 5362306a36Sopenharmony_ci process one memory area while the second memory area is being filled/used by 5462306a36Sopenharmony_ci the STM32 DMA transfer. 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci With STM32 MDMA linked-list mode, a single request initiates the data array 5762306a36Sopenharmony_ci (collection of nodes) to be transferred until the linked-list pointer for the 5862306a36Sopenharmony_ci channel is null. The channel transfer complete of the last node is the end of 5962306a36Sopenharmony_ci transfer, unless first and last nodes are linked to each other, in such a 6062306a36Sopenharmony_ci case, the linked-list loops on to create a circular MDMA transfer. 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci STM32 MDMA has direct connections with STM32 DMA. This enables autonomous 6362306a36Sopenharmony_ci communication and synchronization between peripherals, thus saving CPU 6462306a36Sopenharmony_ci resources and bus congestion. Transfer Complete signal of STM32 DMA channel 6562306a36Sopenharmony_ci can triggers STM32 MDMA transfer. STM32 MDMA can clear the request generated 6662306a36Sopenharmony_ci by the STM32 DMA by writing to its Interrupt Clear register (whose address is 6762306a36Sopenharmony_ci stored in MDMA_CxMAR, and bit mask in MDMA_CxMDR). 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci .. table:: STM32 MDMA interconnect table with STM32 DMA 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 7262306a36Sopenharmony_ci | STM32 DMAMUX | STM32 DMA | STM32 DMA | STM32 MDMA | 7362306a36Sopenharmony_ci | channels | channels | Transfer | request | 7462306a36Sopenharmony_ci | | | complete | | 7562306a36Sopenharmony_ci | | | signal | | 7662306a36Sopenharmony_ci +==============+================+===========+============+ 7762306a36Sopenharmony_ci | Channel *0* | DMA1 channel 0 | dma1_tcf0 | *0x00* | 7862306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 7962306a36Sopenharmony_ci | Channel *1* | DMA1 channel 1 | dma1_tcf1 | *0x01* | 8062306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 8162306a36Sopenharmony_ci | Channel *2* | DMA1 channel 2 | dma1_tcf2 | *0x02* | 8262306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 8362306a36Sopenharmony_ci | Channel *3* | DMA1 channel 3 | dma1_tcf3 | *0x03* | 8462306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 8562306a36Sopenharmony_ci | Channel *4* | DMA1 channel 4 | dma1_tcf4 | *0x04* | 8662306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 8762306a36Sopenharmony_ci | Channel *5* | DMA1 channel 5 | dma1_tcf5 | *0x05* | 8862306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 8962306a36Sopenharmony_ci | Channel *6* | DMA1 channel 6 | dma1_tcf6 | *0x06* | 9062306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 9162306a36Sopenharmony_ci | Channel *7* | DMA1 channel 7 | dma1_tcf7 | *0x07* | 9262306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 9362306a36Sopenharmony_ci | Channel *8* | DMA2 channel 0 | dma2_tcf0 | *0x08* | 9462306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 9562306a36Sopenharmony_ci | Channel *9* | DMA2 channel 1 | dma2_tcf1 | *0x09* | 9662306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 9762306a36Sopenharmony_ci | Channel *10* | DMA2 channel 2 | dma2_tcf2 | *0x0A* | 9862306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 9962306a36Sopenharmony_ci | Channel *11* | DMA2 channel 3 | dma2_tcf3 | *0x0B* | 10062306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 10162306a36Sopenharmony_ci | Channel *12* | DMA2 channel 4 | dma2_tcf4 | *0x0C* | 10262306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 10362306a36Sopenharmony_ci | Channel *13* | DMA2 channel 5 | dma2_tcf5 | *0x0D* | 10462306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 10562306a36Sopenharmony_ci | Channel *14* | DMA2 channel 6 | dma2_tcf6 | *0x0E* | 10662306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 10762306a36Sopenharmony_ci | Channel *15* | DMA2 channel 7 | dma2_tcf7 | *0x0F* | 10862306a36Sopenharmony_ci +--------------+----------------+-----------+------------+ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci STM32 DMA-MDMA chaining feature then uses a SRAM buffer. STM32MP1 SoCs embed 11162306a36Sopenharmony_ci three fast access static internal RAMs of various size, used for data storage. 11262306a36Sopenharmony_ci Due to STM32 DMA legacy (within microcontrollers), STM32 DMA performances are 11362306a36Sopenharmony_ci bad with DDR, while they are optimal with SRAM. Hence the SRAM buffer used 11462306a36Sopenharmony_ci between STM32 DMA and STM32 MDMA. This buffer is split in two equal periods 11562306a36Sopenharmony_ci and STM32 DMA uses one period while STM32 MDMA uses the other period 11662306a36Sopenharmony_ci simultaneously. 11762306a36Sopenharmony_ci :: 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci dma[1:2]-tcf[0:7] 12062306a36Sopenharmony_ci .----------------. 12162306a36Sopenharmony_ci ____________ ' _________ V____________ 12262306a36Sopenharmony_ci | STM32 DMA | / __|>_ \ | STM32 MDMA | 12362306a36Sopenharmony_ci |------------| | / \ | |------------| 12462306a36Sopenharmony_ci | DMA_SxM0AR |<=>| | SRAM | |<=>| []-[]...[] | 12562306a36Sopenharmony_ci | DMA_SxM1AR | | \_____/ | | | 12662306a36Sopenharmony_ci |____________| \___<|____/ |____________| 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci STM32 DMA-MDMA chaining uses (struct dma_slave_config).peripheral_config to 12962306a36Sopenharmony_ci exchange the parameters needed to configure MDMA. These parameters are 13062306a36Sopenharmony_ci gathered into a u32 array with three values: 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci * the STM32 MDMA request (which is actually the DMAMUX channel ID), 13362306a36Sopenharmony_ci * the address of the STM32 DMA register to clear the Transfer Complete 13462306a36Sopenharmony_ci interrupt flag, 13562306a36Sopenharmony_ci * the mask of the Transfer Complete interrupt flag of the STM32 DMA channel. 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciDevice Tree updates for STM32 DMA-MDMA chaining support 13862306a36Sopenharmony_ci------------------------------------------------------- 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci **1. Allocate a SRAM buffer** 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci SRAM device tree node is defined in SoC device tree. You can refer to it in 14362306a36Sopenharmony_ci your board device tree to define your SRAM pool. 14462306a36Sopenharmony_ci :: 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci &sram { 14762306a36Sopenharmony_ci my_foo_device_dma_pool: dma-sram@0 { 14862306a36Sopenharmony_ci reg = <0x0 0x1000>; 14962306a36Sopenharmony_ci }; 15062306a36Sopenharmony_ci }; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci Be careful of the start index, in case there are other SRAM consumers. 15362306a36Sopenharmony_ci Define your pool size strategically: to optimise chaining, the idea is that 15462306a36Sopenharmony_ci STM32 DMA and STM32 MDMA can work simultaneously, on each buffer of the 15562306a36Sopenharmony_ci SRAM. 15662306a36Sopenharmony_ci If the SRAM period is greater than the expected DMA transfer, then STM32 DMA 15762306a36Sopenharmony_ci and STM32 MDMA will work sequentially instead of simultaneously. It is not a 15862306a36Sopenharmony_ci functional issue but it is not optimal. 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci Don't forget to refer to your SRAM pool in your device node. You need to 16162306a36Sopenharmony_ci define a new property. 16262306a36Sopenharmony_ci :: 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci &my_foo_device { 16562306a36Sopenharmony_ci ... 16662306a36Sopenharmony_ci my_dma_pool = &my_foo_device_dma_pool; 16762306a36Sopenharmony_ci }; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci Then get this SRAM pool in your foo driver and allocate your SRAM buffer. 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci **2. Allocate a STM32 DMA channel and a STM32 MDMA channel** 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci You need to define an extra channel in your device tree node, in addition to 17462306a36Sopenharmony_ci the one you should already have for "classic" DMA operation. 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci This new channel must be taken from STM32 MDMA channels, so, the phandle of 17762306a36Sopenharmony_ci the DMA controller to use is the MDMA controller's one. 17862306a36Sopenharmony_ci :: 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci &my_foo_device { 18162306a36Sopenharmony_ci [...] 18262306a36Sopenharmony_ci my_dma_pool = &my_foo_device_dma_pool; 18362306a36Sopenharmony_ci dmas = <&dmamux1 ...>, // STM32 DMA channel 18462306a36Sopenharmony_ci <&mdma1 0 0x3 0x1200000a 0 0>; // + STM32 MDMA channel 18562306a36Sopenharmony_ci }; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci Concerning STM32 MDMA bindings: 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci 1. The request line number : whatever the value here, it will be overwritten 19062306a36Sopenharmony_ci by MDMA driver with the STM32 DMAMUX channel ID passed through 19162306a36Sopenharmony_ci (struct dma_slave_config).peripheral_config 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci 2. The priority level : choose Very High (0x3) so that your channel will 19462306a36Sopenharmony_ci take priority other the other during request arbitration 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci 3. A 32bit mask specifying the DMA channel configuration : source and 19762306a36Sopenharmony_ci destination address increment, block transfer with 128 bytes per single 19862306a36Sopenharmony_ci transfer 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci 4. The 32bit value specifying the register to be used to acknowledge the 20162306a36Sopenharmony_ci request: it will be overwritten by MDMA driver, with the DMA channel 20262306a36Sopenharmony_ci interrupt flag clear register address passed through 20362306a36Sopenharmony_ci (struct dma_slave_config).peripheral_config 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci 5. The 32bit mask specifying the value to be written to acknowledge the 20662306a36Sopenharmony_ci request: it will be overwritten by MDMA driver, with the DMA channel 20762306a36Sopenharmony_ci Transfer Complete flag passed through 20862306a36Sopenharmony_ci (struct dma_slave_config).peripheral_config 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ciDriver updates for STM32 DMA-MDMA chaining support in foo driver 21162306a36Sopenharmony_ci---------------------------------------------------------------- 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci **0. (optional) Refactor the original sg_table if dmaengine_prep_slave_sg()** 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci In case of dmaengine_prep_slave_sg(), the original sg_table can't be used as 21662306a36Sopenharmony_ci is. Two new sg_tables must be created from the original one. One for 21762306a36Sopenharmony_ci STM32 DMA transfer (where memory address targets now the SRAM buffer instead 21862306a36Sopenharmony_ci of DDR buffer) and one for STM32 MDMA transfer (where memory address targets 21962306a36Sopenharmony_ci the DDR buffer). 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci The new sg_list items must fit SRAM period length. Here is an example for 22262306a36Sopenharmony_ci DMA_DEV_TO_MEM: 22362306a36Sopenharmony_ci :: 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Assuming sgl and nents, respectively the initial scatterlist and its 22762306a36Sopenharmony_ci * length. 22862306a36Sopenharmony_ci * Assuming sram_dma_buf and sram_period, respectively the memory 22962306a36Sopenharmony_ci * allocated from the pool for DMA usage, and the length of the period, 23062306a36Sopenharmony_ci * which is half of the sram_buf size. 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci struct sg_table new_dma_sgt, new_mdma_sgt; 23362306a36Sopenharmony_ci struct scatterlist *s, *_sgl; 23462306a36Sopenharmony_ci dma_addr_t ddr_dma_buf; 23562306a36Sopenharmony_ci u32 new_nents = 0, len; 23662306a36Sopenharmony_ci int i; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Count the number of entries needed */ 23962306a36Sopenharmony_ci for_each_sg(sgl, s, nents, i) 24062306a36Sopenharmony_ci if (sg_dma_len(s) > sram_period) 24162306a36Sopenharmony_ci new_nents += DIV_ROUND_UP(sg_dma_len(s), sram_period); 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci new_nents++; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci /* Create sg table for STM32 DMA channel */ 24662306a36Sopenharmony_ci ret = sg_alloc_table(&new_dma_sgt, new_nents, GFP_ATOMIC); 24762306a36Sopenharmony_ci if (ret) 24862306a36Sopenharmony_ci dev_err(dev, "DMA sg table alloc failed\n"); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci for_each_sg(new_dma_sgt.sgl, s, new_dma_sgt.nents, i) { 25162306a36Sopenharmony_ci _sgl = sgl; 25262306a36Sopenharmony_ci sg_dma_len(s) = min(sg_dma_len(_sgl), sram_period); 25362306a36Sopenharmony_ci /* Targets the beginning = first half of the sram_buf */ 25462306a36Sopenharmony_ci s->dma_address = sram_buf; 25562306a36Sopenharmony_ci /* 25662306a36Sopenharmony_ci * Targets the second half of the sram_buf 25762306a36Sopenharmony_ci * for odd indexes of the item of the sg_list 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci if (i & 1) 26062306a36Sopenharmony_ci s->dma_address += sram_period; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Create sg table for STM32 MDMA channel */ 26462306a36Sopenharmony_ci ret = sg_alloc_table(&new_mdma_sgt, new_nents, GFP_ATOMIC); 26562306a36Sopenharmony_ci if (ret) 26662306a36Sopenharmony_ci dev_err(dev, "MDMA sg_table alloc failed\n"); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci _sgl = sgl; 26962306a36Sopenharmony_ci len = sg_dma_len(sgl); 27062306a36Sopenharmony_ci ddr_dma_buf = sg_dma_address(sgl); 27162306a36Sopenharmony_ci for_each_sg(mdma_sgt.sgl, s, mdma_sgt.nents, i) { 27262306a36Sopenharmony_ci size_t bytes = min_t(size_t, len, sram_period); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci sg_dma_len(s) = bytes; 27562306a36Sopenharmony_ci sg_dma_address(s) = ddr_dma_buf; 27662306a36Sopenharmony_ci len -= bytes; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!len && sg_next(_sgl)) { 27962306a36Sopenharmony_ci _sgl = sg_next(_sgl); 28062306a36Sopenharmony_ci len = sg_dma_len(_sgl); 28162306a36Sopenharmony_ci ddr_dma_buf = sg_dma_address(_sgl); 28262306a36Sopenharmony_ci } else { 28362306a36Sopenharmony_ci ddr_dma_buf += bytes; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci Don't forget to release these new sg_tables after getting the descriptors 28862306a36Sopenharmony_ci with dmaengine_prep_slave_sg(). 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci **1. Set controller specific parameters** 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci First, use dmaengine_slave_config() with a struct dma_slave_config to 29362306a36Sopenharmony_ci configure STM32 DMA channel. You just have to take care of DMA addresses, 29462306a36Sopenharmony_ci the memory address (depending on the transfer direction) must point on your 29562306a36Sopenharmony_ci SRAM buffer, and set (struct dma_slave_config).peripheral_size != 0. 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci STM32 DMA driver will check (struct dma_slave_config).peripheral_size to 29862306a36Sopenharmony_ci determine if chaining is being used or not. If it is used, then STM32 DMA 29962306a36Sopenharmony_ci driver fills (struct dma_slave_config).peripheral_config with an array of 30062306a36Sopenharmony_ci three u32 : the first one containing STM32 DMAMUX channel ID, the second one 30162306a36Sopenharmony_ci the channel interrupt flag clear register address, and the third one the 30262306a36Sopenharmony_ci channel Transfer Complete flag mask. 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci Then, use dmaengine_slave_config with another struct dma_slave_config to 30562306a36Sopenharmony_ci configure STM32 MDMA channel. Take care of DMA addresses, the device address 30662306a36Sopenharmony_ci (depending on the transfer direction) must point on your SRAM buffer, and 30762306a36Sopenharmony_ci the memory address must point to the buffer originally used for "classic" 30862306a36Sopenharmony_ci DMA operation. Use the previous (struct dma_slave_config).peripheral_size 30962306a36Sopenharmony_ci and .peripheral_config that have been updated by STM32 DMA driver, to set 31062306a36Sopenharmony_ci (struct dma_slave_config).peripheral_size and .peripheral_config of the 31162306a36Sopenharmony_ci struct dma_slave_config to configure STM32 MDMA channel. 31262306a36Sopenharmony_ci :: 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci struct dma_slave_config dma_conf; 31562306a36Sopenharmony_ci struct dma_slave_config mdma_conf; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci memset(&dma_conf, 0, sizeof(dma_conf)); 31862306a36Sopenharmony_ci [...] 31962306a36Sopenharmony_ci config.direction = DMA_DEV_TO_MEM; 32062306a36Sopenharmony_ci config.dst_addr = sram_dma_buf; // SRAM buffer 32162306a36Sopenharmony_ci config.peripheral_size = 1; // peripheral_size != 0 => chaining 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci dmaengine_slave_config(dma_chan, &dma_config); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci memset(&mdma_conf, 0, sizeof(mdma_conf)); 32662306a36Sopenharmony_ci config.direction = DMA_DEV_TO_MEM; 32762306a36Sopenharmony_ci mdma_conf.src_addr = sram_dma_buf; // SRAM buffer 32862306a36Sopenharmony_ci mdma_conf.dst_addr = rx_dma_buf; // original memory buffer 32962306a36Sopenharmony_ci mdma_conf.peripheral_size = dma_conf.peripheral_size; // <- dma_conf 33062306a36Sopenharmony_ci mdma_conf.peripheral_config = dma_config.peripheral_config; // <- dma_conf 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci dmaengine_slave_config(mdma_chan, &mdma_conf); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci **2. Get a descriptor for STM32 DMA channel transaction** 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci In the same way you get your descriptor for your "classic" DMA operation, 33762306a36Sopenharmony_ci you just have to replace the original sg_list (in case of 33862306a36Sopenharmony_ci dmaengine_prep_slave_sg()) with the new sg_list using SRAM buffer, or to 33962306a36Sopenharmony_ci replace the original buffer address, length and period (in case of 34062306a36Sopenharmony_ci dmaengine_prep_dma_cyclic()) with the new SRAM buffer. 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci **3. Get a descriptor for STM32 MDMA channel transaction** 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci If you previously get descriptor (for STM32 DMA) with 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci * dmaengine_prep_slave_sg(), then use dmaengine_prep_slave_sg() for 34762306a36Sopenharmony_ci STM32 MDMA; 34862306a36Sopenharmony_ci * dmaengine_prep_dma_cyclic(), then use dmaengine_prep_dma_cyclic() for 34962306a36Sopenharmony_ci STM32 MDMA. 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci Use the new sg_list using SRAM buffer (in case of dmaengine_prep_slave_sg()) 35262306a36Sopenharmony_ci or, depending on the transfer direction, either the original DDR buffer (in 35362306a36Sopenharmony_ci case of DMA_DEV_TO_MEM) or the SRAM buffer (in case of DMA_MEM_TO_DEV), the 35462306a36Sopenharmony_ci source address being previously set with dmaengine_slave_config(). 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci **4. Submit both transactions** 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci Before submitting your transactions, you may need to define on which 35962306a36Sopenharmony_ci descriptor you want a callback to be called at the end of the transfer 36062306a36Sopenharmony_ci (dmaengine_prep_slave_sg()) or the period (dmaengine_prep_dma_cyclic()). 36162306a36Sopenharmony_ci Depending on the direction, set the callback on the descriptor that finishes 36262306a36Sopenharmony_ci the overal transfer: 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci * DMA_DEV_TO_MEM: set the callback on the "MDMA" descriptor 36562306a36Sopenharmony_ci * DMA_MEM_TO_DEV: set the callback on the "DMA" descriptor 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci Then, submit the descriptors whatever the order, with dmaengine_tx_submit(). 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci **5. Issue pending requests (and wait for callback notification)** 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci As STM32 MDMA channel transfer is triggered by STM32 DMA, you must issue 37262306a36Sopenharmony_ci STM32 MDMA channel before STM32 DMA channel. 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci If any, your callback will be called to warn you about the end of the overal 37562306a36Sopenharmony_ci transfer or the period completion. 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci Don't forget to terminate both channels. STM32 DMA channel is configured in 37862306a36Sopenharmony_ci cyclic Double-Buffer mode so it won't be disabled by HW, you need to terminate 37962306a36Sopenharmony_ci it. STM32 MDMA channel will be stopped by HW in case of sg transfer, but not 38062306a36Sopenharmony_ci in case of cyclic transfer. You can terminate it whatever the kind of transfer. 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci **STM32 DMA-MDMA chaining DMA_MEM_TO_DEV special case** 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci STM32 DMA-MDMA chaining in DMA_MEM_TO_DEV is a special case. Indeed, the 38562306a36Sopenharmony_ci STM32 MDMA feeds the SRAM buffer with the DDR data, and the STM32 DMA reads 38662306a36Sopenharmony_ci data from SRAM buffer. So some data (the first period) have to be copied in 38762306a36Sopenharmony_ci SRAM buffer when the STM32 DMA starts to read. 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci A trick could be pausing the STM32 DMA channel (that will raise a Transfer 39062306a36Sopenharmony_ci Complete signal, triggering the STM32 MDMA channel), but the first data read 39162306a36Sopenharmony_ci by the STM32 DMA could be "wrong". The proper way is to prepare the first SRAM 39262306a36Sopenharmony_ci period with dmaengine_prep_dma_memcpy(). Then this first period should be 39362306a36Sopenharmony_ci "removed" from the sg or the cyclic transfer. 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci Due to this complexity, rather use the STM32 DMA-MDMA chaining for 39662306a36Sopenharmony_ci DMA_DEV_TO_MEM and keep the "classic" DMA usage for DMA_MEM_TO_DEV, unless 39762306a36Sopenharmony_ci you're not afraid. 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ciResources 40062306a36Sopenharmony_ci--------- 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci Application note, datasheet and reference manual are available on ST website 40362306a36Sopenharmony_ci (STM32MP1_). 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci Dedicated focus on three application notes (AN5224_, AN4031_ & AN5001_) 40662306a36Sopenharmony_ci dealing with STM32 DMAMUX, STM32 DMA and STM32 MDMA. 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci.. _STM32MP1: https://www.st.com/en/microcontrollers-microprocessors/stm32mp1-series.html 40962306a36Sopenharmony_ci.. _AN5224: https://www.st.com/resource/en/application_note/an5224-stm32-dmamux-the-dma-request-router-stmicroelectronics.pdf 41062306a36Sopenharmony_ci.. _AN4031: https://www.st.com/resource/en/application_note/dm00046011-using-the-stm32f2-stm32f4-and-stm32f7-series-dma-controller-stmicroelectronics.pdf 41162306a36Sopenharmony_ci.. _AN5001: https://www.st.com/resource/en/application_note/an5001-stm32cube-expansion-package-for-stm32h7-series-mdma-stmicroelectronics.pdf 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci:Authors: 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci- Amelie Delaunay <amelie.delaunay@foss.st.com>