EmbeddedPkg/MmcDxe: invoke SetIos() protocol method to set speed and width
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / MmcIdentification.c
CommitLineData
b4fdedc2
OM
1/** @file\r
2*\r
eff98cf9 3* Copyright (c) 2011-2015, ARM Limited. All rights reserved.\r
b4fdedc2
OM
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
b4fdedc2
OM
15#include "Mmc.h"\r
16\r
17typedef union {\r
18 UINT32 Raw;\r
19 OCR Ocr;\r
20} OCR_RESPONSE;\r
21\r
22#define MAX_RETRY_COUNT 1000\r
23#define CMD_RETRY_COUNT 20\r
24#define RCA_SHIFT_OFFSET 16\r
25#define EMMC_CARD_SIZE 512\r
26#define EMMC_ECSD_SIZE_OFFSET 53\r
27\r
752ae805
HZ
28#define EXTCSD_BUS_WIDTH 183\r
29#define EXTCSD_HS_TIMING 185\r
30\r
31#define EMMC_TIMING_BACKWARD 0\r
32#define EMMC_TIMING_HS 1\r
33#define EMMC_TIMING_HS200 2\r
34#define EMMC_TIMING_HS400 3\r
35\r
36#define EMMC_BUS_WIDTH_1BIT 0\r
37#define EMMC_BUS_WIDTH_4BIT 1\r
38#define EMMC_BUS_WIDTH_8BIT 2\r
39#define EMMC_BUS_WIDTH_DDR_4BIT 5\r
40#define EMMC_BUS_WIDTH_DDR_8BIT 6\r
41\r
42#define EMMC_SWITCH_ERROR (1 << 7)\r
43\r
44#define DEVICE_STATE(x) (((x) >> 9) & 0xf)\r
45typedef enum _EMMC_DEVICE_STATE {\r
46 EMMC_IDLE_STATE = 0,\r
47 EMMC_READY_STATE,\r
48 EMMC_IDENT_STATE,\r
49 EMMC_STBY_STATE,\r
50 EMMC_TRAN_STATE,\r
51 EMMC_DATA_STATE,\r
52 EMMC_RCV_STATE,\r
53 EMMC_PRG_STATE,\r
54 EMMC_DIS_STATE,\r
55 EMMC_BTST_STATE,\r
56 EMMC_SLP_STATE\r
57} EMMC_DEVICE_STATE;\r
58\r
b4fdedc2
OM
59UINT32 mEmmcRcaCount = 0;\r
60\r
752ae805
HZ
61STATIC\r
62EFI_STATUS\r
63EFIAPI\r
64EmmcGetDeviceState (\r
65 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
66 OUT EMMC_DEVICE_STATE *State\r
67 )\r
68{\r
69 EFI_MMC_HOST_PROTOCOL *Host;\r
70 EFI_STATUS Status;\r
71 UINT32 Data, RCA;\r
72\r
73 if (State == NULL) {\r
74 return EFI_INVALID_PARAMETER;\r
75 }\r
76\r
77 Host = MmcHostInstance->MmcHost;\r
78 RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;\r
79 Status = Host->SendCommand (Host, MMC_CMD13, RCA);\r
80 if (EFI_ERROR (Status)) {\r
81 DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get card status, Status=%r.\n", Status));\r
82 return Status;\r
83 }\r
84 Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R1, &Data);\r
85 if (EFI_ERROR (Status)) {\r
86 DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to get response of CMD13, Status=%r.\n", Status));\r
87 return Status;\r
88 }\r
89 if (Data & EMMC_SWITCH_ERROR) {\r
90 DEBUG ((EFI_D_ERROR, "EmmcGetDeviceState(): Failed to switch expected mode, Status=%r.\n", Status));\r
91 return EFI_DEVICE_ERROR;\r
92 }\r
93 *State = DEVICE_STATE(Data);\r
94 return EFI_SUCCESS;\r
95}\r
96\r
97STATIC\r
98EFI_STATUS\r
99EFIAPI\r
100EmmcSetEXTCSD (\r
101 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
102 UINT32 ExtCmdIndex,\r
103 UINT32 Value\r
104 )\r
105{\r
106 EFI_MMC_HOST_PROTOCOL *Host;\r
107 EMMC_DEVICE_STATE State;\r
108 EFI_STATUS Status;\r
109 UINT32 Argument;\r
110\r
111 Host = MmcHostInstance->MmcHost;\r
112 Argument = EMMC_CMD6_ARG_ACCESS(3) | EMMC_CMD6_ARG_INDEX(ExtCmdIndex) |\r
113 EMMC_CMD6_ARG_VALUE(Value) | EMMC_CMD6_ARG_CMD_SET(1);\r
114 Status = Host->SendCommand (Host, MMC_CMD6, Argument);\r
115 if (EFI_ERROR (Status)) {\r
116 DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to send CMD6, Status=%r.\n", Status));\r
117 return Status;\r
118 }\r
119 // Make sure device exiting prog mode\r
120 do {\r
121 Status = EmmcGetDeviceState (MmcHostInstance, &State);\r
122 if (EFI_ERROR (Status)) {\r
123 DEBUG ((EFI_D_ERROR, "EmmcSetEXTCSD(): Failed to get device state, Status=%r.\n", Status));\r
124 return Status;\r
125 }\r
126 } while (State == EMMC_PRG_STATE);\r
127 return EFI_SUCCESS;\r
128}\r
129\r
b4fdedc2
OM
130STATIC\r
131EFI_STATUS\r
132EFIAPI\r
133EmmcIdentificationMode (\r
134 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
135 IN OCR_RESPONSE Response\r
136 )\r
137{\r
138 EFI_MMC_HOST_PROTOCOL *Host;\r
139 EFI_BLOCK_IO_MEDIA *Media;\r
140 EFI_STATUS Status;\r
752ae805 141 EMMC_DEVICE_STATE State;\r
b4fdedc2 142 UINT32 RCA;\r
b4fdedc2
OM
143\r
144 Host = MmcHostInstance->MmcHost;\r
145 Media = MmcHostInstance->BlockIo.Media;\r
146\r
147 // Fetch card identity register\r
148 Status = Host->SendCommand (Host, MMC_CMD2, 0);\r
149 if (EFI_ERROR (Status)) {\r
150 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));\r
151 return Status;\r
152 }\r
153\r
154 Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));\r
155 if (EFI_ERROR (Status)) {\r
156 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));\r
157 return Status;\r
158 }\r
159\r
160 // Assign a relative address value to the card\r
161 MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this\r
162 RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;\r
163 Status = Host->SendCommand (Host, MMC_CMD3, RCA);\r
164 if (EFI_ERROR (Status)) {\r
165 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));\r
166 return Status;\r
167 }\r
168\r
169 // Fetch card specific data\r
170 Status = Host->SendCommand (Host, MMC_CMD9, RCA);\r
171 if (EFI_ERROR (Status)) {\r
172 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));\r
173 return Status;\r
174 }\r
175\r
176 Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));\r
177 if (EFI_ERROR (Status)) {\r
178 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));\r
179 return Status;\r
180 }\r
181\r
182 // Select the card\r
183 Status = Host->SendCommand (Host, MMC_CMD7, RCA);\r
184 if (EFI_ERROR (Status)) {\r
185 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));\r
186 }\r
187\r
752ae805
HZ
188 if (MMC_HOST_HAS_SETIOS(Host)) {\r
189 // Set 1-bit bus width\r
190 Status = Host->SetIos (Host, 0, 1, EMMCBACKWARD);\r
191 if (EFI_ERROR (Status)) {\r
192 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set 1-bit bus width error, Status=%r.\n", Status));\r
193 return Status;\r
194 }\r
195\r
196 // Set 1-bit bus width for EXTCSD\r
197 Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_1BIT);\r
198 if (EFI_ERROR (Status)) {\r
199 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Set extcsd bus width error, Status=%r.\n", Status));\r
200 return Status;\r
201 }\r
202 }\r
203\r
b4fdedc2
OM
204 // Fetch ECSD\r
205 Status = Host->SendCommand (Host, MMC_CMD8, RCA);\r
206 if (EFI_ERROR (Status)) {\r
207 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));\r
208 }\r
209\r
e88fcb47 210 Status = Host->ReadBlockData (Host, 0, 512, (UINT32 *)&(MmcHostInstance->CardInfo.ECSDData));\r
b4fdedc2
OM
211 if (EFI_ERROR (Status)) {\r
212 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));\r
213 return Status;\r
214 }\r
215\r
752ae805
HZ
216 // Make sure device exiting data mode\r
217 do {\r
218 Status = EmmcGetDeviceState (MmcHostInstance, &State);\r
219 if (EFI_ERROR (Status)) {\r
220 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to get device state, Status=%r.\n", Status));\r
221 return Status;\r
222 }\r
223 } while (State == EMMC_DATA_STATE);\r
224\r
b4fdedc2
OM
225 // Set up media\r
226 Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards\r
227 Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;\r
228 Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;\r
229 Media->LogicalBlocksPerPhysicalBlock = 1;\r
230 Media->IoAlign = 4;\r
231 // Compute last block using bits [215:212] of the ECSD\r
e88fcb47 232 Media->LastBlock = MmcHostInstance->CardInfo.ECSDData.SECTOR_COUNT - 1; // eMMC isn't supposed to report this for\r
b4fdedc2
OM
233 // Cards <2GB in size, but the model does.\r
234\r
235 // Setup card type\r
236 MmcHostInstance->CardInfo.CardType = EMMC_CARD;\r
237 return EFI_SUCCESS;\r
238}\r
239\r
752ae805
HZ
240STATIC\r
241EFI_STATUS\r
242InitializeEmmcDevice (\r
243 IN MMC_HOST_INSTANCE *MmcHostInstance\r
244 )\r
245{\r
246 EFI_MMC_HOST_PROTOCOL *Host;\r
247 EFI_STATUS Status = EFI_SUCCESS;\r
248 ECSD *ECSDData;\r
249 UINT32 BusClockFreq, Idx;\r
250 UINT32 TimingMode[4] = {EMMCHS52DDR1V2, EMMCHS52DDR1V8, EMMCHS52, EMMCHS26};\r
251\r
252 Host = MmcHostInstance->MmcHost;\r
253 ECSDData = &MmcHostInstance->CardInfo.ECSDData;\r
254 if (ECSDData->DEVICE_TYPE == EMMCBACKWARD)\r
255 return EFI_SUCCESS;\r
256\r
257 if (!MMC_HOST_HAS_SETIOS(Host)) {\r
258 return EFI_SUCCESS;\r
259 }\r
260 Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_HS_TIMING, EMMC_TIMING_HS);\r
261 if (EFI_ERROR (Status)) {\r
262 DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to switch high speed mode, Status:%r.\n", Status));\r
263 return Status;\r
264 }\r
265\r
266 for (Idx = 0; Idx < 4; Idx++) {\r
267 switch (TimingMode[Idx]) {\r
268 case EMMCHS52DDR1V2:\r
269 case EMMCHS52DDR1V8:\r
270 case EMMCHS52:\r
271 BusClockFreq = 52000000;\r
272 break;\r
273 case EMMCHS26:\r
274 BusClockFreq = 26000000;\r
275 break;\r
276 default:\r
277 return EFI_UNSUPPORTED;\r
278 }\r
279 Status = Host->SetIos (Host, BusClockFreq, 8, TimingMode[Idx]);\r
280 if (!EFI_ERROR (Status)) {\r
281 Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT);\r
282 if (EFI_ERROR (Status)) {\r
283 DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status));\r
284 }\r
285 return Status;\r
286 }\r
287 }\r
288 return Status;\r
289}\r
290\r
b4fdedc2
OM
291STATIC\r
292EFI_STATUS\r
293InitializeSdMmcDevice (\r
294 IN MMC_HOST_INSTANCE *MmcHostInstance\r
295 )\r
296{\r
297 UINT32 CmdArg;\r
298 UINT32 Response[4];\r
299 UINTN BlockSize;\r
300 UINTN CardSize;\r
301 UINTN NumBlocks;\r
302 EFI_STATUS Status;\r
303 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
304\r
305 MmcHost = MmcHostInstance->MmcHost;\r
306\r
307 // Send a command to get Card specific data\r
308 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
309 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
310 if (EFI_ERROR (Status)) {\r
311 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
312 return Status;\r
313 }\r
314\r
315 // Read Response\r
316 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
317 if (EFI_ERROR (Status)) {\r
318 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));\r
319 return Status;\r
320 }\r
321 PrintCSD (Response);\r
322\r
323 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
324 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
325 NumBlocks = ((CardSize + 1) * 1024);\r
326 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
327 } else {\r
328 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
329 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
330 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
331 }\r
332\r
333 // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
334 if (BlockSize > 512) {\r
335 NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);\r
336 BlockSize = 512;\r
337 }\r
338\r
339 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
340 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
341 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
342 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
343 MmcHostInstance->BlockIo.Media->MediaId++;\r
344\r
345 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
346 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
347 if (EFI_ERROR (Status)) {\r
348 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
349 return Status;\r
350 }\r
351\r
352 return EFI_SUCCESS;\r
353}\r
354\r
355STATIC\r
356EFI_STATUS\r
357EFIAPI\r
358MmcIdentificationMode (\r
359 IN MMC_HOST_INSTANCE *MmcHostInstance\r
360 )\r
361{\r
362 EFI_STATUS Status;\r
363 UINT32 Response[4];\r
364 UINTN Timeout;\r
365 UINTN CmdArg;\r
366 BOOLEAN IsHCS;\r
367 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
368 OCR_RESPONSE OcrResponse;\r
369\r
370 MmcHost = MmcHostInstance->MmcHost;\r
371 CmdArg = 0;\r
372 IsHCS = FALSE;\r
373\r
374 if (MmcHost == NULL) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377\r
378 // We can get into this function if we restart the identification mode\r
379 if (MmcHostInstance->State == MmcHwInitializationState) {\r
380 // Initialize the MMC Host HW\r
381 Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
382 if (EFI_ERROR (Status)) {\r
383 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));\r
384 return Status;\r
385 }\r
386 }\r
387\r
388 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
389 if (EFI_ERROR (Status)) {\r
390 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));\r
391 return Status;\r
392 }\r
393 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
394 if (EFI_ERROR (Status)) {\r
395 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));\r
396 return Status;\r
397 }\r
398\r
139b5773
OM
399 // Send CMD1 to get OCR (MMC)\r
400 // This command only valid for MMC and eMMC\r
32010753
HZ
401 Timeout = MAX_RETRY_COUNT;\r
402 do {\r
403 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);\r
404 if (EFI_ERROR (Status))\r
405 break;\r
b4fdedc2
OM
406 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);\r
407 if (EFI_ERROR (Status)) {\r
408 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
409 return Status;\r
410 }\r
32010753
HZ
411 Timeout--;\r
412 } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0));\r
413 if (Status == EFI_SUCCESS) {\r
b4fdedc2
OM
414 if (!OcrResponse.Ocr.PowerUp) {\r
415 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));\r
416 return EFI_DEVICE_ERROR;\r
417 }\r
418 OcrResponse.Ocr.PowerUp = 0;\r
419 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {\r
420 MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;\r
421 }\r
422 else {\r
423 MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;\r
424 }\r
139b5773 425 // Check whether MMC or eMMC\r
b4fdedc2
OM
426 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||\r
427 OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {\r
428 return EmmcIdentificationMode (MmcHostInstance, OcrResponse);\r
429 }\r
b4fdedc2
OM
430 }\r
431\r
432 // Are we using SDIO ?\r
433 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
434 if (Status == EFI_SUCCESS) {\r
435 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));\r
436 return EFI_UNSUPPORTED;\r
437 }\r
438\r
439 // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
440 CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
441 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
442 if (Status == EFI_SUCCESS) {\r
443 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
444 IsHCS = TRUE;\r
445 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
446 if (EFI_ERROR (Status)) {\r
447 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));\r
448 return Status;\r
449 }\r
450 PrintResponseR1 (Response[0]);\r
451 // Check if it is valid response\r
452 if (Response[0] != CmdArg) {\r
453 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
454 return EFI_UNSUPPORTED;\r
455 }\r
456 } else {\r
457 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
458 }\r
459\r
460 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
461 Timeout = MAX_RETRY_COUNT;\r
462 while (Timeout > 0) {\r
463 // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
464 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
465 if (Status == EFI_SUCCESS) {\r
466 DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
467 if (IsHCS) {\r
468 MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
469 } else {\r
470 MmcHostInstance->CardInfo.CardType = SD_CARD;\r
471 }\r
472\r
473 // Note: The first time CmdArg will be zero\r
474 CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
475 if (IsHCS) {\r
476 CmdArg |= BIT30;\r
477 }\r
478 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
479 if (!EFI_ERROR (Status)) {\r
480 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
481 if (EFI_ERROR (Status)) {\r
482 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
483 return Status;\r
484 }\r
485 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
486 }\r
487 } else {\r
488 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
489 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
490\r
491 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
492 if (!EFI_ERROR (Status)) {\r
493 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
494 if (EFI_ERROR (Status)) {\r
495 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
496 return Status;\r
497 }\r
498 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
499 }\r
500 }\r
501\r
502 if (!EFI_ERROR (Status)) {\r
503 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
eff98cf9 504 gBS->Stall (1);\r
b4fdedc2
OM
505 Timeout--;\r
506 } else {\r
507 if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
508 MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
509 DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
510 }\r
511 break; // The MMC/SD card is ready. Continue the Identification Mode\r
512 }\r
513 } else {\r
eff98cf9 514 gBS->Stall (1);\r
b4fdedc2
OM
515 Timeout--;\r
516 }\r
517 }\r
518\r
519 if (Timeout == 0) {\r
520 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
521 return EFI_NO_MEDIA;\r
522 } else {\r
523 PrintOCR (Response[0]);\r
524 }\r
525\r
526 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
527 if (EFI_ERROR (Status)) {\r
528 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
529 return Status;\r
530 }\r
531\r
532 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
533 if (EFI_ERROR (Status)) {\r
534 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
535 return Status;\r
536 }\r
537 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
538 if (EFI_ERROR (Status)) {\r
539 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));\r
540 return Status;\r
541 }\r
542\r
543 PrintCID (Response);\r
544\r
545 Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);\r
546 if (EFI_ERROR (Status)) {\r
547 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
548 return Status;\r
549 }\r
550\r
551 //\r
552 // Note, SD specifications say that "if the command execution causes a state change, it\r
553 // will be visible to the host in the response to the next command"\r
554 // The status returned for this CMD3 will be 2 - identification\r
555 //\r
556 CmdArg = 1;\r
557 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
558 if (EFI_ERROR (Status)) {\r
559 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
560 return Status;\r
561 }\r
562\r
563 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
564 if (EFI_ERROR (Status)) {\r
565 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));\r
566 return Status;\r
567 }\r
568 PrintRCA (Response[0]);\r
569\r
570 // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
571 if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
572 MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
573 } else {\r
574 MmcHostInstance->CardInfo.RCA = CmdArg;\r
575 }\r
576 Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
577 if (EFI_ERROR (Status)) {\r
578 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
579 return Status;\r
580 }\r
581\r
582 return EFI_SUCCESS;\r
583}\r
584\r
585EFI_STATUS\r
586InitializeMmcDevice (\r
587 IN MMC_HOST_INSTANCE *MmcHostInstance\r
588 )\r
589{\r
590 EFI_STATUS Status;\r
591 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
592 UINTN BlockCount;\r
593\r
594 BlockCount = 1;\r
595 MmcHost = MmcHostInstance->MmcHost;\r
596\r
597 Status = MmcIdentificationMode (MmcHostInstance);\r
598 if (EFI_ERROR (Status)) {\r
599 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));\r
600 return Status;\r
601 }\r
602\r
603 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
604 if (EFI_ERROR (Status)) {\r
605 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));\r
606 return Status;\r
607 }\r
608\r
609 if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
610 Status = InitializeSdMmcDevice (MmcHostInstance);\r
752ae805
HZ
611 } else {\r
612 Status = InitializeEmmcDevice (MmcHostInstance);\r
613 }\r
614 if (EFI_ERROR (Status)) {\r
615 return Status;\r
b4fdedc2
OM
616 }\r
617\r
618 // Set Block Length\r
619 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
620 if (EFI_ERROR (Status)) {\r
621 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
622 MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
623 return Status;\r
624 }\r
625\r
626 // Block Count (not used). Could return an error for SD card\r
627 if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
628 Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
629 if (EFI_ERROR (Status)) {\r
630 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));\r
631 return Status;\r
632 }\r
633 }\r
634\r
635 return EFI_SUCCESS;\r
636}\r