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