]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A9_Zynq_ZC702/RTOSDemo_bsp/ps7_cortexa9_0/libsrc/sdps_v2_1/src/xsdps_options.c
Preparing for next release...
[freertos] / FreeRTOS / Demo / CORTEX_A9_Zynq_ZC702 / RTOSDemo_bsp / ps7_cortexa9_0 / libsrc / sdps_v2_1 / src / xsdps_options.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2013 - 2014 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xsdps_options.c
36 *
37 * Contains API's for changing the various options in host and card.
38 * See xsdps.h for a detailed description of the device and driver.
39 *
40 * <pre>
41 * MODIFICATION HISTORY:
42 *
43 * Ver   Who    Date     Changes
44 * ----- ---    -------- -----------------------------------------------
45 * 1.00a hk/sg  10/17/13 Initial release
46 * 2.1   hk     04/18/14 Increase sleep for eMMC switch command.
47 *                       Add sleep for microblaze designs. CR# 781117.
48 *
49 * </pre>
50 *
51 ******************************************************************************/
52
53 /***************************** Include Files *********************************/
54 #include "xsdps.h"
55 /*
56  * The header sleep.h and API usleep() can only be used with an arm design.
57  * MB_Sleep() is used for microblaze design.
58  */
59 #ifdef __arm__
60
61 #include "sleep.h"
62
63 #endif
64
65 #ifdef __MICROBLAZE__
66
67 #include "microblaze_sleep.h"
68
69 #endif
70
71 /************************** Constant Definitions *****************************/
72 #define XSDPS_SCR_BLKCNT        1
73 #define XSDPS_SCR_BLKSIZE       8
74 #define XSDPS_4_BIT_WIDTH       0x2
75 #define XSDPS_SWITCH_CMD_BLKCNT         1
76 #define XSDPS_SWITCH_CMD_BLKSIZE        64
77 #define XSDPS_SWITCH_CMD_HS_GET 0x00FFFFF0
78 #define XSDPS_SWITCH_CMD_HS_SET 0x80FFFFF1
79 #define XSDPS_EXT_CSD_CMD_BLKCNT        1
80 #define XSDPS_EXT_CSD_CMD_BLKSIZE       512
81 #define XSDPS_CLK_52_MHZ                52000000
82 #define XSDPS_MMC_HIGH_SPEED_ARG        0x03B90100
83 #define XSDPS_MMC_4_BIT_BUS_ARG         0x03B70100
84 #define XSDPS_MMC_DELAY_FOR_SWITCH      2000
85
86 /**************************** Type Definitions *******************************/
87
88 /***************** Macros (Inline Functions) Definitions *********************/
89
90 /************************** Function Prototypes ******************************/
91 int XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);
92 void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);
93
94 /*****************************************************************************/
95 /**
96 * Update Block size for read/write operations.
97 *
98 * @param        InstancePtr is a pointer to the instance to be worked on.
99 * @param        BlkSize - Block size passed by the user.
100 *
101 * @return       None
102 *
103 ******************************************************************************/
104 int XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize)
105 {
106         u32 Status = 0;
107         u32 PresentStateReg = 0;
108
109         Xil_AssertNonvoid(InstancePtr != NULL);
110         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
111
112         PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
113                         XSDPS_PRES_STATE_OFFSET);
114
115         if (PresentStateReg & (XSDPS_PSR_INHIBIT_CMD_MASK |
116                         XSDPS_PSR_INHIBIT_DAT_MASK |
117                         XSDPS_PSR_WR_ACTIVE_MASK | XSDPS_PSR_RD_ACTIVE_MASK)) {
118                 Status = XST_FAILURE;
119                 goto RETURN_PATH;
120         }
121
122
123         /*
124          * Send block write command
125          */
126         Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0);
127         if (Status != XST_SUCCESS) {
128                 Status = XST_FAILURE;
129                 goto RETURN_PATH;
130         }
131
132         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
133                         XSDPS_RESP0_OFFSET);
134
135         /*
136          * Set block size to the value passed
137          */
138         BlkSize &= XSDPS_BLK_SIZE_MASK;
139         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
140                          BlkSize);
141
142         Status = XST_SUCCESS;
143
144         RETURN_PATH:
145                 return Status;
146
147 }
148
149 /*****************************************************************************/
150 /**
151 *
152 * API to get bus width support by card.
153 *
154 *
155 * @param        InstancePtr is a pointer to the XSdPs instance.
156 * @param        SCR - buffer to store SCR register returned by card.
157 *
158 * @return
159 *               - XST_SUCCESS if successful.
160 *               - XST_FAILURE if fail.
161 *
162 * @note         None.
163 *
164 ******************************************************************************/
165 int XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR)
166 {
167         u32 Status = 0;
168         u32 StatusReg = 0x0;
169         u16 BlkCnt;
170         u16 BlkSize;
171         int LoopCnt;
172
173         Xil_AssertNonvoid(InstancePtr != NULL);
174         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
175
176         for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) {
177                 SCR[LoopCnt] = 0;
178         }
179
180         /*
181          * Send block write command
182          */
183         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
184                         InstancePtr->RelCardAddr, 0);
185         if (Status != XST_SUCCESS) {
186                 Status = XST_FAILURE;
187                 goto RETURN_PATH;
188         }
189
190         BlkCnt = XSDPS_SCR_BLKCNT;
191         BlkSize = XSDPS_SCR_BLKSIZE;
192
193         /*
194          * Set block size to the value passed
195          */
196         BlkSize &= XSDPS_BLK_SIZE_MASK;
197         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
198                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
199
200         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR);
201
202         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
203                         XSDPS_XFER_MODE_OFFSET,
204                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
205
206         Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0, BlkCnt);
207         if (Status != XST_SUCCESS) {
208                 Status = XST_FAILURE;
209                 goto RETURN_PATH;
210         }
211
212         /*
213          * Check for transfer complete
214          * Polling for response for now
215          */
216         do {
217                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
218                                         XSDPS_NORM_INTR_STS_OFFSET);
219                 if (StatusReg & XSDPS_INTR_ERR_MASK) {
220                         /*
221                          * Write to clear error bits
222                          */
223                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
224                                         XSDPS_ERR_INTR_STS_OFFSET,
225                                         XSDPS_ERROR_INTR_ALL_MASK);
226                         Status = XST_FAILURE;
227                         goto RETURN_PATH;
228                 }
229         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0);
230
231         /*
232          * Write to clear bit
233          */
234         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
235                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
236
237         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
238                         XSDPS_RESP0_OFFSET);
239
240         Status = XST_SUCCESS;
241
242         RETURN_PATH:
243                 return Status;
244
245 }
246
247 /*****************************************************************************/
248 /**
249 *
250 * API to set bus width to 4-bit in card and host
251 *
252 *
253 * @param        InstancePtr is a pointer to the XSdPs instance.
254 *
255 * @return
256 *               - XST_SUCCESS if successful.
257 *               - XST_FAILURE if fail.
258 *
259 * @note         None.
260 *
261 ******************************************************************************/
262 int XSdPs_Change_BusWidth(XSdPs *InstancePtr)
263 {
264         u32 Status = 0;
265         u32 StatusReg = 0x0;
266         u32 Arg = 0;
267
268         Xil_AssertNonvoid(InstancePtr != NULL);
269         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
270
271 #ifndef MMC_CARD
272
273         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
274                         InstancePtr->RelCardAddr, 0);
275         if (Status != XST_SUCCESS) {
276                 Status = XST_FAILURE;
277                 goto RETURN_PATH;
278         }
279
280         Arg = XSDPS_4_BIT_WIDTH;
281         Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0);
282         if (Status != XST_SUCCESS) {
283                 Status = XST_FAILURE;
284                 goto RETURN_PATH;
285         }
286
287         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
288                                         XSDPS_HOST_CTRL1_OFFSET);
289         StatusReg |= XSDPS_HC_WIDTH_MASK;
290         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
291                         XSDPS_HOST_CTRL1_OFFSET,StatusReg);
292
293         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
294                         XSDPS_RESP0_OFFSET);
295
296 #else
297
298         Arg = XSDPS_MMC_4_BIT_BUS_ARG;
299         Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0);
300         if (Status != XST_SUCCESS) {
301                 Status = XST_FAILURE;
302                 goto RETURN_PATH;
303         }
304
305 #ifdef __arm__
306
307         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
308
309 #endif
310
311 #ifdef __MICROBLAZE__
312
313         /* 2 msec delay */
314         MB_Sleep(2);
315
316 #endif
317
318         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
319                                         XSDPS_HOST_CTRL1_OFFSET);
320         StatusReg |= XSDPS_HC_WIDTH_MASK;
321         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
322                         XSDPS_HOST_CTRL1_OFFSET,StatusReg);
323
324         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
325                         XSDPS_RESP0_OFFSET);
326
327 #endif
328
329         Status = XST_SUCCESS;
330
331         RETURN_PATH:
332                 return Status;
333
334 }
335
336 /*****************************************************************************/
337 /**
338 *
339 * API to get bus speed supported by card.
340 *
341 *
342 * @param        InstancePtr is a pointer to the XSdPs instance.
343 * @param        ReadBuff - buffer to store function group support data
344 *               returned by card.
345 *
346 * @return
347 *               - XST_SUCCESS if successful.
348 *               - XST_FAILURE if fail.
349 *
350 * @note         None.
351 *
352 ******************************************************************************/
353 int XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff)
354 {
355         u32 Status = 0;
356         u32 StatusReg = 0x0;
357         u32 Arg = 0;
358         u16 BlkCnt;
359         u16 BlkSize;
360         int LoopCnt;
361
362         Xil_AssertNonvoid(InstancePtr != NULL);
363         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
364
365         for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) {
366                 ReadBuff[LoopCnt] = 0;
367         }
368
369         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
370         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
371         BlkSize &= XSDPS_BLK_SIZE_MASK;
372         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
373                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
374
375         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
376
377         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
378                         XSDPS_XFER_MODE_OFFSET,
379                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
380
381         Arg = XSDPS_SWITCH_CMD_HS_GET;
382
383         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1);
384         if (Status != XST_SUCCESS) {
385                 Status = XST_FAILURE;
386                 goto RETURN_PATH;
387         }
388
389         /*
390          * Check for transfer complete
391          * Polling for response for now
392          */
393         do {
394                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
395                                         XSDPS_NORM_INTR_STS_OFFSET);
396                 if (StatusReg & XSDPS_INTR_ERR_MASK) {
397                         /*
398                          * Write to clear error bits
399                          */
400                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
401                                         XSDPS_ERR_INTR_STS_OFFSET,
402                                         XSDPS_ERROR_INTR_ALL_MASK);
403                         Status = XST_FAILURE;
404                         goto RETURN_PATH;
405                 }
406         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0);
407
408         /*
409          * Write to clear bit
410          */
411         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
412                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
413
414         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
415                         XSDPS_RESP0_OFFSET);
416
417         Status = XST_SUCCESS;
418
419         RETURN_PATH:
420                 return Status;
421
422 }
423
424 /*****************************************************************************/
425 /**
426 *
427 * API to set high speed in card and host. Changes clock in host accordingly.
428 *
429 *
430 * @param        InstancePtr is a pointer to the XSdPs instance.
431 *
432 * @return
433 *               - XST_SUCCESS if successful.
434 *               - XST_FAILURE if fail.
435 *
436 * @note         None.
437 *
438 ******************************************************************************/
439 int XSdPs_Change_BusSpeed(XSdPs *InstancePtr)
440 {
441         u32 Status = 0;
442         u32 StatusReg = 0x0;
443         u32 Arg = 0;
444
445 #ifndef MMC_CARD
446         u32 ClockReg;
447         u8 ReadBuff[64];
448         u16 BlkCnt;
449         u16 BlkSize;
450 #endif
451
452         Xil_AssertNonvoid(InstancePtr != NULL);
453         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
454
455 #ifndef MMC_CARD
456
457         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
458         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
459         BlkSize &= XSDPS_BLK_SIZE_MASK;
460         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
461                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
462
463         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
464
465         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
466                         XSDPS_XFER_MODE_OFFSET,
467                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
468
469         Arg = XSDPS_SWITCH_CMD_HS_SET;
470         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1);
471         if (Status != XST_SUCCESS) {
472                 Status = XST_FAILURE;
473                 goto RETURN_PATH;
474         }
475
476         /*
477          * Check for transfer complete
478          * Polling for response for now
479          */
480         do {
481                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
482                                         XSDPS_NORM_INTR_STS_OFFSET);
483                 if (StatusReg & XSDPS_INTR_ERR_MASK) {
484                         /*
485                          * Write to clear error bits
486                          */
487                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
488                                         XSDPS_ERR_INTR_STS_OFFSET,
489                                         XSDPS_ERROR_INTR_ALL_MASK);
490                         Status = XST_FAILURE;
491                         goto RETURN_PATH;
492                 }
493         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0);
494
495         /*
496          * Write to clear bit
497          */
498         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
499                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
500
501         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
502                         XSDPS_CLK_CTRL_OFFSET);
503         ClockReg &= ~(XSDPS_CC_INT_CLK_EN_MASK | XSDPS_CC_SD_CLK_EN_MASK);
504
505         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
506                         XSDPS_CLK_CTRL_OFFSET, ClockReg);
507
508         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
509                         XSDPS_CLK_CTRL_OFFSET);
510         ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK);
511         ClockReg |= XSDPS_CC_SDCLK_FREQ_BASE_MASK | XSDPS_CC_INT_CLK_EN_MASK;
512         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
513                         XSDPS_CLK_CTRL_OFFSET, ClockReg);
514
515         /*
516          * Wait for internal clock to stabilize
517          */
518         while((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
519                 XSDPS_CLK_CTRL_OFFSET) & XSDPS_CC_INT_CLK_STABLE_MASK) == 0);
520
521         /*
522          * Enable SD clock
523          */
524         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
525                         XSDPS_CLK_CTRL_OFFSET);
526         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
527                         XSDPS_CLK_CTRL_OFFSET,
528                         ClockReg | XSDPS_CC_SD_CLK_EN_MASK);
529
530
531         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
532                                         XSDPS_HOST_CTRL1_OFFSET);
533         StatusReg |= XSDPS_HC_SPEED_MASK;
534         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
535                         XSDPS_HOST_CTRL1_OFFSET,StatusReg);
536
537         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
538                         XSDPS_RESP0_OFFSET);
539
540 #else
541
542         Arg = XSDPS_MMC_HIGH_SPEED_ARG;
543         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0);
544         if (Status != XST_SUCCESS) {
545                 Status = XST_FAILURE;
546                 goto RETURN_PATH;
547         }
548
549 #ifdef __arm__
550
551         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
552
553 #endif
554
555 #ifdef __MICROBLAZE__
556
557         /* 2 msec delay */
558         MB_Sleep(2);
559
560 #endif
561
562         XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ);
563
564         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
565                                         XSDPS_HOST_CTRL1_OFFSET);
566         StatusReg |= XSDPS_HC_SPEED_MASK;
567         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
568                         XSDPS_HOST_CTRL1_OFFSET,StatusReg);
569
570         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
571                         XSDPS_RESP0_OFFSET);
572 #endif
573
574         Status = XST_SUCCESS;
575
576         RETURN_PATH:
577                 return Status;
578
579 }
580
581 /*****************************************************************************/
582 /**
583 *
584 * API to change clock freq to given value.
585 *
586 *
587 * @param        InstancePtr is a pointer to the XSdPs instance.
588 * @param        SelFreq - Clock frequency in Hz.
589 *
590 * @return       None
591 *
592 * @note         This API will change clock frequency to the value less than
593 *               or equal to the given value using the permissible dividors.
594 *
595 ******************************************************************************/
596 int XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)
597 {
598         u16 ClockReg;
599         int DivCnt;
600         u16 Divisor;
601         u16 ClkLoopCnt;
602         int Status;
603
604         Xil_AssertNonvoid(InstancePtr != NULL);
605         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
606
607         /*
608          * Disable clock
609          */
610         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
611                         XSDPS_CLK_CTRL_OFFSET);
612         ClockReg &= ~(XSDPS_CC_INT_CLK_EN_MASK | XSDPS_CC_SD_CLK_EN_MASK);
613
614         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
615                         XSDPS_CLK_CTRL_OFFSET, ClockReg);
616
617         /*
618          * Calculate divisor
619          */
620         DivCnt = 0x1;
621         for(ClkLoopCnt = 0; ClkLoopCnt < XSDPS_CC_MAX_NUM_OF_DIV;
622                 ClkLoopCnt++) {
623                 if( ((InstancePtr->Config.InputClockHz)/DivCnt) <= SelFreq) {
624                         Divisor = DivCnt/2;
625                         Divisor = Divisor << XSDPS_CC_DIV_SHIFT;
626                         break;
627                 }
628                 DivCnt = DivCnt << 1;
629         }
630
631         if(ClkLoopCnt == 9) {
632
633                 /*
634                  * No valid divisor found for given frequency
635                  */
636                 Status = XST_FAILURE;
637                 goto RETURN_PATH;
638         }
639
640         /*
641          * Set clock divisor
642          */
643         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
644                         XSDPS_CLK_CTRL_OFFSET);
645         ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK);
646
647         ClockReg |= Divisor | XSDPS_CC_INT_CLK_EN_MASK;
648         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
649                         XSDPS_CLK_CTRL_OFFSET, ClockReg);
650
651         /*
652          * Wait for internal clock to stabilize
653          */
654         while((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
655                 XSDPS_CLK_CTRL_OFFSET) & XSDPS_CC_INT_CLK_STABLE_MASK) == 0);
656
657         /*
658          * Enable SD clock
659          */
660         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
661                         XSDPS_CLK_CTRL_OFFSET);
662         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
663                         XSDPS_CLK_CTRL_OFFSET,
664                         ClockReg | XSDPS_CC_SD_CLK_EN_MASK);
665
666         Status = XST_SUCCESS;
667
668         RETURN_PATH:
669                 return Status;
670
671 }
672
673 /*****************************************************************************/
674 /**
675 *
676 * API to send pullup command to card before using DAT line 3(using 4-bit bus)
677 *
678 *
679 * @param        InstancePtr is a pointer to the XSdPs instance.
680 *
681 * @return
682 *               - XST_SUCCESS if successful.
683 *               - XST_FAILURE if fail.
684 *
685 * @note         None.
686 *
687 ******************************************************************************/
688 int XSdPs_Pullup(XSdPs *InstancePtr)
689 {
690         u32 Status = 0;
691
692         Xil_AssertNonvoid(InstancePtr != NULL);
693         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
694
695         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
696                         InstancePtr->RelCardAddr, 0);
697         if (Status != XST_SUCCESS) {
698                 Status = XST_FAILURE;
699                 goto RETURN_PATH;
700         }
701
702         Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0, 0);
703         if (Status != XST_SUCCESS) {
704                 Status = XST_FAILURE;
705                 goto RETURN_PATH;
706         }
707
708         Status = XST_SUCCESS;
709
710         RETURN_PATH:
711                 return Status;
712
713 }
714
715 /*****************************************************************************/
716 /**
717 *
718 * API to get EXT_CSD register of eMMC.
719 *
720 *
721 * @param        InstancePtr is a pointer to the XSdPs instance.
722 * @param        ReadBuff - buffer to store EXT_CSD
723 *
724 * @return
725 *               - XST_SUCCESS if successful.
726 *               - XST_FAILURE if fail.
727 *
728 * @note         None.
729 *
730 ******************************************************************************/
731 int XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff)
732 {
733         u32 Status = 0;
734         u32 StatusReg = 0x0;
735         u32 Arg = 0;
736         u16 BlkCnt;
737         u16 BlkSize;
738         int LoopCnt;
739
740         Xil_AssertNonvoid(InstancePtr != NULL);
741         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
742
743         for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) {
744                 ReadBuff[LoopCnt] = 0;
745         }
746
747         BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT;
748         BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE;
749         BlkSize &= XSDPS_BLK_SIZE_MASK;
750         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
751                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
752
753         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
754
755         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
756                         XSDPS_XFER_MODE_OFFSET,
757                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
758
759         Arg = 0;
760
761         /*
762          * Send SEND_EXT_CSD command
763          */
764         Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1);
765         if (Status != XST_SUCCESS) {
766                 Status = XST_FAILURE;
767                 goto RETURN_PATH;
768         }
769
770         /*
771          * Check for transfer complete
772          * Polling for response for now
773          */
774         do {
775                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
776                                         XSDPS_NORM_INTR_STS_OFFSET);
777                 if (StatusReg & XSDPS_INTR_ERR_MASK) {
778                         /*
779                          * Write to clear error bits
780                          */
781                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
782                                         XSDPS_ERR_INTR_STS_OFFSET,
783                                         XSDPS_ERROR_INTR_ALL_MASK);
784                         Status = XST_FAILURE;
785                         goto RETURN_PATH;
786                 }
787         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0);
788
789         /*
790          * Write to clear bit
791          */
792         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
793                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
794
795         Status = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
796                         XSDPS_RESP0_OFFSET);
797
798         Status = XST_SUCCESS;
799
800         RETURN_PATH:
801                 return Status;
802
803 }
804