Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:02

0001 /*
0002  * Copyright (c) 2016, Freescale Semiconductor, Inc.
0003  * Copyright 2016-2021 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_usdhc.h"
0010 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
0011 #include "fsl_cache.h"
0012 #endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
0013 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
0014 #include "fsl_memory.h"
0015 #endif
0016 /*******************************************************************************
0017  * Definitions
0018  ******************************************************************************/
0019 
0020 /* Component ID definition, used by tools. */
0021 #ifndef FSL_COMPONENT_ID
0022 #define FSL_COMPONENT_ID "platform.drivers.usdhc"
0023 #endif
0024 
0025 /*! @brief Clock setting */
0026 /* Max SD clock divisor from base clock */
0027 #define USDHC_MAX_DVS          ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
0028 #define USDHC_MAX_CLKFS        ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
0029 #define USDHC_PREV_DVS(x)      ((x) -= 1U)
0030 #define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
0031 /*! @brief USDHC ADMA table address align size */
0032 #define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U)
0033 
0034 /* Typedef for interrupt handler. */
0035 typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
0036 /*! @brief check flag avalibility */
0037 #define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
0038 
0039 /*! @brief usdhc transfer flags */
0040 enum _usdhc_transfer_flags
0041 {
0042     kUSDHC_CommandOnly        = 1U,  /*!< transfer command only */
0043     kUSDHC_CommandAndTxData   = 2U,  /*!< transfer command and transmit data */
0044     kUSDHC_CommandAndRxData   = 4U,  /*!< transfer command and receive data */
0045     kUSDHC_DataWithAutoCmd12  = 8U,  /*!< transfer data with auto cmd12 enabled */
0046     kUSDHC_DataWithAutoCmd23  = 16U, /*!< transfer data with auto cmd23 enabled */
0047     kUSDHC_BootData           = 32U, /*!< transfer boot data */
0048     kUSDHC_BootDataContinuous = 64U, /*!< transfer boot data continuous */
0049 };
0050 
0051 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
0052 #define USDHC_ADDR_CPU_2_DMA(addr) (MEMORY_ConvertMemoryMapAddress((addr), kMEMORY_Local2DMA))
0053 #else
0054 #define USDHC_ADDR_CPU_2_DMA(addr) (addr)
0055 #endif
0056 /*******************************************************************************
0057  * Prototypes
0058  ******************************************************************************/
0059 /*!
0060  * @brief Get the instance.
0061  *
0062  * @param base USDHC peripheral base address.
0063  * @return Instance number.
0064  */
0065 static uint32_t USDHC_GetInstance(USDHC_Type *base);
0066 
0067 /*!
0068  * @brief Start transfer according to current transfer state
0069  *
0070  * @param base USDHC peripheral base address.
0071  * @param transferFlags transfer flags, @ref _usdhc_transfer_flags.
0072  * @param blockSize block size.
0073  * @param blockCount block count.
0074  */
0075 static status_t USDHC_SetTransferConfig(USDHC_Type *base,
0076                                         uint32_t transferFlags,
0077                                         size_t blockSize,
0078                                         uint32_t blockCount);
0079 
0080 /*!
0081  * @brief Receive command response
0082  *
0083  * @param base USDHC peripheral base address.
0084  * @param command Command to be sent.
0085  */
0086 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command);
0087 
0088 /*!
0089  * @brief Read DATAPORT when buffer enable bit is set.
0090  *
0091  * @param base USDHC peripheral base address.
0092  * @param data Data to be read.
0093  * @param transferredWords The number of data words have been transferred last time transaction.
0094  * @return The number of total data words have been transferred after this time transaction.
0095  */
0096 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
0097 
0098 /*!
0099  * @brief Read data by using DATAPORT polling way.
0100  *
0101  * @param base USDHC peripheral base address.
0102  * @param data Data to be read.
0103  * @retval kStatus_Fail Read DATAPORT failed.
0104  * @retval kStatus_Success Operate successfully.
0105  */
0106 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
0107 
0108 /*!
0109  * @brief Write DATAPORT when buffer enable bit is set.
0110  *
0111  * @param base USDHC peripheral base address.
0112  * @param data Data to be read.
0113  * @param transferredWords The number of data words have been transferred last time.
0114  * @return The number of total data words have been transferred after this time transaction.
0115  */
0116 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
0117 
0118 /*!
0119  * @brief Write data by using DATAPORT polling way.
0120  *
0121  * @param base USDHC peripheral base address.
0122  * @param data Data to be transferred.
0123  * @retval kStatus_Fail Write DATAPORT failed.
0124  * @retval kStatus_Success Operate successfully.
0125  */
0126 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
0127 
0128 /*!
0129  * @brief Transfer data by polling way.
0130  *
0131  * @param base USDHC peripheral base address.
0132  * @param data Data to be transferred.
0133  * @param use DMA flag.
0134  * @retval kStatus_Fail Transfer data failed.
0135  * @retval kStatus_InvalidArgument Argument is invalid.
0136  * @retval kStatus_Success Operate successfully.
0137  */
0138 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
0139 
0140 /*!
0141  * @brief wait command done
0142  *
0143  * @param base USDHC peripheral base address.
0144  * @param command configuration
0145  * @param pollingCmdDone polling command done flag
0146  */
0147 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
0148 
0149 /*!
0150  * @brief Handle card detect interrupt.
0151  *
0152  * @param base USDHC peripheral base address.
0153  * @param handle USDHC handle.
0154  * @param interruptFlags Card detect related interrupt flags.
0155  */
0156 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
0157 
0158 /*!
0159  * @brief Handle command interrupt.
0160  *
0161  * @param base USDHC peripheral base address.
0162  * @param handle USDHC handle.
0163  * @param interruptFlags Command related interrupt flags.
0164  */
0165 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
0166 
0167 /*!
0168  * @brief Handle data interrupt.
0169  *
0170  * @param base USDHC peripheral base address.
0171  * @param handle USDHC handle.
0172  * @param interruptFlags Data related interrupt flags.
0173  */
0174 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
0175 
0176 /*!
0177  * @brief Handle SDIO card interrupt signal.
0178  *
0179  * @param base USDHC peripheral base address.
0180  * @param handle USDHC handle.
0181  */
0182 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
0183 
0184 /*!
0185  * @brief Handle SDIO block gap event.
0186  *
0187  * @param base USDHC peripheral base address.
0188  * @param handle USDHC handle.
0189  */
0190 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
0191 
0192 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
0193 /*!
0194  * @brief Handle retuning
0195  *
0196  * @param base USDHC peripheral base address.
0197  * @param handle USDHC handle.
0198  * @param interrupt flags
0199  */
0200 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
0201 #endif
0202 /*******************************************************************************
0203  * Variables
0204  ******************************************************************************/
0205 /*! @brief USDHC base pointer array */
0206 static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
0207 
0208 /*! @brief USDHC internal handle pointer array */
0209 static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {0};
0210 
0211 /*! @brief USDHC IRQ name array */
0212 static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
0213 
0214 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0215 /*! @brief USDHC clock array name */
0216 static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
0217 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0218 
0219 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
0220 /*! @brief Pointers to USDHC resets for each instance. */
0221 static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS;
0222 #endif
0223 
0224 /* USDHC ISR for transactional APIs. */
0225 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
0226 static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR;
0227 #else
0228 static usdhc_isr_t s_usdhcIsr;
0229 #endif
0230 /*! @brief Dummy data buffer for mmc boot mode  */
0231 AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
0232 
0233 /*******************************************************************************
0234  * Code
0235  ******************************************************************************/
0236 static uint32_t USDHC_GetInstance(USDHC_Type *base)
0237 {
0238     uint8_t instance = 0;
0239 
0240     while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
0241     {
0242         instance++;
0243     }
0244 
0245     assert(instance < ARRAY_SIZE(s_usdhcBase));
0246 
0247     return instance;
0248 }
0249 
0250 static status_t USDHC_SetTransferConfig(USDHC_Type *base, uint32_t transferFlags, size_t blockSize, uint32_t blockCount)
0251 {
0252     uint32_t mixCtrl = base->MIX_CTRL;
0253 
0254     if (((uint32_t)kUSDHC_CommandOnly & transferFlags) != 0U)
0255     {
0256         /* clear data flags */
0257         mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
0258                      USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK);
0259 
0260         if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
0261         {
0262             return kStatus_USDHC_BusyTransferring;
0263         }
0264     }
0265     else
0266     {
0267         /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
0268         if ((transferFlags & (uint32_t)kUSDHC_BootDataContinuous) != 0U)
0269         {
0270             /* clear stop at block gap request */
0271             base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
0272             /* continous transfer data */
0273             base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
0274             return kStatus_Success;
0275         }
0276 
0277         /* check data inhibit flag */
0278         if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag))
0279         {
0280             return kStatus_USDHC_BusyTransferring;
0281         }
0282         /* check transfer block count */
0283         if ((blockCount > USDHC_MAX_BLOCK_COUNT))
0284         {
0285             return kStatus_InvalidArgument;
0286         }
0287 
0288         /* config mix parameter */
0289         mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
0290                      USDHC_MIX_CTRL_AC12EN_MASK);
0291 
0292         if ((transferFlags & (uint32_t)kUSDHC_CommandAndRxData) != 0U)
0293         {
0294             mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
0295         }
0296 
0297         if (blockCount > 1U)
0298         {
0299             mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
0300             /* auto command 12 */
0301             if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd12) != 0U)
0302             {
0303                 mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
0304             }
0305         }
0306 
0307         /* auto command 23, auto send set block count cmd before multiple read/write */
0308         if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd23) != 0U)
0309         {
0310             mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
0311             base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
0312             /* config the block count to DS_ADDR */
0313             base->DS_ADDR = blockCount;
0314         }
0315         else
0316         {
0317             mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
0318             base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
0319         }
0320 
0321         /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
0322         if ((transferFlags & (uint32_t)kUSDHC_BootData) == 0U)
0323         {
0324             /* config data block size/block count */
0325             base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
0326                              (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
0327         }
0328         else
0329         {
0330             mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
0331             base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
0332         }
0333     }
0334     /* config the mix parameter */
0335     base->MIX_CTRL = mixCtrl;
0336 
0337     return kStatus_Success;
0338 }
0339 
0340 void USDHC_SetDataConfig(USDHC_Type *base,
0341                          usdhc_transfer_direction_t dataDirection,
0342                          uint32_t blockCount,
0343                          uint32_t blockSize)
0344 {
0345     assert(blockCount <= USDHC_MAX_BLOCK_COUNT);
0346 
0347     uint32_t mixCtrl = base->MIX_CTRL;
0348 
0349     /* block attribute configuration */
0350     base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
0351                      (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
0352 
0353     /* config mix parameter */
0354     mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK);
0355 
0356     mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U);
0357 
0358     base->MIX_CTRL = mixCtrl;
0359 }
0360 
0361 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
0362 {
0363     assert(command != NULL);
0364 
0365     uint32_t response0 = base->CMD_RSP0;
0366     uint32_t response1 = base->CMD_RSP1;
0367     uint32_t response2 = base->CMD_RSP2;
0368 
0369     if (command->responseType != kCARD_ResponseTypeNone)
0370     {
0371         command->response[0U] = response0;
0372         if (command->responseType == kCARD_ResponseTypeR2)
0373         {
0374             /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
0375             after removed internal CRC7 and end bit. */
0376             command->response[0U] <<= 8U;
0377             command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
0378             command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
0379             command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U);
0380         }
0381     }
0382 
0383     /* check response error flag */
0384     if ((command->responseErrorFlags != 0U) &&
0385         ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
0386          (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
0387     {
0388         if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
0389         {
0390             return kStatus_USDHC_SendCommandFailed;
0391         }
0392     }
0393 
0394     return kStatus_Success;
0395 }
0396 
0397 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
0398 {
0399     uint32_t i;
0400     uint32_t totalWords;
0401     uint32_t wordsCanBeRead; /* The words can be read at this time. */
0402     uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
0403 
0404     /* If DMA is enable, do not need to polling data port */
0405     if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
0406     {
0407         /*
0408          * Add non aligned access support ,user need make sure your buffer size is big
0409          * enough to hold the data,in other words,user need make sure the buffer size
0410          * is 4 byte aligned
0411          */
0412         if (data->blockSize % sizeof(uint32_t) != 0U)
0413         {
0414             data->blockSize +=
0415                 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
0416         }
0417 
0418         totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
0419 
0420         /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
0421         if (readWatermark >= totalWords)
0422         {
0423             wordsCanBeRead = totalWords;
0424         }
0425         /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
0426         transfers watermark level words. */
0427         else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
0428         {
0429             wordsCanBeRead = readWatermark;
0430         }
0431         /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
0432         left
0433         words. */
0434         else
0435         {
0436             wordsCanBeRead = (totalWords - transferredWords);
0437         }
0438 
0439         i = 0U;
0440         while (i < wordsCanBeRead)
0441         {
0442             data->rxData[transferredWords++] = USDHC_ReadData(base);
0443             i++;
0444         }
0445     }
0446 
0447     return transferredWords;
0448 }
0449 
0450 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
0451 {
0452     uint32_t totalWords;
0453     uint32_t transferredWords = 0U, interruptStatus = 0U;
0454     status_t error = kStatus_Success;
0455 
0456     /*
0457      * Add non aligned access support ,user need make sure your buffer size is big
0458      * enough to hold the data,in other words,user need make sure the buffer size
0459      * is 4 byte aligned
0460      */
0461     if (data->blockSize % sizeof(uint32_t) != 0U)
0462     {
0463         data->blockSize +=
0464             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
0465     }
0466 
0467     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
0468 
0469     while ((error == kStatus_Success) && (transferredWords < totalWords))
0470     {
0471         while (
0472             !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag |
0473                                                   (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
0474         {
0475             interruptStatus = USDHC_GetInterruptStatusFlags(base);
0476         }
0477 
0478         /* during std tuning process, software do not need to read data, but wait BRR is enough */
0479         if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) &&
0480             (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag)))
0481         {
0482             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
0483 
0484             return kStatus_Success;
0485         }
0486 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
0487         else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
0488         {
0489             USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
0490             /* if tuning error occur ,return directly */
0491             error = kStatus_USDHC_TuningError;
0492         }
0493 #endif
0494         else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
0495         {
0496             if (!(data->enableIgnoreError))
0497             {
0498                 error = kStatus_Fail;
0499             }
0500             /* clear data error flag */
0501             USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
0502         }
0503         else
0504         {
0505             /* Intentional empty */
0506         }
0507 
0508         if (error == kStatus_Success)
0509         {
0510             transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
0511             /* clear buffer read ready */
0512             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
0513             interruptStatus = 0U;
0514         }
0515     }
0516 
0517     /* Clear data complete flag after the last read operation. */
0518     USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
0519 
0520     return error;
0521 }
0522 
0523 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
0524 {
0525     uint32_t i;
0526     uint32_t totalWords;
0527     uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
0528     uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
0529 
0530     /* If DMA is enable, do not need to polling data port */
0531     if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
0532     {
0533         /*
0534          * Add non aligned access support ,user need make sure your buffer size is big
0535          * enough to hold the data,in other words,user need make sure the buffer size
0536          * is 4 byte aligned
0537          */
0538         if (data->blockSize % sizeof(uint32_t) != 0U)
0539         {
0540             data->blockSize +=
0541                 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
0542         }
0543 
0544         totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
0545 
0546         /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
0547         if (writeWatermark >= totalWords)
0548         {
0549             wordsCanBeWrote = totalWords;
0550         }
0551         /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
0552         transfers watermark level words. */
0553         else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
0554         {
0555             wordsCanBeWrote = writeWatermark;
0556         }
0557         /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
0558         words. */
0559         else
0560         {
0561             wordsCanBeWrote = (totalWords - transferredWords);
0562         }
0563 
0564         i = 0U;
0565         while (i < wordsCanBeWrote)
0566         {
0567             USDHC_WriteData(base, data->txData[transferredWords++]);
0568             i++;
0569         }
0570     }
0571 
0572     return transferredWords;
0573 }
0574 
0575 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
0576 {
0577     uint32_t totalWords;
0578 
0579     uint32_t transferredWords = 0U, interruptStatus = 0U;
0580     status_t error = kStatus_Success;
0581 
0582     /*
0583      * Add non aligned access support ,user need make sure your buffer size is big
0584      * enough to hold the data,in other words,user need make sure the buffer size
0585      * is 4 byte aligned
0586      */
0587     if (data->blockSize % sizeof(uint32_t) != 0U)
0588     {
0589         data->blockSize +=
0590             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
0591     }
0592 
0593     totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
0594 
0595     while ((error == kStatus_Success) && (transferredWords < totalWords))
0596     {
0597         while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag |
0598                                                         (uint32_t)kUSDHC_DataErrorFlag |
0599                                                         (uint32_t)kUSDHC_TuningErrorFlag)))
0600         {
0601             interruptStatus = USDHC_GetInterruptStatusFlags(base);
0602         }
0603 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
0604         if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
0605         {
0606             USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
0607             /* if tuning error occur ,return directly */
0608             return kStatus_USDHC_TuningError;
0609         }
0610         else
0611 #endif
0612             if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
0613         {
0614             if (!(data->enableIgnoreError))
0615             {
0616                 error = kStatus_Fail;
0617             }
0618             /* clear data error flag */
0619             USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
0620         }
0621         else
0622         {
0623             /* Intentional empty */
0624         }
0625 
0626         if (error == kStatus_Success)
0627         {
0628             transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
0629             /* clear buffer write ready */
0630             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
0631             interruptStatus = 0U;
0632         }
0633     }
0634 
0635     /* Wait write data complete or data transfer error after the last writing operation. */
0636     while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)))
0637     {
0638         interruptStatus = USDHC_GetInterruptStatusFlags(base);
0639     }
0640 
0641     if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL)
0642     {
0643         if (!(data->enableIgnoreError))
0644         {
0645             error = kStatus_Fail;
0646         }
0647     }
0648     USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag));
0649 
0650     return error;
0651 }
0652 
0653 /*!
0654  * brief send command function
0655  *
0656  * param base USDHC peripheral base address.
0657  * param command configuration
0658  */
0659 void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
0660 {
0661     assert(NULL != command);
0662 
0663     uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
0664 
0665     if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
0666     {
0667         if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) ||
0668             (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7))
0669         {
0670             flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
0671                       (uint32_t)kUSDHC_EnableIndexCheckFlag);
0672         }
0673         else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b))
0674         {
0675             flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
0676                       (uint32_t)kUSDHC_EnableIndexCheckFlag);
0677         }
0678         else if (command->responseType == kCARD_ResponseTypeR2)
0679         {
0680             flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag);
0681         }
0682         else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4))
0683         {
0684             flags |= ((uint32_t)kUSDHC_ResponseLength48Flag);
0685         }
0686         else
0687         {
0688             /* Intentional empty */
0689         }
0690 
0691         if (command->type == kCARD_CommandTypeAbort)
0692         {
0693             flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag;
0694         }
0695 
0696         /* config cmd index */
0697         xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
0698                       USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
0699 
0700         xferType |=
0701             (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
0702              ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
0703                          USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
0704 
0705         /* config the command xfertype and argument */
0706         base->CMD_ARG     = command->argument;
0707         base->CMD_XFR_TYP = xferType;
0708     }
0709 
0710     if (command->type == kCARD_CommandTypeEmpty)
0711     {
0712         /* disable CMD done interrupt for empty command */
0713         base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
0714     }
0715 }
0716 
0717 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
0718 {
0719     assert(NULL != command);
0720 
0721     status_t error           = kStatus_Success;
0722     uint32_t interruptStatus = 0U;
0723     /* check if need polling command done or not */
0724     if (pollingCmdDone)
0725     {
0726         /* Wait command complete or USDHC encounters error. */
0727         while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag)))
0728         {
0729             interruptStatus = USDHC_GetInterruptStatusFlags(base);
0730         }
0731 
0732         if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL)
0733         {
0734             error = kStatus_Fail;
0735         }
0736 
0737         /* Receive response when command completes successfully. */
0738         if (error == kStatus_Success)
0739         {
0740             error = USDHC_ReceiveCommandResponse(base, command);
0741         }
0742 
0743         USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
0744     }
0745 
0746     return error;
0747 }
0748 
0749 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
0750 {
0751     status_t error           = kStatus_Success;
0752     uint32_t interruptStatus = 0U;
0753 
0754     if (enDMA)
0755     {
0756         /* Wait data complete or USDHC encounters error. */
0757         while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
0758         {
0759             interruptStatus = USDHC_GetInterruptStatusFlags(base);
0760         }
0761 
0762 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
0763         if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
0764         {
0765             error = kStatus_USDHC_TuningError;
0766         }
0767         else
0768 #endif
0769             if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
0770         {
0771             if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag)))
0772             {
0773                 error = kStatus_USDHC_TransferDataFailed;
0774             }
0775         }
0776         else
0777         {
0778             /* Intentional empty */
0779         }
0780         /* load dummy data */
0781         if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
0782         {
0783             *(data->rxData) = s_usdhcBootDummy;
0784         }
0785 
0786         USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag));
0787     }
0788     else
0789     {
0790         if (data->rxData != NULL)
0791         {
0792             error = USDHC_ReadByDataPortBlocking(base, data);
0793             if (error != kStatus_Success)
0794             {
0795                 return error;
0796             }
0797         }
0798         else
0799         {
0800             error = USDHC_WriteByDataPortBlocking(base, data);
0801             if (error != kStatus_Success)
0802             {
0803                 return error;
0804             }
0805         }
0806     }
0807 
0808     return error;
0809 }
0810 
0811 /*!
0812  * brief USDHC module initialization function.
0813  *
0814  * Configures the USDHC according to the user configuration.
0815  *
0816  * Example:
0817    code
0818    usdhc_config_t config;
0819    config.cardDetectDat3 = false;
0820    config.endianMode = kUSDHC_EndianModeLittle;
0821    config.dmaMode = kUSDHC_DmaModeAdma2;
0822    config.readWatermarkLevel = 128U;
0823    config.writeWatermarkLevel = 128U;
0824    USDHC_Init(USDHC, &config);
0825    endcode
0826  *
0827  * param base USDHC peripheral base address.
0828  * param config USDHC configuration information.
0829  * retval kStatus_Success Operate successfully.
0830  */
0831 void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
0832 {
0833     assert(config != NULL);
0834     assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
0835     assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
0836 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
0837     assert(config->writeBurstLen <= 16U);
0838 #endif
0839     uint32_t proctl, sysctl, wml;
0840 
0841 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0842     /* Enable USDHC clock. */
0843     CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
0844 #endif
0845 
0846 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
0847     /* Reset the USDHC module */
0848     RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]);
0849 #endif
0850 
0851     /* Reset ALL USDHC. */
0852     base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK;
0853 
0854     proctl = base->PROT_CTRL;
0855     wml    = base->WTMK_LVL;
0856     sysctl = base->SYS_CTRL;
0857 
0858     proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
0859     /* Endian mode*/
0860     proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
0861 
0862 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
0863     /* Watermark level */
0864     wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK);
0865     wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel));
0866 #else
0867     /* Watermark level */
0868     wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
0869              USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
0870     wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
0871             USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
0872 #endif
0873 
0874     /* config the data timeout value */
0875     sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
0876     sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
0877 
0878     base->SYS_CTRL  = sysctl;
0879     base->WTMK_LVL  = wml;
0880     base->PROT_CTRL = proctl;
0881 
0882 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
0883     /* disable external DMA */
0884     base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
0885 #endif
0886     /* disable internal DMA and DDR mode */
0887     base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
0888     /* disable interrupt, enable all the interrupt status, clear status. */
0889     base->INT_STATUS_EN = kUSDHC_AllInterruptFlags;
0890     base->INT_SIGNAL_EN = 0UL;
0891     base->INT_STATUS    = kUSDHC_AllInterruptFlags;
0892 }
0893 
0894 /*!
0895  * brief Deinitializes the USDHC.
0896  *
0897  * param base USDHC peripheral base address.
0898  */
0899 void USDHC_Deinit(USDHC_Type *base)
0900 {
0901 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0902     /* Disable clock. */
0903     CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
0904 #endif
0905 }
0906 
0907 /*!
0908  * brief Resets the USDHC.
0909  *
0910  * param base USDHC peripheral base address.
0911  * param mask The reset type mask(_usdhc_reset).
0912  * param timeout Timeout for reset.
0913  * retval true Reset successfully.
0914  * retval false Reset failed.
0915  */
0916 bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
0917 {
0918     base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK
0919 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
0920                                | USDHC_SYS_CTRL_RSTT_MASK
0921 #endif
0922                                ));
0923     /* Delay some time to wait reset success. */
0924     while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask))
0925     {
0926         if (timeout == 0UL)
0927         {
0928             break;
0929         }
0930         timeout--;
0931     }
0932 
0933     return ((0UL == timeout) ? false : true);
0934 }
0935 
0936 /*!
0937  * brief Gets the capability information.
0938  *
0939  * param base USDHC peripheral base address.
0940  * param capability Structure to save capability information.
0941  */
0942 void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
0943 {
0944     assert(capability != NULL);
0945 
0946     uint32_t htCapability;
0947     uint32_t maxBlockLength;
0948 
0949     htCapability = base->HOST_CTRL_CAP;
0950 
0951     /* Get the capability of USDHC. */
0952     maxBlockLength             = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
0953     capability->maxBlockLength = (512UL << maxBlockLength);
0954     /* Other attributes not in HTCAPBLT register. */
0955     capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
0956     capability->flags =
0957         (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK |
0958                          USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK));
0959     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK;
0960     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
0961     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
0962 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
0963     capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
0964 #endif
0965 
0966 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
0967     capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
0968 #endif
0969     /* USDHC support 4/8 bit data bus width. */
0970     capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
0971 }
0972 
0973 /*!
0974  * brief Sets the SD bus clock frequency.
0975  *
0976  * param base USDHC peripheral base address.
0977  * param srcClock_Hz USDHC source clock frequency united in Hz.
0978  * param busClock_Hz SD bus clock frequency united in Hz.
0979  *
0980  * return The nearest frequency of busClock_Hz configured to SD bus.
0981  */
0982 uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
0983 {
0984     assert(srcClock_Hz != 0U);
0985     assert(busClock_Hz != 0U);
0986 
0987     uint32_t totalDiv         = 0UL;
0988     uint32_t divisor          = 0UL;
0989     uint32_t prescaler        = 0UL;
0990     uint32_t sysctl           = 0UL;
0991     uint32_t nearestFrequency = 0UL;
0992 
0993     if (busClock_Hz > srcClock_Hz)
0994     {
0995         busClock_Hz = srcClock_Hz;
0996     }
0997 
0998     totalDiv = srcClock_Hz / busClock_Hz;
0999 
1000     /* calucate total divisor first */
1001     if (totalDiv > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
1002     {
1003         return 0UL;
1004     }
1005 
1006     if (totalDiv != 0UL)
1007     {
1008         /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
1009         if ((srcClock_Hz / totalDiv) > busClock_Hz)
1010         {
1011             totalDiv++;
1012         }
1013 
1014         /* divide the total divisor to div and prescaler */
1015         if (totalDiv > USDHC_MAX_DVS)
1016         {
1017             prescaler = totalDiv / USDHC_MAX_DVS;
1018             /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
1019             while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL))
1020             {
1021                 prescaler++;
1022             }
1023             /* calucate the divisor */
1024             divisor = totalDiv / prescaler;
1025             /* fine tuning the divisor until divisor * prescaler >= totalDiv */
1026             while ((divisor * prescaler) < totalDiv)
1027             {
1028                 divisor++;
1029                 if (divisor > USDHC_MAX_DVS)
1030                 {
1031                     prescaler <<= 1UL;
1032                     if (prescaler > USDHC_MAX_CLKFS)
1033                     {
1034                         return 0UL;
1035                     }
1036                     divisor = totalDiv / prescaler;
1037                 }
1038             }
1039         }
1040         else
1041         {
1042             /* in this situation , divsior and SDCLKFS can generate same clock
1043             use SDCLKFS*/
1044             if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL))
1045             {
1046                 divisor   = totalDiv;
1047                 prescaler = 1UL;
1048             }
1049             else
1050             {
1051                 divisor   = 1UL;
1052                 prescaler = totalDiv;
1053             }
1054         }
1055         nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler;
1056     }
1057     /* in this condition , srcClock_Hz = busClock_Hz, */
1058     else
1059     {
1060         /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
1061         totoal divider = 2U */
1062         divisor          = 0UL;
1063         prescaler        = 0UL;
1064         nearestFrequency = srcClock_Hz;
1065     }
1066 
1067     /* calucate the value write to register */
1068     if (divisor != 0UL)
1069     {
1070         USDHC_PREV_DVS(divisor);
1071     }
1072     /* calucate the value write to register */
1073     if (prescaler != 0UL)
1074     {
1075         USDHC_PREV_CLKFS(prescaler, 1UL);
1076     }
1077 
1078     /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
1079     sysctl = base->SYS_CTRL;
1080     sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
1081     sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
1082     base->SYS_CTRL = sysctl;
1083 
1084     /* Wait until the SD clock is stable. */
1085     while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK))
1086     {
1087     }
1088 
1089     return nearestFrequency;
1090 }
1091 
1092 /*!
1093  * brief Sends 80 clocks to the card to set it to the active state.
1094  *
1095  * This function must be called each time the card is inserted to ensure that the card can receive the command
1096  * correctly.
1097  *
1098  * param base USDHC peripheral base address.
1099  * param timeout Timeout to initialize card.
1100  * retval true Set card active successfully.
1101  * retval false Set card active failed.
1102  */
1103 bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
1104 {
1105     base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
1106     /* Delay some time to wait card become active state. */
1107     while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK))
1108     {
1109         if (0UL == timeout)
1110         {
1111             break;
1112         }
1113         timeout--;
1114     }
1115 
1116     return ((0UL == timeout) ? false : true);
1117 }
1118 
1119 /*!
1120  * brief the enable/disable DDR mode
1121  *
1122  * param base USDHC peripheral base address.
1123  * param enable/disable flag
1124  * param nibble position
1125  */
1126 void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
1127 {
1128     uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
1129 
1130     if (enable)
1131     {
1132         base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
1133         base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
1134         prescaler >>= 1UL;
1135     }
1136     else
1137     {
1138         base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
1139 
1140         if (prescaler == 0UL)
1141         {
1142             prescaler += 1UL;
1143         }
1144         else
1145         {
1146             prescaler <<= 1UL;
1147         }
1148     }
1149 
1150     base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
1151 }
1152 
1153 /*!
1154  * brief Configures the MMC boot feature.
1155  *
1156  * Example:
1157    code
1158    usdhc_boot_config_t config;
1159    config.ackTimeoutCount = 4;
1160    config.bootMode = kUSDHC_BootModeNormal;
1161    config.blockCount = 5;
1162    config.enableBootAck = true;
1163    config.enableBoot = true;
1164    config.enableAutoStopAtBlockGap = true;
1165    USDHC_SetMmcBootConfig(USDHC, &config);
1166    endcode
1167  *
1168  * param base USDHC peripheral base address.
1169  * param config The MMC boot configuration information.
1170  */
1171 void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
1172 {
1173     assert(config != NULL);
1174     assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
1175     assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
1176 
1177     uint32_t mmcboot = base->MMC_BOOT;
1178 
1179     mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
1180     mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
1181 
1182     if (config->enableBootAck)
1183     {
1184         mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
1185     }
1186     if (config->enableAutoStopAtBlockGap)
1187     {
1188         mmcboot |=
1189             USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
1190         /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
1191         base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1192                          (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
1193     }
1194     else
1195     {
1196         base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1197                          (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
1198     }
1199 
1200     base->MMC_BOOT = mmcboot;
1201 }
1202 
1203 /*!
1204  * brief Sets the ADMA1 descriptor table configuration.
1205  *
1206  * param admaTable Adma table address.
1207  * param admaTableWords Adma table length.
1208  * param dataBufferAddr Data buffer address.
1209  * param dataBytes Data length.
1210  * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1211  *  reference _usdhc_adma_flag.
1212  * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1213  * retval kStatus_Success Operate successfully.
1214  */
1215 status_t USDHC_SetADMA1Descriptor(
1216     uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1217 {
1218     assert(NULL != admaTable);
1219     assert(NULL != dataBufferAddr);
1220 
1221     uint32_t miniEntries, startEntries = 0UL,
1222                           maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
1223     usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable);
1224     uint32_t i, dmaBufferLen = 0UL;
1225     const uint32_t *data = dataBufferAddr;
1226 
1227     if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL)
1228     {
1229         return kStatus_USDHC_DMADataAddrNotAlign;
1230     }
1231 
1232     if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1233     {
1234         return kStatus_USDHC_NotSupport;
1235     }
1236     /*
1237      * Add non aligned access support ,user need make sure your buffer size is big
1238      * enough to hold the data,in other words,user need make sure the buffer size
1239      * is 4 byte aligned
1240      */
1241     if (dataBytes % sizeof(uint32_t) != 0UL)
1242     {
1243         /* make the data length as word-aligned */
1244         dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1245     }
1246 
1247     /* Check if ADMA descriptor's number is enough. */
1248     if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1249     {
1250         miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1251     }
1252     else
1253     {
1254         miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1255     }
1256 
1257     /* ADMA1 needs two descriptors to finish a transfer */
1258     miniEntries <<= 1UL;
1259 
1260     if (miniEntries + startEntries > maxEntries)
1261     {
1262         return kStatus_OutOfRange;
1263     }
1264 
1265     for (i = startEntries; i < (miniEntries + startEntries); i += 2UL)
1266     {
1267         if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1268         {
1269             dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1270         }
1271         else
1272         {
1273             dmaBufferLen = dataBytes;
1274         }
1275 
1276         adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
1277         adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength;
1278         adma1EntryAddress[i + 1UL] = (uint32_t)(data);
1279         adma1EntryAddress[i + 1UL] |=
1280             (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma1DescriptorInterrupFlag;
1281         data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1282         dataBytes -= dmaBufferLen;
1283     }
1284     /* the end of the descriptor */
1285     adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag;
1286 
1287     return kStatus_Success;
1288 }
1289 
1290 /*!
1291  * brief Sets the ADMA2 descriptor table configuration.
1292  *
1293  * param admaTable Adma table address.
1294  * param admaTableWords Adma table length.
1295  * param dataBufferAddr Data buffer address.
1296  * param dataBytes Data Data length.
1297  * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1298  *  reference _usdhc_adma_flag.
1299  * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1300  * retval kStatus_Success Operate successfully.
1301  */
1302 status_t USDHC_SetADMA2Descriptor(
1303     uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1304 {
1305     assert(NULL != admaTable);
1306     assert(NULL != dataBufferAddr);
1307 
1308     uint32_t miniEntries, startEntries = 0UL,
1309                           maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
1310     usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable);
1311     uint32_t i, dmaBufferLen = 0UL;
1312     const uint32_t *data = dataBufferAddr;
1313 
1314     if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1315     {
1316         return kStatus_USDHC_DMADataAddrNotAlign;
1317     }
1318     /*
1319      * Add non aligned access support ,user need make sure your buffer size is big
1320      * enough to hold the data,in other words,user need make sure the buffer size
1321      * is 4 byte aligned
1322      */
1323     if (dataBytes % sizeof(uint32_t) != 0UL)
1324     {
1325         /* make the data length as word-aligned */
1326         dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1327     }
1328 
1329     /* Check if ADMA descriptor's number is enough. */
1330     if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1331     {
1332         miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1333     }
1334     else
1335     {
1336         miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1337     }
1338     /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
1339     data adress and data size is enough */
1340     if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1341     {
1342         for (i = 0UL; i < maxEntries; i++)
1343         {
1344             if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL)
1345             {
1346                 break;
1347             }
1348         }
1349         startEntries = i;
1350         /* add one entry for dummy entry */
1351         miniEntries += 1UL;
1352     }
1353 
1354     if ((miniEntries + startEntries) > maxEntries)
1355     {
1356         return kStatus_OutOfRange;
1357     }
1358 
1359     for (i = startEntries; i < (miniEntries + startEntries); i++)
1360     {
1361         if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1362         {
1363             dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1364         }
1365         else
1366         {
1367             dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) :
1368                                                dataBytes); /* adma don't support 0 data length transfer descriptor */
1369         }
1370 
1371         /* Each descriptor for ADMA2 is 64-bit in length */
1372         adma2EntryAddress[i].address   = (dataBytes == 0UL) ? &s_usdhcBootDummy : data;
1373         adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
1374         adma2EntryAddress[i].attribute |=
1375             (dataBytes == 0UL) ?
1376                 0UL :
1377                 ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag);
1378         data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1379 
1380         if (dataBytes != 0UL)
1381         {
1382             dataBytes -= dmaBufferLen;
1383         }
1384     }
1385 
1386     /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
1387     engine
1388     will not stop at block gap */
1389     if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1390     {
1391         adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer;
1392     }
1393     else
1394     {
1395         /* set the end bit */
1396         adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag;
1397     }
1398 
1399     return kStatus_Success;
1400 }
1401 
1402 /*!
1403  * brief Internal DMA configuration.
1404  * This function is used to config the USDHC DMA related registers.
1405  * param base USDHC peripheral base address.
1406  * param adma configuration
1407  * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
1408  * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to
1409  * false.
1410  * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1411  * retval kStatus_Success Operate successfully.
1412  */
1413 status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
1414                                     usdhc_adma_config_t *dmaConfig,
1415                                     const uint32_t *dataAddr,
1416                                     bool enAutoCmd23)
1417 {
1418     assert(dmaConfig != NULL);
1419     assert(dataAddr != NULL);
1420     assert((NULL != dmaConfig->admaTable) &&
1421            (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1422 
1423 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1424     /* disable the external DMA if support */
1425     base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1426 #endif
1427 
1428     if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1429     {
1430         /* check DMA data buffer address align or not */
1431         if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1432         {
1433             return kStatus_USDHC_DMADataAddrNotAlign;
1434         }
1435         /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
1436              and block count should load to DS_ADDR*/
1437         if (enAutoCmd23)
1438         {
1439             base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1440         }
1441         else
1442         {
1443             base->DS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1444         }
1445     }
1446     else
1447     {
1448         /* When use ADMA, disable simple DMA */
1449         base->DS_ADDR       = 0UL;
1450         base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)(dmaConfig->admaTable));
1451     }
1452 
1453 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
1454     /* select DMA mode and config the burst length */
1455     base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1456     base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1457 #else
1458     /* select DMA mode and config the burst length */
1459     base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
1460     base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
1461 #endif
1462     /* enable DMA */
1463     base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1464 
1465     return kStatus_Success;
1466 }
1467 
1468 /*!
1469  * brief Sets the DMA descriptor table configuration.
1470  * A high level DMA descriptor configuration function.
1471  * param base USDHC peripheral base address.
1472  * param adma configuration
1473  * param data Data descriptor
1474  * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1475  *  reference _usdhc_adma_flag
1476  * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1477  * retval kStatus_Success Operate successfully.
1478  */
1479 status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
1480                                   usdhc_adma_config_t *dmaConfig,
1481                                   usdhc_data_t *dataConfig,
1482                                   uint32_t flags)
1483 {
1484     assert(NULL != dmaConfig);
1485     assert((NULL != dmaConfig->admaTable) &&
1486            (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1487     assert(NULL != dataConfig);
1488 
1489     status_t error = kStatus_Fail;
1490     uint32_t bootDummyOffset =
1491         dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL;
1492     const uint32_t *data = (const uint32_t *)USDHC_ADDR_CPU_2_DMA((uint32_t)(
1493         (uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + bootDummyOffset));
1494     uint32_t blockSize   = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
1495 
1496 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1497     if (dmaConfig->dmaMode == kUSDHC_ExternalDMA)
1498     {
1499         /* enable the external DMA */
1500         base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1501     }
1502     else
1503 #endif
1504         if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1505     {
1506         error = kStatus_Success;
1507     }
1508     else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1509     {
1510         error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1511     }
1512     /* ADMA2 */
1513     else
1514     {
1515         error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1516     }
1517 
1518     /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
1519      * boot data, only the DMA descriptor need update */
1520     if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
1521         (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous))
1522     {
1523         error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
1524     }
1525 
1526     return error;
1527 }
1528 
1529 /*!
1530  * brief Transfers the command/data using a blocking method.
1531  *
1532  * This function waits until the command response/data is received or the USDHC encounters an error by polling the
1533  * status
1534  * flag.
1535  * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1536  * the re-entry mechanism.
1537  *
1538  * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API.
1539  *
1540  * param base USDHC peripheral base address.
1541  * param adma configuration
1542  * param transfer Transfer content.
1543  * retval kStatus_InvalidArgument Argument is invalid.
1544  * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1545  * retval kStatus_USDHC_SendCommandFailed Send command failed.
1546  * retval kStatus_USDHC_TransferDataFailed Transfer data failed.
1547  * retval kStatus_Success Operate successfully.
1548  */
1549 status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
1550 {
1551     assert(transfer != NULL);
1552 
1553     status_t error           = kStatus_Fail;
1554     usdhc_command_t *command = transfer->command;
1555     usdhc_data_t *data       = transfer->data;
1556     bool enDMA               = true;
1557     bool executeTuning       = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1558     uint32_t transferFlags   = (uint32_t)kUSDHC_CommandOnly;
1559     size_t blockSize         = 0U;
1560     size_t blockCount        = 0U;
1561 
1562 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1563     /*check re-tuning request*/
1564     if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL)
1565     {
1566         USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1567         return kStatus_USDHC_ReTuningRequest;
1568     }
1569 #endif
1570 
1571     if (data != NULL)
1572     {
1573         /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1574         if ((dmaConfig != NULL) && (!executeTuning))
1575         {
1576             error = USDHC_SetAdmaTableConfig(base, dmaConfig, data,
1577                                              (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ?
1578                                                             kUSDHC_AdmaDescriptorMultipleFlag :
1579                                                             kUSDHC_AdmaDescriptorSingleFlag));
1580         }
1581         blockSize     = data->blockSize;
1582         blockCount    = data->blockCount;
1583         transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1584         transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1585         transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1586         transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1587         transferFlags |=
1588             data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1589 
1590         command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1591     }
1592 
1593     /* if the DMA desciptor configure fail or not needed , disable it */
1594     if (error != kStatus_Success)
1595     {
1596         enDMA = false;
1597         /* disable DMA, using polling mode in this situation */
1598         USDHC_EnableInternalDMA(base, false);
1599     }
1600 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1601     else
1602     {
1603         if (data->txData != NULL)
1604         {
1605             /* clear the DCACHE */
1606             DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1607         }
1608         else
1609         {
1610             /* clear the DCACHE */
1611             DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1612         }
1613     }
1614 #endif
1615 
1616     /* config the data transfer parameter */
1617     error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1618     if (error != kStatus_Success)
1619     {
1620         return error;
1621     }
1622     /* send command first */
1623     USDHC_SendCommand(base, command);
1624     /* wait command done */
1625     error =
1626         USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal));
1627     if (kStatus_Success != error)
1628     {
1629         return kStatus_USDHC_SendCommandFailed;
1630     }
1631 
1632     /* wait transfer data finsih */
1633     if (data != NULL)
1634     {
1635         error = USDHC_TransferDataBlocking(base, data, enDMA);
1636         if (kStatus_Success != error)
1637         {
1638             return error;
1639         }
1640     }
1641 
1642     return kStatus_Success;
1643 }
1644 
1645 #if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
1646 static status_t USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type *base,
1647                                                       usdhc_adma_config_t *dmaConfig,
1648                                                       usdhc_scatter_gather_data_t *dataConfig,
1649                                                       uint32_t *totalTransferSize)
1650 {
1651     assert(NULL != dmaConfig);
1652     assert((NULL != dmaConfig->admaTable) &&
1653            (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1654     assert(NULL != dataConfig);
1655 
1656     status_t error                               = kStatus_Fail;
1657     uint32_t *admaDesBuffer                      = dmaConfig->admaTable;
1658     uint32_t admaDesLen                          = dmaConfig->admaTableWords;
1659     usdhc_scatter_gather_data_list_t *sgDataList = &dataConfig->sgData;
1660     uint32_t oneDescriptorMaxTransferSize        = dmaConfig->dmaMode == kUSDHC_DmaModeAdma1 ?
1661                                                 USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY :
1662                                                 USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1663     uint32_t miniEntries = 0U;
1664 
1665     while (sgDataList != NULL)
1666     {
1667         if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1668         {
1669             error = USDHC_SetADMA1Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1670         }
1671         /* ADMA2 */
1672         else
1673         {
1674             error = USDHC_SetADMA2Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1675         }
1676 
1677         if (error != kStatus_Success)
1678         {
1679             return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1680         }
1681 
1682 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1683         if (dataConfig->dataDirection == kUSDHC_TransferDirectionSend)
1684         {
1685             /* clear the DCACHE */
1686             DCACHE_CleanByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1687         }
1688         else
1689         {
1690             /* clear the DCACHE */
1691             DCACHE_CleanInvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1692         }
1693 #endif
1694 
1695         *totalTransferSize += sgDataList->dataSize;
1696         if (sgDataList->dataList != NULL)
1697         {
1698             if ((sgDataList->dataSize % oneDescriptorMaxTransferSize) == 0UL)
1699             {
1700                 miniEntries = sgDataList->dataSize / oneDescriptorMaxTransferSize;
1701             }
1702             else
1703             {
1704                 miniEntries = ((sgDataList->dataSize / oneDescriptorMaxTransferSize) + 1UL);
1705             }
1706             if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1707             {
1708                 admaDesBuffer[miniEntries * 2U - 1U] &= ~kUSDHC_Adma1DescriptorEndFlag;
1709             }
1710             else
1711             {
1712                 admaDesBuffer[miniEntries * 2U - 2U] &= ~kUSDHC_Adma2DescriptorEndFlag;
1713             }
1714             admaDesBuffer += miniEntries * 2U;
1715             admaDesLen -= miniEntries * 2U;
1716         }
1717 
1718         sgDataList = sgDataList->dataList;
1719     }
1720 
1721     base->DS_ADDR       = 0UL;
1722     base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
1723 
1724     /* select DMA mode and config the burst length */
1725     base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1726     base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1727 
1728     /* enable DMA */
1729     base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1730 
1731     return error;
1732 }
1733 
1734 /*!
1735  * brief Transfers the command/scatter gather data using an interrupt and an asynchronous method.
1736  *
1737  * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
1738  * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
1739  * this API doesn't support the re-entry mechanism.
1740  * This function is target for the application would like to have scatter gather buffer to be transferred within one
1741  * read/write request, non scatter gather buffer is support by this function also.
1742  *
1743  * note Call API @ref USDHC_TransferCreateHandle when calling this API.
1744  *
1745  * param base USDHC peripheral base address.
1746  * param handle USDHC handle.
1747  * param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only.
1748  * param transfer scatter gather transfer content.
1749  *
1750  * retval #kStatus_InvalidArgument Argument is invalid.
1751  * retval #kStatus_USDHC_BusyTransferring Busy transferring.
1752  * retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1753  * retval #kStatus_Success Operate successfully.
1754  */
1755 status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base,
1756                                                     usdhc_handle_t *handle,
1757                                                     usdhc_adma_config_t *dmaConfig,
1758                                                     usdhc_scatter_gather_transfer_t *transfer)
1759 {
1760     assert(handle != NULL);
1761     assert(transfer != NULL);
1762     assert(dmaConfig != NULL);
1763 
1764     status_t error                                 = kStatus_Fail;
1765     usdhc_command_t *command                       = transfer->command;
1766     uint32_t totalTransferSize                     = 0U;
1767     uint32_t transferFlags                         = kUSDHC_CommandOnly;
1768     size_t blockSize                               = 0U;
1769     size_t blockCount                              = 0U;
1770     usdhc_scatter_gather_data_t *scatterGatherData = transfer->data;
1771     bool enDMA                                     = false;
1772 
1773     /* check data inhibit flag */
1774     if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
1775     {
1776         return kStatus_USDHC_BusyTransferring;
1777     }
1778 
1779     handle->command = command;
1780     handle->data    = scatterGatherData;
1781     /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1782     handle->transferredWords = 0UL;
1783 
1784     /* Update ADMA descriptor table according to different DMA mode(ADMA1, ADMA2).*/
1785     if (scatterGatherData != NULL)
1786     {
1787         if (scatterGatherData->sgData.dataAddr == NULL)
1788         {
1789             return kStatus_InvalidArgument;
1790         }
1791 
1792         if (scatterGatherData->dataType != (uint32_t)kUSDHC_TransferDataTuning)
1793         {
1794             if (USDHC_SetScatterGatherAdmaTableConfig(base, dmaConfig, transfer->data, &totalTransferSize) !=
1795                 kStatus_Success)
1796             {
1797                 return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1798             }
1799 
1800             enDMA = true;
1801         }
1802         blockSize     = scatterGatherData->blockSize;
1803         blockCount    = totalTransferSize / scatterGatherData->blockSize;
1804         transferFlags = scatterGatherData->enableAutoCommand12 ? kUSDHC_DataWithAutoCmd12 : 0U;
1805         transferFlags |= scatterGatherData->enableAutoCommand23 ? kUSDHC_DataWithAutoCmd23 : 0U;
1806         transferFlags |= scatterGatherData->dataDirection == kUSDHC_TransferDirectionSend ? kUSDHC_CommandAndTxData :
1807                                                                                             kUSDHC_CommandAndRxData;
1808         command->flags |= kUSDHC_DataPresentFlag;
1809     }
1810 
1811     error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1812     if (error != kStatus_Success)
1813     {
1814         return error;
1815     }
1816 
1817     /* enable interrupt per transfer request */
1818     if (scatterGatherData != NULL)
1819     {
1820         USDHC_ClearInterruptStatusFlags(
1821             base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1822                       (uint32_t)kUSDHC_CommandFlag);
1823         USDHC_EnableInterruptSignal(
1824             base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1825                       (uint32_t)kUSDHC_CommandFlag);
1826     }
1827     else
1828     {
1829         USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1830         USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1831     }
1832 
1833     /* send command first */
1834     USDHC_SendCommand(base, command);
1835 
1836     return kStatus_Success;
1837 }
1838 #else
1839 /*!
1840  * brief Transfers the command/data using an interrupt and an asynchronous method.
1841  *
1842  * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
1843  * error.
1844  * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1845  * the re-entry mechanism.
1846  *
1847  * note Call the API 'USDHC_TransferCreateHandle' when calling this API.
1848  *
1849  * param base USDHC peripheral base address.
1850  * param handle USDHC handle.
1851  * param adma configuration.
1852  * param transfer Transfer content.
1853  * retval kStatus_InvalidArgument Argument is invalid.
1854  * retval kStatus_USDHC_BusyTransferring Busy transferring.
1855  * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1856  * retval kStatus_Success Operate successfully.
1857  */
1858 status_t USDHC_TransferNonBlocking(USDHC_Type *base,
1859                                    usdhc_handle_t *handle,
1860                                    usdhc_adma_config_t *dmaConfig,
1861                                    usdhc_transfer_t *transfer)
1862 {
1863     assert(handle != NULL);
1864     assert(transfer != NULL);
1865 
1866     status_t error           = kStatus_Fail;
1867     usdhc_command_t *command = transfer->command;
1868     usdhc_data_t *data       = transfer->data;
1869     bool executeTuning       = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1870     bool enDMA               = true;
1871     uint32_t transferFlags   = (uint32_t)kUSDHC_CommandOnly;
1872     size_t blockSize         = 0U;
1873     size_t blockCount        = 0U;
1874 
1875 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1876     /*check re-tuning request*/
1877     if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL)
1878     {
1879         USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1880         return kStatus_USDHC_ReTuningRequest;
1881     }
1882 #endif
1883     /* Save command and data into handle before transferring. */
1884 
1885     handle->command = command;
1886     handle->data    = data;
1887     /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1888     handle->transferredWords = 0UL;
1889 
1890     if (data != NULL)
1891     {
1892         /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1893         if ((dmaConfig != NULL) && (!executeTuning))
1894         {
1895             error = USDHC_SetAdmaTableConfig(
1896                 base, dmaConfig, data,
1897                 (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ?
1898                                kUSDHC_AdmaDescriptorMultipleFlag :
1899                                kUSDHC_AdmaDescriptorSingleFlag));
1900         }
1901 
1902         blockSize     = data->blockSize;
1903         blockCount    = data->blockCount;
1904         transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1905         transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1906         transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1907         transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1908         transferFlags |=
1909             data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1910 
1911         command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1912     }
1913 
1914     /* if the DMA desciptor configure fail or not needed , disable it */
1915     if (error != kStatus_Success)
1916     {
1917         /* disable DMA, using polling mode in this situation */
1918         USDHC_EnableInternalDMA(base, false);
1919         enDMA = false;
1920     }
1921 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1922     else
1923     {
1924         if (data->txData != NULL)
1925         {
1926             /* clear the DCACHE */
1927             DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1928         }
1929         else
1930         {
1931             /* clear the DCACHE */
1932             DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1933         }
1934     }
1935 #endif
1936 
1937     /* config the data transfer parameter */
1938     error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1939     if (error != kStatus_Success)
1940     {
1941         return error;
1942     }
1943 
1944     /* enable interrupt per transfer request */
1945     if (handle->data != NULL)
1946     {
1947         USDHC_ClearInterruptStatusFlags(
1948             base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag |
1949                       (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1950                                      (uint32_t)kUSDHC_DmaCompleteFlag :
1951                                      0U));
1952         USDHC_EnableInterruptSignal(base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) |
1953                                               (uint32_t)kUSDHC_CommandFlag |
1954                                               (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1955                                                              (uint32_t)kUSDHC_DmaCompleteFlag :
1956                                                              0U));
1957     }
1958     else
1959     {
1960         USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1961         USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1962     }
1963 
1964     /* send command first */
1965     USDHC_SendCommand(base, command);
1966 
1967     return kStatus_Success;
1968 }
1969 #endif
1970 
1971 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1972 /*!
1973  * brief manual tuning trigger or abort
1974  * User should handle the tuning cmd and find the boundary of the delay
1975  * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS
1976  * This function should called before USDHC_AdjustDelayforSDR104 function
1977  * param base USDHC peripheral base address.
1978  * param tuning enable flag
1979  */
1980 void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
1981 {
1982     if (enable)
1983     {
1984         /* make sure std_tun_en bit is clear */
1985         base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
1986         /* disable auto tuning here */
1987         base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
1988         /* execute tuning for SDR104 mode */
1989         base->MIX_CTRL |= USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK;
1990     }
1991     else
1992     { /* abort the tuning */
1993         base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK;
1994     }
1995 }
1996 
1997 /*!
1998  * brief the SDR104 mode delay setting adjust
1999  * This function should called after USDHC_ManualTuningForSDR104
2000  * param base USDHC peripheral base address.
2001  * param delay setting configuration
2002  * retval kStatus_Fail config the delay setting fail
2003  * retval kStatus_Success config the delay setting success
2004  */
2005 status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
2006 {
2007     uint32_t clkTuneCtrl = 0UL;
2008 
2009     clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2010 
2011     clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
2012 
2013     clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
2014 
2015     /* load the delay setting */
2016     base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2017     /* check delat setting error */
2018     if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2019                           USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2020     {
2021         return kStatus_Fail;
2022     }
2023 
2024     return kStatus_Success;
2025 }
2026 
2027 /*!
2028  * brief The tuning delay cell setting.
2029  *
2030  * param base USDHC peripheral base address.
2031  * param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE.
2032  * param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT.
2033  * param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST.
2034  * retval kStatus_Fail config the delay setting fail
2035  * retval kStatus_Success config the delay setting success
2036  */
2037 status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay)
2038 {
2039     assert(preDelay <=
2040            (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_SHIFT));
2041     assert(outDelay <=
2042            (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_SHIFT));
2043     assert(postDelay <=
2044            (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_SHIFT));
2045 
2046     uint32_t clkTuneCtrl = 0UL;
2047 
2048     clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2049 
2050     clkTuneCtrl &=
2051         ~(USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK | USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK |
2052           USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK);
2053 
2054     clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(preDelay) |
2055                    USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT(outDelay) |
2056                    USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST(postDelay);
2057 
2058     /* load the delay setting */
2059     base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2060     /* check delat setting error */
2061     if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2062                           USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2063     {
2064         return kStatus_Fail;
2065     }
2066 
2067     return kStatus_Success;
2068 }
2069 
2070 /*!
2071  * brief the enable standard tuning function
2072  * The standard tuning window and tuning counter use the default config
2073  * tuning cmd is send by the software, user need to check the tuning result
2074  * can be used for SDR50,SDR104,HS200 mode tuning
2075  * param base USDHC peripheral base address.
2076  * param tuning start tap
2077  * param tuning step
2078  * param enable/disable flag
2079  */
2080 void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
2081 {
2082     uint32_t tuningCtrl = 0UL;
2083 
2084     if (enable)
2085     {
2086         /* feedback clock */
2087         base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
2088         /* config tuning start and step */
2089         tuningCtrl = base->TUNING_CTRL;
2090         tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
2091         tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
2092                        USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
2093         base->TUNING_CTRL = tuningCtrl;
2094 
2095         /* excute tuning */
2096         base->AUTOCMD12_ERR_STATUS |=
2097             (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2098     }
2099     else
2100     {
2101         /* disable the standard tuning */
2102         base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
2103         /* clear excute tuning */
2104         base->AUTOCMD12_ERR_STATUS &=
2105             ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2106     }
2107 }
2108 
2109 #if FSL_FEATURE_USDHC_HAS_HS400_MODE
2110 /*!
2111  * brief config the strobe DLL delay target and update interval
2112  *
2113  * param base USDHC peripheral base address.
2114  * param delayTarget delay target
2115  * param updateInterval update interval
2116  */
2117 void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval)
2118 {
2119     assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >>
2120                            USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT));
2121 
2122     /* reset strobe dll firstly */
2123     base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
2124     /* clear reset and other register fields */
2125     base->STROBE_DLL_CTRL = 0;
2126     /* configure the DELAY target and update interval */
2127     base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
2128                              USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) |
2129                              USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget);
2130 
2131     while (
2132         (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK |
2133                                            USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) !=
2134         ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)))
2135     {
2136     }
2137 }
2138 #endif
2139 
2140 /*!
2141  * brief the auto tuning enbale for CMD/DATA line
2142  *
2143  * param base USDHC peripheral base address.
2144  */
2145 void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
2146 {
2147     uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
2148 
2149     base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
2150 
2151     /* 1bit data width */
2152     if (busWidth == 0UL)
2153     {
2154         base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2155         base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2156     }
2157     /* 4bit data width */
2158     else if (busWidth == 1UL)
2159     {
2160         base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2161         base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2162     }
2163     /* 8bit data width */
2164     else
2165     {
2166         base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2167         base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2168     }
2169 }
2170 #endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
2171 
2172 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2173 {
2174     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag))
2175     {
2176         if (handle->callback.CardInserted != NULL)
2177         {
2178             handle->callback.CardInserted(base, handle->userData);
2179         }
2180     }
2181     else
2182     {
2183         if (handle->callback.CardRemoved != NULL)
2184         {
2185             handle->callback.CardRemoved(base, handle->userData);
2186         }
2187     }
2188 }
2189 
2190 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2191 {
2192     assert(handle->command != NULL);
2193 
2194     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag))
2195     {
2196         if (handle->callback.TransferComplete != NULL)
2197         {
2198             handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2199         }
2200     }
2201     else
2202     {
2203         /* Receive response */
2204         if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
2205         {
2206             if (handle->callback.TransferComplete != NULL)
2207             {
2208                 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2209             }
2210         }
2211         else
2212         {
2213             if (handle->callback.TransferComplete != NULL)
2214             {
2215                 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData);
2216             }
2217         }
2218     }
2219     /* disable interrupt signal and reset command pointer */
2220     USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag);
2221     handle->command = NULL;
2222 }
2223 
2224 #if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
2225 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2226 {
2227     assert(handle->data != NULL);
2228 
2229     status_t transferStatus = kStatus_USDHC_BusyTransferring;
2230 
2231     if ((!(handle->data->enableIgnoreError)) &&
2232         (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2233     {
2234         transferStatus = kStatus_USDHC_TransferDataFailed;
2235     }
2236     else
2237     {
2238         if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2239         {
2240             /* std tuning process only need to wait BRR */
2241             if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2242             {
2243                 transferStatus = kStatus_USDHC_TransferDataComplete;
2244             }
2245         }
2246         else
2247         {
2248             if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag))
2249             {
2250                 transferStatus = kStatus_USDHC_TransferDMAComplete;
2251             }
2252 
2253             if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2254             {
2255                 transferStatus = kStatus_USDHC_TransferDataComplete;
2256 
2257 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2258                 if (handle->data->dataDirection == kUSDHC_TransferDirectionReceive)
2259                 {
2260                     usdhc_scatter_gather_data_list_t *sgDataList = &handle->data->sgData;
2261                     while (sgDataList != NULL)
2262                     {
2263                         DCACHE_InvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
2264                         sgDataList = sgDataList->dataList;
2265                     }
2266                 }
2267 #endif
2268             }
2269         }
2270     }
2271 
2272     if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2273     {
2274         handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2275         USDHC_DisableInterruptSignal(
2276             base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_DmaCompleteFlag);
2277         handle->data = NULL;
2278     }
2279 }
2280 
2281 #else
2282 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2283 {
2284     assert(handle->data != NULL);
2285 
2286     status_t transferStatus   = kStatus_USDHC_BusyTransferring;
2287     uint32_t transferredWords = handle->transferredWords;
2288 
2289     if ((!(handle->data->enableIgnoreError)) &&
2290         (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2291     {
2292         transferStatus = kStatus_USDHC_TransferDataFailed;
2293     }
2294     else
2295     {
2296         if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2297         {
2298             /* std tuning process only need to wait BRR */
2299             if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2300             {
2301                 transferStatus = kStatus_USDHC_TransferDataComplete;
2302             }
2303             else
2304             {
2305                 handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords);
2306             }
2307         }
2308         else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag))
2309         {
2310             handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords);
2311         }
2312         else
2313         {
2314             if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) &&
2315                 (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous))
2316             {
2317                 *(handle->data->rxData) = s_usdhcBootDummy;
2318             }
2319 
2320             if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2321             {
2322                 transferStatus = kStatus_USDHC_TransferDataComplete;
2323 
2324 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2325                 if (handle->data->rxData != NULL)
2326                 {
2327                     DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData),
2328                                              (handle->data->blockSize) * (handle->data->blockCount));
2329                 }
2330 #endif
2331             }
2332         }
2333     }
2334 
2335     if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2336     {
2337         handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2338         USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag);
2339         handle->data = NULL;
2340     }
2341 }
2342 #endif
2343 
2344 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
2345 {
2346     if (handle->callback.SdioInterrupt != NULL)
2347     {
2348         handle->callback.SdioInterrupt(base, handle->userData);
2349     }
2350 }
2351 
2352 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
2353 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2354 {
2355     assert(handle->callback.ReTuning != NULL);
2356     /* retuning request */
2357     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag))
2358     {
2359         handle->callback.ReTuning(base, handle->userData); /* retuning fail */
2360     }
2361 }
2362 #endif
2363 
2364 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
2365 {
2366     if (handle->callback.BlockGap != NULL)
2367     {
2368         handle->callback.BlockGap(base, handle->userData);
2369     }
2370 }
2371 
2372 /*!
2373  * brief Creates the USDHC handle.
2374  *
2375  * param base USDHC peripheral base address.
2376  * param handle USDHC handle pointer.
2377  * param callback Structure pointer to contain all callback functions.
2378  * param userData Callback function parameter.
2379  */
2380 void USDHC_TransferCreateHandle(USDHC_Type *base,
2381                                 usdhc_handle_t *handle,
2382                                 const usdhc_transfer_callback_t *callback,
2383                                 void *userData)
2384 {
2385     assert(handle != NULL);
2386     assert(callback != NULL);
2387 
2388     /* Zero the handle. */
2389     (void)memset(handle, 0, sizeof(*handle));
2390 
2391     /* Set the callback. */
2392     handle->callback.CardInserted     = callback->CardInserted;
2393     handle->callback.CardRemoved      = callback->CardRemoved;
2394     handle->callback.SdioInterrupt    = callback->SdioInterrupt;
2395     handle->callback.BlockGap         = callback->BlockGap;
2396     handle->callback.TransferComplete = callback->TransferComplete;
2397     handle->callback.ReTuning         = callback->ReTuning;
2398     handle->userData                  = userData;
2399 
2400     /* Save the handle in global variables to support the double weak mechanism. */
2401     s_usdhcHandle[USDHC_GetInstance(base)] = handle;
2402 
2403     /* save IRQ handler */
2404     s_usdhcIsr = USDHC_TransferHandleIRQ;
2405 
2406     (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
2407 }
2408 
2409 /*!
2410  * brief IRQ handler for the USDHC.
2411  *
2412  * This function deals with the IRQs on the given host controller.
2413  *
2414  * param base USDHC peripheral base address.
2415  * param handle USDHC handle.
2416  */
2417 void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
2418 {
2419     assert(handle != NULL);
2420 
2421     uint32_t interruptFlags;
2422 
2423     interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base);
2424 
2425     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag))
2426     {
2427         USDHC_TransferHandleCardDetect(base, handle, interruptFlags);
2428     }
2429     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag))
2430     {
2431         USDHC_TransferHandleCommand(base, handle, interruptFlags);
2432     }
2433     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag))
2434     {
2435         USDHC_TransferHandleData(base, handle, interruptFlags);
2436     }
2437     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag))
2438     {
2439         USDHC_TransferHandleSdioInterrupt(base, handle);
2440     }
2441     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag))
2442     {
2443         USDHC_TransferHandleBlockGap(base, handle);
2444     }
2445 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
2446     if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag))
2447     {
2448         USDHC_TransferHandleReTuning(base, handle, interruptFlags);
2449     }
2450 #endif
2451     USDHC_ClearInterruptStatusFlags(base, interruptFlags);
2452 }
2453 
2454 #ifdef USDHC0
2455 void USDHC0_DriverIRQHandler(void);
2456 void USDHC0_DriverIRQHandler(void)
2457 {
2458     s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
2459     SDK_ISR_EXIT_BARRIER;
2460 }
2461 #endif
2462 
2463 #ifdef USDHC1
2464 void USDHC1_DriverIRQHandler(void);
2465 void USDHC1_DriverIRQHandler(void)
2466 {
2467     s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
2468     SDK_ISR_EXIT_BARRIER;
2469 }
2470 #endif
2471 
2472 #ifdef USDHC2
2473 void USDHC2_DriverIRQHandler(void);
2474 void USDHC2_DriverIRQHandler(void)
2475 {
2476     s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
2477     SDK_ISR_EXIT_BARRIER;
2478 }
2479 
2480 #endif