fsl_usdhc.c 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796
  1. /*
  2. * The Clear BSD License
  3. * Copyright (c) 2016, Freescale Semiconductor, Inc.
  4. * Copyright 2016-2017 NXP
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted (subject to the limitations in the disclaimer below) provided
  9. * that the following conditions are met:
  10. *
  11. * o Redistributions of source code must retain the above copyright notice, this list
  12. * of conditions and the following disclaimer.
  13. *
  14. * o Redistributions in binary form must reproduce the above copyright notice, this
  15. * list of conditions and the following disclaimer in the documentation and/or
  16. * other materials provided with the distribution.
  17. *
  18. * o Neither the name of the copyright holder nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
  23. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  24. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  25. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  26. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  27. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  28. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  29. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  30. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  31. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "fsl_usdhc.h"
  35. #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
  36. #include "fsl_cache.h"
  37. #endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
  38. /*******************************************************************************
  39. * Definitions
  40. ******************************************************************************/
  41. /* Component ID definition, used by tools. */
  42. #ifndef FSL_COMPONENT_ID
  43. #define FSL_COMPONENT_ID "platform.drivers.usdhc"
  44. #endif
  45. /*! @brief Clock setting */
  46. /* Max SD clock divisor from base clock */
  47. #define USDHC_MAX_DVS ((USDHC_SYS_CTRL_DVS_MASK >> USDHC_SYS_CTRL_DVS_SHIFT) + 1U)
  48. #define USDHC_MAX_CLKFS ((USDHC_SYS_CTRL_SDCLKFS_MASK >> USDHC_SYS_CTRL_SDCLKFS_SHIFT) + 1U)
  49. #define USDHC_PREV_DVS(x) ((x) -= 1U)
  50. #define USDHC_PREV_CLKFS(x, y) ((x) >>= (y))
  51. /* Typedef for interrupt handler. */
  52. typedef void (*usdhc_isr_t)(USDHC_Type *base, usdhc_handle_t *handle);
  53. /*! @brief Dummy data buffer for mmc boot mode */
  54. AT_NONCACHEABLE_SECTION_ALIGN(uint32_t s_usdhcBootDummy, USDHC_ADMA2_ADDRESS_ALIGN);
  55. /*******************************************************************************
  56. * Prototypes
  57. ******************************************************************************/
  58. /*!
  59. * @brief Get the instance.
  60. *
  61. * @param base USDHC peripheral base address.
  62. * @return Instance number.
  63. */
  64. static uint32_t USDHC_GetInstance(USDHC_Type *base);
  65. /*!
  66. * @brief Set transfer interrupt.
  67. *
  68. * @param base USDHC peripheral base address.
  69. * @param usingInterruptSignal True to use IRQ signal.
  70. */
  71. static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal);
  72. /*!
  73. * @brief Start transfer according to current transfer state
  74. *
  75. * @param base USDHC peripheral base address.
  76. * @param data Data to be transferred.
  77. * @param flag data present flag
  78. */
  79. static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag);
  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. * @brief Read DATAPORT when buffer enable bit is set.
  89. *
  90. * @param base USDHC peripheral base address.
  91. * @param data Data to be read.
  92. * @param transferredWords The number of data words have been transferred last time transaction.
  93. * @return The number of total data words have been transferred after this time transaction.
  94. */
  95. static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
  96. /*!
  97. * @brief Read data by using DATAPORT polling way.
  98. *
  99. * @param base USDHC peripheral base address.
  100. * @param data Data to be read.
  101. * @retval kStatus_Fail Read DATAPORT failed.
  102. * @retval kStatus_Success Operate successfully.
  103. */
  104. static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
  105. /*!
  106. * @brief Write DATAPORT when buffer enable bit is set.
  107. *
  108. * @param base USDHC peripheral base address.
  109. * @param data Data to be read.
  110. * @param transferredWords The number of data words have been transferred last time.
  111. * @return The number of total data words have been transferred after this time transaction.
  112. */
  113. static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords);
  114. /*!
  115. * @brief Write data by using DATAPORT polling way.
  116. *
  117. * @param base USDHC peripheral base address.
  118. * @param data Data to be transferred.
  119. * @retval kStatus_Fail Write DATAPORT failed.
  120. * @retval kStatus_Success Operate successfully.
  121. */
  122. static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data);
  123. /*!
  124. * @brief Transfer data by polling way.
  125. *
  126. * @param base USDHC peripheral base address.
  127. * @param data Data to be transferred.
  128. * @param use DMA flag.
  129. * @retval kStatus_Fail Transfer data failed.
  130. * @retval kStatus_InvalidArgument Argument is invalid.
  131. * @retval kStatus_Success Operate successfully.
  132. */
  133. static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA);
  134. /*!
  135. * @brief Handle card detect interrupt.
  136. *
  137. * @param base USDHC peripheral base address.
  138. * @param handle USDHC handle.
  139. * @param interruptFlags Card detect related interrupt flags.
  140. */
  141. static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
  142. /*!
  143. * @brief Handle command interrupt.
  144. *
  145. * @param base USDHC peripheral base address.
  146. * @param handle USDHC handle.
  147. * @param interruptFlags Command related interrupt flags.
  148. */
  149. static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
  150. /*!
  151. * @brief Handle data interrupt.
  152. *
  153. * @param base USDHC peripheral base address.
  154. * @param handle USDHC handle.
  155. * @param interruptFlags Data related interrupt flags.
  156. */
  157. static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
  158. /*!
  159. * @brief Handle SDIO card interrupt signal.
  160. *
  161. * @param base USDHC peripheral base address.
  162. * @param handle USDHC handle.
  163. */
  164. static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle);
  165. /*!
  166. * @brief Handle SDIO block gap event.
  167. *
  168. * @param base USDHC peripheral base address.
  169. * @param handle USDHC handle.
  170. */
  171. static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle);
  172. /*!
  173. * @brief Handle retuning
  174. *
  175. * @param base USDHC peripheral base address.
  176. * @param handle USDHC handle.
  177. * @param interrupt flags
  178. */
  179. static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags);
  180. /*!
  181. * @brief wait command done
  182. *
  183. * @param base USDHC peripheral base address.
  184. * @param command configuration
  185. * @param pollingCmdDone polling command done flag
  186. */
  187. static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone);
  188. /*******************************************************************************
  189. * Variables
  190. ******************************************************************************/
  191. /*! @brief USDHC base pointer array */
  192. static USDHC_Type *const s_usdhcBase[] = USDHC_BASE_PTRS;
  193. /*! @brief USDHC internal handle pointer array */
  194. static usdhc_handle_t *s_usdhcHandle[ARRAY_SIZE(s_usdhcBase)] = {NULL};
  195. /*! @brief USDHC IRQ name array */
  196. static const IRQn_Type s_usdhcIRQ[] = USDHC_IRQS;
  197. #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
  198. /*! @brief USDHC clock array name */
  199. static const clock_ip_name_t s_usdhcClock[] = USDHC_CLOCKS;
  200. #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
  201. /* USDHC ISR for transactional APIs. */
  202. static usdhc_isr_t s_usdhcIsr;
  203. /*******************************************************************************
  204. * Code
  205. ******************************************************************************/
  206. static uint32_t USDHC_GetInstance(USDHC_Type *base)
  207. {
  208. uint8_t instance = 0;
  209. while ((instance < ARRAY_SIZE(s_usdhcBase)) && (s_usdhcBase[instance] != base))
  210. {
  211. instance++;
  212. }
  213. assert(instance < ARRAY_SIZE(s_usdhcBase));
  214. return instance;
  215. }
  216. static void USDHC_SetTransferInterrupt(USDHC_Type *base, bool usingInterruptSignal)
  217. {
  218. uint32_t interruptEnabled; /* The Interrupt status flags to be enabled */
  219. /* Disable all interrupts */
  220. USDHC_DisableInterruptStatus(base, (uint32_t)kUSDHC_AllInterruptFlags);
  221. USDHC_DisableInterruptSignal(base, (uint32_t)kUSDHC_AllInterruptFlags);
  222. DisableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
  223. interruptEnabled = (kUSDHC_CommandFlag | kUSDHC_CardInsertionFlag | kUSDHC_DataFlag | kUSDHC_CardRemovalFlag |
  224. kUSDHC_SDR104TuningFlag | kUSDHC_BlockGapEventFlag);
  225. USDHC_EnableInterruptStatus(base, interruptEnabled);
  226. if (usingInterruptSignal)
  227. {
  228. USDHC_EnableInterruptSignal(base, interruptEnabled);
  229. }
  230. }
  231. static status_t USDHC_SetDataTransferConfig(USDHC_Type *base, usdhc_data_t *data, uint32_t *dataPresentFlag)
  232. {
  233. uint32_t mixCtrl = base->MIX_CTRL;
  234. if (data != NULL)
  235. {
  236. /* if transfer boot continous, only need set the CREQ bit, leave others as it is */
  237. if (data->dataType == kUSDHC_TransferDataBootcontinous)
  238. {
  239. /* clear stop at block gap request */
  240. base->PROT_CTRL &= ~USDHC_PROT_CTRL_SABGREQ_MASK;
  241. /* continous transfer data */
  242. base->PROT_CTRL |= USDHC_PROT_CTRL_CREQ_MASK;
  243. return kStatus_Success;
  244. }
  245. /* check data inhibit flag */
  246. if (base->PRES_STATE & kUSDHC_DataInhibitFlag)
  247. {
  248. return kStatus_USDHC_BusyTransferring;
  249. }
  250. /* check transfer block count */
  251. if ((data->blockCount > USDHC_MAX_BLOCK_COUNT) || ((data->txData == NULL) && (data->rxData == NULL)))
  252. {
  253. return kStatus_InvalidArgument;
  254. }
  255. /* config mix parameter */
  256. mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
  257. USDHC_MIX_CTRL_AC12EN_MASK);
  258. if (data->rxData)
  259. {
  260. mixCtrl |= USDHC_MIX_CTRL_DTDSEL_MASK;
  261. }
  262. if (data->blockCount > 1U)
  263. {
  264. mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
  265. /* auto command 12 */
  266. if (data->enableAutoCommand12)
  267. {
  268. mixCtrl |= USDHC_MIX_CTRL_AC12EN_MASK;
  269. }
  270. }
  271. /* auto command 23, auto send set block count cmd before multiple read/write */
  272. if ((data->enableAutoCommand23))
  273. {
  274. mixCtrl |= USDHC_MIX_CTRL_AC23EN_MASK;
  275. base->VEND_SPEC2 |= USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
  276. /* config the block count to DS_ADDR */
  277. base->DS_ADDR = data->blockCount;
  278. }
  279. else
  280. {
  281. mixCtrl &= ~USDHC_MIX_CTRL_AC23EN_MASK;
  282. base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_ACMD23_ARGU2_EN_MASK;
  283. }
  284. /* if transfer boot data, leave the block count to USDHC_SetMmcBootConfig function */
  285. if (data->dataType != kUSDHC_TransferDataBoot)
  286. {
  287. /* config data block size/block count */
  288. base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
  289. (USDHC_BLK_ATT_BLKSIZE(data->blockSize) | USDHC_BLK_ATT_BLKCNT(data->blockCount)));
  290. }
  291. else
  292. {
  293. mixCtrl |= USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK;
  294. base->PROT_CTRL |= USDHC_PROT_CTRL_RD_DONE_NO_8CLK_MASK;
  295. }
  296. /* data present flag */
  297. *dataPresentFlag |= kUSDHC_DataPresentFlag;
  298. }
  299. else
  300. {
  301. /* clear data flags */
  302. mixCtrl &= ~(USDHC_MIX_CTRL_MSBSEL_MASK | USDHC_MIX_CTRL_BCEN_MASK | USDHC_MIX_CTRL_DTDSEL_MASK |
  303. USDHC_MIX_CTRL_AC12EN_MASK);
  304. if (base->PRES_STATE & kUSDHC_CommandInhibitFlag)
  305. {
  306. return kStatus_USDHC_BusyTransferring;
  307. }
  308. }
  309. /* config the mix parameter */
  310. base->MIX_CTRL = mixCtrl;
  311. return kStatus_Success;
  312. }
  313. static status_t USDHC_ReceiveCommandResponse(USDHC_Type *base, usdhc_command_t *command)
  314. {
  315. uint32_t i;
  316. if (command->responseType != kCARD_ResponseTypeNone)
  317. {
  318. command->response[0U] = base->CMD_RSP0;
  319. if (command->responseType == kCARD_ResponseTypeR2)
  320. {
  321. command->response[1U] = base->CMD_RSP1;
  322. command->response[2U] = base->CMD_RSP2;
  323. command->response[3U] = base->CMD_RSP3;
  324. i = 4U;
  325. /* R3-R2-R1-R0(lowest 8 bit is invalid bit) has the same format as R2 format in SD specification document
  326. after removed internal CRC7 and end bit. */
  327. do
  328. {
  329. command->response[i - 1U] <<= 8U;
  330. if (i > 1U)
  331. {
  332. command->response[i - 1U] |= ((command->response[i - 2U] & 0xFF000000U) >> 24U);
  333. }
  334. } while (i--);
  335. }
  336. }
  337. /* check response error flag */
  338. if ((command->responseErrorFlags != 0U) &&
  339. ((command->responseType == kCARD_ResponseTypeR1) || (command->responseType == kCARD_ResponseTypeR1b) ||
  340. (command->responseType == kCARD_ResponseTypeR6) || (command->responseType == kCARD_ResponseTypeR5)))
  341. {
  342. if (((command->responseErrorFlags) & (command->response[0U])) != 0U)
  343. {
  344. return kStatus_USDHC_SendCommandFailed;
  345. }
  346. }
  347. return kStatus_Success;
  348. }
  349. static uint32_t USDHC_ReadDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
  350. {
  351. uint32_t i;
  352. uint32_t totalWords;
  353. uint32_t wordsCanBeRead; /* The words can be read at this time. */
  354. uint32_t readWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_RD_WML_MASK) >> USDHC_WTMK_LVL_RD_WML_SHIFT);
  355. /* If DMA is enable, do not need to polling data port */
  356. if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
  357. {
  358. /*
  359. * Add non aligned access support ,user need make sure your buffer size is big
  360. * enough to hold the data,in other words,user need make sure the buffer size
  361. * is 4 byte aligned
  362. */
  363. if (data->blockSize % sizeof(uint32_t) != 0U)
  364. {
  365. data->blockSize +=
  366. sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
  367. }
  368. totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
  369. /* If watermark level is equal or bigger than totalWords, transfers totalWords data. */
  370. if (readWatermark >= totalWords)
  371. {
  372. wordsCanBeRead = totalWords;
  373. }
  374. /* If watermark level is less than totalWords and left words to be sent is equal or bigger than readWatermark,
  375. transfers watermark level words. */
  376. else if ((readWatermark < totalWords) && ((totalWords - transferredWords) >= readWatermark))
  377. {
  378. wordsCanBeRead = readWatermark;
  379. }
  380. /* If watermark level is less than totalWords and left words to be sent is less than readWatermark, transfers
  381. left
  382. words. */
  383. else
  384. {
  385. wordsCanBeRead = (totalWords - transferredWords);
  386. }
  387. i = 0U;
  388. while (i < wordsCanBeRead)
  389. {
  390. data->rxData[transferredWords++] = USDHC_ReadData(base);
  391. i++;
  392. }
  393. }
  394. return transferredWords;
  395. }
  396. static status_t USDHC_ReadByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
  397. {
  398. uint32_t totalWords;
  399. uint32_t transferredWords = 0U, interruptStatus = 0U;
  400. status_t error = kStatus_Success;
  401. /*
  402. * Add non aligned access support ,user need make sure your buffer size is big
  403. * enough to hold the data,in other words,user need make sure the buffer size
  404. * is 4 byte aligned
  405. */
  406. if (data->blockSize % sizeof(uint32_t) != 0U)
  407. {
  408. data->blockSize +=
  409. sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
  410. }
  411. totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
  412. while ((error == kStatus_Success) && (transferredWords < totalWords))
  413. {
  414. while (!(interruptStatus & (kUSDHC_BufferReadReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag)))
  415. {
  416. interruptStatus = USDHC_GetInterruptStatusFlags(base);
  417. }
  418. /* during std tuning process, software do not need to read data, but wait BRR is enough */
  419. if ((data->dataType == kUSDHC_TransferDataTuning) && (interruptStatus & kUSDHC_BufferReadReadyFlag))
  420. {
  421. USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag | kUSDHC_TuningPassFlag);
  422. return kStatus_Success;
  423. }
  424. else if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U)
  425. {
  426. USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
  427. /* if tuning error occur ,return directly */
  428. error = kStatus_USDHC_TuningError;
  429. }
  430. else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U)
  431. {
  432. if (!(data->enableIgnoreError))
  433. {
  434. error = kStatus_Fail;
  435. }
  436. /* clear data error flag */
  437. USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
  438. }
  439. else
  440. {
  441. }
  442. if (error == kStatus_Success)
  443. {
  444. transferredWords = USDHC_ReadDataPort(base, data, transferredWords);
  445. /* clear buffer read ready */
  446. USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferReadReadyFlag);
  447. interruptStatus = 0U;
  448. }
  449. }
  450. /* Clear data complete flag after the last read operation. */
  451. USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataCompleteFlag);
  452. return error;
  453. }
  454. static uint32_t USDHC_WriteDataPort(USDHC_Type *base, usdhc_data_t *data, uint32_t transferredWords)
  455. {
  456. uint32_t i;
  457. uint32_t totalWords;
  458. uint32_t wordsCanBeWrote; /* Words can be wrote at this time. */
  459. uint32_t writeWatermark = ((base->WTMK_LVL & USDHC_WTMK_LVL_WR_WML_MASK) >> USDHC_WTMK_LVL_WR_WML_SHIFT);
  460. /* If DMA is enable, do not need to polling data port */
  461. if ((base->MIX_CTRL & USDHC_MIX_CTRL_DMAEN_MASK) == 0U)
  462. {
  463. /*
  464. * Add non aligned access support ,user need make sure your buffer size is big
  465. * enough to hold the data,in other words,user need make sure the buffer size
  466. * is 4 byte aligned
  467. */
  468. if (data->blockSize % sizeof(uint32_t) != 0U)
  469. {
  470. data->blockSize +=
  471. sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
  472. }
  473. totalWords = ((data->blockCount * data->blockSize) / sizeof(uint32_t));
  474. /* If watermark level is equal or bigger than totalWords, transfers totalWords data.*/
  475. if (writeWatermark >= totalWords)
  476. {
  477. wordsCanBeWrote = totalWords;
  478. }
  479. /* If watermark level is less than totalWords and left words to be sent is equal or bigger than watermark,
  480. transfers watermark level words. */
  481. else if ((writeWatermark < totalWords) && ((totalWords - transferredWords) >= writeWatermark))
  482. {
  483. wordsCanBeWrote = writeWatermark;
  484. }
  485. /* If watermark level is less than totalWords and left words to be sent is less than watermark, transfers left
  486. words. */
  487. else
  488. {
  489. wordsCanBeWrote = (totalWords - transferredWords);
  490. }
  491. i = 0U;
  492. while (i < wordsCanBeWrote)
  493. {
  494. USDHC_WriteData(base, data->txData[transferredWords++]);
  495. i++;
  496. }
  497. }
  498. return transferredWords;
  499. }
  500. static status_t USDHC_WriteByDataPortBlocking(USDHC_Type *base, usdhc_data_t *data)
  501. {
  502. uint32_t totalWords;
  503. uint32_t transferredWords = 0U, interruptStatus = 0U;
  504. status_t error = kStatus_Success;
  505. /*
  506. * Add non aligned access support ,user need make sure your buffer size is big
  507. * enough to hold the data,in other words,user need make sure the buffer size
  508. * is 4 byte aligned
  509. */
  510. if (data->blockSize % sizeof(uint32_t) != 0U)
  511. {
  512. data->blockSize +=
  513. sizeof(uint32_t) - (data->blockSize % sizeof(uint32_t)); /* make the block size as word-aligned */
  514. }
  515. totalWords = (data->blockCount * data->blockSize) / sizeof(uint32_t);
  516. while ((error == kStatus_Success) && (transferredWords < totalWords))
  517. {
  518. while (!(interruptStatus & (kUSDHC_BufferWriteReadyFlag | kUSDHC_DataErrorFlag | kUSDHC_TuningErrorFlag)))
  519. {
  520. interruptStatus = USDHC_GetInterruptStatusFlags(base);
  521. }
  522. if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U)
  523. {
  524. USDHC_ClearInterruptStatusFlags(base, kUSDHC_TuningErrorFlag);
  525. /* if tuning error occur ,return directly */
  526. return kStatus_USDHC_TuningError;
  527. }
  528. else if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U)
  529. {
  530. if (!(data->enableIgnoreError))
  531. {
  532. error = kStatus_Fail;
  533. }
  534. /* clear data error flag */
  535. USDHC_ClearInterruptStatusFlags(base, kUSDHC_DataErrorFlag);
  536. }
  537. else
  538. {
  539. }
  540. if (error == kStatus_Success)
  541. {
  542. transferredWords = USDHC_WriteDataPort(base, data, transferredWords);
  543. /* clear buffer write ready */
  544. USDHC_ClearInterruptStatusFlags(base, kUSDHC_BufferWriteReadyFlag);
  545. interruptStatus = 0U;
  546. }
  547. }
  548. /* Wait write data complete or data transfer error after the last writing operation. */
  549. while (!(interruptStatus & (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag)))
  550. {
  551. interruptStatus = USDHC_GetInterruptStatusFlags(base);
  552. }
  553. if ((interruptStatus & kUSDHC_DataErrorFlag) != 0U)
  554. {
  555. if (!(data->enableIgnoreError))
  556. {
  557. error = kStatus_Fail;
  558. }
  559. }
  560. USDHC_ClearInterruptStatusFlags(base, (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag));
  561. return error;
  562. }
  563. void USDHC_SendCommand(USDHC_Type *base, usdhc_command_t *command)
  564. {
  565. assert(NULL != command);
  566. uint32_t xferType = base->CMD_XFR_TYP, flags = command->flags;
  567. if (((base->PRES_STATE & kUSDHC_CommandInhibitFlag) == 0U) && (command->type != kCARD_CommandTypeEmpty))
  568. {
  569. /* Define the flag corresponding to each response type. */
  570. switch (command->responseType)
  571. {
  572. case kCARD_ResponseTypeNone:
  573. break;
  574. case kCARD_ResponseTypeR1: /* Response 1 */
  575. case kCARD_ResponseTypeR5: /* Response 5 */
  576. case kCARD_ResponseTypeR6: /* Response 6 */
  577. case kCARD_ResponseTypeR7: /* Response 7 */
  578. flags |= (kUSDHC_ResponseLength48Flag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag);
  579. break;
  580. case kCARD_ResponseTypeR1b: /* Response 1 with busy */
  581. case kCARD_ResponseTypeR5b: /* Response 5 with busy */
  582. flags |= (kUSDHC_ResponseLength48BusyFlag | kUSDHC_EnableCrcCheckFlag | kUSDHC_EnableIndexCheckFlag);
  583. break;
  584. case kCARD_ResponseTypeR2: /* Response 2 */
  585. flags |= (kUSDHC_ResponseLength136Flag | kUSDHC_EnableCrcCheckFlag);
  586. break;
  587. case kCARD_ResponseTypeR3: /* Response 3 */
  588. case kCARD_ResponseTypeR4: /* Response 4 */
  589. flags |= (kUSDHC_ResponseLength48Flag);
  590. break;
  591. default:
  592. break;
  593. }
  594. if (command->type == kCARD_CommandTypeAbort)
  595. {
  596. flags |= kUSDHC_CommandTypeAbortFlag;
  597. }
  598. /* config cmd index */
  599. xferType &= ~(USDHC_CMD_XFR_TYP_CMDINX_MASK | USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK |
  600. USDHC_CMD_XFR_TYP_CCCEN_MASK | USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK);
  601. xferType |=
  602. (((command->index << USDHC_CMD_XFR_TYP_CMDINX_SHIFT) & USDHC_CMD_XFR_TYP_CMDINX_MASK) |
  603. ((flags) & (USDHC_CMD_XFR_TYP_CMDTYP_MASK | USDHC_CMD_XFR_TYP_CICEN_MASK | USDHC_CMD_XFR_TYP_CCCEN_MASK |
  604. USDHC_CMD_XFR_TYP_RSPTYP_MASK | USDHC_CMD_XFR_TYP_DPSEL_MASK)));
  605. /* config the command xfertype and argument */
  606. base->CMD_ARG = command->argument;
  607. base->CMD_XFR_TYP = xferType;
  608. }
  609. if (command->type == kCARD_CommandTypeEmpty)
  610. {
  611. /* disable CMD done interrupt for empty command */
  612. base->INT_SIGNAL_EN &= ~USDHC_INT_SIGNAL_EN_CCIEN_MASK;
  613. }
  614. }
  615. static status_t USDHC_WaitCommandDone(USDHC_Type *base, usdhc_command_t *command, bool pollingCmdDone)
  616. {
  617. assert(NULL != command);
  618. status_t error = kStatus_Success;
  619. uint32_t interruptStatus = 0U;
  620. /* check if need polling command done or not */
  621. if (pollingCmdDone)
  622. {
  623. /* Wait command complete or USDHC encounters error. */
  624. while (!(interruptStatus & (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag)))
  625. {
  626. interruptStatus = USDHC_GetInterruptStatusFlags(base);
  627. }
  628. if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U)
  629. {
  630. error = kStatus_USDHC_TuningError;
  631. }
  632. else if ((interruptStatus & kUSDHC_CommandErrorFlag) != 0U)
  633. {
  634. error = kStatus_Fail;
  635. }
  636. else
  637. {
  638. }
  639. /* Receive response when command completes successfully. */
  640. if (error == kStatus_Success)
  641. {
  642. error = USDHC_ReceiveCommandResponse(base, command);
  643. }
  644. USDHC_ClearInterruptStatusFlags(
  645. base, (kUSDHC_CommandCompleteFlag | kUSDHC_CommandErrorFlag | kUSDHC_TuningErrorFlag));
  646. }
  647. return error;
  648. }
  649. static status_t USDHC_TransferDataBlocking(USDHC_Type *base, usdhc_data_t *data, bool enDMA)
  650. {
  651. status_t error = kStatus_Success;
  652. uint32_t interruptStatus = 0U;
  653. if (enDMA)
  654. {
  655. /* Wait data complete or USDHC encounters error. */
  656. while (!((interruptStatus &
  657. (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag | kUSDHC_TuningErrorFlag))))
  658. {
  659. interruptStatus = USDHC_GetInterruptStatusFlags(base);
  660. }
  661. if ((interruptStatus & kUSDHC_TuningErrorFlag) != 0U)
  662. {
  663. error = kStatus_USDHC_TuningError;
  664. }
  665. else if (((interruptStatus & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag)) != 0U))
  666. {
  667. if ((!(data->enableIgnoreError)) || (interruptStatus & kUSDHC_DataTimeoutFlag))
  668. {
  669. error = kStatus_Fail;
  670. }
  671. }
  672. else
  673. {
  674. }
  675. /* load dummy data */
  676. if ((data->dataType == kUSDHC_TransferDataBootcontinous) && (error == kStatus_Success))
  677. {
  678. *(data->rxData) = s_usdhcBootDummy;
  679. }
  680. USDHC_ClearInterruptStatusFlags(base, (kUSDHC_DataCompleteFlag | kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag |
  681. kUSDHC_TuningPassFlag | kUSDHC_TuningErrorFlag));
  682. }
  683. else
  684. {
  685. if (data->rxData)
  686. {
  687. error = USDHC_ReadByDataPortBlocking(base, data);
  688. }
  689. else
  690. {
  691. error = USDHC_WriteByDataPortBlocking(base, data);
  692. }
  693. }
  694. return error;
  695. }
  696. void USDHC_Init(USDHC_Type *base, const usdhc_config_t *config)
  697. {
  698. assert(config);
  699. assert((config->writeWatermarkLevel >= 1U) && (config->writeWatermarkLevel <= 128U));
  700. assert((config->readWatermarkLevel >= 1U) && (config->readWatermarkLevel <= 128U));
  701. assert(config->writeBurstLen <= 16U);
  702. uint32_t proctl, sysctl, wml;
  703. /* Enable USDHC clock. */
  704. CLOCK_EnableClock(s_usdhcClock[USDHC_GetInstance(base)]);
  705. /* Reset USDHC. */
  706. USDHC_Reset(base, kUSDHC_ResetAll, 100U);
  707. proctl = base->PROT_CTRL;
  708. wml = base->WTMK_LVL;
  709. sysctl = base->SYS_CTRL;
  710. proctl &= ~(USDHC_PROT_CTRL_EMODE_MASK | USDHC_PROT_CTRL_DMASEL_MASK);
  711. /* Endian mode*/
  712. proctl |= USDHC_PROT_CTRL_EMODE(config->endianMode);
  713. /* Watermark level */
  714. wml &= ~(USDHC_WTMK_LVL_RD_WML_MASK | USDHC_WTMK_LVL_WR_WML_MASK | USDHC_WTMK_LVL_RD_BRST_LEN_MASK |
  715. USDHC_WTMK_LVL_WR_BRST_LEN_MASK);
  716. wml |= (USDHC_WTMK_LVL_RD_WML(config->readWatermarkLevel) | USDHC_WTMK_LVL_WR_WML(config->writeWatermarkLevel) |
  717. USDHC_WTMK_LVL_RD_BRST_LEN(config->readBurstLen) | USDHC_WTMK_LVL_WR_BRST_LEN(config->writeBurstLen));
  718. /* config the data timeout value */
  719. sysctl &= ~USDHC_SYS_CTRL_DTOCV_MASK;
  720. sysctl |= USDHC_SYS_CTRL_DTOCV(config->dataTimeout);
  721. base->SYS_CTRL = sysctl;
  722. base->WTMK_LVL = wml;
  723. base->PROT_CTRL = proctl;
  724. #if FSL_FEATURE_USDHC_HAS_EXT_DMA
  725. /* disable external DMA */
  726. base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
  727. #endif
  728. /* disable internal DMA and DDR mode */
  729. base->MIX_CTRL &= ~(USDHC_MIX_CTRL_DMAEN_MASK | USDHC_MIX_CTRL_DDR_EN_MASK);
  730. /* Enable interrupt status but doesn't enable interrupt signal. */
  731. USDHC_SetTransferInterrupt(base, false);
  732. }
  733. void USDHC_Deinit(USDHC_Type *base)
  734. {
  735. /* Disable clock. */
  736. CLOCK_DisableClock(s_usdhcClock[USDHC_GetInstance(base)]);
  737. }
  738. bool USDHC_Reset(USDHC_Type *base, uint32_t mask, uint32_t timeout)
  739. {
  740. base->SYS_CTRL |= (mask & (USDHC_SYS_CTRL_RSTA_MASK | USDHC_SYS_CTRL_RSTC_MASK | USDHC_SYS_CTRL_RSTD_MASK));
  741. /* Delay some time to wait reset success. */
  742. while ((base->SYS_CTRL & mask) != 0U)
  743. {
  744. if (timeout == 0U)
  745. {
  746. break;
  747. }
  748. timeout--;
  749. }
  750. return ((!timeout) ? false : true);
  751. }
  752. void USDHC_GetCapability(USDHC_Type *base, usdhc_capability_t *capability)
  753. {
  754. assert(capability);
  755. uint32_t htCapability;
  756. uint32_t maxBlockLength;
  757. htCapability = base->HOST_CTRL_CAP;
  758. /* Get the capability of USDHC. */
  759. maxBlockLength = ((htCapability & USDHC_HOST_CTRL_CAP_MBL_MASK) >> USDHC_HOST_CTRL_CAP_MBL_SHIFT);
  760. capability->maxBlockLength = (512U << maxBlockLength);
  761. /* Other attributes not in HTCAPBLT register. */
  762. capability->maxBlockCount = USDHC_MAX_BLOCK_COUNT;
  763. capability->flags = (htCapability & (kUSDHC_SupportAdmaFlag | kUSDHC_SupportHighSpeedFlag | kUSDHC_SupportDmaFlag |
  764. kUSDHC_SupportSuspendResumeFlag | kUSDHC_SupportV330Flag));
  765. capability->flags |= (htCapability & kUSDHC_SupportV300Flag);
  766. capability->flags |= (htCapability & kUSDHC_SupportV180Flag);
  767. capability->flags |=
  768. (htCapability & (kUSDHC_SupportDDR50Flag | kUSDHC_SupportSDR104Flag | kUSDHC_SupportSDR50Flag));
  769. /* USDHC support 4/8 bit data bus width. */
  770. capability->flags |= (kUSDHC_Support4BitFlag | kUSDHC_Support8BitFlag);
  771. }
  772. uint32_t USDHC_SetSdClock(USDHC_Type *base, uint32_t srcClock_Hz, uint32_t busClock_Hz)
  773. {
  774. assert(srcClock_Hz != 0U);
  775. assert((busClock_Hz != 0U) && (busClock_Hz <= srcClock_Hz));
  776. uint32_t totalDiv = 0U;
  777. uint32_t divisor = 0U;
  778. uint32_t prescaler = 0U;
  779. uint32_t sysctl = 0U;
  780. uint32_t nearestFrequency = 0U;
  781. /* calucate total divisor first */
  782. if ((totalDiv = srcClock_Hz / busClock_Hz) > (USDHC_MAX_CLKFS * USDHC_MAX_DVS))
  783. {
  784. return 0U;
  785. }
  786. if (totalDiv != 0U)
  787. {
  788. /* calucate the divisor (srcClock_Hz / divisor) <= busClock_Hz */
  789. if ((srcClock_Hz / totalDiv) > busClock_Hz)
  790. {
  791. totalDiv++;
  792. }
  793. /* divide the total divisor to div and prescaler */
  794. if (totalDiv > USDHC_MAX_DVS)
  795. {
  796. prescaler = totalDiv / USDHC_MAX_DVS;
  797. /* prescaler must be a value which equal 2^n and smaller than SDHC_MAX_CLKFS */
  798. while (((USDHC_MAX_CLKFS % prescaler) != 0U) || (prescaler == 1U))
  799. {
  800. prescaler++;
  801. }
  802. /* calucate the divisor */
  803. divisor = totalDiv / prescaler;
  804. /* fine tuning the divisor until divisor * prescaler >= totalDiv */
  805. while ((divisor * prescaler) < totalDiv)
  806. {
  807. divisor++;
  808. }
  809. nearestFrequency = srcClock_Hz / (divisor == 0U ? 1U : divisor) / prescaler;
  810. }
  811. else
  812. {
  813. /* in this situation , divsior and SDCLKFS can generate same clock
  814. use SDCLKFS*/
  815. if ((USDHC_MAX_DVS % totalDiv) == 0U)
  816. {
  817. divisor = 0U;
  818. prescaler = totalDiv;
  819. }
  820. else
  821. {
  822. divisor = (totalDiv / 2U) + 1U; /* make sure the output frequency not bigger than target value */
  823. prescaler = 2U;
  824. }
  825. nearestFrequency = srcClock_Hz / totalDiv;
  826. }
  827. }
  828. /* in this condition , srcClock_Hz = busClock_Hz, */
  829. else
  830. {
  831. /* in DDR mode , set SDCLKFS to 0, divisor = 0, actually the
  832. totoal divider = 2U */
  833. divisor = 0U;
  834. prescaler = 0U;
  835. nearestFrequency = srcClock_Hz;
  836. }
  837. /* calucate the value write to register */
  838. if (divisor != 0U)
  839. {
  840. USDHC_PREV_DVS(divisor);
  841. }
  842. /* calucate the value write to register */
  843. if (prescaler != 0U)
  844. {
  845. USDHC_PREV_CLKFS(prescaler, 1U);
  846. }
  847. /* Set the SD clock frequency divisor, SD clock frequency select, data timeout counter value. */
  848. sysctl = base->SYS_CTRL;
  849. sysctl &= ~(USDHC_SYS_CTRL_DVS_MASK | USDHC_SYS_CTRL_SDCLKFS_MASK);
  850. sysctl |= (USDHC_SYS_CTRL_DVS(divisor) | USDHC_SYS_CTRL_SDCLKFS(prescaler));
  851. base->SYS_CTRL = sysctl;
  852. /* Wait until the SD clock is stable. */
  853. while (!(base->PRES_STATE & USDHC_PRES_STATE_SDSTB_MASK))
  854. {
  855. }
  856. return nearestFrequency;
  857. }
  858. bool USDHC_SetCardActive(USDHC_Type *base, uint32_t timeout)
  859. {
  860. base->SYS_CTRL |= USDHC_SYS_CTRL_INITA_MASK;
  861. /* Delay some time to wait card become active state. */
  862. while ((base->SYS_CTRL & USDHC_SYS_CTRL_INITA_MASK) == USDHC_SYS_CTRL_INITA_MASK)
  863. {
  864. if (!timeout)
  865. {
  866. break;
  867. }
  868. timeout--;
  869. }
  870. return ((!timeout) ? false : true);
  871. }
  872. void USDHC_EnableDDRMode(USDHC_Type *base, bool enable, uint32_t nibblePos)
  873. {
  874. uint32_t prescaler = (base->SYS_CTRL & USDHC_SYS_CTRL_SDCLKFS_MASK) >> USDHC_SYS_CTRL_SDCLKFS_SHIFT;
  875. if (enable)
  876. {
  877. base->MIX_CTRL &= ~USDHC_MIX_CTRL_NIBBLE_POS_MASK;
  878. base->MIX_CTRL |= (USDHC_MIX_CTRL_DDR_EN_MASK | USDHC_MIX_CTRL_NIBBLE_POS(nibblePos));
  879. prescaler >>= 1U;
  880. }
  881. else
  882. {
  883. base->MIX_CTRL &= ~USDHC_MIX_CTRL_DDR_EN_MASK;
  884. if (prescaler == 0U)
  885. {
  886. prescaler += 1U;
  887. }
  888. else
  889. {
  890. prescaler <<= 1U;
  891. }
  892. }
  893. base->SYS_CTRL = (base->SYS_CTRL & (~USDHC_SYS_CTRL_SDCLKFS_MASK)) | USDHC_SYS_CTRL_SDCLKFS(prescaler);
  894. }
  895. void USDHC_SetMmcBootConfig(USDHC_Type *base, const usdhc_boot_config_t *config)
  896. {
  897. assert(config);
  898. assert(config->ackTimeoutCount <= (USDHC_MMC_BOOT_DTOCV_ACK_MASK >> USDHC_MMC_BOOT_DTOCV_ACK_SHIFT));
  899. assert(config->blockCount <= (USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK >> USDHC_MMC_BOOT_BOOT_BLK_CNT_SHIFT));
  900. uint32_t mmcboot = base->MMC_BOOT;
  901. mmcboot &= ~(USDHC_MMC_BOOT_DTOCV_ACK_MASK | USDHC_MMC_BOOT_BOOT_MODE_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT_MASK);
  902. mmcboot |= USDHC_MMC_BOOT_DTOCV_ACK(config->ackTimeoutCount) | USDHC_MMC_BOOT_BOOT_MODE(config->bootMode);
  903. if (config->enableBootAck)
  904. {
  905. mmcboot |= USDHC_MMC_BOOT_BOOT_ACK_MASK;
  906. }
  907. if (config->enableAutoStopAtBlockGap)
  908. {
  909. mmcboot |=
  910. USDHC_MMC_BOOT_AUTO_SABG_EN_MASK | USDHC_MMC_BOOT_BOOT_BLK_CNT(USDHC_MAX_BLOCK_COUNT - config->blockCount);
  911. /* always set the block count to USDHC_MAX_BLOCK_COUNT to use auto stop at block gap feature */
  912. base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
  913. (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(USDHC_MAX_BLOCK_COUNT)));
  914. }
  915. else
  916. {
  917. base->BLK_ATT = ((base->BLK_ATT & ~(USDHC_BLK_ATT_BLKSIZE_MASK | USDHC_BLK_ATT_BLKCNT_MASK)) |
  918. (USDHC_BLK_ATT_BLKSIZE(config->blockSize) | USDHC_BLK_ATT_BLKCNT(config->blockCount)));
  919. }
  920. base->MMC_BOOT = mmcboot;
  921. }
  922. status_t USDHC_SetADMA1Descriptor(
  923. uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
  924. {
  925. assert(NULL != admaTable);
  926. assert(NULL != dataBufferAddr);
  927. uint32_t miniEntries, startEntries = 0U,
  928. maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma1_descriptor_t);
  929. usdhc_adma1_descriptor_t *adma1EntryAddress = (usdhc_adma1_descriptor_t *)(admaTable);
  930. uint32_t i, dmaBufferLen = 0U;
  931. const uint32_t *data = dataBufferAddr;
  932. if (((uint32_t)data % USDHC_ADMA1_ADDRESS_ALIGN) != 0U)
  933. {
  934. return kStatus_USDHC_DMADataAddrNotAlign;
  935. }
  936. if (flags == kUSDHC_AdmaDescriptorMultipleFlag)
  937. {
  938. return kStatus_USDHC_NotSupport;
  939. }
  940. /*
  941. * Add non aligned access support ,user need make sure your buffer size is big
  942. * enough to hold the data,in other words,user need make sure the buffer size
  943. * is 4 byte aligned
  944. */
  945. if (dataBytes % sizeof(uint32_t) != 0U)
  946. {
  947. /* make the data length as word-aligned */
  948. dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
  949. }
  950. /* Check if ADMA descriptor's number is enough. */
  951. if ((dataBytes % USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U)
  952. {
  953. miniEntries = dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
  954. }
  955. else
  956. {
  957. miniEntries = ((dataBytes / USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
  958. }
  959. /* ADMA1 needs two descriptors to finish a transfer */
  960. miniEntries <<= 1U;
  961. if (miniEntries + startEntries > maxEntries)
  962. {
  963. return kStatus_OutOfRange;
  964. }
  965. for (i = startEntries; i < (miniEntries + startEntries); i += 2U)
  966. {
  967. if (dataBytes > USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
  968. {
  969. dmaBufferLen = USDHC_ADMA1_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
  970. }
  971. else
  972. {
  973. dmaBufferLen = dataBytes;
  974. }
  975. adma1EntryAddress[i] = (dmaBufferLen << USDHC_ADMA1_DESCRIPTOR_LENGTH_SHIFT);
  976. adma1EntryAddress[i] |= kUSDHC_Adma1DescriptorTypeSetLength;
  977. adma1EntryAddress[i + 1U] = (uint32_t)(data);
  978. adma1EntryAddress[i + 1U] |= kUSDHC_Adma1DescriptorTypeTransfer;
  979. data += dmaBufferLen / sizeof(uint32_t);
  980. dataBytes -= dmaBufferLen;
  981. }
  982. /* the end of the descriptor */
  983. adma1EntryAddress[i - 1U] |= kUSDHC_Adma1DescriptorEndFlag;
  984. return kStatus_Success;
  985. }
  986. status_t USDHC_SetADMA2Descriptor(
  987. uint32_t *admaTable, uint32_t admaTableWords, const uint32_t *dataBufferAddr, uint32_t dataBytes, uint32_t flags)
  988. {
  989. assert(NULL != admaTable);
  990. assert(NULL != dataBufferAddr);
  991. uint32_t miniEntries, startEntries = 0U,
  992. maxEntries = (admaTableWords * sizeof(uint32_t)) / sizeof(usdhc_adma2_descriptor_t);
  993. usdhc_adma2_descriptor_t *adma2EntryAddress = (usdhc_adma2_descriptor_t *)(admaTable);
  994. uint32_t i, dmaBufferLen = 0U;
  995. const uint32_t *data = dataBufferAddr;
  996. if (((uint32_t)data % USDHC_ADMA2_ADDRESS_ALIGN) != 0U)
  997. {
  998. return kStatus_USDHC_DMADataAddrNotAlign;
  999. }
  1000. /*
  1001. * Add non aligned access support ,user need make sure your buffer size is big
  1002. * enough to hold the data,in other words,user need make sure the buffer size
  1003. * is 4 byte aligned
  1004. */
  1005. if (dataBytes % sizeof(uint32_t) != 0U)
  1006. {
  1007. /* make the data length as word-aligned */
  1008. dataBytes += sizeof(uint32_t) - (dataBytes % sizeof(uint32_t));
  1009. }
  1010. /* Check if ADMA descriptor's number is enough. */
  1011. if ((dataBytes % USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) == 0U)
  1012. {
  1013. miniEntries = dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
  1014. }
  1015. else
  1016. {
  1017. miniEntries = ((dataBytes / USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY) + 1U);
  1018. }
  1019. /* calucate the start entry for multiple descriptor mode, ADMA engine is not stop, so update the descriptor
  1020. data adress and data size is enough */
  1021. if (flags == kUSDHC_AdmaDescriptorMultipleFlag)
  1022. {
  1023. for (i = 0U; i < maxEntries; i++)
  1024. {
  1025. if ((adma2EntryAddress[i].attribute & kUSDHC_Adma2DescriptorValidFlag) == 0U)
  1026. {
  1027. break;
  1028. }
  1029. }
  1030. startEntries = i;
  1031. /* add one entry for dummy entry */
  1032. miniEntries += 1U;
  1033. }
  1034. if ((miniEntries + startEntries) > maxEntries)
  1035. {
  1036. return kStatus_OutOfRange;
  1037. }
  1038. for (i = startEntries; i < (miniEntries + startEntries); i++)
  1039. {
  1040. if (dataBytes > USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY)
  1041. {
  1042. dmaBufferLen = USDHC_ADMA2_DESCRIPTOR_MAX_LENGTH_PER_ENTRY;
  1043. }
  1044. else
  1045. {
  1046. dmaBufferLen = (dataBytes == 0U ? sizeof(uint32_t) :
  1047. dataBytes); /* adma don't support 0 data length transfer descriptor */
  1048. }
  1049. /* Each descriptor for ADMA2 is 64-bit in length */
  1050. adma2EntryAddress[i].address = (dataBytes == 0U) ? &s_usdhcBootDummy : data;
  1051. adma2EntryAddress[i].attribute = (dmaBufferLen << USDHC_ADMA2_DESCRIPTOR_LENGTH_SHIFT);
  1052. adma2EntryAddress[i].attribute |=
  1053. (dataBytes == 0U) ? 0U : (kUSDHC_Adma2DescriptorTypeTransfer | kUSDHC_Adma2DescriptorInterruptFlag);
  1054. data += (dmaBufferLen / sizeof(uint32_t));
  1055. if (dataBytes != 0U)
  1056. {
  1057. dataBytes -= dmaBufferLen;
  1058. }
  1059. }
  1060. /* add a dummy valid ADMA descriptor for multiple descriptor mode, this is useful when transfer boot data, the ADMA
  1061. engine
  1062. will not stop at block gap */
  1063. if (flags == kUSDHC_AdmaDescriptorMultipleFlag)
  1064. {
  1065. adma2EntryAddress[startEntries + 1U].attribute |= kUSDHC_Adma2DescriptorTypeTransfer;
  1066. }
  1067. else
  1068. {
  1069. /* set the end bit */
  1070. adma2EntryAddress[i - 1U].attribute |= kUSDHC_Adma2DescriptorEndFlag;
  1071. }
  1072. return kStatus_Success;
  1073. }
  1074. status_t USDHC_SetInternalDmaConfig(USDHC_Type *base,
  1075. usdhc_adma_config_t *dmaConfig,
  1076. const uint32_t *dataAddr,
  1077. bool enAutoCmd23)
  1078. {
  1079. assert(dmaConfig);
  1080. assert(dataAddr);
  1081. #if FSL_FEATURE_USDHC_HAS_EXT_DMA
  1082. /* disable the external DMA if support */
  1083. base->VEND_SPEC &= ~USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
  1084. #endif
  1085. if (dmaConfig->dmaMode == kUSDHC_DmaModeSimple)
  1086. {
  1087. /* check DMA data buffer address align or not */
  1088. if (((uint32_t)dataAddr % USDHC_ADMA2_ADDRESS_ALIGN) != 0U)
  1089. {
  1090. return kStatus_USDHC_DMADataAddrNotAlign;
  1091. }
  1092. /* in simple DMA mode if use auto CMD23, address should load to ADMA addr,
  1093. and block count should load to DS_ADDR*/
  1094. if (enAutoCmd23)
  1095. {
  1096. base->ADMA_SYS_ADDR = (uint32_t)dataAddr;
  1097. }
  1098. else
  1099. {
  1100. base->DS_ADDR = (uint32_t)dataAddr;
  1101. }
  1102. }
  1103. else
  1104. {
  1105. /* When use ADMA, disable simple DMA */
  1106. base->DS_ADDR = 0U;
  1107. base->ADMA_SYS_ADDR = (uint32_t)(dmaConfig->admaTable);
  1108. }
  1109. /* select DMA mode and config the burst length */
  1110. base->PROT_CTRL &= ~(USDHC_PROT_CTRL_DMASEL_MASK | USDHC_PROT_CTRL_BURST_LEN_EN_MASK);
  1111. base->PROT_CTRL |= USDHC_PROT_CTRL_DMASEL(dmaConfig->dmaMode) | USDHC_PROT_CTRL_BURST_LEN_EN(dmaConfig->burstLen);
  1112. /* enable DMA */
  1113. base->MIX_CTRL |= USDHC_MIX_CTRL_DMAEN_MASK;
  1114. return kStatus_Success;
  1115. }
  1116. status_t USDHC_SetAdmaTableConfig(USDHC_Type *base,
  1117. usdhc_adma_config_t *dmaConfig,
  1118. usdhc_data_t *dataConfig,
  1119. uint32_t flags)
  1120. {
  1121. assert(NULL != dmaConfig);
  1122. assert(NULL != dmaConfig->admaTable);
  1123. assert(NULL != dataConfig);
  1124. status_t error = kStatus_Fail;
  1125. uint32_t bootDummyOffset = dataConfig->dataType == kUSDHC_TransferDataBootcontinous ? sizeof(uint32_t) : 0U;
  1126. const uint32_t *data =
  1127. (const uint32_t *)((uint32_t)((dataConfig->rxData == NULL) ? dataConfig->txData : dataConfig->rxData) +
  1128. bootDummyOffset);
  1129. uint32_t blockSize = dataConfig->blockSize * dataConfig->blockCount - bootDummyOffset;
  1130. switch (dmaConfig->dmaMode)
  1131. {
  1132. #if FSL_FEATURE_USDHC_HAS_EXT_DMA
  1133. case kUSDHC_ExternalDMA:
  1134. /* enable the external DMA */
  1135. base->VEND_SPEC |= USDHC_VEND_SPEC_EXT_DMA_EN_MASK;
  1136. break;
  1137. #endif
  1138. case kUSDHC_DmaModeSimple:
  1139. error = kStatus_Success;
  1140. break;
  1141. case kUSDHC_DmaModeAdma1:
  1142. error = USDHC_SetADMA1Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
  1143. break;
  1144. case kUSDHC_DmaModeAdma2:
  1145. error = USDHC_SetADMA2Descriptor(dmaConfig->admaTable, dmaConfig->admaTableWords, data, blockSize, flags);
  1146. break;
  1147. default:
  1148. return kStatus_USDHC_PrepareAdmaDescriptorFailed;
  1149. }
  1150. /* for internal dma, internal DMA configurations should not update the configurations when continous transfer the
  1151. * boot data, only the DMA descriptor need update */
  1152. if ((dmaConfig->dmaMode != kUSDHC_ExternalDMA) && (error == kStatus_Success) &&
  1153. (dataConfig->dataType != kUSDHC_TransferDataBootcontinous))
  1154. {
  1155. error = USDHC_SetInternalDmaConfig(base, dmaConfig, data, dataConfig->enableAutoCommand23);
  1156. }
  1157. return error;
  1158. }
  1159. status_t USDHC_TransferBlocking(USDHC_Type *base, usdhc_adma_config_t *dmaConfig, usdhc_transfer_t *transfer)
  1160. {
  1161. assert(transfer);
  1162. status_t error = kStatus_Fail;
  1163. usdhc_command_t *command = transfer->command;
  1164. usdhc_data_t *data = transfer->data;
  1165. bool enDMA = true;
  1166. bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning);
  1167. /*check re-tuning request*/
  1168. if ((USDHC_GetInterruptStatusFlags(base) & kUSDHC_ReTuningEventFlag) != 0U)
  1169. {
  1170. USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
  1171. return kStatus_USDHC_ReTuningRequest;
  1172. }
  1173. /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
  1174. if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning))
  1175. {
  1176. error = USDHC_SetAdmaTableConfig(base, dmaConfig, data, (data->dataType & kUSDHC_TransferDataBoot) ?
  1177. kUSDHC_AdmaDescriptorMultipleFlag :
  1178. kUSDHC_AdmaDescriptorSingleFlag);
  1179. }
  1180. /* if the DMA desciptor configure fail or not needed , disable it */
  1181. if (error != kStatus_Success)
  1182. {
  1183. enDMA = false;
  1184. /* disable DMA, using polling mode in this situation */
  1185. USDHC_EnableInternalDMA(base, false);
  1186. }
  1187. #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
  1188. else
  1189. {
  1190. if (data->txData != NULL)
  1191. {
  1192. /* clear the DCACHE */
  1193. DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
  1194. }
  1195. else
  1196. {
  1197. /* clear the DCACHE */
  1198. DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
  1199. }
  1200. }
  1201. #endif
  1202. /* config the data transfer parameter */
  1203. error = USDHC_SetDataTransferConfig(base, data, &(command->flags));
  1204. if (kStatus_Success != error)
  1205. {
  1206. return error;
  1207. }
  1208. /* send command first */
  1209. USDHC_SendCommand(base, command);
  1210. /* wait command done */
  1211. error = USDHC_WaitCommandDone(base, command, (data == NULL) || (data->dataType == kUSDHC_TransferDataNormal));
  1212. /* wait transfer data finsih */
  1213. if ((data != NULL) && (error == kStatus_Success))
  1214. {
  1215. return USDHC_TransferDataBlocking(base, data, enDMA);
  1216. }
  1217. return error;
  1218. }
  1219. status_t USDHC_TransferNonBlocking(USDHC_Type *base,
  1220. usdhc_handle_t *handle,
  1221. usdhc_adma_config_t *dmaConfig,
  1222. usdhc_transfer_t *transfer)
  1223. {
  1224. assert(handle);
  1225. assert(transfer);
  1226. status_t error = kStatus_Fail;
  1227. usdhc_command_t *command = transfer->command;
  1228. usdhc_data_t *data = transfer->data;
  1229. bool executeTuning = ((data == NULL) ? false : data->dataType == kUSDHC_TransferDataTuning);
  1230. /*check re-tuning request*/
  1231. if ((USDHC_GetInterruptStatusFlags(base) & (kUSDHC_ReTuningEventFlag)) != 0U)
  1232. {
  1233. USDHC_ClearInterruptStatusFlags(base, kUSDHC_ReTuningEventFlag);
  1234. return kStatus_USDHC_ReTuningRequest;
  1235. }
  1236. /* Save command and data into handle before transferring. */
  1237. handle->command = command;
  1238. handle->data = data;
  1239. handle->interruptFlags = 0U;
  1240. /* transferredWords will only be updated in ISR when transfer way is DATAPORT. */
  1241. handle->transferredWords = 0U;
  1242. /* Update ADMA descriptor table according to different DMA mode(no DMA, ADMA1, ADMA2).*/
  1243. if ((data != NULL) && (dmaConfig != NULL) && (!executeTuning))
  1244. {
  1245. error = USDHC_SetAdmaTableConfig(base, dmaConfig, data, (data->dataType & kUSDHC_TransferDataBoot) ?
  1246. kUSDHC_AdmaDescriptorMultipleFlag :
  1247. kUSDHC_AdmaDescriptorSingleFlag);
  1248. }
  1249. /* if the DMA desciptor configure fail or not needed , disable it */
  1250. if (error != kStatus_Success)
  1251. {
  1252. /* disable DMA, using polling mode in this situation */
  1253. USDHC_EnableInternalDMA(base, false);
  1254. }
  1255. #if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
  1256. else
  1257. {
  1258. if (data->txData != NULL)
  1259. {
  1260. /* clear the DCACHE */
  1261. DCACHE_CleanByRange((uint32_t)data->txData, (data->blockSize) * (data->blockCount));
  1262. }
  1263. else
  1264. {
  1265. /* clear the DCACHE */
  1266. DCACHE_CleanInvalidateByRange((uint32_t)data->rxData, (data->blockSize) * (data->blockCount));
  1267. }
  1268. }
  1269. #endif
  1270. error = USDHC_SetDataTransferConfig(base, data, &(command->flags));
  1271. if (kStatus_Success != error)
  1272. {
  1273. return error;
  1274. }
  1275. /* send command first */
  1276. USDHC_SendCommand(base, command);
  1277. return kStatus_Success;
  1278. }
  1279. #if defined(FSL_FEATURE_USDHC_HAS_SDR50_MODE) && (FSL_FEATURE_USDHC_HAS_SDR50_MODE)
  1280. void USDHC_EnableManualTuning(USDHC_Type *base, bool enable)
  1281. {
  1282. if (enable)
  1283. {
  1284. /* make sure std_tun_en bit is clear */
  1285. base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
  1286. /* disable auto tuning here */
  1287. base->MIX_CTRL &= ~USDHC_MIX_CTRL_AUTO_TUNE_EN_MASK;
  1288. /* execute tuning for SDR104 mode */
  1289. base->MIX_CTRL |=
  1290. USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK | USDHC_MIX_CTRL_FBCLK_SEL_MASK;
  1291. }
  1292. else
  1293. { /* abort the tuning */
  1294. base->MIX_CTRL &= ~(USDHC_MIX_CTRL_EXE_TUNE_MASK | USDHC_MIX_CTRL_SMP_CLK_SEL_MASK);
  1295. }
  1296. }
  1297. status_t USDHC_AdjustDelayForManualTuning(USDHC_Type *base, uint32_t delay)
  1298. {
  1299. uint32_t clkTuneCtrl = 0U;
  1300. clkTuneCtrl = base->CLK_TUNE_CTRL_STATUS;
  1301. clkTuneCtrl &= ~USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE_MASK;
  1302. clkTuneCtrl |= USDHC_CLK_TUNE_CTRL_STATUS_DLY_CELL_SET_PRE(delay);
  1303. /* load the delay setting */
  1304. base->CLK_TUNE_CTRL_STATUS = clkTuneCtrl;
  1305. /* check delat setting error */
  1306. if (base->CLK_TUNE_CTRL_STATUS &
  1307. (USDHC_CLK_TUNE_CTRL_STATUS_PRE_ERR_MASK | USDHC_CLK_TUNE_CTRL_STATUS_NXT_ERR_MASK))
  1308. {
  1309. return kStatus_Fail;
  1310. }
  1311. return kStatus_Success;
  1312. }
  1313. void USDHC_EnableStandardTuning(USDHC_Type *base, uint32_t tuningStartTap, uint32_t step, bool enable)
  1314. {
  1315. uint32_t tuningCtrl = 0U;
  1316. if (enable)
  1317. {
  1318. /* feedback clock */
  1319. base->MIX_CTRL |= USDHC_MIX_CTRL_FBCLK_SEL_MASK;
  1320. /* config tuning start and step */
  1321. tuningCtrl = base->TUNING_CTRL;
  1322. tuningCtrl &= ~(USDHC_TUNING_CTRL_TUNING_START_TAP_MASK | USDHC_TUNING_CTRL_TUNING_STEP_MASK);
  1323. tuningCtrl |= (USDHC_TUNING_CTRL_TUNING_START_TAP(tuningStartTap) | USDHC_TUNING_CTRL_TUNING_STEP(step) |
  1324. USDHC_TUNING_CTRL_STD_TUNING_EN_MASK);
  1325. base->TUNING_CTRL = tuningCtrl;
  1326. /* excute tuning */
  1327. base->AUTOCMD12_ERR_STATUS |=
  1328. (USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
  1329. }
  1330. else
  1331. {
  1332. /* disable the standard tuning */
  1333. base->TUNING_CTRL &= ~USDHC_TUNING_CTRL_STD_TUNING_EN_MASK;
  1334. /* clear excute tuning */
  1335. base->AUTOCMD12_ERR_STATUS &=
  1336. ~(USDHC_AUTOCMD12_ERR_STATUS_EXECUTE_TUNING_MASK | USDHC_AUTOCMD12_ERR_STATUS_SMP_CLK_SEL_MASK);
  1337. }
  1338. }
  1339. void USDHC_EnableAutoTuningForCmdAndData(USDHC_Type *base)
  1340. {
  1341. uint32_t busWidth = 0U;
  1342. base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_CMD_EN_MASK;
  1343. busWidth = (base->PROT_CTRL & USDHC_PROT_CTRL_DTW_MASK) >> USDHC_PROT_CTRL_DTW_SHIFT;
  1344. if (busWidth == kUSDHC_DataBusWidth1Bit)
  1345. {
  1346. base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
  1347. base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
  1348. }
  1349. else if (busWidth == kUSDHC_DataBusWidth4Bit)
  1350. {
  1351. base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
  1352. base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
  1353. }
  1354. else if (busWidth == kUSDHC_DataBusWidth8Bit)
  1355. {
  1356. base->VEND_SPEC2 |= USDHC_VEND_SPEC2_TUNING_8bit_EN_MASK;
  1357. base->VEND_SPEC2 &= ~USDHC_VEND_SPEC2_TUNING_1bit_EN_MASK;
  1358. }
  1359. else
  1360. {
  1361. }
  1362. }
  1363. #endif /* FSL_FEATURE_USDHC_HAS_SDR50_MODE */
  1364. static void USDHC_TransferHandleCardDetect(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
  1365. {
  1366. if (interruptFlags & kUSDHC_CardInsertionFlag)
  1367. {
  1368. if (handle->callback.CardInserted)
  1369. {
  1370. handle->callback.CardInserted(base, handle->userData);
  1371. }
  1372. }
  1373. else
  1374. {
  1375. if (handle->callback.CardRemoved)
  1376. {
  1377. handle->callback.CardRemoved(base, handle->userData);
  1378. }
  1379. }
  1380. }
  1381. static void USDHC_TransferHandleCommand(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
  1382. {
  1383. assert(handle->command);
  1384. if ((interruptFlags & kUSDHC_CommandErrorFlag) && (!(handle->data)))
  1385. {
  1386. if (handle->callback.TransferComplete)
  1387. {
  1388. handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
  1389. }
  1390. }
  1391. else
  1392. {
  1393. /* Receive response */
  1394. if (kStatus_Success != USDHC_ReceiveCommandResponse(base, handle->command))
  1395. {
  1396. if (handle->callback.TransferComplete)
  1397. {
  1398. handle->callback.TransferComplete(base, handle, kStatus_USDHC_SendCommandFailed, handle->userData);
  1399. }
  1400. }
  1401. else if ((!(handle->data)) && (handle->callback.TransferComplete))
  1402. {
  1403. if (handle->callback.TransferComplete)
  1404. {
  1405. handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
  1406. }
  1407. }
  1408. else
  1409. {
  1410. }
  1411. }
  1412. }
  1413. static void USDHC_TransferHandleData(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
  1414. {
  1415. assert(handle->data);
  1416. if ((!(handle->data->enableIgnoreError)) && ((interruptFlags & (kUSDHC_DataErrorFlag | kUSDHC_DmaErrorFlag))))
  1417. {
  1418. if (handle->callback.TransferComplete)
  1419. {
  1420. handle->callback.TransferComplete(base, handle, kStatus_USDHC_TransferDataFailed, handle->userData);
  1421. }
  1422. }
  1423. else
  1424. {
  1425. if (interruptFlags & kUSDHC_BufferReadReadyFlag)
  1426. {
  1427. /* std tuning process only need to wait BRR */
  1428. if (handle->data->dataType == kUSDHC_TransferDataTuning)
  1429. {
  1430. if (handle->callback.TransferComplete)
  1431. {
  1432. handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
  1433. }
  1434. }
  1435. else
  1436. {
  1437. handle->transferredWords = USDHC_ReadDataPort(base, handle->data, handle->transferredWords);
  1438. }
  1439. }
  1440. else if (interruptFlags & kUSDHC_BufferWriteReadyFlag)
  1441. {
  1442. handle->transferredWords = USDHC_WriteDataPort(base, handle->data, handle->transferredWords);
  1443. }
  1444. else
  1445. {
  1446. if ((interruptFlags & kUSDHC_DmaCompleteFlag) &&
  1447. (handle->data->dataType == kUSDHC_TransferDataBootcontinous))
  1448. {
  1449. *(handle->data->rxData) = s_usdhcBootDummy;
  1450. }
  1451. if ((handle->callback.TransferComplete) && (interruptFlags & kUSDHC_DataCompleteFlag))
  1452. {
  1453. handle->callback.TransferComplete(base, handle, kStatus_Success, handle->userData);
  1454. }
  1455. }
  1456. }
  1457. }
  1458. static void USDHC_TransferHandleSdioInterrupt(USDHC_Type *base, usdhc_handle_t *handle)
  1459. {
  1460. if (handle->callback.SdioInterrupt)
  1461. {
  1462. handle->callback.SdioInterrupt(base, handle->userData);
  1463. }
  1464. }
  1465. static void USDHC_TransferHandleReTuning(USDHC_Type *base, usdhc_handle_t *handle, uint32_t interruptFlags)
  1466. {
  1467. assert(handle->callback.ReTuning);
  1468. /* retuning request */
  1469. if ((interruptFlags & kUSDHC_TuningErrorFlag) == kUSDHC_TuningErrorFlag)
  1470. {
  1471. handle->callback.ReTuning(base, handle->userData); /* retuning fail */
  1472. }
  1473. }
  1474. static void USDHC_TransferHandleBlockGap(USDHC_Type *base, usdhc_handle_t *handle)
  1475. {
  1476. if (handle->callback.BlockGap)
  1477. {
  1478. handle->callback.BlockGap(base, handle->userData);
  1479. }
  1480. }
  1481. void USDHC_TransferCreateHandle(USDHC_Type *base,
  1482. usdhc_handle_t *handle,
  1483. const usdhc_transfer_callback_t *callback,
  1484. void *userData)
  1485. {
  1486. assert(handle);
  1487. assert(callback);
  1488. /* Zero the handle. */
  1489. memset(handle, 0, sizeof(*handle));
  1490. /* Set the callback. */
  1491. handle->callback.CardInserted = callback->CardInserted;
  1492. handle->callback.CardRemoved = callback->CardRemoved;
  1493. handle->callback.SdioInterrupt = callback->SdioInterrupt;
  1494. handle->callback.BlockGap = callback->BlockGap;
  1495. handle->callback.TransferComplete = callback->TransferComplete;
  1496. handle->callback.ReTuning = callback->ReTuning;
  1497. handle->userData = userData;
  1498. /* Save the handle in global variables to support the double weak mechanism. */
  1499. s_usdhcHandle[USDHC_GetInstance(base)] = handle;
  1500. /* Enable interrupt in NVIC. */
  1501. USDHC_SetTransferInterrupt(base, true);
  1502. /* disable the tuning pass interrupt */
  1503. USDHC_DisableInterruptSignal(base, kUSDHC_TuningPassFlag | kUSDHC_ReTuningEventFlag);
  1504. /* save IRQ handler */
  1505. s_usdhcIsr = USDHC_TransferHandleIRQ;
  1506. EnableIRQ(s_usdhcIRQ[USDHC_GetInstance(base)]);
  1507. }
  1508. void USDHC_TransferHandleIRQ(USDHC_Type *base, usdhc_handle_t *handle)
  1509. {
  1510. assert(handle);
  1511. uint32_t interruptFlags;
  1512. interruptFlags = USDHC_GetInterruptStatusFlags(base);
  1513. handle->interruptFlags = interruptFlags;
  1514. if (interruptFlags & kUSDHC_CardDetectFlag)
  1515. {
  1516. USDHC_TransferHandleCardDetect(base, handle, (interruptFlags & kUSDHC_CardDetectFlag));
  1517. }
  1518. if (interruptFlags & kUSDHC_CommandFlag)
  1519. {
  1520. USDHC_TransferHandleCommand(base, handle, (interruptFlags & kUSDHC_CommandFlag));
  1521. }
  1522. if (interruptFlags & kUSDHC_DataFlag)
  1523. {
  1524. USDHC_TransferHandleData(base, handle, (interruptFlags & kUSDHC_DataFlag));
  1525. }
  1526. if (interruptFlags & kUSDHC_CardInterruptFlag)
  1527. {
  1528. USDHC_TransferHandleSdioInterrupt(base, handle);
  1529. }
  1530. if (interruptFlags & kUSDHC_BlockGapEventFlag)
  1531. {
  1532. USDHC_TransferHandleBlockGap(base, handle);
  1533. }
  1534. if (interruptFlags & kUSDHC_SDR104TuningFlag)
  1535. {
  1536. USDHC_TransferHandleReTuning(base, handle, (interruptFlags & kUSDHC_SDR104TuningFlag));
  1537. }
  1538. USDHC_ClearInterruptStatusFlags(base, interruptFlags);
  1539. }
  1540. #ifdef USDHC0
  1541. void USDHC0_DriverIRQHandler(void)
  1542. {
  1543. s_usdhcIsr(s_usdhcBase[0U], s_usdhcHandle[0U]);
  1544. /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
  1545. exception return operation might vector to incorrect interrupt */
  1546. #if defined __CORTEX_M && (__CORTEX_M == 4U)
  1547. __DSB();
  1548. #endif
  1549. }
  1550. #endif
  1551. #ifdef USDHC1
  1552. void USDHC1_DriverIRQHandler(void)
  1553. {
  1554. s_usdhcIsr(s_usdhcBase[1U], s_usdhcHandle[1U]);
  1555. /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
  1556. exception return operation might vector to incorrect interrupt */
  1557. #if defined __CORTEX_M && (__CORTEX_M == 4U)
  1558. __DSB();
  1559. #endif
  1560. }
  1561. #endif
  1562. #ifdef USDHC2
  1563. void USDHC2_DriverIRQHandler(void)
  1564. {
  1565. s_usdhcIsr(s_usdhcBase[2U], s_usdhcHandle[2U]);
  1566. /* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping
  1567. exception return operation might vector to incorrect interrupt */
  1568. #if defined __CORTEX_M && (__CORTEX_M == 4U)
  1569. __DSB();
  1570. #endif
  1571. }
  1572. #endif