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