1 //*****************************************************************************
2 //
3 //! @file am_hal_sdhc.c
4 //!
5 //! @brief Functions for interfacing with the SDHC.
6 //!
7 //! @addtogroup sdhc_4p SDHC host controller
8 //! @ingroup apollo4p_hal
9 //! @{
10 //
11 //*****************************************************************************
12
13 //*****************************************************************************
14 //
15 // Copyright (c) 2023, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision stable-7da8bae71f of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47
48 #include <stdbool.h>
49 #include <stdint.h>
50
51 #include "am_mcu_apollo.h"
52
53 #include "am_util_delay.h"
54 #include "am_util_stdio.h"
55 #include "am_util_debug.h"
56
57 //*****************************************************************************
58 //
59 // Private Types.
60 //
61 //*****************************************************************************
62
63 #define AM_HAL_MAGIC_SDHC 0x8313B0
64 #define AM_HAL_SDHC_CHK_HANDLE(h) \
65 ((h) && ((am_hal_handle_prefix_t *)(h))->s.bInit && (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_SDHC))
66
67 #define AM_HAL_SDHC_DEBUG(fmt, ...) am_util_debug_printf("[SDHC] line %04d - "fmt, __LINE__, ##__VA_ARGS__)
68
69 //
70 //! SD Host software reset types
71 //
72 typedef enum
73 {
74 AM_HAL_SDHC_SW_RESET_DATA_LINE = 0U, /**< Reset the data circuit only. */
75 AM_HAL_SDHC_SW_RESET_CMD_LINE = 1U, /**< Reset the command circuit only. */
76 AM_HAL_SDHC_SW_RESET_ALL = 2U /**< Reset the whole SD Host controller. */
77 } am_hal_sdhc_sw_reset_e;
78
79 //
80 //! SD Host Register Types
81 //
82 typedef struct
83 {
84 bool bValid;
85 uint32_t regHOSTCTRL1;
86 uint32_t regCLOCKCTRL;
87 uint32_t regINTENABLE;
88 uint32_t regINTSIG;
89 uint32_t regAUTO;
90 } am_hal_sdhc_register_state_t;
91
92 //
93 //! SDHC State structure.
94 //
95 typedef struct
96 {
97 //
98 //! Handle validation prefix.
99 //
100 am_hal_handle_prefix_t prefix;
101
102 //
103 //! Physical module number.
104 //
105 uint32_t ui32Module;
106 uint32_t ui32HostSDMABufSize;
107 uint8_t ui8BaseClockFreq;
108
109 //
110 //! Link to the card host
111 //
112 am_hal_card_host_t *pHost;
113
114 //
115 //! Save the error count
116 //
117 bool bCmdErr;
118 bool bDataErr;
119 uint32_t ui32DataErrCnt;
120 uint32_t ui32CmdErrCnt;
121
122 //
123 //! Store the data transfer infomation
124 //
125 uint32_t *pui32Buf;
126 uint32_t ui32DataLen;
127 uint32_t ui32BlkCnt;
128 uint32_t ui32BlkNum;
129 uint32_t ui32BlkSize;
130 uint32_t ui32BlksPerSDMA;
131 am_hal_data_dir_e eDataDir;
132 bool bAsyncCmdIsDone;
133
134 //
135 //! Power Save-Restore register state
136 //
137 am_hal_sdhc_register_state_t registerState;
138 } am_hal_sdhc_state_t;
139
140 //*****************************************************************************
141 //
142 // Global Variables.
143 //
144 //*****************************************************************************
145 static am_hal_sdhc_state_t g_SDHCState[AM_REG_SDIO_NUM_MODULES];
146
147 //*****************************************************************************
148 //
149 // Internal Functions.
150 //
151 //*****************************************************************************
152
am_hal_sdhc_software_reset(SDIO_Type * pSDHC,am_hal_sdhc_sw_reset_e eSoftwareReset)153 static uint32_t am_hal_sdhc_software_reset(SDIO_Type *pSDHC, am_hal_sdhc_sw_reset_e eSoftwareReset)
154 {
155 uint32_t ui32Mask;
156 uint32_t ui32Timeout;
157
158 if ( !pSDHC->PRESENT_b.CARDINSERTED )
159 {
160 return AM_HAL_STATUS_FAIL;
161 }
162
163 ui32Mask = 0x1 << (SDIO_CLOCKCTRL_SWRSTDAT_Pos - eSoftwareReset);
164
165 pSDHC->CLOCKCTRL |= ui32Mask;
166
167 ui32Timeout = 150;
168 do
169 {
170 if ( ui32Timeout == 0 )
171 {
172 return AM_HAL_STATUS_FAIL;
173 }
174 ui32Timeout--;
175 am_util_delay_ms(1);
176 } while (pSDHC->CLOCKCTRL & ui32Mask);
177
178 return AM_HAL_STATUS_SUCCESS;
179 }
180
181 //
182 // SDHC send command function
183 //
am_hal_sdhc_check_cmd_inhibit(SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)184 static inline uint32_t am_hal_sdhc_check_cmd_inhibit(SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
185 {
186 uint32_t ui32CmdInhibitMask;
187
188 //
189 // Check if CMD and DAT Lines are busy
190 //
191 ui32CmdInhibitMask = SDIO_PRESENT_CMDINHCMD_Msk | SDIO_PRESENT_CMDINHDAT_Msk;
192
193 if ( !pCmdData || pCmdData->bNotUseDataLine )
194 {
195 ui32CmdInhibitMask &= ~SDIO_PRESENT_CMDINHDAT_Msk;
196 }
197
198 if ( am_hal_delay_us_status_check(100, (uint32_t)&pSDHC->PRESENT, ui32CmdInhibitMask,
199 ui32CmdInhibitMask, false) == AM_HAL_STATUS_TIMEOUT )
200 {
201 AM_HAL_SDHC_DEBUG("%s : CMD and DAT line is busy\n", __FUNCTION__);
202 pCmd->eError = AM_HAL_CMD_ERR_TIMEOUT;
203 return AM_HAL_STATUS_TIMEOUT;
204 }
205
206 return AM_HAL_STATUS_SUCCESS;
207 }
208
209 //
210 // Prepare the command register value
211 //
am_hal_sdhc_prepare_cmd(SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)212 static uint32_t am_hal_sdhc_prepare_cmd(SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
213 {
214 uint32_t ui32CmdReg = 0x0;
215 //
216 // Response Type Select
217 //
218 if ( !(pCmd->ui32RespType & MMC_RSP_PRESENT) )
219 {
220 ui32CmdReg = SDIO_TRANSFER_RESPTYPESEL_NORESPONSE;
221 }
222 else if ( pCmd->ui32RespType & MMC_RSP_136 )
223 {
224 ui32CmdReg |= SDIO_TRANSFER_RESPTYPESEL_LEN136 << SDIO_TRANSFER_RESPTYPESEL_Pos;
225 }
226 else if ( pCmd->ui32RespType & MMC_RSP_BUSY )
227 {
228 ui32CmdReg |= SDIO_TRANSFER_RESPTYPESEL_LEN48CHKBUSY << SDIO_TRANSFER_RESPTYPESEL_Pos;
229 }
230 else
231 {
232 ui32CmdReg |= SDIO_TRANSFER_RESPTYPESEL_LEN48 << SDIO_TRANSFER_RESPTYPESEL_Pos;
233 }
234
235 //
236 // Data Present Select
237 //
238 if ( pCmdData != NULL )
239 {
240 ui32CmdReg |= SDIO_TRANSFER_DATAPRSNTSEL_Msk;
241 }
242
243 //
244 // Command CRC Check Enable
245 //
246 if ( pCmd->ui32RespType & MMC_RSP_CRC )
247 {
248 ui32CmdReg |= SDIO_TRANSFER_CMDCRCCHKEN_Msk;
249 }
250
251 //
252 // Command Index Check Enable
253 //
254 if ( pCmd->ui32RespType & MMC_RSP_OPCODE )
255 {
256 ui32CmdReg |= SDIO_TRANSFER_CMDIDXCHKEN_Msk;
257 }
258
259 ui32CmdReg |= (pCmd->ui8Idx << SDIO_TRANSFER_CMDIDX_Pos);
260
261 return ui32CmdReg;
262 }
263
264 //
265 // ADMA2 functions - maximum 127*16 = 2032 Blocks can be used by upper layer block-oriented APIs
266 // redefining 'AM_HAL_ADMA_TABLE_NO_ENTRIES' to get the much larger data transfer.
267 //
268
269 #define AM_HAL_ADMA_MAX_LEN 65535
270 #define AM_HAL_ADMA_MAX_BLKS_PER_ENTRY 127 // (AM_HAL_ADMA_MAX_LEN/512)
271
272 //
273 //! Maximum block number for one ADMA2 is limited to 127*AM_HAL_ADMA_TABLE_NO_ENTRIES.
274 //! enlarging the entry number if want to transfer more blocks
275 //! in one ADMA2 transaction.
276 //
277 #define AM_HAL_ADMA_TABLE_NO_ENTRIES 16 // 127*16*512 = 1016KB
278
279 //
280 //! @name Decriptor table defines
281 //! @{
282 //
283 #define AM_HAL_ADMA_DESC_ATTR_VALID (0x1 << 0)
284 #define AM_HAL_ADMA_DESC_ATTR_END (0x1 << 1)
285 #define AM_HAL_ADMA_DESC_ATTR_INT (0x1 << 2)
286 #define AM_HAL_ADMA_DESC_ATTR_ACT0 (0x1 << 3)
287 #define AM_HAL_ADMA_DESC_ATTR_ACT1 (0x1 << 4)
288 #define AM_HAL_ADMA_DESC_ATTR_ACT2 (0x1 << 5)
289
290 #define AM_HAL_ADMA_DESC_TRANSFER_DATA AM_HAL_ADMA_DESC_ATTR_ACT2
291 #define AM_HAL_ADMA_DESC_LINK_DESC (AM_HAL_ADMA_DESC_ATTR_ACT1 | AM_HAL_ADMA_DESC_ATTR_ACT2)
292 //! @}
293
294 typedef uint32_t dma_addr_t;
295
296 typedef struct
297 {
298 uint8_t ui8Attr;
299 uint8_t ui8Reserved;
300 uint16_t ui16Len;
301 uint32_t ui32AddrLow;
302 } am_hal_sdhc_adma_desc_t;
303
304 static am_hal_sdhc_adma_desc_t adma_desc_table[AM_HAL_ADMA_TABLE_NO_ENTRIES];
305
am_hal_sdhc_prepare_sdhci_adma_desc(uint32_t ui32Idx,dma_addr_t ui32DmaAddr,uint16_t ui16Len,bool bEnd)306 static void am_hal_sdhc_prepare_sdhci_adma_desc(uint32_t ui32Idx, dma_addr_t ui32DmaAddr, uint16_t ui16Len, bool bEnd)
307 {
308 am_hal_sdhc_adma_desc_t *pDesc;
309 uint8_t ui8Attr;
310
311 pDesc = &adma_desc_table[ui32Idx];
312
313 ui8Attr = AM_HAL_ADMA_DESC_ATTR_VALID | AM_HAL_ADMA_DESC_TRANSFER_DATA;
314 if ( bEnd )
315 {
316 ui8Attr |= AM_HAL_ADMA_DESC_ATTR_END;
317 }
318
319 pDesc->ui8Attr = ui8Attr;
320 pDesc->ui16Len = ui16Len;
321 pDesc->ui8Reserved = 0;
322 pDesc->ui32AddrLow = ui32DmaAddr;
323 }
324
am_hal_sdhc_prepare_adma_table(am_hal_card_cmd_data_t * pCmdData)325 static void am_hal_sdhc_prepare_adma_table(am_hal_card_cmd_data_t *pCmdData)
326 {
327 bool bEnd;
328 uint32_t i;
329 int32_t i32BlkCnt;
330 uint32_t ui32XferBytes;
331 uint32_t ui32IovLen;
332 uint8_t ui8IovCnt = 0;
333 uint8_t ui8IovIndex = 0;
334 dma_addr_t ui32DmaAddr;
335
336 ui8IovCnt = pCmdData->ui8IovCnt;
337 if ( ui8IovCnt )
338 {
339 i = 0;
340 while (ui8IovCnt > 0)
341 {
342 ui32DmaAddr = (dma_addr_t)(pCmdData->pIov[ui8IovIndex].pIovBase);
343 ui32IovLen = pCmdData->pIov[ui8IovIndex].ui32IovLen;
344 while (ui32IovLen > 0)
345 {
346 if ( ui8IovCnt > 1 )
347 {
348 bEnd = false;
349 }
350 else
351 {
352 bEnd = (ui32IovLen > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY * pCmdData->ui32BlkSize) ? false : true;
353 }
354
355 if ( ui32IovLen > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY * pCmdData->ui32BlkSize )
356 {
357 ui32XferBytes = AM_HAL_ADMA_MAX_BLKS_PER_ENTRY * pCmdData->ui32BlkSize;
358 }
359 else
360 {
361 ui32XferBytes = ui32IovLen;
362 }
363 am_hal_sdhc_prepare_sdhci_adma_desc(i, ui32DmaAddr, ui32XferBytes, bEnd);
364 ui32DmaAddr += ui32XferBytes;
365 ui32IovLen -= ui32XferBytes;
366 i++;
367 }
368 ui8IovIndex++;
369 ui8IovCnt--;
370 }
371 }
372 else
373 {
374 i = 0;
375 i32BlkCnt = (pCmdData->ui32BlkCnt == 0) ? 1 : pCmdData->ui32BlkCnt;
376 ui32DmaAddr = (dma_addr_t)(pCmdData->pui8Buf);
377 while (i32BlkCnt > 0)
378 {
379 ui32XferBytes = (i32BlkCnt > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY) ?
380 AM_HAL_ADMA_MAX_BLKS_PER_ENTRY*pCmdData->ui32BlkSize : i32BlkCnt*pCmdData->ui32BlkSize;
381 bEnd = (i32BlkCnt > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY) ? false : true;
382 am_hal_sdhc_prepare_sdhci_adma_desc(i, ui32DmaAddr, ui32XferBytes, bEnd);
383 i++;
384 ui32DmaAddr += ui32XferBytes;
385 i32BlkCnt -= AM_HAL_ADMA_MAX_BLKS_PER_ENTRY;
386 }
387 }
388 }
389
390 //
391 // Prepare transfer mode register and set the block size, block count, SDMA and host control registers (for DMA)
392 //
am_hal_sdhc_prepare_xfer(am_hal_sdhc_state_t * pSDHCState,SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)393 static uint32_t am_hal_sdhc_prepare_xfer(am_hal_sdhc_state_t *pSDHCState, SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
394 {
395 uint32_t ui32ModeReg = 0;
396 uint32_t ui32BlkReg = 0;
397
398 if ( pCmdData != NULL )
399 {
400 pSDHCState->pui32Buf = (uint32_t *)(pCmdData->pui8Buf);
401 pSDHCState->ui32DataLen = (pCmdData->ui32BlkCnt == 0) ? pCmdData->ui32BlkSize : (pCmdData->ui32BlkCnt * pCmdData->ui32BlkSize);
402 pSDHCState->eDataDir = pCmdData->dir;
403 pSDHCState->ui32BlkSize = pCmdData->ui32BlkSize;
404 pSDHCState->ui32BlkCnt = pCmdData->ui32BlkCnt;
405 pSDHCState->ui32BlkNum = pCmdData->ui32BlkCnt;
406
407 //
408 // Transfer direction - 0x1 Read
409 //
410 if ( pCmdData->dir == AM_HAL_DATA_DIR_READ )
411 {
412 ui32ModeReg |= SDIO_TRANSFER_DXFERDIRSEL_Msk;
413 }
414
415 //
416 // Transfer DMA setting
417 //
418 if ( pCmdData->eXferMode == AM_HAL_HOST_XFER_DEFAULT )
419 {
420 pCmdData->eXferMode = pSDHCState->pHost->eXferMode;
421 }
422
423 switch (pCmdData->eXferMode)
424 {
425 case AM_HAL_HOST_XFER_SDMA:
426 ui32ModeReg |= SDIO_TRANSFER_DMAEN_Msk;
427 pSDHC->HOSTCTRL1_b.DMASELECT = SDIO_HOSTCTRL1_DMASELECT_SDMA;
428 pSDHC->SDMA = (dma_addr_t)(pCmdData->pui8Buf);
429 pSDHCState->ui32BlksPerSDMA = pSDHCState->ui32HostSDMABufSize / pCmdData->ui32BlkSize;
430 break;
431 case AM_HAL_HOST_XFER_ADMA:
432 ui32ModeReg |= SDIO_TRANSFER_DMAEN_Msk;
433 pSDHC->HOSTCTRL1_b.DMASELECT = SDIO_HOSTCTRL1_DMASELECT_ADMA232;
434 am_hal_sdhc_prepare_adma_table(pCmdData);
435 pSDHC->ADMALOWD = (dma_addr_t)(&adma_desc_table[0]);
436 break;
437 default:
438 break;
439 }
440
441 //
442 // Auto Command setting
443 //
444 if ( pCmd->bAutoCMD12 )
445 {
446 ui32ModeReg |= SDIO_TRANSFER_ACMDEN_CMD12ENABLE << SDIO_TRANSFER_ACMDEN_Pos;
447 }
448 else if ( pCmd->bAutoCMD23 )
449 {
450 ui32ModeReg |= SDIO_TRANSFER_ACMDEN_CMD23ENABLE << SDIO_TRANSFER_ACMDEN_Pos;
451
452 #ifdef AM_DEBUG_PRINTF
453 if (pCmdData->eXferMode == AM_HAL_HOST_XFER_SDMA)
454 {
455 AM_HAL_SDHC_DEBUG("SDMA can't be used if enabling CMD23\n");
456 }
457 #endif
458
459 pSDHC->SDMA = pCmdData->ui32BlkCnt;
460 }
461
462 //
463 // Set the block count and size
464 //
465 ui32BlkReg |= pCmdData->ui32BlkSize << SDIO_BLOCK_TRANSFERBLOCKSIZE_Pos;
466 if ( pCmdData->ui32BlkCnt > 1 )
467 {
468 ui32ModeReg |= SDIO_TRANSFER_BLKSEL_Msk | SDIO_TRANSFER_BLKCNTEN_Msk;
469 ui32BlkReg |= pCmdData->ui32BlkCnt << SDIO_BLOCK_BLKCNT_Pos;
470 }
471
472 pSDHC->BLOCK = ui32BlkReg;
473
474 //
475 // Set the data timeout
476 //
477 pSDHC->CLOCKCTRL |= (0xe << SDIO_CLOCKCTRL_TIMEOUTCNT_Pos);
478 }
479
480 return ui32ModeReg;
481 }
482
483 //
484 // Get the command response after sending out the command
485 //
am_hal_sdhc_get_cmd_response(SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd)486 static void am_hal_sdhc_get_cmd_response(SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd)
487 {
488 uint32_t ui32RegResp[4];
489
490 pCmd->eError = AM_HAL_CMD_ERR_NONE;
491 if ( pCmd->ui32RespType == MMC_RSP_NONE )
492 {
493 return;
494 }
495
496 if ( pCmd->ui32RespType & MMC_RSP_136 )
497 {
498 ui32RegResp[0] = pSDHC->RESPONSE0;
499 ui32RegResp[1] = pSDHC->RESPONSE1;
500 ui32RegResp[2] = pSDHC->RESPONSE2;
501 ui32RegResp[3] = pSDHC->RESPONSE3;
502 pCmd->ui32Resp[0] = (ui32RegResp[3] << 8) | (ui32RegResp[2] >> 24);
503 pCmd->ui32Resp[1] = (ui32RegResp[2] << 8) | (ui32RegResp[1] >> 24);
504 pCmd->ui32Resp[2] = (ui32RegResp[1] << 8) | (ui32RegResp[0] >> 24);
505 pCmd->ui32Resp[3] = (ui32RegResp[0] << 8);
506 }
507 else
508 {
509 pCmd->ui32Resp[0] = pSDHC->RESPONSE0;
510 }
511 }
512
513 //
514 // Sending the command by writing the argument and command registers
515 //
am_hal_sdhc_send_cmd(am_hal_sdhc_state_t * pSDHCState,SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)516 static uint32_t am_hal_sdhc_send_cmd(am_hal_sdhc_state_t *pSDHCState, SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
517 {
518 uint32_t ui32CmdReg;
519
520 if ( am_hal_sdhc_check_cmd_inhibit(pSDHC, pCmd, pCmdData) == AM_HAL_STATUS_TIMEOUT )
521 {
522 pCmd->eError = AM_HAL_CMD_ERR_INHIBIT;
523 pSDHCState->bCmdErr = true;
524 pSDHCState->ui32CmdErrCnt++;
525 return AM_HAL_STATUS_TIMEOUT;
526 }
527
528 //
529 // Prepare the command register value
530 //
531 ui32CmdReg = am_hal_sdhc_prepare_cmd(pSDHC, pCmd, pCmdData);
532
533 //
534 // Prepare the transfer mode register value
535 //
536 ui32CmdReg |= am_hal_sdhc_prepare_xfer(pSDHCState, pSDHC, pCmd, pCmdData);
537
538 //
539 // Eliminate the DAXI side effects
540 //
541 am_hal_sysctrl_bus_write_flush();
542
543 //
544 // Write the argument and command register
545 //
546 pSDHC->ARGUMENT1 = pCmd->ui32Arg;
547 pSDHC->TRANSFER = ui32CmdReg;
548
549 return AM_HAL_STATUS_SUCCESS;
550
551 }
552
am_hal_sdhc_check_cmd_error_type(uint32_t ui32IntStatus)553 static inline am_hal_card_cmd_err_e am_hal_sdhc_check_cmd_error_type(uint32_t ui32IntStatus)
554 {
555 if (ui32IntStatus & SDIO_INTSTAT_COMMANDINDEXERROR_Msk)
556 {
557 return AM_HAL_CMD_ERR_INDEX;
558 }
559 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDENDBITERROR_Msk)
560 {
561 return AM_HAL_CMD_ERR_ENDBIT;
562 }
563 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDCRCERROR_Msk)
564 {
565 return AM_HAL_CMD_ERR_CRC;
566 }
567 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDTIMEOUTERROR_Msk)
568 {
569 return AM_HAL_CMD_ERR_NO_RESPONSE;
570 }
571 else
572 {
573 return AM_HAL_CMD_ERR_TIMEOUT;
574 }
575 }
576
577 //
578 // Wait the command done by checking command completion interrupt status
579 //
580 #define AM_HAL_WAIT_CMD_DONE_TIMEOUT 2
581
am_hal_sdhc_wait_cmd_done(am_hal_sdhc_state_t * pSDHCState,SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd)582 static uint32_t inline am_hal_sdhc_wait_cmd_done(am_hal_sdhc_state_t *pSDHCState, SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd)
583 {
584 uint32_t ui32Status;
585 uint32_t ui32IntStatus;
586 uint32_t ui32BitMask = SDIO_INTSTAT_COMMANDCOMPLETE_Msk;
587
588 ui32Status = am_hal_delay_us_status_check(
589 AM_HAL_WAIT_CMD_DONE_TIMEOUT*1000, (uint32_t)&pSDHC->INTSTAT,
590 ui32BitMask,
591 ui32BitMask,
592 true);
593
594 if ( AM_HAL_STATUS_SUCCESS != ui32Status )
595 {
596 ui32IntStatus = pSDHC->INTSTAT;
597 pCmd->eError = am_hal_sdhc_check_cmd_error_type(ui32IntStatus);
598 pSDHCState->bCmdErr = true;
599 pSDHCState->ui32CmdErrCnt++;
600 AM_HAL_SDHC_DEBUG("wait CMD completion INT timeout, Error Type : %d\n", pCmd->eError);
601 return AM_HAL_STATUS_TIMEOUT;
602 }
603
604 pSDHC->INTSTAT = ui32BitMask;
605
606 return AM_HAL_STATUS_SUCCESS;
607 }
608
609 //
610 // Do the PIO block transfer
611 //
am_hal_sdhc_pio_xfer_data(am_hal_sdhc_state_t * pSDHCState)612 static void am_hal_sdhc_pio_xfer_data(am_hal_sdhc_state_t *pSDHCState)
613 {
614 uint32_t ui32PreBufReadyMask;
615
616 ui32PreBufReadyMask = pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ ?
617 SDIO_PRESENT_BUFRDEN_Msk : SDIO_PRESENT_BUFWREN_Msk;
618
619 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
620
621 while (pSDHC->PRESENT & ui32PreBufReadyMask)
622 {
623 if ( pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ )
624 {
625 for (int i = 0; i < pSDHCState->ui32BlkSize; i += 4)
626 {
627 *pSDHCState->pui32Buf++ = pSDHC->BUFFER;
628 }
629 }
630 else
631 {
632 for (int i = 0; i < pSDHCState->ui32BlkSize; i += 4)
633 {
634 pSDHC->BUFFER = *pSDHCState->pui32Buf++;
635 }
636 }
637 pSDHCState->ui32BlkCnt--;
638 }
639 }
640
641 //
642 // Do the SDMA block transfer
643 //
am_hal_sdhc_sdma_xfer_data(am_hal_sdhc_state_t * pSDHCState)644 static void am_hal_sdhc_sdma_xfer_data(am_hal_sdhc_state_t *pSDHCState)
645 {
646 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
647
648 //
649 // Load the next DMA address
650 //
651 pSDHCState->ui32BlkCnt -= pSDHCState->ui32BlksPerSDMA;
652 pSDHCState->pui32Buf += pSDHCState->ui32HostSDMABufSize / sizeof(uint32_t);
653 pSDHC->SDMA = (dma_addr_t)(pSDHCState->pui32Buf);
654 }
655
am_hal_sdhc_check_data_error_type(uint32_t ui32IntStatus)656 static inline am_hal_card_data_err_e am_hal_sdhc_check_data_error_type(uint32_t ui32IntStatus)
657 {
658 if (ui32IntStatus & SDIO_INTSTAT_ADMAERROR_Msk)
659 {
660 return AM_HAL_DATA_ERR_ADMAERROR;
661 }
662 else if (ui32IntStatus & SDIO_INTSTAT_DATACRCERROR_Msk)
663 {
664 return AM_HAL_DATA_ERR_DATACRCERROR;
665 }
666 else if (ui32IntStatus & SDIO_INTSTAT_DATATIMEOUTERROR_Msk)
667 {
668 return AM_HAL_DATA_ERR_DATATIMEOUTERROR;
669 }
670 else if (ui32IntStatus & SDIO_INTSTAT_DATAENDBITERROR_Msk)
671 {
672 return AM_HAL_DATA_ERR_DATAENDBITERROR;
673 }
674 else
675 {
676 return AM_HAL_DATA_ERR_TIMEOUT;
677 }
678 }
679
680 #define DYNAMIC_SWITCH_SDCLK_FEATURE
681
682 //
683 // Xfer timeout value depends on the card performance. 80000 is an empirical value.
684 //
685 #define XFER_DATA_TIMEOUT 80000
686
687 //
688 // Transfer the block data to the card
689 //
am_hal_sdhc_xfer_data(am_hal_sdhc_state_t * pSDHCState,am_hal_card_cmd_data_t * pCmdData)690 static uint32_t am_hal_sdhc_xfer_data(am_hal_sdhc_state_t *pSDHCState,
691 am_hal_card_cmd_data_t *pCmdData)
692 {
693 bool bXferDone;
694 uint32_t ui32BufReadyMask;
695 uint32_t ui32IntStatus;
696 uint32_t ui32Timeout = XFER_DATA_TIMEOUT;
697
698 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
699
700 #ifdef AM_DEBUG_PRINTF
701 am_hal_card_host_t *pHost = pSDHCState->pHost;
702 #endif
703
704 if ( pCmdData->ui32BlkCnt != 0 )
705 {
706 ui32Timeout = XFER_DATA_TIMEOUT*pCmdData->ui32BlkCnt;
707 }
708
709 AM_HAL_SDHC_DEBUG("Xfer Timeout is %d\n", ui32Timeout);
710 AM_HAL_SDHC_DEBUG("Xfer BLK Cnt is %d\n", pSDHCState->ui32BlkCnt);
711 AM_HAL_SDHC_DEBUG("Xfer DataLen is %d\n", pSDHCState->ui32DataLen);
712 AM_HAL_SDHC_DEBUG("Xfer Mode is %d\n", pHost->eXferMode);
713 AM_HAL_SDHC_DEBUG("Xfer speed is %d\n", pHost->ui32Clock);
714 AM_HAL_SDHC_DEBUG("Xfer Width is %d\n", pHost->eBusWidth);
715
716 ui32BufReadyMask = pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ ?
717 SDIO_INTSTAT_BUFFERREADREADY_Msk : SDIO_INTSTAT_BUFFERWRITEREADY_Msk;
718
719 bXferDone = false;
720 ui32IntStatus = 0;
721 while ( !(ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk) && (ui32Timeout > 0) )
722 {
723 ui32IntStatus = pSDHC->INTSTAT;
724
725 if ( ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk )
726 {
727 // Invalidate DAXI to make sure CPU sees the new data when loaded
728 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
729
730 //
731 // Transfer completed
732 //
733 pSDHC->INTSTAT = SDIO_INTSTAT_TRANSFERCOMPLETE_Msk;
734 pSDHCState->ui32BlkCnt = 0;
735 bXferDone = true;
736 AM_HAL_SDHC_DEBUG("Xfer Completed\n");
737 }
738 else if ( ui32IntStatus & SDIO_INTSTAT_DMAINTERRUPT_Msk )
739 {
740 // Invalidate DAXI to make sure CPU sees the new data when loaded
741 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
742
743 //
744 // Transfer SDMA data
745 //
746 pSDHC->INTSTAT = SDIO_INTSTAT_DMAINTERRUPT_Msk;
747 AM_HAL_SDHC_DEBUG("Xfer SDMA DMA INTR\n");
748 am_hal_sdhc_sdma_xfer_data(pSDHCState);
749 }
750 else if ( ui32IntStatus & ui32BufReadyMask )
751 {
752 //
753 // Transfer PIO data if PIO buffer is ready
754 //
755 pSDHC->INTSTAT = ui32BufReadyMask;
756 AM_HAL_SDHC_DEBUG("Xfer PIO\n");
757 am_hal_sdhc_pio_xfer_data(pSDHCState);
758 }
759 else if (ui32IntStatus & (SDIO_INTSTAT_ADMAERROR_Msk |
760 SDIO_INTSTAT_DATACRCERROR_Msk |
761 SDIO_INTSTAT_DATATIMEOUTERROR_Msk |
762 SDIO_INTSTAT_DATAENDBITERROR_Msk))
763 {
764 pSDHC->INTSTAT = ui32IntStatus;
765 AM_HAL_SDHC_DEBUG("Xfer Data Error - 0x%x\n", ui32IntStatus);
766 pCmdData->eDataError = am_hal_sdhc_check_data_error_type(ui32IntStatus);
767 pSDHCState->bDataErr = true;
768 pSDHCState->ui32DataErrCnt++;
769 ui32Timeout = 1;
770 }
771
772 if ( ui32Timeout-- > 0 )
773 {
774 am_util_delay_us(5);
775 }
776 // AM_HAL_SDHC_DEBUG("INT STATUS 0x%x\n", ui32IntStatus);
777 }
778
779 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
780
781 //
782 // Disable the SDCLK after the xfer is done
783 //
784 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
785 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
786 #endif
787
788 if ( !bXferDone && ui32Timeout == 0 )
789 {
790 return (pSDHCState->ui32BlkNum - pSDHCState->ui32BlkCnt) << 16 | AM_HAL_STATUS_TIMEOUT;
791 }
792 else
793 {
794 return (pSDHCState->ui32BlkNum - pSDHCState->ui32BlkCnt) << 16 | AM_HAL_STATUS_SUCCESS;
795 }
796 }
797
798 //*****************************************************************************
799 //
800 // External Functions.
801 //
802 //*****************************************************************************
803
804 //*****************************************************************************
805 //
806 // SDHC initialization function
807 //
808 //*****************************************************************************
am_hal_sdhc_initialize(uint32_t ui32Module,void ** ppHandle)809 uint32_t am_hal_sdhc_initialize(uint32_t ui32Module, void **ppHandle)
810 {
811
812 #ifndef AM_HAL_DISABLE_API_VALIDATION
813 //
814 // Check that the request module is in range.
815 //
816 if ( ui32Module >= AM_REG_SDIO_NUM_MODULES )
817 {
818 return AM_HAL_STATUS_OUT_OF_RANGE;
819 }
820
821 //
822 // Check for valid arguements.
823 //
824 if ( !ppHandle )
825 {
826 return AM_HAL_STATUS_INVALID_ARG;
827 }
828
829 //
830 // Check if the handle is unallocated.
831 //
832 if ( g_SDHCState[ui32Module].prefix.s.bInit )
833 {
834 return AM_HAL_STATUS_INVALID_OPERATION;
835 }
836 #endif // AM_HAL_DISABLE_API_VALIDATION
837
838 //
839 // Initialize the handle.
840 //
841 g_SDHCState[ui32Module].prefix.s.bInit = true;
842 g_SDHCState[ui32Module].prefix.s.magic = AM_HAL_MAGIC_SDHC;
843 g_SDHCState[ui32Module].ui32Module = ui32Module;
844
845 //
846 // Return the handle.
847 //
848 *ppHandle = (void *)&g_SDHCState[ui32Module];
849
850 //
851 // Return the status.
852 //
853 return AM_HAL_STATUS_SUCCESS;
854 }
855
856 //*****************************************************************************
857 //
858 // SDHC Deinitialize function
859 //
860 //*****************************************************************************
am_hal_sdhc_deinitialize(void * pHandle)861 uint32_t am_hal_sdhc_deinitialize(void *pHandle)
862 {
863 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
864
865 #ifndef AM_HAL_DISABLE_API_VALIDATION
866 //
867 // Check the handle.
868 //
869 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
870 {
871 return AM_HAL_STATUS_INVALID_HANDLE;
872 }
873 #endif // AM_HAL_DISABLE_API_VALIDATION
874
875 //
876 // Reset the handle.
877 //
878 pSDHCState->prefix.s.bInit = false;
879 pSDHCState->ui32Module = 0;
880
881 //
882 // Return the status.
883 //
884 return AM_HAL_STATUS_SUCCESS;
885 }
886
887 //*****************************************************************************
888 //
889 // SDHC power control function
890 //
891 // This function updates the peripheral to a given power state.
892 //
893 //*****************************************************************************
am_hal_sdhc_power_control(void * pHandle,am_hal_sysctrl_power_state_e ePowerState,bool bRetainState)894 uint32_t am_hal_sdhc_power_control(void *pHandle, am_hal_sysctrl_power_state_e ePowerState, bool bRetainState)
895 {
896 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
897
898 #ifndef AM_HAL_DISABLE_API_VALIDATION
899 //
900 // Check the handle.
901 //
902 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
903 {
904 return AM_HAL_STATUS_INVALID_HANDLE;
905 }
906
907 #endif // AM_HAL_DISABLE_API_VALIDATION
908
909 //
910 // Decode the requested power state and update SDHC operation accordingly.
911 //
912 switch (ePowerState)
913 {
914 case AM_HAL_SYSCTRL_WAKE:
915
916 if ( bRetainState && !pSDHCState->registerState.bValid )
917 {
918 return AM_HAL_STATUS_INVALID_OPERATION;
919 }
920
921 //
922 // Enable power control.
923 //
924 am_hal_pwrctrl_periph_enable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_SDIO + pSDHCState->ui32Module));
925
926
927 if ( bRetainState )
928 {
929 //
930 // Restore SDHC registers
931 //
932 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 = pSDHCState->registerState.regHOSTCTRL1;
933 SDHCn(pSDHCState->ui32Module)->CLOCKCTRL = pSDHCState->registerState.regCLOCKCTRL;
934 SDHCn(pSDHCState->ui32Module)->INTENABLE = pSDHCState->registerState.regINTENABLE;
935 SDHCn(pSDHCState->ui32Module)->INTSIG = pSDHCState->registerState.regINTSIG;
936 SDHCn(pSDHCState->ui32Module)->AUTO = pSDHCState->registerState.regAUTO;
937 pSDHCState->registerState.bValid = false;
938 }
939 break;
940
941 case AM_HAL_SYSCTRL_NORMALSLEEP:
942 case AM_HAL_SYSCTRL_DEEPSLEEP:
943 if ( bRetainState )
944 {
945 //
946 // Save SDHC Registers
947 //
948 pSDHCState->registerState.regHOSTCTRL1 = SDHCn(pSDHCState->ui32Module)->HOSTCTRL1;
949 pSDHCState->registerState.regCLOCKCTRL = SDHCn(pSDHCState->ui32Module)->CLOCKCTRL;
950 pSDHCState->registerState.regINTENABLE = SDHCn(pSDHCState->ui32Module)->INTENABLE;
951 pSDHCState->registerState.regINTSIG = SDHCn(pSDHCState->ui32Module)->INTSIG;
952 pSDHCState->registerState.regAUTO = SDHCn(pSDHCState->ui32Module)->AUTO;
953 pSDHCState->registerState.bValid = true;
954 }
955
956 //
957 // Disable all the interrupts.
958 am_hal_sdhc_intr_status_disable(pHandle, 0xFFFFFFFF);
959
960
961 //
962 // Disable power control.
963 //
964 am_hal_pwrctrl_periph_disable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_SDIO + pSDHCState->ui32Module));
965 break;
966
967 default:
968 return AM_HAL_STATUS_INVALID_ARG;
969 }
970
971 //
972 // Return the status.
973 //
974 return AM_HAL_STATUS_SUCCESS;
975 }
976
977 //*****************************************************************************
978 //
979 // SDHC setup card host function
980 //
981 // This function updates pHost related settings by checking the capabilites of underlying
982 // SDHC host controller. These settings are important for validate the arguments to the card
983 // block read, write, erase, speed, bus width.
984 //
985 //*****************************************************************************
am_hal_sdhc_setup_host(void * pHandle,am_hal_card_host_t * pHost)986 uint32_t am_hal_sdhc_setup_host(void *pHandle, am_hal_card_host_t *pHost)
987 {
988 SDIO_Type *pSDHC;
989 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
990
991 #ifndef AM_HAL_DISABLE_API_VALIDATION
992 //
993 // Check the handle.
994 //
995 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
996 {
997 return AM_HAL_STATUS_INVALID_HANDLE;
998 }
999
1000 if ( !pSDHCState->prefix.s.bEnable )
1001 {
1002 return AM_HAL_STATUS_INVALID_OPERATION;
1003 }
1004
1005 #endif // AM_HAL_DISABLE_API_VALIDATION
1006
1007 //
1008 // Link to the card host
1009 //
1010 pSDHCState->pHost = pHost;
1011
1012 pSDHC = SDHCn(pSDHCState->ui32Module);
1013
1014 pSDHCState->ui8BaseClockFreq = pSDHC->CAPABILITIES0_b.SDCLKFREQ;
1015
1016 pHost->ui8Version = pSDHC->SLOTSTAT_b.SPECVER;
1017 pHost->ui32MaxClock = pSDHCState->ui8BaseClockFreq * 1000000;
1018 pHost->ui32MinClock = pHost->ui32MaxClock / 256;
1019 pHost->ui32Clock = 0x0;
1020
1021 //
1022 // Default transfer mode is ADMA
1023 //
1024 pHost->eXferMode = AM_HAL_HOST_XFER_ADMA;
1025 pHost->eBusWidth = AM_HAL_HOST_BUS_WIDTH_1;
1026 pHost->eUHSMode = AM_HAL_HOST_UHS_NONE;
1027
1028
1029 pHost->ui32MaxADMA2BlkNums = AM_HAL_ADMA_TABLE_NO_ENTRIES*AM_HAL_ADMA_MAX_BLKS_PER_ENTRY;
1030
1031 //
1032 // Default 4K SDMA boundary size
1033 //
1034 pSDHCState->ui32HostSDMABufSize = 4096*(0x1 << pSDHC->BLOCK_b.HOSTSDMABUFSZ);
1035 pSDHCState->bAsyncCmdIsDone = true;
1036
1037 return AM_HAL_STATUS_SUCCESS;
1038 }
1039
1040 //*****************************************************************************
1041 //
1042 // SDHC detects the card function
1043 //
1044 // This function detects the present of card in the slot.
1045 //
1046 //*****************************************************************************
am_hal_sdhc_get_cd(void * pHandle)1047 bool am_hal_sdhc_get_cd(void *pHandle)
1048 {
1049 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1050
1051 #ifndef AM_HAL_DISABLE_API_VALIDATION
1052 //
1053 // Check the handle.
1054 //
1055 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1056 {
1057 return AM_HAL_STATUS_INVALID_HANDLE;
1058 }
1059
1060 if ( !pSDHCState->prefix.s.bEnable )
1061 {
1062 return AM_HAL_STATUS_INVALID_OPERATION;
1063 }
1064 #endif // AM_HAL_DISABLE_API_VALIDATION
1065
1066 return SDHCn(pSDHCState->ui32Module)->PRESENT_b.CARDINSERTED;
1067 }
1068
1069 //*****************************************************************************
1070 //
1071 // SDHC detects the card write protection
1072 //
1073 // This function detects the card write protection in the slot.
1074 //
1075 //*****************************************************************************
am_hal_sdhc_get_wr_protect(void * pHandle)1076 bool am_hal_sdhc_get_wr_protect(void *pHandle)
1077 {
1078 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1079
1080 #ifndef AM_HAL_DISABLE_API_VALIDATION
1081 //
1082 // Check the handle.
1083 //
1084 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1085 {
1086 return AM_HAL_STATUS_INVALID_HANDLE;
1087 }
1088
1089 if ( !pSDHCState->prefix.s.bEnable )
1090 {
1091 return AM_HAL_STATUS_INVALID_OPERATION;
1092 }
1093 #endif // AM_HAL_DISABLE_API_VALIDATION
1094
1095 return SDHCn(pSDHCState->ui32Module)->PRESENT_b.WRPROTSW;
1096 }
1097
1098 //*****************************************************************************
1099 //
1100 // SDHC sets the SDIO bus IO volage
1101 //
1102 // This function sets the bus voltage needed to communiate with the card.
1103 //
1104 //*****************************************************************************
am_hal_sdhc_set_bus_voltage(void * pHandle,am_hal_host_bus_voltage_e eBusVoltage)1105 uint32_t am_hal_sdhc_set_bus_voltage(void *pHandle, am_hal_host_bus_voltage_e eBusVoltage)
1106 {
1107 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1108 am_hal_card_host_t *pHost;
1109
1110 #ifndef AM_HAL_DISABLE_API_VALIDATION
1111 //
1112 // Check the handle.
1113 //
1114 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1115 {
1116 return AM_HAL_STATUS_INVALID_HANDLE;
1117 }
1118
1119 if ( !pSDHCState->prefix.s.bEnable )
1120 {
1121 return AM_HAL_STATUS_INVALID_OPERATION;
1122 }
1123
1124 #endif // AM_HAL_DISABLE_API_VALIDATION
1125
1126 pHost = pSDHCState->pHost;
1127
1128 switch (eBusVoltage)
1129 {
1130 case AM_HAL_HOST_BUS_VOLTAGE_1_8:
1131 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_1_8V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1132 break;
1133 case AM_HAL_HOST_BUS_VOLTAGE_3_0:
1134 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_3_0V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1135 break;
1136 case AM_HAL_HOST_BUS_VOLTAGE_3_3:
1137 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_3_3V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1138 break;
1139 }
1140 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_SDBUSPOWER_Msk;
1141
1142 pHost->eBusVoltage = eBusVoltage;
1143
1144 return AM_HAL_STATUS_SUCCESS;
1145 }
1146
1147 //*****************************************************************************
1148 //
1149 // SDHC sets the SDIO bus width
1150 //
1151 // This function sets the bus width needed to communiate with the card.
1152 //
1153 //*****************************************************************************
am_hal_sdhc_set_bus_width(void * pHandle,am_hal_host_bus_width_e eBusWidth)1154 uint32_t am_hal_sdhc_set_bus_width(void *pHandle, am_hal_host_bus_width_e eBusWidth)
1155 {
1156 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1157 am_hal_card_host_t *pHost;
1158
1159 #ifndef AM_HAL_DISABLE_API_VALIDATION
1160 //
1161 // Check the handle.
1162 //
1163 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1164 {
1165 return AM_HAL_STATUS_INVALID_HANDLE;
1166 }
1167
1168 if ( !pSDHCState->prefix.s.bEnable )
1169 {
1170 return AM_HAL_STATUS_INVALID_OPERATION;
1171 }
1172
1173 #endif // AM_HAL_DISABLE_API_VALIDATION
1174
1175 pHost = pSDHCState->pHost;
1176
1177 if ( eBusWidth == AM_HAL_HOST_BUS_WIDTH_8 )
1178 {
1179 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.XFERWIDTH = 0x1;
1180 }
1181 else
1182 {
1183 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.XFERWIDTH = 0x0;
1184 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.DATATRANSFERWIDTH = (eBusWidth == AM_HAL_HOST_BUS_WIDTH_4) ? 1 : 0;
1185 }
1186
1187 pHost->eBusWidth = eBusWidth;
1188
1189 return AM_HAL_STATUS_SUCCESS;
1190 }
1191
1192 //*****************************************************************************
1193 //
1194 // SDHC sets the SDIO bus clock speed
1195 //
1196 // This function sets the bus clock speed needed to communiate with the card.
1197 //
1198 //*****************************************************************************
am_hal_sdhc_set_bus_clock(void * pHandle,uint32_t ui32Clock)1199 uint32_t am_hal_sdhc_set_bus_clock(void *pHandle, uint32_t ui32Clock)
1200 {
1201 uint32_t ui32Divider;
1202
1203 SDIO_Type *pSDHC;
1204 am_hal_card_host_t *pHost;
1205 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1206
1207 #ifndef AM_HAL_DISABLE_API_VALIDATION
1208 //
1209 // Check the handle.
1210 //
1211 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1212 {
1213 return AM_HAL_STATUS_INVALID_HANDLE;
1214 }
1215
1216 if ( !pSDHCState->prefix.s.bEnable )
1217 {
1218 return AM_HAL_STATUS_INVALID_OPERATION;
1219 }
1220
1221 #endif // AM_HAL_DISABLE_API_VALIDATION
1222
1223 pSDHC = SDHCn(pSDHCState->ui32Module);
1224 pHost = pSDHCState->pHost;
1225
1226 //
1227 // Find the nearest the clock divider
1228 //
1229 for (ui32Divider = 1; ui32Divider <= 256; ui32Divider *= 2)
1230 {
1231 if ( (pHost->ui32MaxClock / ui32Divider) <= ui32Clock )
1232 {
1233 break;
1234 }
1235 }
1236 ui32Clock = pHost->ui32MaxClock / ui32Divider;
1237
1238 //
1239 // Same clock setting and do nothing
1240 //
1241 if ( pHost->ui32Clock == ui32Clock )
1242 {
1243 return AM_HAL_STATUS_SUCCESS;
1244 }
1245
1246 ui32Divider >>= 1;
1247
1248 //
1249 // Should stop the clock before changing the clock setting
1250 //
1251 pSDHC->CLOCKCTRL &= ~(SDIO_CLOCKCTRL_CLKEN_Msk | SDIO_CLOCKCTRL_SDCLKEN_Msk);
1252
1253 //
1254 // Set the divider
1255 //
1256 pSDHC->CLOCKCTRL_b.FREQSEL = ui32Divider;
1257
1258 //
1259 // Now enable the internal clock
1260 //
1261 pSDHC->CLOCKCTRL_b.CLKEN = 0x1;
1262
1263 //
1264 // Wait util the internal clock to be stablized
1265 //
1266 uint32_t ui32Timeout = 1000;
1267 while ( pSDHC->CLOCKCTRL_b.CLKSTABLE == 0 )
1268 {
1269 if ( ui32Timeout == 0 )
1270 {
1271 AM_HAL_SDHC_DEBUG("Internal clock can not be stablized\n");
1272 return AM_HAL_STATUS_FAIL;
1273 }
1274 ui32Timeout--;
1275 am_util_delay_us(10);
1276 }
1277
1278 //
1279 // Now enable the SDCLK
1280 //
1281 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x1;
1282
1283 pHost->ui32Clock = ui32Clock;
1284
1285 return AM_HAL_STATUS_SUCCESS;
1286 }
1287
1288 //*****************************************************************************
1289 //
1290 // SDHC sets the SDIO UHS Mode
1291 //
1292 // This function sets the bus clock speed needed to communiate with the card.
1293 //
1294 //*****************************************************************************
am_hal_sdhc_set_uhs_mode(void * pHandle,am_hal_host_uhs_mode_e eUHSMode)1295 uint32_t am_hal_sdhc_set_uhs_mode(void *pHandle, am_hal_host_uhs_mode_e eUHSMode)
1296 {
1297 SDIO_Type *pSDHC;
1298 am_hal_card_host_t *pHost;
1299 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1300
1301 #ifndef AM_HAL_DISABLE_API_VALIDATION
1302 //
1303 // Check the handle.
1304 //
1305 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1306 {
1307 return AM_HAL_STATUS_INVALID_HANDLE;
1308 }
1309
1310 if ( !pSDHCState->prefix.s.bEnable )
1311 {
1312 return AM_HAL_STATUS_INVALID_OPERATION;
1313 }
1314 #endif // AM_HAL_DISABLE_API_VALIDATION
1315
1316 pSDHC = SDHCn(pSDHCState->ui32Module);
1317 pHost = pSDHCState->pHost;
1318
1319 if ( pHost->eUHSMode == eUHSMode )
1320 {
1321 return AM_HAL_STATUS_SUCCESS;
1322 }
1323
1324 pSDHC->AUTO_b.UHSMODESEL = eUHSMode - AM_HAL_HOST_UHS_NONE;
1325 pHost->eUHSMode = eUHSMode;
1326
1327 return AM_HAL_STATUS_SUCCESS;
1328 }
1329
1330 //*****************************************************************************
1331 //
1332 // SDHC checks the SDIO bus busy DAT0 line
1333 //
1334 // This function checks if DAT0 line is busy or not.
1335 //
1336 //*****************************************************************************
am_hal_sdhc_card_busy(void * pHandle,uint32_t ui32TimeoutMS)1337 uint32_t am_hal_sdhc_card_busy(void *pHandle, uint32_t ui32TimeoutMS)
1338 {
1339 uint32_t ui32Dat0BusyMask;
1340 SDIO_Type *pSDHC;
1341 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1342
1343 #ifndef AM_HAL_DISABLE_API_VALIDATION
1344 //
1345 // Check the handle.
1346 //
1347 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1348 {
1349 return AM_HAL_STATUS_INVALID_HANDLE;
1350 }
1351
1352 if ( !pSDHCState->prefix.s.bEnable )
1353 {
1354 return AM_HAL_STATUS_INVALID_OPERATION;
1355 }
1356 #endif // AM_HAL_DISABLE_API_VALIDATION
1357
1358 pSDHC = SDHCn(pSDHCState->ui32Module);
1359
1360 ui32Dat0BusyMask = 0x1 << SDIO_PRESENT_DAT30LINE_Pos;
1361
1362 uint32_t ui32Status;
1363 ui32Status = am_hal_delay_us_status_check(
1364 ui32TimeoutMS*1000, (uint32_t)&pSDHC->PRESENT,
1365 ui32Dat0BusyMask,
1366 ui32Dat0BusyMask,
1367 true);
1368
1369 if ( AM_HAL_STATUS_SUCCESS != ui32Status )
1370 {
1371 AM_HAL_SDHC_DEBUG("%s : wait DAT0 busy timeout\n", __FUNCTION__);
1372 }
1373
1374 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1375 //
1376 // Disable the SDCLK
1377 //
1378 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1379 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1380 #endif
1381
1382 return ui32Status;
1383 }
1384
1385 //*****************************************************************************
1386 //
1387 // SDHC Set TxRx Delays
1388 //
1389 //*****************************************************************************
am_hal_sdhc_set_txrx_delay(void * pHandle,uint8_t ui8TxRxDelays[2])1390 void am_hal_sdhc_set_txrx_delay(void *pHandle, uint8_t ui8TxRxDelays[2])
1391 {
1392 // Adjust TX CLK delay
1393 MCUCTRL->SDIOCTRL_b.SDIOITAPCHGWIN = 1;
1394
1395 MCUCTRL->SDIOCTRL_b.SDIOOTAPDLYSEL = ui8TxRxDelays[0];
1396 MCUCTRL->SDIOCTRL_b.SDIOOTAPDLYENA = 1;
1397
1398 // Adjust RX CLK delay
1399 MCUCTRL->SDIOCTRL_b.SDIOITAPDLYSEL = ui8TxRxDelays[1];
1400 MCUCTRL->SDIOCTRL_b.SDIOITAPDLYENA = 1;
1401
1402 MCUCTRL->SDIOCTRL_b.SDIOITAPCHGWIN = 0;
1403 }
1404
1405 //
1406 // SDHC Enable function
1407 //
am_hal_sdhc_enable(void * pHandle)1408 uint32_t am_hal_sdhc_enable(void *pHandle)
1409 {
1410 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1411 SDIO_Type *pSDHC;
1412 uint32_t ui32Status;
1413
1414 #ifndef AM_HAL_DISABLE_API_VALIDATION
1415 //
1416 // Check the handle.
1417 //
1418 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1419 {
1420 return AM_HAL_STATUS_INVALID_HANDLE;
1421 }
1422
1423 if ( pSDHCState->prefix.s.bEnable )
1424 {
1425 return AM_HAL_STATUS_INVALID_OPERATION;
1426 }
1427 #endif // AM_HAL_DISABLE_API_VALIDATION
1428
1429 pSDHC = SDHCn(pSDHCState->ui32Module);
1430
1431 //
1432 // Enable the clock to SDIO peripheral
1433 //
1434 MCUCTRL->SDIOCTRL |= (MCUCTRL_SDIOCTRL_SDIOSYSCLKEN_Msk | MCUCTRL_SDIOCTRL_SDIOXINCLKEN_Msk);
1435
1436 // Wait some time util clock stable
1437 am_util_delay_ms(10);
1438
1439 //
1440 // Note SW_RESET_ALL is *only* used here before initializing other registers
1441 //
1442 if ( (ui32Status = am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_ALL)) != AM_HAL_STATUS_SUCCESS )
1443 {
1444 AM_HAL_SDHC_DEBUG("Software Reset ALL failed\n");
1445 return ui32Status;
1446 }
1447
1448
1449 //
1450 // Enable all interrupts
1451 //
1452 SDHCn(pSDHCState->ui32Module)->INTENABLE = (uint32_t)-1;
1453
1454 //
1455 // Disable all interrupts SIGNAL
1456 //
1457 SDHCn(pSDHCState->ui32Module)->INTSIG = 0x0;
1458
1459 //
1460 // Enable SDIO IRQ only after host is initialized successfully
1461 //
1462 NVIC_SetPriority(SDIO_IRQn, AM_IRQ_PRIORITY_DEFAULT);
1463 NVIC_EnableIRQ(SDIO_IRQn);
1464
1465 //
1466 // Reset CMD and Data error count
1467 //
1468 pSDHCState->bCmdErr = false;
1469 pSDHCState->bDataErr = false;
1470 pSDHCState->ui32DataErrCnt = 0;
1471 pSDHCState->ui32CmdErrCnt = 0;
1472
1473 pSDHCState->prefix.s.bEnable = true;
1474
1475 //
1476 // Return the status.
1477 //
1478 return AM_HAL_STATUS_SUCCESS;
1479 }
1480
1481 //
1482 // SDHC Disable function
1483 //
am_hal_sdhc_disable(void * pHandle)1484 uint32_t am_hal_sdhc_disable(void *pHandle)
1485 {
1486 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1487
1488 #ifndef AM_HAL_DISABLE_API_VALIDATION
1489 //
1490 // Check the handle.
1491 //
1492 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1493 {
1494 return AM_HAL_STATUS_INVALID_HANDLE;
1495 }
1496 #endif // AM_HAL_DISABLE_API_VALIDATION
1497
1498 if ( !pSDHCState->prefix.s.bEnable )
1499 {
1500 return AM_HAL_STATUS_SUCCESS;
1501 }
1502
1503 pSDHCState->prefix.s.bEnable = false;
1504
1505 //
1506 // Disable SDIO IRQ
1507 //
1508 NVIC_DisableIRQ(SDIO_IRQn);
1509
1510 //
1511 // Disable all interrupts SIGNAL
1512 //
1513 SDHCn(pSDHCState->ui32Module)->INTSIG = 0x0;
1514
1515 //
1516 // Disable all interrupts
1517 //
1518 SDHCn(pSDHCState->ui32Module)->INTENABLE = 0x0;
1519
1520 //
1521 // Clear all interrupt status
1522 //
1523 SDHCn(pSDHCState->ui32Module)->INTSTAT = (uint32_t)-1;
1524
1525 //
1526 // Disable the clock to SDIO peripheral
1527 //
1528 MCUCTRL->SDIOCTRL &= ~(MCUCTRL_SDIOCTRL_SDIOSYSCLKEN_Msk | MCUCTRL_SDIOCTRL_SDIOXINCLKEN_Msk);
1529
1530 //
1531 // Wait some time until clock is stable
1532 //
1533 am_util_delay_ms(10);
1534
1535 //
1536 // Return the status.
1537 //
1538 return AM_HAL_STATUS_SUCCESS;
1539 }
1540
1541 //*****************************************************************************
1542 //
1543 // SDHC send command function
1544 //
1545 // This function sends a command to SD/MMC/eMMC/SDIO card and gets the response. if this command
1546 // is using synchronous transfer mode, it will be blocked until the data in the buffer has been
1547 // transmited or received. if this command is using asynchronous transfer mode, it will return immediately
1548 // after sending the command, data transfer completion done event will be notified by registered callback
1549 // function in the ISR.
1550 //
1551 //*****************************************************************************
am_hal_sdhc_execute_cmd(void * pHandle,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)1552 uint32_t am_hal_sdhc_execute_cmd(void *pHandle, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
1553 {
1554 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1555 SDIO_Type *pSDHC = NULL;
1556 uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
1557
1558 #ifndef AM_HAL_DISABLE_API_VALIDATION
1559 //
1560 // Check the handle.
1561 //
1562 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1563 {
1564 return AM_HAL_STATUS_INVALID_HANDLE;
1565 }
1566
1567 if ( !pSDHCState->prefix.s.bEnable )
1568 {
1569 return AM_HAL_STATUS_INVALID_OPERATION;
1570 }
1571 #endif // AM_HAL_DISABLE_API_VALIDATION
1572
1573 pSDHC = SDHCn(pSDHCState->ui32Module);
1574
1575 if ( !pSDHCState->bAsyncCmdIsDone )
1576 {
1577 AM_HAL_SDHC_DEBUG("Return because the previous async command is still ongoing\n");
1578 return AM_HAL_STATUS_IN_USE;
1579 }
1580
1581 //
1582 // Reset the CMD and DATA internal circuit for safe
1583 //
1584 if (pSDHCState->bCmdErr)
1585 {
1586 am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_CMD_LINE);
1587 pSDHCState->bCmdErr = false;
1588 AM_HAL_SDHC_DEBUG("Software reset the Cmd Error\n");
1589 }
1590
1591 if (pSDHCState->bDataErr)
1592 {
1593 am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_DATA_LINE);
1594 pSDHCState->bDataErr = false;
1595 AM_HAL_SDHC_DEBUG("Software reset the Data Error\n");
1596 }
1597
1598 //
1599 // Clear all interrupts's status
1600 //
1601 pSDHC->INTENABLE_b.CARDINTERRUPTSTATUSENABLE = 0x0;
1602 pSDHC->INTSTAT = ((uint32_t)-1);
1603
1604 //
1605 // Disable all interrupts firstly except card insert and removal
1606 //
1607 pSDHC->INTSIG = ( SDIO_INTSIG_CARDINSERTEN_Msk | SDIO_INTSIG_CARDREMOVALEN_Msk | SDIO_INTSIG_CARDINTEN_Msk);
1608
1609 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1610 //
1611 // Enable the SDCLK
1612 //
1613 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x1;
1614 AM_HAL_SDHC_DEBUG("Enable the SDCLK\n");
1615 #endif
1616
1617 if ( (ui32Status = am_hal_sdhc_send_cmd(pSDHCState, pSDHC, pCmd, pCmdData)) != AM_HAL_STATUS_SUCCESS )
1618 {
1619 return ui32Status;
1620 }
1621
1622 if ( (ui32Status = am_hal_sdhc_wait_cmd_done(pSDHCState, pSDHC, pCmd)) != AM_HAL_STATUS_SUCCESS )
1623 {
1624 return ui32Status;
1625 }
1626
1627 am_hal_sdhc_get_cmd_response(pSDHC, pCmd);
1628
1629 if ( pCmd->bASync )
1630 {
1631 AM_CRITICAL_BEGIN
1632 pSDHC->INTSIG = ((uint32_t)-1);
1633 pSDHCState->bAsyncCmdIsDone = false;
1634 AM_CRITICAL_END
1635 }
1636
1637 if ( pCmdData == NULL || pCmd->bASync )
1638 {
1639 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1640 if (pCmdData == NULL && !pCmd->bCheckBusyCmd)
1641 {
1642 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1643 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1644 }
1645 #endif
1646 return AM_HAL_STATUS_SUCCESS;
1647 }
1648
1649 return am_hal_sdhc_xfer_data(pSDHCState, pCmdData);
1650 }
1651
1652 //
1653 // SDHC normal/error status interrupts enable function
1654 //
am_hal_sdhc_intr_status_enable(void * pHandle,uint32_t ui32IntMask)1655 uint32_t am_hal_sdhc_intr_status_enable(void *pHandle, uint32_t ui32IntMask)
1656 {
1657 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1658 uint32_t ui32Module;
1659
1660 #ifndef AM_HAL_DISABLE_API_VALIDATION
1661 //
1662 // Check the handle.
1663 //
1664 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1665 {
1666 return AM_HAL_STATUS_INVALID_HANDLE;
1667 }
1668
1669 if ( !pSDHCState->prefix.s.bEnable )
1670 {
1671 return AM_HAL_STATUS_INVALID_OPERATION;
1672 }
1673 #endif // AM_HAL_DISABLE_API_VALIDATION
1674
1675 ui32Module = pSDHCState->ui32Module;
1676
1677 //
1678 // Set the interrupt enables according to the mask.
1679 //
1680 SDHCn(ui32Module)->INTENABLE |= ui32IntMask;
1681
1682 //
1683 // Return the status.
1684 //
1685 return AM_HAL_STATUS_SUCCESS;
1686 }
1687
1688 //
1689 // SDHC normal/error status interrupts disable function
1690 //
am_hal_sdhc_intr_status_disable(void * pHandle,uint32_t ui32IntMask)1691 uint32_t am_hal_sdhc_intr_status_disable(void *pHandle, uint32_t ui32IntMask)
1692 {
1693 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1694 uint32_t ui32Module;
1695
1696 #ifndef AM_HAL_DISABLE_API_VALIDATION
1697 //
1698 // Check the handle.
1699 //
1700 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1701 {
1702 return AM_HAL_STATUS_INVALID_HANDLE;
1703 }
1704
1705 if ( !pSDHCState->prefix.s.bEnable )
1706 {
1707 return AM_HAL_STATUS_INVALID_OPERATION;
1708 }
1709 #endif // AM_HAL_DISABLE_API_VALIDATION
1710
1711 ui32Module = pSDHCState->ui32Module;
1712 //
1713 // Clear the interrupt enables according to the mask.
1714 //
1715 SDHCn(ui32Module)->INTENABLE &= ~ui32IntMask;
1716
1717 //
1718 // Return the status.
1719 //
1720 return AM_HAL_STATUS_SUCCESS;
1721 }
1722
1723 //
1724 // SDHC normal/error interrupt status get function
1725 //
am_hal_sdhc_intr_status_get(void * pHandle,uint32_t * pui32Status,bool bEnabledOnly)1726 uint32_t am_hal_sdhc_intr_status_get(void *pHandle, uint32_t *pui32Status, bool bEnabledOnly)
1727 {
1728 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1729 uint32_t ui32Module;
1730
1731 #ifndef AM_HAL_DISABLE_API_VALIDATION
1732 //
1733 // Check the handle.
1734 //
1735 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1736 {
1737 return AM_HAL_STATUS_INVALID_HANDLE;
1738 }
1739
1740 if ( !pSDHCState->prefix.s.bEnable )
1741 {
1742 return AM_HAL_STATUS_INVALID_OPERATION;
1743 }
1744 #endif // AM_HAL_DISABLE_API_VALIDATION
1745
1746 ui32Module = pSDHCState->ui32Module;
1747
1748 //
1749 // if requested, only return the interrupts that are enabled.
1750 //
1751 if ( bEnabledOnly )
1752 {
1753 uint32_t ui32RetVal = SDHCn(ui32Module)->INTSTAT;
1754 *pui32Status = ui32RetVal & SDHCn(ui32Module)->INTENABLE;
1755 }
1756 else
1757 {
1758 *pui32Status = SDHCn(ui32Module)->INTSTAT;
1759 }
1760
1761 return AM_HAL_STATUS_SUCCESS;
1762 }
1763
1764 //
1765 // SDHC normal/error interrupt status clear function
1766 //
am_hal_sdhc_intr_status_clear(void * pHandle,uint32_t ui32IntMask)1767 uint32_t am_hal_sdhc_intr_status_clear(void *pHandle, uint32_t ui32IntMask)
1768 {
1769 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1770 uint32_t ui32Module;
1771
1772 #ifndef AM_HAL_DISABLE_API_VALIDATION
1773 //
1774 // Check the handle.
1775 //
1776 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1777 {
1778 return AM_HAL_STATUS_INVALID_HANDLE;
1779 }
1780
1781 if ( !pSDHCState->prefix.s.bEnable )
1782 {
1783 return AM_HAL_STATUS_INVALID_OPERATION;
1784 }
1785 #endif // AM_HAL_DISABLE_API_VALIDATION
1786
1787 ui32Module = pSDHCState->ui32Module;
1788
1789 SDHCn(ui32Module)->INTSTAT = ui32IntMask;
1790
1791 //
1792 // Return the status.
1793 //
1794 return AM_HAL_STATUS_SUCCESS;
1795 }
1796
1797 //
1798 // SDHC normal interrupt signal enable function
1799 //
am_hal_sdhc_intr_signal_enable(void * pHandle,uint32_t ui32IntMask)1800 uint32_t am_hal_sdhc_intr_signal_enable(void *pHandle, uint32_t ui32IntMask)
1801 {
1802 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1803 uint32_t ui32Module;
1804
1805 #ifndef AM_HAL_DISABLE_API_VALIDATION
1806 //
1807 // Check the handle.
1808 //
1809 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1810 {
1811 return AM_HAL_STATUS_INVALID_HANDLE;
1812 }
1813
1814 if ( !pSDHCState->prefix.s.bEnable )
1815 {
1816 return AM_HAL_STATUS_INVALID_OPERATION;
1817 }
1818 #endif // AM_HAL_DISABLE_API_VALIDATION
1819
1820 ui32Module = pSDHCState->ui32Module;
1821
1822 //
1823 // Set the interrupt enables according to the mask.
1824 //
1825 SDHCn(ui32Module)->INTSIG |= ui32IntMask;
1826
1827 //
1828 // Return the status.
1829 //
1830 return AM_HAL_STATUS_SUCCESS;
1831 }
1832
1833 //
1834 // SDHC normal status signal disable function
1835 //
am_hal_sdhc_intr_signal_disable(void * pHandle,uint32_t ui32IntMask)1836 uint32_t am_hal_sdhc_intr_signal_disable(void *pHandle, uint32_t ui32IntMask)
1837 {
1838 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1839 uint32_t ui32Module;
1840
1841 #ifndef AM_HAL_DISABLE_API_VALIDATION
1842 //
1843 // Check the handle.
1844 //
1845 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1846 {
1847 return AM_HAL_STATUS_INVALID_HANDLE;
1848 }
1849
1850 if ( !pSDHCState->prefix.s.bEnable )
1851 {
1852 return AM_HAL_STATUS_INVALID_OPERATION;
1853 }
1854 #endif // AM_HAL_DISABLE_API_VALIDATION
1855
1856 ui32Module = pSDHCState->ui32Module;
1857 //
1858 // Clear the interrupt enables according to the mask.
1859 //
1860 SDHCn(ui32Module)->INTSIG &= ~ui32IntMask;
1861
1862 //
1863 // Return the status.
1864 //
1865 return AM_HAL_STATUS_SUCCESS;
1866 }
1867
1868 //
1869 // SDHC interrupt service routine
1870 //
am_hal_sdhc_interrupt_service(void * pHandle,uint32_t ui32IntStatus)1871 uint32_t am_hal_sdhc_interrupt_service(void *pHandle, uint32_t ui32IntStatus)
1872 {
1873 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1874 am_hal_card_host_t *pHost = pSDHCState->pHost;
1875 SDIO_Type *pSDHC = NULL;
1876 am_hal_host_evt_t evt;
1877
1878 #ifndef AM_HAL_DISABLE_API_VALIDATION
1879 //
1880 // Check the handle.
1881 //
1882 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1883 {
1884 return AM_HAL_STATUS_INVALID_HANDLE;
1885 }
1886
1887 if ( !pSDHCState->prefix.s.bEnable )
1888 {
1889 return AM_HAL_STATUS_INVALID_OPERATION;
1890 }
1891 #endif // AM_HAL_DISABLE_API_VALIDATION
1892
1893 pSDHC = SDHCn(pSDHCState->ui32Module);
1894
1895 //
1896 // Asynchronous PIO write
1897 //
1898 if ( ui32IntStatus & SDIO_INTSTAT_BUFFERREADREADY_Msk ||
1899 ui32IntStatus & SDIO_INTSTAT_BUFFERWRITEREADY_Msk )
1900 {
1901 am_hal_sdhc_pio_xfer_data(pSDHCState);
1902 // AM_HAL_SDHC_DEBUG("%d\n", pSDHCState->ui32BlkCnt);
1903 }
1904
1905 //
1906 // Asynchronous SDMA interrupt
1907 //
1908 if ( ui32IntStatus & SDIO_INTSTAT_DMAINTERRUPT_Msk )
1909 {
1910 // Invalidate DAXI to make sure CPU sees the new data when loaded
1911 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
1912
1913 am_hal_sdhc_sdma_xfer_data(pSDHCState);
1914 // AM_HAL_SDHC_DEBUG("ISR - DMA Xfer BlkCnt %d\n", pSDHCState->ui32BlkCnt);
1915 evt.eType = AM_HAL_EVT_SDMA_DONE;
1916 evt.pCtx = pSDHCState->pHost;
1917 evt.ui32BlkCnt = pSDHCState->ui32BlksPerSDMA;
1918 if ( pSDHCState->pHost->pfunEvtCallback )
1919 {
1920 pSDHCState->pHost->pfunEvtCallback(&evt);
1921 }
1922 }
1923
1924 //
1925 // Asynchronous PIO read, write, SDMA and ADMA xfer completion
1926 //
1927 if ( ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk )
1928 {
1929 // Invalidate DAXI to make sure CPU sees the new data when loaded
1930 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
1931
1932 evt.eType = AM_HAL_EVT_XFER_COMPLETE;
1933 evt.pCtx = pSDHCState->pHost;
1934 evt.ui32BlkCnt = pSDHCState->ui32BlkCnt;
1935 if ( pSDHCState->pHost->pfunEvtCallback )
1936 {
1937 pSDHCState->pHost->pfunEvtCallback(&evt);
1938 }
1939 AM_HAL_SDHC_DEBUG("ISR - Xfer Completion BlkCnt %d\n", pSDHCState->ui32BlkNum);
1940 pSDHCState->bAsyncCmdIsDone = true;
1941
1942 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1943 //
1944 // Disable the SDCLK after the xfer is done
1945 //
1946 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1947 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1948 #endif
1949
1950 }
1951
1952 if (ui32IntStatus & (SDIO_INTSTAT_ADMAERROR_Msk |
1953 SDIO_INTSTAT_DATACRCERROR_Msk |
1954 SDIO_INTSTAT_DATATIMEOUTERROR_Msk |
1955 SDIO_INTSTAT_DATAENDBITERROR_Msk))
1956 {
1957 evt.eType = AM_HAL_EVT_DAT_ERR;
1958 evt.pCtx = pSDHCState->pHost;
1959 evt.ui32BlkCnt = pSDHCState->ui32BlkCnt;
1960 pHost->AsyncCmdData.eDataError = am_hal_sdhc_check_data_error_type(ui32IntStatus);
1961 pSDHCState->bDataErr = true;
1962 pSDHCState->ui32DataErrCnt++;
1963 if ( pSDHCState->pHost->pfunEvtCallback )
1964 {
1965 pSDHCState->pHost->pfunEvtCallback(&evt);
1966 }
1967 AM_HAL_SDHC_DEBUG("Xfer ERR INT 0x%x\n", ui32IntStatus);
1968 pSDHCState->bAsyncCmdIsDone = true;
1969
1970 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1971 //
1972 // Disable the SDCLK after the xfer is done
1973 //
1974 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1975 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1976 #endif
1977
1978 }
1979
1980 //
1981 // SD Card insert or removal interrupt
1982 //
1983 if (ui32IntStatus & ( SDIO_INTSTAT_CARDREMOVAL_Msk |
1984 SDIO_INTSTAT_CARDINSERTION_Msk))
1985 {
1986 uint32_t ui32PresentState = SDHCn(pSDHCState->ui32Module)->PRESENT;
1987
1988 if ( ui32IntStatus & SDIO_INTSTAT_CARDREMOVAL_Msk )
1989 {
1990 evt.eType = AM_HAL_EVT_CARD_NOT_PRESENT;
1991 }
1992
1993 if ( (ui32IntStatus & SDIO_INTSTAT_CARDINSERTION_Msk) && (ui32PresentState & SDIO_PRESENT_CARDINSERTED_Msk) )
1994 {
1995 evt.eType = AM_HAL_EVT_CARD_PRESENT;
1996 }
1997 else
1998 {
1999 evt.eType = AM_HAL_EVT_CARD_NOT_PRESENT;
2000 }
2001
2002 if ( pSDHCState->pHost->pfunEvtCallback )
2003 {
2004 pSDHCState->pHost->pfunEvtCallback(&evt);
2005 }
2006
2007 AM_HAL_SDHC_DEBUG("SD Card INT 0x%x\n", ui32IntStatus);
2008 }
2009
2010 //
2011 // Return the status.
2012 //
2013 return AM_HAL_STATUS_SUCCESS;
2014 }
2015
2016 //*****************************************************************************
2017 //
2018 // End Doxygen group.
2019 //! @}
2020 //
2021 //*****************************************************************************
2022