]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
MdeModulePkg/SdMmcPciHcDxe: Hook SwitchClockFreq after SD clock start
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / SdMmcPciHcDxe / EmmcDevice.c
CommitLineData
48555339
FT
1/** @file\r
2 This file provides some helper functions which are specific for EMMC device.\r
3\r
b5547b9c 4 Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.\r
8c983d3e 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 (CMD0 with argument of 0x00000000) to the device to\r
14 make it go to Idle State.\r
15\r
16 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
17\r
18 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
19 @param[in] Slot The slot number of the SD card to send the command to.\r
20\r
21 @retval EFI_SUCCESS The EMMC device is reset correctly.\r
22 @retval Others The device reset fails.\r
23\r
24**/\r
25EFI_STATUS\r
26EmmcReset (\r
27 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
28 IN UINT8 Slot\r
29 )\r
30{\r
31 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
32 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
33 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
34 EFI_STATUS Status;\r
35\r
36 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
37 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
38 ZeroMem (&Packet, sizeof (Packet));\r
39\r
40 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
41 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
42 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
43\r
44 SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
45 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;\r
46 SdMmcCmdBlk.ResponseType = 0;\r
47 SdMmcCmdBlk.CommandArgument = 0;\r
48\r
9252d67a
JZ
49 gBS->Stall (1000);\r
50\r
48555339
FT
51 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
52\r
53 return Status;\r
54}\r
55\r
56/**\r
57 Send command SEND_OP_COND to the EMMC device to get the data of the OCR register.\r
58\r
59 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
60\r
61 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
62 @param[in] Slot The slot number of the SD card to send the command to.\r
63 @param[in, out] Argument On input, the argument of SEND_OP_COND is to send to the device.\r
64 On output, the argument is the value of OCR register.\r
65\r
66 @retval EFI_SUCCESS The operation is done correctly.\r
67 @retval Others The operation fails.\r
68\r
69**/\r
70EFI_STATUS\r
71EmmcGetOcr (\r
72 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
73 IN UINT8 Slot,\r
74 IN OUT UINT32 *Argument\r
75 )\r
76{\r
77 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
78 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
79 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
80 EFI_STATUS Status;\r
81\r
82 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
83 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
84 ZeroMem (&Packet, sizeof (Packet));\r
85\r
86 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
87 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
88 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
89\r
90 SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
91 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
92 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
93 SdMmcCmdBlk.CommandArgument = *Argument;\r
94\r
95 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
96 if (!EFI_ERROR (Status)) {\r
97 //\r
98 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
99 //\r
100 *Argument = SdMmcStatusBlk.Resp0;\r
101 }\r
102\r
103 return Status;\r
104}\r
105\r
106/**\r
107 Broadcast command ALL_SEND_CID to the bus to ask all the EMMC devices to send the\r
108 data of their CID registers.\r
109\r
110 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
111\r
112 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
113 @param[in] Slot The slot number of the SD card to send the command to.\r
114\r
115 @retval EFI_SUCCESS The operation is done correctly.\r
116 @retval Others The operation fails.\r
117\r
118**/\r
119EFI_STATUS\r
120EmmcGetAllCid (\r
121 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
122 IN UINT8 Slot\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\r
130 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
131 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
132 ZeroMem (&Packet, sizeof (Packet));\r
133\r
134 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
135 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
136 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
137\r
138 SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
139 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
140 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
141 SdMmcCmdBlk.CommandArgument = 0;\r
142\r
143 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
144\r
145 return Status;\r
146}\r
147\r
148/**\r
149 Send command SET_RELATIVE_ADDR to the EMMC device to assign a Relative device\r
150 Address (RCA).\r
151\r
152 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
153\r
154 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
155 @param[in] Slot The slot number of the SD card to send the command to.\r
156 @param[in] Rca The relative device address to be assigned.\r
157\r
158 @retval EFI_SUCCESS The operation is done correctly.\r
159 @retval Others The operation fails.\r
160\r
161**/\r
162EFI_STATUS\r
163EmmcSetRca (\r
164 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
165 IN UINT8 Slot,\r
166 IN UINT16 Rca\r
167 )\r
168{\r
169 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
170 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
171 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
172 EFI_STATUS Status;\r
173\r
174 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
175 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
176 ZeroMem (&Packet, sizeof (Packet));\r
177\r
178 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
179 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
180 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
181\r
182 SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
183 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
184 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
185 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
186\r
187 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
188\r
189 return Status;\r
190}\r
191\r
192/**\r
193 Send command SEND_CSD to the EMMC device to get the data of the CSD register.\r
194\r
195 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
196\r
197 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
198 @param[in] Slot The slot number of the SD card to send the command to.\r
199 @param[in] Rca The relative device address of selected device.\r
200 @param[out] Csd The buffer to store the content of the CSD register.\r
201 Note the caller should ignore the lowest byte of this\r
202 buffer as the content of this byte is meaningless even\r
203 if the operation succeeds.\r
204\r
205 @retval EFI_SUCCESS The operation is done correctly.\r
206 @retval Others The operation fails.\r
207\r
208**/\r
209EFI_STATUS\r
210EmmcGetCsd (\r
211 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
212 IN UINT8 Slot,\r
213 IN UINT16 Rca,\r
214 OUT EMMC_CSD *Csd\r
215 )\r
216{\r
217 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
218 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
219 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
220 EFI_STATUS Status;\r
221\r
222 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
223 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
224 ZeroMem (&Packet, sizeof (Packet));\r
225\r
226 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
227 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
228 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
229\r
230 SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
231 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
232 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
233 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
234\r
235 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
236 if (!EFI_ERROR (Status)) {\r
237 //\r
238 // For details, refer to SD Host Controller Simplified Spec 3.0 Table 2-12.\r
239 //\r
240 CopyMem (((UINT8*)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
241 }\r
242\r
243 return Status;\r
244}\r
245\r
246/**\r
247 Send command SELECT_DESELECT_CARD to the EMMC device to select/deselect it.\r
248\r
249 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
250\r
251 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
252 @param[in] Slot The slot number of the SD card to send the command to.\r
253 @param[in] Rca The relative device address of selected device.\r
254\r
255 @retval EFI_SUCCESS The operation is done correctly.\r
256 @retval Others The operation fails.\r
257\r
258**/\r
259EFI_STATUS\r
260EmmcSelect (\r
261 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
262 IN UINT8 Slot,\r
263 IN UINT16 Rca\r
264 )\r
265{\r
266 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
267 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
268 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
269 EFI_STATUS Status;\r
270\r
271 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
272 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
273 ZeroMem (&Packet, sizeof (Packet));\r
274\r
275 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
276 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
277 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
278\r
279 SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
280 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
281 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
282 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
283\r
284 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
285\r
286 return Status;\r
287}\r
288\r
289/**\r
290 Send command SEND_EXT_CSD to the EMMC device to get the data of the EXT_CSD register.\r
291\r
292 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
293\r
294 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
295 @param[in] Slot The slot number of the SD card to send the command to.\r
296 @param[out] ExtCsd The buffer to store the content of the EXT_CSD register.\r
297\r
298 @retval EFI_SUCCESS The operation is done correctly.\r
299 @retval Others The operation fails.\r
300\r
301**/\r
302EFI_STATUS\r
303EmmcGetExtCsd (\r
304 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
305 IN UINT8 Slot,\r
306 OUT EMMC_EXT_CSD *ExtCsd\r
307 )\r
308{\r
309 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
310 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
311 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
312 EFI_STATUS Status;\r
313\r
314 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
315 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
316 ZeroMem (&Packet, sizeof (Packet));\r
317\r
318 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
319 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
320 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
321\r
322 SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
323 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
324 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
325 SdMmcCmdBlk.CommandArgument = 0x00000000;\r
326\r
327 Packet.InDataBuffer = ExtCsd;\r
328 Packet.InTransferLength = sizeof (EMMC_EXT_CSD);\r
329\r
330 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
331 return Status;\r
332}\r
333\r
334/**\r
335 Send command SWITCH to the EMMC device to switch the mode of operation of the\r
336 selected Device or modifies the EXT_CSD registers.\r
337\r
338 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
339\r
340 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
341 @param[in] Slot The slot number of the SD card to send the command to.\r
342 @param[in] Access The access mode of SWTICH command.\r
343 @param[in] Index The offset of the field to be access.\r
344 @param[in] Value The value to be set to the specified field of EXT_CSD register.\r
345 @param[in] CmdSet The value of CmdSet field of EXT_CSD register.\r
346\r
347 @retval EFI_SUCCESS The operation is done correctly.\r
348 @retval Others The operation fails.\r
349\r
350**/\r
351EFI_STATUS\r
352EmmcSwitch (\r
353 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
354 IN UINT8 Slot,\r
355 IN UINT8 Access,\r
356 IN UINT8 Index,\r
357 IN UINT8 Value,\r
358 IN UINT8 CmdSet\r
359 )\r
360{\r
361 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
362 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
363 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
364 EFI_STATUS Status;\r
365\r
366 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
367 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
368 ZeroMem (&Packet, sizeof (Packet));\r
369\r
370 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
371 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
372 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
373\r
374 SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
375 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
376 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
377 SdMmcCmdBlk.CommandArgument = (Access << 24) | (Index << 16) | (Value << 8) | CmdSet;\r
378\r
379 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
380\r
381 return Status;\r
382}\r
383\r
384/**\r
385 Send command SEND_STATUS to the addressed EMMC device to get its status register.\r
386\r
387 Refer to EMMC Electrical Standard Spec 5.1 Section 6.10.4 for details.\r
388\r
389 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
390 @param[in] Slot The slot number of the SD card to send the command to.\r
391 @param[in] Rca The relative device address of addressed device.\r
392 @param[out] DevStatus The returned device status.\r
393\r
394 @retval EFI_SUCCESS The operation is done correctly.\r
395 @retval Others The operation fails.\r
396\r
397**/\r
398EFI_STATUS\r
399EmmcSendStatus (\r
400 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
401 IN UINT8 Slot,\r
402 IN UINT16 Rca,\r
403 OUT UINT32 *DevStatus\r
404 )\r
405{\r
406 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
407 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
408 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
409 EFI_STATUS Status;\r
410\r
411 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
412 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
413 ZeroMem (&Packet, sizeof (Packet));\r
414\r
415 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
416 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
417 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
418\r
419 SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
420 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
421 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
422 SdMmcCmdBlk.CommandArgument = (UINT32)Rca << 16;\r
423\r
424 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
425 if (!EFI_ERROR (Status)) {\r
426 *DevStatus = SdMmcStatusBlk.Resp0;\r
427 }\r
428\r
429 return Status;\r
430}\r
431\r
432/**\r
433 Send command SEND_TUNING_BLOCK to the EMMC device for HS200 optimal sampling point\r
434 detection.\r
435\r
436 It may be sent up to 40 times until the host finishes the tuning procedure.\r
437\r
438 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 for details.\r
439\r
440 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
441 @param[in] Slot The slot number of the SD card to send the command to.\r
442 @param[in] BusWidth The bus width to work.\r
443\r
444 @retval EFI_SUCCESS The operation is done correctly.\r
445 @retval Others The operation fails.\r
446\r
447**/\r
448EFI_STATUS\r
449EmmcSendTuningBlk (\r
450 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
451 IN UINT8 Slot,\r
452 IN UINT8 BusWidth\r
453 )\r
454{\r
455 EFI_SD_MMC_COMMAND_BLOCK SdMmcCmdBlk;\r
456 EFI_SD_MMC_STATUS_BLOCK SdMmcStatusBlk;\r
457 EFI_SD_MMC_PASS_THRU_COMMAND_PACKET Packet;\r
458 EFI_STATUS Status;\r
459 UINT8 TuningBlock[128];\r
460\r
461 ZeroMem (&SdMmcCmdBlk, sizeof (SdMmcCmdBlk));\r
462 ZeroMem (&SdMmcStatusBlk, sizeof (SdMmcStatusBlk));\r
463 ZeroMem (&Packet, sizeof (Packet));\r
464\r
465 Packet.SdMmcCmdBlk = &SdMmcCmdBlk;\r
466 Packet.SdMmcStatusBlk = &SdMmcStatusBlk;\r
467 Packet.Timeout = SD_MMC_HC_GENERIC_TIMEOUT;\r
468\r
469 SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
470 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
471 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
472 SdMmcCmdBlk.CommandArgument = 0;\r
473\r
474 Packet.InDataBuffer = TuningBlock;\r
475 if (BusWidth == 8) {\r
476 Packet.InTransferLength = sizeof (TuningBlock);\r
477 } else {\r
478 Packet.InTransferLength = 64;\r
479 }\r
480\r
481 Status = SdMmcPassThruPassThru (PassThru, Slot, &Packet, NULL);\r
482\r
483 return Status;\r
484}\r
485\r
486/**\r
487 Tunning the clock to get HS200 optimal sampling point.\r
488\r
489 Command SEND_TUNING_BLOCK may be sent up to 40 times until the host finishes the\r
490 tuning procedure.\r
491\r
492 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
493 Simplified Spec 3.0 Figure 2-29 for details.\r
494\r
495 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
496 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
497 @param[in] Slot The slot number of the SD card to send the command to.\r
498 @param[in] BusWidth The bus width to work.\r
499\r
500 @retval EFI_SUCCESS The operation is done correctly.\r
501 @retval Others The operation fails.\r
502\r
503**/\r
504EFI_STATUS\r
505EmmcTuningClkForHs200 (\r
506 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
507 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
508 IN UINT8 Slot,\r
509 IN UINT8 BusWidth\r
510 )\r
511{\r
512 EFI_STATUS Status;\r
513 UINT8 HostCtrl2;\r
514 UINT8 Retry;\r
515\r
516 //\r
517 // Notify the host that the sampling clock tuning procedure starts.\r
518 //\r
519 HostCtrl2 = BIT6;\r
520 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
521 if (EFI_ERROR (Status)) {\r
522 return Status;\r
523 }\r
524 //\r
525 // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
526 //\r
527 Retry = 0;\r
528 do {\r
529 Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);\r
530 if (EFI_ERROR (Status)) {\r
e27ccaba 531 DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));\r
48555339
FT
532 return Status;\r
533 }\r
534\r
535 Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
536 if (EFI_ERROR (Status)) {\r
537 return Status;\r
538 }\r
539\r
8c983d3e 540 if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
48555339
FT
541 break;\r
542 }\r
8c983d3e
FT
543\r
544 if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
545 return EFI_SUCCESS;\r
546 }\r
48555339
FT
547 } while (++Retry < 40);\r
548\r
e27ccaba 549 DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
8c983d3e
FT
550 //\r
551 // Abort the tuning procedure and reset the tuning circuit.\r
552 //\r
553 HostCtrl2 = (UINT8)~(BIT6 | BIT7);\r
554 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
555 if (EFI_ERROR (Status)) {\r
556 return Status;\r
48555339 557 }\r
8c983d3e 558 return EFI_DEVICE_ERROR;\r
48555339
FT
559}\r
560\r
561/**\r
562 Switch the bus width to specified width.\r
563\r
564 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
565 Simplified Spec 3.0 Figure 3-7 for details.\r
566\r
567 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\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 to be assigned.\r
571 @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
572 use single data rate data simpling method.\r
573 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
574\r
575 @retval EFI_SUCCESS The operation is done correctly.\r
576 @retval Others The operation fails.\r
577\r
578**/\r
579EFI_STATUS\r
580EmmcSwitchBusWidth (\r
581 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
582 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
583 IN UINT8 Slot,\r
584 IN UINT16 Rca,\r
585 IN BOOLEAN IsDdr,\r
586 IN UINT8 BusWidth\r
587 )\r
588{\r
589 EFI_STATUS Status;\r
590 UINT8 Access;\r
591 UINT8 Index;\r
592 UINT8 Value;\r
593 UINT8 CmdSet;\r
594 UINT32 DevStatus;\r
595\r
596 //\r
597 // Write Byte, the Value field is written into the byte pointed by Index.\r
598 //\r
599 Access = 0x03;\r
600 Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
601 if (BusWidth == 4) {\r
602 Value = 1;\r
603 } else if (BusWidth == 8) {\r
604 Value = 2;\r
605 } else {\r
606 return EFI_INVALID_PARAMETER;\r
607 }\r
608\r
609 if (IsDdr) {\r
610 Value += 4;\r
611 }\r
612\r
613 CmdSet = 0;\r
614 Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
615 if (EFI_ERROR (Status)) {\r
e27ccaba 616 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
48555339
FT
617 return Status;\r
618 }\r
619\r
620 Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
621 if (EFI_ERROR (Status)) {\r
e27ccaba 622 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Send status fails with %r\n", Status));\r
48555339
FT
623 return Status;\r
624 }\r
625 //\r
626 // Check the switch operation is really successful or not.\r
627 //\r
628 if ((DevStatus & BIT7) != 0) {\r
e27ccaba 629 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
48555339
FT
630 return EFI_DEVICE_ERROR;\r
631 }\r
632\r
633 Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
634\r
635 return Status;\r
636}\r
637\r
638/**\r
195f673f 639 Switch the bus timing and clock frequency.\r
48555339
FT
640\r
641 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
642 Simplified Spec 3.0 Figure 3-3 for details.\r
643\r
adec1f5d
AM
644 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
645 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
646 @param[in] Slot The slot number of the SD card to send the command to.\r
647 @param[in] Rca The relative device address to be assigned.\r
648 @param[in] DriverStrength Driver strength to set for speed modes that support it.\r
649 @param[in] BusTiming The bus mode timing indicator.\r
650 @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.\r
48555339
FT
651\r
652 @retval EFI_SUCCESS The operation is done correctly.\r
653 @retval Others The operation fails.\r
654\r
655**/\r
656EFI_STATUS\r
195f673f 657EmmcSwitchBusTiming (\r
48555339
FT
658 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
659 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
660 IN UINT8 Slot,\r
661 IN UINT16 Rca,\r
adec1f5d
AM
662 IN EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength,\r
663 IN SD_MMC_BUS_MODE BusTiming,\r
48555339
FT
664 IN UINT32 ClockFreq\r
665 )\r
666{\r
667 EFI_STATUS Status;\r
668 UINT8 Access;\r
669 UINT8 Index;\r
670 UINT8 Value;\r
671 UINT8 CmdSet;\r
672 UINT32 DevStatus;\r
673 SD_MMC_HC_PRIVATE_DATA *Private;\r
a8c1fc70 674 UINT8 HostCtrl1;\r
48555339
FT
675\r
676 Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
677 //\r
678 // Write Byte, the Value field is written into the byte pointed by Index.\r
679 //\r
680 Access = 0x03;\r
681 Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
48555339 682 CmdSet = 0;\r
adec1f5d
AM
683 switch (BusTiming) {\r
684 case SdMmcMmcHs400:\r
685 Value = (UINT8)((DriverStrength.Emmc << 4) | 3);\r
686 break;\r
687 case SdMmcMmcHs200:\r
688 Value = (UINT8)((DriverStrength.Emmc << 4) | 2);\r
689 break;\r
690 case SdMmcMmcHsSdr:\r
691 case SdMmcMmcHsDdr:\r
692 Value = 1;\r
693 break;\r
694 case SdMmcMmcLegacy:\r
695 Value = 0;\r
696 break;\r
697 default:\r
698 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d\n)", BusTiming));\r
699 return EFI_INVALID_PARAMETER;\r
700 }\r
48555339
FT
701\r
702 Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
703 if (EFI_ERROR (Status)) {\r
adec1f5d 704 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to bus timing %d fails with %r\n", BusTiming, Status));\r
195f673f
AM
705 return Status;\r
706 }\r
707\r
a8c1fc70
AM
708 if (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcHsDdr) {\r
709 HostCtrl1 = BIT2;\r
710 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
711 if (EFI_ERROR (Status)) {\r
712 return Status;\r
713 }\r
714 } else {\r
715 HostCtrl1 = (UINT8)~BIT2;\r
716 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
717 if (EFI_ERROR (Status)) {\r
718 return Status;\r
719 }\r
720 }\r
721\r
722 Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);\r
723 if (EFI_ERROR (Status)) {\r
724 return Status;\r
725 }\r
726\r
195f673f
AM
727 //\r
728 // Convert the clock freq unit from MHz to KHz.\r
729 //\r
49accded 730 Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);\r
195f673f 731 if (EFI_ERROR (Status)) {\r
48555339
FT
732 return Status;\r
733 }\r
734\r
735 Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
736 if (EFI_ERROR (Status)) {\r
195f673f 737 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Send status fails with %r\n", Status));\r
48555339
FT
738 return Status;\r
739 }\r
740 //\r
741 // Check the switch operation is really successful or not.\r
742 //\r
743 if ((DevStatus & BIT7) != 0) {\r
195f673f 744 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
48555339
FT
745 return EFI_DEVICE_ERROR;\r
746 }\r
b7b803a6 747\r
48555339
FT
748 return Status;\r
749}\r
750\r
751/**\r
752 Switch to the High Speed timing according to request.\r
753\r
754 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
755 Simplified Spec 3.0 Figure 2-29 for details.\r
756\r
757 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
758 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
759 @param[in] Slot The slot number of the SD card to send the command to.\r
760 @param[in] Rca The relative device address to be assigned.\r
adec1f5d 761 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
762\r
763 @retval EFI_SUCCESS The operation is done correctly.\r
764 @retval Others The operation fails.\r
765\r
766**/\r
767EFI_STATUS\r
768EmmcSwitchToHighSpeed (\r
769 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
770 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
771 IN UINT8 Slot,\r
772 IN UINT16 Rca,\r
adec1f5d 773 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
774 )\r
775{\r
a8c1fc70
AM
776 EFI_STATUS Status;\r
777 BOOLEAN IsDdr;\r
48555339 778\r
76e1e563 779 if ((BusMode->BusTiming != SdMmcMmcHsSdr && BusMode->BusTiming != SdMmcMmcHsDdr && BusMode->BusTiming != SdMmcMmcLegacy) ||\r
adec1f5d
AM
780 BusMode->ClockFreq > 52) {\r
781 return EFI_INVALID_PARAMETER;\r
782 }\r
783\r
784 if (BusMode->BusTiming == SdMmcMmcHsDdr) {\r
785 IsDdr = TRUE;\r
786 } else {\r
787 IsDdr = FALSE;\r
788 }\r
789\r
790 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusMode->BusWidth);\r
48555339
FT
791 if (EFI_ERROR (Status)) {\r
792 return Status;\r
793 }\r
adec1f5d 794\r
adec1f5d 795 return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
48555339
FT
796}\r
797\r
798/**\r
adec1f5d 799 Switch to the HS200 timing. This function assumes that eMMC bus is still in legacy mode.\r
48555339
FT
800\r
801 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
802 Simplified Spec 3.0 Figure 2-29 for details.\r
803\r
adec1f5d
AM
804 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
805 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
806 @param[in] Slot The slot number of the SD card to send the command to.\r
807 @param[in] Rca The relative device address to be assigned.\r
808 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
809\r
810 @retval EFI_SUCCESS The operation is done correctly.\r
811 @retval Others The operation fails.\r
812\r
813**/\r
814EFI_STATUS\r
815EmmcSwitchToHS200 (\r
816 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
817 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
818 IN UINT8 Slot,\r
819 IN UINT16 Rca,\r
adec1f5d 820 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
821 )\r
822{\r
a8c1fc70 823 EFI_STATUS Status;\r
48555339 824\r
adec1f5d
AM
825 if (BusMode->BusTiming != SdMmcMmcHs200 ||\r
826 (BusMode->BusWidth != 4 && BusMode->BusWidth != 8)) {\r
48555339
FT
827 return EFI_INVALID_PARAMETER;\r
828 }\r
829\r
adec1f5d 830 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusMode->BusWidth);\r
48555339
FT
831 if (EFI_ERROR (Status)) {\r
832 return Status;\r
833 }\r
a4708009 834\r
adec1f5d 835 Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
48555339
FT
836 if (EFI_ERROR (Status)) {\r
837 return Status;\r
838 }\r
839\r
adec1f5d 840 Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode->BusWidth);\r
48555339
FT
841\r
842 return Status;\r
843}\r
844\r
845/**\r
adec1f5d 846 Switch to the HS400 timing. This function assumes that eMMC bus is still in legacy mode.\r
48555339
FT
847\r
848 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
849 Simplified Spec 3.0 Figure 2-29 for details.\r
850\r
adec1f5d
AM
851 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
852 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
853 @param[in] Slot The slot number of the SD card to send the command to.\r
854 @param[in] Rca The relative device address to be assigned.\r
855 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
856\r
857 @retval EFI_SUCCESS The operation is done correctly.\r
858 @retval Others The operation fails.\r
859\r
860**/\r
861EFI_STATUS\r
862EmmcSwitchToHS400 (\r
863 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
864 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
865 IN UINT8 Slot,\r
866 IN UINT16 Rca,\r
adec1f5d 867 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
868 )\r
869{\r
a8c1fc70
AM
870 EFI_STATUS Status;\r
871 SD_MMC_BUS_SETTINGS Hs200BusMode;\r
872 UINT32 HsFreq;\r
adec1f5d
AM
873\r
874 if (BusMode->BusTiming != SdMmcMmcHs400 ||\r
875 BusMode->BusWidth != 8) {\r
876 return EFI_INVALID_PARAMETER;\r
877 }\r
a4708009 878\r
adec1f5d
AM
879 Hs200BusMode.BusTiming = SdMmcMmcHs200;\r
880 Hs200BusMode.BusWidth = BusMode->BusWidth;\r
881 Hs200BusMode.ClockFreq = BusMode->ClockFreq;\r
882 Hs200BusMode.DriverStrength = BusMode->DriverStrength;\r
48555339 883\r
adec1f5d 884 Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &Hs200BusMode);\r
48555339
FT
885 if (EFI_ERROR (Status)) {\r
886 return Status;\r
887 }\r
adec1f5d 888\r
48555339 889 //\r
adec1f5d
AM
890 // Set to High Speed timing and set the clock frequency to a value less than or equal to 52MHz.\r
891 // This step is necessary to be able to switch Bus into 8 bit DDR mode which is unsupported in HS200.\r
48555339 892 //\r
adec1f5d
AM
893 HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;\r
894 Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);\r
48555339
FT
895 if (EFI_ERROR (Status)) {\r
896 return Status;\r
897 }\r
a4708009 898\r
adec1f5d
AM
899 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, BusMode->BusWidth);\r
900 if (EFI_ERROR (Status)) {\r
901 return Status;\r
902 }\r
a4708009 903\r
adec1f5d
AM
904 return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
905}\r
48555339 906\r
adec1f5d
AM
907/**\r
908 Check if passed BusTiming is supported in both controller and card.\r
909\r
910 @param[in] Private Pointer to controller private data\r
911 @param[in] SlotIndex Index of the slot in the controller\r
912 @param[in] ExtCsd Pointer to the card's extended CSD\r
913 @param[in] BusTiming Bus timing to check\r
914\r
915 @retval TRUE Both card and controller support given BusTiming\r
916 @retval FALSE Card or controller doesn't support given BusTiming\r
917**/\r
918BOOLEAN\r
919EmmcIsBusTimingSupported (\r
920 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
921 IN UINT8 SlotIndex,\r
922 IN EMMC_EXT_CSD *ExtCsd,\r
923 IN SD_MMC_BUS_MODE BusTiming\r
924 )\r
925{\r
926 BOOLEAN Supported;\r
927 SD_MMC_HC_SLOT_CAP *Capabilities;\r
928\r
929 Capabilities = &Private->Capability[SlotIndex];\r
930\r
931 Supported = FALSE;\r
932 switch (BusTiming) {\r
933 case SdMmcMmcHs400:\r
934 if ((((ExtCsd->DeviceType & (BIT6 | BIT7)) != 0) && (Capabilities->Hs400 != 0)) && Capabilities->BusWidth8 != 0) {\r
935 Supported = TRUE;\r
936 }\r
937 break;\r
938 case SdMmcMmcHs200:\r
939 if ((((ExtCsd->DeviceType & (BIT4 | BIT5)) != 0) && (Capabilities->Sdr104 != 0))) {\r
940 Supported = TRUE;\r
941 }\r
942 break;\r
943 case SdMmcMmcHsDdr:\r
944 if ((((ExtCsd->DeviceType & (BIT2 | BIT3)) != 0) && (Capabilities->Ddr50 != 0))) {\r
945 Supported = TRUE;\r
946 }\r
947 break;\r
948 case SdMmcMmcHsSdr:\r
949 if ((((ExtCsd->DeviceType & BIT1) != 0) && (Capabilities->HighSpeed != 0))) {\r
950 Supported = TRUE;\r
951 }\r
952 break;\r
953 case SdMmcMmcLegacy:\r
954 if ((ExtCsd->DeviceType & BIT0) != 0) {\r
955 Supported = TRUE;\r
956 }\r
957 break;\r
958 default:\r
959 ASSERT (FALSE);\r
960 }\r
961\r
962 return Supported;\r
963}\r
964\r
965/**\r
966 Get the target bus timing to set on the link. This function\r
967 will try to select highest bus timing supported by card, controller\r
968 and the driver.\r
969\r
970 @param[in] Private Pointer to controller private data\r
971 @param[in] SlotIndex Index of the slot in the controller\r
972 @param[in] ExtCsd Pointer to the card's extended CSD\r
973\r
974 @return Bus timing value that should be set on link\r
975**/\r
976SD_MMC_BUS_MODE\r
977EmmcGetTargetBusTiming (\r
978 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
979 IN UINT8 SlotIndex,\r
980 IN EMMC_EXT_CSD *ExtCsd\r
981 )\r
982{\r
983 SD_MMC_BUS_MODE BusTiming;\r
984\r
985 //\r
986 // We start with highest bus timing that this driver currently supports and\r
987 // return as soon as we find supported timing.\r
988 //\r
989 BusTiming = SdMmcMmcHs400;\r
990 while (BusTiming > SdMmcMmcLegacy) {\r
991 if (EmmcIsBusTimingSupported (Private, SlotIndex, ExtCsd, BusTiming)) {\r
992 break;\r
993 }\r
994 BusTiming--;\r
995 }\r
996\r
997 return BusTiming;\r
998}\r
999\r
1000/**\r
1001 Check if the passed bus width is supported by controller and card.\r
1002\r
1003 @param[in] Private Pointer to controller private data\r
1004 @param[in] SlotIndex Index of the slot in the controller\r
1005 @param[in] BusTiming Bus timing set on the link\r
1006 @param[in] BusWidth Bus width to check\r
1007\r
1008 @retval TRUE Passed bus width is supported in current bus configuration\r
1009 @retval FALSE Passed bus width is not supported in current bus configuration\r
1010**/\r
1011BOOLEAN\r
1012EmmcIsBusWidthSupported (\r
1013 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1014 IN UINT8 SlotIndex,\r
1015 IN SD_MMC_BUS_MODE BusTiming,\r
1016 IN UINT16 BusWidth\r
1017 )\r
1018{\r
1019 if (BusWidth == 8 && Private->Capability[SlotIndex].BusWidth8 != 0) {\r
1020 return TRUE;\r
1021 } else if (BusWidth == 4 && BusTiming != SdMmcMmcHs400) {\r
1022 return TRUE;\r
1023 } else if (BusWidth == 1 && (BusTiming == SdMmcMmcHsSdr || BusTiming == SdMmcMmcLegacy)) {\r
1024 return TRUE;\r
1025 }\r
1026\r
1027 return FALSE;\r
1028}\r
1029\r
1030/**\r
1031 Get the target bus width to be set on the bus.\r
1032\r
1033 @param[in] Private Pointer to controller private data\r
1034 @param[in] SlotIndex Index of the slot in the controller\r
1035 @param[in] ExtCsd Pointer to card's extended CSD\r
1036 @param[in] BusTiming Bus timing set on the bus\r
1037\r
1038 @return Bus width to be set on the bus\r
1039**/\r
1040UINT8\r
1041EmmcGetTargetBusWidth (\r
1042 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1043 IN UINT8 SlotIndex,\r
1044 IN EMMC_EXT_CSD *ExtCsd,\r
1045 IN SD_MMC_BUS_MODE BusTiming\r
1046 )\r
1047{\r
1048 UINT8 BusWidth;\r
1049 UINT8 PreferredBusWidth;\r
1050\r
1051 PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;\r
1052\r
1053 if (PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE &&\r
1054 EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, PreferredBusWidth)) {\r
1055 BusWidth = PreferredBusWidth;\r
1056 } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 8)) {\r
1057 BusWidth = 8;\r
1058 } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 4)) {\r
1059 BusWidth = 4;\r
1060 } else {\r
1061 BusWidth = 1;\r
1062 }\r
1063\r
1064 return BusWidth;\r
1065}\r
1066\r
1067/**\r
1068 Get the target clock frequency to be set on the bus.\r
1069\r
1070 @param[in] Private Pointer to controller private data\r
1071 @param[in] SlotIndex Index of the slot in the controller\r
1072 @param[in] ExtCsd Pointer to card's extended CSD\r
1073 @param[in] BusTiming Bus timing to be set on the bus\r
1074\r
1075 @return Value of the clock frequency to be set on bus in MHz\r
1076**/\r
1077UINT32\r
1078EmmcGetTargetClockFreq (\r
1079 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1080 IN UINT8 SlotIndex,\r
1081 IN EMMC_EXT_CSD *ExtCsd,\r
1082 IN SD_MMC_BUS_MODE BusTiming\r
1083 )\r
1084{\r
1085 UINT32 PreferredClockFreq;\r
1086 UINT32 MaxClockFreq;\r
1087\r
1088 PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;\r
1089\r
1090 switch (BusTiming) {\r
1091 case SdMmcMmcHs400:\r
1092 case SdMmcMmcHs200:\r
1093 MaxClockFreq = 200;\r
1094 break;\r
1095 case SdMmcMmcHsSdr:\r
1096 case SdMmcMmcHsDdr:\r
1097 MaxClockFreq = 52;\r
1098 break;\r
1099 default:\r
1100 MaxClockFreq = 26;\r
1101 break;\r
1102 }\r
1103\r
1104 if (PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE && PreferredClockFreq < MaxClockFreq) {\r
1105 return PreferredClockFreq;\r
1106 } else {\r
1107 return MaxClockFreq;\r
1108 }\r
1109}\r
1110\r
1111/**\r
1112 Get the driver strength to be set on bus.\r
1113\r
1114 @param[in] Private Pointer to controller private data\r
1115 @param[in] SlotIndex Index of the slot in the controller\r
1116 @param[in] ExtCsd Pointer to card's extended CSD\r
1117 @param[in] BusTiming Bus timing set on the bus\r
1118\r
1119 @return Value of the driver strength to be set on the bus\r
1120**/\r
1121EDKII_SD_MMC_DRIVER_STRENGTH\r
1122EmmcGetTargetDriverStrength (\r
1123 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1124 IN UINT8 SlotIndex,\r
1125 IN EMMC_EXT_CSD *ExtCsd,\r
1126 IN SD_MMC_BUS_MODE BusTiming\r
1127 )\r
1128{\r
1129 EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;\r
1130 EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;\r
1131\r
1132 PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;\r
1133 DriverStrength.Emmc = EmmcDriverStrengthType0;\r
1134\r
1135 if (PreferredDriverStrength.Emmc != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE &&\r
1136 (ExtCsd->DriverStrength & (BIT0 << PreferredDriverStrength.Emmc))) {\r
1137 DriverStrength.Emmc = PreferredDriverStrength.Emmc;\r
1138 }\r
1139\r
1140 return DriverStrength;\r
1141}\r
1142\r
1143/**\r
1144 Get the target settings for the bus mode.\r
1145\r
1146 @param[in] Private Pointer to controller private data\r
1147 @param[in] SlotIndex Index of the slot in the controller\r
1148 @param[in] ExtCsd Pointer to card's extended CSD\r
1149 @param[out] BusMode Target configuration of the bus\r
1150**/\r
1151VOID\r
1152EmmcGetTargetBusMode (\r
1153 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1154 IN UINT8 SlotIndex,\r
1155 IN EMMC_EXT_CSD *ExtCsd,\r
1156 OUT SD_MMC_BUS_SETTINGS *BusMode\r
1157 )\r
1158{\r
1159 BusMode->BusTiming = EmmcGetTargetBusTiming (Private, SlotIndex, ExtCsd);\r
1160 BusMode->BusWidth = EmmcGetTargetBusWidth (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
1161 BusMode->ClockFreq = EmmcGetTargetClockFreq (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
1162 BusMode->DriverStrength = EmmcGetTargetDriverStrength (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
48555339
FT
1163}\r
1164\r
1165/**\r
1166 Switch the high speed timing according to request.\r
1167\r
1168 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
1169 Simplified Spec 3.0 Figure 2-29 for details.\r
1170\r
1171 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1172 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
1173 @param[in] Slot The slot number of the SD card to send the command to.\r
1174 @param[in] Rca The relative device address to be assigned.\r
1175\r
1176 @retval EFI_SUCCESS The operation is done correctly.\r
1177 @retval Others The operation fails.\r
1178\r
1179**/\r
1180EFI_STATUS\r
1181EmmcSetBusMode (\r
1182 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1183 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
1184 IN UINT8 Slot,\r
1185 IN UINT16 Rca\r
1186 )\r
1187{\r
1188 EFI_STATUS Status;\r
1189 EMMC_CSD Csd;\r
1190 EMMC_EXT_CSD ExtCsd;\r
adec1f5d 1191 SD_MMC_BUS_SETTINGS BusMode;\r
48555339
FT
1192 SD_MMC_HC_PRIVATE_DATA *Private;\r
1193\r
1194 Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
1195\r
1196 Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);\r
1197 if (EFI_ERROR (Status)) {\r
e27ccaba 1198 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));\r
48555339
FT
1199 return Status;\r
1200 }\r
1201\r
1202 Status = EmmcSelect (PassThru, Slot, Rca);\r
1203 if (EFI_ERROR (Status)) {\r
e27ccaba 1204 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));\r
48555339
FT
1205 return Status;\r
1206 }\r
1207\r
7f3b0bad 1208 ASSERT (Private->BaseClkFreq[Slot] != 0);\r
adec1f5d 1209\r
48555339 1210 //\r
adec1f5d 1211 // Get Device_Type from EXT_CSD register.\r
48555339
FT
1212 //\r
1213 Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);\r
1214 if (EFI_ERROR (Status)) {\r
e27ccaba 1215 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));\r
48555339
FT
1216 return Status;\r
1217 }\r
48555339 1218\r
adec1f5d 1219 EmmcGetTargetBusMode (Private, Slot, &ExtCsd, &BusMode);\r
48555339 1220\r
adec1f5d
AM
1221 DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Target bus mode: timing = %d, width = %d, clock freq = %d, driver strength = %d\n",\r
1222 BusMode.BusTiming, BusMode.BusWidth, BusMode.ClockFreq, BusMode.DriverStrength.Emmc));\r
48555339 1223\r
adec1f5d
AM
1224 if (BusMode.BusTiming == SdMmcMmcHs400) {\r
1225 Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);\r
1226 } else if (BusMode.BusTiming == SdMmcMmcHs200) {\r
1227 Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);\r
48555339 1228 } else {\r
76e1e563
AM
1229 //\r
1230 // Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy\r
1231 // bus timing. This is because even though we might not want to\r
1232 // change the timing itself we still want to allow customization of\r
1233 // bus parameters such as clock frequency and bus width.\r
1234 //\r
adec1f5d 1235 Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);\r
48555339
FT
1236 }\r
1237\r
adec1f5d 1238 DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (BusMode.BusTiming == SdMmcMmcHs400) ? "HS400" : ((BusMode.BusTiming == SdMmcMmcHs200) ? "HS200" : "HighSpeed"), Status));\r
48555339
FT
1239\r
1240 return Status;\r
1241}\r
1242\r
1243/**\r
1244 Execute EMMC device identification procedure.\r
1245\r
1246 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1247\r
1248 @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
1249 @param[in] Slot The slot number of the SD card to send the command to.\r
1250\r
1251 @retval EFI_SUCCESS There is a EMMC card.\r
1252 @retval Others There is not a EMMC card.\r
1253\r
1254**/\r
1255EFI_STATUS\r
1256EmmcIdentification (\r
1257 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1258 IN UINT8 Slot\r
1259 )\r
1260{\r
1261 EFI_STATUS Status;\r
1262 EFI_PCI_IO_PROTOCOL *PciIo;\r
1263 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1264 UINT32 Ocr;\r
1265 UINT16 Rca;\r
ec86d285 1266 UINTN Retry;\r
48555339
FT
1267\r
1268 PciIo = Private->PciIo;\r
1269 PassThru = &Private->PassThru;\r
1270\r
1271 Status = EmmcReset (PassThru, Slot);\r
1272 if (EFI_ERROR (Status)) {\r
e27ccaba 1273 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));\r
48555339
FT
1274 return Status;\r
1275 }\r
1276\r
ec86d285
FT
1277 Ocr = 0;\r
1278 Retry = 0;\r
48555339
FT
1279 do {\r
1280 Status = EmmcGetOcr (PassThru, Slot, &Ocr);\r
1281 if (EFI_ERROR (Status)) {\r
e27ccaba 1282 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));\r
48555339
FT
1283 return Status;\r
1284 }\r
1285 Ocr |= BIT30;\r
ec86d285
FT
1286\r
1287 if (Retry++ == 100) {\r
1288 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails too many times\n"));\r
1289 return EFI_DEVICE_ERROR;\r
1290 }\r
1291 gBS->Stall(10 * 1000);\r
48555339
FT
1292 } while ((Ocr & BIT31) == 0);\r
1293\r
1294 Status = EmmcGetAllCid (PassThru, Slot);\r
1295 if (EFI_ERROR (Status)) {\r
e27ccaba 1296 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));\r
48555339
FT
1297 return Status;\r
1298 }\r
1299 //\r
1300 // Slot starts from 0 and valid RCA starts from 1.\r
1301 // Here we takes a simple formula to calculate the RCA.\r
1302 // Don't support multiple devices on the slot, that is\r
1303 // shared bus slot feature.\r
1304 //\r
1305 Rca = Slot + 1;\r
1306 Status = EmmcSetRca (PassThru, Slot, Rca);\r
1307 if (EFI_ERROR (Status)) {\r
e27ccaba 1308 DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));\r
48555339
FT
1309 return Status;\r
1310 }\r
1311 //\r
1312 // Enter Data Tranfer Mode.\r
1313 //\r
e27ccaba 1314 DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
48555339
FT
1315 Private->Slot[Slot].CardType = EmmcCardType;\r
1316\r
1317 Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);\r
1318\r
1319 return Status;\r
1320}\r
1321\r