@@ -26,6 +26,8 @@ LOG_MODULE_REGISTER(stm32_sdmmc, CONFIG_SDMMC_LOG_LEVEL);
2626#include <zephyr/drivers/dma.h>
2727#include <zephyr/drivers/dma/dma_stm32.h>
2828#include <stm32_ll_dma.h>
29+ /* Uses a shared DMA channel for read & write */
30+ #define STM32_SDMMC_USE_DMA_SHARED DT_INST_DMAS_HAS_NAME(0, txrx)
2931#endif
3032
3133#ifndef MMC_TypeDef
@@ -87,11 +89,16 @@ struct stm32_sdmmc_priv {
8789 const struct reset_dt_spec reset ;
8890
8991#if STM32_SDMMC_USE_DMA
92+ #if STM32_SDMMC_USE_DMA_SHARED
93+ struct sdmmc_dma_stream dma_txrx ;
94+ DMA_HandleTypeDef dma_txrx_handle ;
95+ #else
9096 struct sdmmc_dma_stream dma_rx ;
9197 struct sdmmc_dma_stream dma_tx ;
9298 DMA_HandleTypeDef dma_tx_handle ;
9399 DMA_HandleTypeDef dma_rx_handle ;
94100#endif
101+ #endif /* STM32_SDMMC_USE_DMA */
95102};
96103
97104#ifdef CONFIG_SDMMC_STM32_HWFC
@@ -208,24 +215,45 @@ static int stm32_sdmmc_configure_dma(DMA_HandleTypeDef *handle, struct sdmmc_dma
208215
209216 dma -> cfg .user_data = handle ;
210217
218+ /* Reserve the channel in the DMA subsystem, even though we use the HAL API.
219+ * See the usage of STM32_DMA_HAL_OVERRIDE.
220+ */
211221 ret = dma_config (dma -> dev , dma -> channel , & dma -> cfg );
212222 if (ret != 0 ) {
213223 LOG_ERR ("Failed to conig" );
214224 return ret ;
215225 }
216226
227+ #if DT_HAS_COMPAT_STATUS_OKAY (st_stm32_dma_v1 )
217228 handle -> Instance = __LL_DMA_GET_STREAM_INSTANCE (dma -> reg , dma -> channel_nb );
218229 handle -> Init .Channel = dma -> cfg .dma_slot * DMA_CHANNEL_1 ;
219230 handle -> Init .PeriphInc = DMA_PINC_DISABLE ;
220231 handle -> Init .MemInc = DMA_MINC_ENABLE ;
221232 handle -> Init .PeriphDataAlignment = DMA_PDATAALIGN_WORD ;
222233 handle -> Init .MemDataAlignment = DMA_MDATAALIGN_WORD ;
223234 handle -> Init .Mode = DMA_PFCTRL ;
224- handle -> Init .Priority = table_priority [dma -> cfg .channel_priority ],
235+ handle -> Init .Priority = table_priority [dma -> cfg .channel_priority ];
225236 handle -> Init .FIFOMode = DMA_FIFOMODE_ENABLE ;
226237 handle -> Init .FIFOThreshold = DMA_FIFO_THRESHOLD_FULL ;
227238 handle -> Init .MemBurst = DMA_MBURST_INC4 ;
228239 handle -> Init .PeriphBurst = DMA_PBURST_INC4 ;
240+ #else
241+ uint32_t channel_id = dma -> channel_nb - STM32_DMA_STREAM_OFFSET ;
242+
243+ BUILD_ASSERT (STM32_SDMMC_USE_DMA_SHARED == 1 , "Only txrx is supported on this family" );
244+ /* handle->Init.Direction is not initialised here on purpose.
245+ * Since the channel is reused for both directions, the direction is
246+ * configured before each read/write call.
247+ */
248+ handle -> Instance = __LL_DMA_GET_CHANNEL_INSTANCE (dma -> reg , channel_id );
249+ handle -> Init .Request = dma -> cfg .dma_slot ;
250+ handle -> Init .PeriphInc = DMA_PINC_DISABLE ;
251+ handle -> Init .MemInc = DMA_MINC_ENABLE ;
252+ handle -> Init .PeriphDataAlignment = DMA_PDATAALIGN_WORD ;
253+ handle -> Init .MemDataAlignment = DMA_MDATAALIGN_WORD ;
254+ handle -> Init .Mode = DMA_NORMAL ;
255+ handle -> Init .Priority = table_priority [dma -> cfg .channel_priority ];
256+ #endif
229257
230258 return ret ;
231259}
@@ -236,6 +264,15 @@ static int stm32_sdmmc_dma_init(struct stm32_sdmmc_priv *priv)
236264
237265 LOG_DBG ("using dma" );
238266
267+ #if STM32_SDMMC_USE_DMA_SHARED
268+ err = stm32_sdmmc_configure_dma (& priv -> dma_txrx_handle , & priv -> dma_txrx );
269+ if (err ) {
270+ LOG_ERR ("failed to init shared DMA" );
271+ return err ;
272+ }
273+ __HAL_LINKDMA (& priv -> hsd , hdmatx , priv -> dma_txrx_handle );
274+ __HAL_LINKDMA (& priv -> hsd , hdmarx , priv -> dma_txrx_handle );
275+ #else
239276 err = stm32_sdmmc_configure_dma (& priv -> dma_tx_handle , & priv -> dma_tx );
240277 if (err ) {
241278 LOG_ERR ("failed to init tx dma" );
@@ -251,29 +288,39 @@ static int stm32_sdmmc_dma_init(struct stm32_sdmmc_priv *priv)
251288 }
252289 __HAL_LINKDMA (& priv -> hsd , hdmarx , priv -> dma_rx_handle );
253290 HAL_DMA_Init (& priv -> dma_rx_handle );
291+ #endif /* STM32_SDMMC_USE_DMA_SHARED */
254292
255293 return err ;
256294}
257295
258296static int stm32_sdmmc_dma_deinit (struct stm32_sdmmc_priv * priv )
259297{
260298 int ret ;
299+
300+ /* Since we use STM32_DMA_HAL_OVERRIDE, the only purpose of dma_stop
301+ * is to notify the DMA subsystem that the channel is no longer in use.
302+ * Calling this before or after HAL_DMA_DeInit makes no difference.
303+ * There is no possibility of runtime failures apart from providing an
304+ * invalid channel ID, which is already validated by the setup.
305+ */
306+ #if STM32_SDMMC_USE_DMA_SHARED
307+ struct sdmmc_dma_stream * dma_txrx = & priv -> dma_txrx ;
308+
309+ ret = dma_stop (dma_txrx -> dev , dma_txrx -> channel );
310+ __ASSERT (ret == 0 , "Shared DMA channel index corrupted" );
311+ #else
261312 struct sdmmc_dma_stream * dma_tx = & priv -> dma_tx ;
262313 struct sdmmc_dma_stream * dma_rx = & priv -> dma_rx ;
263314
264315 ret = dma_stop (dma_tx -> dev , dma_tx -> channel );
316+ __ASSERT (ret == 0 , "TX DMA channel index corrupted" );
265317 HAL_DMA_DeInit (& priv -> dma_tx_handle );
266- if (ret != 0 ) {
267- LOG_ERR ("Failed to stop tx DMA transmission" );
268- return ret ;
269- }
318+
270319 ret = dma_stop (dma_rx -> dev , dma_rx -> channel );
320+ __ASSERT (ret == 0 , "RX DMA channel index corrupted" );
271321 HAL_DMA_DeInit (& priv -> dma_rx_handle );
272- if (ret != 0 ) {
273- LOG_ERR ("Failed to stop rx DMA transmission" );
274- return ret ;
275- }
276- return ret ;
322+ #endif
323+ return 0 ;
277324}
278325
279326#endif
@@ -401,6 +448,15 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf,
401448
402449 k_sem_take (& priv -> thread_lock , K_FOREVER );
403450
451+ #if STM32_SDMMC_USE_DMA_SHARED
452+ /* Initialise the shared DMA channel for the current direction */
453+ priv -> dma_txrx_handle .Init .Direction = LL_DMA_DIRECTION_PERIPH_TO_MEMORY ;
454+ if (HAL_DMA_Init (& priv -> dma_txrx_handle ) != HAL_OK ) {
455+ err = - EIO ;
456+ goto end ;
457+ }
458+ #endif
459+
404460 err = stm32_sdmmc_read_blocks (& priv -> hsd , data_buf , start_sector , num_sector );
405461 if (err != HAL_OK ) {
406462 LOG_ERR ("sd read block failed %d" , err );
@@ -410,6 +466,10 @@ static int stm32_sdmmc_access_read(struct disk_info *disk, uint8_t *data_buf,
410466
411467 k_sem_take (& priv -> sync , K_FOREVER );
412468
469+ #if STM32_SDMMC_USE_DMA_SHARED
470+ HAL_DMA_DeInit (& priv -> dma_txrx_handle );
471+ #endif
472+
413473 if (priv -> status != DISK_STATUS_OK ) {
414474 LOG_ERR ("sd read error %d" , priv -> status );
415475 err = - EIO ;
@@ -457,6 +517,15 @@ static int stm32_sdmmc_access_write(struct disk_info *disk,
457517
458518 k_sem_take (& priv -> thread_lock , K_FOREVER );
459519
520+ #if STM32_SDMMC_USE_DMA_SHARED
521+ /* Initialise the shared DMA channel for the current direction */
522+ priv -> dma_txrx_handle .Init .Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH ;
523+ if (HAL_DMA_Init (& priv -> dma_txrx_handle ) != HAL_OK ) {
524+ err = - EIO ;
525+ goto end ;
526+ }
527+ #endif
528+
460529 err = stm32_sdmmc_write_blocks (& priv -> hsd , (uint8_t * )data_buf , start_sector , num_sector );
461530 if (err != HAL_OK ) {
462531 LOG_ERR ("sd write block failed %d" , err );
@@ -466,6 +535,10 @@ static int stm32_sdmmc_access_write(struct disk_info *disk,
466535
467536 k_sem_take (& priv -> sync , K_FOREVER );
468537
538+ #if STM32_SDMMC_USE_DMA_SHARED
539+ HAL_DMA_DeInit (& priv -> dma_txrx_handle );
540+ #endif
541+
469542 if (priv -> status != DISK_STATUS_OK ) {
470543 LOG_ERR ("sd write error %d" , priv -> status );
471544 err = - EIO ;
@@ -813,8 +886,12 @@ static struct stm32_sdmmc_priv stm32_sdmmc_priv_1 = {
813886 .pclken = pclken_sdmmc ,
814887 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET (0 ),
815888 .reset = RESET_DT_SPEC_INST_GET (0 ),
889+ #if STM32_SDMMC_USE_DMA_SHARED
890+ SDMMC_DMA_CHANNEL (txrx , TXRX )
891+ #else
816892 SDMMC_DMA_CHANNEL (rx , RX )
817893 SDMMC_DMA_CHANNEL (tx , TX )
894+ #endif
818895};
819896
820897DEVICE_DT_INST_DEFINE (0 , disk_stm32_sdmmc_init , NULL ,
0 commit comments