1 //*****************************************************************************
2 //
3 //! @file am_hal_card.c
4 //!
5 //! @brief Functions for interfacing with the card host.
6 //!
7 //! @addtogroup card_4p Card Functionality for SD/MMC/eMMC/SDIO
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 <stdint.h>
49 #include <stdbool.h>
50 #include <string.h>
51 
52 #include "am_mcu_apollo.h"
53 #include "am_util_stdio.h"
54 #include "am_util_debug.h"
55 #include "am_util_delay.h"
56 
57 //
58 // Internal macros
59 //
60 #define SDIO_TIMING_SCAN_MIN_ACCEPTANCE_LENGTH  2 // Acceptable length should be determined based on system level test.
61 #define AM_HAL_CARD_DEBUG(fmt, ...) am_util_debug_printf("[CARD] line %04d - "fmt, __LINE__, ##__VA_ARGS__)
62 
63 //
64 // Private internal functions
65 //
66 
67 //
68 //! CMD0 - go idle
69 //
am_hal_sdmmc_cmd0_go_idle(am_hal_card_t * pCard)70 static inline uint32_t am_hal_sdmmc_cmd0_go_idle(am_hal_card_t *pCard)
71 {
72     am_hal_card_cmd_t cmd;
73     am_hal_card_host_t *pHost = pCard->pHost;
74 
75     memset(&cmd, 0, sizeof(cmd));
76     cmd.ui8Idx   = MMC_CMD_GO_IDLE_STATE;
77     cmd.ui32Arg  = 0x0;
78     cmd.ui32RespType = MMC_RSP_NONE;
79 
80     pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
81 
82     return cmd.eError;
83 }
84 
85 
86 #define SECTOR_MODE       0x4
87 #define CMD1_CARD_RDY_BIT ((uint32_t)0x1 << 31)
88 //
89 //! CMD1 - send operation condition
90 //
am_hal_sdmmc_cmd1_send_op_cond(am_hal_card_t * pCard)91 static inline uint32_t am_hal_sdmmc_cmd1_send_op_cond(am_hal_card_t *pCard)
92 {
93     uint32_t ui32CardOCR = 0;
94     uint8_t ui8Tries = 100;
95 
96     am_hal_card_cmd_t cmd;
97     am_hal_card_host_t *pHost = pCard->pHost;
98 
99     memset(&cmd, 0, sizeof(cmd));
100     cmd.ui8Idx = MMC_CMD_SEND_OP_COND;
101     cmd.ui32Arg = SECTOR_MODE << 28;
102     cmd.ui32RespType = MMC_RSP_R3;
103 
104     do
105     {
106         pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
107 
108         if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
109         {
110             ui32CardOCR = cmd.ui32Resp[0];
111             cmd.ui32Arg |= ui32CardOCR;
112         }
113 
114         if ( ui32CardOCR & CMD1_CARD_RDY_BIT )
115         {
116             pCard->ui32OCR = ui32CardOCR;
117             break;
118         }
119 
120         am_util_delay_ms(10);
121     } while (--ui8Tries != 0);
122 
123     return ui8Tries == 0x0 ? AM_HAL_CMD_ERR_TIMEOUT : cmd.eError;
124 }
125 
126 //
127 //! CMD2 - send card identification
128 //
am_hal_sdmmc_cmd2_send_cid(am_hal_card_t * pCard)129 static inline uint32_t am_hal_sdmmc_cmd2_send_cid(am_hal_card_t *pCard)
130 {
131     am_hal_card_cmd_t cmd;
132     am_hal_card_host_t *pHost = pCard->pHost;
133 
134     memset(&cmd, 0, sizeof(cmd));
135     cmd.ui8Idx   = MMC_CMD_ALL_SEND_CID;
136     cmd.ui32Arg  = 0x0;
137     cmd.ui32RespType = MMC_RSP_R2;
138 
139     pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
140 
141     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
142     {
143         memcpy((void *)pCard->ui32CID, (void *)&cmd.ui32Resp[0], 16);
144         pCard->bCidValid = 1;
145     }
146 
147     return cmd.eError;
148 }
149 
150 //
151 //! CMD3 - set the relative card address
152 //
am_hal_sdmmc_cmd3_set_rca(am_hal_card_t * pCard,uint16_t ui16RCA)153 static inline uint32_t am_hal_sdmmc_cmd3_set_rca(am_hal_card_t *pCard, uint16_t ui16RCA)
154 {
155     am_hal_card_cmd_t cmd;
156     am_hal_card_host_t *pHost = pCard->pHost;
157 
158     memset(&cmd, 0, sizeof(cmd));
159     cmd.ui8Idx   = MMC_CMD_SET_RELATIVE_ADDR;
160     cmd.ui32Arg  = ui16RCA << 16;
161     cmd.ui32RespType = MMC_RSP_R1;
162 
163     pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
164 
165     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
166     {
167         pCard->ui8RCA = ui16RCA;
168     }
169 
170     return cmd.eError;
171 }
172 
173 //
174 //! CMD5 - Sleep/Awake
175 //
am_hal_sdmmc_cmd5(am_hal_card_t * pCard,bool sleep)176 static uint32_t am_hal_sdmmc_cmd5(am_hal_card_t *pCard, bool sleep)
177 {
178     uint32_t ui32Status;
179     am_hal_card_cmd_t cmd;
180     am_hal_card_host_t *pHost = pCard->pHost;
181 
182     memset(&cmd, 0, sizeof(cmd));
183     cmd.ui8Idx   = MMC_CMD_SLEEP_AWAKE;
184     cmd.ui32Arg  = pCard->ui8RCA << 16 | sleep << 15;
185     cmd.ui32RespType = MMC_RSP_R1b;
186     cmd.bCheckBusyCmd = true;
187 
188     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
189     {
190         return ui32Status;
191     }
192 
193     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
194     {
195         if ( sleep == true )
196         {
197             pCard->eState = AM_HAL_CARD_STATE_SLP;
198         }
199         else
200         {
201             pCard->eState = AM_HAL_CARD_STATE_STDY;
202         }
203     }
204 
205     if ((ui32Status = pHost->ops->card_busy(pHost->pHandle, 20)) != AM_HAL_STATUS_SUCCESS)
206     {
207         return ui32Status;
208     }
209 
210     return AM_HAL_STATUS_SUCCESS;
211 }
212 
213 //
214 //! CMD7 - select the card
215 //
216 
am_hal_sdmmc_cmd7_card_select(am_hal_card_t * pCard)217 static uint32_t am_hal_sdmmc_cmd7_card_select(am_hal_card_t *pCard)
218 {
219     am_hal_card_cmd_t cmd;
220     am_hal_card_host_t *pHost = pCard->pHost;
221 
222     memset(&cmd, 0, sizeof(cmd));
223     cmd.ui8Idx   = MMC_CMD_SELECT_CARD;
224     cmd.ui32Arg  = pCard->ui8RCA << 16;
225 
226     //
227     // RCA of zero is not valid for a card select, so this
228     // is a card deselect which requires no response
229     //
230     if ( pCard->ui8RCA == 0x0 )
231     {
232         cmd.ui32RespType = MMC_RSP_NONE;
233     }
234     else
235     {
236         cmd.ui32RespType = MMC_RSP_R1;
237     }
238 
239     pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
240 
241     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
242     {
243         //
244         // For a card deselect, the state is stand-by-state
245         //
246         if ( pCard->ui8RCA == 0x0 )
247         {
248             pCard->eState = AM_HAL_CARD_STATE_STDY;
249         }
250         //
251         // for a card select, the state is the transfer state
252         //
253         else
254         {
255             pCard->eState = AM_HAL_CARD_STATE_TRANS;
256         }
257     }
258 
259     return cmd.eError;
260 }
261 
262 //
263 //! CMD7 - select/deselect the card
264 //
am_hal_sdmmc_cmd7_card_deselect(am_hal_card_t * pCard)265 static uint32_t am_hal_sdmmc_cmd7_card_deselect(am_hal_card_t *pCard)
266 {
267     uint8_t ui8RCA = pCard->ui8RCA;
268     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
269 
270     pCard->ui8RCA = 0;
271     if ( AM_HAL_CMD_ERR_NONE != am_hal_sdmmc_cmd7_card_select(pCard) )
272     {
273         AM_HAL_CARD_DEBUG("sleep - am_hal_sdmmc_cmd7_card_select Failed\n");
274         ui32Status = AM_HAL_STATUS_FAIL;
275     }
276     pCard->ui8RCA = ui8RCA;
277 
278     return ui32Status;
279 }
280 
281 //
282 //! CMD8 - get the 512 bytes ext csd
283 //
am_hal_sdmmc_cmd8_send_ext_csd(am_hal_card_t * pCard)284 static uint32_t am_hal_sdmmc_cmd8_send_ext_csd(am_hal_card_t *pCard)
285 {
286     am_hal_card_cmd_t cmd;
287     am_hal_card_cmd_data_t cmd_data;
288     am_hal_card_host_t *pHost = pCard->pHost;
289 
290     memset(&cmd, 0x0, sizeof(cmd));
291     memset(&cmd_data, 0x0, sizeof(cmd_data));
292 
293     cmd.ui8Idx   = MMC_CMD_SEND_EXT_CSD;
294     cmd.ui32Arg  = pCard->ui8RCA << 16;
295     cmd.ui32RespType = MMC_RSP_R1;
296 
297     cmd_data.pui8Buf = (uint8_t *)pCard->ui32ExtCSD;
298     cmd_data.ui32BlkCnt = 1;
299     cmd_data.ui32BlkSize = 512;
300     cmd_data.dir = AM_HAL_DATA_DIR_READ;
301 
302     pHost->ops->execute_cmd(pHost->pHandle, &cmd, &cmd_data);
303 
304     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
305     {
306         pCard->bExtCsdValid = 1;
307     }
308 
309     return cmd.eError;
310 }
311 
312 //
313 //! CMD9 - get the CSD
314 //
am_hal_sdmmc_cmd9_send_csd(am_hal_card_t * pCard)315 static inline uint32_t am_hal_sdmmc_cmd9_send_csd(am_hal_card_t *pCard)
316 {
317     am_hal_card_cmd_t cmd;
318     am_hal_card_host_t *pHost = pCard->pHost;
319 
320     memset(&cmd, 0, sizeof(cmd));
321     cmd.ui8Idx   = MMC_CMD_SEND_CSD;
322     cmd.ui32Arg  = pCard->ui8RCA << 16;
323     cmd.ui32RespType = MMC_RSP_R2;
324 
325     pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL);
326 
327     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
328     {
329         memcpy((void *)pCard->ui32CSD, (void *)&cmd.ui32Resp[0], 16);
330         pCard->bCsdValid = 1;
331     }
332 
333     return cmd.eError;
334 }
335 
336 //
337 //! Card Cache Control
338 //
339 static uint32_t
am_hal_card_cache_ctrl(am_hal_card_t * pCard,bool bCacheEnable)340 am_hal_card_cache_ctrl(am_hal_card_t *pCard, bool bCacheEnable)
341 {
342     uint32_t ui32Mode;
343 #ifndef AM_HAL_DISABLE_API_VALIDATION
344         if ( !pCard || !pCard->pHost )
345         {
346             AM_HAL_CARD_DEBUG("This card is not connected to a host\n");
347             return AM_HAL_STATUS_INVALID_ARG;
348         }
349 #endif // AM_HAL_DISABLE_API_VALIDATION
350 
351     if (pCard->ui32CacheSize > 0)
352     {
353         ui32Mode = MMC_EXT_MODE_WRITE_BYTE | (MMC_EXT_REGS_CACHE_CTRL << 16) | (bCacheEnable ? (1 << 8) : 0);
354         return am_hal_card_mode_switch(pCard, ui32Mode, DEFAULT_CMD6_TIMEOUT_MS);
355     }
356 
357     return AM_HAL_STATUS_INVALID_OPERATION;
358 }
359 
360 //
361 //! Card Cache On
362 //
363 static inline uint32_t
am_hal_card_cache_on(am_hal_card_t * pCard)364 am_hal_card_cache_on(am_hal_card_t *pCard)
365 {
366     return am_hal_card_cache_ctrl(pCard, true);
367 }
368 
369 //
370 //! Card Cache Off
371 //
372 static inline uint32_t
am_hal_card_cache_off(am_hal_card_t * pCard)373 am_hal_card_cache_off(am_hal_card_t *pCard)
374 {
375     return am_hal_card_cache_ctrl(pCard, false);
376 }
377 
378 //
379 //! Card Power Notification
380 //
381 static uint32_t
am_hal_card_pwr_notification(am_hal_card_t * pCard,uint8_t ui8NotifyType)382 am_hal_card_pwr_notification(am_hal_card_t *pCard,
383                              uint8_t ui8NotifyType)
384 {
385     uint32_t ui32Mode;
386     uint32_t ui32Timeout;
387 
388 #ifndef AM_HAL_DISABLE_API_VALIDATION
389         if ( !pCard || !pCard->pHost )
390         {
391             AM_HAL_CARD_DEBUG("This card is not connected to a host\n");
392             return AM_HAL_STATUS_INVALID_ARG;
393         }
394 #endif // AM_HAL_DISABLE_API_VALIDATION
395 
396     if (pCard->ui8ExtCSDRev < 6)
397     {
398         AM_HAL_CARD_DEBUG("this eMMC card type is not supporting notification\n");
399         return AM_HAL_STATUS_INVALID_OPERATION;
400     }
401 
402     ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_PWR_OFF_NOTIFY << 16 | ui8NotifyType << 8;
403 
404     //
405     // Timeout Selection based upon notification type
406     //
407     switch (ui8NotifyType)
408     {
409         case MMC_EXT_CSD_POWER_OFF_LONG:
410             ui32Timeout = pCard->ui32PowerOffNotificationLongTimeout;
411             break;
412         case MMC_EXT_CSD_SLEEP_NOTIFICATION:
413             ui32Timeout = pCard->ui32SleepNotificationTimeout;
414             break;
415         case MMC_EXT_CSD_POWERED_ON:
416             ui32Timeout = DEFAULT_CMD6_TIMEOUT_MS;
417             break;
418         default:
419             AM_HAL_CARD_DEBUG("Unknown notification type\n");
420             return AM_HAL_STATUS_INVALID_ARG;
421     }
422 
423     if (am_hal_card_mode_switch(pCard, ui32Mode, ui32Timeout) != AM_HAL_STATUS_SUCCESS)
424     {
425         AM_HAL_CARD_DEBUG("Unknown notification type\n");
426         return AM_HAL_STATUS_FAIL;
427     }
428 
429     pCard->ui8PowerOffNotification = ui8NotifyType;
430 
431     return AM_HAL_STATUS_SUCCESS;
432 }
433 
434 //
435 //! Card MMC Init
436 //
437 static uint32_t
am_hal_card_mmc_init(am_hal_card_t * pCard)438 am_hal_card_mmc_init(am_hal_card_t *pCard)
439 {
440     uint32_t ui32RetVal = AM_HAL_STATUS_SUCCESS;
441 
442     //
443     // Reset the card
444     //
445     if ( am_hal_sdmmc_cmd0_go_idle(pCard) != AM_HAL_CMD_ERR_NONE )
446     {
447         AM_HAL_CARD_DEBUG("CMD0 Failed\n");
448         return AM_HAL_STATUS_FAIL;
449     }
450 
451     //
452     // Set the operation condition of the card
453     //
454     if ( am_hal_sdmmc_cmd1_send_op_cond(pCard) != AM_HAL_CMD_ERR_NONE )
455     {
456         AM_HAL_CARD_DEBUG("CMD1 Failed\n");
457         return AM_HAL_STATUS_FAIL;
458     }
459 
460     //
461     // Get the CID information of the card
462     //
463     if ( am_hal_sdmmc_cmd2_send_cid(pCard) != AM_HAL_CMD_ERR_NONE )
464     {
465         AM_HAL_CARD_DEBUG("CMD2 Failed\n");
466         return AM_HAL_STATUS_FAIL;
467     }
468 
469     //
470     // Set relative card address to 0x1
471     //
472     if ( am_hal_sdmmc_cmd3_set_rca(pCard, 0x1) != AM_HAL_CMD_ERR_NONE )
473     {
474         AM_HAL_CARD_DEBUG("CMD3 Failed\n");
475         return AM_HAL_STATUS_FAIL;
476     }
477 
478     //
479     // Get the card CSD
480     //
481     if ( am_hal_sdmmc_cmd9_send_csd(pCard) != AM_HAL_CMD_ERR_NONE )
482     {
483         AM_HAL_CARD_DEBUG("CMD9 Failed\n");
484         return AM_HAL_STATUS_FAIL;
485     }
486 
487     //
488     // Select the card
489     //
490     if ( am_hal_sdmmc_cmd7_card_select(pCard) != AM_HAL_CMD_ERR_NONE )
491     {
492         AM_HAL_CARD_DEBUG("CMD7 Failed\n");
493         return AM_HAL_STATUS_FAIL;
494     }
495 
496     //
497     // Get the ext csd
498     //
499     if ( am_hal_sdmmc_cmd8_send_ext_csd(pCard) != AM_HAL_CMD_ERR_NONE )
500     {
501        AM_HAL_CARD_DEBUG("CMD8 Failed\n");
502        return AM_HAL_STATUS_FAIL;
503     }
504 
505     //
506     // Parse the CSD and EXT CSD to know the feature of card
507     //
508     uint32_t ui32CSize = am_hal_unstuff_bits(pCard->ui32CSD, 62, 12);
509     pCard->bHighCapcity = (ui32CSize == 0xFFF) ? true : false;
510 
511     //
512     // High capacity card
513     //
514     if ( pCard->bHighCapcity )
515     {
516         //
517         // get blksize and capacity information from the ext csd
518         //
519         pCard->ui32BlkSize = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 61, 1) ? 4096 : 512;
520         pCard->bUseBlkEmulation = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 62, 1) ? false : true;
521         pCard->ui32NativeBlkSize = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 63, 1) ? 4096 : 512;
522         pCard->ui16CmdClass = am_hal_unstuff_bits(pCard->ui32CSD, 84, 12);
523         pCard->ui8SpecVer = am_hal_unstuff_bits(pCard->ui32CSD, 122, 4);
524         pCard->ui32RpmbSizeMult = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 168, 1);
525         pCard->ui8ExtCSDRev = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 192, 1);
526         pCard->ui8DeviceType = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 196, 1);
527         pCard->ui32MaxBlks = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 212, 4);
528         pCard->ui32Capacity = pCard->ui32MaxBlks*pCard->ui32BlkSize;
529         pCard->ui32CacheSize = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 249, 4);
530         pCard->ui8SecureErase = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 231, 1);
531         pCard->ui32GenericCmd6Timeout = DEFAULT_CMD6_TIMEOUT_MS;
532         if (pCard->ui8ExtCSDRev >= 6)
533         {
534             pCard->ui32SleepNotificationTimeout = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 216, 1)*10;
535             pCard->ui32PowerOffNotificationLongTimeout = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 247, 1)*10;
536             pCard->ui32GenericCmd6Timeout = am_hal_unstuff_bytes(pCard->ui32ExtCSD, 248, 1)*10;
537         }
538     }
539     else
540     {
541         //
542         // non high capacity card gets blksize and capacity information from the CSD
543         //
544     }
545 
546     //
547     // Always enable the cache if it's supported
548     //
549     ui32RetVal = am_hal_card_cache_on(pCard);
550     if ( AM_HAL_STATUS_SUCCESS == ui32RetVal )
551     {
552         //
553         // Reread the card to get the updated cache status.
554         //
555         ui32RetVal = am_hal_card_get_ext_csd_field(pCard, MMC_EXT_REGS_CACHE_CTRL, 1);
556         AM_HAL_CARD_DEBUG("\r\nExtCsd CACHE_ON - %s\r\n", ((ui32RetVal == 1) ? "Pass" : "Fail"));
557     }
558     else
559     {
560         AM_HAL_CARD_DEBUG("\r\am_hal_card_cache_on - status %x\r\n", ui32RetVal);
561     }
562 
563     //
564     // Always enable the notifcaition if it's supported
565     //
566     pCard->ui8PowerOffNotification = MMC_EXT_CSD_NO_POWER_NOTIFICATION;
567     if (am_hal_card_pwr_notification(pCard, MMC_EXT_CSD_POWERED_ON) == AM_HAL_STATUS_SUCCESS)
568     {
569         pCard->ui8PowerOffNotification = MMC_EXT_CSD_POWERED_ON;
570     }
571 
572     return AM_HAL_STATUS_SUCCESS;
573 }
574 
575 static uint32_t
am_hal_card_sd_init(am_hal_card_t * pCard)576 am_hal_card_sd_init(am_hal_card_t *pCard)
577 {
578     AM_HAL_CARD_DEBUG("card type %d is not supported yet\n", pCard->eType);
579     return AM_HAL_STATUS_FAIL;
580 }
581 
582 static uint32_t
am_hal_card_type_detect(am_hal_card_t * pCard)583 am_hal_card_type_detect(am_hal_card_t *pCard)
584 {
585     AM_HAL_CARD_DEBUG("card type detect is not supported yet\n");
586     return AM_HAL_STATUS_FAIL;
587 }
588 
589 static uint32_t
am_hal_card_set_bus_width(am_hal_card_t * pCard,am_hal_host_bus_width_e eBusWidth)590 am_hal_card_set_bus_width(am_hal_card_t *pCard, am_hal_host_bus_width_e eBusWidth)
591 {
592     uint32_t ui32Mode;
593     uint32_t ui32Status;
594 
595     am_hal_card_host_t *pHost;
596 
597 #ifndef AM_HAL_DISABLE_API_VALIDATION
598 
599     if ( !pCard || !pCard->pHost )
600     {
601         return AM_HAL_STATUS_INVALID_ARG;
602     }
603 
604 #endif // AM_HAL_DISABLE_API_VALIDATION
605 
606     pHost = pCard->pHost;
607     ui32Mode = 0x0;
608     if ( eBusWidth != pHost->eBusWidth || pHost->eUHSMode != pCard->cfg.eUHSMode)
609     {
610         switch ( eBusWidth )
611         {
612             case AM_HAL_HOST_BUS_WIDTH_1:
613                 //
614                 // 3 << 24 | 183 << 16 | 0 << 8
615                 // 0x03b70000
616                 //
617                 ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_BUS_WIDTH | MMC_EXT_SET_BUS_WIDTH1;
618                 break;
619             case AM_HAL_HOST_BUS_WIDTH_4:
620                 //
621                 // 3 << 24 | 183 << 16 | 1 << 8
622                 // 0x03b70100
623                 //
624                 if (pCard->cfg.eUHSMode == AM_HAL_HOST_UHS_DDR50)
625                 {
626                     ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_BUS_WIDTH | MMC_EXT_SET_BUS_WIDTH4_DDR;
627                 }
628                 else
629                 {
630                     ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_BUS_WIDTH | MMC_EXT_SET_BUS_WIDTH4;
631                 }
632                 break;
633             case AM_HAL_HOST_BUS_WIDTH_8:
634                 //
635                 // 3 << 24 | 183 << 16 | 2 << 8
636                 // 0x03b70200
637                 //
638                 if (pCard->cfg.eUHSMode == AM_HAL_HOST_UHS_DDR50)
639                 {
640                     ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_BUS_WIDTH | MMC_EXT_SET_BUS_WIDTH8_DDR;
641                 }
642                 else
643                 {
644                     ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_BUS_WIDTH | MMC_EXT_SET_BUS_WIDTH8;
645                 }
646                 break;
647         }
648 
649         if ( (ui32Status = am_hal_card_mode_switch(pCard, ui32Mode, DEFAULT_CMD6_TIMEOUT_MS)) != AM_HAL_STATUS_SUCCESS )
650         {
651             return ui32Status;
652         }
653 
654         if ( pHost->ops->set_bus_width(pHost->pHandle, eBusWidth) != AM_HAL_STATUS_SUCCESS )
655         {
656             return AM_HAL_STATUS_FAIL;
657         }
658     }
659 
660     return AM_HAL_STATUS_SUCCESS;
661 }
662 
663 static uint32_t
am_hal_card_set_uhs_mode(am_hal_card_t * pCard,am_hal_host_uhs_mode_e eUHSMode)664 am_hal_card_set_uhs_mode(am_hal_card_t *pCard, am_hal_host_uhs_mode_e eUHSMode)
665 {
666     am_hal_card_host_t *pHost;
667 
668 #ifndef AM_HAL_DISABLE_API_VALIDATION
669     if ( !pCard || !pCard->pHost )
670     {
671         return AM_HAL_STATUS_INVALID_ARG;
672     }
673 #endif // AM_HAL_DISABLE_API_VALIDATION
674 
675     pHost = pCard->pHost;
676 
677     //
678     // Already in this UHS mode
679     //
680     if ( pHost->eUHSMode == eUHSMode )
681     {
682         return AM_HAL_STATUS_SUCCESS;
683     }
684 
685     if ( eUHSMode == AM_HAL_HOST_UHS_DDR50 )
686     {
687         if (pCard->eType == AM_HAL_CARD_TYPE_EMMC || pCard->eType == AM_HAL_CARD_TYPE_MMC)
688         {
689             //
690             // Card does not support DDR52 mode
691             //
692             if ((pCard->ui8DeviceType & HS_DDR_52MHZ_18_3V) == 0x0)
693             {
694                 return AM_HAL_STATUS_FAIL;
695             }
696 
697             if (pHost->ops->set_uhs_mode)
698             {
699                 return pHost->ops->set_uhs_mode(pHost->pHandle, eUHSMode);
700             }
701         }
702         else
703         {
704             if (pHost->ops->set_uhs_mode)
705             {
706                 return pHost->ops->set_uhs_mode(pHost->pHandle, eUHSMode);
707             }
708         }
709     }
710     else
711     {
712         if (pCard->eType == AM_HAL_CARD_TYPE_EMMC || pCard->eType == AM_HAL_CARD_TYPE_MMC)
713         {
714             if (pHost->ops->set_uhs_mode)
715             {
716                 return pHost->ops->set_uhs_mode(pHost->pHandle, AM_HAL_HOST_UHS_NONE);
717             }
718         }
719         else
720         {
721             if (pHost->ops->set_uhs_mode)
722             {
723                 return pHost->ops->set_uhs_mode(pHost->pHandle, eUHSMode);
724             }
725         }
726     }
727 
728     return AM_HAL_STATUS_SUCCESS;
729 }
730 
731 static uint32_t
am_hal_card_set_voltage(am_hal_card_t * pCard,am_hal_host_bus_voltage_e eBusVoltage)732 am_hal_card_set_voltage(am_hal_card_t *pCard, am_hal_host_bus_voltage_e eBusVoltage)
733 {
734     am_hal_card_host_t *pHost;
735 
736 #ifndef AM_HAL_DISABLE_API_VALIDATION
737 
738     if ( !pCard || !pCard->pHost )
739     {
740         return AM_HAL_STATUS_INVALID_ARG;
741     }
742 
743 #endif // AM_HAL_DISABLE_API_VALIDATION
744 
745     pHost = pCard->pHost;
746 
747     if ( eBusVoltage != pHost->eBusVoltage )
748     {
749         if ( pHost->ops->set_bus_voltage(pHost->pHandle, eBusVoltage) != AM_HAL_STATUS_SUCCESS )
750         {
751             return AM_HAL_STATUS_FAIL;
752         }
753     }
754 
755     return AM_HAL_STATUS_SUCCESS;
756 }
757 
758 #define ENABLE_SDR_96MHZ
759 
760 #define MMC_LEGACY_HS 26000000
761 #define MMC_SDR_HS    52000000
762 #define MMC_DDR_HS    52000000
763 #define MMC_HS200    200000000
764 
765 //
766 // apollo4 SDHC speed limitation settings
767 //
768 #define MMC_HS200_MAX_SPEED_LIMIT 96000000
769 #define MMC_HS_MAX_SPEED_LIMIT 48000000
770 
771 static uint32_t
am_hal_card_set_speed(am_hal_card_t * pCard,uint32_t ui32Clock)772 am_hal_card_set_speed(am_hal_card_t *pCard, uint32_t ui32Clock)
773 {
774     uint32_t ui32Status;
775     uint32_t ui32Mode;
776     uint32_t ui32HSMode = 1;
777     am_hal_card_host_t *pHost;
778 
779 #ifndef AM_HAL_DISABLE_API_VALIDATION
780 
781     if ( !pCard || !pCard->pHost )
782     {
783         return AM_HAL_STATUS_INVALID_ARG;
784     }
785 
786 #endif // AM_HAL_DISABLE_API_VALIDATION
787 
788     pHost = pCard->pHost;
789 
790 #ifdef ENABLE_SDR_96MHZ
791     if ((pCard->cfg.eUHSMode == AM_HAL_HOST_UHS_SDR104) &&
792         (ui32Clock > MMC_HS_MAX_SPEED_LIMIT) &&
793         (ui32Clock <= MMC_HS200_MAX_SPEED_LIMIT))
794     {
795         ui32HSMode = 2;
796     }
797 #endif
798 
799     if ( (pCard->ui8SpecVer >= 4) && (ui32Clock >= MMC_LEGACY_HS) )
800     {
801         //
802         // Already in the high speed mode
803         //
804         if ( am_hal_unstuff_bytes(pCard->ui32ExtCSD, 185, 1) != ui32HSMode )
805         {
806             //
807             // 0x03B90100
808             //
809             ui32Mode = MMC_EXT_MODE_WRITE_BYTE | MMC_EXT_REGS_HIGH_SPEED | (ui32HSMode << 8);
810             if ( (ui32Status = am_hal_card_mode_switch(pCard, ui32Mode, DEFAULT_CMD6_TIMEOUT_MS)) != AM_HAL_STATUS_SUCCESS )
811             {
812                 return ui32Status;
813             }
814 
815             //
816             // read back the ext_csd and check 'HS_TIMING' is set or not
817             //
818             if ( am_hal_sdmmc_cmd8_send_ext_csd(pCard) != AM_HAL_CMD_ERR_NONE )
819             {
820                 return AM_HAL_STATUS_FAIL;
821             }
822 
823             if ( am_hal_unstuff_bytes(pCard->ui32ExtCSD, 185, 1) != ui32HSMode )
824             {
825                 AM_HAL_CARD_DEBUG("%d - Failed to switch to high speed mode\n", __FUNCTION__);
826                 return AM_HAL_STATUS_FAIL;
827             }
828         }
829     }
830 
831     if ( pHost->ops->set_bus_clock(pHost->pHandle, ui32Clock) != AM_HAL_STATUS_SUCCESS )
832     {
833         return AM_HAL_STATUS_FAIL;
834     }
835 
836     return AM_HAL_STATUS_SUCCESS;
837 }
838 
839 //
840 // Static helper function:
841 //  Count the longest consecutive 1s in a 32bit word
842 //
843 static uint32_t
count_consecutive_ones(uint32_t * pVal)844 count_consecutive_ones(uint32_t* pVal)
845 {
846     uint32_t count = 0;
847     uint32_t data = *pVal;
848 
849     while ( data )
850     {
851         data = (data & (data << 1));
852         count++;
853     }
854     return count;
855 }
856 
857 //
858 // Static helper function:
859 //  Find and return the mid point of the longest continuous 1s in a 32bit word
860 //
861 static uint32_t
find_mid_point(uint32_t * pVal)862 find_mid_point(uint32_t* pVal)
863 {
864     uint32_t pattern_len = 0;
865     uint32_t max_len = 0;
866     uint32_t pick_point = 0;
867     bool pattern_start = false;
868     uint32_t val = *pVal;
869 
870     for ( uint32_t i = 0; i < 32; i++ )
871     {
872         if ( val & (0x01 << i) )
873         {
874             pattern_start = true;
875             pattern_len++;
876         }
877         else
878         {
879             if ( pattern_start == true )
880             {
881                 pattern_start = false;
882                 if ( pattern_len > max_len )
883                 {
884                     max_len = pattern_len;
885                     pick_point = i - 1 - pattern_len / 2;
886                 }
887                 pattern_len = 0;
888             }
889         }
890     }
891 
892     return pick_point;
893 }
894 
895 uint32_t
am_hal_card_emmc_calibrate(am_hal_host_uhs_mode_e eUHSMode,uint32_t ui32Clock,am_hal_host_bus_width_e eBusWidth,uint8_t * ui8CalibBuf,uint32_t ui32StartBlk,uint32_t ui32BlkCnt,uint8_t ui8TxRxDelays[2])896 am_hal_card_emmc_calibrate(am_hal_host_uhs_mode_e eUHSMode,
897                            uint32_t ui32Clock,
898                            am_hal_host_bus_width_e eBusWidth,
899                            uint8_t *ui8CalibBuf,
900                            uint32_t ui32StartBlk,
901                            uint32_t ui32BlkCnt,
902                            uint8_t ui8TxRxDelays[2])
903 {
904     am_hal_card_t eMMCard;
905     am_hal_card_host_t *pSdhcCardHost;
906 
907     uint32_t i;
908     uint32_t len = ui32BlkCnt*512;
909     uint8_t  ui8TxDelay = 0;
910     uint8_t  ui8RxDelay = 0;
911     uint32_t ui32TxResult = 0;
912     uint32_t ui32RxResultArray[16] = {0};
913 
914 #ifdef AM_DEBUG_PRINTF
915     if (eUHSMode == AM_HAL_HOST_UHS_DDR50)
916     {
917         AM_HAL_CARD_DEBUG("eMMC Timing Scan for DDR %d Hz %d bit mode...\n", ui32Clock, eBusWidth);
918     }
919     else
920     {
921         AM_HAL_CARD_DEBUG("eMMC Timing Scan for SDR %d Hz %d bit mode...\n", ui32Clock, eBusWidth);
922     }
923 #endif
924 
925     for (int j = 0; j < 16; j++)
926     {
927         for (int k = 0; k < 32; k++)
928         {
929             //
930             // Get the uderlying SDHC card host instance
931             //
932             pSdhcCardHost = am_hal_get_card_host(AM_HAL_SDHC_CARD_HOST, true);
933 
934             if (pSdhcCardHost == NULL)
935             {
936                 AM_HAL_CARD_DEBUG("No such card host and stop\n");
937                 return AM_HAL_STATUS_FAIL;
938             }
939 
940             ui8TxRxDelays[0] = j;
941             ui8TxRxDelays[1] = k;
942             AM_HAL_CARD_DEBUG("Test TX delay setting SDIOOTAPDLYSEL = %d, RX delay setting SDIOITAPDLYSEL = %d\n", j, k);
943             am_hal_card_host_set_txrx_delay(pSdhcCardHost, ui8TxRxDelays);
944 
945             //
946             // check if card is present
947             //
948             if (am_hal_card_host_find_card(pSdhcCardHost, &eMMCard) != AM_HAL_STATUS_SUCCESS)
949             {
950                 AM_HAL_CARD_DEBUG("No card is present now\n");
951                 return AM_HAL_STATUS_FAIL;
952             }
953 
954             if (am_hal_card_init(&eMMCard, NULL, AM_HAL_CARD_PWR_CTRL_NONE) != AM_HAL_STATUS_SUCCESS)
955             {
956                 AM_HAL_CARD_DEBUG("card initialization failed\n");
957                 return AM_HAL_STATUS_FAIL;
958             }
959 
960             if (am_hal_card_cfg_set(&eMMCard, AM_HAL_CARD_TYPE_EMMC,
961                 eBusWidth, ui32Clock, AM_HAL_HOST_BUS_VOLTAGE_1_8,
962                 eUHSMode) != AM_HAL_STATUS_SUCCESS)
963             {
964                 AM_HAL_CARD_DEBUG("card config failed\n");
965                 continue;
966             }
967 
968             for (i = 0; i < len; i++)
969             {
970                 ui8CalibBuf[i] = i % 256;
971             }
972 
973             am_hal_card_block_write_sync(&eMMCard, ui32StartBlk, ui32BlkCnt, (uint8_t *)ui8CalibBuf);
974 
975             memset((void *)ui8CalibBuf, 0x0, len);
976             am_hal_card_block_read_sync(&eMMCard, ui32StartBlk, ui32BlkCnt, (uint8_t *)ui8CalibBuf);
977 
978             for (i = 0; i < len; i++)
979             {
980                 if (ui8CalibBuf[i] != i % 256)
981                 {
982                     break;
983                 }
984             }
985 
986             if (i == len)
987             {
988                 ui32RxResultArray[j] |= 0x01 << k;
989                 AM_HAL_CARD_DEBUG("TX Delay SDIOOTAPDLYSEL = %d, RX Delay SDIOITAPDLYSEL = %d works\n", j, k);
990             }
991             else
992             {
993                 AM_HAL_CARD_DEBUG("TX Delay SDIOOTAPDLYSEL = %d, RX Delay SDIOITAPDLYSEL = %d doesn't work\n", j, k);
994             }
995         }
996     }
997 
998 #ifdef AM_DEBUG_PRINTF
999     AM_HAL_CARD_DEBUG("\nSDIO TX RX Delay Scan Result:\n");
1000     for (i = 0; i < 16; i++ )
1001     {
1002         AM_HAL_CARD_DEBUG("TX_Delay = %2d, RX_Delay Window = 0x%08X\n", i, ui32RxResultArray[i]);
1003     }
1004 #endif
1005 
1006     uint32_t ui32Result = 0;
1007     for (i = 0; i < 16; i++ )
1008     {
1009         ui32Result = count_consecutive_ones(&ui32RxResultArray[i]);
1010         if ( ui32Result >= SDIO_TIMING_SCAN_MIN_ACCEPTANCE_LENGTH )
1011         {
1012             ui32TxResult |= 0x01 << i;
1013         }
1014     }
1015 
1016     //
1017     // Check consecutive passing settings
1018     //
1019     if ( ui32TxResult == 0 )
1020     {
1021         //
1022         // No acceptable window
1023         //
1024         return AM_HAL_STATUS_FAIL;
1025     }
1026     else
1027     {
1028         ui32Result = count_consecutive_ones(&ui32TxResult);
1029         if ( ui32Result < SDIO_TIMING_SCAN_MIN_ACCEPTANCE_LENGTH )
1030         {
1031             //
1032             // No acceptable window
1033             //
1034             return AM_HAL_STATUS_FAIL;
1035         }
1036     }
1037 
1038     //
1039     // Find TX Delay Value
1040     //
1041     ui8TxDelay = find_mid_point(&ui32TxResult);
1042 
1043     AM_HAL_CARD_DEBUG("\nSDIO Timing Scan found a RX delay window %X with TX delay Setting = %d.\n", ui32RxResultArray[ui8TxDelay], ui8TxDelay);
1044 
1045     //
1046     // Find RX Delay Value
1047     //
1048     ui8RxDelay = find_mid_point(&ui32RxResultArray[ui8TxDelay]);
1049     ui8TxRxDelays[0] = ui8TxDelay;
1050     ui8TxRxDelays[1] = ui8RxDelay;
1051 
1052     AM_HAL_CARD_DEBUG("Timing Scan set the SDIO TX delay to %d and RX delay to %d.\n", ui8TxDelay, ui8RxDelay);
1053 
1054     //
1055     // Force the card host to reset with the calibration settings
1056     //
1057     pSdhcCardHost = am_hal_get_card_host(AM_HAL_SDHC_CARD_HOST, true);
1058 
1059     if (pSdhcCardHost == NULL)
1060     {
1061         AM_HAL_CARD_DEBUG("No such card host and stop\n");
1062         return AM_HAL_STATUS_FAIL;
1063     }
1064     am_hal_card_host_set_txrx_delay(pSdhcCardHost, ui8TxRxDelays);
1065 
1066     return AM_HAL_STATUS_SUCCESS;
1067 }
1068 
1069 //
1070 // Public functions
1071 //
1072 
1073 //*****************************************************************************
1074 //
1075 // Power off the SDHC or eMMC CARD
1076 //
1077 //*****************************************************************************
1078 uint32_t
am_hal_card_pwrctrl_sleep(am_hal_card_t * pCard)1079 am_hal_card_pwrctrl_sleep(am_hal_card_t *pCard)
1080 {
1081     am_hal_card_host_t *pHost;
1082     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
1083 
1084 #ifndef AM_HAL_DISABLE_API_VALIDATION
1085     if ( !pCard || !pCard->pHost )
1086     {
1087         return AM_HAL_STATUS_INVALID_ARG;
1088     }
1089 #endif // AM_HAL_DISABLE_API_VALIDATION
1090 
1091     pHost = pCard->pHost;
1092 
1093     switch (pCard->eCardPwrCtrlPolicy)
1094     {
1095         case AM_HAL_CARD_PWR_CTRL_SDHC_AND_CARD_OFF:
1096             //
1097             // Flush the cache before power off the eMMC card
1098             //
1099             if ( (ui32Status = am_hal_card_cache_off(pCard)) != AM_HAL_STATUS_SUCCESS )
1100             {
1101                 AM_HAL_CARD_DEBUG("sdhc & card power off - am_hal_card_cache_off Failed\n");
1102                 return ui32Status;
1103             }
1104 
1105             //
1106             // Host is going to power off the device
1107             //
1108             if ((ui32Status = am_hal_card_pwr_notification(pCard, MMC_EXT_CSD_POWER_OFF_LONG)) != AM_HAL_STATUS_SUCCESS)
1109             {
1110                 AM_HAL_CARD_DEBUG("sdhc & card power off - am_hal_card_cache_off Failed\n");
1111                 return ui32Status;
1112             }
1113 
1114             //
1115             // Deselect card
1116             //
1117             if ((ui32Status = am_hal_sdmmc_cmd7_card_deselect(pCard)) != AM_HAL_STATUS_SUCCESS)
1118             {
1119                 AM_HAL_CARD_DEBUG("sdhc & card sleep - Failed to deselect the card\n");
1120                 return AM_HAL_STATUS_FAIL;
1121             }
1122 
1123             //
1124             // Goto Sleep state before power off the card
1125             //
1126             if ( AM_HAL_CMD_ERR_NONE != am_hal_sdmmc_cmd5(pCard, true) )
1127             {
1128                 AM_HAL_CARD_DEBUG("sdhc & card sleep - am_hal_sdmmc_cmd5 Failed\n");
1129                 return AM_HAL_STATUS_FAIL;
1130             }
1131 
1132             //
1133             // Call User Set Callback Function for Power Control
1134             //
1135             if (pCard->pCardPwrCtrlFunc)
1136             {
1137                 pCard->pCardPwrCtrlFunc(AM_HAL_CARD_PWR_OFF);
1138             }
1139 
1140             pCard->eState = AM_HAL_CARD_STATE_PWROFF;
1141 
1142             if ((ui32Status = pHost->ops->deinit(pHost->pHandle)) != AM_HAL_STATUS_SUCCESS)
1143             {
1144                 AM_HAL_CARD_DEBUG("sdhc & card power off - host deinit failed\n");
1145                 return ui32Status;
1146             }
1147             break;
1148 
1149         case AM_HAL_CARD_PWR_CTRL_SDHC_OFF_AND_CARD_SLEEP:
1150 
1151             //
1152             // Flush the cache before power off the eMMC card
1153             //
1154             if ( (ui32Status = am_hal_card_cache_off(pCard)) != AM_HAL_STATUS_SUCCESS )
1155             {
1156                 AM_HAL_CARD_DEBUG("sdhc & card sleep - am_hal_card_cache_off Failed\n");
1157                 return ui32Status;
1158             }
1159 
1160             //
1161             // Host is going to put the device in Sleep Mode
1162             //
1163             if ( (ui32Status = am_hal_card_pwr_notification(pCard, MMC_EXT_CSD_SLEEP_NOTIFICATION)) != AM_HAL_STATUS_SUCCESS )
1164             {
1165                 AM_HAL_CARD_DEBUG("sdhc & card sleep - am_hal_card_pwr_notification Failed\n");
1166                 return ui32Status;
1167             }
1168 
1169             //
1170             // Deselect card
1171             //
1172             if ((ui32Status = am_hal_sdmmc_cmd7_card_deselect(pCard)) != AM_HAL_STATUS_SUCCESS)
1173             {
1174                 AM_HAL_CARD_DEBUG("sdhc & card sleep - Failed to deselect the card\n");
1175                 return AM_HAL_STATUS_FAIL;
1176             }
1177 
1178             //
1179             // Goto Sleep state
1180             //
1181             if ( AM_HAL_CMD_ERR_NONE != am_hal_sdmmc_cmd5(pCard, true) )
1182             {
1183                 AM_HAL_CARD_DEBUG("sdhc & card sleep - am_hal_sdmmc_cmd5 Failed\n");
1184                 return AM_HAL_STATUS_FAIL;
1185             }
1186 
1187             //
1188             // Power off the SDHC controller
1189             //
1190             if ((ui32Status = pHost->ops->pwr_ctrl(pHost->pHandle, false)) != AM_HAL_STATUS_SUCCESS)
1191             {
1192                 AM_HAL_CARD_DEBUG("sdhc & card sleep - emmc card power control failed\n");
1193                 return ui32Status;
1194             }
1195             break;
1196 
1197         case AM_HAL_CARD_PWR_CTRL_SDHC_OFF:
1198             //
1199             // Power off the SDHC controller
1200             //
1201             if ((ui32Status = pHost->ops->pwr_ctrl(pHost->pHandle, false)) != AM_HAL_STATUS_SUCCESS)
1202             {
1203                 AM_HAL_CARD_DEBUG("sdhc - emmc card power control failed\n");
1204                 return ui32Status;
1205             }
1206             break;
1207 
1208         default:
1209             break;
1210 
1211     }
1212 
1213     return AM_HAL_STATUS_SUCCESS;
1214 }
1215 
1216 //*****************************************************************************
1217 //
1218 // Power on the SDHC or eMMC CARD
1219 //
1220 //*****************************************************************************
1221 uint32_t
am_hal_card_pwrctrl_wakeup(am_hal_card_t * pCard)1222 am_hal_card_pwrctrl_wakeup(am_hal_card_t *pCard)
1223 {
1224     uint32_t ui32Status;
1225     am_hal_card_host_t *pHost;
1226 
1227 #ifndef AM_HAL_DISABLE_API_VALIDATION
1228     if ( !pCard || !pCard->pHost )
1229     {
1230         return AM_HAL_STATUS_INVALID_ARG;
1231     }
1232 #endif // AM_HAL_DISABLE_API_VALIDATION
1233 
1234     pHost = pCard->pHost;
1235 
1236     switch (pCard->eCardPwrCtrlPolicy)
1237     {
1238         case AM_HAL_CARD_PWR_CTRL_SDHC_AND_CARD_OFF:
1239             //
1240             // ReInit the SDHC controller
1241             //
1242             if ((ui32Status = pHost->ops->init(pHost)) != AM_HAL_STATUS_SUCCESS)
1243             {
1244                 AM_HAL_CARD_DEBUG("wakeup reinit sdhc controller failed\n");
1245                 return ui32Status;
1246             }
1247 
1248             //
1249             // ReInit the card again
1250             //
1251             if ((ui32Status = am_hal_card_init(pCard,
1252                 pCard->pCardPwrCtrlFunc, pCard->eCardPwrCtrlPolicy)) != AM_HAL_STATUS_SUCCESS)
1253             {
1254                 AM_HAL_CARD_DEBUG("wakeup reinit sd card failed\n");
1255                 return ui32Status;
1256             }
1257 
1258             //
1259             // Reconfig the card with the original settings
1260             //
1261             if ((ui32Status = am_hal_card_cfg_set(pCard, pCard->eType, pCard->cfg.eBusWidth,
1262                 pCard->cfg.ui32Clock, pCard->cfg.eIoVoltage, pCard->cfg.eUHSMode)) != AM_HAL_STATUS_SUCCESS)
1263             {
1264                 AM_HAL_CARD_DEBUG("wakeup configure sd card failed\n");
1265                 return ui32Status;
1266             }
1267             break;
1268 
1269         case AM_HAL_CARD_PWR_CTRL_SDHC_OFF_AND_CARD_SLEEP:
1270             //
1271             // Power on the SDHC controller
1272             //
1273             if ((ui32Status = pHost->ops->pwr_ctrl(pHost->pHandle, true)) != AM_HAL_STATUS_SUCCESS)
1274             {
1275                 AM_HAL_CARD_DEBUG("wakeup - power on the sdhc controller failed\n");
1276                 return ui32Status;
1277             }
1278 
1279             //
1280             // Exit Sleep state
1281             //
1282             if ( AM_HAL_CMD_ERR_NONE != am_hal_sdmmc_cmd5(pCard, false) )
1283             {
1284                 AM_HAL_CARD_DEBUG("wakeup - am_hal_sdmmc_cmd5 Failed\n");
1285                 return AM_HAL_STATUS_FAIL;
1286             }
1287 
1288             //
1289             // Reselect card
1290             //
1291             if ( AM_HAL_CMD_ERR_NONE != am_hal_sdmmc_cmd7_card_select(pCard) )
1292             {
1293                 AM_HAL_CARD_DEBUG("wakeup - am_hal_sdmmc_cmd7_card_select Failed\n");
1294                 return AM_HAL_STATUS_FAIL;
1295             }
1296             break;
1297 
1298         case AM_HAL_CARD_PWR_CTRL_SDHC_OFF:
1299             //
1300             // Power on the SDHC controller
1301             //
1302             if ((ui32Status = pHost->ops->pwr_ctrl(pHost->pHandle, true)) != AM_HAL_STATUS_SUCCESS)
1303             {
1304                 AM_HAL_CARD_DEBUG("wakeup - power on the sdhc controller failed\n");
1305                 return ui32Status;
1306             }
1307             break;
1308 
1309         default:
1310             break;
1311     }
1312 
1313     return AM_HAL_STATUS_SUCCESS;
1314 }
1315 
1316 //*****************************************************************************
1317 //
1318 // Get the card instance function
1319 //
1320 //*****************************************************************************
1321 uint32_t
am_hal_card_host_find_card(am_hal_card_host_t * pHost,am_hal_card_t * pCard)1322 am_hal_card_host_find_card(am_hal_card_host_t *pHost, am_hal_card_t *pCard)
1323 {
1324 
1325 #ifndef AM_HAL_DISABLE_API_VALIDATION
1326 
1327     if ( !pHost || !pCard )
1328     {
1329         return AM_HAL_STATUS_INVALID_ARG;
1330     }
1331 
1332 #endif // AM_HAL_DISABLE_API_VALIDATION
1333 
1334     if ( pHost->bCardInSlot ||
1335         pHost->ops->get_cd(pHost->pHandle) )
1336     {
1337         pCard->eState = AM_HAL_CARD_STATE_PRESENT;
1338         pCard->pHost  = pHost;
1339         //
1340         // Fill the default setting with the host's current value
1341         //
1342         pCard->cfg.eBusWidth = pHost->eBusWidth;
1343         pCard->cfg.eIoVoltage = pHost->eBusVoltage;
1344         pCard->cfg.ui32Clock = pHost->ui32MinClock;
1345         pCard->cfg.eUHSMode = pHost->eUHSMode;
1346         pCard->eState = AM_HAL_CARD_STATE_PWROFF;
1347         return AM_HAL_STATUS_SUCCESS;
1348     }
1349     else
1350     {
1351         pCard->eState = AM_HAL_CARD_STATE_NOT_PRESENT;
1352         return AM_HAL_STATUS_FAIL;
1353     }
1354 }
1355 
1356 //*****************************************************************************
1357 //
1358 // Set the card operation configurations
1359 //
1360 //*****************************************************************************
1361 uint32_t
am_hal_card_cfg_set(am_hal_card_t * pCard,am_hal_card_type_e eType,am_hal_host_bus_width_e eBusWidth,uint32_t ui32Clock,am_hal_host_bus_voltage_e eIoVoltage,am_hal_host_uhs_mode_e eUHSMode)1362 am_hal_card_cfg_set(am_hal_card_t *pCard, am_hal_card_type_e eType,
1363                     am_hal_host_bus_width_e eBusWidth,
1364                     uint32_t ui32Clock,
1365                     am_hal_host_bus_voltage_e eIoVoltage,
1366                     am_hal_host_uhs_mode_e eUHSMode)
1367 {
1368 #ifndef AM_HAL_DISABLE_API_VALIDATION
1369     if ( !pCard || !pCard->pHost )
1370     {
1371         AM_HAL_CARD_DEBUG("This card is not connected to a host\n");
1372         return AM_HAL_STATUS_INVALID_ARG;
1373     }
1374 #endif // AM_HAL_DISABLE_API_VALIDATION
1375 
1376     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
1377     {
1378         return AM_HAL_STATUS_INVALID_OPERATION;
1379     }
1380 
1381     //
1382     // Checking the validation of the clock settings
1383     // Clock should not exceed the capabilities of the SDHC
1384     // DDR mode, max speed is not higer than 48MHz
1385     // SDR mode, max speed is not higer than 96MHz
1386     // Legacy card, max speed is not higher than 26MHz
1387     //
1388     if ((ui32Clock > pCard->pHost->ui32MaxClock) || (ui32Clock < pCard->pHost->ui32MinClock) ||
1389         ((eUHSMode == AM_HAL_HOST_UHS_DDR50) && (ui32Clock > MMC_HS_MAX_SPEED_LIMIT)) ||
1390         ((eUHSMode == AM_HAL_HOST_UHS_NONE) && (ui32Clock > MMC_HS200_MAX_SPEED_LIMIT)) ||
1391         ((ui32Clock > MMC_LEGACY_HS) && (pCard->ui8SpecVer < 4)))
1392     {
1393         return AM_HAL_STATUS_INVALID_ARG;
1394     }
1395 
1396     pCard->eType = eType;
1397     pCard->cfg.eBusWidth = eBusWidth;
1398     pCard->cfg.ui32Clock = ui32Clock;
1399     pCard->cfg.eIoVoltage = eIoVoltage;
1400     pCard->cfg.eUHSMode = eUHSMode;
1401 
1402     if (am_hal_card_set_voltage(pCard, pCard->cfg.eIoVoltage) != AM_HAL_STATUS_SUCCESS )
1403     {
1404         AM_HAL_CARD_DEBUG("Failed to change bus voltage\n");
1405         return AM_HAL_STATUS_FAIL;
1406     }
1407 
1408     if ( eUHSMode == AM_HAL_HOST_UHS_SDR104 )
1409     {
1410         //
1411         // Configure the card bus width
1412         //
1413         if ( am_hal_card_set_bus_width(pCard, pCard->cfg.eBusWidth) != AM_HAL_STATUS_SUCCESS )
1414         {
1415             AM_HAL_CARD_DEBUG("Failed to change bus width\n");
1416             return AM_HAL_STATUS_FAIL;
1417         }
1418 
1419         //
1420         // Configure the card bus speed
1421         //
1422         if ( am_hal_card_set_speed(pCard, pCard->cfg.ui32Clock) != AM_HAL_STATUS_SUCCESS )
1423         {
1424             AM_HAL_CARD_DEBUG("Failed to change bus speed\n");
1425             return AM_HAL_STATUS_FAIL;
1426         }
1427     }
1428     else
1429     {
1430         //
1431         // Configure the card bus speed
1432         //
1433         if ( am_hal_card_set_speed(pCard, pCard->cfg.ui32Clock) != AM_HAL_STATUS_SUCCESS )
1434         {
1435             AM_HAL_CARD_DEBUG("Failed to change bus speed\n");
1436             return AM_HAL_STATUS_FAIL;
1437         }
1438 
1439         //
1440         // Configure the card bus width
1441         //
1442         if ( am_hal_card_set_bus_width(pCard, pCard->cfg.eBusWidth) != AM_HAL_STATUS_SUCCESS )
1443         {
1444             AM_HAL_CARD_DEBUG("Failed to change bus width\n");
1445             return AM_HAL_STATUS_FAIL;
1446         }
1447     }
1448 
1449     //
1450     // Select the UHS mode
1451     //
1452     if (am_hal_card_set_uhs_mode(pCard, pCard->cfg.eUHSMode) != AM_HAL_STATUS_SUCCESS)
1453     {
1454         AM_HAL_CARD_DEBUG("Failed to change UHS mode\n");
1455         return AM_HAL_STATUS_FAIL;
1456     }
1457 
1458     return AM_HAL_STATUS_SUCCESS;
1459 }
1460 
1461 //*****************************************************************************
1462 //
1463 // Initialize the card instance function
1464 //
1465 //*****************************************************************************
1466 uint32_t
am_hal_card_init(am_hal_card_t * pCard,am_hal_card_pwr_ctrl_func pCardPwrCtrlFunc,am_hal_card_pwr_ctrl_policy_e eCardPwrCtrlPolicy)1467 am_hal_card_init(am_hal_card_t *pCard,
1468                  am_hal_card_pwr_ctrl_func pCardPwrCtrlFunc,
1469                  am_hal_card_pwr_ctrl_policy_e eCardPwrCtrlPolicy)
1470 {
1471 #ifndef AM_HAL_DISABLE_API_VALIDATION
1472     if ( !pCard || !pCard->pHost )
1473     {
1474         AM_HAL_CARD_DEBUG("This card is not connected to a host\n");
1475         return AM_HAL_STATUS_INVALID_ARG;
1476     }
1477 #endif // AM_HAL_DISABLE_API_VALIDATION
1478 
1479     //
1480     // Turn on the eMMC card power supply firstly
1481     //
1482     if (pCard->eState == AM_HAL_CARD_STATE_PWROFF && pCardPwrCtrlFunc != NULL)
1483     {
1484         AM_HAL_CARD_DEBUG("turn on the eMMC power supply\n");
1485         pCardPwrCtrlFunc(AM_HAL_CARD_PWR_ON);
1486     }
1487 
1488     pCard->pCardPwrCtrlFunc = pCardPwrCtrlFunc;
1489     pCard->eState = AM_HAL_CARD_STATE_PWRON;
1490     pCard->eCardPwrCtrlPolicy = eCardPwrCtrlPolicy;
1491 
1492     AM_HAL_CARD_DEBUG("card type is %d\n", pCard->eType);
1493 
1494     // Note: remove below code unless 'am_hal_card_type_detect' is finished
1495     pCard->eType = AM_HAL_CARD_TYPE_EMMC;
1496 
1497     switch (pCard->eType)
1498     {
1499         case AM_HAL_CARD_TYPE_UNKNOWN:
1500             if ( am_hal_card_type_detect(pCard) != AM_HAL_STATUS_SUCCESS )
1501             {
1502                 return AM_HAL_STATUS_FAIL;
1503             }
1504             break;
1505         case AM_HAL_CARD_TYPE_MMC:
1506         case AM_HAL_CARD_TYPE_EMMC:
1507             if ( am_hal_card_mmc_init(pCard) != AM_HAL_STATUS_SUCCESS )
1508             {
1509                 return AM_HAL_STATUS_FAIL;
1510             }
1511             break;
1512         case AM_HAL_CARD_TYPE_SDSC:
1513         case AM_HAL_CARD_TYPE_SDHC:
1514         case AM_HAL_CARD_TYPE_SDIO:
1515         case AM_HAL_CARD_TYPE_COMBO:
1516             if ( am_hal_card_sd_init(pCard) != AM_HAL_STATUS_SUCCESS )
1517             {
1518                 return AM_HAL_STATUS_FAIL;
1519             }
1520             break;
1521     }
1522 
1523     return AM_HAL_STATUS_SUCCESS;
1524 }
1525 
1526 //*****************************************************************************
1527 //
1528 // De-Initialize the card instance function
1529 //
1530 //*****************************************************************************
1531 uint32_t
am_hal_card_deinit(am_hal_card_t * pCard)1532 am_hal_card_deinit(am_hal_card_t *pCard)
1533 {
1534 #ifndef AM_HAL_DISABLE_API_VALIDATION
1535     if ( !pCard || !pCard->pHost )
1536     {
1537         AM_HAL_CARD_DEBUG("This card is not connected to a host\n");
1538         return AM_HAL_STATUS_INVALID_ARG;
1539     }
1540 #endif // AM_HAL_DISABLE_API_VALIDATION
1541 
1542     memset((void *)pCard, 0x0, sizeof(am_hal_card_t));
1543 
1544     return AM_HAL_STATUS_SUCCESS;
1545 }
1546 
1547 #ifdef  DSP_RAM1_WORKAROUND
1548 
1549 #define DSP_RAM1_START_ADDR 0x101C4000
1550 #define DSP_RAM1_SIZE       96*1024  // 96KB
1551 
1552 #define DSP_RAM1_TMP_ADDR   DSP_RAM1_START_ADDR
1553 
1554 #endif
1555 
1556 #define ENABLE_SDHC_AUTO_CMD23_FEATURE
1557 
1558 static uint32_t
am_hal_card_block_rw(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,uint8_t * pui8Buf,bool bRead,bool bASync)1559 am_hal_card_block_rw(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, uint8_t *pui8Buf, bool bRead, bool bASync)
1560 {
1561     uint32_t ui32Status;
1562 
1563     am_hal_card_host_t *pHost;
1564     am_hal_card_cmd_t cmd;
1565     am_hal_card_cmd_data_t cmd_data;
1566 
1567 #ifndef AM_HAL_DISABLE_API_VALIDATION
1568 
1569     if ( !pCard || !pCard->pHost )
1570     {
1571         return AM_HAL_STATUS_INVALID_ARG;
1572     }
1573 
1574 #endif // AM_HAL_DISABLE_API_VALIDATION
1575 
1576     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
1577     {
1578         return AM_HAL_STATUS_INVALID_OPERATION;
1579     }
1580 
1581     pHost = pCard->pHost;
1582 
1583     //
1584     // Check if the start block number and block count is valid or not
1585     //
1586     if ( ui32Blk >= pCard->ui32MaxBlks || (ui32BlkCnt > 0xFFFF) || (ui32Blk + ui32BlkCnt) > pCard->ui32MaxBlks )
1587     {
1588         return AM_HAL_STATUS_OUT_OF_RANGE;
1589     }
1590 
1591     if ( pHost->eXferMode == AM_HAL_HOST_XFER_ADMA && ui32BlkCnt > pHost->ui32MaxADMA2BlkNums )
1592     {
1593         ui32BlkCnt = pHost->ui32MaxADMA2BlkNums;
1594     }
1595 
1596 #ifdef DSP_RAM1_WORKAROUND
1597     if (bRead == false)
1598     {
1599         memcpy((void *)DSP_RAM1_TMP_ADDR, pui8Buf, ui32BlkCnt*512);
1600         pui8Buf = (uint8_t *)DSP_RAM1_TMP_ADDR;
1601     }
1602 #endif
1603 
1604 #ifndef ENABLE_SDHC_AUTO_CMD23_FEATURE
1605     //
1606     // Send CMD23 firstly for mulitple blocks transfer
1607     //
1608     memset((void *)&cmd, 0x0, sizeof(cmd));
1609     if ( ui32BlkCnt > 1 )
1610     {
1611         cmd.ui8Idx = MMC_CMD_SET_BLOCK_COUNT;
1612         cmd.ui32Arg = ui32BlkCnt;
1613         cmd.ui32RespType = MMC_RSP_R1;
1614 
1615         if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1616         {
1617             return ui32Status;
1618         }
1619     }
1620 #endif
1621 
1622     memset((void *)&cmd, 0x0, sizeof(cmd));
1623     memset((void *)&cmd_data, 0x0, sizeof(cmd_data));
1624     if ( bRead )
1625     {
1626         cmd.ui8Idx = ui32BlkCnt > 1 ? MMC_CMD_READ_MULTIPLE_BLOCK : MMC_CMD_READ_SINGLE_BLOCK;
1627     }
1628     else
1629     {
1630         cmd.ui8Idx = ui32BlkCnt > 1 ? MMC_CMD_WRITE_MULTIPLE_BLOCK : MMC_CMD_WRITE_SINGLE_BLOCK;
1631     }
1632 
1633     cmd.ui32Arg = pCard->bHighCapcity ? ui32Blk : ui32Blk * pCard->ui32BlkSize;
1634     cmd.ui32RespType = MMC_RSP_R1;
1635     cmd.bASync = bASync;
1636 #ifdef ENABLE_SDHC_AUTO_CMD23_FEATURE
1637     cmd.bAutoCMD23 = ui32BlkCnt > 1 ? true : false;
1638 #endif
1639 
1640     cmd_data.pui8Buf = pui8Buf;
1641     cmd_data.ui32BlkCnt = ui32BlkCnt;
1642     cmd_data.ui32BlkSize = pCard->ui32BlkSize;
1643     cmd_data.dir = bRead ? AM_HAL_DATA_DIR_READ : AM_HAL_DATA_DIR_WRITE;
1644 
1645     if ( cmd.bASync )
1646     {
1647         pHost->AsyncCmd = cmd;
1648         pHost->AsyncCmdData = cmd_data;
1649     }
1650 
1651     ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, &cmd_data);
1652 
1653     return ui32Status;
1654 }
1655 
1656 //*****************************************************************************
1657 //
1658 // synchronous block-oriented read function
1659 //
1660 //*****************************************************************************
1661 uint32_t
am_hal_card_block_read_sync(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,uint8_t * pui8Buf)1662 am_hal_card_block_read_sync(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, uint8_t *pui8Buf)
1663 {
1664     return am_hal_card_block_rw(pCard, ui32Blk, ui32BlkCnt, pui8Buf, true, false);
1665 }
1666 
1667 //*****************************************************************************
1668 //
1669 // synchronous block-oriented write function
1670 //
1671 //*****************************************************************************
1672 uint32_t
am_hal_card_block_write_sync(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,uint8_t * pui8Buf)1673 am_hal_card_block_write_sync(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, uint8_t *pui8Buf)
1674 {
1675     return am_hal_card_block_rw(pCard, ui32Blk, ui32BlkCnt, pui8Buf, false, false);
1676 }
1677 
1678 //*****************************************************************************
1679 //
1680 // asynchronous block-oriented read function
1681 //
1682 //*****************************************************************************
1683 uint32_t
am_hal_card_block_read_async(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,uint8_t * pui8Buf)1684 am_hal_card_block_read_async(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, uint8_t *pui8Buf)
1685 {
1686     return am_hal_card_block_rw(pCard, ui32Blk, ui32BlkCnt, pui8Buf, true, true);
1687 }
1688 
1689 //*****************************************************************************
1690 //
1691 // asynchronous block-oriented write function
1692 //
1693 //*****************************************************************************
1694 uint32_t
am_hal_card_block_write_async(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,uint8_t * pui8Buf)1695 am_hal_card_block_write_async(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, uint8_t *pui8Buf)
1696 {
1697     return am_hal_card_block_rw(pCard, ui32Blk, ui32BlkCnt, pui8Buf, false, true);
1698 }
1699 
1700 //*****************************************************************************
1701 //
1702 // block-oriented erase function
1703 //
1704 //*****************************************************************************
1705 uint32_t
am_hal_card_block_erase(am_hal_card_t * pCard,uint32_t ui32Blk,uint32_t ui32BlkCnt,am_hal_card_erase_type_t erasetype,uint32_t ui32TimeoutMS)1706 am_hal_card_block_erase(am_hal_card_t *pCard, uint32_t ui32Blk, uint32_t ui32BlkCnt, am_hal_card_erase_type_t erasetype, uint32_t ui32TimeoutMS)
1707 {
1708     uint32_t ui32Status;
1709     am_hal_card_host_t *pHost;
1710     am_hal_card_cmd_t cmd;
1711 
1712 #ifndef AM_HAL_DISABLE_API_VALIDATION
1713 
1714     if ( !pCard || !pCard->pHost )
1715     {
1716         return AM_HAL_STATUS_INVALID_ARG;
1717     }
1718 
1719 #endif // AM_HAL_DISABLE_API_VALIDATION
1720 
1721     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
1722     {
1723         return AM_HAL_STATUS_INVALID_OPERATION;
1724     }
1725 
1726     //
1727     // Check if the start block number and block count is valid or not
1728     //
1729     if ( ui32Blk >= pCard->ui32MaxBlks || ui32Blk + ui32BlkCnt > pCard->ui32MaxBlks )
1730     {
1731         return AM_HAL_STATUS_OUT_OF_RANGE;
1732     }
1733 
1734     if ( erasetype == AM_HAL_SECURE_ERASE || erasetype == AM_HAL_SECURE_TRIM1 || erasetype == AM_HAL_SECURE_TRIM2 )
1735     {
1736         if ( !(pCard->ui8SecureErase & SEC_ER_EN) )
1737         {
1738             AM_HAL_CARD_DEBUG("This device does not support Secure Erase or Trim\n");
1739             return AM_HAL_STATUS_INVALID_ARG;
1740         }
1741     }
1742 
1743     if ( erasetype == AM_HAL_TRIM || erasetype == AM_HAL_SECURE_TRIM1 || erasetype == AM_HAL_SECURE_TRIM2 )
1744     {
1745         if ( !(pCard->ui8SecureErase & SEC_GB_CL_EN) )
1746         {
1747             AM_HAL_CARD_DEBUG("This device does not support Trim operation\n");
1748             return AM_HAL_STATUS_INVALID_ARG;
1749         }
1750     }
1751 
1752     pHost = pCard->pHost;
1753 
1754     //
1755     // Define the erase start address
1756     //
1757     memset((void *)&cmd, 0x0, sizeof(cmd));
1758     cmd.ui8Idx = MMC_CMD_ERASE_GROUP_START;
1759     cmd.ui32Arg = pCard->bHighCapcity ? ui32Blk : ui32Blk * pCard->ui32BlkSize;
1760     cmd.ui32RespType = MMC_RSP_R1;
1761 
1762     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1763     {
1764         return ui32Status;
1765     }
1766 
1767     //
1768     // Define the erase end address
1769     //
1770     memset((void *)&cmd, 0x0, sizeof(cmd));
1771     cmd.ui8Idx = MMC_CMD_ERASE_GROUP_END;
1772     cmd.ui32Arg = pCard->bHighCapcity ? (ui32Blk + ui32BlkCnt - 1) : (ui32Blk + ui32BlkCnt - 1) * pCard->ui32BlkSize;
1773     cmd.ui32RespType = MMC_RSP_R1;
1774 
1775     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1776     {
1777         return ui32Status;
1778     }
1779 
1780     //
1781     // Do the erase job
1782     //
1783     memset((void *)&cmd, 0x0, sizeof(cmd));
1784     cmd.bCheckBusyCmd = true;
1785     cmd.ui8Idx = MMC_CMD_ERASE;
1786     cmd.ui32Arg = (uint32_t)erasetype;
1787     cmd.ui32RespType = MMC_RSP_R1b;
1788 
1789     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1790     {
1791         return ui32Status;
1792     }
1793 
1794     return pHost->ops->card_busy(pHost->pHandle, ui32TimeoutMS);
1795 }
1796 
1797 //*****************************************************************************
1798 //
1799 // Get the card status function
1800 //
1801 //*****************************************************************************
1802 uint32_t
am_hal_card_status(am_hal_card_t * pCard,uint32_t * pui32Status)1803 am_hal_card_status(am_hal_card_t *pCard, uint32_t *pui32Status)
1804 {
1805     uint32_t ui32Status;
1806     am_hal_card_cmd_t cmd;
1807 
1808 #ifndef AM_HAL_DISABLE_API_VALIDATION
1809 
1810     if ( !pCard || !pCard->pHost )
1811     {
1812         return AM_HAL_STATUS_INVALID_ARG;
1813     }
1814 
1815 #endif // AM_HAL_DISABLE_API_VALIDATION
1816 
1817     if ( pCard->eState < AM_HAL_CARD_STATE_STDY )
1818     {
1819         return AM_HAL_STATUS_INVALID_OPERATION;
1820     }
1821 
1822     am_hal_card_host_t *pHost = pCard->pHost;
1823 
1824     memset(&cmd, 0, sizeof(cmd));
1825     cmd.ui8Idx = MMC_CMD_SEND_STATUS;
1826     cmd.ui32Arg = pCard->ui8RCA << 16;
1827     cmd.ui32RespType = MMC_RSP_R1;
1828 
1829     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1830     {
1831         return ui32Status;
1832     }
1833 
1834     if ( cmd.eError == AM_HAL_CMD_ERR_NONE )
1835     {
1836         *pui32Status = cmd.ui32Resp[0];
1837     }
1838 
1839     return ui32Status;
1840 }
1841 
1842 //*****************************************************************************
1843 //
1844 // Get the card state function
1845 //
1846 //*****************************************************************************
am_hal_card_state(am_hal_card_t * pCard)1847 am_hal_card_state_e am_hal_card_state(am_hal_card_t *pCard)
1848 {
1849     uint32_t ui32Status = 0;
1850     uint32_t ui32State;
1851 
1852 #ifndef AM_HAL_DISABLE_API_VALIDATION
1853 
1854     if ( !pCard || !pCard->pHost )
1855     {
1856         return AM_HAL_CARD_STATE_ERROR;
1857     }
1858 
1859 #endif // AM_HAL_DISABLE_API_VALIDATION
1860 
1861     if ( am_hal_card_status(pCard, &ui32Status) != AM_HAL_STATUS_SUCCESS )
1862     {
1863         return AM_HAL_CARD_STATE_ERROR;
1864     }
1865     else
1866     {
1867         ui32State = ui32Status >> 9 & 0xF;
1868         if ( ui32State <= 10 )
1869         {
1870             pCard->eState = (am_hal_card_state_e)(ui32State + 2);
1871         }
1872         else
1873         {
1874             return AM_HAL_CARD_STATE_ERROR;
1875         }
1876     }
1877 
1878     return pCard->eState;
1879 }
1880 
1881 //*****************************************************************************
1882 //
1883 // CMD6 - Mode switch
1884 //
1885 //*****************************************************************************
1886 uint32_t
am_hal_card_mode_switch(am_hal_card_t * pCard,uint32_t ui32Mode,uint32_t ui32Timeout)1887 am_hal_card_mode_switch(am_hal_card_t *pCard, uint32_t ui32Mode, uint32_t ui32Timeout)
1888 {
1889     uint32_t ui32Status;
1890     uint32_t ui32CardStatus;
1891     am_hal_card_cmd_t cmd;
1892 
1893 #ifndef AM_HAL_DISABLE_API_VALIDATION
1894 
1895     if ( !pCard || !pCard->pHost )
1896     {
1897         return AM_HAL_STATUS_INVALID_ARG;
1898     }
1899 
1900 #endif // AM_HAL_DISABLE_API_VALIDATION
1901 
1902     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
1903     {
1904         return AM_HAL_STATUS_INVALID_OPERATION;
1905     }
1906 
1907     am_hal_card_host_t *pHost = pCard->pHost;
1908 
1909     memset(&cmd, 0, sizeof(cmd));
1910     cmd.ui8Idx = MMC_CMD_SWITCH;
1911     cmd.ui32Arg = ui32Mode;
1912     pCard->bExtCsdValid = 0;
1913 
1914     if ( pCard->eType == AM_HAL_CARD_TYPE_MMC || pCard->eType == AM_HAL_CARD_TYPE_EMMC )
1915     {
1916         cmd.bCheckBusyCmd = true;
1917         cmd.ui32RespType = MMC_RSP_R1b;
1918     }
1919     else
1920     {
1921         cmd.ui32RespType = MMC_RSP_R1;
1922     }
1923 
1924     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
1925     {
1926         return ui32Status;
1927     }
1928 
1929     if ( pCard->eType == AM_HAL_CARD_TYPE_MMC || pCard->eType == AM_HAL_CARD_TYPE_EMMC )
1930     {
1931         if ((ui32Status = pHost->ops->card_busy(pHost->pHandle, 10)) != AM_HAL_STATUS_SUCCESS)
1932         {
1933             return ui32Status;
1934         }
1935     }
1936 
1937     ui32CardStatus = 0x0;
1938 
1939     do
1940     {
1941         ui32Status = am_hal_card_status(pCard, &ui32CardStatus);
1942         if (ui32Status == AM_HAL_STATUS_SUCCESS && (ui32CardStatus & MMC_STATUS_SWITCH_ERROR))
1943         {
1944             AM_HAL_CARD_DEBUG("switch failed - mode is 0x%x !\n", ui32Mode);
1945             return AM_HAL_STATUS_FAIL;
1946         }
1947         if (ui32Status == AM_HAL_STATUS_SUCCESS && (ui32CardStatus & MMC_STATUS_RDY_FOR_DATA))
1948         {
1949             AM_HAL_CARD_DEBUG("switch succeeded - mode is 0x%x !\n", ui32Mode);
1950             return AM_HAL_STATUS_SUCCESS;
1951         }
1952         am_util_delay_ms(1);
1953     } while (ui32Timeout--);
1954 
1955     return ui32Timeout ? AM_HAL_STATUS_SUCCESS : AM_HAL_STATUS_FAIL;
1956 }
1957 
1958 //*****************************************************************************
1959 //
1960 // Read blocks of data from the card (GEN_CMD)
1961 //
1962 //*****************************************************************************
1963 static uint32_t
am_hal_card_cmd56_read(am_hal_card_t * pCard,uint32_t ui32Arg,uint8_t * pui8Buf,bool bASync)1964 am_hal_card_cmd56_read(am_hal_card_t *pCard, uint32_t ui32Arg, uint8_t *pui8Buf, bool bASync)
1965 {
1966     uint32_t ui32Status;
1967 
1968     am_hal_card_host_t *pHost;
1969     am_hal_card_cmd_t cmd;
1970     am_hal_card_cmd_data_t cmd_data;
1971 
1972 #ifndef AM_HAL_DISABLE_API_VALIDATION
1973 
1974     if ( !pCard || !pCard->pHost )
1975     {
1976         return AM_HAL_STATUS_INVALID_ARG;
1977     }
1978 
1979 #endif // AM_HAL_DISABLE_API_VALIDATION
1980 
1981     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
1982     {
1983         return AM_HAL_STATUS_INVALID_OPERATION;
1984     }
1985 
1986     pHost = pCard->pHost;
1987 
1988     memset((void *)&cmd, 0x0, sizeof(cmd));
1989     cmd.ui8Idx = MMC_CMD_CMD56;
1990     cmd.ui32Arg = ui32Arg;
1991     cmd.ui32RespType = MMC_RSP_R1;
1992     cmd.bASync = bASync;
1993 
1994     memset((void *)&cmd_data, 0x0, sizeof(cmd_data));
1995     cmd_data.pui8Buf = pui8Buf;
1996     cmd_data.ui32BlkCnt = 1;
1997     cmd_data.ui32BlkSize = 512;
1998     cmd_data.dir = AM_HAL_DATA_DIR_READ;
1999 
2000     if ( cmd.bASync )
2001     {
2002         pHost->AsyncCmd = cmd;
2003         pHost->AsyncCmdData = cmd_data;
2004     }
2005 
2006     ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, &cmd_data);
2007 
2008     return ui32Status;
2009 }
2010 
2011 //*****************************************************************************
2012 //
2013 // Read blocks of data from the card (GEN_CMD) asynchronously
2014 //
2015 //*****************************************************************************
2016 uint32_t
am_hal_card_cmd56_read_async(am_hal_card_t * pCard,uint32_t ui32Arg,uint8_t * pui8Buf)2017 am_hal_card_cmd56_read_async(am_hal_card_t *pCard, uint32_t ui32Arg, uint8_t *pui8Buf)
2018 {
2019     return am_hal_card_cmd56_read(pCard, ui32Arg, pui8Buf, true);
2020 }
2021 
2022 //*****************************************************************************
2023 //
2024 // Read blocks of data from the card (GEN_CMD) synchronously
2025 //
2026 //*****************************************************************************
2027 uint32_t
am_hal_card_cmd56_read_sync(am_hal_card_t * pCard,uint32_t ui32Arg,uint8_t * pui8Buf)2028 am_hal_card_cmd56_read_sync(am_hal_card_t *pCard, uint32_t ui32Arg, uint8_t *pui8Buf)
2029 {
2030     return am_hal_card_cmd56_read(pCard, ui32Arg, pui8Buf, false);
2031 }
2032 
2033 //*****************************************************************************
2034 //
2035 // register the card event call back function
2036 //
2037 //*****************************************************************************
2038 uint32_t
am_hal_card_register_evt_callback(am_hal_card_t * pCard,am_hal_host_event_cb_t pfunCallback)2039 am_hal_card_register_evt_callback(am_hal_card_t *pCard, am_hal_host_event_cb_t pfunCallback)
2040 {
2041 #ifndef AM_HAL_DISABLE_API_VALIDATION
2042     if ( !pCard || !pCard->pHost )
2043     {
2044         AM_HAL_CARD_DEBUG("both Card and Host are needed to be initialized firstly\n");
2045         return AM_HAL_STATUS_INVALID_ARG;
2046     }
2047 #endif // AM_HAL_DISABLE_API_VALIDATION
2048 
2049     pCard->pHost->pfunEvtCallback = pfunCallback;
2050 
2051     return AM_HAL_STATUS_SUCCESS;
2052 }
2053 
2054 //*****************************************************************************
2055 //
2056 // card cid information parse function
2057 //
2058 //*****************************************************************************
2059 uint32_t
am_hal_card_get_cid_field(am_hal_card_t * pCard,uint16_t ui16Offset,uint8_t ui8Size)2060 am_hal_card_get_cid_field(am_hal_card_t *pCard, uint16_t ui16Offset, uint8_t ui8Size)
2061 {
2062 #ifndef AM_HAL_DISABLE_API_VALIDATION
2063     if ( !pCard || !pCard->bCidValid )
2064     {
2065         return 0xFFFFFFFF;
2066     }
2067 #endif // AM_HAL_DISABLE_API_VALIDATION
2068 
2069     return am_hal_unstuff_bits(pCard->ui32CID, ui16Offset, ui8Size);
2070 
2071 
2072 }
2073 
2074 //*****************************************************************************
2075 //
2076 // card csd information parse function
2077 //
2078 //*****************************************************************************
2079 uint32_t
am_hal_card_get_csd_field(am_hal_card_t * pCard,uint16_t ui16Offset,uint8_t ui8Size)2080 am_hal_card_get_csd_field(am_hal_card_t *pCard, uint16_t ui16Offset, uint8_t ui8Size)
2081 {
2082 #ifndef AM_HAL_DISABLE_API_VALIDATION
2083     if ( !pCard || !pCard->bCsdValid )
2084     {
2085         return 0xFFFFFFFF;
2086     }
2087 #endif // AM_HAL_DISABLE_API_VALIDATION
2088 
2089     return am_hal_unstuff_bits(pCard->ui32CSD, ui16Offset, ui8Size);
2090 
2091 }
2092 
2093 //*****************************************************************************
2094 //
2095 // card ext csd information parse function
2096 //
2097 //*****************************************************************************
2098 uint32_t
am_hal_card_get_ext_csd_field(am_hal_card_t * pCard,uint16_t ui16Offset,uint8_t ui8Size)2099 am_hal_card_get_ext_csd_field(am_hal_card_t *pCard, uint16_t ui16Offset, uint8_t ui8Size)
2100 {
2101 
2102 #ifndef AM_HAL_DISABLE_API_VALIDATION
2103 
2104     if ( !pCard || !pCard->pHost)
2105     {
2106         return 0xFFFFFFFF;
2107     }
2108 
2109 #endif // AM_HAL_DISABLE_API_VALIDATION
2110 
2111     if ( !pCard->bExtCsdValid )
2112     {
2113         if (am_hal_sdmmc_cmd8_send_ext_csd(pCard) != AM_HAL_CMD_ERR_NONE)
2114         {
2115             return 0xFFFFFFFF;
2116         }
2117         pCard->bExtCsdValid = 1;
2118     }
2119 
2120     return am_hal_unstuff_bytes(pCard->ui32ExtCSD, ui16Offset, ui8Size);
2121 
2122 }
2123 
2124 //*****************************************************************************
2125 //
2126 // Get the card information function
2127 //
2128 //*****************************************************************************
2129 uint32_t
am_hal_card_get_info(am_hal_card_t * pCard,am_hal_card_info_t * pCardInfo)2130 am_hal_card_get_info(am_hal_card_t *pCard, am_hal_card_info_t *pCardInfo)
2131 {
2132 #ifndef AM_HAL_DISABLE_API_VALIDATION
2133     if ( !pCard || !pCard->pHost )
2134     {
2135         AM_HAL_CARD_DEBUG("both Card and Host are needed to be initialized firstly\n");
2136         return AM_HAL_STATUS_INVALID_ARG;
2137     }
2138 #endif // AM_HAL_DISABLE_API_VALIDATION
2139 
2140     pCardInfo->eType        = pCard->eType;
2141     pCardInfo->ui16CmdClass = pCard->ui16CmdClass;
2142     pCardInfo->ui8RCA       = pCard->ui8RCA;
2143     pCardInfo->ui32MaxBlks  = pCard->ui32MaxBlks;
2144     pCardInfo->ui32BlkSize  = pCard->ui32BlkSize;
2145     if ( pCard->bHighCapcity )
2146     {
2147         pCardInfo->ui32LogiMaxBlks = pCard->ui32MaxBlks;
2148         pCardInfo->ui32LogiBlkSize = pCard->ui32BlkSize;
2149     }
2150     else
2151     {
2152         pCardInfo->ui32LogiMaxBlks = (pCard->ui32MaxBlks) * ((pCard->ui32BlkSize) / 512);
2153         pCardInfo->ui32LogiBlkSize = 512;
2154     }
2155 
2156     return AM_HAL_STATUS_SUCCESS;
2157 }
2158 
2159 uint32_t
am_hal_card_block_rpmb_rw(am_hal_card_t * pCard,uint8_t * pui8Buf,bool bRead,bool bRelWrite)2160 am_hal_card_block_rpmb_rw(am_hal_card_t *pCard, uint8_t *pui8Buf, bool bRead, bool bRelWrite)
2161 {
2162     uint32_t ui32Status;
2163 
2164     am_hal_card_host_t *pHost;
2165     am_hal_card_cmd_t cmd;
2166     am_hal_card_cmd_data_t cmd_data;
2167 
2168 #ifndef AM_HAL_DISABLE_API_VALIDATION
2169 
2170     if ( !pCard || !pCard->pHost )
2171     {
2172         return AM_HAL_STATUS_INVALID_ARG;
2173     }
2174 
2175 #endif // AM_HAL_DISABLE_API_VALIDATION
2176 
2177     if ( pCard->eState != AM_HAL_CARD_STATE_TRANS )
2178     {
2179         return AM_HAL_STATUS_INVALID_OPERATION;
2180     }
2181 
2182     pHost = pCard->pHost;
2183 
2184     //
2185     // Send CMD23 firstly for mulitple blocks transfer
2186     //
2187     memset((void *)&cmd, 0x0, sizeof(cmd));
2188 
2189     cmd.ui8Idx = MMC_CMD_SET_BLOCK_COUNT;
2190     cmd.ui32RespType = MMC_RSP_R1;
2191     cmd.ui32Arg = 1;
2192 
2193     if ( bRelWrite )
2194     {
2195         cmd.ui32Arg |= ((uint32_t)0x01 << 31);
2196     }
2197 
2198     if ( (ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, NULL)) != AM_HAL_STATUS_SUCCESS )
2199     {
2200         return ui32Status;
2201     }
2202 
2203     memset((void *)&cmd, 0x0, sizeof(cmd));
2204     memset((void *)&cmd_data, 0x0, sizeof(cmd_data));
2205     if ( bRead )
2206     {
2207         cmd.ui8Idx = MMC_CMD_READ_MULTIPLE_BLOCK;
2208     }
2209     else
2210     {
2211         cmd.ui8Idx = MMC_CMD_WRITE_MULTIPLE_BLOCK;
2212     }
2213 
2214     cmd.ui32Arg = 0;
2215     cmd.ui32RespType = MMC_RSP_R1;
2216     cmd.bASync = false;
2217     cmd.bAutoCMD23 = false;
2218 
2219     cmd_data.ui32BlkCnt = 1;
2220     cmd_data.pui8Buf = pui8Buf;
2221     cmd_data.ui32BlkSize = 512;
2222     cmd_data.dir = bRead ? AM_HAL_DATA_DIR_READ : AM_HAL_DATA_DIR_WRITE;
2223 
2224     ui32Status = pHost->ops->execute_cmd(pHost->pHandle, &cmd, &cmd_data);
2225 
2226     return ui32Status;
2227 }
2228 
2229 //*****************************************************************************
2230 //
2231 // End Doxygen group.
2232 //! @}
2233 //
2234 //*****************************************************************************
2235