1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_specification.h"
10 #include "fsl_card.h"
11
12 /*******************************************************************************
13 * Variables
14 ******************************************************************************/
15 SDK_ALIGN(uint32_t g_sdmmc[SDK_SIZEALIGN(SDMMC_GLOBAL_BUFFER_SIZE, SDMMC_DATA_BUFFER_ALIGN_CAHCE)],
16 MAX(SDMMC_DATA_BUFFER_ALIGN_CAHCE, HOST_DMA_BUFFER_ADDR_ALIGN));
17 /*******************************************************************************
18 * Code
19 ******************************************************************************/
20
SDMMC_Delay(uint32_t num)21 void SDMMC_Delay(uint32_t num)
22 {
23 volatile uint32_t i, j;
24
25 for (i = 0U; i < num; i++)
26 {
27 for (j = 0U; j < 10000U; j++)
28 {
29 __asm("nop");
30 }
31 }
32 }
33
SDMMC_SelectCard(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer,uint32_t relativeAddress,bool isSelected)34 status_t SDMMC_SelectCard(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer, uint32_t relativeAddress, bool isSelected)
35 {
36 assert(transfer);
37
38 HOST_TRANSFER content = {0};
39 HOST_COMMAND command = {0};
40
41 command.index = kSDMMC_SelectCard;
42 if (isSelected)
43 {
44 command.argument = relativeAddress << 16U;
45 command.responseType = kCARD_ResponseTypeR1;
46 }
47 else
48 {
49 command.argument = 0U;
50 command.responseType = kCARD_ResponseTypeNone;
51 }
52
53 content.command = &command;
54 content.data = NULL;
55 if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag))
56 {
57 return kStatus_SDMMC_TransferFailed;
58 }
59
60 /* Wait until card to transfer state */
61 return kStatus_Success;
62 }
63
SDMMC_SendApplicationCommand(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer,uint32_t relativeAddress)64 status_t SDMMC_SendApplicationCommand(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer, uint32_t relativeAddress)
65 {
66 assert(transfer);
67
68 HOST_TRANSFER content = {0};
69 HOST_COMMAND command = {0};
70
71 command.index = kSDMMC_ApplicationCommand;
72 command.argument = (relativeAddress << 16U);
73 command.responseType = kCARD_ResponseTypeR1;
74
75 content.command = &command;
76 content.data = 0U;
77 if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag))
78 {
79 return kStatus_SDMMC_TransferFailed;
80 }
81
82 if (!(command.response[0U] & kSDMMC_R1ApplicationCommandFlag))
83 {
84 return kStatus_SDMMC_CardNotSupport;
85 }
86
87 return kStatus_Success;
88 }
89
SDMMC_SetBlockCount(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer,uint32_t blockCount)90 status_t SDMMC_SetBlockCount(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer, uint32_t blockCount)
91 {
92 assert(transfer);
93
94 HOST_TRANSFER content = {0};
95 HOST_COMMAND command = {0};
96
97 command.index = kSDMMC_SetBlockCount;
98 command.argument = blockCount;
99 command.responseType = kCARD_ResponseTypeR1;
100
101 content.command = &command;
102 content.data = 0U;
103 if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag))
104 {
105 return kStatus_SDMMC_TransferFailed;
106 }
107
108 return kStatus_Success;
109 }
110
SDMMC_GoIdle(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer)111 status_t SDMMC_GoIdle(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer)
112 {
113 assert(transfer);
114
115 HOST_TRANSFER content = {0};
116 HOST_COMMAND command = {0};
117
118 command.index = kSDMMC_GoIdleState;
119
120 content.command = &command;
121 content.data = 0U;
122 if (kStatus_Success != transfer(base, &content))
123 {
124 return kStatus_SDMMC_TransferFailed;
125 }
126
127 return kStatus_Success;
128 }
129
SDMMC_SetBlockSize(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer,uint32_t blockSize)130 status_t SDMMC_SetBlockSize(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer, uint32_t blockSize)
131 {
132 assert(transfer);
133
134 HOST_TRANSFER content = {0};
135 HOST_COMMAND command = {0};
136
137 command.index = kSDMMC_SetBlockLength;
138 command.argument = blockSize;
139 command.responseType = kCARD_ResponseTypeR1;
140
141 content.command = &command;
142 content.data = 0U;
143 if ((kStatus_Success != transfer(base, &content)) || (command.response[0U] & kSDMMC_R1ErrorAllFlag))
144 {
145 return kStatus_SDMMC_TransferFailed;
146 }
147
148 return kStatus_Success;
149 }
150
SDMMC_SetCardInactive(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer)151 status_t SDMMC_SetCardInactive(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer)
152 {
153 assert(transfer);
154
155 HOST_TRANSFER content = {0};
156 HOST_COMMAND command = {0};
157
158 command.index = kSDMMC_GoInactiveState;
159 command.argument = 0U;
160 command.responseType = kCARD_ResponseTypeNone;
161
162 content.command = &command;
163 content.data = 0U;
164 if ((kStatus_Success != transfer(base, &content)))
165 {
166 return kStatus_SDMMC_TransferFailed;
167 }
168
169 return kStatus_Success;
170 }
171
SDMMC_SwitchVoltage(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer)172 status_t SDMMC_SwitchVoltage(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer)
173 {
174 assert(transfer);
175
176 HOST_TRANSFER content = {0};
177 HOST_COMMAND command = {0};
178
179 command.index = kSD_VoltageSwitch;
180 command.argument = 0U;
181 command.responseType = kCARD_ResponseTypeR1;
182
183 content.command = &command;
184 content.data = NULL;
185 if (kStatus_Success != transfer(base, &content))
186 {
187 return kStatus_SDMMC_TransferFailed;
188 }
189 /* disable card clock */
190 HOST_ENABLE_CARD_CLOCK(base, false);
191
192 /* check data line and cmd line status */
193 if ((GET_HOST_STATUS(base) &
194 (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) != 0U)
195 {
196 return kStatus_SDMMC_SwitchVoltageFail;
197 }
198
199 /* host switch to 1.8V */
200 HOST_SWITCH_VOLTAGE180V(base, true);
201
202 SDMMC_Delay(100U);
203
204 /*enable sd clock*/
205 HOST_ENABLE_CARD_CLOCK(base, true);
206 /*enable force clock on*/
207 HOST_FORCE_SDCLOCK_ON(base, true);
208 /* dealy 1ms,not exactly correct when use while */
209 SDMMC_Delay(10U);
210 /*disable force clock on*/
211 HOST_FORCE_SDCLOCK_ON(base, false);
212
213 /* check data line and cmd line status */
214 if ((GET_HOST_STATUS(base) &
215 (CARD_DATA1_STATUS_MASK | CARD_DATA2_STATUS_MASK | CARD_DATA3_STATUS_MASK | CARD_DATA0_NOT_BUSY)) == 0U)
216 {
217 return kStatus_SDMMC_SwitchVoltageFail;
218 }
219
220 return kStatus_Success;
221 }
222
SDMMC_ExecuteTuning(HOST_TYPE * base,HOST_TRANSFER_FUNCTION transfer,uint32_t tuningCmd,uint32_t blockSize)223 status_t SDMMC_ExecuteTuning(HOST_TYPE *base, HOST_TRANSFER_FUNCTION transfer, uint32_t tuningCmd, uint32_t blockSize)
224 {
225 HOST_TRANSFER content = {0U};
226 HOST_COMMAND command = {0U};
227 HOST_DATA data = {0U};
228 uint32_t buffer[32U] = {0U};
229 bool tuningError = true;
230
231 command.index = tuningCmd;
232 command.argument = 0U;
233 command.responseType = kCARD_ResponseTypeR1;
234
235 data.blockSize = blockSize;
236 data.blockCount = 1U;
237 data.rxData = buffer;
238 /* add this macro for adpter to different driver */
239 HOST_ENABLE_TUNING_FLAG(data);
240
241 content.command = &command;
242 content.data = &data;
243
244 /* enable the standard tuning */
245 HOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true);
246
247 while (true)
248 {
249 /* send tuning block */
250 if ((kStatus_Success != transfer(base, &content)))
251 {
252 return kStatus_SDMMC_TransferFailed;
253 }
254 SDMMC_Delay(1U);
255
256 /*wait excute tuning bit clear*/
257 if ((HOST_EXECUTE_STANDARD_TUNING_STATUS(base) != 0U))
258 {
259 continue;
260 }
261
262 /* if tuning error , re-tuning again */
263 if ((HOST_CHECK_TUNING_ERROR(base) != 0U) && tuningError)
264 {
265 tuningError = false;
266 /* enable the standard tuning */
267 HOST_EXECUTE_STANDARD_TUNING_ENABLE(base, true);
268 HOST_ADJUST_TUNING_DELAY(base, HOST_STANDARD_TUNING_START);
269 }
270 else
271 {
272 break;
273 }
274 }
275
276 /* delay to wait the host controller stable */
277 SDMMC_Delay(100U);
278
279 /* check tuning result*/
280 if (HOST_EXECUTE_STANDARD_TUNING_RESULT(base) == 0U)
281 {
282 return kStatus_SDMMC_TuningFail;
283 }
284
285 HOST_AUTO_STANDARD_RETUNING_TIMER(base);
286
287 return kStatus_Success;
288 }
289