]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdDevice.c
MdeModulePkg/SdMmcPciHcDxe: Hook SwitchClockFreq after SD clock start
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / SdDevice.c
CommitLineData
48555339
FT
1/** @file\r
2 This file provides some helper functions which are specific for SD card device.\r
3\r
b5547b9c 4 Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.\r
ac30e4c1 5 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
9d510e61 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
48555339
FT
7\r
8**/\r
9\r
10#include "SdMmcPciHcDxe.h"\r
11\r
12/**\r
13 Send command GO_IDLE_STATE to the device to make it go to Idle State.\r
14\r
15 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
16\r
17 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
18 @param[in] Slot The slot number of the SD card to send the command to.\r
19\r
20 @retval EFI_SUCCESS The SD device is reset correctly.\r
21 @retval Others The device reset fails.\r
22\r
23**/\r
24EFI_STATUS\r
25SdCardReset (\r
26 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
27 IN UINT8 Slot\r
28 )\r
29{\r
30 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
31 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
32 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
33 EFI_STATUS Status;\r
34\r
35 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
36 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
37 ZeroMem (&Packet, sizeof (Packet));\r
38\r
39 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
40 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
41 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
42\r
43 SdMmcCmdBlk.CommandIndex = SD_GO_IDLE_STATE;\r
44 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;\r
45\r
46 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
47\r
48 return Status;\r
49}\r
50\r
51/**\r
52 Send command SEND_IF_COND to the device to inquiry the SD Memory Card interface\r
53 condition.\r
54\r
55 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
56\r
57 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
58 @param[in] Slot The slot number of the SD card to send the command to.\r
59 @param[in] SupplyVoltage The supplied voltage by the host.\r
60 @param[in] CheckPattern The check pattern to be sent to the device.\r
61\r
62 @retval EFI_SUCCESS The operation is done correctly.\r
63 @retval Others The operation fails.\r
64\r
65**/\r
66EFI_STATUS\r
67SdCardVoltageCheck (\r
68 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
69 IN UINT8 Slot,\r
70 IN UINT8 SupplyVoltage,\r
71 IN UINT8 CheckPattern\r
72 )\r
73{\r
74 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
75 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
76 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
77 EFI_STATUS Status;\r
78\r
79 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
80 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
81 ZeroMem (&Packet, sizeof (Packet));\r
82\r
83 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
84 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
85 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
86\r
87 SdMmcCmdBlk.CommandIndex = SD_SEND_IF_COND;\r
88 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
89 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR7;\r
90 SdMmcCmdBlk.CommandArgument = (SupplyVoltage << 8) | CheckPattern;\r
91\r
92 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
93\r
94 if (!EFI_ERROR (Status)) {\r
95 if (SdMmcStatusBlk.Resp0 != SdMmcCmdBlk.CommandArgument) {\r
96 return EFI_DEVICE_ERROR;\r
97 }\r
98 }\r
99\r
100 return Status;\r
101}\r
102\r
103/**\r
104 Send command SDIO_SEND_OP_COND to the device to see whether it is SDIO device.\r
105\r
106 Refer to SDIO Simplified Spec 3 Section 3.2 for details.\r
107\r
108 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
109 @param[in] Slot The slot number of the SD card to send the command to.\r
110 @param[in] VoltageWindow The supply voltage window.\r
111 @param[in] S18R The boolean to show if it should switch to 1.8v.\r
112\r
113 @retval EFI_SUCCESS The operation is done correctly.\r
114 @retval Others The operation fails.\r
115\r
116**/\r
117EFI_STATUS\r
118SdioSendOpCond (\r
119 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
120 IN UINT8 Slot,\r
121 IN UINT32 VoltageWindow,\r
122 IN BOOLEAN S18R\r
123 )\r
124{\r
125 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
126 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
127 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
128 EFI_STATUS Status;\r
129 UINT32 Switch;\r
130\r
131 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
132 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
133 ZeroMem (&Packet, sizeof (Packet));\r
134\r
135 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
136 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
137 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
138\r
139 SdMmcCmdBlk.CommandIndex = SDIO_SEND_OP_COND;\r
140 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
141 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR4;\r
142\r
143 Switch = S18R ? BIT24 : 0;\r
144\r
145 SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch;\r
146\r
147 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
148\r
149 return Status;\r
150}\r
151\r
152/**\r
153 Send command SD_SEND_OP_COND to the device to see whether it is SDIO device.\r
154\r
155 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
156\r
157 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
158 @param[in] Slot The slot number of the SD card to send the command to.\r
159 @param[in] Rca The relative device address of addressed device.\r
160 @param[in] VoltageWindow The supply voltage window.\r
161 @param[in] S18R The boolean to show if it should switch to 1.8v.\r
162 @param[in] Xpc The boolean to show if it should provide 0.36w power control.\r
163 @param[in] Hcs The boolean to show if it support host capacity info.\r
164 @param[out] Ocr The buffer to store returned OCR register value.\r
165\r
166 @retval EFI_SUCCESS The operation is done correctly.\r
167 @retval Others The operation fails.\r
168\r
169**/\r
170EFI_STATUS\r
171SdCardSendOpCond (\r
172 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
173 IN UINT8 Slot,\r
174 IN UINT16 Rca,\r
175 IN UINT32 VoltageWindow,\r
176 IN BOOLEAN S18R,\r
177 IN BOOLEAN Xpc,\r
178 IN BOOLEAN Hcs,\r
179 OUT UINT32 *Ocr\r
180 )\r
181{\r
182 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
183 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
184 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
185 EFI_STATUS Status;\r
186 UINT32 Switch;\r
187 UINT32 MaxPower;\r
188 UINT32 HostCapacity;\r
189\r
190 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
191 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
192 ZeroMem (&Packet, sizeof (Packet));\r
193\r
194 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
195 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
196 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
197\r
198 SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
199 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
200 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
201 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
202\r
203 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
204 if (EFI_ERROR (Status)) {\r
205 return Status;\r
206 }\r
207\r
208 SdMmcCmdBlk.CommandIndex = SD_SEND_OP_COND;\r
209 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
210 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
211\r
212 Switch = S18R ? BIT24 : 0;\r
213 MaxPower = Xpc ? BIT28 : 0;\r
214 HostCapacity = Hcs ? BIT30 : 0;\r
215\r
216 SdMmcCmdBlk.CommandArgument = (VoltageWindow & 0xFFFFFF) | Switch | MaxPower | HostCapacity;\r
217\r
218 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
219 if (!EFI_ERROR (Status)) {\r
220 //\r
221 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
222 //\r
223 *Ocr = SdMmcStatusBlk.Resp0;\r
224 }\r
225\r
226 return Status;\r
227}\r
228\r
229/**\r
230 Broadcast command ALL_SEND_CID to the bus to ask all the SD devices to send the\r
231 data of their CID registers.\r
232\r
233 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
234\r
235 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
236 @param[in] Slot The slot number of the SD card to send the command to.\r
237\r
238 @retval EFI_SUCCESS The operation is done correctly.\r
239 @retval Others The operation fails.\r
240\r
241**/\r
242EFI_STATUS\r
243SdCardAllSendCid (\r
244 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
245 IN UINT8 Slot\r
246 )\r
247{\r
248 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
249 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
250 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
251 EFI_STATUS Status;\r
252\r
253 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
254 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
255 ZeroMem (&Packet, sizeof (Packet));\r
256\r
257 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
258 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
259 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
260\r
261 SdMmcCmdBlk.CommandIndex = SD_ALL_SEND_CID;\r
262 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
263 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
264\r
265 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
266\r
267 return Status;\r
268}\r
269\r
270/**\r
271 Send command SET_RELATIVE_ADDR to the SD device to assign a Relative device\r
272 Address (RCA).\r
273\r
274 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
275\r
276 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
277 @param[in] Slot The slot number of the SD card to send the command to.\r
278 @param[out] Rca The relative device address to assign.\r
279\r
280 @retval EFI_SUCCESS The operation is done correctly.\r
281 @retval Others The operation fails.\r
282\r
283**/\r
284EFI_STATUS\r
285SdCardSetRca (\r
286 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
287 IN UINT8 Slot,\r
288 OUT UINT16 *Rca\r
289 )\r
290{\r
291 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
292 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
293 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
294 EFI_STATUS Status;\r
295\r
296 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
297 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
298 ZeroMem (&Packet, sizeof (Packet));\r
299\r
300 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
301 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
302 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
303\r
304 SdMmcCmdBlk.CommandIndex = SD_SET_RELATIVE_ADDR;\r
305 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
306 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR6;\r
307\r
308 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
309 if (!EFI_ERROR (Status)) {\r
310 *Rca = (UINT16)(SdMmcStatusBlk.Resp0 >> 16);\r
311 }\r
312\r
313 return Status;\r
314}\r
315\r
48555339
FT
316/**\r
317 Send command SELECT_DESELECT_CARD to the SD device to select/deselect it.\r
318\r
319 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
320\r
321 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
322 @param[in] Slot The slot number of the SD card to send the command to.\r
323 @param[in] Rca The relative device address of selected device.\r
324\r
325 @retval EFI_SUCCESS The operation is done correctly.\r
326 @retval Others The operation fails.\r
327\r
328**/\r
329EFI_STATUS\r
330SdCardSelect (\r
331 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
332 IN UINT8 Slot,\r
333 IN UINT16 Rca\r
334 )\r
335{\r
336 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
337 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
338 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
339 EFI_STATUS Status;\r
340\r
341 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
342 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
343 ZeroMem (&Packet, sizeof (Packet));\r
344\r
345 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
346 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
347 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
348\r
349 SdMmcCmdBlk.CommandIndex = SD_SELECT_DESELECT_CARD;\r
350 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
ac30e4c1
FT
351 if (Rca != 0) {\r
352 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
353 }\r
48555339
FT
354 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
355\r
356 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
357\r
358 return Status;\r
359}\r
360\r
361/**\r
362 Send command VOLTAGE_SWITCH to the SD device to switch the voltage of the device.\r
363\r
364 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
365\r
366 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
367 @param[in] Slot The slot number of the SD card to send the command to.\r
368\r
369 @retval EFI_SUCCESS The operation is done correctly.\r
370 @retval Others The operation fails.\r
371\r
372**/\r
373EFI_STATUS\r
374SdCardVoltageSwitch (\r
375 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
376 IN UINT8 Slot\r
377 )\r
378{\r
379 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
380 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
381 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
382 EFI_STATUS Status;\r
383\r
384 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
385 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
386 ZeroMem (&Packet, sizeof (Packet));\r
387\r
388 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
389 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
390 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
391\r
392 SdMmcCmdBlk.CommandIndex = SD_VOLTAGE_SWITCH;\r
393 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
394 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
395 SdMmcCmdBlk.CommandArgument = 0;\r
396\r
397 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
398\r
399 return Status;\r
400}\r
401\r
402/**\r
403 Send command SET_BUS_WIDTH to the SD device to set the bus width.\r
404\r
405 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
406\r
407 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
408 @param[in] Slot The slot number of the SD card to send the command to.\r
409 @param[in] Rca The relative device address of addressed device.\r
410 @param[in] BusWidth The bus width to be set, it could be 1 or 4.\r
411\r
412 @retval EFI_SUCCESS The operation is done correctly.\r
413 @retval Others The operation fails.\r
414\r
415**/\r
416EFI_STATUS\r
417SdCardSetBusWidth (\r
418 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
419 IN UINT8 Slot,\r
420 IN UINT16 Rca,\r
421 IN UINT8 BusWidth\r
422 )\r
423{\r
424 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
425 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
426 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
427 EFI_STATUS Status;\r
428 UINT8 Value;\r
429\r
430 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
431 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
432 ZeroMem (&Packet, sizeof (Packet));\r
433\r
434 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
435 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
436 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
437\r
438 SdMmcCmdBlk.CommandIndex = SD_APP_CMD;\r
439 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
440 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
441 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
442\r
443 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
444 if (EFI_ERROR (Status)) {\r
445 return Status;\r
446 }\r
447\r
448 SdMmcCmdBlk.CommandIndex = SD_SET_BUS_WIDTH;\r
449 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
450 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
451\r
452 if (BusWidth == 1) {\r
453 Value = 0;\r
454 } else if (BusWidth == 4) {\r
455 Value = 2;\r
456 } else {\r
457 return EFI_INVALID_PARAMETER;\r
458 }\r
459\r
460 SdMmcCmdBlk.CommandArgument = Value & 0x3;\r
461\r
462 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
463 return Status;\r
464}\r
465\r
466/**\r
467 Send command SWITCH_FUNC to the SD device to check switchable function or switch card function.\r
468\r
469 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
470\r
adec1f5d
AM
471 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
472 @param[in] Slot The slot number of the SD card to send the command to.\r
473 @param[in] BusTiming Target bus timing based on which access group value will be set.\r
474 @param[in] CommandSystem The value for command set group.\r
475 @param[in] DriverStrength The value for driver strength group.\r
476 @param[in] PowerLimit The value for power limit group.\r
477 @param[in] Mode Switch or check function.\r
478 @param[out] SwitchResp The return switch function status.\r
48555339
FT
479\r
480 @retval EFI_SUCCESS The operation is done correctly.\r
481 @retval Others The operation fails.\r
482\r
483**/\r
484EFI_STATUS\r
485SdCardSwitch (\r
6263ae93
FT
486 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
487 IN UINT8 Slot,\r
adec1f5d 488 IN SD_MMC_BUS_MODE BusTiming,\r
6263ae93 489 IN UINT8 CommandSystem,\r
adec1f5d 490 IN SD_DRIVER_STRENGTH_TYPE DriverStrength,\r
6263ae93
FT
491 IN UINT8 PowerLimit,\r
492 IN BOOLEAN Mode,\r
493 OUT UINT8 *SwitchResp\r
48555339
FT
494 )\r
495{\r
496 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
497 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
498 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
499 EFI_STATUS Status;\r
500 UINT32 ModeValue;\r
adec1f5d 501 UINT8 AccessMode;\r
48555339
FT
502\r
503 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
504 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
505 ZeroMem (&Packet, sizeof (Packet));\r
506\r
507 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
508 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
509 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
510\r
511 SdMmcCmdBlk.CommandIndex = SD_SWITCH_FUNC;\r
512 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
513 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
514\r
515 ModeValue = Mode ? BIT31 : 0;\r
adec1f5d
AM
516\r
517 switch (BusTiming) {\r
518 case SdMmcUhsDdr50:\r
519 AccessMode = 0x4;\r
520 break;\r
521 case SdMmcUhsSdr104:\r
522 AccessMode = 0x3;\r
523 break;\r
524 case SdMmcUhsSdr50:\r
525 AccessMode = 0x2;\r
526 break;\r
527 case SdMmcUhsSdr25:\r
528 case SdMmcSdHs:\r
529 AccessMode = 0x1;\r
530 break;\r
531 case SdMmcUhsSdr12:\r
532 case SdMmcSdDs:\r
533 AccessMode = 0;\r
534 break;\r
535 default:\r
536 AccessMode = 0xF;\r
537 }\r
538\r
539 SdMmcCmdBlk.CommandArgument = (AccessMode & 0xF) | ((CommandSystem & 0xF) << 4) | \\r
540 ((DriverStrength & 0xF) << 8) | ((PowerLimit & 0xF) << 12) | \\r
48555339
FT
541 ModeValue;\r
542\r
6263ae93
FT
543 Packet.InDataBuffer = SwitchResp;\r
544 Packet.InTransferLength = 64;\r
48555339
FT
545\r
546 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
adec1f5d
AM
547 if (EFI_ERROR (Status)) {\r
548 return Status;\r
549 }\r
550\r
551 if (Mode) {\r
552 if ((((AccessMode & 0xF) != 0xF) && ((SwitchResp[16] & 0xF) != AccessMode)) ||\r
553 (((CommandSystem & 0xF) != 0xF) && (((SwitchResp[16] >> 4) & 0xF) != CommandSystem)) ||\r
554 (((DriverStrength & 0xF) != 0xF) && ((SwitchResp[15] & 0xF) != DriverStrength)) ||\r
555 (((PowerLimit & 0xF) != 0xF) && (((SwitchResp[15] >> 4) & 0xF) != PowerLimit))) {\r
556 return EFI_DEVICE_ERROR;\r
557 }\r
558 }\r
48555339
FT
559\r
560 return Status;\r
561}\r
562\r
563/**\r
564 Send command SEND_STATUS to the addressed SD device to get its status register.\r
565\r
566 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
567\r
568 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
569 @param[in] Slot The slot number of the SD card to send the command to.\r
570 @param[in] Rca The relative device address of addressed device.\r
571 @param[out] DevStatus The returned device status.\r
572\r
573 @retval EFI_SUCCESS The operation is done correctly.\r
574 @retval Others The operation fails.\r
575\r
576**/\r
577EFI_STATUS\r
578SdCardSendStatus (\r
579 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
580 IN UINT8 Slot,\r
581 IN UINT16 Rca,\r
582 OUT UINT32 *DevStatus\r
583 )\r
584{\r
585 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
586 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
587 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
588 EFI_STATUS Status;\r
589\r
590 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
591 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
592 ZeroMem (&Packet, sizeof (Packet));\r
593\r
594 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
595 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
596 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
597\r
598 SdMmcCmdBlk.CommandIndex = SD_SEND_STATUS;\r
599 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
600 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
601 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
602\r
603 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
604 if (!EFI_ERROR (Status)) {\r
605 *DevStatus = SdMmcStatusBlk.Resp0;\r
606 }\r
607\r
608 return Status;\r
609}\r
610\r
611/**\r
612 Send command SEND_TUNING_BLOCK to the SD device for HS200 optimal sampling point\r
613 detection.\r
614\r
615 It may be sent up to 40 times until the host finishes the tuning procedure.\r
616\r
617 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 for details.\r
618\r
619 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
620 @param[in] Slot The slot number of the SD card to send the command to.\r
621\r
622 @retval EFI_SUCCESS The operation is done correctly.\r
623 @retval Others The operation fails.\r
624\r
625**/\r
626EFI_STATUS\r
627SdCardSendTuningBlk (\r
628 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
629 IN UINT8 Slot\r
630 )\r
631{\r
632 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
633 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
634 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
635 EFI_STATUS Status;\r
636 UINT8 TuningBlock[64];\r
637\r
638 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
639 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
640 ZeroMem (&Packet, sizeof (Packet));\r
641\r
642 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
643 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
644 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
645\r
646 SdMmcCmdBlk.CommandIndex = SD_SEND_TUNING_BLOCK;\r
647 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
648 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
649 SdMmcCmdBlk.CommandArgument = 0;\r
650\r
651 Packet.InDataBuffer = TuningBlock;\r
652 Packet.InTransferLength = sizeof (TuningBlock);\r
653\r
654 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
655\r
656 return Status;\r
657}\r
658\r
659/**\r
660 Tunning the sampling point of SDR104 or SDR50 bus speed mode.\r
661\r
662 Command SD_SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
663 tuning procedure.\r
664\r
665 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
666 SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
667\r
668 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
669 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
670 @param[in] Slot The slot number of the SD card to send the command to.\r
671\r
672 @retval EFI_SUCCESS The operation is done correctly.\r
673 @retval Others The operation fails.\r
674\r
675**/\r
676EFI_STATUS\r
677SdCardTuningClock (\r
678 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
679 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
680 IN UINT8 Slot\r
681 )\r
682{\r
683 EFI_STATUS Status;\r
684 UINT8 HostCtrl2;\r
685 UINT8 Retry;\r
686\r
687 //\r
688 // Notify the host that the sampling clock tuning procedure starts.\r
689 //\r
690 HostCtrl2 = BIT6;\r
691 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
692 if (EFI_ERROR (Status)) {\r
693 return Status;\r
694 }\r
695 //\r
696 // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
697 //\r
698 Retry = 0;\r
699 do {\r
700 Status = SdCardSendTuningBlk (PassThru, Slot);\r
701 if (EFI_ERROR (Status)) {\r
e27ccaba 702 DEBUG ((DEBUG_ERROR, "SdCardSendTuningBlk: Send tuning block fails with %r\n", Status));\r
48555339
FT
703 return Status;\r
704 }\r
705\r
706 Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
707 if (EFI_ERROR (Status)) {\r
708 return Status;\r
709 }\r
710\r
8c983d3e 711 if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
48555339
FT
712 break;\r
713 }\r
8c983d3e
FT
714 if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
715 return EFI_SUCCESS;\r
716 }\r
48555339
FT
717 } while (++Retry < 40);\r
718\r
e27ccaba 719 DEBUG ((DEBUG_ERROR, "SdCardTuningClock: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
8c983d3e
FT
720 //\r
721 // Abort the tuning procedure and reset the tuning circuit.\r
722 //\r
723 HostCtrl2 = (UINT8)~(BIT6 | BIT7);\r
724 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
725 if (EFI_ERROR (Status)) {\r
726 return Status;\r
48555339 727 }\r
8c983d3e 728 return EFI_DEVICE_ERROR;\r
48555339
FT
729}\r
730\r
731/**\r
732 Switch the bus width to specified width.\r
733\r
734 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
735 SD Host Controller Simplified Spec 3.0 section Figure 3-7 for details.\r
736\r
737 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
738 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
739 @param[in] Slot The slot number of the SD card to send the command to.\r
740 @param[in] Rca The relative device address to be assigned.\r
741 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
742\r
743 @retval EFI_SUCCESS The operation is done correctly.\r
744 @retval Others The operation fails.\r
745\r
746**/\r
747EFI_STATUS\r
748SdCardSwitchBusWidth (\r
749 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
750 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
751 IN UINT8 Slot,\r
752 IN UINT16 Rca,\r
753 IN UINT8 BusWidth\r
754 )\r
755{\r
756 EFI_STATUS Status;\r
757 UINT32 DevStatus;\r
758\r
759 Status = SdCardSetBusWidth (PassThru, Slot, Rca, BusWidth);\r
760 if (EFI_ERROR (Status)) {\r
e27ccaba 761 DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
48555339
FT
762 return Status;\r
763 }\r
764\r
765 Status = SdCardSendStatus (PassThru, Slot, Rca, &DevStatus);\r
766 if (EFI_ERROR (Status)) {\r
e27ccaba 767 DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: Send status fails with %r\n", Status));\r
48555339
FT
768 return Status;\r
769 }\r
770 //\r
771 // Check the switch operation is really successful or not.\r
772 //\r
773 if ((DevStatus >> 16) != 0) {\r
e27ccaba 774 DEBUG ((DEBUG_ERROR, "SdCardSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
48555339
FT
775 return EFI_DEVICE_ERROR;\r
776 }\r
777\r
778 Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
779\r
780 return Status;\r
781}\r
782\r
adec1f5d
AM
783/**\r
784 Check if passed BusTiming is supported in both controller and card.\r
785\r
786 @param[in] Private Pointer to controller private data\r
787 @param[in] SlotIndex Index of the slot in the controller\r
788 @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card\r
789 @param[in] IsInUhsI Flag indicating if link is in UHS-I\r
790\r
791 @retval TRUE Both card and controller support given BusTiming\r
792 @retval FALSE Card or controller doesn't support given BusTiming\r
793**/\r
794BOOLEAN\r
795SdIsBusTimingSupported (\r
796 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
797 IN UINT8 SlotIndex,\r
798 IN UINT8 CardSupportedBusTimings,\r
799 IN BOOLEAN IsInUhsI,\r
800 IN SD_MMC_BUS_MODE BusTiming\r
801 )\r
802{\r
803 SD_MMC_HC_SLOT_CAP *Capability;\r
804\r
805 Capability = &Private->Capability[SlotIndex];\r
806\r
807 if (IsInUhsI) {\r
808 switch (BusTiming) {\r
809 case SdMmcUhsSdr104:\r
810 if ((Capability->Sdr104 != 0) && ((CardSupportedBusTimings & BIT3) != 0)) {\r
811 return TRUE;\r
812 }\r
813 break;\r
814 case SdMmcUhsDdr50:\r
815 if ((Capability->Ddr50 != 0) && ((CardSupportedBusTimings & BIT4) != 0)) {\r
816 return TRUE;\r
817 }\r
818 break;\r
819 case SdMmcUhsSdr50:\r
820 if ((Capability->Sdr50 != 0) && ((CardSupportedBusTimings & BIT2) != 0)) {\r
821 return TRUE;\r
822 }\r
823 break;\r
824 case SdMmcUhsSdr25:\r
825 if ((CardSupportedBusTimings & BIT1) != 0) {\r
826 return TRUE;\r
827 }\r
828 break;\r
829 case SdMmcUhsSdr12:\r
830 if ((CardSupportedBusTimings & BIT0) != 0) {\r
831 return TRUE;\r
832 }\r
833 break;\r
834 default:\r
835 break;\r
836 }\r
837 } else {\r
838 switch (BusTiming) {\r
839 case SdMmcSdHs:\r
840 if ((Capability->HighSpeed != 0) && (CardSupportedBusTimings & BIT1) != 0) {\r
841 return TRUE;\r
842 }\r
843 break;\r
844 case SdMmcSdDs:\r
845 if ((CardSupportedBusTimings & BIT0) != 0) {\r
846 return TRUE;\r
847 }\r
848 break;\r
849 default:\r
850 break;\r
851 }\r
852 }\r
853\r
854 return FALSE;\r
855}\r
856\r
857/**\r
858 Get the target bus timing to set on the link. This function\r
859 will try to select highest bus timing supported by card, controller\r
860 and the driver.\r
861\r
862 @param[in] Private Pointer to controller private data\r
863 @param[in] SlotIndex Index of the slot in the controller\r
864 @param[in] CardSupportedBusTimings Bitmask indicating which bus timings are supported by card\r
865 @param[in] IsInUhsI Flag indicating if link is in UHS-I\r
866\r
867 @return Bus timing value that should be set on link\r
868**/\r
869SD_MMC_BUS_MODE\r
870SdGetTargetBusTiming (\r
871 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
872 IN UINT8 SlotIndex,\r
873 IN UINT8 CardSupportedBusTimings,\r
874 IN BOOLEAN IsInUhsI\r
875 )\r
876{\r
877 SD_MMC_BUS_MODE BusTiming;\r
878\r
879 if (IsInUhsI) {\r
880 BusTiming = SdMmcUhsSdr104;\r
881 } else {\r
882 BusTiming = SdMmcSdHs;\r
883 }\r
884\r
885 while (BusTiming > SdMmcSdDs) {\r
886 if (SdIsBusTimingSupported (Private, SlotIndex, CardSupportedBusTimings, IsInUhsI, BusTiming)) {\r
887 break;\r
888 }\r
889 BusTiming--;\r
890 }\r
891\r
892 return BusTiming;\r
893}\r
894\r
895/**\r
896 Get the target bus width to be set on the bus.\r
897\r
898 @param[in] Private Pointer to controller private data\r
899 @param[in] SlotIndex Index of the slot in the controller\r
900 @param[in] BusTiming Bus timing set on the bus\r
901\r
902 @return Bus width to be set on the bus\r
903**/\r
904UINT8\r
905SdGetTargetBusWidth (\r
906 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
907 IN UINT8 SlotIndex,\r
908 IN SD_MMC_BUS_MODE BusTiming\r
909 )\r
910{\r
911 UINT8 BusWidth;\r
912 UINT8 PreferredBusWidth;\r
913\r
914 PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;\r
915\r
916 if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
917 if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&\r
918 (PreferredBusWidth == 1 || PreferredBusWidth == 4)) {\r
919 BusWidth = PreferredBusWidth;\r
920 } else {\r
921 BusWidth = 4;\r
922 }\r
923 } else {\r
924 //\r
925 // UHS-I modes support only 4-bit width.\r
926 // Switch to 4-bit has been done before calling this function anyway so\r
927 // this is purely informational.\r
928 //\r
929 BusWidth = 4;\r
930 }\r
931\r
932 return BusWidth;\r
933}\r
934\r
935/**\r
936 Get the target clock frequency to be set on the bus.\r
937\r
938 @param[in] Private Pointer to controller private data\r
939 @param[in] SlotIndex Index of the slot in the controller\r
940 @param[in] BusTiming Bus timing to be set on the bus\r
941\r
942 @return Value of the clock frequency to be set on bus in MHz\r
943**/\r
944UINT32\r
945SdGetTargetBusClockFreq (\r
946 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
947 IN UINT8 SlotIndex,\r
948 IN SD_MMC_BUS_MODE BusTiming\r
949 )\r
950{\r
951 UINT32 PreferredClockFreq;\r
952 UINT32 MaxClockFreq;\r
953\r
954 PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;\r
955\r
956 switch (BusTiming) {\r
957 case SdMmcUhsSdr104:\r
958 MaxClockFreq = 208;\r
959 break;\r
960 case SdMmcUhsSdr50:\r
961 MaxClockFreq = 100;\r
962 break;\r
963 case SdMmcUhsDdr50:\r
964 case SdMmcUhsSdr25:\r
965 case SdMmcSdHs:\r
966 MaxClockFreq = 50;\r
967 break;\r
968 case SdMmcUhsSdr12:\r
969 case SdMmcSdDs:\r
970 default:\r
971 MaxClockFreq = 25;\r
972 }\r
973\r
974 if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {\r
975 return PreferredClockFreq;\r
976 } else {\r
977 return MaxClockFreq;\r
978 }\r
979}\r
980\r
981/**\r
982 Get the driver strength to be set on bus.\r
983\r
984 @param[in] Private Pointer to controller private data\r
985 @param[in] SlotIndex Index of the slot in the controller\r
986 @param[in] CardSupportedDriverStrengths Bitmask indicating which driver strengths are supported on the card\r
987 @param[in] BusTiming Bus timing set on the bus\r
988\r
989 @return Value of the driver strength to be set on the bus\r
990**/\r
991EDKII_SD_MMC_DRIVER_STRENGTH\r
992SdGetTargetDriverStrength (\r
993 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
994 IN UINT8 SlotIndex,\r
995 IN UINT8 CardSupportedDriverStrengths,\r
996 IN SD_MMC_BUS_MODE BusTiming\r
997 )\r
998{\r
999 EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;\r
1000 EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;\r
1001\r
1002 if (BusTiming == SdMmcSdDs || BusTiming == SdMmcSdHs) {\r
1003 DriverStrength.Sd = SdDriverStrengthIgnore;\r
1004 return DriverStrength;\r
1005 }\r
1006\r
1007 PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;\r
1008 DriverStrength.Sd = SdDriverStrengthTypeB;\r
1009\r
1010 if (PreferredDriverStrength.Sd != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&\r
1011 (CardSupportedDriverStrengths & (BIT0 << PreferredDriverStrength.Sd))) {\r
1012\r
1013 if ((PreferredDriverStrength.Sd == SdDriverStrengthTypeA &&\r
1014 (Private->Capability[SlotIndex].DriverTypeA != 0)) ||\r
1015 (PreferredDriverStrength.Sd == SdDriverStrengthTypeC &&\r
1016 (Private->Capability[SlotIndex].DriverTypeC != 0)) ||\r
1017 (PreferredDriverStrength.Sd == SdDriverStrengthTypeD &&\r
1018 (Private->Capability[SlotIndex].DriverTypeD != 0))) {\r
1019 DriverStrength.Sd = PreferredDriverStrength.Sd;\r
1020 }\r
1021 }\r
1022\r
1023 return DriverStrength;\r
1024}\r
1025\r
1026/**\r
1027 Get the target settings for the bus mode.\r
1028\r
1029 @param[in] Private Pointer to controller private data\r
1030 @param[in] SlotIndex Index of the slot in the controller\r
1031 @param[in] SwitchQueryResp Pointer to switch query response\r
1032 @param[in] IsInUhsI Flag indicating if link is in UHS-I mode\r
1033 @param[out] BusMode Target configuration of the bus\r
1034**/\r
1035VOID\r
1036SdGetTargetBusMode (\r
1037 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1038 IN UINT8 SlotIndex,\r
1039 IN UINT8 *SwitchQueryResp,\r
1040 IN BOOLEAN IsInUhsI,\r
1041 OUT SD_MMC_BUS_SETTINGS *BusMode\r
1042 )\r
1043{\r
1044 BusMode->BusTiming = SdGetTargetBusTiming (Private, SlotIndex, SwitchQueryResp[13], IsInUhsI);\r
1045 BusMode->BusWidth = SdGetTargetBusWidth (Private, SlotIndex, BusMode->BusTiming);\r
1046 BusMode->ClockFreq = SdGetTargetBusClockFreq (Private, SlotIndex, BusMode->BusTiming);\r
1047 BusMode->DriverStrength = SdGetTargetDriverStrength (Private, SlotIndex, SwitchQueryResp[9], BusMode->BusTiming);\r
1048}\r
1049\r
48555339
FT
1050/**\r
1051 Switch the high speed timing according to request.\r
1052\r
1053 Refer to SD Physical Layer Simplified Spec 4.1 Section 4.7 and\r
1054 SD Host Controller Simplified Spec 3.0 section Figure 2-29 for details.\r
1055\r
1056 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1057 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
1058 @param[in] Slot The slot number of the SD card to send the command to.\r
1059 @param[in] Rca The relative device address to be assigned.\r
1060 @param[in] S18A The boolean to show if it's a UHS-I SD card.\r
1061\r
1062 @retval EFI_SUCCESS The operation is done correctly.\r
1063 @retval Others The operation fails.\r
1064\r
1065**/\r
1066EFI_STATUS\r
1067SdCardSetBusMode (\r
1068 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1069 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
1070 IN UINT8 Slot,\r
1071 IN UINT16 Rca,\r
1072 IN BOOLEAN S18A\r
1073 )\r
1074{\r
1075 EFI_STATUS Status;\r
1076 SD_MMC_HC_SLOT_CAP *Capability;\r
48555339 1077 UINT8 HostCtrl1;\r
6263ae93 1078 UINT8 SwitchResp[64];\r
48555339 1079 SD_MMC_HC_PRIVATE_DATA *Private;\r
adec1f5d 1080 SD_MMC_BUS_SETTINGS BusMode;\r
48555339
FT
1081\r
1082 Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
1083\r
1084 Capability = &Private->Capability[Slot];\r
1085\r
1086 Status = SdCardSelect (PassThru, Slot, Rca);\r
1087 if (EFI_ERROR (Status)) {\r
1088 return Status;\r
1089 }\r
1090\r
adec1f5d
AM
1091 if (S18A) {\r
1092 //\r
1093 // For UHS-I speed modes 4-bit data bus is requiered so we\r
1094 // switch here irrespective of platform preference.\r
1095 //\r
1096 Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, 4);\r
1097 if (EFI_ERROR (Status)) {\r
1098 return Status;\r
1099 }\r
48555339 1100 }\r
adec1f5d 1101\r
48555339 1102 //\r
6263ae93
FT
1103 // Get the supported bus speed from SWITCH cmd return data group #1.\r
1104 //\r
adec1f5d 1105 Status = SdCardSwitch (PassThru, Slot, 0xFF, 0xF, SdDriverStrengthIgnore, 0xF, FALSE, SwitchResp);\r
6263ae93
FT
1106 if (EFI_ERROR (Status)) {\r
1107 return Status;\r
1108 }\r
adec1f5d
AM
1109\r
1110 SdGetTargetBusMode (Private, Slot, SwitchResp, S18A, &BusMode);\r
1111\r
1112 DEBUG ((DEBUG_INFO, "SdCardSetBusMode: Target bus mode: bus timing = %d, bus width = %d, clock freq[MHz] = %d, driver strength = %d\n",\r
1113 BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Sd));\r
1114\r
1115 if (!S18A) {\r
1116 Status = SdCardSwitchBusWidth (PciIo, PassThru, Slot, Rca, BusMode.BusWidth);\r
1117 if (EFI_ERROR (Status)) {\r
1118 return Status;\r
1119 }\r
48555339
FT
1120 }\r
1121\r
adec1f5d 1122 Status = SdCardSwitch (PassThru, Slot, BusMode.BusTiming, 0xF, BusMode.DriverStrength.Sd, 0xF, TRUE, SwitchResp);\r
48555339
FT
1123 if (EFI_ERROR (Status)) {\r
1124 return Status;\r
1125 }\r
1126\r
adec1f5d
AM
1127 Status = SdMmcSetDriverStrength (Private->PciIo, Slot, BusMode.DriverStrength.Sd);\r
1128 if (EFI_ERROR (Status)) {\r
1129 return Status;\r
6263ae93
FT
1130 }\r
1131\r
48555339 1132 //\r
adec1f5d 1133 // Set to High Speed timing\r
48555339 1134 //\r
adec1f5d 1135 if (BusMode.BusTiming == SdMmcSdHs) {\r
48555339
FT
1136 HostCtrl1 = BIT2;\r
1137 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
1138 if (EFI_ERROR (Status)) {\r
1139 return Status;\r
1140 }\r
1141 }\r
1142\r
adec1f5d 1143 Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusMode.BusTiming);\r
48555339
FT
1144 if (EFI_ERROR (Status)) {\r
1145 return Status;\r
1146 }\r
1147\r
49accded 1148 Status = SdMmcHcClockSupply (Private, Slot, BusMode.BusTiming, FALSE, BusMode.ClockFreq * 1000);\r
48555339
FT
1149 if (EFI_ERROR (Status)) {\r
1150 return Status;\r
1151 }\r
1152\r
adec1f5d 1153 if ((BusMode.BusTiming == SdMmcUhsSdr104) || ((BusMode.BusTiming == SdMmcUhsSdr50) && (Capability->TuningSDR50 != 0))) {\r
48555339
FT
1154 Status = SdCardTuningClock (PciIo, PassThru, Slot);\r
1155 if (EFI_ERROR (Status)) {\r
1156 return Status;\r
1157 }\r
1158 }\r
1159\r
1160 return Status;\r
1161}\r
1162\r
1163/**\r
1164 Execute SD device identification procedure.\r
1165\r
1166 Refer to SD Physical Layer Simplified Spec 4.1 Section 3.6 for details.\r
1167\r
1168 @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
1169 @param[in] Slot The slot number of the SD card to send the command to.\r
1170\r
1171 @retval EFI_SUCCESS There is a SD card.\r
1172 @retval Others There is not a SD card.\r
1173\r
1174**/\r
1175EFI_STATUS\r
1176SdCardIdentification (\r
1177 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1178 IN UINT8 Slot\r
1179 )\r
1180{\r
1181 EFI_STATUS Status;\r
1182 EFI_PCI_IO_PROTOCOL *PciIo;\r
1183 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1184 UINT32 Ocr;\r
1185 UINT16 Rca;\r
1186 BOOLEAN Xpc;\r
1187 BOOLEAN S18r;\r
1188 UINT64 MaxCurrent;\r
1189 UINT16 ControllerVer;\r
1190 UINT8 PowerCtrl;\r
1191 UINT32 PresentState;\r
1192 UINT8 HostCtrl2;\r
ec86d285 1193 UINTN Retry;\r
48555339
FT
1194\r
1195 PciIo = Private->PciIo;\r
1196 PassThru = &Private->PassThru;\r
1197 //\r
1198 // 1. Send Cmd0 to the device\r
1199 //\r
1200 Status = SdCardReset (PassThru, Slot);\r
1201 if (EFI_ERROR (Status)) {\r
e27ccaba 1202 DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd0 fails with %r\n", Status));\r
48555339
FT
1203 return Status;\r
1204 }\r
1205 //\r
1206 // 2. Send Cmd8 to the device\r
1207 //\r
1208 Status = SdCardVoltageCheck (PassThru, Slot, 0x1, 0xFF);\r
1209 if (EFI_ERROR (Status)) {\r
e27ccaba 1210 DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing Cmd8 fails with %r\n", Status));\r
48555339
FT
1211 return Status;\r
1212 }\r
1213 //\r
1214 // 3. Send SDIO Cmd5 to the device to the SDIO device OCR register.\r
1215 //\r
1216 Status = SdioSendOpCond (PassThru, Slot, 0, FALSE);\r
1217 if (!EFI_ERROR (Status)) {\r
e27ccaba 1218 DEBUG ((DEBUG_INFO, "SdCardIdentification: Found SDIO device, ignore it as we don't support\n"));\r
48555339
FT
1219 return EFI_DEVICE_ERROR;\r
1220 }\r
1221 //\r
1222 // 4. Send Acmd41 with voltage window 0 to the device\r
1223 //\r
1224 Status = SdCardSendOpCond (PassThru, Slot, 0, 0, FALSE, FALSE, FALSE, &Ocr);\r
1225 if (EFI_ERROR (Status)) {\r
e27ccaba 1226 DEBUG ((DEBUG_INFO, "SdCardIdentification: Executing SdCardSendOpCond fails with %r\n", Status));\r
48555339
FT
1227 return EFI_DEVICE_ERROR;\r
1228 }\r
1229\r
1230 if (Private->Capability[Slot].Voltage33 != 0) {\r
1231 //\r
1232 // Support 3.3V\r
1233 //\r
1234 MaxCurrent = ((UINT32)Private->MaxCurrent[Slot] & 0xFF) * 4;\r
1235 } else if (Private->Capability[Slot].Voltage30 != 0) {\r
1236 //\r
1237 // Support 3.0V\r
1238 //\r
1239 MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 8) & 0xFF) * 4;\r
1240 } else if (Private->Capability[Slot].Voltage18 != 0) {\r
1241 //\r
1242 // Support 1.8V\r
1243 //\r
1244 MaxCurrent = (((UINT32)Private->MaxCurrent[Slot] >> 16) & 0xFF) * 4;\r
1245 } else {\r
1246 ASSERT (FALSE);\r
1247 return EFI_DEVICE_ERROR;\r
1248 }\r
1249\r
1250 if (MaxCurrent >= 150) {\r
1251 Xpc = TRUE;\r
1252 } else {\r
1253 Xpc = FALSE;\r
1254 }\r
1255\r
1256 Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_CTRL_VER, TRUE, sizeof (ControllerVer), &ControllerVer);\r
1257 if (EFI_ERROR (Status)) {\r
1258 return Status;\r
1259 }\r
1260\r
bbce0015
JB
1261 if (((ControllerVer & 0xFF) >= SD_MMC_HC_CTRL_VER_300) &&\r
1262 ((ControllerVer & 0xFF) <= SD_MMC_HC_CTRL_VER_420)) {\r
48555339 1263 S18r = TRUE;\r
bdf038cc 1264 } else if (((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_100) || ((ControllerVer & 0xFF) == SD_MMC_HC_CTRL_VER_200)) {\r
48555339
FT
1265 S18r = FALSE;\r
1266 } else {\r
1267 ASSERT (FALSE);\r
1268 return EFI_UNSUPPORTED;\r
1269 }\r
1270 //\r
1271 // 5. Repeatly send Acmd41 with supply voltage window to the device.\r
1272 // Note here we only support the cards complied with SD physical\r
1273 // layer simplified spec version 2.0 and version 3.0 and above.\r
1274 //\r
ec86d285
FT
1275 Ocr = 0;\r
1276 Retry = 0;\r
48555339
FT
1277 do {\r
1278 Status = SdCardSendOpCond (PassThru, Slot, 0, Ocr, S18r, Xpc, TRUE, &Ocr);\r
1279 if (EFI_ERROR (Status)) {\r
e27ccaba 1280 DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails with %r Ocr %x, S18r %x, Xpc %x\n", Status, Ocr, S18r, Xpc));\r
48555339
FT
1281 return EFI_DEVICE_ERROR;\r
1282 }\r
ec86d285
FT
1283\r
1284 if (Retry++ == 100) {\r
1285 DEBUG ((DEBUG_ERROR, "SdCardIdentification: SdCardSendOpCond fails too many times\n"));\r
1286 return EFI_DEVICE_ERROR;\r
1287 }\r
1288 gBS->Stall(10 * 1000);\r
48555339
FT
1289 } while ((Ocr & BIT31) == 0);\r
1290\r
1291 //\r
1292 // 6. If the S18A bit is set and the Host Controller supports 1.8V signaling\r
1293 // (One of support bits is set to 1: SDR50, SDR104 or DDR50 in the\r
1294 // Capabilities register), switch its voltage to 1.8V.\r
1295 //\r
1296 if ((Private->Capability[Slot].Sdr50 != 0 ||\r
1297 Private->Capability[Slot].Sdr104 != 0 ||\r
1298 Private->Capability[Slot].Ddr50 != 0) &&\r
1299 ((Ocr & BIT24) != 0)) {\r
1300 Status = SdCardVoltageSwitch (PassThru, Slot);\r
1301 if (EFI_ERROR (Status)) {\r
e27ccaba 1302 DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardVoltageSwitch fails with %r\n", Status));\r
48555339
FT
1303 Status = EFI_DEVICE_ERROR;\r
1304 goto Error;\r
1305 } else {\r
1306 Status = SdMmcHcStopClock (PciIo, Slot);\r
1307 if (EFI_ERROR (Status)) {\r
1308 Status = EFI_DEVICE_ERROR;\r
1309 goto Error;\r
1310 }\r
1311\r
1312 SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
1313 if (((PresentState >> 20) & 0xF) != 0) {\r
e27ccaba 1314 DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x\n", PresentState));\r
48555339
FT
1315 Status = EFI_DEVICE_ERROR;\r
1316 goto Error;\r
1317 }\r
1318 HostCtrl2 = BIT3;\r
1319 SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
1320\r
1321 gBS->Stall (5000);\r
1322\r
1323 SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
1324 if ((HostCtrl2 & BIT3) == 0) {\r
e27ccaba 1325 DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with HostCtrl2 = 0x%x\n", HostCtrl2));\r
48555339
FT
1326 Status = EFI_DEVICE_ERROR;\r
1327 goto Error;\r
1328 }\r
1329\r
49accded
AM
1330 //\r
1331 // Restart the clock with first time parameters.\r
1332 // NOTE: it is not required to actually restart the clock\r
1333 // and go through internal clock setup again. Some time\r
1334 // could be saved if we simply started the SD clock.\r
1335 //\r
1336 SdMmcHcClockSupply (Private, Slot, 0, TRUE, 400);\r
48555339 1337\r
2a8b78cf 1338 gBS->Stall (1000);\r
48555339
FT
1339\r
1340 SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_PRESENT_STATE, TRUE, sizeof (PresentState), &PresentState);\r
1341 if (((PresentState >> 20) & 0xF) != 0xF) {\r
e27ccaba 1342 DEBUG ((DEBUG_ERROR, "SdCardIdentification: SwitchVoltage fails with PresentState = 0x%x, It should be 0xF\n", PresentState));\r
48555339
FT
1343 Status = EFI_DEVICE_ERROR;\r
1344 goto Error;\r
1345 }\r
1346 }\r
e27ccaba 1347 DEBUG ((DEBUG_INFO, "SdCardIdentification: Switch to 1.8v signal voltage success\n"));\r
48555339
FT
1348 }\r
1349\r
1350 Status = SdCardAllSendCid (PassThru, Slot);\r
1351 if (EFI_ERROR (Status)) {\r
e27ccaba 1352 DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardAllSendCid fails with %r\n", Status));\r
48555339
FT
1353 return Status;\r
1354 }\r
1355\r
1356 Status = SdCardSetRca (PassThru, Slot, &Rca);\r
1357 if (EFI_ERROR (Status)) {\r
e27ccaba 1358 DEBUG ((DEBUG_ERROR, "SdCardIdentification: Executing SdCardSetRca fails with %r\n", Status));\r
48555339
FT
1359 return Status;\r
1360 }\r
1361 //\r
1362 // Enter Data Tranfer Mode.\r
1363 //\r
e27ccaba 1364 DEBUG ((DEBUG_INFO, "SdCardIdentification: Found a SD device at slot [%d]\n", Slot));\r
48555339
FT
1365 Private->Slot[Slot].CardType = SdCardType;\r
1366\r
1367 Status = SdCardSetBusMode (PciIo, PassThru, Slot, Rca, ((Ocr & BIT24) != 0));\r
1368\r
1369 return Status;\r
1370\r
1371Error:\r
1372 //\r
1373 // Set SD Bus Power = 0\r
1374 //\r
1375 PowerCtrl = (UINT8)~BIT0;\r
1376 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_POWER_CTRL, sizeof (PowerCtrl), &PowerCtrl);\r
1377 return EFI_DEVICE_ERROR;\r
1378}\r
1379\r