]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
EmbeddedPkg/MmcDxe: set I/O speed and bus width in SD stack
[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
OM
212 // Fetch ECSD\r
213 Status = Host->SendCommand (Host, MMC_CMD8, RCA);\r
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
257 UINT32 BusClockFreq, Idx;\r
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
289 Status = EmmcSetEXTCSD (MmcHostInstance, EXTCSD_BUS_WIDTH, EMMC_BUS_WIDTH_DDR_8BIT);\r
290 if (EFI_ERROR (Status)) {\r
291 DEBUG ((DEBUG_ERROR, "InitializeEmmcDevice(): Failed to set EXTCSD bus width, Status:%r\n", Status));\r
292 }\r
293 return Status;\r
294 }\r
295 }\r
296 return Status;\r
297}\r
298\r
b4fdedc2
OM
299STATIC\r
300EFI_STATUS\r
301InitializeSdMmcDevice (\r
302 IN MMC_HOST_INSTANCE *MmcHostInstance\r
303 )\r
304{\r
305 UINT32 CmdArg;\r
306 UINT32 Response[4];\r
e06253ba 307 UINT32 Buffer[128];\r
b4fdedc2
OM
308 UINTN BlockSize;\r
309 UINTN CardSize;\r
310 UINTN NumBlocks;\r
e06253ba
HZ
311 BOOLEAN CccSwitch;\r
312 SCR Scr;\r
b4fdedc2
OM
313 EFI_STATUS Status;\r
314 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
315\r
316 MmcHost = MmcHostInstance->MmcHost;\r
317\r
318 // Send a command to get Card specific data\r
319 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
320 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
321 if (EFI_ERROR (Status)) {\r
322 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
323 return Status;\r
324 }\r
325\r
326 // Read Response\r
327 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
328 if (EFI_ERROR (Status)) {\r
329 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));\r
330 return Status;\r
331 }\r
332 PrintCSD (Response);\r
e06253ba
HZ
333 if (MMC_CSD_GET_CCC(Response) & SD_CCC_SWITCH) {\r
334 CccSwitch = TRUE;\r
335 } else {\r
336 CccSwitch = FALSE;\r
337 }\r
b4fdedc2
OM
338\r
339 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
340 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
341 NumBlocks = ((CardSize + 1) * 1024);\r
342 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
343 } else {\r
344 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
345 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
346 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
347 }\r
348\r
349 // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
350 if (BlockSize > 512) {\r
351 NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);\r
352 BlockSize = 512;\r
353 }\r
354\r
355 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
356 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
357 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
358 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
359 MmcHostInstance->BlockIo.Media->MediaId++;\r
360\r
361 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
362 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
363 if (EFI_ERROR (Status)) {\r
364 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
365 return Status;\r
366 }\r
367\r
e06253ba
HZ
368 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
369 if (EFI_ERROR (Status)) {\r
370 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
371 return Status;\r
372 }\r
373 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
374 if (EFI_ERROR (Status)) {\r
375 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
376 return Status;\r
377 }\r
378 if ((Response[0] & MMC_STATUS_APP_CMD) == 0) {\r
379 return EFI_SUCCESS;\r
380 }\r
381\r
382 /* SCR */\r
383 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD51, 0);\r
384 if (EFI_ERROR (Status)) {\r
385 DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): Error and Status = %r\n", __func__, Status));\r
386 return Status;\r
387 } else {\r
388 Status = MmcHost->ReadBlockData (MmcHost, 0, 8, Buffer);\r
389 if (EFI_ERROR (Status)) {\r
390 DEBUG ((EFI_D_ERROR, "%a(MMC_ACMD51): ReadBlockData Error and Status = %r\n", __func__, Status));\r
391 return Status;\r
392 }\r
393 CopyMem (&Scr, Buffer, 8);\r
394 if (Scr.SD_SPEC == 2) {\r
395 if (Scr.SD_SPEC3 == 1) {\r
396 if (Scr.SD_SPEC4 == 1) {\r
397 DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 4.xx\n"));\r
398 } else {\r
399 DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 3.0x\n"));\r
400 }\r
401 } else {\r
402 if (Scr.SD_SPEC4 == 0) {\r
403 DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 2.0\n"));\r
404 } else {\r
405 DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
406 }\r
407 }\r
408 } else {\r
409 if ((Scr.SD_SPEC3 == 0) && (Scr.SD_SPEC4 == 0)) {\r
410 if (Scr.SD_SPEC == 1) {\r
411 DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.10\n"));\r
412 } else {\r
413 DEBUG ((EFI_D_INFO, "Found SD Card for Spec Version 1.0\n"));\r
414 }\r
415 } else {\r
416 DEBUG ((EFI_D_ERROR, "Found invalid SD Card\n"));\r
417 }\r
418 }\r
419 }\r
420 if (CccSwitch) {\r
421 /* SD Switch, Mode:1, Group:0, Value:1 */\r
422 CmdArg = 1 << 31 | 0x00FFFFFF;\r
423 CmdArg &= ~(0xF << (0 * 4));\r
424 CmdArg |= 1 << (0 * 4);\r
425 Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, CmdArg);\r
426 if (EFI_ERROR (Status)) {\r
427 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
428 return Status;\r
429 } else {\r
430 Status = MmcHost->ReadBlockData (MmcHost, 0, 64, Buffer);\r
431 if (EFI_ERROR (Status)) {\r
432 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): ReadBlockData Error and Status = %r\n", Status));\r
433 return Status;\r
434 }\r
435 }\r
436 }\r
437 if (Scr.SD_BUS_WIDTHS & SD_BUS_WIDTH_4BIT) {\r
438 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
439 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, CmdArg);\r
440 if (EFI_ERROR (Status)) {\r
441 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD55): Error and Status = %r\n", Status));\r
442 return Status;\r
443 }\r
444 /* Width: 4 */\r
445 Status = MmcHost->SendCommand (MmcHost, MMC_CMD6, 2);\r
446 if (EFI_ERROR (Status)) {\r
447 DEBUG ((EFI_D_ERROR, "%a(MMC_CMD6): Error and Status = %r\n", Status));\r
448 return Status;\r
449 }\r
450 }\r
451 if (MMC_HOST_HAS_SETIOS(MmcHost)) {\r
452 Status = MmcHost->SetIos (MmcHost, 26 * 1000 * 1000, 4, EMMCBACKWARD);\r
453 if (EFI_ERROR (Status)) {\r
454 DEBUG ((EFI_D_ERROR, "%a(SetIos): Error and Status = %r\n", Status));\r
455 return Status;\r
456 }\r
457 }\r
b4fdedc2
OM
458 return EFI_SUCCESS;\r
459}\r
460\r
461STATIC\r
462EFI_STATUS\r
463EFIAPI\r
464MmcIdentificationMode (\r
465 IN MMC_HOST_INSTANCE *MmcHostInstance\r
466 )\r
467{\r
468 EFI_STATUS Status;\r
469 UINT32 Response[4];\r
470 UINTN Timeout;\r
471 UINTN CmdArg;\r
472 BOOLEAN IsHCS;\r
473 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
474 OCR_RESPONSE OcrResponse;\r
475\r
476 MmcHost = MmcHostInstance->MmcHost;\r
477 CmdArg = 0;\r
478 IsHCS = FALSE;\r
479\r
480 if (MmcHost == NULL) {\r
481 return EFI_INVALID_PARAMETER;\r
482 }\r
483\r
484 // We can get into this function if we restart the identification mode\r
485 if (MmcHostInstance->State == MmcHwInitializationState) {\r
486 // Initialize the MMC Host HW\r
487 Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
488 if (EFI_ERROR (Status)) {\r
489 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));\r
490 return Status;\r
491 }\r
492 }\r
493\r
494 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
495 if (EFI_ERROR (Status)) {\r
496 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));\r
497 return Status;\r
498 }\r
499 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
500 if (EFI_ERROR (Status)) {\r
501 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));\r
502 return Status;\r
503 }\r
504\r
139b5773
OM
505 // Send CMD1 to get OCR (MMC)\r
506 // This command only valid for MMC and eMMC\r
32010753
HZ
507 Timeout = MAX_RETRY_COUNT;\r
508 do {\r
509 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);\r
510 if (EFI_ERROR (Status))\r
511 break;\r
b4fdedc2
OM
512 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);\r
513 if (EFI_ERROR (Status)) {\r
514 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
515 return Status;\r
516 }\r
32010753
HZ
517 Timeout--;\r
518 } while (!OcrResponse.Ocr.PowerUp && (Timeout > 0));\r
519 if (Status == EFI_SUCCESS) {\r
b4fdedc2
OM
520 if (!OcrResponse.Ocr.PowerUp) {\r
521 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));\r
522 return EFI_DEVICE_ERROR;\r
523 }\r
524 OcrResponse.Ocr.PowerUp = 0;\r
525 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {\r
526 MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;\r
527 }\r
528 else {\r
529 MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;\r
530 }\r
139b5773 531 // Check whether MMC or eMMC\r
b4fdedc2
OM
532 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||\r
533 OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {\r
534 return EmmcIdentificationMode (MmcHostInstance, OcrResponse);\r
535 }\r
b4fdedc2
OM
536 }\r
537\r
538 // Are we using SDIO ?\r
539 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
540 if (Status == EFI_SUCCESS) {\r
541 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));\r
542 return EFI_UNSUPPORTED;\r
543 }\r
544\r
545 // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
546 CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
547 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
548 if (Status == EFI_SUCCESS) {\r
549 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
550 IsHCS = TRUE;\r
551 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
552 if (EFI_ERROR (Status)) {\r
553 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));\r
554 return Status;\r
555 }\r
556 PrintResponseR1 (Response[0]);\r
557 // Check if it is valid response\r
558 if (Response[0] != CmdArg) {\r
559 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
560 return EFI_UNSUPPORTED;\r
561 }\r
562 } else {\r
563 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
564 }\r
565\r
566 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
567 Timeout = MAX_RETRY_COUNT;\r
568 while (Timeout > 0) {\r
569 // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
570 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
571 if (Status == EFI_SUCCESS) {\r
572 DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
573 if (IsHCS) {\r
574 MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
575 } else {\r
576 MmcHostInstance->CardInfo.CardType = SD_CARD;\r
577 }\r
578\r
579 // Note: The first time CmdArg will be zero\r
580 CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
581 if (IsHCS) {\r
582 CmdArg |= BIT30;\r
583 }\r
584 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
585 if (!EFI_ERROR (Status)) {\r
586 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
587 if (EFI_ERROR (Status)) {\r
588 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
589 return Status;\r
590 }\r
591 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
592 }\r
593 } else {\r
594 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
595 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
596\r
597 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
598 if (!EFI_ERROR (Status)) {\r
599 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
600 if (EFI_ERROR (Status)) {\r
601 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
602 return Status;\r
603 }\r
604 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
605 }\r
606 }\r
607\r
608 if (!EFI_ERROR (Status)) {\r
609 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
eff98cf9 610 gBS->Stall (1);\r
b4fdedc2
OM
611 Timeout--;\r
612 } else {\r
613 if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
614 MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
615 DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
616 }\r
617 break; // The MMC/SD card is ready. Continue the Identification Mode\r
618 }\r
619 } else {\r
eff98cf9 620 gBS->Stall (1);\r
b4fdedc2
OM
621 Timeout--;\r
622 }\r
623 }\r
624\r
625 if (Timeout == 0) {\r
626 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
627 return EFI_NO_MEDIA;\r
628 } else {\r
629 PrintOCR (Response[0]);\r
630 }\r
631\r
632 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
633 if (EFI_ERROR (Status)) {\r
634 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
635 return Status;\r
636 }\r
637\r
638 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
639 if (EFI_ERROR (Status)) {\r
640 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
641 return Status;\r
642 }\r
643 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
644 if (EFI_ERROR (Status)) {\r
645 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));\r
646 return Status;\r
647 }\r
648\r
649 PrintCID (Response);\r
650\r
651 Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);\r
652 if (EFI_ERROR (Status)) {\r
653 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
654 return Status;\r
655 }\r
656\r
657 //\r
658 // Note, SD specifications say that "if the command execution causes a state change, it\r
659 // will be visible to the host in the response to the next command"\r
660 // The status returned for this CMD3 will be 2 - identification\r
661 //\r
662 CmdArg = 1;\r
663 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
664 if (EFI_ERROR (Status)) {\r
665 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
666 return Status;\r
667 }\r
668\r
669 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
670 if (EFI_ERROR (Status)) {\r
671 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));\r
672 return Status;\r
673 }\r
674 PrintRCA (Response[0]);\r
675\r
676 // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
677 if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
678 MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
679 } else {\r
680 MmcHostInstance->CardInfo.RCA = CmdArg;\r
681 }\r
682 Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
683 if (EFI_ERROR (Status)) {\r
684 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
685 return Status;\r
686 }\r
687\r
688 return EFI_SUCCESS;\r
689}\r
690\r
691EFI_STATUS\r
692InitializeMmcDevice (\r
693 IN MMC_HOST_INSTANCE *MmcHostInstance\r
694 )\r
695{\r
696 EFI_STATUS Status;\r
697 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
698 UINTN BlockCount;\r
699\r
700 BlockCount = 1;\r
701 MmcHost = MmcHostInstance->MmcHost;\r
702\r
703 Status = MmcIdentificationMode (MmcHostInstance);\r
704 if (EFI_ERROR (Status)) {\r
705 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));\r
706 return Status;\r
707 }\r
708\r
709 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
710 if (EFI_ERROR (Status)) {\r
711 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));\r
712 return Status;\r
713 }\r
714\r
715 if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
716 Status = InitializeSdMmcDevice (MmcHostInstance);\r
752ae805
HZ
717 } else {\r
718 Status = InitializeEmmcDevice (MmcHostInstance);\r
719 }\r
720 if (EFI_ERROR (Status)) {\r
721 return Status;\r
b4fdedc2
OM
722 }\r
723\r
724 // Set Block Length\r
725 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
726 if (EFI_ERROR (Status)) {\r
727 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
728 MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
729 return Status;\r
730 }\r
731\r
732 // Block Count (not used). Could return an error for SD card\r
733 if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
734 Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
735 if (EFI_ERROR (Status)) {\r
736 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));\r
737 return Status;\r
738 }\r
739 }\r
740\r
741 return EFI_SUCCESS;\r
742}\r