]> git.sur5r.net Git - freertos/blob - FreeRTOS-Labs/Source/FreeRTOS-Plus-FAT/portable/Zynq/xsdps_options.c
Add the Labs projects provided in the V10.2.1_191129 zip file.
[freertos] / FreeRTOS-Labs / Source / FreeRTOS-Plus-FAT / portable / Zynq / xsdps_options.c
1 /******************************************************************************\r
2 *\r
3 * Copyright (C) 2013 - 2015 Xilinx, Inc.  All rights reserved.\r
4 *\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy\r
6 * of this software and associated documentation files (the "Software"), to deal\r
7 * in the Software without restriction, including without limitation the rights\r
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
9 * copies of the Software, and to permit persons to whom the Software is\r
10 * furnished to do so, subject to the following conditions:\r
11 *\r
12 * The above copyright notice and this permission notice shall be included in\r
13 * all copies or substantial portions of the Software.\r
14 *\r
15 * Use of the Software is limited solely to applications:\r
16 * (a) running on a Xilinx device, or\r
17 * (b) that interact with a Xilinx device through a bus or interconnect.\r
18 *\r
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\r
22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\r
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF\r
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
25 * SOFTWARE.\r
26 *\r
27 * Except as contained in this notice, the name of the Xilinx shall not be used\r
28 * in advertising or otherwise to promote the sale, use or other dealings in\r
29 * this Software without prior written authorization from Xilinx.\r
30 *\r
31 ******************************************************************************/\r
32 /*****************************************************************************/\r
33 /**\r
34 *\r
35 * @file xsdps_options.c\r
36 * @addtogroup sdps_v2_5\r
37 * @{\r
38 *\r
39 * Contains API's for changing the various options in host and card.\r
40 * See xsdps.h for a detailed description of the device and driver.\r
41 *\r
42 * <pre>\r
43 * MODIFICATION HISTORY:\r
44 *\r
45 * Ver   Who    Date     Changes\r
46 * ----- ---    -------- -----------------------------------------------\r
47 * 1.00a hk/sg  10/17/13 Initial release\r
48 * 2.1   hk     04/18/14 Increase sleep for eMMC switch command.\r
49 *                       Add sleep for microblaze designs. CR# 781117.\r
50 * 2.3   sk     09/23/14 Use XSdPs_Change_ClkFreq API whenever changing\r
51 *                                               clock.CR# 816586.\r
52 * 2.5   sg         07/09/15 Added SD 3.0 features\r
53 *       kvn    07/15/15 Modified the code according to MISRAC-2012.\r
54 *\r
55 * </pre>\r
56 *\r
57 ******************************************************************************/\r
58 \r
59 /***************************** Include Files *********************************/\r
60 #include "xsdps.h"\r
61 #include "xil_cache.h"\r
62 /*\r
63  * The header sleep.h and API usleep() can only be used with an arm design.\r
64  * MB_Sleep() is used for microblaze design.\r
65  */\r
66 #if defined (__arm__) || defined (__aarch64__)\r
67 \r
68 #include "sleep.h"\r
69 \r
70 #endif\r
71 \r
72 #ifdef __MICROBLAZE__\r
73 \r
74 #include "microblaze_sleep.h"\r
75 \r
76 #endif\r
77 \r
78 #include <FreeRTOS.h>\r
79 #include "task.h"\r
80 \r
81 #include "FreeRTOSFATConfig.h"\r
82 #include "uncached_memory.h"\r
83 \r
84 /************************** Constant Definitions *****************************/\r
85 \r
86 /**************************** Type Definitions *******************************/\r
87 \r
88 /***************** Macros (Inline Functions) Definitions *********************/\r
89 \r
90 /************************** Function Prototypes ******************************/\r
91 s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);\r
92 void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);\r
93 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);\r
94 static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr);\r
95 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);\r
96 \r
97 #if( ffconfigSDIO_DRIVER_USES_INTERRUPT != 0 )\r
98         /* Declared in ff_sddisk.c :\r
99         Function will sleep and get interrupted on a change of\r
100         the status register.  It will loop until:\r
101                 1. Expected bit (ulMask) becomes high\r
102                 2. Time-out reached (normally 2 seconds)\r
103         */\r
104         extern u32 XSdPs_WaitInterrupt( XSdPs *InstancePtr, u32 ulMask );\r
105         /* Clear the interrupt before using it. */\r
106         extern void XSdPs_ClearInterrupt( XSdPs *InstancePtr );\r
107 #else\r
108         #error Please define ffconfigSDIO_DRIVER_USES_INTERRUPT\r
109 #endif\r
110 \r
111 /*****************************************************************************/\r
112 /**\r
113 * Update Block size for read/write operations.\r
114 *\r
115 * @param        InstancePtr is a pointer to the instance to be worked on.\r
116 * @param        BlkSize - Block size passed by the user.\r
117 *\r
118 * @return       None\r
119 *\r
120 ******************************************************************************/\r
121 s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize)\r
122 {\r
123         s32 Status;\r
124         u32 PresentStateReg;\r
125 \r
126         Xil_AssertNonvoid(InstancePtr != NULL);\r
127         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
128 \r
129         PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
130                         XSDPS_PRES_STATE_OFFSET);\r
131 \r
132         if ((PresentStateReg & ((u32)XSDPS_PSR_INHIBIT_CMD_MASK |\r
133                         (u32)XSDPS_PSR_INHIBIT_DAT_MASK |\r
134                         (u32)XSDPS_PSR_WR_ACTIVE_MASK | (u32)XSDPS_PSR_RD_ACTIVE_MASK)) != 0U) {\r
135                 Status = XST_FAILURE;\r
136                 goto RETURN_PATH;\r
137         }\r
138 \r
139 \r
140         /* Send block write command */\r
141         Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0U);\r
142         if (Status != XST_SUCCESS) {\r
143                 Status = XST_FAILURE;\r
144                 goto RETURN_PATH;\r
145         }\r
146 \r
147         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
148                         XSDPS_RESP0_OFFSET);\r
149 \r
150         /* Set block size to the value passed */\r
151         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,\r
152                          BlkSize & XSDPS_BLK_SIZE_MASK);\r
153 \r
154         Status = XST_SUCCESS;\r
155 \r
156         RETURN_PATH:\r
157                 return Status;\r
158 \r
159 }\r
160 \r
161 /*****************************************************************************/\r
162 /**\r
163 *\r
164 * API to get bus width support by card.\r
165 *\r
166 *\r
167 * @param        InstancePtr is a pointer to the XSdPs instance.\r
168 * @param        SCR - buffer to store SCR register returned by card.\r
169 *\r
170 * @return\r
171 *               - XST_SUCCESS if successful.\r
172 *               - XST_FAILURE if fail.\r
173 *\r
174 * @note         None.\r
175 *\r
176 ******************************************************************************/\r
177 s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR)\r
178 {\r
179         s32 Status;\r
180         u16 BlkCnt;\r
181         u16 BlkSize;\r
182         s32 LoopCnt;\r
183 \r
184         Xil_AssertNonvoid(InstancePtr != NULL);\r
185         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
186 \r
187         for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) {\r
188                 SCR[LoopCnt] = 0U;\r
189         }\r
190 \r
191         /* Send block write command */\r
192         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,\r
193                         InstancePtr->RelCardAddr, 0U);\r
194         if (Status != XST_SUCCESS) {\r
195                 Status = XST_FAILURE;\r
196                 goto RETURN_PATH;\r
197         }\r
198 \r
199         BlkCnt = XSDPS_SCR_BLKCNT;\r
200         BlkSize = XSDPS_SCR_BLKSIZE;\r
201 \r
202         /* Set block size to the value passed */\r
203         BlkSize &= XSDPS_BLK_SIZE_MASK;\r
204         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
205                         XSDPS_BLK_SIZE_OFFSET, BlkSize);\r
206 \r
207         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR);\r
208 \r
209         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
210                         XSDPS_XFER_MODE_OFFSET,\r
211                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
212 \r
213         Xil_DCacheInvalidateRange((u32)SCR, 8);\r
214 \r
215         Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0U, BlkCnt);\r
216         if (Status != XST_SUCCESS) {\r
217                 Status = XST_FAILURE;\r
218                 goto RETURN_PATH;\r
219         }\r
220 \r
221         /*\r
222          * Check for transfer complete\r
223          */\r
224         Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
225         if (Status != XST_SUCCESS) {\r
226                 goto RETURN_PATH;\r
227         }\r
228 \r
229         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
230                         XSDPS_RESP0_OFFSET);\r
231 \r
232         Status = XST_SUCCESS;\r
233 \r
234         RETURN_PATH:\r
235                 return Status;\r
236 \r
237 }\r
238 \r
239 /*****************************************************************************/\r
240 /**\r
241 *\r
242 * API to set bus width to 4-bit in card and host\r
243 *\r
244 *\r
245 * @param        InstancePtr is a pointer to the XSdPs instance.\r
246 *\r
247 * @return\r
248 *               - XST_SUCCESS if successful.\r
249 *               - XST_FAILURE if fail.\r
250 *\r
251 * @note         None.\r
252 *\r
253 ******************************************************************************/\r
254 s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr)\r
255 {\r
256         s32 Status;\r
257         u32 StatusReg;\r
258         u32 Arg;\r
259 \r
260         Xil_AssertNonvoid(InstancePtr != NULL);\r
261         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
262 \r
263 \r
264         if (InstancePtr->CardType == XSDPS_CARD_SD) {\r
265 \r
266                 Status = XSdPs_CmdTransfer(InstancePtr, CMD55, InstancePtr->RelCardAddr,\r
267                                 0U);\r
268                 if (Status != XST_SUCCESS) {\r
269                         Status = XST_FAILURE;\r
270                         goto RETURN_PATH;\r
271                 }\r
272 \r
273                 InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;\r
274 \r
275                 Arg = ((u32)InstancePtr->BusWidth);\r
276 \r
277                 Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0U);\r
278                 if (Status != XST_SUCCESS) {\r
279                         Status = XST_FAILURE;\r
280                         goto RETURN_PATH;\r
281                 }\r
282         } else {\r
283 \r
284                 if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3)\r
285                                 && (InstancePtr->CardType == XSDPS_CHIP_EMMC)) {\r
286                         /* in case of eMMC data width 8-bit */\r
287                         InstancePtr->BusWidth = XSDPS_8_BIT_WIDTH;\r
288                 } else {\r
289                         InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;\r
290                 }\r
291 \r
292                 if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {\r
293                         Arg = XSDPS_MMC_8_BIT_BUS_ARG;\r
294                 } else {\r
295                         Arg = XSDPS_MMC_4_BIT_BUS_ARG;\r
296                 }\r
297 \r
298                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);\r
299                 if (Status != XST_SUCCESS) {\r
300                         Status = XST_FAILURE;\r
301                         goto RETURN_PATH;\r
302                 }\r
303 \r
304                 /* Check for transfer complete */\r
305                 Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
306                 if (Status != XST_SUCCESS) {\r
307                         goto RETURN_PATH;\r
308                 }\r
309         }\r
310 \r
311 #if defined (__arm__) || defined (__aarch64__)\r
312 \r
313         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);\r
314 \r
315 #endif\r
316 \r
317 #ifdef __MICROBLAZE__\r
318 \r
319         /* 2 msec delay */\r
320         MB_Sleep(2);\r
321 \r
322 #endif\r
323 \r
324         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,\r
325                                         XSDPS_HOST_CTRL1_OFFSET);\r
326 \r
327         /* Width setting in controller */\r
328         if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {\r
329                 StatusReg |= XSDPS_HC_EXT_BUS_WIDTH;\r
330         } else {\r
331                 StatusReg |= XSDPS_HC_WIDTH_MASK;\r
332         }\r
333 \r
334         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,\r
335                         XSDPS_HOST_CTRL1_OFFSET,\r
336                         (u8)StatusReg);\r
337 \r
338         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
339                         XSDPS_RESP0_OFFSET);\r
340 \r
341         Status = XST_SUCCESS;\r
342 \r
343         RETURN_PATH:\r
344                 return Status;\r
345 \r
346 }\r
347 \r
348 /*****************************************************************************/\r
349 /**\r
350 *\r
351 * API to get bus speed supported by card.\r
352 *\r
353 *\r
354 * @param        InstancePtr is a pointer to the XSdPs instance.\r
355 * @param        ReadBuff - buffer to store function group support data\r
356 *               returned by card.\r
357 *\r
358 * @return\r
359 *               - XST_SUCCESS if successful.\r
360 *               - XST_FAILURE if fail.\r
361 *\r
362 * @note         None.\r
363 *\r
364 ******************************************************************************/\r
365 s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff)\r
366 {\r
367         s32 Status;\r
368         u32 Arg;\r
369         u16 BlkCnt;\r
370         u16 BlkSize;\r
371         s32 LoopCnt;\r
372 \r
373         Xil_AssertNonvoid(InstancePtr != NULL);\r
374         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
375 \r
376         for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) {\r
377                 ReadBuff[LoopCnt] = 0U;\r
378         }\r
379 \r
380         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;\r
381         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;\r
382         BlkSize &= XSDPS_BLK_SIZE_MASK;\r
383         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
384                         XSDPS_BLK_SIZE_OFFSET, BlkSize);\r
385 \r
386         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);\r
387 \r
388         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
389                         XSDPS_XFER_MODE_OFFSET,\r
390                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
391 \r
392         Arg = XSDPS_SWITCH_CMD_HS_GET;\r
393 \r
394         Xil_DCacheInvalidateRange((u32)ReadBuff, 64);\r
395 \r
396         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);\r
397         if (Status != XST_SUCCESS) {\r
398                 Status = XST_FAILURE;\r
399                 goto RETURN_PATH;\r
400         }\r
401 \r
402         /*\r
403          * Check for transfer complete\r
404          */\r
405         Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
406         if (Status != XST_SUCCESS) {\r
407                 goto RETURN_PATH;\r
408         }\r
409 \r
410         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
411                         XSDPS_RESP0_OFFSET);\r
412 \r
413         Status = XST_SUCCESS;\r
414 \r
415         RETURN_PATH:\r
416                 return Status;\r
417 \r
418 }\r
419 \r
420 /*****************************************************************************/\r
421 /**\r
422 *\r
423 * API to set high speed in card and host. Changes clock in host accordingly.\r
424 *\r
425 *\r
426 * @param        InstancePtr is a pointer to the XSdPs instance.\r
427 *\r
428 * @return\r
429 *               - XST_SUCCESS if successful.\r
430 *               - XST_FAILURE if fail.\r
431 *\r
432 * @note         None.\r
433 *\r
434 ******************************************************************************/\r
435 s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr)\r
436 {\r
437         s32 Status;\r
438         u32 StatusReg;\r
439         u32 Arg;\r
440         u16 BlkCnt;\r
441         u16 BlkSize;\r
442         u8 ReadBuff[64];\r
443 \r
444         Xil_AssertNonvoid(InstancePtr != NULL);\r
445         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
446 \r
447         if (InstancePtr->CardType == XSDPS_CARD_SD) {\r
448 \r
449                 BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;\r
450                 BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;\r
451                 BlkSize &= XSDPS_BLK_SIZE_MASK;\r
452                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
453                                 XSDPS_BLK_SIZE_OFFSET, BlkSize);\r
454 \r
455                 XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);\r
456 \r
457                 Xil_DCacheFlushRange((u32)ReadBuff, 64);\r
458 \r
459                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
460                                 XSDPS_XFER_MODE_OFFSET,\r
461                                 XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
462 \r
463                 Arg = XSDPS_SWITCH_CMD_HS_SET;\r
464 \r
465                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);\r
466                 if (Status != XST_SUCCESS) {\r
467                         Status = XST_FAILURE;\r
468                         goto RETURN_PATH;\r
469                 }\r
470 \r
471                 /*\r
472                  * Check for transfer complete\r
473                  */\r
474                 Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
475                 if (Status != XST_SUCCESS) {\r
476                         goto RETURN_PATH;\r
477                 }\r
478 \r
479                 /* Change the clock frequency to 50 MHz */\r
480                 InstancePtr->BusSpeed = XSDPS_CLK_50_MHZ;\r
481                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);\r
482                 if (Status != XST_SUCCESS) {\r
483                                 Status = XST_FAILURE;\r
484                                 goto RETURN_PATH;\r
485                 }\r
486 \r
487         } else if (InstancePtr->CardType == XSDPS_CARD_MMC) {\r
488                 Arg = XSDPS_MMC_HIGH_SPEED_ARG;\r
489 \r
490                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);\r
491                 if (Status != XST_SUCCESS) {\r
492                         Status = XST_FAILURE;\r
493                         goto RETURN_PATH;\r
494                 }\r
495 \r
496                 /*\r
497                  * Check for transfer complete\r
498                  */\r
499                 Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
500                 if (Status != XST_SUCCESS) {\r
501                         goto RETURN_PATH;\r
502                 }\r
503 \r
504                 /* Change the clock frequency to 52 MHz */\r
505                 InstancePtr->BusSpeed = XSDPS_CLK_52_MHZ;\r
506                 Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ);\r
507                 if (Status != XST_SUCCESS) {\r
508                         Status = XST_FAILURE;\r
509                         goto RETURN_PATH;\r
510                 }\r
511         } else {\r
512                 Arg = XSDPS_MMC_HS200_ARG;\r
513 \r
514                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);\r
515                 if (Status != XST_SUCCESS) {\r
516                         Status = XST_FAILURE;\r
517                         goto RETURN_PATH;\r
518                 }\r
519 \r
520                 /*\r
521                  * Check for transfer complete\r
522                  */\r
523                 Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
524                 if (Status != XST_SUCCESS) {\r
525                         goto RETURN_PATH;\r
526                 }\r
527 \r
528                 /* Change the clock frequency to 200 MHz */\r
529                 InstancePtr->BusSpeed = XSDPS_MMC_HS200_MAX_CLK;\r
530 \r
531                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);\r
532                 if (Status != XST_SUCCESS) {\r
533                         Status = XST_FAILURE;\r
534                         goto RETURN_PATH;\r
535                 }\r
536                 Status = XSdPs_Execute_Tuning(InstancePtr);\r
537                 if (Status != XST_SUCCESS) {\r
538                         Status = XST_FAILURE;\r
539                         goto RETURN_PATH;\r
540                 }\r
541         }\r
542 \r
543 #if defined (__arm__) || defined (__aarch64__)\r
544 \r
545         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);\r
546 \r
547 #endif\r
548 \r
549 #ifdef __MICROBLAZE__\r
550 \r
551         /* 2 msec delay */\r
552         MB_Sleep(2);\r
553 \r
554 #endif\r
555 \r
556         StatusReg = (s32)XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,\r
557                                         XSDPS_HOST_CTRL1_OFFSET);\r
558         StatusReg |= XSDPS_HC_SPEED_MASK;\r
559         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,\r
560                         XSDPS_HOST_CTRL1_OFFSET, (u8)StatusReg);\r
561 \r
562         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
563                         XSDPS_RESP0_OFFSET);\r
564 \r
565 \r
566         Status = XST_SUCCESS;\r
567 \r
568         RETURN_PATH:\r
569                 return Status;\r
570 \r
571 }\r
572 \r
573 /*****************************************************************************/\r
574 /**\r
575 *\r
576 * API to change clock freq to given value.\r
577 *\r
578 *\r
579 * @param        InstancePtr is a pointer to the XSdPs instance.\r
580 * @param        SelFreq - Clock frequency in Hz.\r
581 *\r
582 * @return       None\r
583 *\r
584 * @note         This API will change clock frequency to the value less than\r
585 *               or equal to the given value using the permissible dividors.\r
586 *\r
587 ******************************************************************************/\r
588 s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)\r
589 {\r
590         u16 ClockReg;\r
591         u16 DivCnt;\r
592         u16 Divisor = 0U;\r
593         u16 ExtDivisor;\r
594         s32 Status;\r
595         u16 ReadReg;\r
596 \r
597         Xil_AssertNonvoid(InstancePtr != NULL);\r
598         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
599 \r
600         /* Disable clock */\r
601         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
602                         XSDPS_CLK_CTRL_OFFSET);\r
603         ClockReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK);\r
604         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
605                         XSDPS_CLK_CTRL_OFFSET, ClockReg);\r
606 \r
607         if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {\r
608                 /* Calculate divisor */\r
609                 for (DivCnt = 0x1U; DivCnt <= XSDPS_CC_EXT_MAX_DIV_CNT;DivCnt++) {\r
610                         if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {\r
611                                 Divisor = DivCnt >> 1;\r
612                                 break;\r
613                         }\r
614                 }\r
615 \r
616                 if (DivCnt > XSDPS_CC_EXT_MAX_DIV_CNT) {\r
617                         /* No valid divisor found for given frequency */\r
618                         Status = XST_FAILURE;\r
619                         goto RETURN_PATH;\r
620                 }\r
621         } else {\r
622                 /* Calculate divisor */\r
623                 DivCnt = 0x1U;\r
624                 while (DivCnt <= XSDPS_CC_MAX_DIV_CNT) {\r
625                         if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {\r
626                                 Divisor = DivCnt / 2U;\r
627                                 break;\r
628                         }\r
629                         DivCnt = DivCnt << 1U;\r
630                 }\r
631 \r
632                 if (DivCnt > XSDPS_CC_MAX_DIV_CNT) {\r
633                         /* No valid divisor found for given frequency */\r
634                         Status = XST_FAILURE;\r
635                         goto RETURN_PATH;\r
636                 }\r
637         }\r
638 \r
639         /* Set clock divisor */\r
640         if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {\r
641                 ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
642                                 XSDPS_CLK_CTRL_OFFSET);\r
643                 ClockReg &= ~(XSDPS_CC_SDCLK_FREQ_SEL_MASK |\r
644                 XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK);\r
645 \r
646                 ExtDivisor = Divisor >> 8;\r
647                 ExtDivisor <<= XSDPS_CC_EXT_DIV_SHIFT;\r
648                 ExtDivisor &= XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK;\r
649 \r
650                 Divisor <<= XSDPS_CC_DIV_SHIFT;\r
651                 Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;\r
652                 ClockReg |= Divisor | ExtDivisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;\r
653                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,\r
654                                 ClockReg);\r
655         } else {\r
656                 ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
657                                 XSDPS_CLK_CTRL_OFFSET);\r
658                 ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK);\r
659 \r
660                 Divisor <<= XSDPS_CC_DIV_SHIFT;\r
661                 Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;\r
662                 ClockReg |= Divisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;\r
663                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,\r
664                                 ClockReg);\r
665         }\r
666 \r
667         /* Wait for internal clock to stabilize */\r
668         ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
669                                 XSDPS_CLK_CTRL_OFFSET);\r
670         while((ReadReg & XSDPS_CC_INT_CLK_STABLE_MASK) == 0U) {\r
671                 ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
672                                         XSDPS_CLK_CTRL_OFFSET);;\r
673         }\r
674 \r
675         /* Enable SD clock */\r
676         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
677                         XSDPS_CLK_CTRL_OFFSET);\r
678         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
679                         XSDPS_CLK_CTRL_OFFSET,\r
680                         ClockReg | XSDPS_CC_SD_CLK_EN_MASK);\r
681 \r
682         Status = XST_SUCCESS;\r
683 \r
684 RETURN_PATH:\r
685                 return Status;\r
686 \r
687 }\r
688 \r
689 /*****************************************************************************/\r
690 /**\r
691 *\r
692 * API to send pullup command to card before using DAT line 3(using 4-bit bus)\r
693 *\r
694 *\r
695 * @param        InstancePtr is a pointer to the XSdPs instance.\r
696 *\r
697 * @return\r
698 *               - XST_SUCCESS if successful.\r
699 *               - XST_FAILURE if fail.\r
700 *\r
701 * @note         None.\r
702 *\r
703 ******************************************************************************/\r
704 s32 XSdPs_Pullup(XSdPs *InstancePtr)\r
705 {\r
706         s32 Status;\r
707 \r
708         Xil_AssertNonvoid(InstancePtr != NULL);\r
709         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
710 \r
711         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,\r
712                         InstancePtr->RelCardAddr, 0U);\r
713         if (Status != XST_SUCCESS) {\r
714                 Status = XST_FAILURE;\r
715                 goto RETURN_PATH;\r
716         }\r
717 \r
718         Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0U, 0U);\r
719         if (Status != XST_SUCCESS) {\r
720                 Status = XST_FAILURE;\r
721                 goto RETURN_PATH;\r
722         }\r
723 \r
724         Status = XST_SUCCESS;\r
725 \r
726         RETURN_PATH:\r
727                 return Status;\r
728 \r
729 }\r
730 \r
731 /*****************************************************************************/\r
732 /**\r
733 *\r
734 * API to get EXT_CSD register of eMMC.\r
735 *\r
736 *\r
737 * @param        InstancePtr is a pointer to the XSdPs instance.\r
738 * @param        ReadBuff - buffer to store EXT_CSD\r
739 *\r
740 * @return\r
741 *               - XST_SUCCESS if successful.\r
742 *               - XST_FAILURE if fail.\r
743 *\r
744 * @note         None.\r
745 *\r
746 ******************************************************************************/\r
747 s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff)\r
748 {\r
749         s32 Status;\r
750         u32 Arg = 0U;\r
751         u16 BlkCnt;\r
752         u16 BlkSize;\r
753         s32 LoopCnt;\r
754 \r
755         Xil_AssertNonvoid(InstancePtr != NULL);\r
756         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
757 \r
758         for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) {\r
759                 ReadBuff[LoopCnt] = 0U;\r
760         }\r
761 \r
762         BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT;\r
763         BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE;\r
764         BlkSize &= XSDPS_BLK_SIZE_MASK;\r
765         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
766                         XSDPS_BLK_SIZE_OFFSET, BlkSize);\r
767 \r
768         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);\r
769 \r
770         Xil_DCacheInvalidateRange((u32)ReadBuff, 512U);\r
771 \r
772         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
773                         XSDPS_XFER_MODE_OFFSET,\r
774                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
775 \r
776 \r
777         /* Send SEND_EXT_CSD command */\r
778         Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1U);\r
779         if (Status != XST_SUCCESS) {\r
780                 Status = XST_FAILURE;\r
781                 goto RETURN_PATH;\r
782         }\r
783 \r
784         /*\r
785          * Check for transfer complete\r
786          */\r
787         Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
788         if (Status != XST_SUCCESS) {\r
789                 goto RETURN_PATH;\r
790         }\r
791 \r
792         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,\r
793                         XSDPS_RESP0_OFFSET);\r
794 \r
795         Status = XST_SUCCESS;\r
796 \r
797         RETURN_PATH:\r
798                 return Status;\r
799 \r
800 }\r
801 \r
802 \r
803 /*****************************************************************************/\r
804 /**\r
805 *\r
806 * API to UHS-I mode initialization\r
807 *\r
808 *\r
809 * @param        InstancePtr is a pointer to the XSdPs instance.\r
810 * @param        Mode UHS-I mode\r
811 *\r
812 * @return\r
813 *               - XST_SUCCESS if successful.\r
814 *               - XST_FAILURE if fail.\r
815 *\r
816 * @note         None.\r
817 *\r
818 ******************************************************************************/\r
819 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode)\r
820 {\r
821         s32 Status;\r
822         u16 CtrlReg;\r
823         u32 Arg;\r
824         u16 BlkCnt;\r
825         u16 BlkSize;\r
826         u8 ReadBuff[64];\r
827 \r
828         Xil_AssertNonvoid(InstancePtr != NULL);\r
829         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
830 \r
831         /* Drive strength */\r
832 \r
833         /* Bus speed mode selection */\r
834         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;\r
835         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;\r
836         BlkSize &= XSDPS_BLK_SIZE_MASK;\r
837         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,\r
838                         BlkSize);\r
839 \r
840         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);\r
841 \r
842         Xil_DCacheFlushRange((u32)ReadBuff, 64);\r
843 \r
844         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,\r
845                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
846 \r
847         switch (Mode) {\r
848         case 0U:\r
849                 Arg = XSDPS_SWITCH_CMD_SDR12_SET;\r
850                 InstancePtr->BusSpeed = XSDPS_SD_SDR12_MAX_CLK;\r
851                 break;\r
852         case 1U:\r
853                 Arg = XSDPS_SWITCH_CMD_SDR25_SET;\r
854                 InstancePtr->BusSpeed = XSDPS_SD_SDR25_MAX_CLK;\r
855                 break;\r
856         case 2U:\r
857                 Arg = XSDPS_SWITCH_CMD_SDR50_SET;\r
858                 InstancePtr->BusSpeed = XSDPS_SD_SDR50_MAX_CLK;\r
859                 break;\r
860         case 3U:\r
861                 Arg = XSDPS_SWITCH_CMD_SDR104_SET;\r
862                 InstancePtr->BusSpeed = XSDPS_SD_SDR104_MAX_CLK;\r
863                 break;\r
864         case 4U:\r
865                 Arg = XSDPS_SWITCH_CMD_DDR50_SET;\r
866                 InstancePtr->BusSpeed = XSDPS_SD_DDR50_MAX_CLK;\r
867                 break;\r
868         default:\r
869                 Status = XST_FAILURE;\r
870                 goto RETURN_PATH;\r
871                 break;\r
872         }\r
873 \r
874         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);\r
875         if (Status != XST_SUCCESS) {\r
876                 Status = XST_FAILURE;\r
877                 goto RETURN_PATH;\r
878         }\r
879 \r
880         /*\r
881          * Check for transfer complete\r
882          */\r
883         Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
884         if (Status != XST_SUCCESS) {\r
885                 goto RETURN_PATH;\r
886         }\r
887 \r
888         /* Current limit */\r
889 \r
890         /* Set UHS mode in controller */\r
891         CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,\r
892                         XSDPS_HOST_CTRL2_OFFSET);\r
893         CtrlReg &= (u16)(~XSDPS_HC2_UHS_MODE_MASK);\r
894         CtrlReg |= Mode;\r
895         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,\r
896                         XSDPS_HOST_CTRL2_OFFSET, CtrlReg);\r
897 \r
898         /* Change the clock frequency */\r
899         Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);\r
900         if (Status != XST_SUCCESS) {\r
901                         Status = XST_FAILURE;\r
902                         goto RETURN_PATH;\r
903         }\r
904 \r
905         if((Mode == XSDPS_UHS_SPEED_MODE_SDR104) ||\r
906                         (Mode == XSDPS_UHS_SPEED_MODE_DDR50)) {\r
907                 /* Send tuning pattern */\r
908                 Status = XSdPs_Execute_Tuning(InstancePtr);\r
909                 if (Status != XST_SUCCESS) {\r
910                                 Status = XST_FAILURE;\r
911                                 goto RETURN_PATH;\r
912                 }\r
913         }\r
914 \r
915         Status = XST_SUCCESS;\r
916 \r
917         RETURN_PATH:\r
918                 return Status;\r
919 }\r
920 \r
921 static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)\r
922 {\r
923         s32 Status;\r
924         u16 BlkCnt;\r
925         u16 BlkSize;\r
926         s32 LoopCnt;\r
927         u8 ReadBuff[128];\r
928 \r
929         Xil_AssertNonvoid(InstancePtr != NULL);\r
930         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);\r
931 \r
932         BlkCnt = XSDPS_TUNING_CMD_BLKCNT;\r
933         BlkSize = XSDPS_TUNING_CMD_BLKSIZE;\r
934         if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH)\r
935         {\r
936                 BlkSize = BlkSize*2U;\r
937         }\r
938         BlkSize &= XSDPS_BLK_SIZE_MASK;\r
939         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,\r
940                         BlkSize);\r
941 \r
942         for (LoopCnt = 0; LoopCnt < (s32)BlkSize; LoopCnt++) {\r
943                 ReadBuff[LoopCnt] = 0U;\r
944         }\r
945 \r
946         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);\r
947 \r
948         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,\r
949                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);\r
950 \r
951         Xil_DCacheInvalidateRange((u32)ReadBuff, BlkSize);\r
952 \r
953         if(InstancePtr->CardType == XSDPS_CARD_SD) {\r
954                 Status = XSdPs_CmdTransfer(InstancePtr, CMD19, 0U, 1U);\r
955         } else {\r
956                 Status = XSdPs_CmdTransfer(InstancePtr, CMD21, 0U, 1U);\r
957         }\r
958 \r
959         if (Status != XST_SUCCESS) {\r
960                 Status = XST_FAILURE;\r
961                 goto RETURN_PATH;\r
962         }\r
963 \r
964         /*\r
965          * Check for transfer complete\r
966          * Polling for response for now\r
967          */\r
968         Status = XSdPs_Wait_For(InstancePtr, XSDPS_INTR_TC_MASK, pdTRUE);\r
969         if (Status != XST_SUCCESS) {\r
970                 goto RETURN_PATH;\r
971         }\r
972 \r
973         Status = XST_SUCCESS;\r
974 \r
975         RETURN_PATH: return Status;\r
976 \r
977 }\r
978 /** @} */\r