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 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_VS18) && FSL_FEATURE_USDHC_HAS_NO_VS18)
961 capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
962 #endif
963 capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
964 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
965 capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
966 #endif
967
968 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
969 capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
970 #endif
971 /* USDHC support 4/8 bit data bus width. */
972 capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
973 }
974
975 /*!
976 * brief Sets the SD bus clock frequency.
977 *
978 * param base USDHC peripheral base address.
979 * param srcClock_Hz USDHC source clock frequency united in Hz.
980 * param busClock_Hz SD bus clock frequency united in Hz.
981 *
982 * return The nearest frequency of busClock_Hz configured to SD bus.
983 */
USDHC_SetSdClock(USDHC_Type * base,uint32_t srcClock_Hz,uint32_t busClock_Hz)984 uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
985 {
986 assert(srcClock_Hz != 0U);
987 assert(busClock_Hz != 0U);
988
989 uint32_t totalDiv = 0UL;
990 uint32_t divisor = 0UL;
991 uint32_t prescaler = 0UL;
992 uint32_t sysctl = 0UL;
993 uint32_t nearestFrequency = 0UL;
994
995 if (busClock_Hz > srcClock_Hz)
996 {
997 busClock_Hz = srcClock_Hz;
998 }
999
1000 totalDiv = srcClock_Hz / busClock_Hz;
1001
1002 /* calucate total divisor first */
1003 if (totalDiv > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
1004 {
1005 return 0UL;
1006 }
1007
1008 if (totalDiv != 0UL)
1009 {
1010 /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
1011 if ((srcClock_Hz / totalDiv) > busClock_Hz)
1012 {
1013 totalDiv++;
1014 }
1015
1016 /* divide the total divisor to div and prescaler */
1017 if (totalDiv > USDHC_MAX_DVS)
1018 {
1019 prescaler = totalDiv / USDHC_MAX_DVS;
1020 /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
1021 while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL))
1022 {
1023 prescaler++;
1024 }
1025 /* calucate the divisor */
1026 divisor = totalDiv / prescaler;
1027 /* fine tuning the divisor until divisor * prescaler >= totalDiv */
1028 while ((divisor * prescaler) < totalDiv)
1029 {
1030 divisor++;
1031 if (divisor > USDHC_MAX_DVS)
1032 {
1033 prescaler <<= 1UL;
1034 if (prescaler > USDHC_MAX_CLKFS)
1035 {
1036 return 0UL;
1037 }
1038 divisor = totalDiv / prescaler;
1039 }
1040 }
1041 }
1042 else
1043 {
1044 /* in this situation , divsior and SDCLKFS can generate same clock
1045 use SDCLKFS*/
1046 if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL))
1047 {
1048 divisor = totalDiv;
1049 prescaler = 1UL;
1050 }
1051 else
1052 {
1053 divisor = 1UL;
1054 prescaler = totalDiv;
1055 }
1056 }
1057 nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler;
1058 }
1059 /* in this condition , srcClock_Hz = busClock_Hz, */
1060 else
1061 {
1062 /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
1063 totoal divider = 2U */
1064 divisor = 0UL;
1065 prescaler = 0UL;
1066 nearestFrequency = srcClock_Hz;
1067 }
1068
1069 /* calucate the value write to register */
1070 if (divisor != 0UL)
1071 {
1072 USDHC_PREV_DVS(divisor);
1073 }
1074 /* calucate the value write to register */
1075 if (prescaler != 0UL)
1076 {
1077 USDHC_PREV_CLKFS(prescaler, 1UL);
1078 }
1079
1080 /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
1081 sysctl = base->SYS_CTRL;
1082 sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
1083 sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
1084 base->SYS_CTRL = sysctl;
1085
1086 /* Wait until the SD clock is stable. */
1087 while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK))
1088 {
1089 }
1090
1091 return nearestFrequency;
1092 }
1093
1094 /*!
1095 * brief Sends 80 clocks to the card to set it to the active state.
1096 *
1097 * This function must be called each time the card is inserted to ensure that the card can receive the command
1098 * correctly.
1099 *
1100 * param base USDHC peripheral base address.
1101 * param timeout Timeout to initialize card.
1102 * retval true Set card active successfully.
1103 * retval false Set card active failed.
1104 */
USDHC_SetCardActive(USDHC_Type * base,uint32_t timeout)1105 bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
1106 {
1107 base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
1108 /* Delay some time to wait card become active state. */
1109 while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK))
1110 {
1111 if (0UL == timeout)
1112 {
1113 break;
1114 }
1115 timeout--;
1116 }
1117
1118 return ((0UL == timeout) ? false : true);
1119 }
1120
1121 /*!
1122 * brief the enable/disable DDR mode
1123 *
1124 * param base USDHC peripheral base address.
1125 * param enable/disable flag
1126 * param nibble position
1127 */
USDHC_EnableDDRMode(USDHC_Type * base,bool enable,uint32_t nibblePos)1128 void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
1129 {
1130 uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
1131
1132 if (enable)
1133 {
1134 base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
1135 base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
1136 prescaler >>= 1UL;
1137 }
1138 else
1139 {
1140 base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
1141
1142 if (prescaler == 0UL)
1143 {
1144 prescaler += 1UL;
1145 }
1146 else
1147 {
1148 prescaler <<= 1UL;
1149 }
1150 }
1151
1152 base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
1153 }
1154
1155 /*!
1156 * brief Configures the MMC boot feature.
1157 *
1158 * Example:
1159 code
1160 usdhc_boot_config_t config;
1161 config.ackTimeoutCount = 4;
1162 config.bootMode = kUSDHC_BootModeNormal;
1163 config.blockCount = 5;
1164 config.enableBootAck = true;
1165 config.enableBoot = true;
1166 config.enableAutoStopAtBlockGap = true;
1167 USDHC_SetMmcBootConfig(USDHC, &config);
1168 endcode
1169 *
1170 * param base USDHC peripheral base address.
1171 * param config The MMC boot configuration information.
1172 */
USDHC_SetMmcBootConfig(USDHC_Type * base,const usdhc_boot_config_t * config)1173 void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
1174 {
1175 assert(config != NULL);
1176 assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
1177 assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
1178
1179 uint32_t mmcboot = base->MMC_BOOT;
1180
1181 mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
1182 mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
1183
1184 if (config->enableBootAck)
1185 {
1186 mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
1187 }
1188 if (config->enableAutoStopAtBlockGap)
1189 {
1190 mmcboot |=
1191 USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
1192 /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
1193 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1194 (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
1195 }
1196 else
1197 {
1198 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1199 (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
1200 }
1201
1202 base->MMC_BOOT = mmcboot;
1203 }
1204
1205 /*!
1206 * brief Sets the ADMA1 descriptor table configuration.
1207 *
1208 * param admaTable Adma table address.
1209 * param admaTableWords Adma table length.
1210 * param dataBufferAddr Data buffer address.
1211 * param dataBytes Data length.
1212 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1213 * reference _usdhc_adma_flag.
1214 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1215 * retval kStatus_Success Operate successfully.
1216 */
USDHC_SetADMA1Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)1217 status_t USDHC_SetADMA1Descriptor(
1218 uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1219 {
1220 assert(NULL != admaTable);
1221 assert(NULL != dataBufferAddr);
1222
1223 uint32_t miniEntries, startEntries = 0UL,
1224 maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
1225 usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable);
1226 uint32_t i, dmaBufferLen = 0UL;
1227 const uint32_t *data = dataBufferAddr;
1228
1229 if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL)
1230 {
1231 return kStatus_USDHC_DMADataAddrNotAlign;
1232 }
1233
1234 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1235 {
1236 return kStatus_USDHC_NotSupport;
1237 }
1238 /*
1239 * Add non aligned access support ,user need make sure your buffer size is big
1240 * enough to hold the data,in other words,user need make sure the buffer size
1241 * is 4 byte aligned
1242 */
1243 if (dataBytes % sizeof(uint32_t) != 0UL)
1244 {
1245 /* make the data length as word-aligned */
1246 dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1247 }
1248
1249 /* Check if ADMA descriptor's number is enough. */
1250 if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1251 {
1252 miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1253 }
1254 else
1255 {
1256 miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1257 }
1258
1259 /* ADMA1 needs two descriptors to finish a transfer */
1260 miniEntries <<= 1UL;
1261
1262 if (miniEntries + startEntries > maxEntries)
1263 {
1264 return kStatus_OutOfRange;
1265 }
1266
1267 for (i = startEntries; i < (miniEntries + startEntries); i += 2UL)
1268 {
1269 if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1270 {
1271 dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1272 }
1273 else
1274 {
1275 dmaBufferLen = dataBytes;
1276 }
1277
1278 adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
1279 adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength;
1280 adma1EntryAddress[i + 1UL] = (uint32_t)(data);
1281 adma1EntryAddress[i + 1UL] |=
1282 (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma1DescriptorInterrupFlag;
1283 data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1284 dataBytes -= dmaBufferLen;
1285 }
1286 /* the end of the descriptor */
1287 adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag;
1288
1289 return kStatus_Success;
1290 }
1291
1292 /*!
1293 * brief Sets the ADMA2 descriptor table configuration.
1294 *
1295 * param admaTable Adma table address.
1296 * param admaTableWords Adma table length.
1297 * param dataBufferAddr Data buffer address.
1298 * param dataBytes Data Data length.
1299 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1300 * reference _usdhc_adma_flag.
1301 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1302 * retval kStatus_Success Operate successfully.
1303 */
USDHC_SetADMA2Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)1304 status_t USDHC_SetADMA2Descriptor(
1305 uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1306 {
1307 assert(NULL != admaTable);
1308 assert(NULL != dataBufferAddr);
1309
1310 uint32_t miniEntries, startEntries = 0UL,
1311 maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
1312 usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable);
1313 uint32_t i, dmaBufferLen = 0UL;
1314 const uint32_t *data = dataBufferAddr;
1315
1316 if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1317 {
1318 return kStatus_USDHC_DMADataAddrNotAlign;
1319 }
1320 /*
1321 * Add non aligned access support ,user need make sure your buffer size is big
1322 * enough to hold the data,in other words,user need make sure the buffer size
1323 * is 4 byte aligned
1324 */
1325 if (dataBytes % sizeof(uint32_t) != 0UL)
1326 {
1327 /* make the data length as word-aligned */
1328 dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1329 }
1330
1331 /* Check if ADMA descriptor's number is enough. */
1332 if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1333 {
1334 miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1335 }
1336 else
1337 {
1338 miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1339 }
1340 /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
1341 data adress and data size is enough */
1342 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1343 {
1344 for (i = 0UL; i < maxEntries; i++)
1345 {
1346 if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL)
1347 {
1348 break;
1349 }
1350 }
1351 startEntries = i;
1352 /* add one entry for dummy entry */
1353 miniEntries += 1UL;
1354 }
1355
1356 if ((miniEntries + startEntries) > maxEntries)
1357 {
1358 return kStatus_OutOfRange;
1359 }
1360
1361 for (i = startEntries; i < (miniEntries + startEntries); i++)
1362 {
1363 if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1364 {
1365 dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1366 }
1367 else
1368 {
1369 dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) :
1370 dataBytes); /* adma don't support 0 data length transfer descriptor */
1371 }
1372
1373 /* Each descriptor for ADMA2 is 64-bit in length */
1374 adma2EntryAddress[i].address = (dataBytes == 0UL) ? &s_usdhcBootDummy : data;
1375 adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
1376 adma2EntryAddress[i].attribute |=
1377 (dataBytes == 0UL) ?
1378 0UL :
1379 ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag);
1380 data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1381
1382 if (dataBytes != 0UL)
1383 {
1384 dataBytes -= dmaBufferLen;
1385 }
1386 }
1387
1388 /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
1389 engine
1390 will not stop at block gap */
1391 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1392 {
1393 adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer;
1394 }
1395 else
1396 {
1397 /* set the end bit */
1398 adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag;
1399 }
1400
1401 return kStatus_Success;
1402 }
1403
1404 /*!
1405 * brief Internal DMA configuration.
1406 * This function is used to config the USDHC DMA related registers.
1407 * param base USDHC peripheral base address.
1408 * param adma configuration
1409 * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
1410 * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to
1411 * false.
1412 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1413 * retval kStatus_Success Operate successfully.
1414 */
USDHC_SetInternalDmaConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,const uint32_t * dataAddr,bool enAutoCmd23)1415 status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
1416 usdhc_adma_config_t *dmaConfig,
1417 const uint32_t *dataAddr,
1418 bool enAutoCmd23)
1419 {
1420 assert(dmaConfig != NULL);
1421 assert(dataAddr != NULL);
1422 assert((NULL != dmaConfig->admaTable) &&
1423 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1424
1425 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1426 /* disable the external DMA if support */
1427 base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1428 #endif
1429
1430 if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1431 {
1432 /* check DMA data buffer address align or not */
1433 if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1434 {
1435 return kStatus_USDHC_DMADataAddrNotAlign;
1436 }
1437 /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
1438 and block count should load to DS_ADDR*/
1439 if (enAutoCmd23)
1440 {
1441 base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1442 }
1443 else
1444 {
1445 base->DS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1446 }
1447 }
1448 else
1449 {
1450 /* When use ADMA, disable simple DMA */
1451 base->DS_ADDR = 0UL;
1452 base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)(dmaConfig->admaTable));
1453 }
1454
1455 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
1456 /* select DMA mode and config the burst length */
1457 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1458 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1459 #else
1460 /* select DMA mode and config the burst length */
1461 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
1462 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
1463 #endif
1464 /* enable DMA */
1465 base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1466
1467 return kStatus_Success;
1468 }
1469
1470 /*!
1471 * brief Sets the DMA descriptor table configuration.
1472 * A high level DMA descriptor configuration function.
1473 * param base USDHC peripheral base address.
1474 * param adma configuration
1475 * param data Data descriptor
1476 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1477 * reference _usdhc_adma_flag
1478 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1479 * retval kStatus_Success Operate successfully.
1480 */
USDHC_SetAdmaTableConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_data_t * dataConfig,uint32_t flags)1481 status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
1482 usdhc_adma_config_t *dmaConfig,
1483 usdhc_data_t *dataConfig,
1484 uint32_t flags)
1485 {
1486 assert(NULL != dmaConfig);
1487 assert((NULL != dmaConfig->admaTable) &&
1488 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1489 assert(NULL != dataConfig);
1490
1491 status_t error = kStatus_Fail;
1492 uint32_t bootDummyOffset =
1493 dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL;
1494 const uint32_t *data = (const uint32_t *)USDHC_ADDR_CPU_2_DMA((uint32_t)(
1495 (uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + bootDummyOffset));
1496 uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
1497
1498 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1499 if (dmaConfig->dmaMode == kUSDHC_ExternalDMA)
1500 {
1501 /* enable the external DMA */
1502 base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1503 }
1504 else
1505 #endif
1506 if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1507 {
1508 error = kStatus_Success;
1509 }
1510 else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1511 {
1512 error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1513 }
1514 /* ADMA2 */
1515 else
1516 {
1517 error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1518 }
1519
1520 /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
1521 * boot data, only the DMA descriptor need update */
1522 if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
1523 (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous))
1524 {
1525 error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
1526 }
1527
1528 return error;
1529 }
1530
1531 /*!
1532 * brief Transfers the command/data using a blocking method.
1533 *
1534 * This function waits until the command response/data is received or the USDHC encounters an error by polling the
1535 * status
1536 * flag.
1537 * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1538 * the re-entry mechanism.
1539 *
1540 * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API.
1541 *
1542 * param base USDHC peripheral base address.
1543 * param adma configuration
1544 * param transfer Transfer content.
1545 * retval kStatus_InvalidArgument Argument is invalid.
1546 * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1547 * retval kStatus_USDHC_SendCommandFailed Send command failed.
1548 * retval kStatus_USDHC_TransferDataFailed Transfer data failed.
1549 * retval kStatus_Success Operate successfully.
1550 */
USDHC_TransferBlocking(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)1551 status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
1552 {
1553 assert(transfer != NULL);
1554
1555 status_t error = kStatus_Fail;
1556 usdhc_command_t *command = transfer->command;
1557 usdhc_data_t *data = transfer->data;
1558 bool enDMA = true;
1559 bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1560 uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
1561 size_t blockSize = 0U;
1562 size_t blockCount = 0U;
1563
1564 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1565 /*check re-tuning request*/
1566 if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL)
1567 {
1568 USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1569 return kStatus_USDHC_ReTuningRequest;
1570 }
1571 #endif
1572
1573 if (data != NULL)
1574 {
1575 /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1576 if ((dmaConfig != NULL) && (!executeTuning))
1577 {
1578 error = USDHC_SetAdmaTableConfig(base, dmaConfig, data,
1579 (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ?
1580 kUSDHC_AdmaDescriptorMultipleFlag :
1581 kUSDHC_AdmaDescriptorSingleFlag));
1582 }
1583 blockSize = data->blockSize;
1584 blockCount = data->blockCount;
1585 transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1586 transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1587 transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1588 transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1589 transferFlags |=
1590 data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1591
1592 command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1593 }
1594
1595 /* if the DMA desciptor configure fail or not needed , disable it */
1596 if (error != kStatus_Success)
1597 {
1598 enDMA = false;
1599 /* disable DMA, using polling mode in this situation */
1600 USDHC_EnableInternalDMA(base, false);
1601 }
1602 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1603 else
1604 {
1605 if (data->txData != NULL)
1606 {
1607 /* clear the DCACHE */
1608 DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1609 }
1610 else
1611 {
1612 /* clear the DCACHE */
1613 DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1614 }
1615 }
1616 #endif
1617
1618 /* config the data transfer parameter */
1619 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1620 if (error != kStatus_Success)
1621 {
1622 return error;
1623 }
1624 /* send command first */
1625 USDHC_SendCommand(base, command);
1626 /* wait command done */
1627 error =
1628 USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal));
1629 if (kStatus_Success != error)
1630 {
1631 return kStatus_USDHC_SendCommandFailed;
1632 }
1633
1634 /* wait transfer data finsih */
1635 if (data != NULL)
1636 {
1637 error = USDHC_TransferDataBlocking(base, data, enDMA);
1638 if (kStatus_Success != error)
1639 {
1640 return error;
1641 }
1642 }
1643
1644 return kStatus_Success;
1645 }
1646
1647 #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)1648 static status_t USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type *base,
1649 usdhc_adma_config_t *dmaConfig,
1650 usdhc_scatter_gather_data_t *dataConfig,
1651 uint32_t *totalTransferSize)
1652 {
1653 assert(NULL != dmaConfig);
1654 assert((NULL != dmaConfig->admaTable) &&
1655 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1656 assert(NULL != dataConfig);
1657
1658 status_t error = kStatus_Fail;
1659 uint32_t *admaDesBuffer = dmaConfig->admaTable;
1660 uint32_t admaDesLen = dmaConfig->admaTableWords;
1661 usdhc_scatter_gather_data_list_t *sgDataList = &dataConfig->sgData;
1662 uint32_t oneDescriptorMaxTransferSize = dmaConfig->dmaMode == kUSDHC_DmaModeAdma1 ?
1663 USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY :
1664 USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1665 uint32_t miniEntries = 0U;
1666
1667 while (sgDataList != NULL)
1668 {
1669 if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1670 {
1671 error = USDHC_SetADMA1Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1672 }
1673 /* ADMA2 */
1674 else
1675 {
1676 error = USDHC_SetADMA2Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1677 }
1678
1679 if (error != kStatus_Success)
1680 {
1681 return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1682 }
1683
1684 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1685 if (dataConfig->dataDirection == kUSDHC_TransferDirectionSend)
1686 {
1687 /* clear the DCACHE */
1688 DCACHE_CleanByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1689 }
1690 else
1691 {
1692 /* clear the DCACHE */
1693 DCACHE_CleanInvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1694 }
1695 #endif
1696
1697 *totalTransferSize += sgDataList->dataSize;
1698 if (sgDataList->dataList != NULL)
1699 {
1700 if ((sgDataList->dataSize % oneDescriptorMaxTransferSize) == 0UL)
1701 {
1702 miniEntries = sgDataList->dataSize / oneDescriptorMaxTransferSize;
1703 }
1704 else
1705 {
1706 miniEntries = ((sgDataList->dataSize / oneDescriptorMaxTransferSize) + 1UL);
1707 }
1708 if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1709 {
1710 admaDesBuffer[miniEntries * 2U - 1U] &= ~kUSDHC_Adma1DescriptorEndFlag;
1711 }
1712 else
1713 {
1714 admaDesBuffer[miniEntries * 2U - 2U] &= ~kUSDHC_Adma2DescriptorEndFlag;
1715 }
1716 admaDesBuffer += miniEntries * 2U;
1717 admaDesLen -= miniEntries * 2U;
1718 }
1719
1720 sgDataList = sgDataList->dataList;
1721 }
1722
1723 base->DS_ADDR = 0UL;
1724 base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
1725
1726 /* select DMA mode and config the burst length */
1727 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1728 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1729
1730 /* enable DMA */
1731 base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1732
1733 return error;
1734 }
1735
1736 /*!
1737 * brief Transfers the command/scatter gather data using an interrupt and an asynchronous method.
1738 *
1739 * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
1740 * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
1741 * this API doesn't support the re-entry mechanism.
1742 * This function is target for the application would like to have scatter gather buffer to be transferred within one
1743 * read/write request, non scatter gather buffer is support by this function also.
1744 *
1745 * note Call API @ref USDHC_TransferCreateHandle when calling this API.
1746 *
1747 * param base USDHC peripheral base address.
1748 * param handle USDHC handle.
1749 * param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only.
1750 * param transfer scatter gather transfer content.
1751 *
1752 * retval #kStatus_InvalidArgument Argument is invalid.
1753 * retval #kStatus_USDHC_BusyTransferring Busy transferring.
1754 * retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1755 * retval #kStatus_Success Operate successfully.
1756 */
USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_scatter_gather_transfer_t * transfer)1757 status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base,
1758 usdhc_handle_t *handle,
1759 usdhc_adma_config_t *dmaConfig,
1760 usdhc_scatter_gather_transfer_t *transfer)
1761 {
1762 assert(handle != NULL);
1763 assert(transfer != NULL);
1764 assert(dmaConfig != NULL);
1765
1766 status_t error = kStatus_Fail;
1767 usdhc_command_t *command = transfer->command;
1768 uint32_t totalTransferSize = 0U;
1769 uint32_t transferFlags = kUSDHC_CommandOnly;
1770 size_t blockSize = 0U;
1771 size_t blockCount = 0U;
1772 usdhc_scatter_gather_data_t *scatterGatherData = transfer->data;
1773 bool enDMA = false;
1774
1775 /* check data inhibit flag */
1776 if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
1777 {
1778 return kStatus_USDHC_BusyTransferring;
1779 }
1780
1781 handle->command = command;
1782 handle->data = scatterGatherData;
1783 /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1784 handle->transferredWords = 0UL;
1785
1786 /* Update ADMA descriptor table according to different DMA mode(ADMA1, ADMA2).*/
1787 if (scatterGatherData != NULL)
1788 {
1789 if (scatterGatherData->sgData.dataAddr == NULL)
1790 {
1791 return kStatus_InvalidArgument;
1792 }
1793
1794 if (scatterGatherData->dataType != (uint32_t)kUSDHC_TransferDataTuning)
1795 {
1796 if (USDHC_SetScatterGatherAdmaTableConfig(base, dmaConfig, transfer->data, &totalTransferSize) !=
1797 kStatus_Success)
1798 {
1799 return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1800 }
1801
1802 enDMA = true;
1803 }
1804 blockSize = scatterGatherData->blockSize;
1805 blockCount = totalTransferSize / scatterGatherData->blockSize;
1806 transferFlags = scatterGatherData->enableAutoCommand12 ? kUSDHC_DataWithAutoCmd12 : 0U;
1807 transferFlags |= scatterGatherData->enableAutoCommand23 ? kUSDHC_DataWithAutoCmd23 : 0U;
1808 transferFlags |= scatterGatherData->dataDirection == kUSDHC_TransferDirectionSend ? kUSDHC_CommandAndTxData :
1809 kUSDHC_CommandAndRxData;
1810 command->flags |= kUSDHC_DataPresentFlag;
1811 }
1812
1813 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1814 if (error != kStatus_Success)
1815 {
1816 return error;
1817 }
1818
1819 /* enable interrupt per transfer request */
1820 if (scatterGatherData != NULL)
1821 {
1822 USDHC_ClearInterruptStatusFlags(
1823 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1824 (uint32_t)kUSDHC_CommandFlag);
1825 USDHC_EnableInterruptSignal(
1826 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1827 (uint32_t)kUSDHC_CommandFlag);
1828 }
1829 else
1830 {
1831 USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1832 USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1833 }
1834
1835 /* send command first */
1836 USDHC_SendCommand(base, command);
1837
1838 return kStatus_Success;
1839 }
1840 #else
1841 /*!
1842 * brief Transfers the command/data using an interrupt and an asynchronous method.
1843 *
1844 * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
1845 * error.
1846 * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1847 * the re-entry mechanism.
1848 *
1849 * note Call the API 'USDHC_TransferCreateHandle' when calling this API.
1850 *
1851 * param base USDHC peripheral base address.
1852 * param handle USDHC handle.
1853 * param adma configuration.
1854 * param transfer Transfer content.
1855 * retval kStatus_InvalidArgument Argument is invalid.
1856 * retval kStatus_USDHC_BusyTransferring Busy transferring.
1857 * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1858 * retval kStatus_Success Operate successfully.
1859 */
USDHC_TransferNonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)1860 status_t USDHC_TransferNonBlocking(USDHC_Type *base,
1861 usdhc_handle_t *handle,
1862 usdhc_adma_config_t *dmaConfig,
1863 usdhc_transfer_t *transfer)
1864 {
1865 assert(handle != NULL);
1866 assert(transfer != NULL);
1867
1868 status_t error = kStatus_Fail;
1869 usdhc_command_t *command = transfer->command;
1870 usdhc_data_t *data = transfer->data;
1871 bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1872 bool enDMA = true;
1873 uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
1874 size_t blockSize = 0U;
1875 size_t blockCount = 0U;
1876
1877 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1878 /*check re-tuning request*/
1879 if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL)
1880 {
1881 USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1882 return kStatus_USDHC_ReTuningRequest;
1883 }
1884 #endif
1885 /* Save command and data into handle before transferring. */
1886
1887 handle->command = command;
1888 handle->data = data;
1889 /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1890 handle->transferredWords = 0UL;
1891
1892 if (data != NULL)
1893 {
1894 /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1895 if ((dmaConfig != NULL) && (!executeTuning))
1896 {
1897 error = USDHC_SetAdmaTableConfig(
1898 base, dmaConfig, data,
1899 (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ?
1900 kUSDHC_AdmaDescriptorMultipleFlag :
1901 kUSDHC_AdmaDescriptorSingleFlag));
1902 }
1903
1904 blockSize = data->blockSize;
1905 blockCount = data->blockCount;
1906 transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1907 transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1908 transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1909 transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1910 transferFlags |=
1911 data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1912
1913 command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1914 }
1915
1916 /* if the DMA desciptor configure fail or not needed , disable it */
1917 if (error != kStatus_Success)
1918 {
1919 /* disable DMA, using polling mode in this situation */
1920 USDHC_EnableInternalDMA(base, false);
1921 enDMA = false;
1922 }
1923 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1924 else
1925 {
1926 if (data->txData != NULL)
1927 {
1928 /* clear the DCACHE */
1929 DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1930 }
1931 else
1932 {
1933 /* clear the DCACHE */
1934 DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1935 }
1936 }
1937 #endif
1938
1939 /* config the data transfer parameter */
1940 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1941 if (error != kStatus_Success)
1942 {
1943 return error;
1944 }
1945
1946 /* enable interrupt per transfer request */
1947 if (handle->data != NULL)
1948 {
1949 USDHC_ClearInterruptStatusFlags(
1950 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag |
1951 (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1952 (uint32_t)kUSDHC_DmaCompleteFlag :
1953 0U));
1954 USDHC_EnableInterruptSignal(base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) |
1955 (uint32_t)kUSDHC_CommandFlag |
1956 (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1957 (uint32_t)kUSDHC_DmaCompleteFlag :
1958 0U));
1959 }
1960 else
1961 {
1962 USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1963 USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1964 }
1965
1966 /* send command first */
1967 USDHC_SendCommand(base, command);
1968
1969 return kStatus_Success;
1970 }
1971 #endif
1972
1973 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1974 /*!
1975 * brief manual tuning trigger or abort
1976 * User should handle the tuning cmd and find the boundary of the delay
1977 * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS
1978 * This function should called before USDHC_AdjustDelayforSDR104 function
1979 * param base USDHC peripheral base address.
1980 * param tuning enable flag
1981 */
USDHC_EnableManualTuning(USDHC_Type * base,bool enable)1982 void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
1983 {
1984 if (enable)
1985 {
1986 /* make sure std_tun_en bit is clear */
1987 base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
1988 /* disable auto tuning here */
1989 base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
1990 /* execute tuning for SDR104 mode */
1991 base->MIX_CTRL |= USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK;
1992 }
1993 else
1994 { /* abort the tuning */
1995 base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK;
1996 }
1997 }
1998
1999 /*!
2000 * brief the SDR104 mode delay setting adjust
2001 * This function should called after USDHC_ManualTuningForSDR104
2002 * param base USDHC peripheral base address.
2003 * param delay setting configuration
2004 * retval kStatus_Fail config the delay setting fail
2005 * retval kStatus_Success config the delay setting success
2006 */
USDHC_AdjustDelayForManualTuning(USDHC_Type * base,uint32_t delay)2007 status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
2008 {
2009 uint32_t clkTuneCtrl = 0UL;
2010
2011 clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2012
2013 clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
2014
2015 clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
2016
2017 /* load the delay setting */
2018 base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2019 /* check delat setting error */
2020 if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2021 USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2022 {
2023 return kStatus_Fail;
2024 }
2025
2026 return kStatus_Success;
2027 }
2028
2029 /*!
2030 * brief The tuning delay cell setting.
2031 *
2032 * param base USDHC peripheral base address.
2033 * param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE.
2034 * param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT.
2035 * param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST.
2036 * retval kStatus_Fail config the delay setting fail
2037 * retval kStatus_Success config the delay setting success
2038 */
USDHC_SetTuningDelay(USDHC_Type * base,uint32_t preDelay,uint32_t outDelay,uint32_t postDelay)2039 status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay)
2040 {
2041 assert(preDelay <=
2042 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_SHIFT));
2043 assert(outDelay <=
2044 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_SHIFT));
2045 assert(postDelay <=
2046 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_SHIFT));
2047
2048 uint32_t clkTuneCtrl = 0UL;
2049
2050 clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2051
2052 clkTuneCtrl &=
2053 ~(USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK | USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK |
2054 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK);
2055
2056 clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(preDelay) |
2057 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT(outDelay) |
2058 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST(postDelay);
2059
2060 /* load the delay setting */
2061 base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2062 /* check delat setting error */
2063 if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2064 USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2065 {
2066 return kStatus_Fail;
2067 }
2068
2069 return kStatus_Success;
2070 }
2071
2072 /*!
2073 * brief the enable standard tuning function
2074 * The standard tuning window and tuning counter use the default config
2075 * tuning cmd is send by the software, user need to check the tuning result
2076 * can be used for SDR50,SDR104,HS200 mode tuning
2077 * param base USDHC peripheral base address.
2078 * param tuning start tap
2079 * param tuning step
2080 * param enable/disable flag
2081 */
USDHC_EnableStandardTuning(USDHC_Type * base,uint32_t tuningStartTap,uint32_t step,bool enable)2082 void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
2083 {
2084 uint32_t tuningCtrl = 0UL;
2085
2086 if (enable)
2087 {
2088 /* feedback clock */
2089 base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
2090 /* config tuning start and step */
2091 tuningCtrl = base->TUNING_CTRL;
2092 tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
2093 tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
2094 USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
2095 base->TUNING_CTRL = tuningCtrl;
2096
2097 /* excute tuning */
2098 base->AUTOCMD12_ERR_STATUS |=
2099 (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2100 }
2101 else
2102 {
2103 /* disable the standard tuning */
2104 base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
2105 /* clear excute tuning */
2106 base->AUTOCMD12_ERR_STATUS &=
2107 ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2108 }
2109 }
2110
2111 #if FSL_FEATURE_USDHC_HAS_HS400_MODE
2112 /*!
2113 * brief config the strobe DLL delay target and update interval
2114 *
2115 * param base USDHC peripheral base address.
2116 * param delayTarget delay target
2117 * param updateInterval update interval
2118 */
USDHC_ConfigStrobeDLL(USDHC_Type * base,uint32_t delayTarget,uint32_t updateInterval)2119 void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval)
2120 {
2121 assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >>
2122 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT));
2123
2124 /* reset strobe dll firstly */
2125 base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
2126 /* clear reset and other register fields */
2127 base->STROBE_DLL_CTRL = 0;
2128 /* configure the DELAY target and update interval */
2129 base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
2130 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) |
2131 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget);
2132
2133 while (
2134 (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK |
2135 USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) !=
2136 ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)))
2137 {
2138 }
2139 }
2140 #endif
2141
2142 /*!
2143 * brief the auto tuning enbale for CMD/DATA line
2144 *
2145 * param base USDHC peripheral base address.
2146 */
USDHC_EnableAutoTuningForCmdAndData(USDHC_Type * base)2147 void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
2148 {
2149 uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
2150
2151 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
2152
2153 #if defined(USDHC_VEND_SPEC2_TUNING_BIT_EN_MASK) && USDHC_VEND_SPEC2_TUNING_BIT_EN_MASK
2154 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_BIT_EN_MASK;
2155 /* 1bit data width */
2156 if (busWidth == 0UL)
2157 {
2158 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_BIT_EN(2U);
2159 }
2160 /* 4bit data width */
2161 else if (busWidth == 1UL)
2162 {
2163 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_BIT_EN(0U);
2164 }
2165 /* 8bit data width */
2166 else
2167 {
2168 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_BIT_EN(1U);
2169 }
2170 #else
2171 /* 1bit data width */
2172 if (busWidth == 0UL)
2173 {
2174 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2175 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2176 }
2177 /* 4bit data width */
2178 else if (busWidth == 1UL)
2179 {
2180 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2181 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2182 }
2183 /* 8bit data width */
2184 else
2185 {
2186 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2187 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2188 }
2189 #endif
2190 }
2191 #endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
2192
USDHC_TransferHandleCardDetect(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2193 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2194 {
2195 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag))
2196 {
2197 if (handle->callback.CardInserted != NULL)
2198 {
2199 handle->callback.CardInserted(base, handle->userData);
2200 }
2201 }
2202 else
2203 {
2204 if (handle->callback.CardRemoved != NULL)
2205 {
2206 handle->callback.CardRemoved(base, handle->userData);
2207 }
2208 }
2209 }
2210
USDHC_TransferHandleCommand(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2211 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2212 {
2213 assert(handle->command != NULL);
2214
2215 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag))
2216 {
2217 if (handle->callback.TransferComplete != NULL)
2218 {
2219 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2220 }
2221 }
2222 else
2223 {
2224 /* Receive response */
2225 if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
2226 {
2227 if (handle->callback.TransferComplete != NULL)
2228 {
2229 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2230 }
2231 }
2232 else
2233 {
2234 if (handle->callback.TransferComplete != NULL)
2235 {
2236 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData);
2237 }
2238 }
2239 }
2240 /* disable interrupt signal and reset command pointer */
2241 USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag);
2242 handle->command = NULL;
2243 }
2244
2245 #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)2246 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2247 {
2248 assert(handle->data != NULL);
2249
2250 status_t transferStatus = kStatus_USDHC_BusyTransferring;
2251
2252 if ((!(handle->data->enableIgnoreError)) &&
2253 (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2254 {
2255 transferStatus = kStatus_USDHC_TransferDataFailed;
2256 }
2257 else
2258 {
2259 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2260 {
2261 /* std tuning process only need to wait BRR */
2262 if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2263 {
2264 transferStatus = kStatus_USDHC_TransferDataComplete;
2265 }
2266 }
2267 else
2268 {
2269 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag))
2270 {
2271 transferStatus = kStatus_USDHC_TransferDMAComplete;
2272 }
2273
2274 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2275 {
2276 transferStatus = kStatus_USDHC_TransferDataComplete;
2277
2278 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2279 if (handle->data->dataDirection == kUSDHC_TransferDirectionReceive)
2280 {
2281 usdhc_scatter_gather_data_list_t *sgDataList = &handle->data->sgData;
2282 while (sgDataList != NULL)
2283 {
2284 DCACHE_InvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
2285 sgDataList = sgDataList->dataList;
2286 }
2287 }
2288 #endif
2289 }
2290 }
2291 }
2292
2293 if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2294 {
2295 handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2296 USDHC_DisableInterruptSignal(
2297 base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_DmaCompleteFlag);
2298 handle->data = NULL;
2299 }
2300 }
2301
2302 #else
USDHC_TransferHandleData(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2303 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2304 {
2305 assert(handle->data != NULL);
2306
2307 status_t transferStatus = kStatus_USDHC_BusyTransferring;
2308 uint32_t transferredWords = handle->transferredWords;
2309
2310 if ((!(handle->data->enableIgnoreError)) &&
2311 (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2312 {
2313 transferStatus = kStatus_USDHC_TransferDataFailed;
2314 }
2315 else
2316 {
2317 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2318 {
2319 /* std tuning process only need to wait BRR */
2320 if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2321 {
2322 transferStatus = kStatus_USDHC_TransferDataComplete;
2323 }
2324 else
2325 {
2326 handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords);
2327 }
2328 }
2329 else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag))
2330 {
2331 handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords);
2332 }
2333 else
2334 {
2335 if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) &&
2336 (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous))
2337 {
2338 *(handle->data->rxData) = s_usdhcBootDummy;
2339 }
2340
2341 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2342 {
2343 transferStatus = kStatus_USDHC_TransferDataComplete;
2344
2345 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2346 if (handle->data->rxData != NULL)
2347 {
2348 DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData),
2349 (handle->data->blockSize) * (handle->data->blockCount));
2350 }
2351 #endif
2352 }
2353 }
2354 }
2355
2356 if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2357 {
2358 handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2359 USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag);
2360 handle->data = NULL;
2361 }
2362 }
2363 #endif
2364
USDHC_TransferHandleSdioInterrupt(USDHC_Type * base,usdhc_handle_t * handle)2365 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
2366 {
2367 if (handle->callback.SdioInterrupt != NULL)
2368 {
2369 handle->callback.SdioInterrupt(base, handle->userData);
2370 }
2371 }
2372
2373 #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)2374 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2375 {
2376 assert(handle->callback.ReTuning != NULL);
2377 /* retuning request */
2378 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag))
2379 {
2380 handle->callback.ReTuning(base, handle->userData); /* retuning fail */
2381 }
2382 }
2383 #endif
2384
USDHC_TransferHandleBlockGap(USDHC_Type * base,usdhc_handle_t * handle)2385 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
2386 {
2387 if (handle->callback.BlockGap != NULL)
2388 {
2389 handle->callback.BlockGap(base, handle->userData);
2390 }
2391 }
2392
2393 /*!
2394 * brief Creates the USDHC handle.
2395 *
2396 * param base USDHC peripheral base address.
2397 * param handle USDHC handle pointer.
2398 * param callback Structure pointer to contain all callback functions.
2399 * param userData Callback function parameter.
2400 */
USDHC_TransferCreateHandle(USDHC_Type * base,usdhc_handle_t * handle,const usdhc_transfer_callback_t * callback,void * userData)2401 void USDHC_TransferCreateHandle(USDHC_Type *base,
2402 usdhc_handle_t *handle,
2403 const usdhc_transfer_callback_t *callback,
2404 void *userData)
2405 {
2406 assert(handle != NULL);
2407 assert(callback != NULL);
2408
2409 /* Zero the handle. */
2410 (void)memset(handle, 0, sizeof(*handle));
2411
2412 /* Set the callback. */
2413 handle->callback.CardInserted = callback->CardInserted;
2414 handle->callback.CardRemoved = callback->CardRemoved;
2415 handle->callback.SdioInterrupt = callback->SdioInterrupt;
2416 handle->callback.BlockGap = callback->BlockGap;
2417 handle->callback.TransferComplete = callback->TransferComplete;
2418 handle->callback.ReTuning = callback->ReTuning;
2419 handle->userData = userData;
2420
2421 /* Save the handle in global variables to support the double weak mechanism. */
2422 s_usdhcHandle[USDHC_GetInstance(base)] = handle;
2423
2424 /* save IRQ handler */
2425 s_usdhcIsr = USDHC_TransferHandleIRQ;
2426
2427 (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
2428 }
2429
2430 /*!
2431 * brief IRQ handler for the USDHC.
2432 *
2433 * This function deals with the IRQs on the given host controller.
2434 *
2435 * param base USDHC peripheral base address.
2436 * param handle USDHC handle.
2437 */
USDHC_TransferHandleIRQ(USDHC_Type * base,usdhc_handle_t * handle)2438 void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
2439 {
2440 assert(handle != NULL);
2441
2442 uint32_t interruptFlags;
2443
2444 interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base);
2445
2446 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag))
2447 {
2448 USDHC_TransferHandleCardDetect(base, handle, interruptFlags);
2449 }
2450 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag))
2451 {
2452 USDHC_TransferHandleCommand(base, handle, interruptFlags);
2453 }
2454 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag))
2455 {
2456 USDHC_TransferHandleData(base, handle, interruptFlags);
2457 }
2458 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag))
2459 {
2460 USDHC_TransferHandleSdioInterrupt(base, handle);
2461 }
2462 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag))
2463 {
2464 USDHC_TransferHandleBlockGap(base, handle);
2465 }
2466 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
2467 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag))
2468 {
2469 USDHC_TransferHandleReTuning(base, handle, interruptFlags);
2470 }
2471 #endif
2472 USDHC_ClearInterruptStatusFlags(base, interruptFlags);
2473 }
2474
2475 #ifdef USDHC0
2476 void USDHC0_DriverIRQHandler(void);
USDHC0_DriverIRQHandler(void)2477 void USDHC0_DriverIRQHandler(void)
2478 {
2479 s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
2480 SDK_ISR_EXIT_BARRIER;
2481 }
2482 #endif
2483
2484 #ifdef USDHC1
2485 void USDHC1_DriverIRQHandler(void);
USDHC1_DriverIRQHandler(void)2486 void USDHC1_DriverIRQHandler(void)
2487 {
2488 s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
2489 SDK_ISR_EXIT_BARRIER;
2490 }
2491 #endif
2492
2493 #ifdef USDHC2
2494 void USDHC2_DriverIRQHandler(void);
USDHC2_DriverIRQHandler(void)2495 void USDHC2_DriverIRQHandler(void)
2496 {
2497 s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
2498 SDK_ISR_EXIT_BARRIER;
2499 }
2500
2501 #endif
2502