]> git.sur5r.net Git - freertos/blob
8151eef1b6db7f6d678458a8add4f13abbc586f7
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2013 - 2015 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 * @addtogroup sdps_v2_5
37 * @{
38 *
39 * Contains API's for changing the various options in host and card.
40 * See xsdps.h for a detailed description of the device and driver.
41 *
42 * <pre>
43 * MODIFICATION HISTORY:
44 *
45 * Ver   Who    Date     Changes
46 * ----- ---    -------- -----------------------------------------------
47 * 1.00a hk/sg  10/17/13 Initial release
48 * 2.1   hk     04/18/14 Increase sleep for eMMC switch command.
49 *                       Add sleep for microblaze designs. CR# 781117.
50 * 2.3   sk     09/23/14 Use XSdPs_Change_ClkFreq API whenever changing
51 *                                               clock.CR# 816586.
52 * 2.5   sg         07/09/15 Added SD 3.0 features
53 *       kvn    07/15/15 Modified the code according to MISRAC-2012.
54 * 2.7   sk     01/08/16 Added workaround for issue in auto tuning mode
55 *                       of SDR50, SDR104 and HS200.
56 *       sk     02/16/16 Corrected the Tuning logic.
57 *       sk     03/02/16 Configured the Tap Delay values for eMMC HS200 mode.
58 *
59 * </pre>
60 *
61 ******************************************************************************/
62
63 /***************************** Include Files *********************************/
64 #include "xsdps.h"
65 /*
66  * The header sleep.h and API usleep() can only be used with an arm design.
67  * MB_Sleep() is used for microblaze design.
68  */
69 #if defined (__arm__) || defined (__aarch64__)
70
71 #include "sleep.h"
72
73 #endif
74
75 #ifdef __MICROBLAZE__
76
77 #include "microblaze_sleep.h"
78
79 #endif
80
81 /************************** Constant Definitions *****************************/
82
83 /**************************** Type Definitions *******************************/
84
85 /***************** Macros (Inline Functions) Definitions *********************/
86
87 /************************** Function Prototypes ******************************/
88 s32 XSdPs_CmdTransfer(XSdPs *InstancePtr, u32 Cmd, u32 Arg, u32 BlkCnt);
89 void XSdPs_SetupADMA2DescTbl(XSdPs *InstancePtr, u32 BlkCnt, const u8 *Buff);
90 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
91 static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr);
92 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode);
93 #if defined (__arm__) || defined (__aarch64__)
94 void XSdPs_SetTapDelay(XSdPs *InstancePtr);
95 #endif
96
97 /*****************************************************************************/
98 /**
99 * Update Block size for read/write operations.
100 *
101 * @param        InstancePtr is a pointer to the instance to be worked on.
102 * @param        BlkSize - Block size passed by the user.
103 *
104 * @return       None
105 *
106 ******************************************************************************/
107 s32 XSdPs_SetBlkSize(XSdPs *InstancePtr, u16 BlkSize)
108 {
109         s32 Status;
110         u32 PresentStateReg;
111
112         Xil_AssertNonvoid(InstancePtr != NULL);
113         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
114
115         PresentStateReg = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
116                         XSDPS_PRES_STATE_OFFSET);
117
118         if ((PresentStateReg & ((u32)XSDPS_PSR_INHIBIT_CMD_MASK |
119                         (u32)XSDPS_PSR_INHIBIT_DAT_MASK |
120                         (u32)XSDPS_PSR_WR_ACTIVE_MASK | (u32)XSDPS_PSR_RD_ACTIVE_MASK)) != 0U) {
121                 Status = XST_FAILURE;
122                 goto RETURN_PATH;
123         }
124
125
126         /* Send block write command */
127         Status = XSdPs_CmdTransfer(InstancePtr, CMD16, BlkSize, 0U);
128         if (Status != XST_SUCCESS) {
129                 Status = XST_FAILURE;
130                 goto RETURN_PATH;
131         }
132
133         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
134                         XSDPS_RESP0_OFFSET);
135
136         /* Set block size to the value passed */
137         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
138                          BlkSize & XSDPS_BLK_SIZE_MASK);
139
140         Status = XST_SUCCESS;
141
142         RETURN_PATH:
143                 return Status;
144
145 }
146
147 /*****************************************************************************/
148 /**
149 *
150 * API to get bus width support by card.
151 *
152 *
153 * @param        InstancePtr is a pointer to the XSdPs instance.
154 * @param        SCR - buffer to store SCR register returned by card.
155 *
156 * @return
157 *               - XST_SUCCESS if successful.
158 *               - XST_FAILURE if fail.
159 *
160 * @note         None.
161 *
162 ******************************************************************************/
163 s32 XSdPs_Get_BusWidth(XSdPs *InstancePtr, u8 *SCR)
164 {
165         s32 Status;
166         u32 StatusReg;
167         u16 BlkCnt;
168         u16 BlkSize;
169         s32 LoopCnt;
170
171         Xil_AssertNonvoid(InstancePtr != NULL);
172         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
173
174         for (LoopCnt = 0; LoopCnt < 8; LoopCnt++) {
175                 SCR[LoopCnt] = 0U;
176         }
177
178         /* Send block write command */
179         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
180                         InstancePtr->RelCardAddr, 0U);
181         if (Status != XST_SUCCESS) {
182                 Status = XST_FAILURE;
183                 goto RETURN_PATH;
184         }
185
186         BlkCnt = XSDPS_SCR_BLKCNT;
187         BlkSize = XSDPS_SCR_BLKSIZE;
188
189         /* Set block size to the value passed */
190         BlkSize &= XSDPS_BLK_SIZE_MASK;
191         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
192                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
193
194         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, SCR);
195
196         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
197                         XSDPS_XFER_MODE_OFFSET,
198                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
199
200         Xil_DCacheInvalidateRange((INTPTR)SCR, 8);
201
202         Status = XSdPs_CmdTransfer(InstancePtr, ACMD51, 0U, BlkCnt);
203         if (Status != XST_SUCCESS) {
204                 Status = XST_FAILURE;
205                 goto RETURN_PATH;
206         }
207
208         /*
209          * Check for transfer complete
210          * Polling for response for now
211          */
212         do {
213                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
214                                         XSDPS_NORM_INTR_STS_OFFSET);
215                 if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
216                         /* Write to clear error bits */
217                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
218                                         XSDPS_ERR_INTR_STS_OFFSET,
219                                         XSDPS_ERROR_INTR_ALL_MASK);
220                         Status = XST_FAILURE;
221                         goto RETURN_PATH;
222                 }
223         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
224
225         /* Write to clear bit */
226         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
227                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
228
229         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
230                         XSDPS_RESP0_OFFSET);
231
232         Status = XST_SUCCESS;
233
234         RETURN_PATH:
235                 return Status;
236
237 }
238
239 /*****************************************************************************/
240 /**
241 *
242 * API to set bus width to 4-bit in card and host
243 *
244 *
245 * @param        InstancePtr is a pointer to the XSdPs instance.
246 *
247 * @return
248 *               - XST_SUCCESS if successful.
249 *               - XST_FAILURE if fail.
250 *
251 * @note         None.
252 *
253 ******************************************************************************/
254 s32 XSdPs_Change_BusWidth(XSdPs *InstancePtr)
255 {
256         s32 Status;
257         u32 StatusReg;
258         u32 Arg;
259
260         Xil_AssertNonvoid(InstancePtr != NULL);
261         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
262
263
264         if (InstancePtr->CardType == XSDPS_CARD_SD) {
265
266                 Status = XSdPs_CmdTransfer(InstancePtr, CMD55, InstancePtr->RelCardAddr,
267                                 0U);
268                 if (Status != XST_SUCCESS) {
269                         Status = XST_FAILURE;
270                         goto RETURN_PATH;
271                 }
272
273                 InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;
274
275                 Arg = ((u32)InstancePtr->BusWidth);
276
277                 Status = XSdPs_CmdTransfer(InstancePtr, ACMD6, Arg, 0U);
278                 if (Status != XST_SUCCESS) {
279                         Status = XST_FAILURE;
280                         goto RETURN_PATH;
281                 }
282         } else {
283
284                 if ((InstancePtr->HC_Version == XSDPS_HC_SPEC_V3)
285                                 && (InstancePtr->CardType == XSDPS_CHIP_EMMC)) {
286                         /* in case of eMMC data width 8-bit */
287                         InstancePtr->BusWidth = XSDPS_8_BIT_WIDTH;
288                 } else {
289                         InstancePtr->BusWidth = XSDPS_4_BIT_WIDTH;
290                 }
291
292                 if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {
293                         Arg = XSDPS_MMC_8_BIT_BUS_ARG;
294                 } else {
295                         Arg = XSDPS_MMC_4_BIT_BUS_ARG;
296                 }
297
298                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
299                 if (Status != XST_SUCCESS) {
300                         Status = XST_FAILURE;
301                         goto RETURN_PATH;
302                 }
303
304                 /* Check for transfer complete */
305                 do {
306                         StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
307                                                 XSDPS_NORM_INTR_STS_OFFSET);
308                         if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
309                                 /* Write to clear error bits */
310                                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
311                                                 XSDPS_ERR_INTR_STS_OFFSET,
312                                                 XSDPS_ERROR_INTR_ALL_MASK);
313                                 Status = XST_FAILURE;
314                                 goto RETURN_PATH;
315                         }
316                 } while((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
317
318                 /* Write to clear bit */
319                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
320                                 XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
321         }
322
323 #if defined (__arm__) || defined (__aarch64__)
324
325         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
326
327 #endif
328
329 #ifdef __MICROBLAZE__
330
331         /* 2 msec delay */
332         MB_Sleep(2);
333
334 #endif
335
336         StatusReg = XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
337                                         XSDPS_HOST_CTRL1_OFFSET);
338
339         /* Width setting in controller */
340         if (InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH) {
341                 StatusReg |= XSDPS_HC_EXT_BUS_WIDTH;
342         } else {
343                 StatusReg |= XSDPS_HC_WIDTH_MASK;
344         }
345
346         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
347                         XSDPS_HOST_CTRL1_OFFSET,
348                         (u8)StatusReg);
349
350         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
351                         XSDPS_RESP0_OFFSET);
352
353         Status = XST_SUCCESS;
354
355         RETURN_PATH:
356                 return Status;
357
358 }
359
360 /*****************************************************************************/
361 /**
362 *
363 * API to get bus speed supported by card.
364 *
365 *
366 * @param        InstancePtr is a pointer to the XSdPs instance.
367 * @param        ReadBuff - buffer to store function group support data
368 *               returned by card.
369 *
370 * @return
371 *               - XST_SUCCESS if successful.
372 *               - XST_FAILURE if fail.
373 *
374 * @note         None.
375 *
376 ******************************************************************************/
377 s32 XSdPs_Get_BusSpeed(XSdPs *InstancePtr, u8 *ReadBuff)
378 {
379         s32 Status;
380         u32 StatusReg;
381         u32 Arg;
382         u16 BlkCnt;
383         u16 BlkSize;
384         s32 LoopCnt;
385
386         Xil_AssertNonvoid(InstancePtr != NULL);
387         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
388
389         for (LoopCnt = 0; LoopCnt < 64; LoopCnt++) {
390                 ReadBuff[LoopCnt] = 0U;
391         }
392
393         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
394         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
395         BlkSize &= XSDPS_BLK_SIZE_MASK;
396         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
397                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
398
399         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
400
401         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
402                         XSDPS_XFER_MODE_OFFSET,
403                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
404
405         Arg = XSDPS_SWITCH_CMD_HS_GET;
406
407         Xil_DCacheInvalidateRange((INTPTR)ReadBuff, 64);
408
409         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
410         if (Status != XST_SUCCESS) {
411                 Status = XST_FAILURE;
412                 goto RETURN_PATH;
413         }
414
415         /*
416          * Check for transfer complete
417          * Polling for response for now
418          */
419         do {
420                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
421                                         XSDPS_NORM_INTR_STS_OFFSET);
422                 if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
423                         /* Write to clear error bits */
424                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
425                                         XSDPS_ERR_INTR_STS_OFFSET,
426                                         XSDPS_ERROR_INTR_ALL_MASK);
427                         Status = XST_FAILURE;
428                         goto RETURN_PATH;
429                 }
430         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
431
432         /* Write to clear bit */
433         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
434                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
435
436         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
437                         XSDPS_RESP0_OFFSET);
438
439         Status = XST_SUCCESS;
440
441         RETURN_PATH:
442                 return Status;
443
444 }
445
446 /*****************************************************************************/
447 /**
448 *
449 * API to set high speed in card and host. Changes clock in host accordingly.
450 *
451 *
452 * @param        InstancePtr is a pointer to the XSdPs instance.
453 *
454 * @return
455 *               - XST_SUCCESS if successful.
456 *               - XST_FAILURE if fail.
457 *
458 * @note         None.
459 *
460 ******************************************************************************/
461 s32 XSdPs_Change_BusSpeed(XSdPs *InstancePtr)
462 {
463         s32 Status;
464         u32 StatusReg;
465         u32 Arg;
466         u32 ClockReg;
467         u16 BlkCnt;
468         u16 BlkSize;
469         u8 ReadBuff[64];
470
471         Xil_AssertNonvoid(InstancePtr != NULL);
472         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
473
474         if (InstancePtr->CardType == XSDPS_CARD_SD) {
475
476                 BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
477                 BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
478                 BlkSize &= XSDPS_BLK_SIZE_MASK;
479                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
480                                 XSDPS_BLK_SIZE_OFFSET, BlkSize);
481
482                 XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
483
484                 Xil_DCacheFlushRange((INTPTR)ReadBuff, 64);
485
486                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
487                                 XSDPS_XFER_MODE_OFFSET,
488                                 XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
489
490                 Arg = XSDPS_SWITCH_CMD_HS_SET;
491
492                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
493                 if (Status != XST_SUCCESS) {
494                         Status = XST_FAILURE;
495                         goto RETURN_PATH;
496                 }
497
498                 /*
499                  * Check for transfer complete
500                  * Polling for response for now
501                  */
502                 do {
503                         StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
504                                                 XSDPS_NORM_INTR_STS_OFFSET);
505                         if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
506                                 /* Write to clear error bits */
507                                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
508                                                 XSDPS_ERR_INTR_STS_OFFSET,
509                                                 XSDPS_ERROR_INTR_ALL_MASK);
510                                 Status = XST_FAILURE;
511                                 goto RETURN_PATH;
512                         }
513                 } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
514
515                 /* Write to clear bit */
516                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
517                                 XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
518
519                 /* Change the clock frequency to 50 MHz */
520                 InstancePtr->BusSpeed = XSDPS_CLK_50_MHZ;
521                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
522                 if (Status != XST_SUCCESS) {
523                                 Status = XST_FAILURE;
524                                 goto RETURN_PATH;
525                 }
526
527         } else if (InstancePtr->CardType == XSDPS_CARD_MMC) {
528                 Arg = XSDPS_MMC_HIGH_SPEED_ARG;
529
530                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
531                 if (Status != XST_SUCCESS) {
532                         Status = XST_FAILURE;
533                         goto RETURN_PATH;
534                 }
535
536                 /*
537                  * Check for transfer complete
538                  */
539                 do {
540                         StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
541                                                 XSDPS_NORM_INTR_STS_OFFSET);
542                         if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
543                                 /*
544                                  * Write to clear error bits
545                                  */
546                                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
547                                                 XSDPS_ERR_INTR_STS_OFFSET,
548                                                 XSDPS_ERROR_INTR_ALL_MASK);
549                                 Status = XST_FAILURE;
550                                 goto RETURN_PATH;
551                         }
552                 } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
553
554                 /*
555                  * Write to clear bit
556                  */
557                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
558                                 XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
559
560                 /* Change the clock frequency to 52 MHz */
561                 InstancePtr->BusSpeed = XSDPS_CLK_52_MHZ;
562                 Status = XSdPs_Change_ClkFreq(InstancePtr, XSDPS_CLK_52_MHZ);
563                 if (Status != XST_SUCCESS) {
564                         Status = XST_FAILURE;
565                         goto RETURN_PATH;
566                 }
567         } else {
568                 Arg = XSDPS_MMC_HS200_ARG;
569
570                 Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 0U);
571                 if (Status != XST_SUCCESS) {
572                         Status = XST_FAILURE;
573                         goto RETURN_PATH;
574                 }
575
576                 /*
577                  * Check for transfer complete
578                  */
579                 do {
580                         StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
581                                                 XSDPS_NORM_INTR_STS_OFFSET);
582                         if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
583                                 /*
584                                  * Write to clear error bits
585                                  */
586                                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
587                                                 XSDPS_ERR_INTR_STS_OFFSET,
588                                                 XSDPS_ERROR_INTR_ALL_MASK);
589                                 Status = XST_FAILURE;
590                                 goto RETURN_PATH;
591                         }
592                 } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
593
594                 /*
595                  * Write to clear bit
596                  */
597                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
598                                 XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
599
600                 /* Change the clock frequency to 200 MHz */
601                 InstancePtr->BusSpeed = XSDPS_MMC_HS200_MAX_CLK;
602
603                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
604                 if (Status != XST_SUCCESS) {
605                         Status = XST_FAILURE;
606                         goto RETURN_PATH;
607                 }
608                 Status = XSdPs_Execute_Tuning(InstancePtr);
609                 if (Status != XST_SUCCESS) {
610                         Status = XST_FAILURE;
611                         goto RETURN_PATH;
612                 }
613 #if defined (__arm__) || defined (__aarch64__)
614                 /* Program the Tap delays */
615                 XSdPs_SetTapDelay(InstancePtr);
616 #endif
617         }
618
619 #if defined (__arm__) || defined (__aarch64__)
620
621         usleep(XSDPS_MMC_DELAY_FOR_SWITCH);
622
623 #endif
624
625 #ifdef __MICROBLAZE__
626
627         /* 2 msec delay */
628         MB_Sleep(2);
629
630 #endif
631
632         StatusReg = (s32)XSdPs_ReadReg8(InstancePtr->Config.BaseAddress,
633                                         XSDPS_HOST_CTRL1_OFFSET);
634         StatusReg |= XSDPS_HC_SPEED_MASK;
635         XSdPs_WriteReg8(InstancePtr->Config.BaseAddress,
636                         XSDPS_HOST_CTRL1_OFFSET, (u8)StatusReg);
637
638         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
639                         XSDPS_RESP0_OFFSET);
640
641
642         Status = XST_SUCCESS;
643
644         RETURN_PATH:
645                 return Status;
646
647 }
648
649 /*****************************************************************************/
650 /**
651 *
652 * API to change clock freq to given value.
653 *
654 *
655 * @param        InstancePtr is a pointer to the XSdPs instance.
656 * @param        SelFreq - Clock frequency in Hz.
657 *
658 * @return       None
659 *
660 * @note         This API will change clock frequency to the value less than
661 *               or equal to the given value using the permissible dividors.
662 *
663 ******************************************************************************/
664 s32 XSdPs_Change_ClkFreq(XSdPs *InstancePtr, u32 SelFreq)
665 {
666         u16 ClockReg;
667         u16 DivCnt;
668         u16 Divisor = 0U;
669         u16 ExtDivisor;
670         u16 ClkLoopCnt;
671         s32 Status;
672         u16 ReadReg;
673
674         Xil_AssertNonvoid(InstancePtr != NULL);
675         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
676
677         /* Disable clock */
678         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
679                         XSDPS_CLK_CTRL_OFFSET);
680         ClockReg &= ~(XSDPS_CC_SD_CLK_EN_MASK | XSDPS_CC_INT_CLK_EN_MASK);
681         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
682                         XSDPS_CLK_CTRL_OFFSET, ClockReg);
683
684         if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
685                 /* Calculate divisor */
686                 for (DivCnt = 0x1U; DivCnt <= XSDPS_CC_EXT_MAX_DIV_CNT;DivCnt++) {
687                         if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {
688                                 Divisor = DivCnt >> 1;
689                                 break;
690                         }
691                 }
692
693                 if (DivCnt > XSDPS_CC_EXT_MAX_DIV_CNT) {
694                         /* No valid divisor found for given frequency */
695                         Status = XST_FAILURE;
696                         goto RETURN_PATH;
697                 }
698         } else {
699                 /* Calculate divisor */
700                 DivCnt = 0x1U;
701                 while (DivCnt <= XSDPS_CC_MAX_DIV_CNT) {
702                         if (((InstancePtr->Config.InputClockHz) / DivCnt) <= SelFreq) {
703                                 Divisor = DivCnt / 2U;
704                                 break;
705                         }
706                         DivCnt = DivCnt << 1U;
707                 }
708
709                 if (DivCnt > XSDPS_CC_MAX_DIV_CNT) {
710                         /* No valid divisor found for given frequency */
711                         Status = XST_FAILURE;
712                         goto RETURN_PATH;
713                 }
714         }
715
716         /* Set clock divisor */
717         if (InstancePtr->HC_Version == XSDPS_HC_SPEC_V3) {
718                 ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
719                                 XSDPS_CLK_CTRL_OFFSET);
720                 ClockReg &= ~(XSDPS_CC_SDCLK_FREQ_SEL_MASK |
721                 XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK);
722
723                 ExtDivisor = Divisor >> 8;
724                 ExtDivisor <<= XSDPS_CC_EXT_DIV_SHIFT;
725                 ExtDivisor &= XSDPS_CC_SDCLK_FREQ_SEL_EXT_MASK;
726
727                 Divisor <<= XSDPS_CC_DIV_SHIFT;
728                 Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;
729                 ClockReg |= Divisor | ExtDivisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;
730                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,
731                                 ClockReg);
732         } else {
733                 ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
734                                 XSDPS_CLK_CTRL_OFFSET);
735                 ClockReg &= (~XSDPS_CC_SDCLK_FREQ_SEL_MASK);
736
737                 Divisor <<= XSDPS_CC_DIV_SHIFT;
738                 Divisor &= XSDPS_CC_SDCLK_FREQ_SEL_MASK;
739                 ClockReg |= Divisor | (u16)XSDPS_CC_INT_CLK_EN_MASK;
740                 XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_CLK_CTRL_OFFSET,
741                                 ClockReg);
742         }
743
744         /* Wait for internal clock to stabilize */
745         ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
746                                 XSDPS_CLK_CTRL_OFFSET);
747         while((ReadReg & XSDPS_CC_INT_CLK_STABLE_MASK) == 0U) {
748                 ReadReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
749                                         XSDPS_CLK_CTRL_OFFSET);;
750         }
751
752         /* Enable SD clock */
753         ClockReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
754                         XSDPS_CLK_CTRL_OFFSET);
755         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
756                         XSDPS_CLK_CTRL_OFFSET,
757                         ClockReg | XSDPS_CC_SD_CLK_EN_MASK);
758
759         Status = XST_SUCCESS;
760
761 RETURN_PATH:
762                 return Status;
763
764 }
765
766 /*****************************************************************************/
767 /**
768 *
769 * API to send pullup command to card before using DAT line 3(using 4-bit bus)
770 *
771 *
772 * @param        InstancePtr is a pointer to the XSdPs instance.
773 *
774 * @return
775 *               - XST_SUCCESS if successful.
776 *               - XST_FAILURE if fail.
777 *
778 * @note         None.
779 *
780 ******************************************************************************/
781 s32 XSdPs_Pullup(XSdPs *InstancePtr)
782 {
783         s32 Status;
784
785         Xil_AssertNonvoid(InstancePtr != NULL);
786         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
787
788         Status = XSdPs_CmdTransfer(InstancePtr, CMD55,
789                         InstancePtr->RelCardAddr, 0U);
790         if (Status != XST_SUCCESS) {
791                 Status = XST_FAILURE;
792                 goto RETURN_PATH;
793         }
794
795         Status = XSdPs_CmdTransfer(InstancePtr, ACMD42, 0U, 0U);
796         if (Status != XST_SUCCESS) {
797                 Status = XST_FAILURE;
798                 goto RETURN_PATH;
799         }
800
801         Status = XST_SUCCESS;
802
803         RETURN_PATH:
804                 return Status;
805
806 }
807
808 /*****************************************************************************/
809 /**
810 *
811 * API to get EXT_CSD register of eMMC.
812 *
813 *
814 * @param        InstancePtr is a pointer to the XSdPs instance.
815 * @param        ReadBuff - buffer to store EXT_CSD
816 *
817 * @return
818 *               - XST_SUCCESS if successful.
819 *               - XST_FAILURE if fail.
820 *
821 * @note         None.
822 *
823 ******************************************************************************/
824 s32 XSdPs_Get_Mmc_ExtCsd(XSdPs *InstancePtr, u8 *ReadBuff)
825 {
826         s32 Status;
827         u32 StatusReg;
828         u32 Arg = 0U;
829         u16 BlkCnt;
830         u16 BlkSize;
831         s32 LoopCnt;
832
833         Xil_AssertNonvoid(InstancePtr != NULL);
834         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
835
836         for (LoopCnt = 0; LoopCnt < 512; LoopCnt++) {
837                 ReadBuff[LoopCnt] = 0U;
838         }
839
840         BlkCnt = XSDPS_EXT_CSD_CMD_BLKCNT;
841         BlkSize = XSDPS_EXT_CSD_CMD_BLKSIZE;
842         BlkSize &= XSDPS_BLK_SIZE_MASK;
843         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
844                         XSDPS_BLK_SIZE_OFFSET, BlkSize);
845
846         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
847
848         Xil_DCacheInvalidateRange((INTPTR)ReadBuff, 512U);
849
850         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
851                         XSDPS_XFER_MODE_OFFSET,
852                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
853
854
855         /* Send SEND_EXT_CSD command */
856         Status = XSdPs_CmdTransfer(InstancePtr, CMD8, Arg, 1U);
857         if (Status != XST_SUCCESS) {
858                 Status = XST_FAILURE;
859                 goto RETURN_PATH;
860         }
861
862         /*
863          * Check for transfer complete
864          * Polling for response for now
865          */
866         do {
867                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
868                                         XSDPS_NORM_INTR_STS_OFFSET);
869                 if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
870                         /* Write to clear error bits */
871                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
872                                         XSDPS_ERR_INTR_STS_OFFSET,
873                                         XSDPS_ERROR_INTR_ALL_MASK);
874                         Status = XST_FAILURE;
875                         goto RETURN_PATH;
876                 }
877         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
878
879         /* Write to clear bit */
880         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
881                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
882
883         Status = (s32)XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
884                         XSDPS_RESP0_OFFSET);
885
886         Status = XST_SUCCESS;
887
888         RETURN_PATH:
889                 return Status;
890
891 }
892
893
894 /*****************************************************************************/
895 /**
896 *
897 * API to UHS-I mode initialization
898 *
899 *
900 * @param        InstancePtr is a pointer to the XSdPs instance.
901 * @param        Mode UHS-I mode
902 *
903 * @return
904 *               - XST_SUCCESS if successful.
905 *               - XST_FAILURE if fail.
906 *
907 * @note         None.
908 *
909 ******************************************************************************/
910 s32 XSdPs_Uhs_ModeInit(XSdPs *InstancePtr, u8 Mode)
911 {
912         s32 Status;
913         u16 StatusReg;
914         u16 CtrlReg;
915         u32 Arg;
916         u16 BlkCnt;
917         u16 BlkSize;
918         u8 ReadBuff[64];
919
920         Xil_AssertNonvoid(InstancePtr != NULL);
921         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
922
923         /* Drive strength */
924
925         /* Bus speed mode selection */
926         BlkCnt = XSDPS_SWITCH_CMD_BLKCNT;
927         BlkSize = XSDPS_SWITCH_CMD_BLKSIZE;
928         BlkSize &= XSDPS_BLK_SIZE_MASK;
929         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
930                         BlkSize);
931
932         XSdPs_SetupADMA2DescTbl(InstancePtr, BlkCnt, ReadBuff);
933
934         Xil_DCacheFlushRange((INTPTR)ReadBuff, 64);
935
936         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,
937                         XSDPS_TM_DAT_DIR_SEL_MASK | XSDPS_TM_DMA_EN_MASK);
938
939         switch (Mode) {
940         case 0U:
941                 Arg = XSDPS_SWITCH_CMD_SDR12_SET;
942                 InstancePtr->BusSpeed = XSDPS_SD_SDR12_MAX_CLK;
943                 break;
944         case 1U:
945                 Arg = XSDPS_SWITCH_CMD_SDR25_SET;
946                 InstancePtr->BusSpeed = XSDPS_SD_SDR25_MAX_CLK;
947                 break;
948         case 2U:
949                 Arg = XSDPS_SWITCH_CMD_SDR50_SET;
950                 InstancePtr->BusSpeed = XSDPS_SD_SDR50_MAX_CLK;
951                 break;
952         case 3U:
953                 Arg = XSDPS_SWITCH_CMD_SDR104_SET;
954                 InstancePtr->BusSpeed = XSDPS_SD_SDR104_MAX_CLK;
955                 break;
956         case 4U:
957                 Arg = XSDPS_SWITCH_CMD_DDR50_SET;
958                 InstancePtr->BusSpeed = XSDPS_SD_DDR50_MAX_CLK;
959                 break;
960         default:
961                 Status = XST_FAILURE;
962                 goto RETURN_PATH;
963                 break;
964         }
965
966         Status = XSdPs_CmdTransfer(InstancePtr, CMD6, Arg, 1U);
967         if (Status != XST_SUCCESS) {
968                 Status = XST_FAILURE;
969                 goto RETURN_PATH;
970         }
971
972         /*
973          * Check for transfer complete
974          * Polling for response for now
975          */
976         do {
977                 StatusReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
978                                 XSDPS_NORM_INTR_STS_OFFSET);
979                 if ((StatusReg & XSDPS_INTR_ERR_MASK) != 0U) {
980                         /* Write to clear error bits */
981                         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
982                                         XSDPS_ERR_INTR_STS_OFFSET, XSDPS_ERROR_INTR_ALL_MASK);
983                         Status = XST_FAILURE;
984                         goto RETURN_PATH;
985                 }
986         } while ((StatusReg & XSDPS_INTR_TC_MASK) == 0U);
987
988         /* Write to clear bit */
989         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
990                         XSDPS_NORM_INTR_STS_OFFSET, XSDPS_INTR_TC_MASK);
991
992
993         /* Current limit */
994
995         /* Set UHS mode in controller */
996         CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
997                         XSDPS_HOST_CTRL2_OFFSET);
998         CtrlReg &= (u16)(~XSDPS_HC2_UHS_MODE_MASK);
999         CtrlReg |= Mode;
1000         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1001                         XSDPS_HOST_CTRL2_OFFSET, CtrlReg);
1002
1003         /* Change the clock frequency */
1004         Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
1005         if (Status != XST_SUCCESS) {
1006                         Status = XST_FAILURE;
1007                         goto RETURN_PATH;
1008         }
1009
1010         if((Mode == XSDPS_UHS_SPEED_MODE_SDR104) ||
1011                         (Mode == XSDPS_UHS_SPEED_MODE_DDR50)) {
1012                 /* Send tuning pattern */
1013                 Status = XSdPs_Execute_Tuning(InstancePtr);
1014                 if (Status != XST_SUCCESS) {
1015                                 Status = XST_FAILURE;
1016                                 goto RETURN_PATH;
1017                 }
1018         }
1019
1020         Status = XST_SUCCESS;
1021
1022         RETURN_PATH:
1023                 return Status;
1024 }
1025
1026 static s32 XSdPs_Execute_Tuning(XSdPs *InstancePtr)
1027 {
1028         s32 Status;
1029         u32 StatusReg;
1030         u32 Arg;
1031         u16 BlkCnt;
1032         u16 BlkSize;
1033         s32 LoopCnt;
1034         u16 CtrlReg;
1035         u8 TuningCount;
1036
1037         Xil_AssertNonvoid(InstancePtr != NULL);
1038         Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
1039
1040         BlkCnt = XSDPS_TUNING_CMD_BLKCNT;
1041         BlkSize = XSDPS_TUNING_CMD_BLKSIZE;
1042         if(InstancePtr->BusWidth == XSDPS_8_BIT_WIDTH)
1043         {
1044                 BlkSize = BlkSize*2U;
1045         }
1046         BlkSize &= XSDPS_BLK_SIZE_MASK;
1047         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_BLK_SIZE_OFFSET,
1048                         BlkSize);
1049
1050         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress, XSDPS_XFER_MODE_OFFSET,
1051                         XSDPS_TM_DAT_DIR_SEL_MASK);
1052
1053         CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1054                                 XSDPS_HOST_CTRL2_OFFSET);
1055         CtrlReg |= XSDPS_HC2_EXEC_TNG_MASK;
1056         XSdPs_WriteReg16(InstancePtr->Config.BaseAddress,
1057                                 XSDPS_HOST_CTRL2_OFFSET, CtrlReg);
1058
1059         for (TuningCount = 0U; TuningCount < MAX_TUNING_COUNT; TuningCount++) {
1060
1061                 if (InstancePtr->CardType == XSDPS_CARD_SD) {
1062                         Status = XSdPs_CmdTransfer(InstancePtr, CMD19, 0U, 1U);
1063                 } else {
1064                         Status = XSdPs_CmdTransfer(InstancePtr, CMD21, 0U, 1U);
1065                 }
1066
1067                 if (Status != XST_SUCCESS) {
1068                         Status = XST_FAILURE;
1069                         goto RETURN_PATH;
1070                 }
1071
1072                 if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1073                                 XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_EXEC_TNG_MASK) == 0U) {
1074                         break;
1075                 }
1076         }
1077
1078         if ((XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1079                         XSDPS_HOST_CTRL2_OFFSET) & XSDPS_HC2_SAMP_CLK_SEL_MASK) == 0U) {
1080                 Status = XST_FAILURE;
1081                 goto RETURN_PATH;
1082         }
1083
1084         /*
1085          * As per controller erratum, program the "SDCLK Frequency
1086          * Select" of clock control register with a value, say
1087          * clock/2. Wait for the Internal clock stable and program
1088          * the desired frequency.
1089          */
1090         CtrlReg = XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
1091                                 XSDPS_HOST_CTRL2_OFFSET);
1092         if ((CtrlReg & XSDPS_HC2_SAMP_CLK_SEL_MASK) != 0U) {
1093                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed/2);
1094                 if (Status != XST_SUCCESS) {
1095                         goto RETURN_PATH ;
1096                 }
1097                 Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
1098                 if (Status != XST_SUCCESS) {
1099                         goto RETURN_PATH ;
1100                 }
1101
1102         }
1103
1104         Status = XST_SUCCESS;
1105
1106         RETURN_PATH: return Status;
1107
1108 }
1109
1110 #if defined (__arm__) || defined (__aarch64__)
1111 /*****************************************************************************/
1112 /**
1113 *
1114 * API to set Tap Delay w.r.t speed modes
1115 *
1116 *
1117 * @param        InstancePtr is a pointer to the XSdPs instance.
1118 *
1119 * @return       None
1120 *
1121 * @note         None.
1122 *
1123 ******************************************************************************/
1124 void XSdPs_SetTapDelay(XSdPs *InstancePtr)
1125 {
1126         u32 DllCtrl, TapDelay;
1127         if (InstancePtr->Config.DeviceId == XPAR_XSDPS_0_DEVICE_ID) {
1128                 DllCtrl = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL);
1129                 DllCtrl |= SD0_DLL_RST;
1130                 XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
1131                 if(InstancePtr->BusSpeed == XSDPS_MMC_HS200_MAX_CLK) {
1132                         /* Program the ITAPDLY */
1133                         TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY);
1134                         TapDelay |= SD0_ITAPCHGWIN;
1135                         XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
1136                         TapDelay |= SD0_ITAPDLYENA;
1137                         XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
1138                         TapDelay &= ~SD0_ITAPCHGWIN;
1139                         XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_ITAPDLY, TapDelay);
1140                         /* Program the OTAPDLY */
1141                         TapDelay = XSdPs_ReadReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL);
1142                         TapDelay |= SD0_OTAPDLYENA;
1143                         XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL, TapDelay);
1144                         TapDelay |= SD0_OTAPDLYSEL_HS200;
1145                         XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_OTAPDLYSEL, TapDelay);
1146                 }
1147                 DllCtrl &= ~SD0_DLL_RST;
1148                 XSdPs_WriteReg(XPS_SYS_CTRL_BASEADDR, SD_DLL_CTRL, DllCtrl);
1149         }
1150 }
1151 #endif
1152 /** @} */