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