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>