1 /******************************************************************************
2 * Copyright (C) 2013 - 2020 Xilinx, Inc.  All rights reserved.
3 * SPDX-License-Identifier: MIT
4 ******************************************************************************/
5 
6 /*****************************************************************************/
7 /**
8 *
9 * @file xsdps.c
10 * @addtogroup sdps_v3_9
11 * @{
12 *
13 * Contains the interface functions of the XSdPs driver.
14 * See xsdps.h for a detailed description of the device and driver.
15 *
16 * <pre>
17 * MODIFICATION HISTORY:
18 *
19 * Ver   Who    Date     Changes
20 * ----- ---    -------- -----------------------------------------------
21 * 1.00a hk/sg  10/17/13 Initial release
22 * 2.0   hk     12/13/13 Added check for arm to use sleep.h and its API's
23 * 2.1   hk     04/18/14 Add sleep for microblaze designs. CR# 781117.
24 * 2.2   hk     07/28/14 Make changes to enable use of data cache.
25 * 2.3   sk     09/23/14 Send command for relative card address
26 *                       when re-initialization is done.CR# 819614.
27 *                        Use XSdPs_Change_ClkFreq API whenever changing
28 *                        clock.CR# 816586.
29 * 2.4    sk       12/04/14 Added support for micro SD without
30 *                         WP/CD. CR# 810655.
31 *                        Checked for DAT Inhibit mask instead of CMD
32 *                         Inhibit mask in Cmd Transfer API.
33 *                        Added Support for SD Card v1.0
34 * 2.5     sg       07/09/15 Added SD 3.0 features
35 *       kvn    07/15/15 Modified the code according to MISRAC-2012.
36 * 2.6   sk     10/12/15 Added support for SD card v1.0 CR# 840601.
37 * 2.7   sk     11/24/15 Considered the slot type befoe checking CD/WP pins.
38 *       sk     12/10/15 Added support for MMC cards.
39 *       sk     02/16/16 Corrected the Tuning logic.
40 *       sk     03/01/16 Removed Bus Width check for eMMC. CR# 938311.
41 * 2.8   sk     05/03/16 Standard Speed for SD to 19MHz in ZynqMPSoC. CR#951024
42 * 3.0   sk     06/09/16 Added support for mkfs to calculate sector count.
43 *       sk     07/16/16 Added support for UHS modes.
44 *       sk     07/07/16 Used usleep API for both arm and microblaze.
45 *       sk     07/16/16 Added Tap delays accordingly to different SD/eMMC
46 *                       operating modes.
47 * 3.1   mi     09/07/16 Removed compilation warnings with extra compiler flags.
48 *       sk     10/13/16 Reduced the delay during power cycle to 1ms as per spec
49 *       sk     10/19/16 Used emmc_hwreset pin to reset eMMC.
50 *       sk     11/07/16 Enable Rst_n bit in ext_csd reg if not enabled.
51 * 3.2   sk     11/30/16 Modified the voltage switching sequence as per spec.
52 *       sk     02/01/17 Added HSD and DDR mode support for eMMC.
53 *       vns    02/09/17 Added ARMA53_32 support for ZynqMP CR#968397
54 *       sk     03/20/17 Add support for EL1 non-secure mode.
55 * 3.3   mn     05/17/17 Add support for 64bit DMA addressing
56 *       mn     07/17/17 Add support for running SD at 200MHz
57 *       mn     07/26/17 Fixed compilation warnings
58 *       mn     08/07/17 Modify driver to support 64-bit DMA in arm64 only
59 *       mn     08/17/17 Added CCI support for A53 and disabled data cache
60 *                       operations when it is enabled.
61 *       mn     08/22/17 Updated for Word Access System support
62 *       mn     09/06/17 Resolved compilation errors with IAR toolchain
63 *       mn     09/26/17 Added UHS_MODE_ENABLE macro to enable UHS mode
64 * 3.4   mn     10/17/17 Use different commands for single and multi block
65 *                       transfers
66 *       mn     03/02/18 Move UHS macro check to SD card initialization routine
67 * 3.5   mn     04/18/18 Resolve compilation warnings for sdps driver
68 * 3.6   mn     07/06/18 Fix Cppcheck and Doxygen warnings for sdps driver
69 *       mn     08/01/18 Add support for using 64Bit DMA with 32-Bit Processor
70 *       mn     08/01/18 Add cache invalidation call before returning from
71 *                       ReadPolled API
72 *       mn     08/14/18 Resolve compilation warnings for ARMCC toolchain
73 *       mn     10/01/18 Change Expected Response for CMD3 to R1 for MMC
74 *       mus    11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
75 * 3.7   mn     02/01/19 Add support for idling of SDIO
76 *       aru    03/12/19 Modified the code according to MISRAC-2012.
77 * 3.8   mn     04/12/19 Modified TapDelay code for supporting ZynqMP and Versal
78 *       mn     09/17/19 Modified ADMA handling API for 32bit and 64bit addresses
79 * 3.9   sd     02/07/20 Added clock support
80 *       mn     03/03/20 Restructured the code for more readability and modularity
81 *       mn     03/30/20 Return XST_DEVICE_IS_STARTED when host is already started
82 *       mn     03/30/20 Move Clock enabling before checking for Host already started
83 *
84 * </pre>
85 *
86 ******************************************************************************/
87 
88 /***************************** Include Files *********************************/
89 #include "xsdps_core.h"
90 
91 /************************** Constant Definitions *****************************/
92 
93 /**************************** Type Definitions *******************************/
94 
95 /***************** Macros (Inline Functions) Definitions *********************/
96 
97 /************************** Function Prototypes ******************************/
98 /*****************************************************************************/
99 /**
100 *
101 * @brief
102 * Initializes a specific XSdPs instance such that the driver is ready to use.
103 *
104 *
105 * @param    InstancePtr is a pointer to the XSdPs instance.
106 * @param    ConfigPtr is a reference to a structure containing information
107 *        about a specific SD device. This function initializes an
108 *        InstancePtr object for a specific device specified by the
109 *        contents of Config.
110 * @param    EffectiveAddr is the device base address in the virtual memory
111 *        address space. The caller is responsible for keeping the address
112 *        mapping from EffectiveAddr to the device physical base address
113 *        unchanged once this function is invoked. Unexpected errors may
114 *        occur if the address mapping changes after this function is
115 *        called. If address translation is not used, use
116 *        ConfigPtr->Config.BaseAddress for this device.
117 *
118 * @return
119 *        - XST_SUCCESS if successful.
120 *        - XST_DEVICE_IS_STARTED if the device is already started.
121 *        It must be stopped to re-initialize.
122 *
123 * @note        This function initializes the host controller.
124 *        Initial clock of 400KHz is set.
125 *        Voltage of 3.3V is selected as that is supported by host.
126 *        Interrupts status is enabled and signal disabled by default.
127 *        Default data direction is card to host and
128 *        32 bit ADMA2 is selected. Default Block size is 512 bytes.
129 *
130 ******************************************************************************/
XSdPs_CfgInitialize(XSdPs * InstancePtr,XSdPs_Config * ConfigPtr,u32 EffectiveAddr)131 s32 XSdPs_CfgInitialize(XSdPs *InstancePtr, XSdPs_Config *ConfigPtr,
132                 u32 EffectiveAddr)
133 {
134     s32 Status;
135 
136     Xil_AssertNonvoid(InstancePtr != NULL);
137     Xil_AssertNonvoid(ConfigPtr != NULL);
138 
139 #if defined  (XCLOCKING)
140     InstancePtr->Config.RefClk = ConfigPtr->RefClk;
141     Xil_ClockEnable(InstancePtr->Config.RefClk);
142 #endif
143     /* If this API is getting called twice, return value accordingly */
144     if (InstancePtr->IsReady == XIL_COMPONENT_IS_READY) {
145         Status = (s32)XST_DEVICE_IS_STARTED;
146         goto RETURN_PATH ;
147     }
148 
149     /* Set some default values. */
150     InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
151     InstancePtr->Config.BaseAddress = EffectiveAddr;
152     InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz;
153     InstancePtr->Config.CardDetect =  ConfigPtr->CardDetect;
154     InstancePtr->Config.WriteProtect =  ConfigPtr->WriteProtect;
155     InstancePtr->Config.BusWidth = ConfigPtr->BusWidth;
156     InstancePtr->Config.BankNumber = ConfigPtr->BankNumber;
157     InstancePtr->Config.HasEMIO = ConfigPtr->HasEMIO;
158     InstancePtr->Config.IsCacheCoherent = ConfigPtr->IsCacheCoherent;
159     InstancePtr->SectorCount = 0U;
160     InstancePtr->Mode = XSDPS_DEFAULT_SPEED_MODE;
161     InstancePtr->OTapDelay = 0U;
162     InstancePtr->ITapDelay = 0U;
163     InstancePtr->Dma64BitAddr = 0U;
164     InstancePtr->SlcrBaseAddr = XPS_SYS_CTRL_BASEADDR;
165 
166     /* Host Controller version is read. */
167     InstancePtr->HC_Version =
168             (u8)(XSdPs_ReadReg16(InstancePtr->Config.BaseAddress,
169             XSDPS_HOST_CTRL_VER_OFFSET) & XSDPS_HC_SPEC_VER_MASK);
170 
171     /*
172      * Read capabilities register and update it in Instance pointer.
173      * It is sufficient to read this once on power on.
174      */
175     InstancePtr->Host_Caps = XSdPs_ReadReg(InstancePtr->Config.BaseAddress,
176                         XSDPS_CAPS_OFFSET);
177 
178     /* Reset the SD bus lines */
179     Status = XSdPs_ResetConfig(InstancePtr);
180     if (Status != XST_SUCCESS) {
181         Status = XST_FAILURE;
182         goto RETURN_PATH ;
183     }
184 
185     /* Configure the SD Host Controller */
186     XSdPs_HostConfig(InstancePtr);
187 
188     InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
189 
190 RETURN_PATH:
191 #if defined  (XCLOCKING)
192     Xil_ClockDisable(InstancePtr->Config.RefClk);
193 #endif
194     return Status;
195 
196 }
197 
198 /*****************************************************************************/
199 /**
200 *
201 * @brief
202 * Initialize Card with Identification mode sequence
203 *
204 *
205 * @param    InstancePtr is a pointer to the instance to be worked on.
206 *
207 * @return
208 *         - XST_SUCCESS if initialization was successful
209 *         - XST_FAILURE if failure - could be because
210 *             a) SD is already initialized
211 *             b) There is no card inserted
212 *             c) One of the steps (commands) in the
213 *               initialization cycle failed
214 *
215 *
216 ******************************************************************************/
XSdPs_CardInitialize(XSdPs * InstancePtr)217 s32 XSdPs_CardInitialize(XSdPs *InstancePtr)
218 {
219     s32 Status;
220 
221     Xil_AssertNonvoid(InstancePtr != NULL);
222     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
223 
224     /* Default settings */
225     InstancePtr->BusWidth = XSDPS_1_BIT_WIDTH;
226     InstancePtr->CardType = XSDPS_CARD_SD;
227     InstancePtr->Switch1v8 = 0U;
228     InstancePtr->BusSpeed = XSDPS_CLK_400_KHZ;
229 
230 #if defined  (XCLOCKING)
231     Xil_ClockEnable(InstancePtr->Config.RefClk);
232 #endif
233 
234     /* Change the clock frequency to 400 KHz */
235     Status = XSdPs_Change_ClkFreq(InstancePtr, InstancePtr->BusSpeed);
236     if (Status != XST_SUCCESS) {
237         Status = XST_FAILURE;
238         goto RETURN_PATH ;
239     }
240 
241     /* Identify the Card whether it is SD, MMC or eMMC */
242     Status = XSdPs_IdentifyCard(InstancePtr);
243     if (Status != XST_SUCCESS) {
244         Status = XST_FAILURE;
245         goto RETURN_PATH;
246     }
247 
248     /* Initialize the identified card */
249     if (InstancePtr->CardType == XSDPS_CARD_SD) {
250         Status = XSdPs_SdCardInitialize(InstancePtr);
251         if (Status != XST_SUCCESS) {
252             Status = XST_FAILURE;
253             goto RETURN_PATH;
254         }
255     } else {
256         Status = XSdPs_MmcCardInitialize(InstancePtr);
257         if (Status != XST_SUCCESS) {
258             Status = XST_FAILURE;
259             goto RETURN_PATH;
260         }
261     }
262 
263 RETURN_PATH:
264 #if defined  (XCLOCKING)
265     Xil_ClockDisable(InstancePtr->Config.RefClk);
266 #endif
267     return Status;
268 }
269 
270 /*****************************************************************************/
271 /**
272 * @brief
273 * This function performs SD read in polled mode.
274 *
275 * @param    InstancePtr is a pointer to the instance to be worked on.
276 * @param    Arg is the address passed by the user that is to be sent as
277 *         argument along with the command.
278 * @param    BlkCnt - Block count passed by the user.
279 * @param    Buff - Pointer to the data buffer for a DMA transfer.
280 *
281 * @return
282 *         - XST_SUCCESS if initialization was successful
283 *         - XST_FAILURE if failure - could be because another transfer
284 *         is in progress or command or data inhibit is set
285 *
286 ******************************************************************************/
XSdPs_ReadPolled(XSdPs * InstancePtr,u32 Arg,u32 BlkCnt,u8 * Buff)287 s32 XSdPs_ReadPolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, u8 *Buff)
288 {
289     s32 Status;
290 
291     Xil_AssertNonvoid(InstancePtr != NULL);
292     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
293 
294 #if defined  (XCLOCKING)
295     Xil_ClockEnable(InstancePtr->Config.RefClk);
296 #endif
297 
298     /* Setup the Read Transfer */
299     Status = XSdPs_SetupTransfer(InstancePtr);
300     if (Status != XST_SUCCESS) {
301         Status = XST_FAILURE;
302         goto RETURN_PATH;
303     }
304 
305     /* Read from the card */
306     Status = XSdPs_Read(InstancePtr, Arg, BlkCnt, Buff);
307     if (Status != XST_SUCCESS) {
308         Status = XST_FAILURE;
309         goto RETURN_PATH;
310     }
311 
312 RETURN_PATH:
313 #if defined  (XCLOCKING)
314     Xil_ClockDisable(InstancePtr->Config.RefClk);
315 #endif
316     return Status;
317 }
318 
319 /*****************************************************************************/
320 /**
321 * @brief
322 * This function performs SD write in polled mode.
323 *
324 * @param    InstancePtr is a pointer to the instance to be worked on.
325 * @param    Arg is the address passed by the user that is to be sent as
326 *         argument along with the command.
327 * @param    BlkCnt - Block count passed by the user.
328 * @param    Buff - Pointer to the data buffer for a DMA transfer.
329 *
330 * @return
331 *         - XST_SUCCESS if initialization was successful
332 *         - XST_FAILURE if failure - could be because another transfer
333 *         is in progress or command or data inhibit is set
334 *
335 ******************************************************************************/
XSdPs_WritePolled(XSdPs * InstancePtr,u32 Arg,u32 BlkCnt,const u8 * Buff)336 s32 XSdPs_WritePolled(XSdPs *InstancePtr, u32 Arg, u32 BlkCnt, const u8 *Buff)
337 {
338     s32 Status;
339 
340     Xil_AssertNonvoid(InstancePtr != NULL);
341     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
342 
343 #if defined  (XCLOCKING)
344     Xil_ClockEnable(InstancePtr->Config.RefClk);
345 #endif
346 
347     /* Setup the Write Transfer */
348     Status = XSdPs_SetupTransfer(InstancePtr);
349     if (Status != XST_SUCCESS) {
350         Status = XST_FAILURE;
351         goto RETURN_PATH;
352     }
353 
354     /* Write to the card */
355     Status = XSdPs_Write(InstancePtr, Arg, BlkCnt, Buff);
356     if (Status != XST_SUCCESS) {
357         Status = XST_FAILURE;
358         goto RETURN_PATH;
359     }
360 
361 RETURN_PATH:
362 #if defined  (XCLOCKING)
363     Xil_ClockDisable(InstancePtr->Config.RefClk);
364 #endif
365     return Status;
366 }
367 
368 /*****************************************************************************/
369 /**
370 *
371 * @brief
372 * API to idle the SDIO Interface
373 *
374 *
375 * @param    InstancePtr is a pointer to the XSdPs instance.
376 *
377 * @return    None
378 *
379 * @note        None.
380 *
381 ******************************************************************************/
XSdPs_Idle(XSdPs * InstancePtr)382 s32 XSdPs_Idle(XSdPs *InstancePtr)
383 {
384     s32 Status;
385 
386     Xil_AssertNonvoid(InstancePtr != NULL);
387     Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
388 
389 #if defined  (XCLOCKING)
390     Xil_ClockEnable(InstancePtr->Config.RefClk);
391 #endif
392 
393     /* Check if the bus is idle */
394     Status = XSdPs_CheckBusIdle(InstancePtr, XSDPS_PSR_INHIBIT_CMD_MASK
395                                         | XSDPS_PSR_INHIBIT_DAT_MASK
396                                         | XSDPS_PSR_DAT_ACTIVE_MASK);
397     if (Status != XST_SUCCESS) {
398         Status = XST_FAILURE;
399         goto RETURN_PATH ;
400     }
401 
402     /* Disable the Bus Power */
403     XSdPs_DisableBusPower(InstancePtr);
404 
405     /* Reset Command and Data Lines */
406     Status = XSdPs_Reset(InstancePtr, XSDPS_SWRST_ALL_MASK);
407     if (Status != XST_SUCCESS) {
408         Status = XST_FAILURE;
409         goto RETURN_PATH ;
410     }
411 
412     Status = XST_SUCCESS;
413 
414 RETURN_PATH:
415 #if defined  (XCLOCKING)
416     Xil_ClockDisable(InstancePtr->Config.RefClk);
417 #endif
418     return Status;
419 }
420 /** @} */
421