1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2021 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_usdhc.h"
10 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
11 #include "fsl_cache.h"
12 #endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
13 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
14 #include "fsl_memory.h"
15 #endif
16 /*******************************************************************************
17  * Definitions
18  ******************************************************************************/
19 
20 /* Component ID definition, used by tools. */
21 #ifndef FSL_COMPONENT_ID
22 #define FSL_COMPONENT_ID "platform.drivers.usdhc"
23 #endif
24 
25 /*! @brief Clock setting */
26 /* Max SD clock divisor from base clock */
27 #define USDHC_MAX_DVS          ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
28 #define USDHC_MAX_CLKFS        ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
29 #define USDHC_PREV_DVS(x)      ((x) -= 1U)
30 #define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
31 /*! @brief USDHC ADMA table address align size */
32 #define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U)
33 
34 /* Typedef for interrupt handler. */
35 typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
36 /*! @brief check flag avalibility */
37 #define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
38 
39 /*! @brief usdhc transfer flags */
40 enum _usdhc_transfer_flags
41 {
42     kUSDHC_CommandOnly        = 1U,  /*!< transfer command only */
43     kUSDHC_CommandAndTxData   = 2U,  /*!< transfer command and transmit data */
44     kUSDHC_CommandAndRxData   = 4U,  /*!< transfer command and receive data */
45     kUSDHC_DataWithAutoCmd12  = 8U,  /*!< transfer data with auto cmd12 enabled */
46     kUSDHC_DataWithAutoCmd23  = 16U, /*!< transfer data with auto cmd23 enabled */
47     kUSDHC_BootData           = 32U, /*!< transfer boot data */
48     kUSDHC_BootDataContinuous = 64U, /*!< transfer boot data continuous */
49 };
50 
51 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
52 #define USDHC_ADDR_CPU_2_DMA(addr) (MEMORY_ConvertMemoryMapAddress((addr), kMEMORY_Local2DMA))
53 #else
54 #define USDHC_ADDR_CPU_2_DMA(addr) (addr)
55 #endif
56 /*******************************************************************************
57  * Prototypes
58  ******************************************************************************/
59 /*!
60  * @brief Get the instance.
61  *
62  * @param base USDHC peripheral base address.
63  * @return Instance number.
64  */
65 static uint32_t USDHC_GetInstance(USDHC_Type *base);
66 
67 /*!
68  * @brief Start transfer according to current transfer state
69  *
70  * @param base USDHC peripheral base address.
71  * @param transferFlags transfer flags, @ref _usdhc_transfer_flags.
72  * @param blockSize block size.
73  * @param blockCount block count.
74  */
75 static status_t USDHC_SetTransferConfig(USDHC_Type *base,
76                                         uint32_t transferFlags,
77                                         size_t blockSize,
78                                         uint32_t blockCount);
79 
80 /*!
81  * @brief Receive command response
82  *
83  * @param base USDHC peripheral base address.
84  * @param command Command to be sent.
85  */
86 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command);
87 
88 /*!
89  * @brief Read DATAPORT when buffer enable bit is set.
90  *
91  * @param base USDHC peripheral base address.
92  * @param data Data to be read.
93  * @param transferredWords The number of data words have been transferred last time transaction.
94  * @return The number of total data words have been transferred after this time transaction.
95  */
96 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
97 
98 /*!
99  * @brief Read data by using DATAPORT polling way.
100  *
101  * @param base USDHC peripheral base address.
102  * @param data Data to be read.
103  * @retval kStatus_Fail Read DATAPORT failed.
104  * @retval kStatus_Success Operate successfully.
105  */
106 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
107 
108 /*!
109  * @brief Write DATAPORT when buffer enable bit is set.
110  *
111  * @param base USDHC peripheral base address.
112  * @param data Data to be read.
113  * @param transferredWords The number of data words have been transferred last time.
114  * @return The number of total data words have been transferred after this time transaction.
115  */
116 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
117 
118 /*!
119  * @brief Write data by using DATAPORT polling way.
120  *
121  * @param base USDHC peripheral base address.
122  * @param data Data to be transferred.
123  * @retval kStatus_Fail Write DATAPORT failed.
124  * @retval kStatus_Success Operate successfully.
125  */
126 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
127 
128 /*!
129  * @brief Transfer data by polling way.
130  *
131  * @param base USDHC peripheral base address.
132  * @param data Data to be transferred.
133  * @param use DMA flag.
134  * @retval kStatus_Fail Transfer data failed.
135  * @retval kStatus_InvalidArgument Argument is invalid.
136  * @retval kStatus_Success Operate successfully.
137  */
138 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
139 
140 /*!
141  * @brief wait command done
142  *
143  * @param base USDHC peripheral base address.
144  * @param command configuration
145  * @param pollingCmdDone polling command done flag
146  */
147 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
148 
149 /*!
150  * @brief Handle card detect interrupt.
151  *
152  * @param base USDHC peripheral base address.
153  * @param handle USDHC handle.
154  * @param interruptFlags Card detect related interrupt flags.
155  */
156 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
157 
158 /*!
159  * @brief Handle command interrupt.
160  *
161  * @param base USDHC peripheral base address.
162  * @param handle USDHC handle.
163  * @param interruptFlags Command related interrupt flags.
164  */
165 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
166 
167 /*!
168  * @brief Handle data interrupt.
169  *
170  * @param base USDHC peripheral base address.
171  * @param handle USDHC handle.
172  * @param interruptFlags Data related interrupt flags.
173  */
174 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
175 
176 /*!
177  * @brief Handle SDIO card interrupt signal.
178  *
179  * @param base USDHC peripheral base address.
180  * @param handle USDHC handle.
181  */
182 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
183 
184 /*!
185  * @brief Handle SDIO block gap event.
186  *
187  * @param base USDHC peripheral base address.
188  * @param handle USDHC handle.
189  */
190 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
191 
192 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
193 /*!
194  * @brief Handle retuning
195  *
196  * @param base USDHC peripheral base address.
197  * @param handle USDHC handle.
198  * @param interrupt flags
199  */
200 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
201 #endif
202 /*******************************************************************************
203  * Variables
204  ******************************************************************************/
205 /*! @brief USDHC base pointer array */
206 static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
207 
208 /*! @brief USDHC internal handle pointer array */
209 static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {0};
210 
211 /*! @brief USDHC IRQ name array */
212 static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
213 
214 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
215 /*! @brief USDHC clock array name */
216 static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
217 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
218 
219 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
220 /*! @brief Pointers to USDHC resets for each instance. */
221 static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS;
222 #endif
223 
224 /* USDHC ISR for transactional APIs. */
225 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
226 static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR;
227 #else
228 static usdhc_isr_t s_usdhcIsr;
229 #endif
230 /*! @brief Dummy data buffer for mmc boot mode  */
231 AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
232 
233 /*******************************************************************************
234  * Code
235  ******************************************************************************/
USDHC_GetInstance(USDHC_Type * base)236 static uint32_t USDHC_GetInstance(USDHC_Type *base)
237 {
238     uint8_t instance = 0;
239 
240     while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
241     {
242         instance++;
243     }
244 
245     assert(instance < ARRAY_SIZE(s_usdhcBase));
246 
247     return instance;
248 }
249 
USDHC_SetTransferConfig(USDHC_Type * base,uint32_t transferFlags,size_t blockSize,uint32_t blockCount)250 static status_t USDHC_SetTransferConfig(USDHC_Type *base, uint32_t transferFlags, size_t blockSize, uint32_t blockCount)
251 {
252     uint32_t mixCtrl = base->MIX_CTRL;
253 
254     if (((uint32_t)kUSDHC_CommandOnly & transferFlags) != 0U)
255     {
256         /* clear data flags */
257         mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
258                      USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK);
259 
260         if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
261         {
262             return kStatus_USDHC_BusyTransferring;
263         }
264     }
265     else
266     {
267         /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
268         if ((transferFlags & (uint32_t)kUSDHC_BootDataContinuous) != 0U)
269         {
270             /* clear stop at block gap request */
271             base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
272             /* continous transfer data */
273             base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
274             return kStatus_Success;
275         }
276 
277         /* check data inhibit flag */
278         if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag))
279         {
280             return kStatus_USDHC_BusyTransferring;
281         }
282         /* check transfer block count */
283         if ((blockCount > USDHC_MAX_BLOCK_COUNT))
284         {
285             return kStatus_InvalidArgument;
286         }
287 
288         /* config mix parameter */
289         mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
290                      USDHC_MIX_CTRL_AC12EN_MASK);
291 
292         if ((transferFlags & (uint32_t)kUSDHC_CommandAndRxData) != 0U)
293         {
294             mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
295         }
296 
297         if (blockCount > 1U)
298         {
299             mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
300             /* auto command 12 */
301             if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd12) != 0U)
302             {
303                 mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
304             }
305         }
306 
307         /* auto command 23, auto send set block count cmd before multiple read/write */
308         if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd23) != 0U)
309         {
310             mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
311             base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
312             /* config the block count to DS_ADDR */
313             base->DS_ADDR = blockCount;
314         }
315         else
316         {
317             mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
318             base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
319         }
320 
321         /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
322         if ((transferFlags & (uint32_t)kUSDHC_BootData) == 0U)
323         {
324             /* config data block size/block count */
325             base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
326                              (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
327         }
328         else
329         {
330             mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
331             base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
332         }
333     }
334     /* config the mix parameter */
335     base->MIX_CTRL = mixCtrl;
336 
337     return kStatus_Success;
338 }
339 
USDHC_SetDataConfig(USDHC_Type * base,usdhc_transfer_direction_t dataDirection,uint32_t blockCount,uint32_t blockSize)340 void USDHC_SetDataConfig(USDHC_Type *base,
341                          usdhc_transfer_direction_t dataDirection,
342                          uint32_t blockCount,
343                          uint32_t blockSize)
344 {
345     assert(blockCount <= USDHC_MAX_BLOCK_COUNT);
346 
347     uint32_t mixCtrl = base->MIX_CTRL;
348 
349     /* block attribute configuration */
350     base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
351                      (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
352 
353     /* config mix parameter */
354     mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK);
355 
356     mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U);
357 
358     base->MIX_CTRL = mixCtrl;
359 }
360 
USDHC_ReceiveCommandResponse(USDHC_Type * base,usdhc_command_t * command)361 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
362 {
363     assert(command != NULL);
364 
365     uint32_t response0 = base->CMD_RSP0;
366     uint32_t response1 = base->CMD_RSP1;
367     uint32_t response2 = base->CMD_RSP2;
368 
369     if (command->responseType != kCARD_ResponseTypeNone)
370     {
371         command->response[0U] = response0;
372         if (command->responseType == kCARD_ResponseTypeR2)
373         {
374             /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
375             after removed internal CRC7 and end bit. */
376             command->response[0U] <<= 8U;
377             command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
378             command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
379             command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U);
380         }
381     }
382 
383     /* check response error flag */
384     if ((command->responseErrorFlags != 0U) &&
385         ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
386          (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
387     {
388         if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
389         {
390             return kStatus_USDHC_SendCommandFailed;
391         }
392     }
393 
394     return kStatus_Success;
395 }
396 
USDHC_ReadDataPort(USDHC_Type * base,usdhc_data_t * data,uint32_t transferredWords)397 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
398 {
399     uint32_t i;
400     uint32_t totalWords;
401     uint32_t wordsCanBeRead; /* The words can be read at this time. */
402     uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
403 
404     /* If DMA is enable, do not need to polling data port */
405     if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
406     {
407         /*
408          * Add non aligned access support ,user need make sure your buffer size is big
409          * enough to hold the data,in other words,user need make sure the buffer size
410          * is 4 byte aligned
411          */
412         if (data->blockSize % sizeof(uint32_t) != 0U)
413         {
414             data->blockSize +=
415                 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
416         }
417 
418         totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
419 
420         /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
421         if (readWatermark >= totalWords)
422         {
423             wordsCanBeRead = totalWords;
424         }
425         /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
426         transfers watermark level words. */
427         else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
428         {
429             wordsCanBeRead = readWatermark;
430         }
431         /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
432         left
433         words. */
434         else
435         {
436             wordsCanBeRead = (totalWords - transferredWords);
437         }
438 
439         i = 0U;
440         while (i < wordsCanBeRead)
441         {
442             data->rxData[transferredWords++] = USDHC_ReadData(base);
443             i++;
444         }
445     }
446 
447     return transferredWords;
448 }
449 
USDHC_ReadByDataPortBlocking(USDHC_Type * base,usdhc_data_t * data)450 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
451 {
452     uint32_t totalWords;
453     uint32_t transferredWords = 0U, interruptStatus = 0U;
454     status_t error = kStatus_Success;
455 
456     /*
457      * Add non aligned access support ,user need make sure your buffer size is big
458      * enough to hold the data,in other words,user need make sure the buffer size
459      * is 4 byte aligned
460      */
461     if (data->blockSize % sizeof(uint32_t) != 0U)
462     {
463         data->blockSize +=
464             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
465     }
466 
467     totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
468 
469     while ((error == kStatus_Success) && (transferredWords < totalWords))
470     {
471         while (
472             !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag |
473                                                   (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
474         {
475             interruptStatus = USDHC_GetInterruptStatusFlags(base);
476         }
477 
478         /* during std tuning process, software do not need to read data, but wait BRR is enough */
479         if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) &&
480             (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag)))
481         {
482             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
483 
484             return kStatus_Success;
485         }
486 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
487         else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
488         {
489             USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
490             /* if tuning error occur ,return directly */
491             error = kStatus_USDHC_TuningError;
492         }
493 #endif
494         else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
495         {
496             if (!(data->enableIgnoreError))
497             {
498                 error = kStatus_Fail;
499             }
500             /* clear data error flag */
501             USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
502         }
503         else
504         {
505             /* Intentional empty */
506         }
507 
508         if (error == kStatus_Success)
509         {
510             transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
511             /* clear buffer read ready */
512             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
513             interruptStatus = 0U;
514         }
515     }
516 
517     /* Clear data complete flag after the last read operation. */
518     USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
519 
520     return error;
521 }
522 
USDHC_WriteDataPort(USDHC_Type * base,usdhc_data_t * data,uint32_t transferredWords)523 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
524 {
525     uint32_t i;
526     uint32_t totalWords;
527     uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
528     uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
529 
530     /* If DMA is enable, do not need to polling data port */
531     if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
532     {
533         /*
534          * Add non aligned access support ,user need make sure your buffer size is big
535          * enough to hold the data,in other words,user need make sure the buffer size
536          * is 4 byte aligned
537          */
538         if (data->blockSize % sizeof(uint32_t) != 0U)
539         {
540             data->blockSize +=
541                 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
542         }
543 
544         totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
545 
546         /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
547         if (writeWatermark >= totalWords)
548         {
549             wordsCanBeWrote = totalWords;
550         }
551         /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
552         transfers watermark level words. */
553         else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
554         {
555             wordsCanBeWrote = writeWatermark;
556         }
557         /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
558         words. */
559         else
560         {
561             wordsCanBeWrote = (totalWords - transferredWords);
562         }
563 
564         i = 0U;
565         while (i < wordsCanBeWrote)
566         {
567             USDHC_WriteData(base, data->txData[transferredWords++]);
568             i++;
569         }
570     }
571 
572     return transferredWords;
573 }
574 
USDHC_WriteByDataPortBlocking(USDHC_Type * base,usdhc_data_t * data)575 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
576 {
577     uint32_t totalWords;
578 
579     uint32_t transferredWords = 0U, interruptStatus = 0U;
580     status_t error = kStatus_Success;
581 
582     /*
583      * Add non aligned access support ,user need make sure your buffer size is big
584      * enough to hold the data,in other words,user need make sure the buffer size
585      * is 4 byte aligned
586      */
587     if (data->blockSize % sizeof(uint32_t) != 0U)
588     {
589         data->blockSize +=
590             sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
591     }
592 
593     totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
594 
595     while ((error == kStatus_Success) && (transferredWords < totalWords))
596     {
597         while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag |
598                                                         (uint32_t)kUSDHC_DataErrorFlag |
599                                                         (uint32_t)kUSDHC_TuningErrorFlag)))
600         {
601             interruptStatus = USDHC_GetInterruptStatusFlags(base);
602         }
603 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
604         if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
605         {
606             USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
607             /* if tuning error occur ,return directly */
608             return kStatus_USDHC_TuningError;
609         }
610         else
611 #endif
612             if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
613         {
614             if (!(data->enableIgnoreError))
615             {
616                 error = kStatus_Fail;
617             }
618             /* clear data error flag */
619             USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
620         }
621         else
622         {
623             /* Intentional empty */
624         }
625 
626         if (error == kStatus_Success)
627         {
628             transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
629             /* clear buffer write ready */
630             USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
631             interruptStatus = 0U;
632         }
633     }
634 
635     /* Wait write data complete or data transfer error after the last writing operation. */
636     while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)))
637     {
638         interruptStatus = USDHC_GetInterruptStatusFlags(base);
639     }
640 
641     if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL)
642     {
643         if (!(data->enableIgnoreError))
644         {
645             error = kStatus_Fail;
646         }
647     }
648     USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag));
649 
650     return error;
651 }
652 
653 /*!
654  * brief send command function
655  *
656  * param base USDHC peripheral base address.
657  * param command configuration
658  */
USDHC_SendCommand(USDHC_Type * base,usdhc_command_t * command)659 void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
660 {
661     assert(NULL != command);
662 
663     uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
664 
665     if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
666     {
667         if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) ||
668             (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7))
669         {
670             flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
671                       (uint32_t)kUSDHC_EnableIndexCheckFlag);
672         }
673         else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b))
674         {
675             flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
676                       (uint32_t)kUSDHC_EnableIndexCheckFlag);
677         }
678         else if (command->responseType == kCARD_ResponseTypeR2)
679         {
680             flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag);
681         }
682         else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4))
683         {
684             flags |= ((uint32_t)kUSDHC_ResponseLength48Flag);
685         }
686         else
687         {
688             /* Intentional empty */
689         }
690 
691         if (command->type == kCARD_CommandTypeAbort)
692         {
693             flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag;
694         }
695 
696         /* config cmd index */
697         xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
698                       USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
699 
700         xferType |=
701             (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
702              ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
703                          USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
704 
705         /* config the command xfertype and argument */
706         base->CMD_ARG     = command->argument;
707         base->CMD_XFR_TYP = xferType;
708     }
709 
710     if (command->type == kCARD_CommandTypeEmpty)
711     {
712         /* disable CMD done interrupt for empty command */
713         base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
714     }
715 }
716 
USDHC_WaitCommandDone(USDHC_Type * base,usdhc_command_t * command,bool pollingCmdDone)717 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
718 {
719     assert(NULL != command);
720 
721     status_t error           = kStatus_Success;
722     uint32_t interruptStatus = 0U;
723     /* check if need polling command done or not */
724     if (pollingCmdDone)
725     {
726         /* Wait command complete or USDHC encounters error. */
727         while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag)))
728         {
729             interruptStatus = USDHC_GetInterruptStatusFlags(base);
730         }
731 
732         if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL)
733         {
734             error = kStatus_Fail;
735         }
736 
737         /* Receive response when command completes successfully. */
738         if (error == kStatus_Success)
739         {
740             error = USDHC_ReceiveCommandResponse(base, command);
741         }
742 
743         USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
744     }
745 
746     return error;
747 }
748 
USDHC_TransferDataBlocking(USDHC_Type * base,usdhc_data_t * data,bool enDMA)749 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
750 {
751     status_t error           = kStatus_Success;
752     uint32_t interruptStatus = 0U;
753 
754     if (enDMA)
755     {
756         /* Wait data complete or USDHC encounters error. */
757         while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
758         {
759             interruptStatus = USDHC_GetInterruptStatusFlags(base);
760         }
761 
762 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
763         if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
764         {
765             error = kStatus_USDHC_TuningError;
766         }
767         else
768 #endif
769             if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
770         {
771             if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag)))
772             {
773                 error = kStatus_USDHC_TransferDataFailed;
774             }
775         }
776         else
777         {
778             /* Intentional empty */
779         }
780         /* load dummy data */
781         if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
782         {
783             *(data->rxData) = s_usdhcBootDummy;
784         }
785 
786         USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag));
787     }
788     else
789     {
790         if (data->rxData != NULL)
791         {
792             error = USDHC_ReadByDataPortBlocking(base, data);
793             if (error != kStatus_Success)
794             {
795                 return error;
796             }
797         }
798         else
799         {
800             error = USDHC_WriteByDataPortBlocking(base, data);
801             if (error != kStatus_Success)
802             {
803                 return error;
804             }
805         }
806     }
807 
808     return error;
809 }
810 
811 /*!
812  * brief USDHC module initialization function.
813  *
814  * Configures the USDHC according to the user configuration.
815  *
816  * Example:
817    code
818    usdhc_config_t config;
819    config.cardDetectDat3 = false;
820    config.endianMode = kUSDHC_EndianModeLittle;
821    config.dmaMode = kUSDHC_DmaModeAdma2;
822    config.readWatermarkLevel = 128U;
823    config.writeWatermarkLevel = 128U;
824    USDHC_Init(USDHC, &config);
825    endcode
826  *
827  * param base USDHC peripheral base address.
828  * param config USDHC configuration information.
829  * retval kStatus_Success Operate successfully.
830  */
USDHC_Init(USDHC_Type * base,const usdhc_config_t * config)831 void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
832 {
833     assert(config != NULL);
834     assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
835     assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
836 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
837     assert(config->writeBurstLen <= 16U);
838 #endif
839     uint32_t proctl, sysctl, wml;
840 
841 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
842     /* Enable USDHC clock. */
843     CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
844 #endif
845 
846 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
847     /* Reset the USDHC module */
848     RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]);
849 #endif
850 
851     /* Reset ALL USDHC. */
852     base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK;
853 
854     proctl = base->PROT_CTRL;
855     wml    = base->WTMK_LVL;
856     sysctl = base->SYS_CTRL;
857 
858     proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
859     /* Endian mode*/
860     proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
861 
862 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
863     /* Watermark level */
864     wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK);
865     wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel));
866 #else
867     /* Watermark level */
868     wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
869              USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
870     wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
871             USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
872 #endif
873 
874     /* config the data timeout value */
875     sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
876     sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
877 
878     base->SYS_CTRL  = sysctl;
879     base->WTMK_LVL  = wml;
880     base->PROT_CTRL = proctl;
881 
882 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
883     /* disable external DMA */
884     base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
885 #endif
886     /* disable internal DMA and DDR mode */
887     base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
888     /* disable interrupt, enable all the interrupt status, clear status. */
889     base->INT_STATUS_EN = kUSDHC_AllInterruptFlags;
890     base->INT_SIGNAL_EN = 0UL;
891     base->INT_STATUS    = kUSDHC_AllInterruptFlags;
892 }
893 
894 /*!
895  * brief Deinitializes the USDHC.
896  *
897  * param base USDHC peripheral base address.
898  */
USDHC_Deinit(USDHC_Type * base)899 void USDHC_Deinit(USDHC_Type *base)
900 {
901 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
902     /* Disable clock. */
903     CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
904 #endif
905 }
906 
907 /*!
908  * brief Resets the USDHC.
909  *
910  * param base USDHC peripheral base address.
911  * param mask The reset type mask(_usdhc_reset).
912  * param timeout Timeout for reset.
913  * retval true Reset successfully.
914  * retval false Reset failed.
915  */
USDHC_Reset(USDHC_Type * base,uint32_t mask,uint32_t timeout)916 bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
917 {
918     base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK
919 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
920                                | USDHC_SYS_CTRL_RSTT_MASK
921 #endif
922                                ));
923     /* Delay some time to wait reset success. */
924     while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask))
925     {
926         if (timeout == 0UL)
927         {
928             break;
929         }
930         timeout--;
931     }
932 
933     return ((0UL == timeout) ? false : true);
934 }
935 
936 /*!
937  * brief Gets the capability information.
938  *
939  * param base USDHC peripheral base address.
940  * param capability Structure to save capability information.
941  */
USDHC_GetCapability(USDHC_Type * base,usdhc_capability_t * capability)942 void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
943 {
944     assert(capability != NULL);
945 
946     uint32_t htCapability;
947     uint32_t maxBlockLength;
948 
949     htCapability = base->HOST_CTRL_CAP;
950 
951     /* Get the capability of USDHC. */
952     maxBlockLength             = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
953     capability->maxBlockLength = (512UL << maxBlockLength);
954     /* Other attributes not in HTCAPBLT register. */
955     capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
956     capability->flags =
957         (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK |
958                          USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK));
959     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK;
960     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
961     capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
962 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
963     capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
964 #endif
965 
966 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
967     capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
968 #endif
969     /* USDHC support 4/8 bit data bus width. */
970     capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
971 }
972 
973 /*!
974  * brief Sets the SD bus clock frequency.
975  *
976  * param base USDHC peripheral base address.
977  * param srcClock_Hz USDHC source clock frequency united in Hz.
978  * param busClock_Hz SD bus clock frequency united in Hz.
979  *
980  * return The nearest frequency of busClock_Hz configured to SD bus.
981  */
USDHC_SetSdClock(USDHC_Type * base,uint32_t srcClock_Hz,uint32_t busClock_Hz)982 uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
983 {
984     assert(srcClock_Hz != 0U);
985     assert(busClock_Hz != 0U);
986 
987     uint32_t totalDiv         = 0UL;
988     uint32_t divisor          = 0UL;
989     uint32_t prescaler        = 0UL;
990     uint32_t sysctl           = 0UL;
991     uint32_t nearestFrequency = 0UL;
992 
993     if (busClock_Hz > srcClock_Hz)
994     {
995         busClock_Hz = srcClock_Hz;
996     }
997 
998     totalDiv = srcClock_Hz / busClock_Hz;
999 
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  */
USDHC_SetCardActive(USDHC_Type * base,uint32_t timeout)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  */
USDHC_EnableDDRMode(USDHC_Type * base,bool enable,uint32_t nibblePos)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  */
USDHC_SetMmcBootConfig(USDHC_Type * base,const usdhc_boot_config_t * config)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  */
USDHC_SetADMA1Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)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  */
USDHC_SetADMA2Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)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  */
USDHC_SetInternalDmaConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,const uint32_t * dataAddr,bool enAutoCmd23)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  */
USDHC_SetAdmaTableConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_data_t * dataConfig,uint32_t flags)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  */
USDHC_TransferBlocking(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)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
USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_scatter_gather_data_t * dataConfig,uint32_t * totalTransferSize)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  */
USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_scatter_gather_transfer_t * transfer)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  */
USDHC_TransferNonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)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  */
USDHC_EnableManualTuning(USDHC_Type * base,bool enable)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  */
USDHC_AdjustDelayForManualTuning(USDHC_Type * base,uint32_t delay)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  */
USDHC_SetTuningDelay(USDHC_Type * base,uint32_t preDelay,uint32_t outDelay,uint32_t postDelay)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  */
USDHC_EnableStandardTuning(USDHC_Type * base,uint32_t tuningStartTap,uint32_t step,bool enable)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  */
USDHC_ConfigStrobeDLL(USDHC_Type * base,uint32_t delayTarget,uint32_t updateInterval)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  */
USDHC_EnableAutoTuningForCmdAndData(USDHC_Type * base)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 
USDHC_TransferHandleCardDetect(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)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 
USDHC_TransferHandleCommand(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)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
USDHC_TransferHandleData(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)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
USDHC_TransferHandleData(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)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 
USDHC_TransferHandleSdioInterrupt(USDHC_Type * base,usdhc_handle_t * handle)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)
USDHC_TransferHandleReTuning(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)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 
USDHC_TransferHandleBlockGap(USDHC_Type * base,usdhc_handle_t * handle)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  */
USDHC_TransferCreateHandle(USDHC_Type * base,usdhc_handle_t * handle,const usdhc_transfer_callback_t * callback,void * userData)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  */
USDHC_TransferHandleIRQ(USDHC_Type * base,usdhc_handle_t * handle)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);
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);
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);
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
2481