11/*
2- * Copyright (c) 2006-2023, RT-Thread Development Team
2+ * Copyright (c) 2006-2024 RT-Thread Development Team
33 *
44 * SPDX-License-Identifier: Apache-2.0
55 *
88 * 2020-05-23 liuduanfei first version
99 * 2020-08-25 wanghaijing add sdmmmc2
1010 * 2023-03-26 wdfk-prog Distinguish between SDMMC and SDIO drivers
11+ * 2024-08-05 wdfk-prog Optimize SDMMC timeout handling and clock divider
1112 */
1213#include "board.h"
1314
2728#endif /* DRV_DEBUG */
2829#include <rtdbg.h>
2930
30- static struct stm32_sdio_class sdio_obj ;
3131static struct rt_mmcsd_host * host1 ;
3232static struct rt_mmcsd_host * host2 ;
3333
@@ -55,6 +55,11 @@ struct rthw_sdio
5555rt_align (SDIO_ALIGN_LEN )
5656static rt_uint8_t cache_buf [SDIO_BUFF_SIZE ];
5757
58+ static rt_uint32_t stm32_sdio_clk_get (void )
59+ {
60+ return SDIO_CLOCK_FREQ ;
61+ }
62+
5863/**
5964 * @brief This function get order from sdio.
6065 * @param data
@@ -154,10 +159,6 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
154159 return ;
155160 }
156161
157- if (sdio -> pkg == RT_NULL )
158- {
159- return ;
160- }
161162 /* Get Card Specific Data */
162163 cmd -> resp [0 ] = hsd -> RESP1 ;
163164 if (resp_type (cmd ) == RESP_R2 )
@@ -221,6 +222,38 @@ static void rthw_sdio_wait_completed(struct rthw_sdio *sdio)
221222 }
222223}
223224
225+ /**
226+ * @brief Calculate timeout for SDMMC data transfer.
227+ *
228+ * @note The timeout is estimated based on transfer size:
229+ * timeout = 100 ms + 2 ms per 512 bytes.
230+ * The result is clamped to the range [100 ms, 5000 ms].
231+ *
232+ * @param data Pointer to transfer data descriptor.
233+ *
234+ * @return Timeout in RT-Thread tick units.
235+ */
236+ static rt_tick_t stm32_sdmmc_calc_timeout (struct mmcsd_data * data )
237+ {
238+ rt_size_t len ;
239+ rt_uint32_t timeout_ms ;
240+
241+ if (data == RT_NULL )
242+ return rt_tick_from_millisecond (100 );
243+
244+ len = data -> blks * data -> blksize ;
245+
246+ /* base timeout + size-based timeout */
247+ timeout_ms = 100 + (len / 512 ) * 2 ;
248+
249+ if (timeout_ms < 100 )
250+ timeout_ms = 100 ;
251+ if (timeout_ms > 5000 )
252+ timeout_ms = 5000 ;
253+
254+ return rt_tick_from_millisecond (timeout_ms );
255+ }
256+
224257/**
225258 * @brief This function send command.
226259 * @param sdio rthw_sdio
@@ -262,7 +295,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
262295 /* data pre configuration */
263296 if (data != RT_NULL )
264297 {
265- SCB_CleanInvalidateDCache ( );
298+ rt_hw_cpu_dcache_ops ( RT_HW_CACHE_FLUSH , cache_buf , data -> blks * data -> blksize );
266299
267300 reg_cmd |= SDMMC_CMD_CMDTRANS ;
268301 __HAL_SD_DISABLE_IT (& sdio -> sdio_des .hw_sdio , SDMMC_MASK_CMDRENDIE | SDMMC_MASK_CMDSENTIE );
@@ -292,14 +325,19 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
292325 /* Waiting for data to be sent to completion */
293326 if (data != RT_NULL )
294327 {
295- volatile rt_uint32_t count = SDIO_TX_RX_COMPLETE_TIMEOUT_LOOPS ;
328+ rt_tick_t start = rt_tick_get ();
329+ rt_tick_t timeout = stm32_sdmmc_calc_timeout (data );
296330
297- while (count && ( hsd -> STA & SDMMC_STA_DPSMACT ) )
331+ while (hsd -> STA & SDMMC_STA_DPSMACT )
298332 {
299- count -- ;
333+ if ((rt_tick_get () - start ) >= timeout )
334+ {
335+ cmd -> err = - RT_ETIMEOUT ;
336+ break ;
337+ }
300338 }
301339
302- if ((count == 0 ) || ( hsd -> STA & SDIO_ERRORS ))
340+ if ((hsd -> STA & SDIO_ERRORS ) != 0 )
303341 {
304342 cmd -> err = - RT_ERROR ;
305343 }
@@ -311,7 +349,7 @@ static void rthw_sdio_send_command(struct rthw_sdio *sdio, struct sdio_pkg *pkg)
311349 if (data -> flags & DATA_DIR_READ )
312350 {
313351 rt_memcpy (data -> buf , cache_buf , data -> blks * data -> blksize );
314- SCB_CleanInvalidateDCache ( );
352+ rt_hw_cpu_dcache_ops ( RT_HW_CACHE_INVALIDATE , cache_buf , data -> blks * data -> blksize );
315353 }
316354 }
317355}
@@ -378,6 +416,33 @@ static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *
378416 SDMMC_InitTypeDef Init = {0 };
379417 rt_uint32_t sdmmc_clk = sdio -> sdio_des .clk_get ();
380418
419+ rt_bool_t stop_flag = RT_TRUE ;
420+
421+ switch (io_cfg -> power_mode & 0X03 )
422+ {
423+ case MMCSD_POWER_OFF :
424+ /* Set Power State to OFF */
425+ (void )SDMMC_PowerState_OFF (hsd -> Instance );
426+ stop_flag = RT_TRUE ;
427+ break ;
428+ case MMCSD_POWER_UP :
429+ /* In F4 series chips, 0X01 is reserved bit and has no practical effect.
430+ For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
431+ For H7 series chips, 0X03 is the power-on function.
432+ */
433+ stop_flag = RT_TRUE ;
434+ break ;
435+ case MMCSD_POWER_ON :
436+ stop_flag = RT_FALSE ;
437+ break ;
438+ default :
439+ LOG_W ("unknown power mode %d" , io_cfg -> power_mode );
440+ stop_flag = RT_FALSE ;
441+ break ;
442+ }
443+
444+ if (stop_flag == RT_TRUE ) return ;
445+
381446 if (sdmmc_clk < 400 * 1000 )
382447 {
383448 LOG_E ("The clock rate is too low! rata:%d" , sdmmc_clk );
@@ -422,91 +487,88 @@ static void rthw_sdio_iocfg(struct rt_mmcsd_host *host, struct rt_mmcsd_io_cfg *
422487 Init .BusWide = SDMMC_BUS_WIDE_1B ;
423488 }
424489 Init .HardwareFlowControl = hsd -> Init .HardwareFlowControl ;
425- /* Check if user Clock div < Normal speed 25Mhz, no change in Clockdiv */
426- if (hsd -> Init .ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ )))
427- {
428- Init .ClockDiv = hsd -> Init .ClockDiv ;
429- }
430- //CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01
431- else if (MMCSD_TIMING_UHS_SDR50 <= io_cfg -> timing && io_cfg -> timing <= MMCSD_TIMING_UHS_DDR50 )
432- {
433- /* UltraHigh speed SD card,user Clock div */
434- Init .ClockDiv = hsd -> Init .ClockDiv ;
435- }
436- //CARD_HIGH_SPEED: High Speed Card <25Mo/s , Spec version 2.00
437- else if (io_cfg -> timing == MMCSD_TIMING_SD_HS )
490+ /* Keep user clock divider if current setting is already <= normal speed */
491+ if (clk != SD_INIT_FREQ )
438492 {
439- /* High speed SD card, Max Frequency = 50Mhz */
440- if (hsd -> Init .ClockDiv == 0U )
493+ if (hsd -> Init .ClockDiv >= (sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ )))
441494 {
442- if (sdmmc_clk > SD_HIGH_SPEED_FREQ )
443- {
444- Init .ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ );
445- }
446- else
447- {
448- Init .ClockDiv = hsd -> Init .ClockDiv ;
449- }
495+ Init .ClockDiv = hsd -> Init .ClockDiv ;
450496 }
451- else
497+ //CARD_ULTRA_HIGH_SPEED :UHS-I SD Card <50Mo/s for SDR50, DDR5 Cards and <104Mo/s for SDR104, Spec version 3.01
498+ else if (MMCSD_TIMING_UHS_SDR50 <= io_cfg -> timing && io_cfg -> timing <= MMCSD_TIMING_UHS_DDR50 )
499+ {
500+ /* UltraHigh speed SD card,user Clock div */
501+ Init .ClockDiv = hsd -> Init .ClockDiv ;
502+ }
503+ //CARD_HIGH_SPEED: High Speed Card <25Mo/s , Spec version 2.00
504+ else if (io_cfg -> timing == MMCSD_TIMING_SD_HS )
452505 {
453- if ((sdmmc_clk /(2U * hsd -> Init .ClockDiv )) > SD_HIGH_SPEED_FREQ )
506+ /* High speed SD card, Max Frequency = 50Mhz */
507+ if (hsd -> Init .ClockDiv == 0U )
454508 {
455- Init .ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ );
509+ if (sdmmc_clk > SD_HIGH_SPEED_FREQ )
510+ {
511+ Init .ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ );
512+ }
513+ else
514+ {
515+ Init .ClockDiv = hsd -> Init .ClockDiv ;
516+ }
456517 }
457518 else
458519 {
459- Init .ClockDiv = hsd -> Init .ClockDiv ;
520+ if ((sdmmc_clk /(2U * hsd -> Init .ClockDiv )) > SD_HIGH_SPEED_FREQ )
521+ {
522+ Init .ClockDiv = sdmmc_clk / (2U * SD_HIGH_SPEED_FREQ );
523+ }
524+ else
525+ {
526+ Init .ClockDiv = hsd -> Init .ClockDiv ;
527+ }
460528 }
461529 }
462- }
463- //CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01
464- else if (io_cfg -> timing == MMCSD_TIMING_LEGACY )
465- {
466- /* No High speed SD card, Max Frequency = 25Mhz */
467- if (hsd -> Init .ClockDiv == 0U )
530+ //CARD_NORMAL_SPEED: Normal Speed Card <12.5Mo/s , Spec Version 1.01
531+ else if (io_cfg -> timing == MMCSD_TIMING_LEGACY )
468532 {
469- if (sdmmc_clk > SD_NORMAL_SPEED_FREQ )
533+ /* No High speed SD card, Max Frequency = 25Mhz */
534+ if (hsd -> Init .ClockDiv == 0U )
470535 {
471- Init .ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ );
536+ if (sdmmc_clk > SD_NORMAL_SPEED_FREQ )
537+ {
538+ Init .ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ );
539+ }
540+ else
541+ {
542+ Init .ClockDiv = hsd -> Init .ClockDiv ;
543+ }
472544 }
473545 else
474546 {
475- Init .ClockDiv = hsd -> Init .ClockDiv ;
547+ if ((sdmmc_clk /(2U * hsd -> Init .ClockDiv )) > SD_NORMAL_SPEED_FREQ )
548+ {
549+ Init .ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ );
550+ }
551+ else
552+ {
553+ Init .ClockDiv = hsd -> Init .ClockDiv ;
554+ }
476555 }
477556 }
478557 else
479558 {
480- if ((sdmmc_clk /(2U * hsd -> Init .ClockDiv )) > SD_NORMAL_SPEED_FREQ )
481- {
482- Init .ClockDiv = sdmmc_clk / (2U * SD_NORMAL_SPEED_FREQ );
483- }
484- else
485- {
486- Init .ClockDiv = hsd -> Init .ClockDiv ;
487- }
559+ Init .ClockDiv = hsd -> Init .ClockDiv ;
488560 }
489561 }
562+ else
563+ {
564+ Init .ClockDiv = hsd -> Init .ClockDiv ;
565+ }
490566 (void )SDMMC_Init (hsd -> Instance , Init );
491567 }
492- switch ((io_cfg -> power_mode ) & 0X03 )
568+ if ((io_cfg -> power_mode & 0X03 ) == MMCSD_POWER_ON )
493569 {
494- case MMCSD_POWER_OFF :
495- /* Set Power State to OFF */
496- (void )SDMMC_PowerState_OFF (hsd -> Instance );
497- break ;
498- case MMCSD_POWER_UP :
499- /* In F4 series chips, 0X01 is reserved bit and has no practical effect.
500- For F7 series chips, 0X01 is power-on after power-off,The SDMMC disables the function and the card clock stops.
501- For H7 series chips, 0X03 is the power-on function.
502- */
503- case MMCSD_POWER_ON :
504570 /* Set Power State to ON */
505571 (void )SDMMC_PowerState_ON (hsd -> Instance );
506- break ;
507- default :
508- LOG_W ("unknown power mode %d" , io_cfg -> power_mode );
509- break ;
510572 }
511573}
512574
@@ -578,15 +640,15 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
578640
579641 if (sdio_des == RT_NULL )
580642 {
581- LOG_E ("L:%d F:%s" ,( sdio_des == RT_NULL ? "sdio_des is NULL" : "" ) );
643+ LOG_E ("sdio_des is NULL" );
582644 return RT_NULL ;
583645 }
584646
585647 sdio = rt_malloc (sizeof (struct rthw_sdio ));
586648
587649 if (sdio == RT_NULL )
588650 {
589- LOG_E ("L:%d F:%s malloc rthw_sdio fail" );
651+ LOG_E ("malloc rthw_sdio fail" );
590652 return RT_NULL ;
591653 }
592654
@@ -596,12 +658,13 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
596658
597659 if (host == RT_NULL )
598660 {
599- LOG_E ("L:%d F:%s mmcsd alloc host fail" );
661+ LOG_E ("mmcsd alloc host fail" );
600662 rt_free (sdio );
601663 return RT_NULL ;
602664 }
603665
604666 rt_memcpy (& sdio -> sdio_des , sdio_des , sizeof (struct stm32_sdio_des ));
667+ sdio -> sdio_des .clk_get = (sdio_des -> clk_get == RT_NULL ? stm32_sdio_clk_get : sdio_des -> clk_get );
605668#ifdef BSP_USING_SDIO1
606669 if (sdio_des -> hw_sdio .Instance == SDMMC1 )
607670 {
@@ -630,14 +693,14 @@ struct rt_mmcsd_host *sdio_host_create(struct stm32_sdio_des *sdio_des)
630693#endif
631694 host -> max_seg_size = SDIO_BUFF_SIZE ;
632695 host -> max_dma_segs = 1 ;
633- host -> max_blk_size = 512 ;
634- host -> max_blk_count = 512 ;
696+ host -> max_blk_size = BLOCKSIZE ;
697+ host -> max_blk_count = BLOCKSIZE ;
635698
636699 /* link up host and sdio */
637700 sdio -> host = host ;
638701 host -> private_data = sdio ;
639702
640- rthw_sdio_irq_update (host , 1 );
703+ rthw_sdio_irq_update (host , RT_TRUE );
641704
642705 /* ready to change */
643706 mmcsd_change (host );
0 commit comments