]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/EmmcDevice.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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
1436aea4
MK
27 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
28 IN UINT8 Slot\r
48555339
FT
29 )\r
30{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
44 SdMmcCmdBlk.CommandIndex = EMMC_GO_IDLE_STATE;\r
45 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBc;\r
46 SdMmcCmdBlk.ResponseType = 0;\r
48555339
FT
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
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
90 SdMmcCmdBlk.CommandIndex = EMMC_SEND_OP_COND;\r
91 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
92 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR3;\r
48555339
FT
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
1436aea4
MK
121 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
122 IN UINT8 Slot\r
48555339
FT
123 )\r
124{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
138 SdMmcCmdBlk.CommandIndex = EMMC_ALL_SEND_CID;\r
139 SdMmcCmdBlk.CommandType = SdMmcCommandTypeBcr;\r
140 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
48555339
FT
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
1436aea4
MK
164 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
165 IN UINT8 Slot,\r
166 IN UINT16 Rca\r
48555339
FT
167 )\r
168{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
182 SdMmcCmdBlk.CommandIndex = EMMC_SET_RELATIVE_ADDR;\r
183 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
184 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
48555339
FT
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
1436aea4 214 OUT EMMC_CSD *Csd\r
48555339
FT
215 )\r
216{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
230 SdMmcCmdBlk.CommandIndex = EMMC_SEND_CSD;\r
231 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
232 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR2;\r
48555339
FT
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
1436aea4 240 CopyMem (((UINT8 *)Csd) + 1, &SdMmcStatusBlk.Resp0, sizeof (EMMC_CSD) - 1);\r
48555339
FT
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
1436aea4
MK
261 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
262 IN UINT8 Slot,\r
263 IN UINT16 Rca\r
48555339
FT
264 )\r
265{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
279 SdMmcCmdBlk.CommandIndex = EMMC_SELECT_DESELECT_CARD;\r
280 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
281 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
48555339
FT
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
1436aea4 306 OUT EMMC_EXT_CSD *ExtCsd\r
48555339
FT
307 )\r
308{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
322 SdMmcCmdBlk.CommandIndex = EMMC_SEND_EXT_CSD;\r
323 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
324 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
48555339
FT
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
1436aea4
MK
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
48555339
FT
359 )\r
360{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
374 SdMmcCmdBlk.CommandIndex = EMMC_SWITCH;\r
375 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
376 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1b;\r
48555339
FT
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
1436aea4 403 OUT UINT32 *DevStatus\r
48555339
FT
404 )\r
405{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
419 SdMmcCmdBlk.CommandIndex = EMMC_SEND_STATUS;\r
420 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAc;\r
421 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
48555339
FT
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
1436aea4
MK
450 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
451 IN UINT8 Slot,\r
452 IN UINT8 BusWidth\r
48555339
FT
453 )\r
454{\r
1436aea4
MK
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
48555339
FT
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
1436aea4
MK
469 SdMmcCmdBlk.CommandIndex = EMMC_SEND_TUNING_BLOCK;\r
470 SdMmcCmdBlk.CommandType = SdMmcCommandTypeAdtc;\r
471 SdMmcCmdBlk.ResponseType = SdMmcResponseTypeR1;\r
48555339
FT
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
1436aea4
MK
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
48555339
FT
510 )\r
511{\r
1436aea4
MK
512 EFI_STATUS Status;\r
513 UINT8 HostCtrl2;\r
514 UINT8 Retry;\r
48555339
FT
515\r
516 //\r
517 // Notify the host that the sampling clock tuning procedure starts.\r
518 //\r
519 HostCtrl2 = BIT6;\r
1436aea4 520 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
48555339
FT
521 if (EFI_ERROR (Status)) {\r
522 return Status;\r
523 }\r
1436aea4 524\r
48555339
FT
525 //\r
526 // Ask the device to send a sequence of tuning blocks till the tuning procedure is done.\r
527 //\r
528 Retry = 0;\r
529 do {\r
530 Status = EmmcSendTuningBlk (PassThru, Slot, BusWidth);\r
531 if (EFI_ERROR (Status)) {\r
e27ccaba 532 DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails with %r\n", Status));\r
48555339
FT
533 return Status;\r
534 }\r
535\r
536 Status = SdMmcHcRwMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, TRUE, sizeof (HostCtrl2), &HostCtrl2);\r
537 if (EFI_ERROR (Status)) {\r
538 return Status;\r
539 }\r
540\r
8c983d3e 541 if ((HostCtrl2 & (BIT6 | BIT7)) == 0) {\r
48555339
FT
542 break;\r
543 }\r
8c983d3e
FT
544\r
545 if ((HostCtrl2 & (BIT6 | BIT7)) == BIT7) {\r
546 return EFI_SUCCESS;\r
547 }\r
48555339
FT
548 } while (++Retry < 40);\r
549\r
e27ccaba 550 DEBUG ((DEBUG_ERROR, "EmmcTuningClkForHs200: Send tuning block fails at %d times with HostCtrl2 %02x\n", Retry, HostCtrl2));\r
8c983d3e
FT
551 //\r
552 // Abort the tuning procedure and reset the tuning circuit.\r
553 //\r
1436aea4
MK
554 HostCtrl2 = (UINT8) ~(BIT6 | BIT7);\r
555 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL2, sizeof (HostCtrl2), &HostCtrl2);\r
8c983d3e
FT
556 if (EFI_ERROR (Status)) {\r
557 return Status;\r
48555339 558 }\r
1436aea4 559\r
8c983d3e 560 return EFI_DEVICE_ERROR;\r
48555339
FT
561}\r
562\r
64362314
AM
563/**\r
564 Check the SWITCH operation status.\r
565\r
566 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
567 @param[in] Slot The slot number on which command should be sent.\r
568 @param[in] Rca The relative device address.\r
569\r
570 @retval EFI_SUCCESS The SWITCH finished siccessfully.\r
571 @retval others The SWITCH failed.\r
572**/\r
573EFI_STATUS\r
574EmmcCheckSwitchStatus (\r
575 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
576 IN UINT8 Slot,\r
577 IN UINT16 Rca\r
578 )\r
579{\r
580 EFI_STATUS Status;\r
581 UINT32 DevStatus;\r
582\r
583 Status = EmmcSendStatus (PassThru, Slot, Rca, &DevStatus);\r
584 if (EFI_ERROR (Status)) {\r
585 DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: Send status fails with %r\n", Status));\r
586 return Status;\r
587 }\r
588\r
589 //\r
590 // Check the switch operation is really successful or not.\r
591 //\r
592 if ((DevStatus & BIT7) != 0) {\r
593 DEBUG ((DEBUG_ERROR, "EmmcCheckSwitchStatus: The switch operation fails as DevStatus is 0x%08x\n", DevStatus));\r
594 return EFI_DEVICE_ERROR;\r
595 }\r
596\r
597 return EFI_SUCCESS;\r
598}\r
599\r
48555339
FT
600/**\r
601 Switch the bus width to specified width.\r
602\r
603 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.9 and SD Host Controller\r
604 Simplified Spec 3.0 Figure 3-7 for details.\r
605\r
606 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
607 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
608 @param[in] Slot The slot number of the SD card to send the command to.\r
609 @param[in] Rca The relative device address to be assigned.\r
610 @param[in] IsDdr If TRUE, use dual data rate data simpling method. Otherwise\r
611 use single data rate data simpling method.\r
612 @param[in] BusWidth The bus width to be set, it could be 4 or 8.\r
613\r
614 @retval EFI_SUCCESS The operation is done correctly.\r
615 @retval Others The operation fails.\r
616\r
617**/\r
618EFI_STATUS\r
619EmmcSwitchBusWidth (\r
1436aea4
MK
620 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
621 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
622 IN UINT8 Slot,\r
623 IN UINT16 Rca,\r
624 IN BOOLEAN IsDdr,\r
625 IN UINT8 BusWidth\r
48555339
FT
626 )\r
627{\r
1436aea4
MK
628 EFI_STATUS Status;\r
629 UINT8 Access;\r
630 UINT8 Index;\r
631 UINT8 Value;\r
632 UINT8 CmdSet;\r
48555339
FT
633\r
634 //\r
635 // Write Byte, the Value field is written into the byte pointed by Index.\r
636 //\r
637 Access = 0x03;\r
638 Index = OFFSET_OF (EMMC_EXT_CSD, BusWidth);\r
639 if (BusWidth == 4) {\r
640 Value = 1;\r
641 } else if (BusWidth == 8) {\r
642 Value = 2;\r
643 } else {\r
644 return EFI_INVALID_PARAMETER;\r
645 }\r
646\r
647 if (IsDdr) {\r
648 Value += 4;\r
649 }\r
650\r
651 CmdSet = 0;\r
652 Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
653 if (EFI_ERROR (Status)) {\r
e27ccaba 654 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusWidth: Switch to bus width %d fails with %r\n", BusWidth, Status));\r
48555339
FT
655 return Status;\r
656 }\r
657\r
64362314 658 Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
48555339 659 if (EFI_ERROR (Status)) {\r
48555339
FT
660 return Status;\r
661 }\r
48555339
FT
662\r
663 Status = SdMmcHcSetBusWidth (PciIo, Slot, BusWidth);\r
664\r
665 return Status;\r
666}\r
667\r
668/**\r
195f673f 669 Switch the bus timing and clock frequency.\r
48555339
FT
670\r
671 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6 and SD Host Controller\r
672 Simplified Spec 3.0 Figure 3-3 for details.\r
673\r
adec1f5d
AM
674 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
675 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
676 @param[in] Slot The slot number of the SD card to send the command to.\r
677 @param[in] Rca The relative device address to be assigned.\r
678 @param[in] DriverStrength Driver strength to set for speed modes that support it.\r
679 @param[in] BusTiming The bus mode timing indicator.\r
680 @param[in] ClockFreq The max clock frequency to be set, the unit is MHz.\r
48555339
FT
681\r
682 @retval EFI_SUCCESS The operation is done correctly.\r
683 @retval Others The operation fails.\r
684\r
685**/\r
686EFI_STATUS\r
195f673f 687EmmcSwitchBusTiming (\r
1436aea4
MK
688 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
689 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
690 IN UINT8 Slot,\r
691 IN UINT16 Rca,\r
692 IN EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength,\r
693 IN SD_MMC_BUS_MODE BusTiming,\r
694 IN UINT32 ClockFreq\r
48555339
FT
695 )\r
696{\r
1436aea4
MK
697 EFI_STATUS Status;\r
698 UINT8 Access;\r
699 UINT8 Index;\r
700 UINT8 Value;\r
701 UINT8 CmdSet;\r
702 SD_MMC_HC_PRIVATE_DATA *Private;\r
703 UINT8 HostCtrl1;\r
704 BOOLEAN DelaySendStatus;\r
48555339
FT
705\r
706 Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
707 //\r
708 // Write Byte, the Value field is written into the byte pointed by Index.\r
709 //\r
710 Access = 0x03;\r
711 Index = OFFSET_OF (EMMC_EXT_CSD, HsTiming);\r
48555339 712 CmdSet = 0;\r
adec1f5d
AM
713 switch (BusTiming) {\r
714 case SdMmcMmcHs400:\r
715 Value = (UINT8)((DriverStrength.Emmc << 4) | 3);\r
716 break;\r
717 case SdMmcMmcHs200:\r
718 Value = (UINT8)((DriverStrength.Emmc << 4) | 2);\r
719 break;\r
720 case SdMmcMmcHsSdr:\r
721 case SdMmcMmcHsDdr:\r
722 Value = 1;\r
723 break;\r
724 case SdMmcMmcLegacy:\r
725 Value = 0;\r
726 break;\r
727 default:\r
64362314 728 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Unsupported BusTiming(%d)\n", BusTiming));\r
adec1f5d
AM
729 return EFI_INVALID_PARAMETER;\r
730 }\r
48555339
FT
731\r
732 Status = EmmcSwitch (PassThru, Slot, Access, Index, Value, CmdSet);\r
733 if (EFI_ERROR (Status)) {\r
adec1f5d 734 DEBUG ((DEBUG_ERROR, "EmmcSwitchBusTiming: Switch to bus timing %d fails with %r\n", BusTiming, Status));\r
195f673f
AM
735 return Status;\r
736 }\r
737\r
1436aea4 738 if ((BusTiming == SdMmcMmcHsSdr) || (BusTiming == SdMmcMmcHsDdr)) {\r
a8c1fc70 739 HostCtrl1 = BIT2;\r
1436aea4 740 Status = SdMmcHcOrMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
a8c1fc70
AM
741 if (EFI_ERROR (Status)) {\r
742 return Status;\r
743 }\r
744 } else {\r
1436aea4
MK
745 HostCtrl1 = (UINT8) ~BIT2;\r
746 Status = SdMmcHcAndMmio (PciIo, Slot, SD_MMC_HC_HOST_CTRL1, sizeof (HostCtrl1), &HostCtrl1);\r
a8c1fc70
AM
747 if (EFI_ERROR (Status)) {\r
748 return Status;\r
749 }\r
750 }\r
751\r
752 Status = SdMmcHcUhsSignaling (Private->ControllerHandle, PciIo, Slot, BusTiming);\r
753 if (EFI_ERROR (Status)) {\r
754 return Status;\r
755 }\r
756\r
64362314
AM
757 //\r
758 // For cases when we switch bus timing to higher mode from current we want to\r
759 // send SEND_STATUS at current, lower, frequency then the target frequency to avoid\r
760 // stability issues. It has been observed that some designs are unable to process the\r
761 // SEND_STATUS at higher frequency during switch to HS200 @200MHz irrespective of the number of retries\r
762 // and only running the clock tuning is able to make them work at target frequency.\r
763 //\r
764 // For cases when we are downgrading the frequency and current high frequency is invalid\r
765 // we have to first change the frequency to target frequency and then send the SEND_STATUS.\r
766 //\r
767 if (Private->Slot[Slot].CurrentFreq < (ClockFreq * 1000)) {\r
768 Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
769 if (EFI_ERROR (Status)) {\r
770 return Status;\r
771 }\r
1436aea4 772\r
64362314
AM
773 DelaySendStatus = FALSE;\r
774 } else {\r
775 DelaySendStatus = TRUE;\r
776 }\r
777\r
195f673f
AM
778 //\r
779 // Convert the clock freq unit from MHz to KHz.\r
780 //\r
49accded 781 Status = SdMmcHcClockSupply (Private, Slot, BusTiming, FALSE, ClockFreq * 1000);\r
195f673f 782 if (EFI_ERROR (Status)) {\r
48555339
FT
783 return Status;\r
784 }\r
785\r
64362314
AM
786 if (DelaySendStatus) {\r
787 Status = EmmcCheckSwitchStatus (PassThru, Slot, Rca);\r
788 if (EFI_ERROR (Status)) {\r
789 return Status;\r
790 }\r
48555339 791 }\r
b7b803a6 792\r
48555339
FT
793 return Status;\r
794}\r
795\r
796/**\r
797 Switch to the High Speed timing according to request.\r
798\r
799 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
800 Simplified Spec 3.0 Figure 2-29 for details.\r
801\r
802 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
803 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
804 @param[in] Slot The slot number of the SD card to send the command to.\r
805 @param[in] Rca The relative device address to be assigned.\r
adec1f5d 806 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
807\r
808 @retval EFI_SUCCESS The operation is done correctly.\r
809 @retval Others The operation fails.\r
810\r
811**/\r
812EFI_STATUS\r
813EmmcSwitchToHighSpeed (\r
1436aea4
MK
814 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
815 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
816 IN UINT8 Slot,\r
817 IN UINT16 Rca,\r
818 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
819 )\r
820{\r
a8c1fc70
AM
821 EFI_STATUS Status;\r
822 BOOLEAN IsDdr;\r
48555339 823\r
1436aea4
MK
824 if (((BusMode->BusTiming != SdMmcMmcHsSdr) && (BusMode->BusTiming != SdMmcMmcHsDdr) && (BusMode->BusTiming != SdMmcMmcLegacy)) ||\r
825 (BusMode->ClockFreq > 52))\r
826 {\r
adec1f5d
AM
827 return EFI_INVALID_PARAMETER;\r
828 }\r
829\r
830 if (BusMode->BusTiming == SdMmcMmcHsDdr) {\r
831 IsDdr = TRUE;\r
832 } else {\r
833 IsDdr = FALSE;\r
834 }\r
835\r
836 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, IsDdr, BusMode->BusWidth);\r
48555339
FT
837 if (EFI_ERROR (Status)) {\r
838 return Status;\r
839 }\r
adec1f5d 840\r
adec1f5d 841 return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
48555339
FT
842}\r
843\r
844/**\r
adec1f5d 845 Switch to the HS200 timing. This function assumes that eMMC bus is still in legacy mode.\r
48555339
FT
846\r
847 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
848 Simplified Spec 3.0 Figure 2-29 for details.\r
849\r
adec1f5d
AM
850 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
851 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
852 @param[in] Slot The slot number of the SD card to send the command to.\r
853 @param[in] Rca The relative device address to be assigned.\r
854 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
855\r
856 @retval EFI_SUCCESS The operation is done correctly.\r
857 @retval Others The operation fails.\r
858\r
859**/\r
860EFI_STATUS\r
861EmmcSwitchToHS200 (\r
1436aea4
MK
862 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
863 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
864 IN UINT8 Slot,\r
865 IN UINT16 Rca,\r
866 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
867 )\r
868{\r
a8c1fc70 869 EFI_STATUS Status;\r
48555339 870\r
1436aea4
MK
871 if ((BusMode->BusTiming != SdMmcMmcHs200) ||\r
872 ((BusMode->BusWidth != 4) && (BusMode->BusWidth != 8)))\r
873 {\r
48555339
FT
874 return EFI_INVALID_PARAMETER;\r
875 }\r
876\r
adec1f5d 877 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, FALSE, BusMode->BusWidth);\r
48555339
FT
878 if (EFI_ERROR (Status)) {\r
879 return Status;\r
880 }\r
a4708009 881\r
adec1f5d 882 Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
48555339
FT
883 if (EFI_ERROR (Status)) {\r
884 return Status;\r
885 }\r
886\r
adec1f5d 887 Status = EmmcTuningClkForHs200 (PciIo, PassThru, Slot, BusMode->BusWidth);\r
48555339
FT
888\r
889 return Status;\r
890}\r
891\r
892/**\r
adec1f5d 893 Switch to the HS400 timing. This function assumes that eMMC bus is still in legacy mode.\r
48555339
FT
894\r
895 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
896 Simplified Spec 3.0 Figure 2-29 for details.\r
897\r
adec1f5d
AM
898 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
899 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
900 @param[in] Slot The slot number of the SD card to send the command to.\r
901 @param[in] Rca The relative device address to be assigned.\r
902 @param[in] BusMode Pointer to SD_MMC_BUS_SETTINGS structure containing bus settings.\r
48555339
FT
903\r
904 @retval EFI_SUCCESS The operation is done correctly.\r
905 @retval Others The operation fails.\r
906\r
907**/\r
908EFI_STATUS\r
909EmmcSwitchToHS400 (\r
1436aea4
MK
910 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
911 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
912 IN UINT8 Slot,\r
913 IN UINT16 Rca,\r
914 IN SD_MMC_BUS_SETTINGS *BusMode\r
48555339
FT
915 )\r
916{\r
a8c1fc70
AM
917 EFI_STATUS Status;\r
918 SD_MMC_BUS_SETTINGS Hs200BusMode;\r
919 UINT32 HsFreq;\r
adec1f5d 920\r
1436aea4
MK
921 if ((BusMode->BusTiming != SdMmcMmcHs400) ||\r
922 (BusMode->BusWidth != 8))\r
923 {\r
adec1f5d
AM
924 return EFI_INVALID_PARAMETER;\r
925 }\r
a4708009 926\r
1436aea4
MK
927 Hs200BusMode.BusTiming = SdMmcMmcHs200;\r
928 Hs200BusMode.BusWidth = BusMode->BusWidth;\r
929 Hs200BusMode.ClockFreq = BusMode->ClockFreq;\r
adec1f5d 930 Hs200BusMode.DriverStrength = BusMode->DriverStrength;\r
48555339 931\r
adec1f5d 932 Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &Hs200BusMode);\r
48555339
FT
933 if (EFI_ERROR (Status)) {\r
934 return Status;\r
935 }\r
adec1f5d 936\r
48555339 937 //\r
adec1f5d
AM
938 // Set to High Speed timing and set the clock frequency to a value less than or equal to 52MHz.\r
939 // This step is necessary to be able to switch Bus into 8 bit DDR mode which is unsupported in HS200.\r
48555339 940 //\r
adec1f5d
AM
941 HsFreq = BusMode->ClockFreq < 52 ? BusMode->ClockFreq : 52;\r
942 Status = EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, SdMmcMmcHsSdr, HsFreq);\r
48555339
FT
943 if (EFI_ERROR (Status)) {\r
944 return Status;\r
945 }\r
a4708009 946\r
adec1f5d
AM
947 Status = EmmcSwitchBusWidth (PciIo, PassThru, Slot, Rca, TRUE, BusMode->BusWidth);\r
948 if (EFI_ERROR (Status)) {\r
949 return Status;\r
950 }\r
a4708009 951\r
adec1f5d
AM
952 return EmmcSwitchBusTiming (PciIo, PassThru, Slot, Rca, BusMode->DriverStrength, BusMode->BusTiming, BusMode->ClockFreq);\r
953}\r
48555339 954\r
adec1f5d
AM
955/**\r
956 Check if passed BusTiming is supported in both controller and card.\r
957\r
958 @param[in] Private Pointer to controller private data\r
959 @param[in] SlotIndex Index of the slot in the controller\r
960 @param[in] ExtCsd Pointer to the card's extended CSD\r
961 @param[in] BusTiming Bus timing to check\r
962\r
963 @retval TRUE Both card and controller support given BusTiming\r
964 @retval FALSE Card or controller doesn't support given BusTiming\r
965**/\r
966BOOLEAN\r
967EmmcIsBusTimingSupported (\r
968 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
969 IN UINT8 SlotIndex,\r
970 IN EMMC_EXT_CSD *ExtCsd,\r
971 IN SD_MMC_BUS_MODE BusTiming\r
972 )\r
973{\r
974 BOOLEAN Supported;\r
975 SD_MMC_HC_SLOT_CAP *Capabilities;\r
976\r
977 Capabilities = &Private->Capability[SlotIndex];\r
978\r
979 Supported = FALSE;\r
980 switch (BusTiming) {\r
981 case SdMmcMmcHs400:\r
1436aea4 982 if ((((ExtCsd->DeviceType & (BIT6 | BIT7)) != 0) && (Capabilities->Hs400 != 0)) && (Capabilities->BusWidth8 != 0)) {\r
adec1f5d
AM
983 Supported = TRUE;\r
984 }\r
1436aea4 985\r
adec1f5d
AM
986 break;\r
987 case SdMmcMmcHs200:\r
988 if ((((ExtCsd->DeviceType & (BIT4 | BIT5)) != 0) && (Capabilities->Sdr104 != 0))) {\r
989 Supported = TRUE;\r
990 }\r
1436aea4 991\r
adec1f5d
AM
992 break;\r
993 case SdMmcMmcHsDdr:\r
994 if ((((ExtCsd->DeviceType & (BIT2 | BIT3)) != 0) && (Capabilities->Ddr50 != 0))) {\r
995 Supported = TRUE;\r
996 }\r
1436aea4 997\r
adec1f5d
AM
998 break;\r
999 case SdMmcMmcHsSdr:\r
1000 if ((((ExtCsd->DeviceType & BIT1) != 0) && (Capabilities->HighSpeed != 0))) {\r
1001 Supported = TRUE;\r
1002 }\r
1436aea4 1003\r
adec1f5d
AM
1004 break;\r
1005 case SdMmcMmcLegacy:\r
1006 if ((ExtCsd->DeviceType & BIT0) != 0) {\r
1007 Supported = TRUE;\r
1008 }\r
1436aea4 1009\r
adec1f5d
AM
1010 break;\r
1011 default:\r
1012 ASSERT (FALSE);\r
1013 }\r
1014\r
1015 return Supported;\r
1016}\r
1017\r
1018/**\r
1019 Get the target bus timing to set on the link. This function\r
1020 will try to select highest bus timing supported by card, controller\r
1021 and the driver.\r
1022\r
1023 @param[in] Private Pointer to controller private data\r
1024 @param[in] SlotIndex Index of the slot in the controller\r
1025 @param[in] ExtCsd Pointer to the card's extended CSD\r
1026\r
1027 @return Bus timing value that should be set on link\r
1028**/\r
1029SD_MMC_BUS_MODE\r
1030EmmcGetTargetBusTiming (\r
1031 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1436aea4
MK
1032 IN UINT8 SlotIndex,\r
1033 IN EMMC_EXT_CSD *ExtCsd\r
adec1f5d
AM
1034 )\r
1035{\r
1036 SD_MMC_BUS_MODE BusTiming;\r
1037\r
1038 //\r
1039 // We start with highest bus timing that this driver currently supports and\r
1040 // return as soon as we find supported timing.\r
1041 //\r
1042 BusTiming = SdMmcMmcHs400;\r
1043 while (BusTiming > SdMmcMmcLegacy) {\r
1044 if (EmmcIsBusTimingSupported (Private, SlotIndex, ExtCsd, BusTiming)) {\r
1045 break;\r
1046 }\r
1436aea4 1047\r
adec1f5d
AM
1048 BusTiming--;\r
1049 }\r
1050\r
1051 return BusTiming;\r
1052}\r
1053\r
1054/**\r
1055 Check if the passed bus width is supported by controller and card.\r
1056\r
1057 @param[in] Private Pointer to controller private data\r
1058 @param[in] SlotIndex Index of the slot in the controller\r
1059 @param[in] BusTiming Bus timing set on the link\r
1060 @param[in] BusWidth Bus width to check\r
1061\r
1062 @retval TRUE Passed bus width is supported in current bus configuration\r
1063 @retval FALSE Passed bus width is not supported in current bus configuration\r
1064**/\r
1065BOOLEAN\r
1066EmmcIsBusWidthSupported (\r
1436aea4
MK
1067 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1068 IN UINT8 SlotIndex,\r
1069 IN SD_MMC_BUS_MODE BusTiming,\r
1070 IN UINT16 BusWidth\r
adec1f5d
AM
1071 )\r
1072{\r
1436aea4 1073 if ((BusWidth == 8) && (Private->Capability[SlotIndex].BusWidth8 != 0)) {\r
adec1f5d 1074 return TRUE;\r
1436aea4 1075 } else if ((BusWidth == 4) && (BusTiming != SdMmcMmcHs400)) {\r
adec1f5d 1076 return TRUE;\r
1436aea4 1077 } else if ((BusWidth == 1) && ((BusTiming == SdMmcMmcHsSdr) || (BusTiming == SdMmcMmcLegacy))) {\r
adec1f5d
AM
1078 return TRUE;\r
1079 }\r
1080\r
1081 return FALSE;\r
1082}\r
1083\r
1084/**\r
1085 Get the target bus width to be set on the bus.\r
1086\r
1087 @param[in] Private Pointer to controller private data\r
1088 @param[in] SlotIndex Index of the slot in the controller\r
1089 @param[in] ExtCsd Pointer to card's extended CSD\r
1090 @param[in] BusTiming Bus timing set on the bus\r
1091\r
1092 @return Bus width to be set on the bus\r
1093**/\r
1094UINT8\r
1095EmmcGetTargetBusWidth (\r
1436aea4
MK
1096 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1097 IN UINT8 SlotIndex,\r
1098 IN EMMC_EXT_CSD *ExtCsd,\r
1099 IN SD_MMC_BUS_MODE BusTiming\r
adec1f5d
AM
1100 )\r
1101{\r
1102 UINT8 BusWidth;\r
1103 UINT8 PreferredBusWidth;\r
1104\r
1105 PreferredBusWidth = Private->Slot[SlotIndex].OperatingParameters.BusWidth;\r
1106\r
1436aea4
MK
1107 if ((PreferredBusWidth != EDKII_SD_MMC_BUS_WIDTH_IGNORE) &&\r
1108 EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, PreferredBusWidth))\r
1109 {\r
adec1f5d
AM
1110 BusWidth = PreferredBusWidth;\r
1111 } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 8)) {\r
1112 BusWidth = 8;\r
1113 } else if (EmmcIsBusWidthSupported (Private, SlotIndex, BusTiming, 4)) {\r
1114 BusWidth = 4;\r
1115 } else {\r
1116 BusWidth = 1;\r
1117 }\r
1118\r
1119 return BusWidth;\r
1120}\r
1121\r
1122/**\r
1123 Get the target clock frequency to be set on the bus.\r
1124\r
1125 @param[in] Private Pointer to controller private data\r
1126 @param[in] SlotIndex Index of the slot in the controller\r
1127 @param[in] ExtCsd Pointer to card's extended CSD\r
1128 @param[in] BusTiming Bus timing to be set on the bus\r
1129\r
1130 @return Value of the clock frequency to be set on bus in MHz\r
1131**/\r
1132UINT32\r
1133EmmcGetTargetClockFreq (\r
1436aea4
MK
1134 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1135 IN UINT8 SlotIndex,\r
1136 IN EMMC_EXT_CSD *ExtCsd,\r
1137 IN SD_MMC_BUS_MODE BusTiming\r
adec1f5d
AM
1138 )\r
1139{\r
1436aea4
MK
1140 UINT32 PreferredClockFreq;\r
1141 UINT32 MaxClockFreq;\r
adec1f5d
AM
1142\r
1143 PreferredClockFreq = Private->Slot[SlotIndex].OperatingParameters.ClockFreq;\r
1144\r
1145 switch (BusTiming) {\r
1146 case SdMmcMmcHs400:\r
1147 case SdMmcMmcHs200:\r
1148 MaxClockFreq = 200;\r
1149 break;\r
1150 case SdMmcMmcHsSdr:\r
1151 case SdMmcMmcHsDdr:\r
1152 MaxClockFreq = 52;\r
1153 break;\r
1154 default:\r
1155 MaxClockFreq = 26;\r
1156 break;\r
1157 }\r
1158\r
1436aea4 1159 if ((PreferredClockFreq != EDKII_SD_MMC_CLOCK_FREQ_IGNORE) && (PreferredClockFreq < MaxClockFreq)) {\r
adec1f5d
AM
1160 return PreferredClockFreq;\r
1161 } else {\r
1162 return MaxClockFreq;\r
1163 }\r
1164}\r
1165\r
1166/**\r
1167 Get the driver strength to be set on bus.\r
1168\r
1169 @param[in] Private Pointer to controller private data\r
1170 @param[in] SlotIndex Index of the slot in the controller\r
1171 @param[in] ExtCsd Pointer to card's extended CSD\r
1172 @param[in] BusTiming Bus timing set on the bus\r
1173\r
1174 @return Value of the driver strength to be set on the bus\r
1175**/\r
1176EDKII_SD_MMC_DRIVER_STRENGTH\r
1177EmmcGetTargetDriverStrength (\r
1436aea4
MK
1178 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1179 IN UINT8 SlotIndex,\r
1180 IN EMMC_EXT_CSD *ExtCsd,\r
1181 IN SD_MMC_BUS_MODE BusTiming\r
adec1f5d
AM
1182 )\r
1183{\r
1184 EDKII_SD_MMC_DRIVER_STRENGTH PreferredDriverStrength;\r
1185 EDKII_SD_MMC_DRIVER_STRENGTH DriverStrength;\r
1186\r
1187 PreferredDriverStrength = Private->Slot[SlotIndex].OperatingParameters.DriverStrength;\r
1436aea4 1188 DriverStrength.Emmc = EmmcDriverStrengthType0;\r
adec1f5d 1189\r
1436aea4
MK
1190 if ((PreferredDriverStrength.Emmc != EDKII_SD_MMC_DRIVER_STRENGTH_IGNORE) &&\r
1191 (ExtCsd->DriverStrength & (BIT0 << PreferredDriverStrength.Emmc)))\r
1192 {\r
adec1f5d
AM
1193 DriverStrength.Emmc = PreferredDriverStrength.Emmc;\r
1194 }\r
1195\r
1196 return DriverStrength;\r
1197}\r
1198\r
1199/**\r
1200 Get the target settings for the bus mode.\r
1201\r
1202 @param[in] Private Pointer to controller private data\r
1203 @param[in] SlotIndex Index of the slot in the controller\r
1204 @param[in] ExtCsd Pointer to card's extended CSD\r
1205 @param[out] BusMode Target configuration of the bus\r
1206**/\r
1207VOID\r
1208EmmcGetTargetBusMode (\r
1209 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1210 IN UINT8 SlotIndex,\r
1211 IN EMMC_EXT_CSD *ExtCsd,\r
1212 OUT SD_MMC_BUS_SETTINGS *BusMode\r
1213 )\r
1214{\r
1436aea4
MK
1215 BusMode->BusTiming = EmmcGetTargetBusTiming (Private, SlotIndex, ExtCsd);\r
1216 BusMode->BusWidth = EmmcGetTargetBusWidth (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
1217 BusMode->ClockFreq = EmmcGetTargetClockFreq (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
adec1f5d 1218 BusMode->DriverStrength = EmmcGetTargetDriverStrength (Private, SlotIndex, ExtCsd, BusMode->BusTiming);\r
48555339
FT
1219}\r
1220\r
1221/**\r
1222 Switch the high speed timing according to request.\r
1223\r
1224 Refer to EMMC Electrical Standard Spec 5.1 Section 6.6.8 and SD Host Controller\r
1225 Simplified Spec 3.0 Figure 2-29 for details.\r
1226\r
1227 @param[in] PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.\r
1228 @param[in] PassThru A pointer to the EFI_SD_MMC_PASS_THRU_PROTOCOL instance.\r
1229 @param[in] Slot The slot number of the SD card to send the command to.\r
1230 @param[in] Rca The relative device address to be assigned.\r
1231\r
1232 @retval EFI_SUCCESS The operation is done correctly.\r
1233 @retval Others The operation fails.\r
1234\r
1235**/\r
1236EFI_STATUS\r
1237EmmcSetBusMode (\r
1436aea4
MK
1238 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
1239 IN EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru,\r
1240 IN UINT8 Slot,\r
1241 IN UINT16 Rca\r
48555339
FT
1242 )\r
1243{\r
1436aea4
MK
1244 EFI_STATUS Status;\r
1245 EMMC_CSD Csd;\r
1246 EMMC_EXT_CSD ExtCsd;\r
1247 SD_MMC_BUS_SETTINGS BusMode;\r
1248 SD_MMC_HC_PRIVATE_DATA *Private;\r
48555339
FT
1249\r
1250 Private = SD_MMC_HC_PRIVATE_FROM_THIS (PassThru);\r
1251\r
1252 Status = EmmcGetCsd (PassThru, Slot, Rca, &Csd);\r
1253 if (EFI_ERROR (Status)) {\r
e27ccaba 1254 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetCsd fails with %r\n", Status));\r
48555339
FT
1255 return Status;\r
1256 }\r
1257\r
1258 Status = EmmcSelect (PassThru, Slot, Rca);\r
1259 if (EFI_ERROR (Status)) {\r
e27ccaba 1260 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: Select fails with %r\n", Status));\r
48555339
FT
1261 return Status;\r
1262 }\r
1263\r
7f3b0bad 1264 ASSERT (Private->BaseClkFreq[Slot] != 0);\r
adec1f5d 1265\r
48555339 1266 //\r
adec1f5d 1267 // Get Device_Type from EXT_CSD register.\r
48555339
FT
1268 //\r
1269 Status = EmmcGetExtCsd (PassThru, Slot, &ExtCsd);\r
1270 if (EFI_ERROR (Status)) {\r
e27ccaba 1271 DEBUG ((DEBUG_ERROR, "EmmcSetBusMode: GetExtCsd fails with %r\n", Status));\r
48555339
FT
1272 return Status;\r
1273 }\r
48555339 1274\r
adec1f5d 1275 EmmcGetTargetBusMode (Private, Slot, &ExtCsd, &BusMode);\r
48555339 1276\r
1436aea4
MK
1277 DEBUG ((\r
1278 DEBUG_INFO,\r
1279 "EmmcSetBusMode: Target bus mode: timing = %d, width = %d, clock freq = %d, driver strength = %d\n",\r
1280 BusMode.BusTiming,\r
1281 BusMode.BusWidth,\r
1282 BusMode.ClockFreq,\r
1283 BusMode.DriverStrength.Emmc\r
1284 ));\r
48555339 1285\r
adec1f5d
AM
1286 if (BusMode.BusTiming == SdMmcMmcHs400) {\r
1287 Status = EmmcSwitchToHS400 (PciIo, PassThru, Slot, Rca, &BusMode);\r
1288 } else if (BusMode.BusTiming == SdMmcMmcHs200) {\r
1289 Status = EmmcSwitchToHS200 (PciIo, PassThru, Slot, Rca, &BusMode);\r
48555339 1290 } else {\r
76e1e563
AM
1291 //\r
1292 // Note that EmmcSwitchToHighSpeed is also called for SdMmcMmcLegacy\r
1293 // bus timing. This is because even though we might not want to\r
1294 // change the timing itself we still want to allow customization of\r
1295 // bus parameters such as clock frequency and bus width.\r
1296 //\r
adec1f5d 1297 Status = EmmcSwitchToHighSpeed (PciIo, PassThru, Slot, Rca, &BusMode);\r
48555339
FT
1298 }\r
1299\r
adec1f5d 1300 DEBUG ((DEBUG_INFO, "EmmcSetBusMode: Switch to %a %r\n", (BusMode.BusTiming == SdMmcMmcHs400) ? "HS400" : ((BusMode.BusTiming == SdMmcMmcHs200) ? "HS200" : "HighSpeed"), Status));\r
48555339
FT
1301\r
1302 return Status;\r
1303}\r
1304\r
1305/**\r
1306 Execute EMMC device identification procedure.\r
1307\r
1308 Refer to EMMC Electrical Standard Spec 5.1 Section 6.4 for details.\r
1309\r
1310 @param[in] Private A pointer to the SD_MMC_HC_PRIVATE_DATA instance.\r
1311 @param[in] Slot The slot number of the SD card to send the command to.\r
1312\r
1313 @retval EFI_SUCCESS There is a EMMC card.\r
1314 @retval Others There is not a EMMC card.\r
1315\r
1316**/\r
1317EFI_STATUS\r
1318EmmcIdentification (\r
1436aea4
MK
1319 IN SD_MMC_HC_PRIVATE_DATA *Private,\r
1320 IN UINT8 Slot\r
48555339
FT
1321 )\r
1322{\r
1323 EFI_STATUS Status;\r
1324 EFI_PCI_IO_PROTOCOL *PciIo;\r
1325 EFI_SD_MMC_PASS_THRU_PROTOCOL *PassThru;\r
1326 UINT32 Ocr;\r
1327 UINT16 Rca;\r
ec86d285 1328 UINTN Retry;\r
48555339
FT
1329\r
1330 PciIo = Private->PciIo;\r
1331 PassThru = &Private->PassThru;\r
1332\r
1333 Status = EmmcReset (PassThru, Slot);\r
1334 if (EFI_ERROR (Status)) {\r
e27ccaba 1335 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd0 fails with %r\n", Status));\r
48555339
FT
1336 return Status;\r
1337 }\r
1338\r
ec86d285
FT
1339 Ocr = 0;\r
1340 Retry = 0;\r
48555339
FT
1341 do {\r
1342 Status = EmmcGetOcr (PassThru, Slot, &Ocr);\r
1343 if (EFI_ERROR (Status)) {\r
e27ccaba 1344 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails with %r\n", Status));\r
48555339
FT
1345 return Status;\r
1346 }\r
1436aea4 1347\r
48555339 1348 Ocr |= BIT30;\r
ec86d285
FT
1349\r
1350 if (Retry++ == 100) {\r
1351 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd1 fails too many times\n"));\r
1352 return EFI_DEVICE_ERROR;\r
1353 }\r
1436aea4
MK
1354\r
1355 gBS->Stall (10 * 1000);\r
48555339
FT
1356 } while ((Ocr & BIT31) == 0);\r
1357\r
1358 Status = EmmcGetAllCid (PassThru, Slot);\r
1359 if (EFI_ERROR (Status)) {\r
e27ccaba 1360 DEBUG ((DEBUG_VERBOSE, "EmmcIdentification: Executing Cmd2 fails with %r\n", Status));\r
48555339
FT
1361 return Status;\r
1362 }\r
1436aea4 1363\r
48555339
FT
1364 //\r
1365 // Slot starts from 0 and valid RCA starts from 1.\r
1366 // Here we takes a simple formula to calculate the RCA.\r
1367 // Don't support multiple devices on the slot, that is\r
1368 // shared bus slot feature.\r
1369 //\r
1370 Rca = Slot + 1;\r
1371 Status = EmmcSetRca (PassThru, Slot, Rca);\r
1372 if (EFI_ERROR (Status)) {\r
e27ccaba 1373 DEBUG ((DEBUG_ERROR, "EmmcIdentification: Executing Cmd3 fails with %r\n", Status));\r
48555339
FT
1374 return Status;\r
1375 }\r
1436aea4 1376\r
48555339
FT
1377 //\r
1378 // Enter Data Tranfer Mode.\r
1379 //\r
e27ccaba 1380 DEBUG ((DEBUG_INFO, "EmmcIdentification: Found a EMMC device at slot [%d], RCA [%d]\n", Slot, Rca));\r
48555339
FT
1381 Private->Slot[Slot].CardType = EmmcCardType;\r
1382\r
1383 Status = EmmcSetBusMode (PciIo, PassThru, Slot, Rca);\r
1384\r
1385 return Status;\r
1386}\r