1 /*
2 * Copyright (c) 2016, Freescale Semiconductor, Inc.
3 * Copyright 2016-2021 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_usdhc.h"
10 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
11 #include "fsl_cache.h"
12 #endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
13 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
14 #include "fsl_memory.h"
15 #endif
16 /*******************************************************************************
17 * Definitions
18 ******************************************************************************/
19
20 /* Component ID definition, used by tools. */
21 #ifndef FSL_COMPONENT_ID
22 #define FSL_COMPONENT_ID "platform.drivers.usdhc"
23 #endif
24
25 /*! @brief Clock setting */
26 /* Max SD clock divisor from base clock */
27 #define USDHC_MAX_DVS ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
28 #define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
29 #define USDHC_PREV_DVS(x) ((x) -= 1U)
30 #define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
31 /*! @brief USDHC ADMA table address align size */
32 #define USDHC_ADMA_TABLE_ADDRESS_ALIGN (4U)
33
34 /* Typedef for interrupt handler. */
35 typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
36 /*! @brief check flag avalibility */
37 #define IS_USDHC_FLAG_SET(reg, flag) (((reg) & ((uint32_t)flag)) != 0UL)
38
39 /*! @brief usdhc transfer flags */
40 enum _usdhc_transfer_flags
41 {
42 kUSDHC_CommandOnly = 1U, /*!< transfer command only */
43 kUSDHC_CommandAndTxData = 2U, /*!< transfer command and transmit data */
44 kUSDHC_CommandAndRxData = 4U, /*!< transfer command and receive data */
45 kUSDHC_DataWithAutoCmd12 = 8U, /*!< transfer data with auto cmd12 enabled */
46 kUSDHC_DataWithAutoCmd23 = 16U, /*!< transfer data with auto cmd23 enabled */
47 kUSDHC_BootData = 32U, /*!< transfer boot data */
48 kUSDHC_BootDataContinuous = 64U, /*!< transfer boot data continuous */
49 };
50
51 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
52 #define USDHC_ADDR_CPU_2_DMA(addr) (MEMORY_ConvertMemoryMapAddress((addr), kMEMORY_Local2DMA))
53 #else
54 #define USDHC_ADDR_CPU_2_DMA(addr) (addr)
55 #endif
56 /*******************************************************************************
57 * Prototypes
58 ******************************************************************************/
59 /*!
60 * @brief Get the instance.
61 *
62 * @param base USDHC peripheral base address.
63 * @return Instance number.
64 */
65 static uint32_t USDHC_GetInstance(USDHC_Type *base);
66
67 /*!
68 * @brief Start transfer according to current transfer state
69 *
70 * @param base USDHC peripheral base address.
71 * @param transferFlags transfer flags, @ref _usdhc_transfer_flags.
72 * @param blockSize block size.
73 * @param blockCount block count.
74 */
75 static status_t USDHC_SetTransferConfig(USDHC_Type *base,
76 uint32_t transferFlags,
77 size_t blockSize,
78 uint32_t blockCount);
79
80 /*!
81 * @brief Receive command response
82 *
83 * @param base USDHC peripheral base address.
84 * @param command Command to be sent.
85 */
86 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command);
87
88 /*!
89 * @brief Read DATAPORT when buffer enable bit is set.
90 *
91 * @param base USDHC peripheral base address.
92 * @param data Data to be read.
93 * @param transferredWords The number of data words have been transferred last time transaction.
94 * @return The number of total data words have been transferred after this time transaction.
95 */
96 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
97
98 /*!
99 * @brief Read data by using DATAPORT polling way.
100 *
101 * @param base USDHC peripheral base address.
102 * @param data Data to be read.
103 * @retval kStatus_Fail Read DATAPORT failed.
104 * @retval kStatus_Success Operate successfully.
105 */
106 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
107
108 /*!
109 * @brief Write DATAPORT when buffer enable bit is set.
110 *
111 * @param base USDHC peripheral base address.
112 * @param data Data to be read.
113 * @param transferredWords The number of data words have been transferred last time.
114 * @return The number of total data words have been transferred after this time transaction.
115 */
116 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
117
118 /*!
119 * @brief Write data by using DATAPORT polling way.
120 *
121 * @param base USDHC peripheral base address.
122 * @param data Data to be transferred.
123 * @retval kStatus_Fail Write DATAPORT failed.
124 * @retval kStatus_Success Operate successfully.
125 */
126 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
127
128 /*!
129 * @brief Transfer data by polling way.
130 *
131 * @param base USDHC peripheral base address.
132 * @param data Data to be transferred.
133 * @param use DMA flag.
134 * @retval kStatus_Fail Transfer data failed.
135 * @retval kStatus_InvalidArgument Argument is invalid.
136 * @retval kStatus_Success Operate successfully.
137 */
138 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
139
140 /*!
141 * @brief wait command done
142 *
143 * @param base USDHC peripheral base address.
144 * @param command configuration
145 * @param pollingCmdDone polling command done flag
146 */
147 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
148
149 /*!
150 * @brief Handle card detect interrupt.
151 *
152 * @param base USDHC peripheral base address.
153 * @param handle USDHC handle.
154 * @param interruptFlags Card detect related interrupt flags.
155 */
156 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
157
158 /*!
159 * @brief Handle command interrupt.
160 *
161 * @param base USDHC peripheral base address.
162 * @param handle USDHC handle.
163 * @param interruptFlags Command related interrupt flags.
164 */
165 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
166
167 /*!
168 * @brief Handle data interrupt.
169 *
170 * @param base USDHC peripheral base address.
171 * @param handle USDHC handle.
172 * @param interruptFlags Data related interrupt flags.
173 */
174 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
175
176 /*!
177 * @brief Handle SDIO card interrupt signal.
178 *
179 * @param base USDHC peripheral base address.
180 * @param handle USDHC handle.
181 */
182 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
183
184 /*!
185 * @brief Handle SDIO block gap event.
186 *
187 * @param base USDHC peripheral base address.
188 * @param handle USDHC handle.
189 */
190 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
191
192 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
193 /*!
194 * @brief Handle retuning
195 *
196 * @param base USDHC peripheral base address.
197 * @param handle USDHC handle.
198 * @param interrupt flags
199 */
200 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
201 #endif
202 /*******************************************************************************
203 * Variables
204 ******************************************************************************/
205 /*! @brief USDHC base pointer array */
206 static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
207
208 /*! @brief USDHC internal handle pointer array */
209 static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {0};
210
211 /*! @brief USDHC IRQ name array */
212 static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
213
214 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
215 /*! @brief USDHC clock array name */
216 static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
217 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
218
219 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
220 /*! @brief Pointers to USDHC resets for each instance. */
221 static const reset_ip_name_t s_usdhcResets[] = USDHC_RSTS;
222 #endif
223
224 /* USDHC ISR for transactional APIs. */
225 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
226 static usdhc_isr_t s_usdhcIsr = (usdhc_isr_t)DefaultISR;
227 #else
228 static usdhc_isr_t s_usdhcIsr;
229 #endif
230 /*! @brief Dummy data buffer for mmc boot mode */
231 AT_NONCACHEABLE_SECTION_ALIGN(static uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
232
233 /*******************************************************************************
234 * Code
235 ******************************************************************************/
USDHC_GetInstance(USDHC_Type * base)236 static uint32_t USDHC_GetInstance(USDHC_Type *base)
237 {
238 uint8_t instance = 0;
239
240 while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
241 {
242 instance++;
243 }
244
245 assert(instance < ARRAY_SIZE(s_usdhcBase));
246
247 return instance;
248 }
249
USDHC_SetTransferConfig(USDHC_Type * base,uint32_t transferFlags,size_t blockSize,uint32_t blockCount)250 static status_t USDHC_SetTransferConfig(USDHC_Type *base, uint32_t transferFlags, size_t blockSize, uint32_t blockCount)
251 {
252 uint32_t mixCtrl = base->MIX_CTRL;
253
254 if (((uint32_t)kUSDHC_CommandOnly & transferFlags) != 0U)
255 {
256 /* clear data flags */
257 mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
258 USDHC_MIX_CTRL_AC12EN_MASK | USDHC_MIX_CTRL_AC23EN_MASK);
259
260 if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
261 {
262 return kStatus_USDHC_BusyTransferring;
263 }
264 }
265 else
266 {
267 /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
268 if ((transferFlags & (uint32_t)kUSDHC_BootDataContinuous) != 0U)
269 {
270 /* clear stop at block gap request */
271 base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
272 /* continous transfer data */
273 base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
274 return kStatus_Success;
275 }
276
277 /* check data inhibit flag */
278 if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_DataInhibitFlag))
279 {
280 return kStatus_USDHC_BusyTransferring;
281 }
282 /* check transfer block count */
283 if ((blockCount > USDHC_MAX_BLOCK_COUNT))
284 {
285 return kStatus_InvalidArgument;
286 }
287
288 /* config mix parameter */
289 mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
290 USDHC_MIX_CTRL_AC12EN_MASK);
291
292 if ((transferFlags & (uint32_t)kUSDHC_CommandAndRxData) != 0U)
293 {
294 mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
295 }
296
297 if (blockCount > 1U)
298 {
299 mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
300 /* auto command 12 */
301 if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd12) != 0U)
302 {
303 mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
304 }
305 }
306
307 /* auto command 23, auto send set block count cmd before multiple read/write */
308 if ((transferFlags & (uint32_t)kUSDHC_DataWithAutoCmd23) != 0U)
309 {
310 mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
311 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
312 /* config the block count to DS_ADDR */
313 base->DS_ADDR = blockCount;
314 }
315 else
316 {
317 mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
318 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
319 }
320
321 /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
322 if ((transferFlags & (uint32_t)kUSDHC_BootData) == 0U)
323 {
324 /* config data block size/block count */
325 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
326 (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
327 }
328 else
329 {
330 mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
331 base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
332 }
333 }
334 /* config the mix parameter */
335 base->MIX_CTRL = mixCtrl;
336
337 return kStatus_Success;
338 }
339
USDHC_SetDataConfig(USDHC_Type * base,usdhc_transfer_direction_t dataDirection,uint32_t blockCount,uint32_t blockSize)340 void USDHC_SetDataConfig(USDHC_Type *base,
341 usdhc_transfer_direction_t dataDirection,
342 uint32_t blockCount,
343 uint32_t blockSize)
344 {
345 assert(blockCount <= USDHC_MAX_BLOCK_COUNT);
346
347 uint32_t mixCtrl = base->MIX_CTRL;
348
349 /* block attribute configuration */
350 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
351 (USDHC_BLK_ATT_BLKSIZE(blockSize) | USDHC_BLK_ATT_BLKCNT(blockCount)));
352
353 /* config mix parameter */
354 mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK);
355
356 mixCtrl |= USDHC_MIX_CTRL_DTDSEL(dataDirection) | (blockCount > 1U ? USDHC_MIX_CTRL_MSBSEL_MASK : 0U);
357
358 base->MIX_CTRL = mixCtrl;
359 }
360
USDHC_ReceiveCommandResponse(USDHC_Type * base,usdhc_command_t * command)361 static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
362 {
363 assert(command != NULL);
364
365 uint32_t response0 = base->CMD_RSP0;
366 uint32_t response1 = base->CMD_RSP1;
367 uint32_t response2 = base->CMD_RSP2;
368
369 if (command->responseType != kCARD_ResponseTypeNone)
370 {
371 command->response[0U] = response0;
372 if (command->responseType == kCARD_ResponseTypeR2)
373 {
374 /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
375 after removed internal CRC7 and end bit. */
376 command->response[0U] <<= 8U;
377 command->response[1U] = (response1 << 8U) | ((response0 & 0xFF000000U) >> 24U);
378 command->response[2U] = (response2 << 8U) | ((response1 & 0xFF000000U) >> 24U);
379 command->response[3U] = (base->CMD_RSP3 << 8U) | ((response2 & 0xFF000000U) >> 24U);
380 }
381 }
382
383 /* check response error flag */
384 if ((command->responseErrorFlags != 0U) &&
385 ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
386 (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
387 {
388 if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
389 {
390 return kStatus_USDHC_SendCommandFailed;
391 }
392 }
393
394 return kStatus_Success;
395 }
396
USDHC_ReadDataPort(USDHC_Type * base,usdhc_data_t * data,uint32_t transferredWords)397 static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
398 {
399 uint32_t i;
400 uint32_t totalWords;
401 uint32_t wordsCanBeRead; /* The words can be read at this time. */
402 uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
403
404 /* If DMA is enable, do not need to polling data port */
405 if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
406 {
407 /*
408 * Add non aligned access support ,user need make sure your buffer size is big
409 * enough to hold the data,in other words,user need make sure the buffer size
410 * is 4 byte aligned
411 */
412 if (data->blockSize % sizeof(uint32_t) != 0U)
413 {
414 data->blockSize +=
415 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
416 }
417
418 totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
419
420 /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
421 if (readWatermark >= totalWords)
422 {
423 wordsCanBeRead = totalWords;
424 }
425 /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
426 transfers watermark level words. */
427 else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
428 {
429 wordsCanBeRead = readWatermark;
430 }
431 /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
432 left
433 words. */
434 else
435 {
436 wordsCanBeRead = (totalWords - transferredWords);
437 }
438
439 i = 0U;
440 while (i < wordsCanBeRead)
441 {
442 data->rxData[transferredWords++] = USDHC_ReadData(base);
443 i++;
444 }
445 }
446
447 return transferredWords;
448 }
449
USDHC_ReadByDataPortBlocking(USDHC_Type * base,usdhc_data_t * data)450 static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
451 {
452 uint32_t totalWords;
453 uint32_t transferredWords = 0U, interruptStatus = 0U;
454 status_t error = kStatus_Success;
455
456 /*
457 * Add non aligned access support ,user need make sure your buffer size is big
458 * enough to hold the data,in other words,user need make sure the buffer size
459 * is 4 byte aligned
460 */
461 if (data->blockSize % sizeof(uint32_t) != 0U)
462 {
463 data->blockSize +=
464 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
465 }
466
467 totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
468
469 while ((error == kStatus_Success) && (transferredWords < totalWords))
470 {
471 while (
472 !(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_BufferReadReadyFlag |
473 (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
474 {
475 interruptStatus = USDHC_GetInterruptStatusFlags(base);
476 }
477
478 /* during std tuning process, software do not need to read data, but wait BRR is enough */
479 if ((data->dataType == (uint32_t)kUSDHC_TransferDataTuning) &&
480 (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_BufferReadReadyFlag)))
481 {
482 USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
483
484 return kStatus_Success;
485 }
486 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
487 else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
488 {
489 USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
490 /* if tuning error occur ,return directly */
491 error = kStatus_USDHC_TuningError;
492 }
493 #endif
494 else if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
495 {
496 if (!(data->enableIgnoreError))
497 {
498 error = kStatus_Fail;
499 }
500 /* clear data error flag */
501 USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
502 }
503 else
504 {
505 /* Intentional empty */
506 }
507
508 if (error == kStatus_Success)
509 {
510 transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
511 /* clear buffer read ready */
512 USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
513 interruptStatus = 0U;
514 }
515 }
516
517 /* Clear data complete flag after the last read operation. */
518 USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
519
520 return error;
521 }
522
USDHC_WriteDataPort(USDHC_Type * base,usdhc_data_t * data,uint32_t transferredWords)523 static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
524 {
525 uint32_t i;
526 uint32_t totalWords;
527 uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
528 uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
529
530 /* If DMA is enable, do not need to polling data port */
531 if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
532 {
533 /*
534 * Add non aligned access support ,user need make sure your buffer size is big
535 * enough to hold the data,in other words,user need make sure the buffer size
536 * is 4 byte aligned
537 */
538 if (data->blockSize % sizeof(uint32_t) != 0U)
539 {
540 data->blockSize +=
541 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
542 }
543
544 totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
545
546 /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
547 if (writeWatermark >= totalWords)
548 {
549 wordsCanBeWrote = totalWords;
550 }
551 /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
552 transfers watermark level words. */
553 else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
554 {
555 wordsCanBeWrote = writeWatermark;
556 }
557 /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
558 words. */
559 else
560 {
561 wordsCanBeWrote = (totalWords - transferredWords);
562 }
563
564 i = 0U;
565 while (i < wordsCanBeWrote)
566 {
567 USDHC_WriteData(base, data->txData[transferredWords++]);
568 i++;
569 }
570 }
571
572 return transferredWords;
573 }
574
USDHC_WriteByDataPortBlocking(USDHC_Type * base,usdhc_data_t * data)575 static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
576 {
577 uint32_t totalWords;
578
579 uint32_t transferredWords = 0U, interruptStatus = 0U;
580 status_t error = kStatus_Success;
581
582 /*
583 * Add non aligned access support ,user need make sure your buffer size is big
584 * enough to hold the data,in other words,user need make sure the buffer size
585 * is 4 byte aligned
586 */
587 if (data->blockSize % sizeof(uint32_t) != 0U)
588 {
589 data->blockSize +=
590 sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
591 }
592
593 totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
594
595 while ((error == kStatus_Success) && (transferredWords < totalWords))
596 {
597 while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_BufferWriteReadyFlag |
598 (uint32_t)kUSDHC_DataErrorFlag |
599 (uint32_t)kUSDHC_TuningErrorFlag)))
600 {
601 interruptStatus = USDHC_GetInterruptStatusFlags(base);
602 }
603 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
604 if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
605 {
606 USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
607 /* if tuning error occur ,return directly */
608 return kStatus_USDHC_TuningError;
609 }
610 else
611 #endif
612 if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataErrorFlag))
613 {
614 if (!(data->enableIgnoreError))
615 {
616 error = kStatus_Fail;
617 }
618 /* clear data error flag */
619 USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
620 }
621 else
622 {
623 /* Intentional empty */
624 }
625
626 if (error == kStatus_Success)
627 {
628 transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
629 /* clear buffer write ready */
630 USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
631 interruptStatus = 0U;
632 }
633 }
634
635 /* Wait write data complete or data transfer error after the last writing operation. */
636 while (!(IS_USDHC_FLAG_SET(interruptStatus, (uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag)))
637 {
638 interruptStatus = USDHC_GetInterruptStatusFlags(base);
639 }
640
641 if ((interruptStatus & (uint32_t)kUSDHC_DataErrorFlag) != 0UL)
642 {
643 if (!(data->enableIgnoreError))
644 {
645 error = kStatus_Fail;
646 }
647 }
648 USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataCompleteFlag | (uint32_t)kUSDHC_DataErrorFlag));
649
650 return error;
651 }
652
653 /*!
654 * brief send command function
655 *
656 * param base USDHC peripheral base address.
657 * param command configuration
658 */
USDHC_SendCommand(USDHC_Type * base,usdhc_command_t * command)659 void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
660 {
661 assert(NULL != command);
662
663 uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
664
665 if (((base->PRES_STATE & (uint32_t)kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
666 {
667 if ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR5) ||
668 (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR7))
669 {
670 flags |= ((uint32_t)kUSDHC_ResponseLength48Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
671 (uint32_t)kUSDHC_EnableIndexCheckFlag);
672 }
673 else if ((command->responseType == kCARD_ResponseTypeR1b) || (command->responseType == kCARD_ResponseTypeR5b))
674 {
675 flags |= ((uint32_t)kUSDHC_ResponseLength48BusyFlag | (uint32_t)kUSDHC_EnableCrcCheckFlag |
676 (uint32_t)kUSDHC_EnableIndexCheckFlag);
677 }
678 else if (command->responseType == kCARD_ResponseTypeR2)
679 {
680 flags |= ((uint32_t)kUSDHC_ResponseLength136Flag | (uint32_t)kUSDHC_EnableCrcCheckFlag);
681 }
682 else if ((command->responseType == kCARD_ResponseTypeR3) || (command->responseType == kCARD_ResponseTypeR4))
683 {
684 flags |= ((uint32_t)kUSDHC_ResponseLength48Flag);
685 }
686 else
687 {
688 /* Intentional empty */
689 }
690
691 if (command->type == kCARD_CommandTypeAbort)
692 {
693 flags |= (uint32_t)kUSDHC_CommandTypeAbortFlag;
694 }
695
696 /* config cmd index */
697 xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
698 USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
699
700 xferType |=
701 (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
702 ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
703 USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
704
705 /* config the command xfertype and argument */
706 base->CMD_ARG = command->argument;
707 base->CMD_XFR_TYP = xferType;
708 }
709
710 if (command->type == kCARD_CommandTypeEmpty)
711 {
712 /* disable CMD done interrupt for empty command */
713 base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
714 }
715 }
716
USDHC_WaitCommandDone(USDHC_Type * base,usdhc_command_t * command,bool pollingCmdDone)717 static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
718 {
719 assert(NULL != command);
720
721 status_t error = kStatus_Success;
722 uint32_t interruptStatus = 0U;
723 /* check if need polling command done or not */
724 if (pollingCmdDone)
725 {
726 /* Wait command complete or USDHC encounters error. */
727 while (!(IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_CommandFlag)))
728 {
729 interruptStatus = USDHC_GetInterruptStatusFlags(base);
730 }
731
732 if ((interruptStatus & (uint32_t)kUSDHC_CommandErrorFlag) != 0UL)
733 {
734 error = kStatus_Fail;
735 }
736
737 /* Receive response when command completes successfully. */
738 if (error == kStatus_Success)
739 {
740 error = USDHC_ReceiveCommandResponse(base, command);
741 }
742
743 USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
744 }
745
746 return error;
747 }
748
USDHC_TransferDataBlocking(USDHC_Type * base,usdhc_data_t * data,bool enDMA)749 static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
750 {
751 status_t error = kStatus_Success;
752 uint32_t interruptStatus = 0U;
753
754 if (enDMA)
755 {
756 /* Wait data complete or USDHC encounters error. */
757 while (!(IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag))))
758 {
759 interruptStatus = USDHC_GetInterruptStatusFlags(base);
760 }
761
762 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
763 if (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_TuningErrorFlag))
764 {
765 error = kStatus_USDHC_TuningError;
766 }
767 else
768 #endif
769 if (IS_USDHC_FLAG_SET(interruptStatus, ((uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
770 {
771 if ((!(data->enableIgnoreError)) || (IS_USDHC_FLAG_SET(interruptStatus, kUSDHC_DataTimeoutFlag)))
772 {
773 error = kStatus_USDHC_TransferDataFailed;
774 }
775 }
776 else
777 {
778 /* Intentional empty */
779 }
780 /* load dummy data */
781 if ((data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
782 {
783 *(data->rxData) = s_usdhcBootDummy;
784 }
785
786 USDHC_ClearInterruptStatusFlags(base, ((uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_TuningErrorFlag));
787 }
788 else
789 {
790 if (data->rxData != NULL)
791 {
792 error = USDHC_ReadByDataPortBlocking(base, data);
793 if (error != kStatus_Success)
794 {
795 return error;
796 }
797 }
798 else
799 {
800 error = USDHC_WriteByDataPortBlocking(base, data);
801 if (error != kStatus_Success)
802 {
803 return error;
804 }
805 }
806 }
807
808 return error;
809 }
810
811 /*!
812 * brief USDHC module initialization function.
813 *
814 * Configures the USDHC according to the user configuration.
815 *
816 * Example:
817 code
818 usdhc_config_t config;
819 config.cardDetectDat3 = false;
820 config.endianMode = kUSDHC_EndianModeLittle;
821 config.dmaMode = kUSDHC_DmaModeAdma2;
822 config.readWatermarkLevel = 128U;
823 config.writeWatermarkLevel = 128U;
824 USDHC_Init(USDHC, &config);
825 endcode
826 *
827 * param base USDHC peripheral base address.
828 * param config USDHC configuration information.
829 * retval kStatus_Success Operate successfully.
830 */
USDHC_Init(USDHC_Type * base,const usdhc_config_t * config)831 void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
832 {
833 assert(config != NULL);
834 assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
835 assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
836 #if !(defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
837 assert(config->writeBurstLen <= 16U);
838 #endif
839 uint32_t proctl, sysctl, wml;
840
841 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
842 /* Enable USDHC clock. */
843 CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
844 #endif
845
846 #if (defined(FSL_FEATURE_USDHC_HAS_RESET) && FSL_FEATURE_USDHC_HAS_RESET)
847 /* Reset the USDHC module */
848 RESET_PeripheralReset(s_usdhcResets[USDHC_GetInstance(base)]);
849 #endif
850
851 /* Reset ALL USDHC. */
852 base->SYS_CTRL |= USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK;
853
854 proctl = base->PROT_CTRL;
855 wml = base->WTMK_LVL;
856 sysctl = base->SYS_CTRL;
857
858 proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
859 /* Endian mode*/
860 proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
861
862 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
863 /* Watermark level */
864 wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK);
865 wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel));
866 #else
867 /* Watermark level */
868 wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
869 USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
870 wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
871 USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
872 #endif
873
874 /* config the data timeout value */
875 sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
876 sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
877
878 base->SYS_CTRL = sysctl;
879 base->WTMK_LVL = wml;
880 base->PROT_CTRL = proctl;
881
882 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
883 /* disable external DMA */
884 base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
885 #endif
886 /* disable internal DMA and DDR mode */
887 base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
888 /* disable interrupt, enable all the interrupt status, clear status. */
889 base->INT_STATUS_EN = kUSDHC_AllInterruptFlags;
890 base->INT_SIGNAL_EN = 0UL;
891 base->INT_STATUS = kUSDHC_AllInterruptFlags;
892 }
893
894 /*!
895 * brief Deinitializes the USDHC.
896 *
897 * param base USDHC peripheral base address.
898 */
USDHC_Deinit(USDHC_Type * base)899 void USDHC_Deinit(USDHC_Type *base)
900 {
901 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
902 /* Disable clock. */
903 CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
904 #endif
905 }
906
907 /*!
908 * brief Resets the USDHC.
909 *
910 * param base USDHC peripheral base address.
911 * param mask The reset type mask(_usdhc_reset).
912 * param timeout Timeout for reset.
913 * retval true Reset successfully.
914 * retval false Reset failed.
915 */
USDHC_Reset(USDHC_Type * base,uint32_t mask,uint32_t timeout)916 bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
917 {
918 base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK
919 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
920 | USDHC_SYS_CTRL_RSTT_MASK
921 #endif
922 ));
923 /* Delay some time to wait reset success. */
924 while (IS_USDHC_FLAG_SET(base->SYS_CTRL, mask))
925 {
926 if (timeout == 0UL)
927 {
928 break;
929 }
930 timeout--;
931 }
932
933 return ((0UL == timeout) ? false : true);
934 }
935
936 /*!
937 * brief Gets the capability information.
938 *
939 * param base USDHC peripheral base address.
940 * param capability Structure to save capability information.
941 */
USDHC_GetCapability(USDHC_Type * base,usdhc_capability_t * capability)942 void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
943 {
944 assert(capability != NULL);
945
946 uint32_t htCapability;
947 uint32_t maxBlockLength;
948
949 htCapability = base->HOST_CTRL_CAP;
950
951 /* Get the capability of USDHC. */
952 maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
953 capability->maxBlockLength = (512UL << maxBlockLength);
954 /* Other attributes not in HTCAPBLT register. */
955 capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
956 capability->flags =
957 (htCapability & (USDHC_HOST_CTRL_CAP_ADMAS_MASK | USDHC_HOST_CTRL_CAP_HSS_MASK | USDHC_HOST_CTRL_CAP_DMAS_MASK |
958 USDHC_HOST_CTRL_CAP_SRS_MASK | USDHC_HOST_CTRL_CAP_VS33_MASK));
959 capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS30_MASK;
960 capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_VS18_MASK;
961 capability->flags |= htCapability & USDHC_HOST_CTRL_CAP_DDR50_SUPPORT_MASK;
962 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR104_MODE
963 capability->flags |= USDHC_HOST_CTRL_CAP_SDR104_SUPPORT_MASK;
964 #endif
965
966 #if defined(FSL_FEATURE_USDHC_HAS_SDR104_MODE) && FSL_FEATURE_USDHC_HAS_SDR50_MODE
967 capability->flags |= USDHC_HOST_CTRL_CAP_SDR50_SUPPORT_MASK;
968 #endif
969 /* USDHC support 4/8 bit data bus width. */
970 capability->flags |= (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 0UL) | (USDHC_HOST_CTRL_CAP_MBL_SHIFT << 1UL);
971 }
972
973 /*!
974 * brief Sets the SD bus clock frequency.
975 *
976 * param base USDHC peripheral base address.
977 * param srcClock_Hz USDHC source clock frequency united in Hz.
978 * param busClock_Hz SD bus clock frequency united in Hz.
979 *
980 * return The nearest frequency of busClock_Hz configured to SD bus.
981 */
USDHC_SetSdClock(USDHC_Type * base,uint32_t srcClock_Hz,uint32_t busClock_Hz)982 uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
983 {
984 assert(srcClock_Hz != 0U);
985 assert(busClock_Hz != 0U);
986
987 uint32_t totalDiv = 0UL;
988 uint32_t divisor = 0UL;
989 uint32_t prescaler = 0UL;
990 uint32_t sysctl = 0UL;
991 uint32_t nearestFrequency = 0UL;
992
993 if (busClock_Hz > srcClock_Hz)
994 {
995 busClock_Hz = srcClock_Hz;
996 }
997
998 totalDiv = srcClock_Hz / busClock_Hz;
999
1000 /* calucate total divisor first */
1001 if (totalDiv > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
1002 {
1003 return 0UL;
1004 }
1005
1006 if (totalDiv != 0UL)
1007 {
1008 /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
1009 if ((srcClock_Hz / totalDiv) > busClock_Hz)
1010 {
1011 totalDiv++;
1012 }
1013
1014 /* divide the total divisor to div and prescaler */
1015 if (totalDiv > USDHC_MAX_DVS)
1016 {
1017 prescaler = totalDiv / USDHC_MAX_DVS;
1018 /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
1019 while (((USDHC_MAX_CLKFS % prescaler) != 0UL) || (prescaler == 1UL))
1020 {
1021 prescaler++;
1022 }
1023 /* calucate the divisor */
1024 divisor = totalDiv / prescaler;
1025 /* fine tuning the divisor until divisor * prescaler >= totalDiv */
1026 while ((divisor * prescaler) < totalDiv)
1027 {
1028 divisor++;
1029 if (divisor > USDHC_MAX_DVS)
1030 {
1031 prescaler <<= 1UL;
1032 if (prescaler > USDHC_MAX_CLKFS)
1033 {
1034 return 0UL;
1035 }
1036 divisor = totalDiv / prescaler;
1037 }
1038 }
1039 }
1040 else
1041 {
1042 /* in this situation , divsior and SDCLKFS can generate same clock
1043 use SDCLKFS*/
1044 if (((totalDiv % 2UL) != 0UL) && (totalDiv != 1UL))
1045 {
1046 divisor = totalDiv;
1047 prescaler = 1UL;
1048 }
1049 else
1050 {
1051 divisor = 1UL;
1052 prescaler = totalDiv;
1053 }
1054 }
1055 nearestFrequency = srcClock_Hz / (divisor == 0UL ? 1UL : divisor) / prescaler;
1056 }
1057 /* in this condition , srcClock_Hz = busClock_Hz, */
1058 else
1059 {
1060 /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
1061 totoal divider = 2U */
1062 divisor = 0UL;
1063 prescaler = 0UL;
1064 nearestFrequency = srcClock_Hz;
1065 }
1066
1067 /* calucate the value write to register */
1068 if (divisor != 0UL)
1069 {
1070 USDHC_PREV_DVS(divisor);
1071 }
1072 /* calucate the value write to register */
1073 if (prescaler != 0UL)
1074 {
1075 USDHC_PREV_CLKFS(prescaler, 1UL);
1076 }
1077
1078 /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
1079 sysctl = base->SYS_CTRL;
1080 sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
1081 sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
1082 base->SYS_CTRL = sysctl;
1083
1084 /* Wait until the SD clock is stable. */
1085 while (!IS_USDHC_FLAG_SET(base->PRES_STATE, USDHC_PRES_STATE_SDSTB_MASK))
1086 {
1087 }
1088
1089 return nearestFrequency;
1090 }
1091
1092 /*!
1093 * brief Sends 80 clocks to the card to set it to the active state.
1094 *
1095 * This function must be called each time the card is inserted to ensure that the card can receive the command
1096 * correctly.
1097 *
1098 * param base USDHC peripheral base address.
1099 * param timeout Timeout to initialize card.
1100 * retval true Set card active successfully.
1101 * retval false Set card active failed.
1102 */
USDHC_SetCardActive(USDHC_Type * base,uint32_t timeout)1103 bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
1104 {
1105 base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
1106 /* Delay some time to wait card become active state. */
1107 while (IS_USDHC_FLAG_SET(base->SYS_CTRL, USDHC_SYS_CTRL_INITA_MASK))
1108 {
1109 if (0UL == timeout)
1110 {
1111 break;
1112 }
1113 timeout--;
1114 }
1115
1116 return ((0UL == timeout) ? false : true);
1117 }
1118
1119 /*!
1120 * brief the enable/disable DDR mode
1121 *
1122 * param base USDHC peripheral base address.
1123 * param enable/disable flag
1124 * param nibble position
1125 */
USDHC_EnableDDRMode(USDHC_Type * base,bool enable,uint32_t nibblePos)1126 void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
1127 {
1128 uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
1129
1130 if (enable)
1131 {
1132 base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
1133 base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
1134 prescaler >>= 1UL;
1135 }
1136 else
1137 {
1138 base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
1139
1140 if (prescaler == 0UL)
1141 {
1142 prescaler += 1UL;
1143 }
1144 else
1145 {
1146 prescaler <<= 1UL;
1147 }
1148 }
1149
1150 base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
1151 }
1152
1153 /*!
1154 * brief Configures the MMC boot feature.
1155 *
1156 * Example:
1157 code
1158 usdhc_boot_config_t config;
1159 config.ackTimeoutCount = 4;
1160 config.bootMode = kUSDHC_BootModeNormal;
1161 config.blockCount = 5;
1162 config.enableBootAck = true;
1163 config.enableBoot = true;
1164 config.enableAutoStopAtBlockGap = true;
1165 USDHC_SetMmcBootConfig(USDHC, &config);
1166 endcode
1167 *
1168 * param base USDHC peripheral base address.
1169 * param config The MMC boot configuration information.
1170 */
USDHC_SetMmcBootConfig(USDHC_Type * base,const usdhc_boot_config_t * config)1171 void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
1172 {
1173 assert(config != NULL);
1174 assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
1175 assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
1176
1177 uint32_t mmcboot = base->MMC_BOOT;
1178
1179 mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
1180 mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
1181
1182 if (config->enableBootAck)
1183 {
1184 mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
1185 }
1186 if (config->enableAutoStopAtBlockGap)
1187 {
1188 mmcboot |=
1189 USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
1190 /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
1191 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1192 (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
1193 }
1194 else
1195 {
1196 base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
1197 (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
1198 }
1199
1200 base->MMC_BOOT = mmcboot;
1201 }
1202
1203 /*!
1204 * brief Sets the ADMA1 descriptor table configuration.
1205 *
1206 * param admaTable Adma table address.
1207 * param admaTableWords Adma table length.
1208 * param dataBufferAddr Data buffer address.
1209 * param dataBytes Data length.
1210 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1211 * reference _usdhc_adma_flag.
1212 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1213 * retval kStatus_Success Operate successfully.
1214 */
USDHC_SetADMA1Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)1215 status_t USDHC_SetADMA1Descriptor(
1216 uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1217 {
1218 assert(NULL != admaTable);
1219 assert(NULL != dataBufferAddr);
1220
1221 uint32_t miniEntries, startEntries = 0UL,
1222 maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
1223 usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(uint32_t)(admaTable);
1224 uint32_t i, dmaBufferLen = 0UL;
1225 const uint32_t *data = dataBufferAddr;
1226
1227 if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0UL)
1228 {
1229 return kStatus_USDHC_DMADataAddrNotAlign;
1230 }
1231
1232 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1233 {
1234 return kStatus_USDHC_NotSupport;
1235 }
1236 /*
1237 * Add non aligned access support ,user need make sure your buffer size is big
1238 * enough to hold the data,in other words,user need make sure the buffer size
1239 * is 4 byte aligned
1240 */
1241 if (dataBytes % sizeof(uint32_t) != 0UL)
1242 {
1243 /* make the data length as word-aligned */
1244 dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1245 }
1246
1247 /* Check if ADMA descriptor's number is enough. */
1248 if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1249 {
1250 miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1251 }
1252 else
1253 {
1254 miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1255 }
1256
1257 /* ADMA1 needs two descriptors to finish a transfer */
1258 miniEntries <<= 1UL;
1259
1260 if (miniEntries + startEntries > maxEntries)
1261 {
1262 return kStatus_OutOfRange;
1263 }
1264
1265 for (i = startEntries; i < (miniEntries + startEntries); i += 2UL)
1266 {
1267 if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1268 {
1269 dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1270 }
1271 else
1272 {
1273 dmaBufferLen = dataBytes;
1274 }
1275
1276 adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
1277 adma1EntryAddress[i] |= (uint32_t)kUSDHC_Adma1DescriptorTypeSetLength;
1278 adma1EntryAddress[i + 1UL] = (uint32_t)(data);
1279 adma1EntryAddress[i + 1UL] |=
1280 (uint32_t)kUSDHC_Adma1DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma1DescriptorInterrupFlag;
1281 data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1282 dataBytes -= dmaBufferLen;
1283 }
1284 /* the end of the descriptor */
1285 adma1EntryAddress[i - 1UL] |= (uint32_t)kUSDHC_Adma1DescriptorEndFlag;
1286
1287 return kStatus_Success;
1288 }
1289
1290 /*!
1291 * brief Sets the ADMA2 descriptor table configuration.
1292 *
1293 * param admaTable Adma table address.
1294 * param admaTableWords Adma table length.
1295 * param dataBufferAddr Data buffer address.
1296 * param dataBytes Data Data length.
1297 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1298 * reference _usdhc_adma_flag.
1299 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1300 * retval kStatus_Success Operate successfully.
1301 */
USDHC_SetADMA2Descriptor(uint32_t * admaTable,uint32_t admaTableWords,const uint32_t * dataBufferAddr,uint32_t dataBytes,uint32_t flags)1302 status_t USDHC_SetADMA2Descriptor(
1303 uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
1304 {
1305 assert(NULL != admaTable);
1306 assert(NULL != dataBufferAddr);
1307
1308 uint32_t miniEntries, startEntries = 0UL,
1309 maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
1310 usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(uint32_t)(admaTable);
1311 uint32_t i, dmaBufferLen = 0UL;
1312 const uint32_t *data = dataBufferAddr;
1313
1314 if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1315 {
1316 return kStatus_USDHC_DMADataAddrNotAlign;
1317 }
1318 /*
1319 * Add non aligned access support ,user need make sure your buffer size is big
1320 * enough to hold the data,in other words,user need make sure the buffer size
1321 * is 4 byte aligned
1322 */
1323 if (dataBytes % sizeof(uint32_t) != 0UL)
1324 {
1325 /* make the data length as word-aligned */
1326 dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
1327 }
1328
1329 /* Check if ADMA descriptor's number is enough. */
1330 if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0UL)
1331 {
1332 miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1333 }
1334 else
1335 {
1336 miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1UL);
1337 }
1338 /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
1339 data adress and data size is enough */
1340 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1341 {
1342 for (i = 0UL; i < maxEntries; i++)
1343 {
1344 if ((adma2EntryAddress[i].attribute & (uint32_t)kUSDHC_Adma2DescriptorValidFlag) == 0UL)
1345 {
1346 break;
1347 }
1348 }
1349 startEntries = i;
1350 /* add one entry for dummy entry */
1351 miniEntries += 1UL;
1352 }
1353
1354 if ((miniEntries + startEntries) > maxEntries)
1355 {
1356 return kStatus_OutOfRange;
1357 }
1358
1359 for (i = startEntries; i < (miniEntries + startEntries); i++)
1360 {
1361 if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
1362 {
1363 dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1364 }
1365 else
1366 {
1367 dmaBufferLen = (dataBytes == 0UL ? sizeof(uint32_t) :
1368 dataBytes); /* adma don't support 0 data length transfer descriptor */
1369 }
1370
1371 /* Each descriptor for ADMA2 is 64-bit in length */
1372 adma2EntryAddress[i].address = (dataBytes == 0UL) ? &s_usdhcBootDummy : data;
1373 adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
1374 adma2EntryAddress[i].attribute |=
1375 (dataBytes == 0UL) ?
1376 0UL :
1377 ((uint32_t)kUSDHC_Adma2DescriptorTypeTransfer | (uint32_t)kUSDHC_Adma2DescriptorInterruptFlag);
1378 data = (uint32_t *)((uint32_t)data + dmaBufferLen);
1379
1380 if (dataBytes != 0UL)
1381 {
1382 dataBytes -= dmaBufferLen;
1383 }
1384 }
1385
1386 /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
1387 engine
1388 will not stop at block gap */
1389 if (flags == (uint32_t)kUSDHC_AdmaDescriptorMultipleFlag)
1390 {
1391 adma2EntryAddress[startEntries + 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorTypeTransfer;
1392 }
1393 else
1394 {
1395 /* set the end bit */
1396 adma2EntryAddress[i - 1UL].attribute |= (uint32_t)kUSDHC_Adma2DescriptorEndFlag;
1397 }
1398
1399 return kStatus_Success;
1400 }
1401
1402 /*!
1403 * brief Internal DMA configuration.
1404 * This function is used to config the USDHC DMA related registers.
1405 * param base USDHC peripheral base address.
1406 * param adma configuration
1407 * param dataAddr transfer data address, a simple DMA parameter, if ADMA is used, leave it to NULL.
1408 * param enAutoCmd23 flag to indicate Auto CMD23 is enable or not, a simple DMA parameter,if ADMA is used, leave it to
1409 * false.
1410 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1411 * retval kStatus_Success Operate successfully.
1412 */
USDHC_SetInternalDmaConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,const uint32_t * dataAddr,bool enAutoCmd23)1413 status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
1414 usdhc_adma_config_t *dmaConfig,
1415 const uint32_t *dataAddr,
1416 bool enAutoCmd23)
1417 {
1418 assert(dmaConfig != NULL);
1419 assert(dataAddr != NULL);
1420 assert((NULL != dmaConfig->admaTable) &&
1421 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1422
1423 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1424 /* disable the external DMA if support */
1425 base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1426 #endif
1427
1428 if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1429 {
1430 /* check DMA data buffer address align or not */
1431 if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0UL)
1432 {
1433 return kStatus_USDHC_DMADataAddrNotAlign;
1434 }
1435 /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
1436 and block count should load to DS_ADDR*/
1437 if (enAutoCmd23)
1438 {
1439 base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1440 }
1441 else
1442 {
1443 base->DS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)dataAddr);
1444 }
1445 }
1446 else
1447 {
1448 /* When use ADMA, disable simple DMA */
1449 base->DS_ADDR = 0UL;
1450 base->ADMA_SYS_ADDR = USDHC_ADDR_CPU_2_DMA((uint32_t)(dmaConfig->admaTable));
1451 }
1452
1453 #if (defined(FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN) && FSL_FEATURE_USDHC_HAS_NO_RW_BURST_LEN)
1454 /* select DMA mode and config the burst length */
1455 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1456 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1457 #else
1458 /* select DMA mode and config the burst length */
1459 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
1460 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
1461 #endif
1462 /* enable DMA */
1463 base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1464
1465 return kStatus_Success;
1466 }
1467
1468 /*!
1469 * brief Sets the DMA descriptor table configuration.
1470 * A high level DMA descriptor configuration function.
1471 * param base USDHC peripheral base address.
1472 * param adma configuration
1473 * param data Data descriptor
1474 * param flags ADAM descriptor flag, used to indicate to create multiple or single descriptor, please
1475 * reference _usdhc_adma_flag
1476 * retval kStatus_OutOfRange ADMA descriptor table length isn't enough to describe data.
1477 * retval kStatus_Success Operate successfully.
1478 */
USDHC_SetAdmaTableConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_data_t * dataConfig,uint32_t flags)1479 status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
1480 usdhc_adma_config_t *dmaConfig,
1481 usdhc_data_t *dataConfig,
1482 uint32_t flags)
1483 {
1484 assert(NULL != dmaConfig);
1485 assert((NULL != dmaConfig->admaTable) &&
1486 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1487 assert(NULL != dataConfig);
1488
1489 status_t error = kStatus_Fail;
1490 uint32_t bootDummyOffset =
1491 dataConfig->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0UL;
1492 const uint32_t *data = (const uint32_t *)USDHC_ADDR_CPU_2_DMA((uint32_t)(
1493 (uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) + bootDummyOffset));
1494 uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
1495
1496 #if FSL_FEATURE_USDHC_HAS_EXT_DMA
1497 if (dmaConfig->dmaMode == kUSDHC_ExternalDMA)
1498 {
1499 /* enable the external DMA */
1500 base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
1501 }
1502 else
1503 #endif
1504 if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
1505 {
1506 error = kStatus_Success;
1507 }
1508 else if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1509 {
1510 error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1511 }
1512 /* ADMA2 */
1513 else
1514 {
1515 error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
1516 }
1517
1518 /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
1519 * boot data, only the DMA descriptor need update */
1520 if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
1521 (dataConfig->dataType != (uint32_t)kUSDHC_TransferDataBootcontinous))
1522 {
1523 error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
1524 }
1525
1526 return error;
1527 }
1528
1529 /*!
1530 * brief Transfers the command/data using a blocking method.
1531 *
1532 * This function waits until the command response/data is received or the USDHC encounters an error by polling the
1533 * status
1534 * flag.
1535 * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1536 * the re-entry mechanism.
1537 *
1538 * note There is no need to call the API 'USDHC_TransferCreateHandle' when calling this API.
1539 *
1540 * param base USDHC peripheral base address.
1541 * param adma configuration
1542 * param transfer Transfer content.
1543 * retval kStatus_InvalidArgument Argument is invalid.
1544 * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1545 * retval kStatus_USDHC_SendCommandFailed Send command failed.
1546 * retval kStatus_USDHC_TransferDataFailed Transfer data failed.
1547 * retval kStatus_Success Operate successfully.
1548 */
USDHC_TransferBlocking(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)1549 status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
1550 {
1551 assert(transfer != NULL);
1552
1553 status_t error = kStatus_Fail;
1554 usdhc_command_t *command = transfer->command;
1555 usdhc_data_t *data = transfer->data;
1556 bool enDMA = true;
1557 bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1558 uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
1559 size_t blockSize = 0U;
1560 size_t blockCount = 0U;
1561
1562 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1563 /*check re-tuning request*/
1564 if ((USDHC_GetInterruptStatusFlags(base) & (uint32_t)kUSDHC_ReTuningEventFlag) != 0UL)
1565 {
1566 USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1567 return kStatus_USDHC_ReTuningRequest;
1568 }
1569 #endif
1570
1571 if (data != NULL)
1572 {
1573 /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1574 if ((dmaConfig != NULL) && (!executeTuning))
1575 {
1576 error = USDHC_SetAdmaTableConfig(base, dmaConfig, data,
1577 (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, kUSDHC_TransferDataBoot) ?
1578 kUSDHC_AdmaDescriptorMultipleFlag :
1579 kUSDHC_AdmaDescriptorSingleFlag));
1580 }
1581 blockSize = data->blockSize;
1582 blockCount = data->blockCount;
1583 transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1584 transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1585 transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1586 transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1587 transferFlags |=
1588 data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1589
1590 command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1591 }
1592
1593 /* if the DMA desciptor configure fail or not needed , disable it */
1594 if (error != kStatus_Success)
1595 {
1596 enDMA = false;
1597 /* disable DMA, using polling mode in this situation */
1598 USDHC_EnableInternalDMA(base, false);
1599 }
1600 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1601 else
1602 {
1603 if (data->txData != NULL)
1604 {
1605 /* clear the DCACHE */
1606 DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1607 }
1608 else
1609 {
1610 /* clear the DCACHE */
1611 DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1612 }
1613 }
1614 #endif
1615
1616 /* config the data transfer parameter */
1617 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1618 if (error != kStatus_Success)
1619 {
1620 return error;
1621 }
1622 /* send command first */
1623 USDHC_SendCommand(base, command);
1624 /* wait command done */
1625 error =
1626 USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == (uint32_t)kUSDHC_TransferDataNormal));
1627 if (kStatus_Success != error)
1628 {
1629 return kStatus_USDHC_SendCommandFailed;
1630 }
1631
1632 /* wait transfer data finsih */
1633 if (data != NULL)
1634 {
1635 error = USDHC_TransferDataBlocking(base, data, enDMA);
1636 if (kStatus_Success != error)
1637 {
1638 return error;
1639 }
1640 }
1641
1642 return kStatus_Success;
1643 }
1644
1645 #if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type * base,usdhc_adma_config_t * dmaConfig,usdhc_scatter_gather_data_t * dataConfig,uint32_t * totalTransferSize)1646 static status_t USDHC_SetScatterGatherAdmaTableConfig(USDHC_Type *base,
1647 usdhc_adma_config_t *dmaConfig,
1648 usdhc_scatter_gather_data_t *dataConfig,
1649 uint32_t *totalTransferSize)
1650 {
1651 assert(NULL != dmaConfig);
1652 assert((NULL != dmaConfig->admaTable) &&
1653 (((USDHC_ADMA_TABLE_ADDRESS_ALIGN - 1U) & (uint32_t)dmaConfig->admaTable) == 0UL));
1654 assert(NULL != dataConfig);
1655
1656 status_t error = kStatus_Fail;
1657 uint32_t *admaDesBuffer = dmaConfig->admaTable;
1658 uint32_t admaDesLen = dmaConfig->admaTableWords;
1659 usdhc_scatter_gather_data_list_t *sgDataList = &dataConfig->sgData;
1660 uint32_t oneDescriptorMaxTransferSize = dmaConfig->dmaMode == kUSDHC_DmaModeAdma1 ?
1661 USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY :
1662 USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
1663 uint32_t miniEntries = 0U;
1664
1665 while (sgDataList != NULL)
1666 {
1667 if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1668 {
1669 error = USDHC_SetADMA1Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1670 }
1671 /* ADMA2 */
1672 else
1673 {
1674 error = USDHC_SetADMA2Descriptor(admaDesBuffer, admaDesLen, sgDataList->dataAddr, sgDataList->dataSize, 0U);
1675 }
1676
1677 if (error != kStatus_Success)
1678 {
1679 return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1680 }
1681
1682 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1683 if (dataConfig->dataDirection == kUSDHC_TransferDirectionSend)
1684 {
1685 /* clear the DCACHE */
1686 DCACHE_CleanByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1687 }
1688 else
1689 {
1690 /* clear the DCACHE */
1691 DCACHE_CleanInvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
1692 }
1693 #endif
1694
1695 *totalTransferSize += sgDataList->dataSize;
1696 if (sgDataList->dataList != NULL)
1697 {
1698 if ((sgDataList->dataSize % oneDescriptorMaxTransferSize) == 0UL)
1699 {
1700 miniEntries = sgDataList->dataSize / oneDescriptorMaxTransferSize;
1701 }
1702 else
1703 {
1704 miniEntries = ((sgDataList->dataSize / oneDescriptorMaxTransferSize) + 1UL);
1705 }
1706 if (dmaConfig->dmaMode == kUSDHC_DmaModeAdma1)
1707 {
1708 admaDesBuffer[miniEntries * 2U - 1U] &= ~kUSDHC_Adma1DescriptorEndFlag;
1709 }
1710 else
1711 {
1712 admaDesBuffer[miniEntries * 2U - 2U] &= ~kUSDHC_Adma2DescriptorEndFlag;
1713 }
1714 admaDesBuffer += miniEntries * 2U;
1715 admaDesLen -= miniEntries * 2U;
1716 }
1717
1718 sgDataList = sgDataList->dataList;
1719 }
1720
1721 base->DS_ADDR = 0UL;
1722 base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
1723
1724 /* select DMA mode and config the burst length */
1725 base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK);
1726 base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode);
1727
1728 /* enable DMA */
1729 base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
1730
1731 return error;
1732 }
1733
1734 /*!
1735 * brief Transfers the command/scatter gather data using an interrupt and an asynchronous method.
1736 *
1737 * This function sends a command and data and returns immediately. It doesn't wait for the transfer to complete or
1738 * to encounter an error. The application must not call this API in multiple threads at the same time. Because of that
1739 * this API doesn't support the re-entry mechanism.
1740 * This function is target for the application would like to have scatter gather buffer to be transferred within one
1741 * read/write request, non scatter gather buffer is support by this function also.
1742 *
1743 * note Call API @ref USDHC_TransferCreateHandle when calling this API.
1744 *
1745 * param base USDHC peripheral base address.
1746 * param handle USDHC handle.
1747 * param dmaConfig adma configurations, must be not NULL, since the function is target for ADMA only.
1748 * param transfer scatter gather transfer content.
1749 *
1750 * retval #kStatus_InvalidArgument Argument is invalid.
1751 * retval #kStatus_USDHC_BusyTransferring Busy transferring.
1752 * retval #kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1753 * retval #kStatus_Success Operate successfully.
1754 */
USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_scatter_gather_transfer_t * transfer)1755 status_t USDHC_TransferScatterGatherADMANonBlocking(USDHC_Type *base,
1756 usdhc_handle_t *handle,
1757 usdhc_adma_config_t *dmaConfig,
1758 usdhc_scatter_gather_transfer_t *transfer)
1759 {
1760 assert(handle != NULL);
1761 assert(transfer != NULL);
1762 assert(dmaConfig != NULL);
1763
1764 status_t error = kStatus_Fail;
1765 usdhc_command_t *command = transfer->command;
1766 uint32_t totalTransferSize = 0U;
1767 uint32_t transferFlags = kUSDHC_CommandOnly;
1768 size_t blockSize = 0U;
1769 size_t blockCount = 0U;
1770 usdhc_scatter_gather_data_t *scatterGatherData = transfer->data;
1771 bool enDMA = false;
1772
1773 /* check data inhibit flag */
1774 if (IS_USDHC_FLAG_SET(base->PRES_STATE, kUSDHC_CommandInhibitFlag))
1775 {
1776 return kStatus_USDHC_BusyTransferring;
1777 }
1778
1779 handle->command = command;
1780 handle->data = scatterGatherData;
1781 /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1782 handle->transferredWords = 0UL;
1783
1784 /* Update ADMA descriptor table according to different DMA mode(ADMA1, ADMA2).*/
1785 if (scatterGatherData != NULL)
1786 {
1787 if (scatterGatherData->sgData.dataAddr == NULL)
1788 {
1789 return kStatus_InvalidArgument;
1790 }
1791
1792 if (scatterGatherData->dataType != (uint32_t)kUSDHC_TransferDataTuning)
1793 {
1794 if (USDHC_SetScatterGatherAdmaTableConfig(base, dmaConfig, transfer->data, &totalTransferSize) !=
1795 kStatus_Success)
1796 {
1797 return kStatus_USDHC_PrepareAdmaDescriptorFailed;
1798 }
1799
1800 enDMA = true;
1801 }
1802 blockSize = scatterGatherData->blockSize;
1803 blockCount = totalTransferSize / scatterGatherData->blockSize;
1804 transferFlags = scatterGatherData->enableAutoCommand12 ? kUSDHC_DataWithAutoCmd12 : 0U;
1805 transferFlags |= scatterGatherData->enableAutoCommand23 ? kUSDHC_DataWithAutoCmd23 : 0U;
1806 transferFlags |= scatterGatherData->dataDirection == kUSDHC_TransferDirectionSend ? kUSDHC_CommandAndTxData :
1807 kUSDHC_CommandAndRxData;
1808 command->flags |= kUSDHC_DataPresentFlag;
1809 }
1810
1811 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1812 if (error != kStatus_Success)
1813 {
1814 return error;
1815 }
1816
1817 /* enable interrupt per transfer request */
1818 if (scatterGatherData != NULL)
1819 {
1820 USDHC_ClearInterruptStatusFlags(
1821 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1822 (uint32_t)kUSDHC_CommandFlag);
1823 USDHC_EnableInterruptSignal(
1824 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag | kUSDHC_DmaCompleteFlag) |
1825 (uint32_t)kUSDHC_CommandFlag);
1826 }
1827 else
1828 {
1829 USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1830 USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1831 }
1832
1833 /* send command first */
1834 USDHC_SendCommand(base, command);
1835
1836 return kStatus_Success;
1837 }
1838 #else
1839 /*!
1840 * brief Transfers the command/data using an interrupt and an asynchronous method.
1841 *
1842 * This function sends a command and data and returns immediately. It doesn't wait the transfer complete or encounter an
1843 * error.
1844 * The application must not call this API in multiple threads at the same time. Because of that this API doesn't support
1845 * the re-entry mechanism.
1846 *
1847 * note Call the API 'USDHC_TransferCreateHandle' when calling this API.
1848 *
1849 * param base USDHC peripheral base address.
1850 * param handle USDHC handle.
1851 * param adma configuration.
1852 * param transfer Transfer content.
1853 * retval kStatus_InvalidArgument Argument is invalid.
1854 * retval kStatus_USDHC_BusyTransferring Busy transferring.
1855 * retval kStatus_USDHC_PrepareAdmaDescriptorFailed Prepare ADMA descriptor failed.
1856 * retval kStatus_Success Operate successfully.
1857 */
USDHC_TransferNonBlocking(USDHC_Type * base,usdhc_handle_t * handle,usdhc_adma_config_t * dmaConfig,usdhc_transfer_t * transfer)1858 status_t USDHC_TransferNonBlocking(USDHC_Type *base,
1859 usdhc_handle_t *handle,
1860 usdhc_adma_config_t *dmaConfig,
1861 usdhc_transfer_t *transfer)
1862 {
1863 assert(handle != NULL);
1864 assert(transfer != NULL);
1865
1866 status_t error = kStatus_Fail;
1867 usdhc_command_t *command = transfer->command;
1868 usdhc_data_t *data = transfer->data;
1869 bool executeTuning = ((data == NULL) ? false : data->dataType == (uint32_t)kUSDHC_TransferDataTuning);
1870 bool enDMA = true;
1871 uint32_t transferFlags = (uint32_t)kUSDHC_CommandOnly;
1872 size_t blockSize = 0U;
1873 size_t blockCount = 0U;
1874
1875 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1876 /*check re-tuning request*/
1877 if ((USDHC_GetInterruptStatusFlags(base) & ((uint32_t)kUSDHC_ReTuningEventFlag)) != 0UL)
1878 {
1879 USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
1880 return kStatus_USDHC_ReTuningRequest;
1881 }
1882 #endif
1883 /* Save command and data into handle before transferring. */
1884
1885 handle->command = command;
1886 handle->data = data;
1887 /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
1888 handle->transferredWords = 0UL;
1889
1890 if (data != NULL)
1891 {
1892 /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
1893 if ((dmaConfig != NULL) && (!executeTuning))
1894 {
1895 error = USDHC_SetAdmaTableConfig(
1896 base, dmaConfig, data,
1897 (uint32_t)(IS_USDHC_FLAG_SET(data->dataType, (uint32_t)kUSDHC_TransferDataBoot) ?
1898 kUSDHC_AdmaDescriptorMultipleFlag :
1899 kUSDHC_AdmaDescriptorSingleFlag));
1900 }
1901
1902 blockSize = data->blockSize;
1903 blockCount = data->blockCount;
1904 transferFlags = data->enableAutoCommand12 ? (uint32_t)kUSDHC_DataWithAutoCmd12 : 0U;
1905 transferFlags |= data->enableAutoCommand23 ? (uint32_t)kUSDHC_DataWithAutoCmd23 : 0U;
1906 transferFlags |= data->txData != NULL ? (uint32_t)kUSDHC_CommandAndTxData : (uint32_t)kUSDHC_CommandAndRxData;
1907 transferFlags |= data->dataType == (uint8_t)kUSDHC_TransferDataBoot ? (uint32_t)kUSDHC_BootData : 0U;
1908 transferFlags |=
1909 data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ? (uint32_t)kUSDHC_BootDataContinuous : 0U;
1910
1911 command->flags |= (uint32_t)kUSDHC_DataPresentFlag;
1912 }
1913
1914 /* if the DMA desciptor configure fail or not needed , disable it */
1915 if (error != kStatus_Success)
1916 {
1917 /* disable DMA, using polling mode in this situation */
1918 USDHC_EnableInternalDMA(base, false);
1919 enDMA = false;
1920 }
1921 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
1922 else
1923 {
1924 if (data->txData != NULL)
1925 {
1926 /* clear the DCACHE */
1927 DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
1928 }
1929 else
1930 {
1931 /* clear the DCACHE */
1932 DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
1933 }
1934 }
1935 #endif
1936
1937 /* config the data transfer parameter */
1938 error = USDHC_SetTransferConfig(base, transferFlags, blockSize, blockCount);
1939 if (error != kStatus_Success)
1940 {
1941 return error;
1942 }
1943
1944 /* enable interrupt per transfer request */
1945 if (handle->data != NULL)
1946 {
1947 USDHC_ClearInterruptStatusFlags(
1948 base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) | (uint32_t)kUSDHC_CommandFlag |
1949 (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1950 (uint32_t)kUSDHC_DmaCompleteFlag :
1951 0U));
1952 USDHC_EnableInterruptSignal(base, (uint32_t)(enDMA == false ? kUSDHC_DataFlag : kUSDHC_DataDMAFlag) |
1953 (uint32_t)kUSDHC_CommandFlag |
1954 (uint32_t)(data->dataType == (uint8_t)kUSDHC_TransferDataBootcontinous ?
1955 (uint32_t)kUSDHC_DmaCompleteFlag :
1956 0U));
1957 }
1958 else
1959 {
1960 USDHC_ClearInterruptStatusFlags(base, kUSDHC_CommandFlag);
1961 USDHC_EnableInterruptSignal(base, kUSDHC_CommandFlag);
1962 }
1963
1964 /* send command first */
1965 USDHC_SendCommand(base, command);
1966
1967 return kStatus_Success;
1968 }
1969 #endif
1970
1971 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
1972 /*!
1973 * brief manual tuning trigger or abort
1974 * User should handle the tuning cmd and find the boundary of the delay
1975 * then calucate a average value which will be config to the CLK_TUNE_CTRL_STATUS
1976 * This function should called before USDHC_AdjustDelayforSDR104 function
1977 * param base USDHC peripheral base address.
1978 * param tuning enable flag
1979 */
USDHC_EnableManualTuning(USDHC_Type * base,bool enable)1980 void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
1981 {
1982 if (enable)
1983 {
1984 /* make sure std_tun_en bit is clear */
1985 base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
1986 /* disable auto tuning here */
1987 base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
1988 /* execute tuning for SDR104 mode */
1989 base->MIX_CTRL |= USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK;
1990 }
1991 else
1992 { /* abort the tuning */
1993 base->MIX_CTRL &= ~USDHC_MIX_CTRL_EXE_TUNE_MASK;
1994 }
1995 }
1996
1997 /*!
1998 * brief the SDR104 mode delay setting adjust
1999 * This function should called after USDHC_ManualTuningForSDR104
2000 * param base USDHC peripheral base address.
2001 * param delay setting configuration
2002 * retval kStatus_Fail config the delay setting fail
2003 * retval kStatus_Success config the delay setting success
2004 */
USDHC_AdjustDelayForManualTuning(USDHC_Type * base,uint32_t delay)2005 status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
2006 {
2007 uint32_t clkTuneCtrl = 0UL;
2008
2009 clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2010
2011 clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
2012
2013 clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
2014
2015 /* load the delay setting */
2016 base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2017 /* check delat setting error */
2018 if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2019 USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2020 {
2021 return kStatus_Fail;
2022 }
2023
2024 return kStatus_Success;
2025 }
2026
2027 /*!
2028 * brief The tuning delay cell setting.
2029 *
2030 * param base USDHC peripheral base address.
2031 * param preDelay Set the number of delay cells on the feedback clock between the feedback clock and CLK_PRE.
2032 * param outDelay Set the number of delay cells on the feedback clock between CLK_PRE and CLK_OUT.
2033 * param postDelay Set the number of delay cells on the feedback clock between CLK_OUT and CLK_POST.
2034 * retval kStatus_Fail config the delay setting fail
2035 * retval kStatus_Success config the delay setting success
2036 */
USDHC_SetTuningDelay(USDHC_Type * base,uint32_t preDelay,uint32_t outDelay,uint32_t postDelay)2037 status_t USDHC_SetTuningDelay(USDHC_Type *base, uint32_t preDelay, uint32_t outDelay, uint32_t postDelay)
2038 {
2039 assert(preDelay <=
2040 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_SHIFT));
2041 assert(outDelay <=
2042 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_SHIFT));
2043 assert(postDelay <=
2044 (USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK >> USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_SHIFT));
2045
2046 uint32_t clkTuneCtrl = 0UL;
2047
2048 clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
2049
2050 clkTuneCtrl &=
2051 ~(USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK | USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT_MASK |
2052 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST_MASK);
2053
2054 clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(preDelay) |
2055 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_OUT(outDelay) |
2056 USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_POST(postDelay);
2057
2058 /* load the delay setting */
2059 base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
2060 /* check delat setting error */
2061 if (IS_USDHC_FLAG_SET(base->CLK_TUNE_CTRL_STATUS,
2062 USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
2063 {
2064 return kStatus_Fail;
2065 }
2066
2067 return kStatus_Success;
2068 }
2069
2070 /*!
2071 * brief the enable standard tuning function
2072 * The standard tuning window and tuning counter use the default config
2073 * tuning cmd is send by the software, user need to check the tuning result
2074 * can be used for SDR50,SDR104,HS200 mode tuning
2075 * param base USDHC peripheral base address.
2076 * param tuning start tap
2077 * param tuning step
2078 * param enable/disable flag
2079 */
USDHC_EnableStandardTuning(USDHC_Type * base,uint32_t tuningStartTap,uint32_t step,bool enable)2080 void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
2081 {
2082 uint32_t tuningCtrl = 0UL;
2083
2084 if (enable)
2085 {
2086 /* feedback clock */
2087 base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
2088 /* config tuning start and step */
2089 tuningCtrl = base->TUNING_CTRL;
2090 tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
2091 tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
2092 USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
2093 base->TUNING_CTRL = tuningCtrl;
2094
2095 /* excute tuning */
2096 base->AUTOCMD12_ERR_STATUS |=
2097 (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2098 }
2099 else
2100 {
2101 /* disable the standard tuning */
2102 base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
2103 /* clear excute tuning */
2104 base->AUTOCMD12_ERR_STATUS &=
2105 ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
2106 }
2107 }
2108
2109 #if FSL_FEATURE_USDHC_HAS_HS400_MODE
2110 /*!
2111 * brief config the strobe DLL delay target and update interval
2112 *
2113 * param base USDHC peripheral base address.
2114 * param delayTarget delay target
2115 * param updateInterval update interval
2116 */
USDHC_ConfigStrobeDLL(USDHC_Type * base,uint32_t delayTarget,uint32_t updateInterval)2117 void USDHC_ConfigStrobeDLL(USDHC_Type *base, uint32_t delayTarget, uint32_t updateInterval)
2118 {
2119 assert(delayTarget <= (USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_MASK >>
2120 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT));
2121
2122 /* reset strobe dll firstly */
2123 base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_RESET_MASK;
2124 /* clear reset and other register fields */
2125 base->STROBE_DLL_CTRL = 0;
2126 /* configure the DELAY target and update interval */
2127 base->STROBE_DLL_CTRL |= USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_ENABLE_MASK |
2128 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_UPDATE_INT(updateInterval) |
2129 USDHC_STROBE_DLL_CTRL_STROBE_DLL_CTRL_SLV_DLY_TARGET(delayTarget);
2130
2131 while (
2132 (USDHC_GetStrobeDLLStatus(base) & (USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK |
2133 USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)) !=
2134 ((USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_SLV_LOCK_MASK | USDHC_STROBE_DLL_STATUS_STROBE_DLL_STS_REF_LOCK_MASK)))
2135 {
2136 }
2137 }
2138 #endif
2139
2140 /*!
2141 * brief the auto tuning enbale for CMD/DATA line
2142 *
2143 * param base USDHC peripheral base address.
2144 */
USDHC_EnableAutoTuningForCmdAndData(USDHC_Type * base)2145 void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
2146 {
2147 uint32_t busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
2148
2149 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
2150
2151 /* 1bit data width */
2152 if (busWidth == 0UL)
2153 {
2154 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2155 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2156 }
2157 /* 4bit data width */
2158 else if (busWidth == 1UL)
2159 {
2160 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2161 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2162 }
2163 /* 8bit data width */
2164 else
2165 {
2166 base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
2167 base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
2168 }
2169 }
2170 #endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
2171
USDHC_TransferHandleCardDetect(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2172 static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2173 {
2174 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInsertionFlag))
2175 {
2176 if (handle->callback.CardInserted != NULL)
2177 {
2178 handle->callback.CardInserted(base, handle->userData);
2179 }
2180 }
2181 else
2182 {
2183 if (handle->callback.CardRemoved != NULL)
2184 {
2185 handle->callback.CardRemoved(base, handle->userData);
2186 }
2187 }
2188 }
2189
USDHC_TransferHandleCommand(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2190 static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2191 {
2192 assert(handle->command != NULL);
2193
2194 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandErrorFlag))
2195 {
2196 if (handle->callback.TransferComplete != NULL)
2197 {
2198 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2199 }
2200 }
2201 else
2202 {
2203 /* Receive response */
2204 if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
2205 {
2206 if (handle->callback.TransferComplete != NULL)
2207 {
2208 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
2209 }
2210 }
2211 else
2212 {
2213 if (handle->callback.TransferComplete != NULL)
2214 {
2215 handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandSuccess, handle->userData);
2216 }
2217 }
2218 }
2219 /* disable interrupt signal and reset command pointer */
2220 USDHC_DisableInterruptSignal(base, kUSDHC_CommandFlag);
2221 handle->command = NULL;
2222 }
2223
2224 #if (defined FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER) && FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER
USDHC_TransferHandleData(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2225 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2226 {
2227 assert(handle->data != NULL);
2228
2229 status_t transferStatus = kStatus_USDHC_BusyTransferring;
2230
2231 if ((!(handle->data->enableIgnoreError)) &&
2232 (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2233 {
2234 transferStatus = kStatus_USDHC_TransferDataFailed;
2235 }
2236 else
2237 {
2238 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2239 {
2240 /* std tuning process only need to wait BRR */
2241 if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2242 {
2243 transferStatus = kStatus_USDHC_TransferDataComplete;
2244 }
2245 }
2246 else
2247 {
2248 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag))
2249 {
2250 transferStatus = kStatus_USDHC_TransferDMAComplete;
2251 }
2252
2253 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2254 {
2255 transferStatus = kStatus_USDHC_TransferDataComplete;
2256
2257 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2258 if (handle->data->dataDirection == kUSDHC_TransferDirectionReceive)
2259 {
2260 usdhc_scatter_gather_data_list_t *sgDataList = &handle->data->sgData;
2261 while (sgDataList != NULL)
2262 {
2263 DCACHE_InvalidateByRange((uint32_t)sgDataList->dataAddr, sgDataList->dataSize);
2264 sgDataList = sgDataList->dataList;
2265 }
2266 }
2267 #endif
2268 }
2269 }
2270 }
2271
2272 if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2273 {
2274 handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2275 USDHC_DisableInterruptSignal(
2276 base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag | (uint32_t)kUSDHC_DmaCompleteFlag);
2277 handle->data = NULL;
2278 }
2279 }
2280
2281 #else
USDHC_TransferHandleData(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2282 static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2283 {
2284 assert(handle->data != NULL);
2285
2286 status_t transferStatus = kStatus_USDHC_BusyTransferring;
2287 uint32_t transferredWords = handle->transferredWords;
2288
2289 if ((!(handle->data->enableIgnoreError)) &&
2290 (IS_USDHC_FLAG_SET(interruptFlags, (uint32_t)kUSDHC_DataErrorFlag | (uint32_t)kUSDHC_DmaErrorFlag)))
2291 {
2292 transferStatus = kStatus_USDHC_TransferDataFailed;
2293 }
2294 else
2295 {
2296 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferReadReadyFlag))
2297 {
2298 /* std tuning process only need to wait BRR */
2299 if (handle->data->dataType == (uint32_t)kUSDHC_TransferDataTuning)
2300 {
2301 transferStatus = kStatus_USDHC_TransferDataComplete;
2302 }
2303 else
2304 {
2305 handle->transferredWords = USDHC_ReadDataPort(base, handle->data, transferredWords);
2306 }
2307 }
2308 else if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BufferWriteReadyFlag))
2309 {
2310 handle->transferredWords = USDHC_WriteDataPort(base, handle->data, transferredWords);
2311 }
2312 else
2313 {
2314 if ((IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DmaCompleteFlag)) &&
2315 (handle->data->dataType == (uint32_t)kUSDHC_TransferDataBootcontinous))
2316 {
2317 *(handle->data->rxData) = s_usdhcBootDummy;
2318 }
2319
2320 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataCompleteFlag))
2321 {
2322 transferStatus = kStatus_USDHC_TransferDataComplete;
2323
2324 #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
2325 if (handle->data->rxData != NULL)
2326 {
2327 DCACHE_InvalidateByRange((uint32_t)(handle->data->rxData),
2328 (handle->data->blockSize) * (handle->data->blockCount));
2329 }
2330 #endif
2331 }
2332 }
2333 }
2334
2335 if ((handle->callback.TransferComplete != NULL) && (transferStatus != kStatus_USDHC_BusyTransferring))
2336 {
2337 handle->callback.TransferComplete(base, handle, transferStatus, handle->userData);
2338 USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_DataFlag | (uint32_t)kUSDHC_DataDMAFlag);
2339 handle->data = NULL;
2340 }
2341 }
2342 #endif
2343
USDHC_TransferHandleSdioInterrupt(USDHC_Type * base,usdhc_handle_t * handle)2344 static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
2345 {
2346 if (handle->callback.SdioInterrupt != NULL)
2347 {
2348 handle->callback.SdioInterrupt(base, handle->userData);
2349 }
2350 }
2351
2352 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
USDHC_TransferHandleReTuning(USDHC_Type * base,usdhc_handle_t * handle,uint32_t interruptFlags)2353 static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
2354 {
2355 assert(handle->callback.ReTuning != NULL);
2356 /* retuning request */
2357 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_TuningErrorFlag))
2358 {
2359 handle->callback.ReTuning(base, handle->userData); /* retuning fail */
2360 }
2361 }
2362 #endif
2363
USDHC_TransferHandleBlockGap(USDHC_Type * base,usdhc_handle_t * handle)2364 static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
2365 {
2366 if (handle->callback.BlockGap != NULL)
2367 {
2368 handle->callback.BlockGap(base, handle->userData);
2369 }
2370 }
2371
2372 /*!
2373 * brief Creates the USDHC handle.
2374 *
2375 * param base USDHC peripheral base address.
2376 * param handle USDHC handle pointer.
2377 * param callback Structure pointer to contain all callback functions.
2378 * param userData Callback function parameter.
2379 */
USDHC_TransferCreateHandle(USDHC_Type * base,usdhc_handle_t * handle,const usdhc_transfer_callback_t * callback,void * userData)2380 void USDHC_TransferCreateHandle(USDHC_Type *base,
2381 usdhc_handle_t *handle,
2382 const usdhc_transfer_callback_t *callback,
2383 void *userData)
2384 {
2385 assert(handle != NULL);
2386 assert(callback != NULL);
2387
2388 /* Zero the handle. */
2389 (void)memset(handle, 0, sizeof(*handle));
2390
2391 /* Set the callback. */
2392 handle->callback.CardInserted = callback->CardInserted;
2393 handle->callback.CardRemoved = callback->CardRemoved;
2394 handle->callback.SdioInterrupt = callback->SdioInterrupt;
2395 handle->callback.BlockGap = callback->BlockGap;
2396 handle->callback.TransferComplete = callback->TransferComplete;
2397 handle->callback.ReTuning = callback->ReTuning;
2398 handle->userData = userData;
2399
2400 /* Save the handle in global variables to support the double weak mechanism. */
2401 s_usdhcHandle[USDHC_GetInstance(base)] = handle;
2402
2403 /* save IRQ handler */
2404 s_usdhcIsr = USDHC_TransferHandleIRQ;
2405
2406 (void)EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
2407 }
2408
2409 /*!
2410 * brief IRQ handler for the USDHC.
2411 *
2412 * This function deals with the IRQs on the given host controller.
2413 *
2414 * param base USDHC peripheral base address.
2415 * param handle USDHC handle.
2416 */
USDHC_TransferHandleIRQ(USDHC_Type * base,usdhc_handle_t * handle)2417 void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
2418 {
2419 assert(handle != NULL);
2420
2421 uint32_t interruptFlags;
2422
2423 interruptFlags = USDHC_GetEnabledInterruptStatusFlags(base);
2424
2425 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardDetectFlag))
2426 {
2427 USDHC_TransferHandleCardDetect(base, handle, interruptFlags);
2428 }
2429 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CommandFlag))
2430 {
2431 USDHC_TransferHandleCommand(base, handle, interruptFlags);
2432 }
2433 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_DataFlag))
2434 {
2435 USDHC_TransferHandleData(base, handle, interruptFlags);
2436 }
2437 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_CardInterruptFlag))
2438 {
2439 USDHC_TransferHandleSdioInterrupt(base, handle);
2440 }
2441 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_BlockGapEventFlag))
2442 {
2443 USDHC_TransferHandleBlockGap(base, handle);
2444 }
2445 #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
2446 if (IS_USDHC_FLAG_SET(interruptFlags, kUSDHC_SDR104TuningFlag))
2447 {
2448 USDHC_TransferHandleReTuning(base, handle, interruptFlags);
2449 }
2450 #endif
2451 USDHC_ClearInterruptStatusFlags(base, interruptFlags);
2452 }
2453
2454 #ifdef USDHC0
2455 void USDHC0_DriverIRQHandler(void);
USDHC0_DriverIRQHandler(void)2456 void USDHC0_DriverIRQHandler(void)
2457 {
2458 s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
2459 SDK_ISR_EXIT_BARRIER;
2460 }
2461 #endif
2462
2463 #ifdef USDHC1
2464 void USDHC1_DriverIRQHandler(void);
USDHC1_DriverIRQHandler(void)2465 void USDHC1_DriverIRQHandler(void)
2466 {
2467 s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
2468 SDK_ISR_EXIT_BARRIER;
2469 }
2470 #endif
2471
2472 #ifdef USDHC2
2473 void USDHC2_DriverIRQHandler(void);
USDHC2_DriverIRQHandler(void)2474 void USDHC2_DriverIRQHandler(void)
2475 {
2476 s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
2477 SDK_ISR_EXIT_BARRIER;
2478 }
2479
2480 #endif
2481