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 release_sdk_4_4_0-3c5977e664 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 dma_addr_t ui32DmaAddr;
332
333 i = 0;
334 i32BlkCnt = pCmdData->ui32BlkCnt;
335 ui32DmaAddr = (dma_addr_t)(pCmdData->pui8Buf);
336 while (i32BlkCnt > 0)
337 {
338 ui32XferBytes = (i32BlkCnt > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY) ?
339 AM_HAL_ADMA_MAX_BLKS_PER_ENTRY*pCmdData->ui32BlkSize : i32BlkCnt*pCmdData->ui32BlkSize;
340 bEnd = (i32BlkCnt > AM_HAL_ADMA_MAX_BLKS_PER_ENTRY) ? false : true;
341 am_hal_sdhc_prepare_sdhci_adma_desc(i, ui32DmaAddr, ui32XferBytes, bEnd);
342 i++;
343 ui32DmaAddr += ui32XferBytes;
344 i32BlkCnt -= AM_HAL_ADMA_MAX_BLKS_PER_ENTRY;
345 }
346 }
347
348 //
349 // Prepare transfer mode register and set the block size, block count, SDMA and host control registers (for DMA)
350 //
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)351 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)
352 {
353 uint32_t ui32ModeReg = 0;
354 uint32_t ui32BlkReg = 0;
355
356 if ( pCmdData != NULL )
357 {
358 pSDHCState->pui32Buf = (uint32_t *)(pCmdData->pui8Buf);
359 pSDHCState->ui32DataLen = pCmdData->ui32BlkCnt * pCmdData->ui32BlkSize;
360 pSDHCState->eDataDir = pCmdData->dir;
361 pSDHCState->ui32BlkSize = pCmdData->ui32BlkSize;
362 pSDHCState->ui32BlkCnt = pCmdData->ui32BlkCnt;
363 pSDHCState->ui32BlkNum = pCmdData->ui32BlkCnt;
364
365 //
366 // Transfer direction - 0x1 Read
367 //
368 if ( pCmdData->dir == AM_HAL_DATA_DIR_READ )
369 {
370 ui32ModeReg |= SDIO_TRANSFER_DXFERDIRSEL_Msk;
371 }
372
373 //
374 // Transfer DMA setting
375 //
376 if ( pCmdData->eXferMode == AM_HAL_HOST_XFER_DEFAULT )
377 {
378 pCmdData->eXferMode = pSDHCState->pHost->eXferMode;
379 }
380
381 switch (pCmdData->eXferMode)
382 {
383 case AM_HAL_HOST_XFER_SDMA:
384 ui32ModeReg |= SDIO_TRANSFER_DMAEN_Msk;
385 pSDHC->HOSTCTRL1_b.DMASELECT = SDIO_HOSTCTRL1_DMASELECT_SDMA;
386 pSDHC->SDMA = (dma_addr_t)(pCmdData->pui8Buf);
387 pSDHCState->ui32BlksPerSDMA = pSDHCState->ui32HostSDMABufSize / pCmdData->ui32BlkSize;
388 break;
389 case AM_HAL_HOST_XFER_ADMA:
390 ui32ModeReg |= SDIO_TRANSFER_DMAEN_Msk;
391 pSDHC->HOSTCTRL1_b.DMASELECT = SDIO_HOSTCTRL1_DMASELECT_ADMA232;
392 am_hal_sdhc_prepare_adma_table(pCmdData);
393 pSDHC->ADMALOWD = (dma_addr_t)(&adma_desc_table[0]);
394 break;
395 default:
396 break;
397 }
398
399 //
400 // Auto Command setting
401 //
402 if ( pCmd->bAutoCMD12 )
403 {
404 ui32ModeReg |= SDIO_TRANSFER_ACMDEN_CMD12ENABLE << SDIO_TRANSFER_ACMDEN_Pos;
405 }
406 else if ( pCmd->bAutoCMD23 )
407 {
408 ui32ModeReg |= SDIO_TRANSFER_ACMDEN_CMD23ENABLE << SDIO_TRANSFER_ACMDEN_Pos;
409
410 #ifdef AM_DEBUG_PRINTF
411 if (pCmdData->eXferMode == AM_HAL_HOST_XFER_SDMA)
412 {
413 AM_HAL_SDHC_DEBUG("SDMA can't be used if enabling CMD23\n");
414 }
415 #endif
416
417 pSDHC->SDMA = pCmdData->ui32BlkCnt;
418 }
419
420 //
421 // Set the block count and size
422 //
423 ui32BlkReg |= pCmdData->ui32BlkSize << SDIO_BLOCK_TRANSFERBLOCKSIZE_Pos;
424 if ( pCmdData->ui32BlkCnt > 1 )
425 {
426 ui32ModeReg |= SDIO_TRANSFER_BLKSEL_Msk | SDIO_TRANSFER_BLKCNTEN_Msk;
427 ui32BlkReg |= pCmdData->ui32BlkCnt << SDIO_BLOCK_BLKCNT_Pos;
428 }
429
430 pSDHC->BLOCK |= ui32BlkReg;
431
432 //
433 // Set the data timeout
434 //
435 pSDHC->CLOCKCTRL |= (0xe << SDIO_CLOCKCTRL_TIMEOUTCNT_Pos);
436 }
437
438 return ui32ModeReg;
439 }
440
441 //
442 // Get the command response after sending out the command
443 //
am_hal_sdhc_get_cmd_response(SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd)444 static void am_hal_sdhc_get_cmd_response(SDIO_Type *pSDHC, am_hal_card_cmd_t *pCmd)
445 {
446 uint32_t ui32RegResp[4];
447
448 pCmd->eError = AM_HAL_CMD_ERR_NONE;
449 if ( pCmd->ui32RespType == MMC_RSP_NONE )
450 {
451 return;
452 }
453
454 if ( pCmd->ui32RespType & MMC_RSP_136 )
455 {
456 ui32RegResp[0] = pSDHC->RESPONSE0;
457 ui32RegResp[1] = pSDHC->RESPONSE1;
458 ui32RegResp[2] = pSDHC->RESPONSE2;
459 ui32RegResp[3] = pSDHC->RESPONSE3;
460 pCmd->ui32Resp[0] = (ui32RegResp[3] << 8) | (ui32RegResp[2] >> 24);
461 pCmd->ui32Resp[1] = (ui32RegResp[2] << 8) | (ui32RegResp[1] >> 24);
462 pCmd->ui32Resp[2] = (ui32RegResp[1] << 8) | (ui32RegResp[0] >> 24);
463 pCmd->ui32Resp[3] = (ui32RegResp[0] << 8);
464 }
465 else
466 {
467 pCmd->ui32Resp[0] = pSDHC->RESPONSE0;
468 }
469 }
470
471 //
472 // Sending the command by writing the argument and command registers
473 //
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)474 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)
475 {
476 uint32_t ui32CmdReg;
477
478 if ( am_hal_sdhc_check_cmd_inhibit(pSDHC, pCmd, pCmdData) == AM_HAL_STATUS_TIMEOUT )
479 {
480 pCmd->eError = AM_HAL_CMD_ERR_INHIBIT;
481 pSDHCState->bCmdErr = true;
482 pSDHCState->ui32CmdErrCnt++;
483 return AM_HAL_STATUS_TIMEOUT;
484 }
485
486 //
487 // Prepare the command register value
488 //
489 ui32CmdReg = am_hal_sdhc_prepare_cmd(pSDHC, pCmd, pCmdData);
490
491 //
492 // Prepare the transfer mode register value
493 //
494 ui32CmdReg |= am_hal_sdhc_prepare_xfer(pSDHCState, pSDHC, pCmd, pCmdData);
495
496 //
497 // Eliminate the DAXI side effects
498 //
499 am_hal_sysctrl_bus_write_flush();
500
501 //
502 // Write the argument and command register
503 //
504 pSDHC->ARGUMENT1 = pCmd->ui32Arg;
505 pSDHC->TRANSFER = ui32CmdReg;
506
507 return AM_HAL_STATUS_SUCCESS;
508
509 }
510
am_hal_sdhc_check_cmd_error_type(uint32_t ui32IntStatus)511 static inline am_hal_card_cmd_err_e am_hal_sdhc_check_cmd_error_type(uint32_t ui32IntStatus)
512 {
513 if (ui32IntStatus & SDIO_INTSTAT_COMMANDINDEXERROR_Msk)
514 {
515 return AM_HAL_CMD_ERR_INDEX;
516 }
517 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDENDBITERROR_Msk)
518 {
519 return AM_HAL_CMD_ERR_ENDBIT;
520 }
521 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDCRCERROR_Msk)
522 {
523 return AM_HAL_CMD_ERR_CRC;
524 }
525 else if (ui32IntStatus & SDIO_INTSTAT_COMMANDTIMEOUTERROR_Msk)
526 {
527 return AM_HAL_CMD_ERR_NO_RESPONSE;
528 }
529 else
530 {
531 return AM_HAL_CMD_ERR_TIMEOUT;
532 }
533 }
534
535 //
536 // Wait the command done by checking command completion interrupt status
537 //
538 #define AM_HAL_WAIT_CMD_DONE_TIMEOUT 2
539
am_hal_sdhc_wait_cmd_done(am_hal_sdhc_state_t * pSDHCState,SDIO_Type * pSDHC,am_hal_card_cmd_t * pCmd)540 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)
541 {
542 uint32_t ui32Status;
543 uint32_t ui32IntStatus;
544 uint32_t ui32BitMask = SDIO_INTSTAT_COMMANDCOMPLETE_Msk;
545
546 ui32Status = am_hal_delay_us_status_check(
547 AM_HAL_WAIT_CMD_DONE_TIMEOUT*1000, (uint32_t)&pSDHC->INTSTAT,
548 ui32BitMask,
549 ui32BitMask,
550 true);
551
552 if ( AM_HAL_STATUS_SUCCESS != ui32Status )
553 {
554 ui32IntStatus = pSDHC->INTSTAT;
555 pCmd->eError = am_hal_sdhc_check_cmd_error_type(ui32IntStatus);
556 pSDHCState->bCmdErr = true;
557 pSDHCState->ui32CmdErrCnt++;
558 AM_HAL_SDHC_DEBUG("wait CMD completion INT timeout, Error Type : %d\n", pCmd->eError);
559 return AM_HAL_STATUS_TIMEOUT;
560 }
561
562 pSDHC->INTSTAT = ui32BitMask;
563
564 return AM_HAL_STATUS_SUCCESS;
565 }
566
567 //
568 // Do the PIO block transfer
569 //
am_hal_sdhc_pio_xfer_data(am_hal_sdhc_state_t * pSDHCState)570 static void am_hal_sdhc_pio_xfer_data(am_hal_sdhc_state_t *pSDHCState)
571 {
572 uint32_t ui32PreBufReadyMask;
573
574 ui32PreBufReadyMask = pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ ?
575 SDIO_PRESENT_BUFRDEN_Msk : SDIO_PRESENT_BUFWREN_Msk;
576
577 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
578
579 while (pSDHC->PRESENT & ui32PreBufReadyMask)
580 {
581 if ( pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ )
582 {
583 for (int i = 0; i < pSDHCState->ui32BlkSize; i += 4)
584 {
585 *pSDHCState->pui32Buf++ = pSDHC->BUFFER;
586 }
587 }
588 else
589 {
590 for (int i = 0; i < pSDHCState->ui32BlkSize; i += 4)
591 {
592 pSDHC->BUFFER = *pSDHCState->pui32Buf++;
593 }
594 }
595 pSDHCState->ui32BlkCnt--;
596 }
597 }
598
599 //
600 // Do the SDMA block transfer
601 //
am_hal_sdhc_sdma_xfer_data(am_hal_sdhc_state_t * pSDHCState)602 static void am_hal_sdhc_sdma_xfer_data(am_hal_sdhc_state_t *pSDHCState)
603 {
604 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
605
606 //
607 // Load the next DMA address
608 //
609 pSDHCState->ui32BlkCnt -= pSDHCState->ui32BlksPerSDMA;
610 pSDHCState->pui32Buf += pSDHCState->ui32HostSDMABufSize / sizeof(uint32_t);
611 pSDHC->SDMA = (dma_addr_t)(pSDHCState->pui32Buf);
612 }
613
am_hal_sdhc_check_data_error_type(uint32_t ui32IntStatus)614 static inline am_hal_card_data_err_e am_hal_sdhc_check_data_error_type(uint32_t ui32IntStatus)
615 {
616 if (ui32IntStatus & SDIO_INTSTAT_ADMAERROR_Msk)
617 {
618 return AM_HAL_DATA_ERR_ADMAERROR;
619 }
620 else if (ui32IntStatus & SDIO_INTSTAT_DATACRCERROR_Msk)
621 {
622 return AM_HAL_DATA_ERR_DATACRCERROR;
623 }
624 else if (ui32IntStatus & SDIO_INTSTAT_DATATIMEOUTERROR_Msk)
625 {
626 return AM_HAL_DATA_ERR_DATATIMEOUTERROR;
627 }
628 else if (ui32IntStatus & SDIO_INTSTAT_DATAENDBITERROR_Msk)
629 {
630 return AM_HAL_DATA_ERR_DATAENDBITERROR;
631 }
632 else
633 {
634 return AM_HAL_DATA_ERR_TIMEOUT;
635 }
636 }
637
638 #define DYNAMIC_SWITCH_SDCLK_FEATURE
639
640 //
641 // Transfer the block data to the card
642 //
am_hal_sdhc_xfer_data(am_hal_sdhc_state_t * pSDHCState,am_hal_card_cmd_data_t * pCmdData)643 static uint32_t am_hal_sdhc_xfer_data(am_hal_sdhc_state_t *pSDHCState,
644 am_hal_card_cmd_data_t *pCmdData)
645 {
646 bool bXferDone;
647 uint32_t ui32BufReadyMask;
648 uint32_t ui32IntStatus;
649
650 SDIO_Type *pSDHC = SDHCn(pSDHCState->ui32Module);
651
652 #ifdef AM_DEBUG_PRINTF
653 am_hal_card_host_t *pHost = pSDHCState->pHost;
654 #endif
655
656 // Xfer timeout value depends on the card performance. 8000 is an empirical value.
657 uint32_t ui32Timeout = 8000*pCmdData->ui32BlkCnt;
658
659 AM_HAL_SDHC_DEBUG("Xfer Timeout is %d\n", ui32Timeout);
660 AM_HAL_SDHC_DEBUG("Xfer BLK Cnt is %d\n", pSDHCState->ui32BlkCnt);
661 AM_HAL_SDHC_DEBUG("Xfer DataLen is %d\n", pSDHCState->ui32DataLen);
662 AM_HAL_SDHC_DEBUG("Xfer Mode is %d\n", pHost->eXferMode);
663 AM_HAL_SDHC_DEBUG("Xfer speed is %d\n", pHost->ui32Clock);
664 AM_HAL_SDHC_DEBUG("Xfer Width is %d\n", pHost->eBusWidth);
665
666 ui32BufReadyMask = pSDHCState->eDataDir == AM_HAL_DATA_DIR_READ ?
667 SDIO_INTSTAT_BUFFERREADREADY_Msk : SDIO_INTSTAT_BUFFERWRITEREADY_Msk;
668
669 bXferDone = false;
670 ui32IntStatus = 0;
671 while ( !(ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk) && (ui32Timeout > 0) )
672 {
673 ui32IntStatus = pSDHC->INTSTAT;
674
675 if ( ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk )
676 {
677 // Invalidate DAXI to make sure CPU sees the new data when loaded
678 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
679
680 //
681 // Transfer completed
682 //
683 pSDHC->INTSTAT = SDIO_INTSTAT_TRANSFERCOMPLETE_Msk;
684 pSDHCState->ui32BlkCnt = 0;
685 bXferDone = true;
686 AM_HAL_SDHC_DEBUG("Xfer Completed\n");
687 }
688 else if ( ui32IntStatus & SDIO_INTSTAT_DMAINTERRUPT_Msk )
689 {
690 // Invalidate DAXI to make sure CPU sees the new data when loaded
691 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
692
693 //
694 // Transfer SDMA data
695 //
696 pSDHC->INTSTAT = SDIO_INTSTAT_DMAINTERRUPT_Msk;
697 AM_HAL_SDHC_DEBUG("Xfer SDMA DMA INTR\n");
698 am_hal_sdhc_sdma_xfer_data(pSDHCState);
699 }
700 else if ( ui32IntStatus & ui32BufReadyMask )
701 {
702 //
703 // Transfer PIO data if PIO buffer is ready
704 //
705 pSDHC->INTSTAT = ui32BufReadyMask;
706 AM_HAL_SDHC_DEBUG("Xfer PIO\n");
707 am_hal_sdhc_pio_xfer_data(pSDHCState);
708 }
709 else if (ui32IntStatus & (SDIO_INTSTAT_ADMAERROR_Msk |
710 SDIO_INTSTAT_DATACRCERROR_Msk |
711 SDIO_INTSTAT_DATATIMEOUTERROR_Msk |
712 SDIO_INTSTAT_DATAENDBITERROR_Msk))
713 {
714 pSDHC->INTSTAT = ui32IntStatus;
715 AM_HAL_SDHC_DEBUG("Xfer Data Error - 0x%x\n", ui32IntStatus);
716 pCmdData->eDataError = am_hal_sdhc_check_data_error_type(ui32IntStatus);
717 pSDHCState->bDataErr = true;
718 pSDHCState->ui32DataErrCnt++;
719 ui32Timeout = 1;
720 }
721
722 if ( ui32Timeout-- > 0 )
723 {
724 am_util_delay_us(5);
725 }
726 // AM_HAL_SDHC_DEBUG("INT STATUS 0x%x\n", ui32IntStatus);
727 }
728
729 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
730
731 //
732 // Disable the SDCLK after the xfer is done
733 //
734 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
735 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
736 #endif
737
738 if ( !bXferDone && ui32Timeout == 0 )
739 {
740 return (pSDHCState->ui32BlkNum - pSDHCState->ui32BlkCnt) << 16 | AM_HAL_STATUS_TIMEOUT;
741 }
742 else
743 {
744 return (pSDHCState->ui32BlkNum - pSDHCState->ui32BlkCnt) << 16 | AM_HAL_STATUS_SUCCESS;
745 }
746 }
747
748 //*****************************************************************************
749 //
750 // External Functions.
751 //
752 //*****************************************************************************
753
754 //*****************************************************************************
755 //
756 // SDHC initialization function
757 //
758 //*****************************************************************************
am_hal_sdhc_initialize(uint32_t ui32Module,void ** ppHandle)759 uint32_t am_hal_sdhc_initialize(uint32_t ui32Module, void **ppHandle)
760 {
761
762 #ifndef AM_HAL_DISABLE_API_VALIDATION
763 //
764 // Check that the request module is in range.
765 //
766 if ( ui32Module >= AM_REG_SDIO_NUM_MODULES )
767 {
768 return AM_HAL_STATUS_OUT_OF_RANGE;
769 }
770
771 //
772 // Check for valid arguements.
773 //
774 if ( !ppHandle )
775 {
776 return AM_HAL_STATUS_INVALID_ARG;
777 }
778
779 //
780 // Check if the handle is unallocated.
781 //
782 if ( g_SDHCState[ui32Module].prefix.s.bInit )
783 {
784 return AM_HAL_STATUS_INVALID_OPERATION;
785 }
786 #endif // AM_HAL_DISABLE_API_VALIDATION
787
788 //
789 // Initialize the handle.
790 //
791 g_SDHCState[ui32Module].prefix.s.bInit = true;
792 g_SDHCState[ui32Module].prefix.s.magic = AM_HAL_MAGIC_SDHC;
793 g_SDHCState[ui32Module].ui32Module = ui32Module;
794
795 //
796 // Return the handle.
797 //
798 *ppHandle = (void *)&g_SDHCState[ui32Module];
799
800 //
801 // Return the status.
802 //
803 return AM_HAL_STATUS_SUCCESS;
804 }
805
806 //*****************************************************************************
807 //
808 // SDHC Deinitialize function
809 //
810 //*****************************************************************************
am_hal_sdhc_deinitialize(void * pHandle)811 uint32_t am_hal_sdhc_deinitialize(void *pHandle)
812 {
813 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
814
815 #ifndef AM_HAL_DISABLE_API_VALIDATION
816 //
817 // Check the handle.
818 //
819 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
820 {
821 return AM_HAL_STATUS_INVALID_HANDLE;
822 }
823 #endif // AM_HAL_DISABLE_API_VALIDATION
824
825 //
826 // Reset the handle.
827 //
828 pSDHCState->prefix.s.bInit = false;
829 pSDHCState->ui32Module = 0;
830
831 //
832 // Return the status.
833 //
834 return AM_HAL_STATUS_SUCCESS;
835 }
836
837 //*****************************************************************************
838 //
839 // SDHC power control function
840 //
841 // This function updates the peripheral to a given power state.
842 //
843 //*****************************************************************************
am_hal_sdhc_power_control(void * pHandle,am_hal_sysctrl_power_state_e ePowerState,bool bRetainState)844 uint32_t am_hal_sdhc_power_control(void *pHandle, am_hal_sysctrl_power_state_e ePowerState, bool bRetainState)
845 {
846 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
847
848 #ifndef AM_HAL_DISABLE_API_VALIDATION
849 //
850 // Check the handle.
851 //
852 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
853 {
854 return AM_HAL_STATUS_INVALID_HANDLE;
855 }
856
857 #endif // AM_HAL_DISABLE_API_VALIDATION
858
859 //
860 // Decode the requested power state and update SDHC operation accordingly.
861 //
862 switch (ePowerState)
863 {
864 case AM_HAL_SYSCTRL_WAKE:
865
866 if ( bRetainState && !pSDHCState->registerState.bValid )
867 {
868 return AM_HAL_STATUS_INVALID_OPERATION;
869 }
870
871 //
872 // Enable power control.
873 //
874 am_hal_pwrctrl_periph_enable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_SDIO + pSDHCState->ui32Module));
875
876
877 if ( bRetainState )
878 {
879 //
880 // Restore SDHC registers
881 //
882 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 = pSDHCState->registerState.regHOSTCTRL1;
883 SDHCn(pSDHCState->ui32Module)->CLOCKCTRL = pSDHCState->registerState.regCLOCKCTRL;
884 SDHCn(pSDHCState->ui32Module)->INTENABLE = pSDHCState->registerState.regINTENABLE;
885 SDHCn(pSDHCState->ui32Module)->INTSIG = pSDHCState->registerState.regINTSIG;
886 SDHCn(pSDHCState->ui32Module)->AUTO = pSDHCState->registerState.regAUTO;
887 pSDHCState->registerState.bValid = false;
888 }
889 break;
890
891 case AM_HAL_SYSCTRL_NORMALSLEEP:
892 case AM_HAL_SYSCTRL_DEEPSLEEP:
893 if ( bRetainState )
894 {
895 //
896 // Save SDHC Registers
897 //
898 pSDHCState->registerState.regHOSTCTRL1 = SDHCn(pSDHCState->ui32Module)->HOSTCTRL1;
899 pSDHCState->registerState.regCLOCKCTRL = SDHCn(pSDHCState->ui32Module)->CLOCKCTRL;
900 pSDHCState->registerState.regINTENABLE = SDHCn(pSDHCState->ui32Module)->INTENABLE;
901 pSDHCState->registerState.regINTSIG = SDHCn(pSDHCState->ui32Module)->INTSIG;
902 pSDHCState->registerState.regAUTO = SDHCn(pSDHCState->ui32Module)->AUTO;
903 pSDHCState->registerState.bValid = true;
904 }
905
906 //
907 // Disable all the interrupts.
908 am_hal_sdhc_intr_status_disable(pHandle, 0xFFFFFFFF);
909
910
911 //
912 // Disable power control.
913 //
914 am_hal_pwrctrl_periph_disable((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_SDIO + pSDHCState->ui32Module));
915 break;
916
917 default:
918 return AM_HAL_STATUS_INVALID_ARG;
919 }
920
921 //
922 // Return the status.
923 //
924 return AM_HAL_STATUS_SUCCESS;
925 }
926
927 //*****************************************************************************
928 //
929 // SDHC setup card host function
930 //
931 // This function updates pHost related settings by checking the capabilites of underlying
932 // SDHC host controller. These settings are important for validate the arguments to the card
933 // block read, write, erase, speed, bus width.
934 //
935 //*****************************************************************************
am_hal_sdhc_setup_host(void * pHandle,am_hal_card_host_t * pHost)936 uint32_t am_hal_sdhc_setup_host(void *pHandle, am_hal_card_host_t *pHost)
937 {
938 SDIO_Type *pSDHC;
939 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
940
941 #ifndef AM_HAL_DISABLE_API_VALIDATION
942 //
943 // Check the handle.
944 //
945 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
946 {
947 return AM_HAL_STATUS_INVALID_HANDLE;
948 }
949
950 if ( !pSDHCState->prefix.s.bEnable )
951 {
952 return AM_HAL_STATUS_INVALID_OPERATION;
953 }
954
955 #endif // AM_HAL_DISABLE_API_VALIDATION
956
957 //
958 // Link to the card host
959 //
960 pSDHCState->pHost = pHost;
961
962 pSDHC = SDHCn(pSDHCState->ui32Module);
963
964 pSDHCState->ui8BaseClockFreq = pSDHC->CAPABILITIES0_b.SDCLKFREQ;
965
966 pHost->ui8Version = pSDHC->SLOTSTAT_b.SPECVER;
967 pHost->ui32MaxClock = pSDHCState->ui8BaseClockFreq * 1000000;
968 pHost->ui32MinClock = pHost->ui32MaxClock / 256;
969 pHost->ui32Clock = 0x0;
970
971 //
972 // Default transfer mode is ADMA
973 //
974 pHost->eXferMode = AM_HAL_HOST_XFER_ADMA;
975 pHost->eBusWidth = AM_HAL_HOST_BUS_WIDTH_1;
976 pHost->eUHSMode = AM_HAL_HOST_UHS_NONE;
977
978
979 pHost->ui32MaxADMA2BlkNums = AM_HAL_ADMA_TABLE_NO_ENTRIES*AM_HAL_ADMA_MAX_BLKS_PER_ENTRY;
980
981 //
982 // Default 4K SDMA boundary size
983 //
984 pSDHCState->ui32HostSDMABufSize = 4096*(0x1 << pSDHC->BLOCK_b.HOSTSDMABUFSZ);
985 pSDHCState->bAsyncCmdIsDone = true;
986
987 return AM_HAL_STATUS_SUCCESS;
988 }
989
990 //*****************************************************************************
991 //
992 // SDHC detects the card function
993 //
994 // This function detects the present of card in the slot.
995 //
996 //*****************************************************************************
am_hal_sdhc_get_cd(void * pHandle)997 bool am_hal_sdhc_get_cd(void *pHandle)
998 {
999 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1000
1001 #ifndef AM_HAL_DISABLE_API_VALIDATION
1002 //
1003 // Check the handle.
1004 //
1005 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1006 {
1007 return AM_HAL_STATUS_INVALID_HANDLE;
1008 }
1009
1010 if ( !pSDHCState->prefix.s.bEnable )
1011 {
1012 return AM_HAL_STATUS_INVALID_OPERATION;
1013 }
1014 #endif // AM_HAL_DISABLE_API_VALIDATION
1015
1016 return SDHCn(pSDHCState->ui32Module)->PRESENT_b.CARDINSERTED;
1017 }
1018
1019 //*****************************************************************************
1020 //
1021 // SDHC sets the SDIO bus IO volage
1022 //
1023 // This function sets the bus voltage needed to communiate with the card.
1024 //
1025 //*****************************************************************************
am_hal_sdhc_set_bus_voltage(void * pHandle,am_hal_host_bus_voltage_e eBusVoltage)1026 uint32_t am_hal_sdhc_set_bus_voltage(void *pHandle, am_hal_host_bus_voltage_e eBusVoltage)
1027 {
1028 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1029 am_hal_card_host_t *pHost;
1030
1031 #ifndef AM_HAL_DISABLE_API_VALIDATION
1032 //
1033 // Check the handle.
1034 //
1035 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1036 {
1037 return AM_HAL_STATUS_INVALID_HANDLE;
1038 }
1039
1040 if ( !pSDHCState->prefix.s.bEnable )
1041 {
1042 return AM_HAL_STATUS_INVALID_OPERATION;
1043 }
1044
1045 #endif // AM_HAL_DISABLE_API_VALIDATION
1046
1047 pHost = pSDHCState->pHost;
1048
1049 switch (eBusVoltage)
1050 {
1051 case AM_HAL_HOST_BUS_VOLTAGE_1_8:
1052 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_1_8V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1053 break;
1054 case AM_HAL_HOST_BUS_VOLTAGE_3_0:
1055 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_3_0V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1056 break;
1057 case AM_HAL_HOST_BUS_VOLTAGE_3_3:
1058 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_VOLTSELECT_3_3V << SDIO_HOSTCTRL1_VOLTSELECT_Pos;
1059 break;
1060 }
1061 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1 |= SDIO_HOSTCTRL1_SDBUSPOWER_Msk;
1062
1063 pHost->eBusVoltage = eBusVoltage;
1064
1065 return AM_HAL_STATUS_SUCCESS;
1066 }
1067
1068 //*****************************************************************************
1069 //
1070 // SDHC sets the SDIO bus width
1071 //
1072 // This function sets the bus width needed to communiate with the card.
1073 //
1074 //*****************************************************************************
am_hal_sdhc_set_bus_width(void * pHandle,am_hal_host_bus_width_e eBusWidth)1075 uint32_t am_hal_sdhc_set_bus_width(void *pHandle, am_hal_host_bus_width_e eBusWidth)
1076 {
1077 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1078 am_hal_card_host_t *pHost;
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
1094 #endif // AM_HAL_DISABLE_API_VALIDATION
1095
1096 pHost = pSDHCState->pHost;
1097
1098 if ( eBusWidth == AM_HAL_HOST_BUS_WIDTH_8 )
1099 {
1100 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.XFERWIDTH = 0x1;
1101 }
1102 else
1103 {
1104 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.XFERWIDTH = 0x0;
1105 SDHCn(pSDHCState->ui32Module)->HOSTCTRL1_b.DATATRANSFERWIDTH = (eBusWidth == AM_HAL_HOST_BUS_WIDTH_4) ? 1 : 0;
1106 }
1107
1108 pHost->eBusWidth = eBusWidth;
1109
1110 return AM_HAL_STATUS_SUCCESS;
1111 }
1112
1113 //*****************************************************************************
1114 //
1115 // SDHC sets the SDIO bus clock speed
1116 //
1117 // This function sets the bus clock speed needed to communiate with the card.
1118 //
1119 //*****************************************************************************
am_hal_sdhc_set_bus_clock(void * pHandle,uint32_t ui32Clock)1120 uint32_t am_hal_sdhc_set_bus_clock(void *pHandle, uint32_t ui32Clock)
1121 {
1122 uint32_t ui32Divider;
1123
1124 SDIO_Type *pSDHC;
1125 am_hal_card_host_t *pHost;
1126 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1127
1128 #ifndef AM_HAL_DISABLE_API_VALIDATION
1129 //
1130 // Check the handle.
1131 //
1132 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1133 {
1134 return AM_HAL_STATUS_INVALID_HANDLE;
1135 }
1136
1137 if ( !pSDHCState->prefix.s.bEnable )
1138 {
1139 return AM_HAL_STATUS_INVALID_OPERATION;
1140 }
1141
1142 #endif // AM_HAL_DISABLE_API_VALIDATION
1143
1144 pSDHC = SDHCn(pSDHCState->ui32Module);
1145 pHost = pSDHCState->pHost;
1146
1147 //
1148 // Find the nearest the clock divider
1149 //
1150 for (ui32Divider = 1; ui32Divider <= 256; ui32Divider *= 2)
1151 {
1152 if ( (pHost->ui32MaxClock / ui32Divider) <= ui32Clock )
1153 {
1154 break;
1155 }
1156 }
1157 ui32Clock = pHost->ui32MaxClock / ui32Divider;
1158
1159 //
1160 // Same clock setting and do nothing
1161 //
1162 if ( pHost->ui32Clock == ui32Clock )
1163 {
1164 return AM_HAL_STATUS_SUCCESS;
1165 }
1166
1167 ui32Divider >>= 1;
1168
1169 //
1170 // Should stop the clock before changing the clock setting
1171 //
1172 pSDHC->CLOCKCTRL &= ~(SDIO_CLOCKCTRL_CLKEN_Msk | SDIO_CLOCKCTRL_SDCLKEN_Msk);
1173
1174 //
1175 // Set the divider
1176 //
1177 pSDHC->CLOCKCTRL_b.FREQSEL = ui32Divider;
1178
1179 //
1180 // Now enable the internal clock
1181 //
1182 pSDHC->CLOCKCTRL_b.CLKEN = 0x1;
1183
1184 //
1185 // Wait util the internal clock to be stablized
1186 //
1187 uint32_t ui32Timeout = 1000;
1188 while ( pSDHC->CLOCKCTRL_b.CLKSTABLE == 0 )
1189 {
1190 if ( ui32Timeout == 0 )
1191 {
1192 AM_HAL_SDHC_DEBUG("Internal clock can not be stablized\n");
1193 return AM_HAL_STATUS_FAIL;
1194 }
1195 ui32Timeout--;
1196 am_util_delay_us(10);
1197 }
1198
1199 //
1200 // Now enable the SDCLK
1201 //
1202 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x1;
1203
1204 pHost->ui32Clock = ui32Clock;
1205
1206 return AM_HAL_STATUS_SUCCESS;
1207 }
1208
1209 //*****************************************************************************
1210 //
1211 // SDHC sets the SDIO UHS Mode
1212 //
1213 // This function sets the bus clock speed needed to communiate with the card.
1214 //
1215 //*****************************************************************************
am_hal_sdhc_set_uhs_mode(void * pHandle,am_hal_host_uhs_mode_e eUHSMode)1216 uint32_t am_hal_sdhc_set_uhs_mode(void *pHandle, am_hal_host_uhs_mode_e eUHSMode)
1217 {
1218 SDIO_Type *pSDHC;
1219 am_hal_card_host_t *pHost;
1220 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1221
1222 #ifndef AM_HAL_DISABLE_API_VALIDATION
1223 //
1224 // Check the handle.
1225 //
1226 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1227 {
1228 return AM_HAL_STATUS_INVALID_HANDLE;
1229 }
1230
1231 if ( !pSDHCState->prefix.s.bEnable )
1232 {
1233 return AM_HAL_STATUS_INVALID_OPERATION;
1234 }
1235 #endif // AM_HAL_DISABLE_API_VALIDATION
1236
1237 pSDHC = SDHCn(pSDHCState->ui32Module);
1238 pHost = pSDHCState->pHost;
1239
1240 if ( pHost->eUHSMode == eUHSMode )
1241 {
1242 return AM_HAL_STATUS_SUCCESS;
1243 }
1244
1245 pSDHC->AUTO_b.UHSMODESEL = eUHSMode - AM_HAL_HOST_UHS_NONE;
1246 pHost->eUHSMode = eUHSMode;
1247
1248 return AM_HAL_STATUS_SUCCESS;
1249 }
1250
1251 //*****************************************************************************
1252 //
1253 // SDHC checks the SDIO bus busy DAT0 line
1254 //
1255 // This function checks if DAT0 line is busy or not.
1256 //
1257 //*****************************************************************************
am_hal_sdhc_card_busy(void * pHandle,uint32_t ui32TimeoutMS)1258 uint32_t am_hal_sdhc_card_busy(void *pHandle, uint32_t ui32TimeoutMS)
1259 {
1260 uint32_t ui32Dat0BusyMask;
1261 SDIO_Type *pSDHC;
1262 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1263
1264 #ifndef AM_HAL_DISABLE_API_VALIDATION
1265 //
1266 // Check the handle.
1267 //
1268 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1269 {
1270 return AM_HAL_STATUS_INVALID_HANDLE;
1271 }
1272
1273 if ( !pSDHCState->prefix.s.bEnable )
1274 {
1275 return AM_HAL_STATUS_INVALID_OPERATION;
1276 }
1277 #endif // AM_HAL_DISABLE_API_VALIDATION
1278
1279 pSDHC = SDHCn(pSDHCState->ui32Module);
1280
1281 ui32Dat0BusyMask = 0x1 << SDIO_PRESENT_DAT30LINE_Pos;
1282
1283 uint32_t ui32Status;
1284 ui32Status = am_hal_delay_us_status_check(
1285 ui32TimeoutMS*1000, (uint32_t)&pSDHC->PRESENT,
1286 ui32Dat0BusyMask,
1287 ui32Dat0BusyMask,
1288 true);
1289
1290 if ( AM_HAL_STATUS_SUCCESS != ui32Status )
1291 {
1292 AM_HAL_SDHC_DEBUG("%s : wait DAT0 busy timeout\n", __FUNCTION__);
1293 }
1294
1295 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1296 //
1297 // Disable the SDCLK
1298 //
1299 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1300 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1301 #endif
1302
1303 return ui32Status;
1304 }
1305
1306 //*****************************************************************************
1307 //
1308 // SDHC Set TxRx Delays
1309 //
1310 //*****************************************************************************
am_hal_sdhc_set_txrx_delay(void * pHandle,uint8_t ui8TxRxDelays[2])1311 void am_hal_sdhc_set_txrx_delay(void *pHandle, uint8_t ui8TxRxDelays[2])
1312 {
1313 // Adjust TX CLK delay
1314 MCUCTRL->SDIOCTRL_b.SDIOITAPCHGWIN = 1;
1315
1316 MCUCTRL->SDIOCTRL_b.SDIOOTAPDLYSEL = ui8TxRxDelays[0];
1317 MCUCTRL->SDIOCTRL_b.SDIOOTAPDLYENA = 1;
1318
1319 // Adjust RX CLK delay
1320 MCUCTRL->SDIOCTRL_b.SDIOITAPDLYSEL = ui8TxRxDelays[1];
1321 MCUCTRL->SDIOCTRL_b.SDIOITAPDLYENA = 1;
1322
1323 MCUCTRL->SDIOCTRL_b.SDIOITAPCHGWIN = 0;
1324 }
1325
1326 //
1327 // SDHC Enable function
1328 //
am_hal_sdhc_enable(void * pHandle)1329 uint32_t am_hal_sdhc_enable(void *pHandle)
1330 {
1331 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1332 SDIO_Type *pSDHC;
1333 uint32_t ui32Status;
1334
1335 #ifndef AM_HAL_DISABLE_API_VALIDATION
1336 //
1337 // Check the handle.
1338 //
1339 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1340 {
1341 return AM_HAL_STATUS_INVALID_HANDLE;
1342 }
1343
1344 if ( pSDHCState->prefix.s.bEnable )
1345 {
1346 return AM_HAL_STATUS_INVALID_OPERATION;
1347 }
1348 #endif // AM_HAL_DISABLE_API_VALIDATION
1349
1350 pSDHC = SDHCn(pSDHCState->ui32Module);
1351
1352 //
1353 // Enable the clock to SDIO peripheral
1354 //
1355 MCUCTRL->SDIOCTRL |= (MCUCTRL_SDIOCTRL_SDIOSYSCLKEN_Msk | MCUCTRL_SDIOCTRL_SDIOXINCLKEN_Msk);
1356
1357 // Wait some time util clock stable
1358 am_util_delay_ms(10);
1359
1360 //
1361 // Note SW_RESET_ALL is *only* used here before initializing other registers
1362 //
1363 if ( (ui32Status = am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_ALL)) != AM_HAL_STATUS_SUCCESS )
1364 {
1365 AM_HAL_SDHC_DEBUG("Software Reset ALL failed\n");
1366 return ui32Status;
1367 }
1368 //
1369 // Enable the SDIO CD (GPIO75) & WP (GPIO74) pins
1370 // remapping to FPGA GP36 and GP35
1371 //
1372 GPIO->SDIFCDWP_b.SDIFCD = 75;
1373 GPIO->SDIFCDWP_b.SDIFWP = 74;
1374
1375 //
1376 // Enable all interrupts
1377 //
1378 SDHCn(pSDHCState->ui32Module)->INTENABLE = (uint32_t)-1;
1379
1380 //
1381 // Disable all interrupts SIGNAL
1382 //
1383 SDHCn(pSDHCState->ui32Module)->INTSIG = 0x0;
1384
1385 //
1386 // Enable SDIO IRQ only after host is initialized successfully
1387 //
1388 NVIC_SetPriority(SDIO_IRQn, AM_IRQ_PRIORITY_DEFAULT);
1389 NVIC_EnableIRQ(SDIO_IRQn);
1390
1391 //
1392 // Reset CMD and Data error count
1393 //
1394 pSDHCState->bCmdErr = false;
1395 pSDHCState->bDataErr = false;
1396 pSDHCState->ui32DataErrCnt = 0;
1397 pSDHCState->ui32CmdErrCnt = 0;
1398
1399 pSDHCState->prefix.s.bEnable = true;
1400
1401 //
1402 // Return the status.
1403 //
1404 return AM_HAL_STATUS_SUCCESS;
1405 }
1406
1407 //
1408 // SDHC Disable function
1409 //
am_hal_sdhc_disable(void * pHandle)1410 uint32_t am_hal_sdhc_disable(void *pHandle)
1411 {
1412 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
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 #endif // AM_HAL_DISABLE_API_VALIDATION
1423
1424 if ( !pSDHCState->prefix.s.bEnable )
1425 {
1426 return AM_HAL_STATUS_SUCCESS;
1427 }
1428
1429 pSDHCState->prefix.s.bEnable = false;
1430
1431 //
1432 // Disable SDIO IRQ
1433 //
1434 NVIC_DisableIRQ(SDIO_IRQn);
1435
1436 //
1437 // Disable all interrupts SIGNAL
1438 //
1439 SDHCn(pSDHCState->ui32Module)->INTSIG = 0x0;
1440
1441 //
1442 // Disable all interrupts
1443 //
1444 SDHCn(pSDHCState->ui32Module)->INTENABLE = 0x0;
1445
1446 //
1447 // Clear all interrupt status
1448 //
1449 SDHCn(pSDHCState->ui32Module)->INTSTAT = (uint32_t)-1;
1450
1451 //
1452 // Disable the clock to SDIO peripheral
1453 //
1454 MCUCTRL->SDIOCTRL &= ~(MCUCTRL_SDIOCTRL_SDIOSYSCLKEN_Msk | MCUCTRL_SDIOCTRL_SDIOXINCLKEN_Msk);
1455
1456 //
1457 // Wait some time until clock is stable
1458 //
1459 am_util_delay_ms(10);
1460
1461 //
1462 // Return the status.
1463 //
1464 return AM_HAL_STATUS_SUCCESS;
1465 }
1466
1467 //*****************************************************************************
1468 //
1469 // SDHC send command function
1470 //
1471 // This function sends a command to SD/MMC/eMMC/SDIO card and gets the response. if this command
1472 // is using synchronous transfer mode, it will be blocked until the data in the buffer has been
1473 // transmited or received. if this command is using asynchronous transfer mode, it will return immediately
1474 // after sending the command, data transfer completion done event will be notified by registered callback
1475 // function in the ISR.
1476 //
1477 //*****************************************************************************
am_hal_sdhc_execute_cmd(void * pHandle,am_hal_card_cmd_t * pCmd,am_hal_card_cmd_data_t * pCmdData)1478 uint32_t am_hal_sdhc_execute_cmd(void *pHandle, am_hal_card_cmd_t *pCmd, am_hal_card_cmd_data_t *pCmdData)
1479 {
1480 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1481 SDIO_Type *pSDHC = NULL;
1482 uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
1483
1484 #ifndef AM_HAL_DISABLE_API_VALIDATION
1485 //
1486 // Check the handle.
1487 //
1488 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1489 {
1490 return AM_HAL_STATUS_INVALID_HANDLE;
1491 }
1492
1493 if ( !pSDHCState->prefix.s.bEnable )
1494 {
1495 return AM_HAL_STATUS_INVALID_OPERATION;
1496 }
1497 #endif // AM_HAL_DISABLE_API_VALIDATION
1498
1499 pSDHC = SDHCn(pSDHCState->ui32Module);
1500
1501 if ( !pSDHCState->bAsyncCmdIsDone )
1502 {
1503 AM_HAL_SDHC_DEBUG("Return because the previous async command is still ongoing\n");
1504 return AM_HAL_STATUS_IN_USE;
1505 }
1506
1507 //
1508 // Reset the CMD and DATA internal circuit for safe
1509 //
1510 if (pSDHCState->bCmdErr)
1511 {
1512 am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_CMD_LINE);
1513 pSDHCState->bCmdErr = false;
1514 AM_HAL_SDHC_DEBUG("Software reset the Cmd Error\n");
1515 }
1516
1517 if (pSDHCState->bDataErr)
1518 {
1519 am_hal_sdhc_software_reset(pSDHC, AM_HAL_SDHC_SW_RESET_DATA_LINE);
1520 pSDHCState->bDataErr = false;
1521 AM_HAL_SDHC_DEBUG("Software reset the Data Error\n");
1522 }
1523
1524 //
1525 // Clear all interrupts's status
1526 //
1527 pSDHC->INTENABLE_b.CARDINTERRUPTSTATUSENABLE = 0x0;
1528 pSDHC->INTSTAT = ((uint32_t)-1);
1529
1530 //
1531 // Disable all interrupts firstly
1532 //
1533 pSDHC->INTSIG = 0x0;
1534
1535 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1536 //
1537 // Enable the SDCLK
1538 //
1539 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x1;
1540 AM_HAL_SDHC_DEBUG("Enable the SDCLK\n");
1541 #endif
1542
1543 if ( (ui32Status = am_hal_sdhc_send_cmd(pSDHCState, pSDHC, pCmd, pCmdData)) != AM_HAL_STATUS_SUCCESS )
1544 {
1545 return ui32Status;
1546 }
1547
1548 if ( (ui32Status = am_hal_sdhc_wait_cmd_done(pSDHCState, pSDHC, pCmd)) != AM_HAL_STATUS_SUCCESS )
1549 {
1550 return ui32Status;
1551 }
1552
1553 am_hal_sdhc_get_cmd_response(pSDHC, pCmd);
1554
1555 if ( pCmd->bASync )
1556 {
1557 AM_CRITICAL_BEGIN
1558 pSDHC->INTSIG = ((uint32_t)-1);
1559 pSDHCState->bAsyncCmdIsDone = false;
1560 AM_CRITICAL_END
1561 }
1562
1563 if ( pCmdData == NULL || pCmd->bASync )
1564 {
1565 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1566 if (pCmdData == NULL && !pCmd->bCheckBusyCmd)
1567 {
1568 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1569 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1570 }
1571 #endif
1572 return AM_HAL_STATUS_SUCCESS;
1573 }
1574
1575 return am_hal_sdhc_xfer_data(pSDHCState, pCmdData);
1576 }
1577
1578 //
1579 // SDHC normal/error status interrupts enable function
1580 //
am_hal_sdhc_intr_status_enable(void * pHandle,uint32_t ui32IntMask)1581 uint32_t am_hal_sdhc_intr_status_enable(void *pHandle, uint32_t ui32IntMask)
1582 {
1583 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1584 uint32_t ui32Module;
1585
1586 #ifndef AM_HAL_DISABLE_API_VALIDATION
1587 //
1588 // Check the handle.
1589 //
1590 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1591 {
1592 return AM_HAL_STATUS_INVALID_HANDLE;
1593 }
1594
1595 if ( !pSDHCState->prefix.s.bEnable )
1596 {
1597 return AM_HAL_STATUS_INVALID_OPERATION;
1598 }
1599 #endif // AM_HAL_DISABLE_API_VALIDATION
1600
1601 ui32Module = pSDHCState->ui32Module;
1602
1603 //
1604 // Set the interrupt enables according to the mask.
1605 //
1606 SDHCn(ui32Module)->INTENABLE |= ui32IntMask;
1607
1608 //
1609 // Return the status.
1610 //
1611 return AM_HAL_STATUS_SUCCESS;
1612 }
1613
1614 //
1615 // SDHC normal/error status interrupts disable function
1616 //
am_hal_sdhc_intr_status_disable(void * pHandle,uint32_t ui32IntMask)1617 uint32_t am_hal_sdhc_intr_status_disable(void *pHandle, uint32_t ui32IntMask)
1618 {
1619 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1620 uint32_t ui32Module;
1621
1622 #ifndef AM_HAL_DISABLE_API_VALIDATION
1623 //
1624 // Check the handle.
1625 //
1626 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1627 {
1628 return AM_HAL_STATUS_INVALID_HANDLE;
1629 }
1630
1631 if ( !pSDHCState->prefix.s.bEnable )
1632 {
1633 return AM_HAL_STATUS_INVALID_OPERATION;
1634 }
1635 #endif // AM_HAL_DISABLE_API_VALIDATION
1636
1637 ui32Module = pSDHCState->ui32Module;
1638 //
1639 // Clear the interrupt enables according to the mask.
1640 //
1641 SDHCn(ui32Module)->INTENABLE &= ~ui32IntMask;
1642
1643 //
1644 // Return the status.
1645 //
1646 return AM_HAL_STATUS_SUCCESS;
1647 }
1648
1649 //
1650 // SDHC normal/error interrupt status get function
1651 //
am_hal_sdhc_intr_status_get(void * pHandle,uint32_t * pui32Status,bool bEnabledOnly)1652 uint32_t am_hal_sdhc_intr_status_get(void *pHandle, uint32_t *pui32Status, bool bEnabledOnly)
1653 {
1654 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1655 uint32_t ui32Module;
1656
1657 #ifndef AM_HAL_DISABLE_API_VALIDATION
1658 //
1659 // Check the handle.
1660 //
1661 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1662 {
1663 return AM_HAL_STATUS_INVALID_HANDLE;
1664 }
1665
1666 if ( !pSDHCState->prefix.s.bEnable )
1667 {
1668 return AM_HAL_STATUS_INVALID_OPERATION;
1669 }
1670 #endif // AM_HAL_DISABLE_API_VALIDATION
1671
1672 ui32Module = pSDHCState->ui32Module;
1673
1674 //
1675 // if requested, only return the interrupts that are enabled.
1676 //
1677 if ( bEnabledOnly )
1678 {
1679 uint32_t ui32RetVal = SDHCn(ui32Module)->INTSTAT;
1680 *pui32Status = ui32RetVal & SDHCn(ui32Module)->INTENABLE;
1681 }
1682 else
1683 {
1684 *pui32Status = SDHCn(ui32Module)->INTSTAT;
1685 }
1686
1687 return AM_HAL_STATUS_SUCCESS;
1688 }
1689
1690 //
1691 // SDHC normal/error interrupt status clear function
1692 //
am_hal_sdhc_intr_status_clear(void * pHandle,uint32_t ui32IntMask)1693 uint32_t am_hal_sdhc_intr_status_clear(void *pHandle, uint32_t ui32IntMask)
1694 {
1695 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1696 uint32_t ui32Module;
1697
1698 #ifndef AM_HAL_DISABLE_API_VALIDATION
1699 //
1700 // Check the handle.
1701 //
1702 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1703 {
1704 return AM_HAL_STATUS_INVALID_HANDLE;
1705 }
1706
1707 if ( !pSDHCState->prefix.s.bEnable )
1708 {
1709 return AM_HAL_STATUS_INVALID_OPERATION;
1710 }
1711 #endif // AM_HAL_DISABLE_API_VALIDATION
1712
1713 ui32Module = pSDHCState->ui32Module;
1714
1715 SDHCn(ui32Module)->INTSTAT = ui32IntMask;
1716
1717 //
1718 // Return the status.
1719 //
1720 return AM_HAL_STATUS_SUCCESS;
1721 }
1722
1723 //
1724 // SDHC normal interrupt signal enable function
1725 //
am_hal_sdhc_intr_signal_enable(void * pHandle,uint32_t ui32IntMask)1726 uint32_t am_hal_sdhc_intr_signal_enable(void *pHandle, uint32_t ui32IntMask)
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 // Set the interrupt enables according to the mask.
1750 //
1751 SDHCn(ui32Module)->INTSIG |= ui32IntMask;
1752
1753 //
1754 // Return the status.
1755 //
1756 return AM_HAL_STATUS_SUCCESS;
1757 }
1758
1759 //
1760 // SDHC normal status signal disable function
1761 //
am_hal_sdhc_intr_signal_disable(void * pHandle,uint32_t ui32IntMask)1762 uint32_t am_hal_sdhc_intr_signal_disable(void *pHandle, uint32_t ui32IntMask)
1763 {
1764 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1765 uint32_t ui32Module;
1766
1767 #ifndef AM_HAL_DISABLE_API_VALIDATION
1768 //
1769 // Check the handle.
1770 //
1771 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1772 {
1773 return AM_HAL_STATUS_INVALID_HANDLE;
1774 }
1775
1776 if ( !pSDHCState->prefix.s.bEnable )
1777 {
1778 return AM_HAL_STATUS_INVALID_OPERATION;
1779 }
1780 #endif // AM_HAL_DISABLE_API_VALIDATION
1781
1782 ui32Module = pSDHCState->ui32Module;
1783 //
1784 // Clear the interrupt enables according to the mask.
1785 //
1786 SDHCn(ui32Module)->INTSIG &= ~ui32IntMask;
1787
1788 //
1789 // Return the status.
1790 //
1791 return AM_HAL_STATUS_SUCCESS;
1792 }
1793
1794 //
1795 // SDHC interrupt service routine
1796 //
am_hal_sdhc_interrupt_service(void * pHandle,uint32_t ui32IntStatus)1797 uint32_t am_hal_sdhc_interrupt_service(void *pHandle, uint32_t ui32IntStatus)
1798 {
1799 am_hal_sdhc_state_t *pSDHCState = (am_hal_sdhc_state_t *)pHandle;
1800 am_hal_card_host_t *pHost = pSDHCState->pHost;
1801 SDIO_Type *pSDHC = NULL;
1802 am_hal_host_evt_t evt;
1803
1804 #ifndef AM_HAL_DISABLE_API_VALIDATION
1805 //
1806 // Check the handle.
1807 //
1808 if ( !AM_HAL_SDHC_CHK_HANDLE(pHandle) )
1809 {
1810 return AM_HAL_STATUS_INVALID_HANDLE;
1811 }
1812
1813 if ( !pSDHCState->prefix.s.bEnable )
1814 {
1815 return AM_HAL_STATUS_INVALID_OPERATION;
1816 }
1817 #endif // AM_HAL_DISABLE_API_VALIDATION
1818
1819 pSDHC = SDHCn(pSDHCState->ui32Module);
1820
1821 //
1822 // Asynchronous PIO write
1823 //
1824 if ( ui32IntStatus & SDIO_INTSTAT_BUFFERREADREADY_Msk ||
1825 ui32IntStatus & SDIO_INTSTAT_BUFFERWRITEREADY_Msk )
1826 {
1827 am_hal_sdhc_pio_xfer_data(pSDHCState);
1828 // AM_HAL_SDHC_DEBUG("%d\n", pSDHCState->ui32BlkCnt);
1829 }
1830
1831 //
1832 // Asynchronous SDMA interrupt
1833 //
1834 if ( ui32IntStatus & SDIO_INTSTAT_DMAINTERRUPT_Msk )
1835 {
1836 // Invalidate DAXI to make sure CPU sees the new data when loaded
1837 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
1838
1839 am_hal_sdhc_sdma_xfer_data(pSDHCState);
1840 // AM_HAL_SDHC_DEBUG("ISR - DMA Xfer BlkCnt %d\n", pSDHCState->ui32BlkCnt);
1841 evt.eType = AM_HAL_EVT_SDMA_DONE;
1842 evt.pCtx = pSDHCState->pHost;
1843 evt.ui32BlkCnt = pSDHCState->ui32BlksPerSDMA;
1844 if ( pSDHCState->pHost->pfunEvtCallback )
1845 {
1846 pSDHCState->pHost->pfunEvtCallback(&evt);
1847 }
1848 }
1849
1850 //
1851 // Asynchronous PIO read, write, SDMA and ADMA xfer completion
1852 //
1853 if ( ui32IntStatus & SDIO_INTSTAT_TRANSFERCOMPLETE_Msk )
1854 {
1855 // Invalidate DAXI to make sure CPU sees the new data when loaded
1856 am_hal_daxi_control(AM_HAL_DAXI_CONTROL_INVALIDATE, 0);
1857
1858 evt.eType = AM_HAL_EVT_XFER_COMPLETE;
1859 evt.pCtx = pSDHCState->pHost;
1860 evt.ui32BlkCnt = pSDHCState->ui32BlkCnt;
1861 if ( pSDHCState->pHost->pfunEvtCallback )
1862 {
1863 pSDHCState->pHost->pfunEvtCallback(&evt);
1864 }
1865 AM_HAL_SDHC_DEBUG("ISR - Xfer Completion BlkCnt %d\n", pSDHCState->ui32BlkNum);
1866 pSDHCState->bAsyncCmdIsDone = true;
1867
1868 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1869 //
1870 // Disable the SDCLK after the xfer is done
1871 //
1872 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1873 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1874 #endif
1875
1876 }
1877
1878 if (ui32IntStatus & (SDIO_INTSTAT_ADMAERROR_Msk |
1879 SDIO_INTSTAT_DATACRCERROR_Msk |
1880 SDIO_INTSTAT_DATATIMEOUTERROR_Msk |
1881 SDIO_INTSTAT_DATAENDBITERROR_Msk))
1882 {
1883 evt.eType = AM_HAL_EVT_DAT_ERR;
1884 evt.pCtx = pSDHCState->pHost;
1885 evt.ui32BlkCnt = pSDHCState->ui32BlkCnt;
1886 pHost->AsyncCmdData.eDataError = am_hal_sdhc_check_data_error_type(ui32IntStatus);
1887 pSDHCState->bDataErr = true;
1888 pSDHCState->ui32DataErrCnt++;
1889 if ( pSDHCState->pHost->pfunEvtCallback )
1890 {
1891 pSDHCState->pHost->pfunEvtCallback(&evt);
1892 }
1893 AM_HAL_SDHC_DEBUG("Xfer ERR INT 0x%x\n", ui32IntStatus);
1894 pSDHCState->bAsyncCmdIsDone = true;
1895
1896 #ifdef DYNAMIC_SWITCH_SDCLK_FEATURE
1897 //
1898 // Disable the SDCLK after the xfer is done
1899 //
1900 pSDHC->CLOCKCTRL_b.SDCLKEN = 0x0;
1901 AM_HAL_SDHC_DEBUG("Disable the SDCLK\n");
1902 #endif
1903
1904 }
1905
1906 //
1907 // Return the status.
1908 //
1909 return AM_HAL_STATUS_SUCCESS;
1910 }
1911
1912 //*****************************************************************************
1913 //
1914 // End Doxygen group.
1915 //! @}
1916 //
1917 //*****************************************************************************
1918