1 /******************************************************************************
2 * Copyright (C) 2013 - 2020 Xilinx, Inc.  All rights reserved.
3 * SPDX-License-Identifier: MIT
4 ******************************************************************************/
5 
6 /*****************************************************************************/
7 /**
8 *
9 * @file xsdps_card.c
10 * @addtogroup sdps_v3_9
11 * @{
12 *
13 * Contains the interface functions of the XSdPs driver.
14 * See xsdps.h for a detailed description of the device and driver.
15 *
16 * <pre>
17 * MODIFICATION HISTORY:
18 *
19 * Ver   Who    Date     Changes
20 * ----- ---    -------- -----------------------------------------------
21 * 3.9   mn     03/03/20 Restructured the code for more readability and modularity
22 *       mn     03/16/20 Move XSdPs_Select_Card API to User APIs
23 *
24 * </pre>
25 *
26 ******************************************************************************/
27 
28 /***************************** Include Files *********************************/
29 #include "xsdps_core.h"
30 
31 /************************** Constant Definitions *****************************/
32 
33 /**************************** Type Definitions *******************************/
34 
35 /***************** Macros (Inline Functions) Definitions *********************/
36 
37 /************************** Function Prototypes ******************************/
38 
39 /*****************************************************************************/
40 /**
41 * @brief
42 * This function performs SD read in polled mode.
43 *
44 * @param    InstancePtr is a pointer to the instance to be worked on.
45 * @param    Arg is the address passed by the user that is to be sent as
46 *         argument along with the command.
47 * @param    BlkCnt - Block count passed by the user.
48 * @param    Buff - Pointer to the data buffer for a DMA transfer.
49 *
50 * @return
51 *         - XST_SUCCESS if initialization was successful
52 *         - XST_FAILURE if failure - could be because another transfer
53 *         is in progress or command or data inhibit is set
54 *
55 ******************************************************************************/
XSdPs_Read(XSdPs * InstancePtr,u32 Arg,u32 BlkCnt,u8 * Buff)56 s32 XSdPs_Read(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff)
57 {
58     s32 Status;
59     u16 BlkSize;
60 
61     BlkSize = XSDPS_BLK_SIZE_512_MASK;
62 
63     XSdPs_SetupReadDma(InstancePtr, BlkCnt, BlkSize, Buff);
64 
65     if (BlkCnt == 1U) {
66         /* Send single block read command */
67         Status = XSdPs_CmdTransfer(InstancePtr, CMD17, Arg, BlkCnt);
68         if (Status != XST_SUCCESS) {
69             Status = XST_FAILURE;
70             goto RETURN_PATH;
71         }
72     } else {
73         /* Send multiple blocks read command */
74         Status = XSdPs_CmdTransfer(InstancePtr, CMD18, Arg, BlkCnt);
75         if (Status != XST_SUCCESS) {
76             Status = XST_FAILURE;
77             goto RETURN_PATH;
78         }
79     }
80 
81     /* Check for transfer done */
82     Status = XSdps_CheckTransferDone(InstancePtr);
83     if (Status != XST_SUCCESS) {
84         Status = XST_FAILURE;
85     }
86 
87     if (InstancePtr->Config.IsCacheCoherent == 0U) {
88         Xil_DCacheInvalidateRange((INTPTR)Buff,
89                 (INTPTR)BlkCnt * BlkSize);
90     }
91 
92     Status = XST_SUCCESS;
93 
94 RETURN_PATH:
95     return Status;
96 }
97 
98 /*****************************************************************************/
99 /**
100 * @brief
101 * This function performs SD write in polled mode.
102 *
103 * @param    InstancePtr is a pointer to the instance to be worked on.
104 * @param    Arg is the address passed by the user that is to be sent as
105 *         argument along with the command.
106 * @param    BlkCnt - Block count passed by the user.
107 * @param    Buff - Pointer to the data buffer for a DMA transfer.
108 *
109 * @return
110 *         - XST_SUCCESS if initialization was successful
111 *         - XST_FAILURE if failure - could be because another transfer
112 *         is in progress or command or data inhibit is set
113 *
114 ******************************************************************************/
XSdPs_Write(XSdPs * InstancePtr,u32 Arg,u32 BlkCnt,const u8 * Buff)115 s32 XSdPs_Write(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff)
116 {
117     s32 Status;
118     u16 BlkSize;
119 
120     BlkSize = XSDPS_BLK_SIZE_512_MASK;
121 
122     XSdPs_SetupWriteDma(InstancePtr, BlkCnt, BlkSize, Buff);
123 
124     if (BlkCnt == 1U) {
125         /* Send single block write command */
126         Status = XSdPs_CmdTransfer(InstancePtr, CMD24, Arg, BlkCnt);
127         if (Status != XST_SUCCESS) {
128             Status = XST_FAILURE;
129             goto RETURN_PATH;
130         }
131     } else {
132         /* Send multiple blocks write command */
133         Status = XSdPs_CmdTransfer(InstancePtr, CMD25, Arg, BlkCnt);
134         if (Status != XST_SUCCESS) {
135             Status = XST_FAILURE;
136             goto RETURN_PATH;
137         }
138     }
139 
140     /* Check for transfer done */
141     Status = XSdps_CheckTransferDone(InstancePtr);
142     if (Status != XST_SUCCESS) {
143         Status = XST_FAILURE;
144     }
145 
146     Status = XST_SUCCESS;
147 
148     RETURN_PATH:
149         return Status;
150 }
151 /*****************************************************************************/
152 /**
153 *
154 * @brief
155 * Identify type of card using CMD0 + CMD1 sequence
156 *
157 *
158 * @param    InstancePtr is a pointer to the XSdPs instance.
159 *
160 ******************************************************************************/
XSdPs_IdentifyCard(XSdPs * InstancePtr)161 s32 XSdPs_IdentifyCard(XSdPs *InstancePtr)
162 {
163     s32 Status;
164 
165     if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) &&
166             ((InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK)
167             == XSDPS_CAPS_EMB_SLOT)) {
168         InstancePtr->CardType = XSDPS_CHIP_EMMC;
169         Status = XST_SUCCESS;
170         goto RETURN_PATH;
171     }
172 
173     /* 74 CLK delay after card is powered up, before the first command. */
174     usleep(XSDPS_INIT_DELAY);
175 
176     /* CMD0 no response expected */
177     Status = XSdPs_CmdTransfer(InstancePtr, CMD0, 0U, 0U);
178     if (Status != XST_SUCCESS) {
179         Status = XST_FAILURE;
180         goto RETURN_PATH;
181     }
182 
183     /* Host High Capacity support & High voltage window */
184     Status = XSdPs_CmdTransfer(InstancePtr, CMD1,
185             XSDPS_ACMD41_HCS | XSDPS_CMD1_HIGH_VOL, 0U);
186     if (Status != XST_SUCCESS) {
187         InstancePtr->CardType = XSDPS_CARD_SD;
188     } else {
189         InstancePtr->CardType = XSDPS_CARD_MMC;
190     }
191 
192     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
193             XSDPS_NORM_INTR_STS_OFFSET, XSDPS_NORM_INTR_ALL_MASK);
194     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
195             XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK);
196 
197     Status = XSdPs_Reset(InstancePtr, XSDPS_SWRST_CMD_LINE_MASK);
198     if (Status != XST_SUCCESS) {
199         Status = XST_FAILURE;
200         goto RETURN_PATH ;
201     }
202 
203     Status = XST_SUCCESS;
204 
205 RETURN_PATH:
206     return Status;
207 }
208 
209 /*****************************************************************************/
210 /**
211 * @brief
212 * SD initialization is done in this function
213 *
214 *
215 * @param    InstancePtr is a pointer to the instance to be worked on.
216 *
217 * @return
218 *         - XST_SUCCESS if initialization was successful
219 *         - XST_FAILURE if failure - could be because
220 *             a) SD is already initialized
221 *             b) There is no card inserted
222 *             c) One of the steps (commands) in the
223                initialization cycle failed
224 *
225 * @note        This function initializes the SD card by following its
226 *        initialization and identification state diagram.
227 *        CMD0 is sent to reset card.
228 *        CMD8 and ACDM41 are sent to identify voltage and
229 *        high capacity support
230 *        CMD2 and CMD3 are sent to obtain Card ID and
231 *        Relative card address respectively.
232 *        CMD9 is sent to read the card specific data.
233 *
234 ******************************************************************************/
XSdPs_SdCardInitialize(XSdPs * InstancePtr)235 s32 XSdPs_SdCardInitialize(XSdPs *InstancePtr)
236 {
237     s32 Status;
238 
239 #ifndef UHS_MODE_ENABLE
240     InstancePtr->Config.BusWidth = XSDPS_WIDTH_4;
241 #endif
242 
243     Status = XSdPs_SdCardEnum(InstancePtr);
244     if (Status != XST_SUCCESS) {
245         Status = XST_FAILURE;
246         goto RETURN_PATH;
247     }
248 
249     Status = XSdPs_SdModeInit(InstancePtr);
250     if (Status != XST_SUCCESS) {
251         Status = XST_FAILURE;
252         goto RETURN_PATH;
253     }
254 
255     Status = XST_SUCCESS;
256 
257 RETURN_PATH:
258     return Status;
259 
260 }
261 
262 /*****************************************************************************/
263 /**
264 * @brief
265 * Mmc initialization is done in this function
266 *
267 *
268 * @param    InstancePtr is a pointer to the instance to be worked on.
269 *
270 * @return
271 *         - XST_SUCCESS if initialization was successful
272 *         - XST_FAILURE if failure - could be because
273 *             a) MMC is already initialized
274 *             b) There is no card inserted
275 *             c) One of the steps (commands) in the initialization
276 *               cycle failed
277 * @note     This function initializes the SD card by following its
278 *        initialization and identification state diagram.
279 *        CMD0 is sent to reset card.
280 *        CMD1 sent to identify voltage and high capacity support
281 *        CMD2 and CMD3 are sent to obtain Card ID and
282 *        Relative card address respectively.
283 *        CMD9 is sent to read the card specific data.
284 *
285 ******************************************************************************/
XSdPs_MmcCardInitialize(XSdPs * InstancePtr)286 s32 XSdPs_MmcCardInitialize(XSdPs *InstancePtr)
287 {
288     s32 Status;
289 
290     Status = XSdPs_MmcCardEnum(InstancePtr);
291     if (Status != XST_SUCCESS) {
292         Status = XST_FAILURE;
293         goto RETURN_PATH;
294     }
295 
296     if (((InstancePtr->CardType == XSDPS_CARD_MMC) &&
297                 (InstancePtr->Card_Version > CSD_SPEC_VER_3)) &&
298                 (InstancePtr->HC_Version == XSDPS_HC_SPEC_V2)) {
299         Status = XSdPs_MmcModeInit(InstancePtr);
300         if (Status != XST_SUCCESS) {
301             Status = XST_FAILURE;
302             goto RETURN_PATH;
303         }
304     } else if (InstancePtr->CardType == XSDPS_CHIP_EMMC) {
305         Status = XSdPs_EmmcModeInit(InstancePtr);
306         if (Status != XST_SUCCESS) {
307             Status = XST_FAILURE;
308             goto RETURN_PATH;
309         }
310     } else {
311         Status = XST_FAILURE;
312         goto RETURN_PATH;
313 
314     }
315 
316     if (InstancePtr->Mode != XSDPS_DDR52_MODE) {
317         Status = XSdPs_SetBlkSize(InstancePtr, XSDPS_BLK_SIZE_512_MASK);
318         if (Status != XST_SUCCESS) {
319             Status = XST_FAILURE;
320             goto RETURN_PATH;
321         }
322     }
323 
324     Status = XST_SUCCESS;
325 
326 RETURN_PATH:
327     return Status;
328 }
329 
330 /*****************************************************************************/
331 /**
332 * @brief
333 * This function checks if the card is present or not.
334 *
335 * @param    InstancePtr is a pointer to the instance to be worked on.
336 *
337 * @return    None
338 *
339 ******************************************************************************/
XSdPs_CheckCardDetect(XSdPs * InstancePtr)340 s32 XSdPs_CheckCardDetect(XSdPs *InstancePtr)
341 {
342     u32 PresentStateReg;
343     s32 Status;
344 
345     if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) &&
346                 ((InstancePtr->Host_Caps & XSDPS_CAPS_SLOT_TYPE_MASK)
347                 == XSDPS_CAPS_EMB_SLOT)) {
348         Status = XST_SUCCESS;
349         goto RETURN_PATH;
350     }
351 
352     if(InstancePtr->Config.CardDetect != 0U) {
353         /*
354          * Check the present state register to make sure
355          * card is inserted and detected by host controller
356          */
357         PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
358                 XSDPS_PRES_STATE_OFFSET);
359         if ((PresentStateReg & XSDPS_PSR_CARD_INSRT_MASK) == 0U)    {
360             Status = XST_FAILURE;
361             goto RETURN_PATH;
362         }
363     }
364 
365     Status = XST_SUCCESS;
366 
367 RETURN_PATH:
368     return Status;
369 }
370 
371 /*****************************************************************************/
372 /**
373 * @brief
374 * This function sends CMD0 to reset the card.
375 *
376 * @param    InstancePtr is a pointer to the instance to be worked on.
377 *
378 * @return    None
379 *
380 ******************************************************************************/
XSdPs_CardReset(XSdPs * InstancePtr)381 s32 XSdPs_CardReset(XSdPs *InstancePtr)
382 {
383     s32 Status;
384 
385     /* CMD0 no response expected */
386     Status = XSdPs_CmdTransfer(InstancePtr, (u32)CMD0, 0U, 0U);
387     if (Status != XST_SUCCESS) {
388         Status = XST_FAILURE;
389     }
390 
391     return Status;
392 }
393 
394 /*****************************************************************************/
395 /**
396 * @brief
397 * This function sends command to get the card interface details.
398 *
399 * @param    InstancePtr is a pointer to the instance to be worked on.
400 *
401 * @return    None
402 *
403 ******************************************************************************/
XSdPs_CardIfCond(XSdPs * InstancePtr)404 s32 XSdPs_CardIfCond(XSdPs *InstancePtr)
405 {
406     u32 RespOCR;
407     s32 Status;
408 
409     /*
410      * CMD8; response expected
411      * 0x1AA - Supply Voltage 2.7 - 3.6V and AA is pattern
412      */
413     Status = XSdPs_CmdTransfer(InstancePtr, CMD8,
414             XSDPS_CMD8_VOL_PATTERN, 0U);
415     if ((Status != XST_SUCCESS) && (Status != XSDPS_CT_ERROR)) {
416         Status = XST_FAILURE;
417         goto RETURN_PATH;
418     }
419 
420     if (Status == XSDPS_CT_ERROR) {
421         Status = XSdPs_Reset(InstancePtr, XSDPS_SWRST_CMD_LINE_MASK);
422         if (Status != XST_SUCCESS) {
423             Status = XST_FAILURE;
424             goto RETURN_PATH ;
425         }
426     }
427 
428     RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
429                         XSDPS_RESP0_OFFSET);
430     if (RespOCR != XSDPS_CMD8_VOL_PATTERN) {
431         InstancePtr->Card_Version = XSDPS_SD_VER_1_0;
432     } else {
433         InstancePtr->Card_Version = XSDPS_SD_VER_2_0;
434     }
435 
436     Status = XST_SUCCESS;
437 
438 RETURN_PATH:
439     return Status;
440 }
441 
442 /*****************************************************************************/
443 /**
444 * @brief
445 * This function sends command to get the card operating condition.
446 *
447 * @param    InstancePtr is a pointer to the instance to be worked on.
448 *
449 * @return    None
450 *
451 ******************************************************************************/
XSdPs_CardOpCond(XSdPs * InstancePtr)452 s32 XSdPs_CardOpCond(XSdPs *InstancePtr)
453 {
454     u32 RespOCR;
455     s32 Status;
456     u32 Arg;
457 
458     /* Send ACMD41 while card is still busy with power up */
459     do {
460         if (InstancePtr->CardType == XSDPS_CARD_SD) {
461             Status = XSdPs_CmdTransfer(InstancePtr, CMD55, 0U, 0U);
462             if (Status != XST_SUCCESS) {
463                 Status = XST_FAILURE;
464                 goto RETURN_PATH;
465             }
466 
467             Arg = XSDPS_ACMD41_HCS | XSDPS_ACMD41_3V3 | (0x1FFU << 15U);
468             if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) &&
469                 (InstancePtr->Config.BusWidth == XSDPS_WIDTH_8)) {
470                 Arg |= XSDPS_OCR_S18;
471             }
472 
473             /* 0x40300000 - Host High Capacity support & 3.3V window */
474             Status = XSdPs_CmdTransfer(InstancePtr, ACMD41,
475                     Arg, 0U);
476         } else {
477             /* Send CMD1 while card is still busy with power up */
478             Status = XSdPs_CmdTransfer(InstancePtr, CMD1,
479                     XSDPS_ACMD41_HCS | XSDPS_CMD1_HIGH_VOL, 0U);
480         }
481         if (Status != XST_SUCCESS) {
482             Status = XST_FAILURE;
483             goto RETURN_PATH;
484         }
485 
486         /* Response with card capacity */
487         RespOCR = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
488                 XSDPS_RESP0_OFFSET);
489     } while ((RespOCR & XSDPS_RESPOCR_READY) == 0U);
490 
491     /* Update HCS support flag based on card capacity response */
492     if ((RespOCR & XSDPS_ACMD41_HCS) != 0U) {
493         InstancePtr->HCS = 1U;
494     }
495 
496     if ((RespOCR & XSDPS_OCR_S18) != 0U) {
497         InstancePtr->Switch1v8 = 1U;
498         Status = XSdPs_Switch_Voltage(InstancePtr);
499         if (Status != XST_SUCCESS) {
500             Status = XST_FAILURE;
501             goto RETURN_PATH;
502         }
503     }
504 
505     Status = XST_SUCCESS;
506 
507 RETURN_PATH:
508     return Status;
509 }
510 
511 /*****************************************************************************/
512 /**
513 * @brief
514 * This function is used to get the card ID.
515 *
516 * @param    InstancePtr is a pointer to the instance to be worked on.
517 *
518 * @return    None
519 *
520 ******************************************************************************/
XSdPs_GetCardId(XSdPs * InstancePtr)521 s32 XSdPs_GetCardId(XSdPs *InstancePtr)
522 {
523     s32 Status;
524 
525     /* CMD2 for Card ID */
526     Status = XSdPs_CmdTransfer(InstancePtr, CMD2, 0U, 0U);
527     if (Status != XST_SUCCESS) {
528         Status = XST_FAILURE;
529         goto RETURN_PATH;
530     }
531 
532     InstancePtr->CardID[0] =
533             XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
534             XSDPS_RESP0_OFFSET);
535     InstancePtr->CardID[1] =
536             XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
537             XSDPS_RESP1_OFFSET);
538     InstancePtr->CardID[2] =
539             XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
540             XSDPS_RESP2_OFFSET);
541     InstancePtr->CardID[3] =
542             XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
543             XSDPS_RESP3_OFFSET);
544 
545     if(InstancePtr->CardType == XSDPS_CARD_SD) {
546         do {
547             Status = XSdPs_CmdTransfer(InstancePtr, CMD3, 0U, 0U);
548             if (Status != XST_SUCCESS) {
549                 Status = XST_FAILURE;
550                 goto RETURN_PATH;
551             }
552 
553             /*
554              * Relative card address is stored as the upper 16 bits
555              * This is to avoid shifting when sending commands
556              */
557             InstancePtr->RelCardAddr =
558                     XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
559                         XSDPS_RESP0_OFFSET) & 0xFFFF0000U;
560         } while (InstancePtr->RelCardAddr == 0U);
561     } else {
562         /* Set relative card address */
563         InstancePtr->RelCardAddr = 0x12340000U;
564         Status = XSdPs_CmdTransfer(InstancePtr, CMD3, (InstancePtr->RelCardAddr), 0U);
565         if (Status != XST_SUCCESS) {
566             Status = XST_FAILURE;
567             goto RETURN_PATH;
568         }
569     }
570 
571     Status = XST_SUCCESS;
572 
573 RETURN_PATH:
574     return Status;
575 }
576 
577 /*****************************************************************************/
578 /**
579 * @brief
580 * This function is used to get the CSD register from the card.
581 *
582 * @param    InstancePtr is a pointer to the instance to be worked on.
583 *
584 * @return    None
585 *
586 ******************************************************************************/
XSdPs_GetCsd(XSdPs * InstancePtr)587 s32 XSdPs_GetCsd(XSdPs *InstancePtr)
588 {
589     s32 Status;
590     u32 CSD[4];
591     u32 BlkLen;
592     u32 DeviceSize;
593     u32 Mult;
594 
595     Status = XSdPs_CmdTransfer(InstancePtr, CMD9, (InstancePtr->RelCardAddr), 0U);
596     if (Status != XST_SUCCESS) {
597         Status = XST_FAILURE;
598         goto RETURN_PATH;
599     }
600 
601     /*
602      * Card specific data is read.
603      * Currently not used for any operation.
604      */
605     CSD[0] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
606             XSDPS_RESP0_OFFSET);
607     CSD[1] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
608             XSDPS_RESP1_OFFSET);
609     CSD[2] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
610             XSDPS_RESP2_OFFSET);
611     CSD[3] = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
612             XSDPS_RESP3_OFFSET);
613 
614     if (InstancePtr->CardType != XSDPS_CARD_SD) {
615         InstancePtr->Card_Version = (u8)((u32)(CSD[3] & CSD_SPEC_VER_MASK) >>18U);
616         Status = XST_SUCCESS;
617         goto RETURN_PATH;
618     }
619 
620     if (((CSD[3] & CSD_STRUCT_MASK) >> 22U) == 0U) {
621         BlkLen = 1U << ((u32)(CSD[2] & READ_BLK_LEN_MASK) >> 8U);
622         Mult = 1U << ((u32)((CSD[1] & C_SIZE_MULT_MASK) >> 7U) + 2U);
623         DeviceSize = (CSD[1] & C_SIZE_LOWER_MASK) >> 22U;
624         DeviceSize |= (CSD[2] & C_SIZE_UPPER_MASK) << 10U;
625         DeviceSize = (DeviceSize + 1U) * Mult;
626         DeviceSize =  DeviceSize * BlkLen;
627         InstancePtr->SectorCount = (DeviceSize/XSDPS_BLK_SIZE_512_MASK);
628     } else if (((CSD[3] & CSD_STRUCT_MASK) >> 22U) == 1U) {
629         InstancePtr->SectorCount = (((CSD[1] & CSD_V2_C_SIZE_MASK) >> 8U) +
630                                         1U) * 1024U;
631     } else {
632         Status = XST_FAILURE;
633         goto RETURN_PATH;
634     }
635 
636     Status = XST_SUCCESS;
637 
638 RETURN_PATH:
639     return Status;
640 }
641 
642 /*****************************************************************************/
643 /**
644 * @brief
645 * This function is used to set the card voltage to 1.8V.
646 *
647 * @param    InstancePtr is a pointer to the instance to be worked on.
648 *
649 * @return    None
650 *
651 ******************************************************************************/
XSdPs_CardSetVoltage18(XSdPs * InstancePtr)652 s32 XSdPs_CardSetVoltage18(XSdPs *InstancePtr)
653 {
654     s32 Status;
655     u16 CtrlReg;
656     u16 ClockReg;
657 
658     /* Stop the clock */
659     CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
660             XSDPS_CLK_CTRL_OFFSET);
661     CtrlReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK);
662     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,
663             CtrlReg);
664 
665     /* Check for 1.8V signal enable bit is cleared by Host */
666     Status = XSdPs_SetVoltage18(InstancePtr);
667     if (Status != XST_SUCCESS) {
668         Status = XST_FAILURE;
669         goto RETURN_PATH;
670     }
671 
672     ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
673                 XSDPS_CLK_CTRL_OFFSET);
674     /* Enable the clock in the controller */
675     Status = XSdPs_EnableClock(InstancePtr, ClockReg);
676     if (Status != XST_SUCCESS) {
677         Status = XST_FAILURE;
678     }
679 
680     /* Wait for 1mSec */
681     (void)usleep(1000U);
682 
683     Status = XST_SUCCESS;
684 
685 RETURN_PATH:
686     return Status;
687 }
688 
689 /*****************************************************************************/
690 /**
691 * @brief
692 * This function is used to do initial Reset Configuration.
693 *
694 * @param    InstancePtr is a pointer to the instance to be worked on.
695 *
696 * @return    None
697 *
698 ******************************************************************************/
XSdPs_ResetConfig(XSdPs * InstancePtr)699 s32 XSdPs_ResetConfig(XSdPs *InstancePtr)
700 {
701     s32 Status;
702 
703     XSdPs_DisableBusPower(InstancePtr);
704 
705     Status = XSdPs_Reset(InstancePtr, XSDPS_SWRST_ALL_MASK);
706     if (Status != XST_SUCCESS) {
707         Status = XST_FAILURE;
708         goto RETURN_PATH ;
709     }
710 
711     XSdPs_EnableBusPower(InstancePtr);
712 
713 RETURN_PATH:
714     return Status;
715 }
716 
717 /*****************************************************************************/
718 /**
719 * @brief
720 * This function is used to do initial Host Configuration.
721 *
722 * @param    InstancePtr is a pointer to the instance to be worked on.
723 *
724 * @return    None
725 *
726 ******************************************************************************/
XSdPs_HostConfig(XSdPs * InstancePtr)727 void XSdPs_HostConfig(XSdPs *InstancePtr)
728 {
729     XSdPs_ConfigPower(InstancePtr);
730 
731     XSdPs_ConfigDma(InstancePtr);
732 
733     XSdPs_ConfigInterrupt(InstancePtr);
734 
735     /*
736      * Transfer mode register - default value
737      * DMA enabled, block count enabled, data direction card to host(read)
738      */
739     InstancePtr->TransferMode = XSDPS_TM_DMA_EN_MASK | XSDPS_TM_BLK_CNT_EN_MASK |
740             XSDPS_TM_DAT_DIR_SEL_MASK;
741 
742     /* Set block size to 512 by default */
743     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
744             XSDPS_BLK_SIZE_OFFSET, XSDPS_BLK_SIZE_512_MASK);
745 }
746 
747 /*****************************************************************************/
748 /**
749 * @brief
750 * This function checks for Reset Done bits to be cleared after a reset assert.
751 *
752 * @param    InstancePtr is a pointer to the instance to be worked on.
753 * @param    Value is the bits to be checked to be cleared.
754 *
755 * @return    None
756 *
757 ******************************************************************************/
XSdPs_CheckResetDone(XSdPs * InstancePtr,u8 Value)758 s32 XSdPs_CheckResetDone(XSdPs *InstancePtr, u8 Value)
759 {
760     u32 Timeout = 1000000U;
761     u32 ReadReg;
762     s32 Status;
763 
764     /* Proceed with initialization only after reset is complete */
765     do {
766         ReadReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
767                 XSDPS_SW_RST_OFFSET);
768         Timeout = Timeout - 1U;
769         usleep(1);
770     } while (((ReadReg & Value) != 0U)
771             && (Timeout != 0U));
772 
773     if (Timeout == 0U) {
774         Status = XST_FAILURE;
775         goto RETURN_PATH ;
776     }
777 
778     Status = XST_SUCCESS;
779 
780 RETURN_PATH:
781     return Status;
782 }
783 
784 /*****************************************************************************/
785 /**
786 * @brief
787 * This function is used to setup the voltage switch.
788 *
789 * @param    InstancePtr is a pointer to the instance to be worked on.
790 *
791 * @return    None
792 *
793 ******************************************************************************/
XSdPs_SetupVoltageSwitch(XSdPs * InstancePtr)794 s32 XSdPs_SetupVoltageSwitch(XSdPs *InstancePtr)
795 {
796     u32 Timeout = 10000;
797     s32 Status;
798     u32 ReadReg;
799 
800     /* Send switch voltage command */
801     Status = XSdPs_CmdTransfer(InstancePtr, CMD11, 0U, 0U);
802     if (Status != XST_SUCCESS) {
803         Status = XST_FAILURE;
804         goto RETURN_PATH;
805     }
806 
807     /* Wait for CMD and DATA line to go low */
808     do {
809         ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
810                 XSDPS_PRES_STATE_OFFSET);
811         Timeout = Timeout - 1;
812         usleep(1);
813     } while (((ReadReg & (XSDPS_PSR_CMD_SG_LVL_MASK |
814             XSDPS_PSR_DAT30_SG_LVL_MASK)) != 0U)
815             && (Timeout != 0U));
816 
817     if (Timeout == 0U) {
818         Status = XST_FAILURE;
819         goto RETURN_PATH ;
820     }
821 
822 RETURN_PATH:
823     return Status;
824 }
825 
826 /*****************************************************************************/
827 /**
828 * @brief
829 * This function is used to check if the Cmd and Dat buses are high.
830 *
831 * @param    InstancePtr is a pointer to the instance to be worked on.
832 *
833 * @return    None
834 *
835 ******************************************************************************/
XSdPs_CheckBusHigh(XSdPs * InstancePtr)836 s32 XSdPs_CheckBusHigh(XSdPs *InstancePtr)
837 {
838     u32 Timeout = 10000;
839     s32 Status;
840     u32 ReadReg;
841 
842     /* Wait for CMD and DATA line to go high */
843     Timeout = MAX_TIMEOUT;
844     do {
845         ReadReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
846                 XSDPS_PRES_STATE_OFFSET);
847         Timeout = Timeout - 1;
848         usleep(1);
849     } while (((ReadReg & (XSDPS_PSR_CMD_SG_LVL_MASK | XSDPS_PSR_DAT30_SG_LVL_MASK))
850             != (XSDPS_PSR_CMD_SG_LVL_MASK | XSDPS_PSR_DAT30_SG_LVL_MASK))
851             && (Timeout != 0U));
852 
853     if (Timeout == 0U) {
854         Status = XST_FAILURE;
855         goto RETURN_PATH ;
856     }
857 
858     Status = XST_SUCCESS;
859 
860 RETURN_PATH:
861     return Status;
862 }
863 
864 /*****************************************************************************/
865 /**
866 *
867 * @brief
868 * API to Identify the supported UHS mode. This API will assign the
869 * corresponding tap delay API to the Config_TapDelay pointer based on the
870 * supported bus speed.
871 *
872 *
873 * @param    InstancePtr is a pointer to the XSdPs instance.
874 * @param    ReadBuff contains the response for CMD6
875 *
876 * @return    None.
877 *
878 * @note        None.
879 *
880 ******************************************************************************/
XSdPs_Identify_UhsMode(XSdPs * InstancePtr,u8 * ReadBuff)881 void XSdPs_Identify_UhsMode(XSdPs *InstancePtr, u8 *ReadBuff)
882 {
883     if (((ReadBuff[13] & UHS_SDR104_SUPPORT) != 0U) &&
884         (InstancePtr->Config.InputClockHz >= XSDPS_SD_INPUT_MAX_CLK)) {
885         InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR104;
886         if (InstancePtr->Config.BankNumber == 2U) {
887             InstancePtr->OTapDelay = SD_OTAPDLYSEL_HS200_B2;
888         } else {
889             InstancePtr->OTapDelay = SD_OTAPDLYSEL_HS200_B0;
890         }
891     } else if (((ReadBuff[13] & UHS_SDR50_SUPPORT) != 0U) &&
892         (InstancePtr->Config.InputClockHz >= XSDPS_SD_SDR50_MAX_CLK)) {
893         InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR50;
894         InstancePtr->OTapDelay = SD_OTAPDLYSEL_SD50;
895     } else if (((ReadBuff[13] & UHS_DDR50_SUPPORT) != 0U) &&
896         (InstancePtr->Config.InputClockHz >= XSDPS_SD_DDR50_MAX_CLK)) {
897         InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_DDR50;
898         InstancePtr->OTapDelay = SD_OTAPDLYSEL_SD_DDR50;
899         InstancePtr->ITapDelay = SD_ITAPDLYSEL_SD_DDR50;
900     } else if (((ReadBuff[13] & UHS_SDR25_SUPPORT) != 0U) &&
901         (InstancePtr->Config.InputClockHz >= XSDPS_SD_SDR25_MAX_CLK)) {
902         InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR25;
903         InstancePtr->OTapDelay = SD_OTAPDLYSEL_SD_HSD;
904         InstancePtr->ITapDelay = SD_ITAPDLYSEL_HSD;
905     } else {
906         InstancePtr->Mode = XSDPS_UHS_SPEED_MODE_SDR12;
907     }
908 }
909 
910 /*****************************************************************************/
911 /**
912 *
913 * @brief
914 * API to set Tap Delay w.r.t speed modes
915 *
916 *
917 * @param    InstancePtr is a pointer to the XSdPs instance.
918 *
919 * @return    None
920 *
921 * @note        None.
922 *
923 ******************************************************************************/
XSdPs_SetTapDelay(XSdPs * InstancePtr)924 void XSdPs_SetTapDelay(XSdPs *InstancePtr)
925 {
926     if ((InstancePtr->Mode == XSDPS_DEFAULT_SPEED_MODE) ||
927         (InstancePtr->Mode == XSDPS_UHS_SPEED_MODE_SDR12)) {
928         return;
929     }
930 
931 #ifndef versal
932     /* Issue DLL Reset */
933     XSdPs_DllRstCtrl(InstancePtr, 1U);
934 #endif
935 
936     /* Configure the Tap Delay Registers */
937     XSdPs_ConfigTapDelay(InstancePtr);
938 
939 #ifndef versal
940     /* Release the DLL out of reset */
941     XSdPs_DllRstCtrl(InstancePtr, 0U);
942 #endif
943 }
944 
945 /*****************************************************************************/
946 /**
947 * @brief
948 * This function is used to change the SD Bus Speed.
949 *
950 * @param    InstancePtr is a pointer to the instance to be worked on.
951 *
952 * @return    None
953 *
954 ******************************************************************************/
XSdPs_Change_SdBusSpeed(XSdPs * InstancePtr)955 s32 XSdPs_Change_SdBusSpeed(XSdPs *InstancePtr)
956 {
957     s32 Status;
958     u32 Arg;
959     u16 BlkCnt;
960     u16 BlkSize;
961     u16 CtrlReg;
962     u8 ReadBuff[64] = {0U};
963 
964     Status = XSdPs_CalcBusSpeed(InstancePtr, &Arg);
965     if (Status != XST_SUCCESS) {
966         Status = XST_FAILURE;
967         goto RETURN_PATH;
968     }
969 
970     BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
971     BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
972 
973     XSdPs_SetupReadDma(InstancePtr, BlkCnt, BlkSize, ReadBuff);
974 
975     Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, BlkCnt);
976     if (Status != XST_SUCCESS) {
977         Status = XST_FAILURE;
978         goto RETURN_PATH;
979     }
980 
981     /* Check for transfer done */
982     Status = XSdps_CheckTransferDone(InstancePtr);
983     if (Status != XST_SUCCESS) {
984         Status = XST_FAILURE;
985     }
986 
987     if (InstancePtr->Switch1v8 != 0U) {
988         /* Set UHS mode in controller */
989         CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
990                 XSDPS_HOST_CTRL2_OFFSET);
991         CtrlReg &= (u16)(~XSDPS_HC2_UHS_MODE_MASK);
992         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
993                         XSDPS_HOST_CTRL2_OFFSET,
994                         CtrlReg | InstancePtr->Mode);
995     }
996 
997     Status = XST_SUCCESS;
998 
999 RETURN_PATH:
1000     return Status;
1001 }
1002 
1003 /*****************************************************************************/
1004 /**
1005 * @brief
1006 * This function is used to change the eMMC bus speed.
1007 *
1008 * @param    InstancePtr is a pointer to the instance to be worked on.
1009 *
1010 * @return    None
1011 *
1012 ******************************************************************************/
XSdPs_Change_MmcBusSpeed(XSdPs * InstancePtr)1013 s32 XSdPs_Change_MmcBusSpeed(XSdPs *InstancePtr)
1014 {
1015     s32 Status;
1016     u32 Arg;
1017 
1018     Status = XSdPs_CalcBusSpeed(InstancePtr, &Arg);
1019     if (Status != XST_SUCCESS) {
1020         Status = XST_FAILURE;
1021         goto RETURN_PATH;
1022     }
1023 
1024     Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
1025     if (Status != XST_SUCCESS) {
1026         Status = XST_FAILURE;
1027         goto RETURN_PATH;
1028     }
1029 
1030     /* Check for transfer done */
1031     Status = XSdps_CheckTransferDone(InstancePtr);
1032     if (Status != XST_SUCCESS) {
1033         Status = XST_FAILURE;
1034     }
1035 
1036     Status = XST_SUCCESS;
1037 
1038 RETURN_PATH:
1039     return Status;
1040 }
1041 
1042 /*****************************************************************************/
1043 /**
1044 * @brief
1045 * This function is used to do the Auto tuning.
1046 *
1047 * @param    InstancePtr is a pointer to the instance to be worked on.
1048 *
1049 * @return    None
1050 *
1051 ******************************************************************************/
XSdPs_AutoTuning(XSdPs * InstancePtr)1052 s32 XSdPs_AutoTuning(XSdPs *InstancePtr)
1053 {
1054     s32 Status;
1055     u16 BlkSize;
1056     u8 TuningCount;
1057 
1058     BlkSize = XSDPS_TUNING_CMD_BLKSIZE;
1059     if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH)
1060     {
1061         BlkSize = BlkSize*2U;
1062     }
1063     BlkSize &= XSDPS_BLK_SIZE_MASK;
1064     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
1065             BlkSize);
1066 
1067     InstancePtr->TransferMode = XSDPS_TM_DAT_DIR_SEL_MASK;
1068 
1069     XSdPs_SetExecTuning(InstancePtr);
1070     /*
1071      * workaround which can work for 1.0/2.0 silicon for auto tuning.
1072      * This can be revisited for 3.0 silicon if necessary.
1073      */
1074     /* Wait for ~60 clock cycles to reset the tap values */
1075     (void)usleep(1U);
1076 
1077     for (TuningCount = 0U; TuningCount < MAX_TUNING_COUNT; TuningCount++) {
1078 
1079         if (InstancePtr->CardType == XSDPS_CARD_SD) {
1080             Status = XSdPs_CmdTransfer(InstancePtr, CMD19, 0U, 1U);
1081         } else {
1082             Status = XSdPs_CmdTransfer(InstancePtr, CMD21, 0U, 1U);
1083         }
1084 
1085         if (Status != XST_SUCCESS) {
1086             Status = XST_FAILURE;
1087             goto RETURN_PATH;
1088         }
1089 
1090         if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1091                 XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_EXEC_TNG_MASK) == 0U) {
1092             break;
1093         }
1094     }
1095 
1096     if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1097             XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_SAMP_CLK_SEL_MASK) == 0U) {
1098         Status = XST_FAILURE;
1099         goto RETURN_PATH;
1100     }
1101 
1102     /* Wait for ~12 clock cycles to synchronize the new tap values */
1103     (void)usleep(1U);
1104 
1105     Status = XST_SUCCESS;
1106 
1107 RETURN_PATH:
1108     return Status;
1109 }
1110 
1111 /*****************************************************************************/
1112 /**
1113 *
1114 * @brief
1115 * API to setup ADMA2 descriptor table
1116 *
1117 *
1118 * @param    InstancePtr is a pointer to the XSdPs instance.
1119 * @param    BlkCnt - block count.
1120 * @param    Buff pointer to data buffer.
1121 *
1122 * @return    None
1123 *
1124 * @note        None.
1125 *
1126 ******************************************************************************/
XSdPs_SetupADMA2DescTbl(XSdPs * InstancePtr,u32 BlkCnt,const u8 * Buff)1127 void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff)
1128 {
1129     if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
1130         XSdPs_Setup64ADMA2DescTbl(InstancePtr, BlkCnt, Buff);
1131     } else {
1132         XSdPs_Setup32ADMA2DescTbl(InstancePtr, BlkCnt, Buff);
1133     }
1134 }
1135 
1136 /*****************************************************************************/
1137 /**
1138 *
1139 * @brief
1140 * API to setup ADMA2 descriptor table for 64 Bit DMA
1141 *
1142 *
1143 * @param    InstancePtr is a pointer to the XSdPs instance.
1144 * @param    BlkCnt - block count.
1145 *
1146 * @return    None
1147 *
1148 * @note        None.
1149 *
1150 ******************************************************************************/
XSdPs_SetupADMA2DescTbl64Bit(XSdPs * InstancePtr,u32 BlkCnt)1151 void XSdPs_SetupADMA2DescTbl64Bit(XSdPs *InstancePtr, u32 BlkCnt)
1152 {
1153 #ifdef __ICCARM__
1154 #pragma data_alignment = 32
1155     static XSdPs_Adma2Descriptor64 Adma2_DescrTbl[32];
1156 #else
1157     static XSdPs_Adma2Descriptor64 Adma2_DescrTbl[32] __attribute__ ((aligned(32)));
1158 #endif
1159     u32 TotalDescLines;
1160     u64 DescNum;
1161     u32 BlkSize;
1162 
1163     /* Setup ADMA2 - Write descriptor table and point ADMA SAR to it */
1164     BlkSize = (u32)XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1165                     XSDPS_BLK_SIZE_OFFSET) &
1166                     XSDPS_BLK_SIZE_MASK;
1167 
1168     if((BlkCnt*BlkSize) < XSDPS_DESC_MAX_LENGTH) {
1169 
1170         TotalDescLines = 1U;
1171 
1172     } else {
1173 
1174         TotalDescLines = ((BlkCnt*BlkSize) / XSDPS_DESC_MAX_LENGTH);
1175         if (((BlkCnt * BlkSize) % XSDPS_DESC_MAX_LENGTH) != 0U) {
1176             TotalDescLines += 1U;
1177         }
1178 
1179     }
1180 
1181     for (DescNum = 0U; DescNum < (TotalDescLines-1); DescNum++) {
1182         Adma2_DescrTbl[DescNum].Address =
1183                 InstancePtr->Dma64BitAddr +
1184                 (DescNum*XSDPS_DESC_MAX_LENGTH);
1185         Adma2_DescrTbl[DescNum].Attribute =
1186                 XSDPS_DESC_TRAN | XSDPS_DESC_VALID;
1187         Adma2_DescrTbl[DescNum].Length = 0U;
1188     }
1189 
1190     Adma2_DescrTbl[TotalDescLines-1].Address =
1191                 InstancePtr->Dma64BitAddr +
1192                 (DescNum*XSDPS_DESC_MAX_LENGTH);
1193 
1194     Adma2_DescrTbl[TotalDescLines-1].Attribute =
1195             XSDPS_DESC_TRAN | XSDPS_DESC_END | XSDPS_DESC_VALID;
1196 
1197     Adma2_DescrTbl[TotalDescLines-1].Length =
1198             (u16)((BlkCnt*BlkSize) - (u32)(DescNum*XSDPS_DESC_MAX_LENGTH));
1199 
1200     XSdPs_WriteReg(InstancePtr->Config.BaseAddress, XSDPS_ADMA_SAR_OFFSET,
1201             (u32)((UINTPTR)&(Adma2_DescrTbl[0]) & (u32)~0x0));
1202 
1203     if (InstancePtr->Config.IsCacheCoherent == 0U) {
1204         Xil_DCacheFlushRange((INTPTR)&(Adma2_DescrTbl[0]),
1205             sizeof(XSdPs_Adma2Descriptor64) * 32U);
1206     }
1207 
1208     /* Clear the 64-Bit Address variable */
1209     InstancePtr->Dma64BitAddr = 0U;
1210 
1211 }
1212 
1213 /*****************************************************************************/
1214 /**
1215 *
1216 * @brief
1217 * API to reset the DLL
1218 *
1219 *
1220 * @param    InstancePtr is a pointer to the XSdPs instance.
1221 *
1222 * @return    None
1223 *
1224 * @note        None.
1225 *
1226 ******************************************************************************/
XSdPs_DllReset(XSdPs * InstancePtr)1227 s32 XSdPs_DllReset(XSdPs *InstancePtr)
1228 {
1229     u32 ClockReg;
1230     s32 Status;
1231 
1232     /* Disable clock */
1233     ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1234             XSDPS_CLK_CTRL_OFFSET);
1235     ClockReg &= ~XSDPS_CC_SD_CLK_EN_MASK;
1236     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1237             XSDPS_CLK_CTRL_OFFSET, (u16)ClockReg);
1238 
1239     /* Issue DLL Reset to load zero tap values */
1240     XSdPs_DllRstCtrl(InstancePtr, 1U);
1241 
1242     /* Wait for 2 micro seconds */
1243     (void)usleep(2U);
1244 
1245     XSdPs_DllRstCtrl(InstancePtr, 0U);
1246 
1247     ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1248                 XSDPS_CLK_CTRL_OFFSET);
1249     /* Enable the clock in the controller */
1250     Status = XSdPs_EnableClock(InstancePtr, ClockReg);
1251     if (Status != XST_SUCCESS) {
1252         Status = XST_FAILURE;
1253     }
1254 
1255     return Status;
1256 }
1257 
1258 /*****************************************************************************/
1259 /**
1260 * @brief
1261 * This function is used to identify the eMMC speed mode.
1262 *
1263 * @param    InstancePtr is a pointer to the instance to be worked on.
1264 * @param    ExtCsd is the extended CSD register from the card
1265 *
1266 * @return    None
1267 *
1268 ******************************************************************************/
XSdPs_IdentifyEmmcMode(XSdPs * InstancePtr,const u8 * ExtCsd)1269 void XSdPs_IdentifyEmmcMode(XSdPs *InstancePtr, const u8 *ExtCsd)
1270 {
1271     if (InstancePtr->BusWidth < XSDPS_4_BIT_WIDTH) {
1272         InstancePtr->Mode = XSDPS_DEFAULT_SPEED_MODE;
1273     } else {
1274         /* Check for card supported speed */
1275         if ((ExtCsd[EXT_CSD_DEVICE_TYPE_BYTE] &
1276                 (EXT_CSD_DEVICE_TYPE_SDR_1V8_HS200 |
1277                 EXT_CSD_DEVICE_TYPE_SDR_1V2_HS200)) != 0U) {
1278             InstancePtr->Mode = XSDPS_HS200_MODE;
1279             if (InstancePtr->Config.BankNumber == 2U) {
1280                 InstancePtr->OTapDelay = SD_OTAPDLYSEL_HS200_B2;
1281             } else {
1282                 InstancePtr->OTapDelay = SD_OTAPDLYSEL_HS200_B0;
1283             }
1284         } else if ((ExtCsd[EXT_CSD_DEVICE_TYPE_BYTE] &
1285                 (EXT_CSD_DEVICE_TYPE_DDR_1V8_HIGH_SPEED |
1286                 EXT_CSD_DEVICE_TYPE_DDR_1V2_HIGH_SPEED)) != 0U) {
1287             InstancePtr->Mode = XSDPS_DDR52_MODE;
1288             InstancePtr->OTapDelay = SD_ITAPDLYSEL_EMMC_DDR50;
1289             InstancePtr->ITapDelay = SD_ITAPDLYSEL_EMMC_DDR50;
1290         } else if ((ExtCsd[EXT_CSD_DEVICE_TYPE_BYTE] &
1291                 EXT_CSD_DEVICE_TYPE_HIGH_SPEED) != 0U) {
1292             InstancePtr->Mode = XSDPS_HIGH_SPEED_MODE;
1293             InstancePtr->OTapDelay = SD_OTAPDLYSEL_EMMC_HSD;
1294             InstancePtr->ITapDelay = SD_ITAPDLYSEL_HSD;
1295         } else {
1296             InstancePtr->Mode = XSDPS_DEFAULT_SPEED_MODE;
1297         }
1298     }
1299 }
1300 
1301 /*****************************************************************************/
1302 /**
1303 * @brief
1304 * This function is used to check the eMMC timing.
1305 *
1306 * @param    InstancePtr is a pointer to the instance to be worked on.
1307 * @param    ExtCsd is the extended CSD register from the card
1308 *
1309 * @return    None
1310 *
1311 ******************************************************************************/
XSdPs_CheckEmmcTiming(XSdPs * InstancePtr,u8 * ExtCsd)1312 s32 XSdPs_CheckEmmcTiming(XSdPs *InstancePtr, u8 *ExtCsd)
1313 {
1314     s32 Status;
1315 
1316     Status = XSdPs_Get_Mmc_ExtCsd(InstancePtr, ExtCsd);
1317     if (Status != XST_SUCCESS) {
1318         Status = XST_FAILURE;
1319         goto RETURN_PATH;
1320     }
1321 
1322     if (InstancePtr->Mode == XSDPS_HS200_MODE) {
1323         if (ExtCsd[EXT_CSD_HS_TIMING_BYTE] != EXT_CSD_HS_TIMING_HS200) {
1324             Status = XST_FAILURE;
1325             goto RETURN_PATH;
1326         }
1327     } else if ((InstancePtr->Mode == XSDPS_HIGH_SPEED_MODE) ||
1328             (InstancePtr->Mode == XSDPS_DDR52_MODE)) {
1329         if (ExtCsd[EXT_CSD_HS_TIMING_BYTE] != EXT_CSD_HS_TIMING_HIGH) {
1330             Status = XST_FAILURE;
1331             goto RETURN_PATH;
1332         }
1333     } else {
1334         Status = XST_FAILURE;
1335     }
1336 
1337 RETURN_PATH:
1338     return Status;
1339 }
1340 
1341 /*****************************************************************************/
1342 /**
1343 * @brief
1344 * This function is used to set the clock to the passed frequency.
1345 *
1346 * @param    InstancePtr is a pointer to the instance to be worked on.
1347 * @param    SelFreq is the selected frequency
1348 *
1349 * @return    None
1350 *
1351 ******************************************************************************/
XSdPs_SetClock(XSdPs * InstancePtr,u32 SelFreq)1352 s32 XSdPs_SetClock(XSdPs *InstancePtr, u32 SelFreq)
1353 {
1354     u16 ClockReg;
1355     s32 Status;
1356 
1357     /* Disable clock */
1358     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1359             XSDPS_CLK_CTRL_OFFSET, 0U);
1360 
1361     /* If selected frequency is zero, return from here */
1362     if (SelFreq == 0U) {
1363         Status = XST_SUCCESS;
1364         goto RETURN_PATH ;
1365     }
1366 
1367     /* Calculate the clock */
1368     ClockReg = XSdPs_CalcClock(InstancePtr, SelFreq);
1369 
1370     /* Enable the clock in the controller */
1371     Status = XSdPs_EnableClock(InstancePtr, ClockReg);
1372     if (Status != XST_SUCCESS) {
1373         Status = XST_FAILURE;
1374     }
1375 
1376 RETURN_PATH:
1377     return Status;
1378 }
1379 
1380 /*****************************************************************************/
1381 /**
1382 * @brief
1383 * This function checks if the voltage is set to 1.8V or not.
1384 *
1385 * @param    InstancePtr is a pointer to the instance to be worked on.
1386 *
1387 * @return
1388 *         - XST_SUCCESS if voltage is 1.8V
1389 *         - XST_FAILURE if voltage is not 1.8V
1390 *
1391 ******************************************************************************/
XSdPs_CheckVoltage18(XSdPs * InstancePtr)1392 s32 XSdPs_CheckVoltage18(XSdPs *InstancePtr)
1393 {
1394     u32 Status;
1395 
1396     if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1397             XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_1V8_EN_MASK) == 0U) {
1398         Status = XST_FAILURE;
1399         goto RETURN_PATH;
1400     }
1401 
1402     Status = XST_SUCCESS;
1403 
1404 RETURN_PATH:
1405     return Status;
1406 }
1407 
1408 /*****************************************************************************/
1409 /**
1410 * @brief
1411 * This function initializes the command sequence.
1412 *
1413 * @param    InstancePtr is a pointer to the instance to be worked on.
1414 * @param    Arg is the address passed by the user that is to be sent as
1415 *         argument along with the command.
1416 * @param    BlkCnt - Block count passed by the user.
1417 *
1418 * @return    None
1419 *
1420 ******************************************************************************/
XSdPs_SetupCmd(XSdPs * InstancePtr,u32 Arg,u32 BlkCnt)1421 s32 XSdPs_SetupCmd(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt)
1422 {
1423     s32 Status;
1424 
1425     /*
1426      * Check the command inhibit to make sure no other
1427      * command transfer is in progress
1428      */
1429     Status = XSdPs_CheckBusIdle(InstancePtr, XSDPS_PSR_INHIBIT_CMD_MASK);
1430     if (Status != XST_SUCCESS) {
1431         Status = XST_FAILURE;
1432         goto RETURN_PATH ;
1433     }
1434 
1435     /* Write block count register */
1436     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1437             XSDPS_BLK_CNT_OFFSET, (u16)BlkCnt);
1438 
1439     XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
1440             XSDPS_TIMEOUT_CTRL_OFFSET, 0xEU);
1441 
1442     /* Write argument register */
1443     XSdPs_WriteReg(InstancePtr->Config.BaseAddress,
1444             XSDPS_ARGMT_OFFSET, Arg);
1445 
1446     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1447             XSDPS_NORM_INTR_STS_OFFSET, XSDPS_NORM_INTR_ALL_MASK);
1448     XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1449             XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK);
1450 
1451     Status = XST_SUCCESS;
1452 
1453 RETURN_PATH:
1454     return Status;
1455 }
1456 
1457 /*****************************************************************************/
1458 /**
1459 * @brief
1460 * This function initiates the Cmd transfer to SD card.
1461 *
1462 * @param    InstancePtr is a pointer to the instance to be worked on.
1463 * @param    Cmd is the command to be sent
1464 *
1465 * @return
1466 *         - XST_SUCCESS if initialization was successful
1467 *         - XST_FAILURE if failure
1468 *
1469 ******************************************************************************/
XSdPs_SendCmd(XSdPs * InstancePtr,u32 Cmd)1470 s32 XSdPs_SendCmd(XSdPs *InstancePtr, u32 Cmd)
1471 {
1472     u32 PresentStateReg;
1473     u32 CommandReg;
1474     s32 Status;
1475 
1476     /* Command register is set to trigger transfer of command */
1477     CommandReg = XSdPs_FrameCmd(InstancePtr, Cmd);
1478 
1479     /*
1480      * Mask to avoid writing to reserved bits 31-30
1481      * This is necessary because 0x8000 is used  by this software to
1482      * distinguish between ACMD and CMD of same number
1483      */
1484     CommandReg = CommandReg & 0x3FFFU;
1485 
1486     /*
1487      * Check for data inhibit in case of command using DAT lines.
1488      * For Tuning Commands DAT lines check can be ignored.
1489      */
1490     if ((Cmd != CMD21) && (Cmd != CMD19)) {
1491         PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
1492                 XSDPS_PRES_STATE_OFFSET);
1493         if (((PresentStateReg & XSDPS_PSR_INHIBIT_DAT_MASK) != 0U) &&
1494                 ((CommandReg & XSDPS_DAT_PRESENT_SEL_MASK) != 0U)) {
1495             Status = XST_FAILURE;
1496             goto RETURN_PATH;
1497         }
1498     }
1499 
1500     XSdPs_WriteReg(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,
1501             (CommandReg << 16) | InstancePtr->TransferMode);
1502 
1503     Status = XST_SUCCESS;
1504 
1505 RETURN_PATH:
1506     return Status;
1507 
1508 }
1509 
1510 /** @} */
1511