]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/MmcIdentification.c
DuetPkg: Add POSTBUILD in DSC files to run post-build automatically
[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
28UINT32 mEmmcRcaCount = 0;\r
29\r
30STATIC\r
31EFI_STATUS\r
32EFIAPI\r
33EmmcIdentificationMode (\r
34 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
35 IN OCR_RESPONSE Response\r
36 )\r
37{\r
38 EFI_MMC_HOST_PROTOCOL *Host;\r
39 EFI_BLOCK_IO_MEDIA *Media;\r
40 EFI_STATUS Status;\r
41 UINT32 RCA;\r
42 UINT32 ECSD[128];\r
43\r
44 Host = MmcHostInstance->MmcHost;\r
45 Media = MmcHostInstance->BlockIo.Media;\r
46\r
47 // Fetch card identity register\r
48 Status = Host->SendCommand (Host, MMC_CMD2, 0);\r
49 if (EFI_ERROR (Status)) {\r
50 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD2, Status=%r.\n", Status));\r
51 return Status;\r
52 }\r
53\r
54 Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CIDData));\r
55 if (EFI_ERROR (Status)) {\r
56 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CID retrieval error, Status=%r.\n", Status));\r
57 return Status;\r
58 }\r
59\r
60 // Assign a relative address value to the card\r
61 MmcHostInstance->CardInfo.RCA = ++mEmmcRcaCount; // TODO: might need a more sophisticated way of doing this\r
62 RCA = MmcHostInstance->CardInfo.RCA << RCA_SHIFT_OFFSET;\r
63 Status = Host->SendCommand (Host, MMC_CMD3, RCA);\r
64 if (EFI_ERROR (Status)) {\r
65 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): RCA set error, Status=%r.\n", Status));\r
66 return Status;\r
67 }\r
68\r
69 // Fetch card specific data\r
70 Status = Host->SendCommand (Host, MMC_CMD9, RCA);\r
71 if (EFI_ERROR (Status)) {\r
72 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Failed to send CMD9, Status=%r.\n", Status));\r
73 return Status;\r
74 }\r
75\r
76 Status = Host->ReceiveResponse (Host, MMC_RESPONSE_TYPE_R2, (UINT32 *)&(MmcHostInstance->CardInfo.CSDData));\r
77 if (EFI_ERROR (Status)) {\r
78 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): CSD retrieval error, Status=%r.\n", Status));\r
79 return Status;\r
80 }\r
81\r
82 // Select the card\r
83 Status = Host->SendCommand (Host, MMC_CMD7, RCA);\r
84 if (EFI_ERROR (Status)) {\r
85 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): Card selection error, Status=%r.\n", Status));\r
86 }\r
87\r
88 // Fetch ECSD\r
89 Status = Host->SendCommand (Host, MMC_CMD8, RCA);\r
90 if (EFI_ERROR (Status)) {\r
91 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD fetch error, Status=%r.\n", Status));\r
92 }\r
93\r
94 Status = Host->ReadBlockData (Host, 0, 512, ECSD);\r
95 if (EFI_ERROR (Status)) {\r
96 DEBUG ((EFI_D_ERROR, "EmmcIdentificationMode(): ECSD read error, Status=%r.\n", Status));\r
97 return Status;\r
98 }\r
99\r
100 // Set up media\r
101 Media->BlockSize = EMMC_CARD_SIZE; // 512-byte support is mandatory for eMMC cards\r
102 Media->MediaId = MmcHostInstance->CardInfo.CIDData.PSN;\r
103 Media->ReadOnly = MmcHostInstance->CardInfo.CSDData.PERM_WRITE_PROTECT;\r
104 Media->LogicalBlocksPerPhysicalBlock = 1;\r
105 Media->IoAlign = 4;\r
106 // Compute last block using bits [215:212] of the ECSD\r
107 Media->LastBlock = ECSD[EMMC_ECSD_SIZE_OFFSET] - 1; // eMMC isn't supposed to report this for\r
108 // Cards <2GB in size, but the model does.\r
109\r
110 // Setup card type\r
111 MmcHostInstance->CardInfo.CardType = EMMC_CARD;\r
112 return EFI_SUCCESS;\r
113}\r
114\r
115STATIC\r
116EFI_STATUS\r
117InitializeSdMmcDevice (\r
118 IN MMC_HOST_INSTANCE *MmcHostInstance\r
119 )\r
120{\r
121 UINT32 CmdArg;\r
122 UINT32 Response[4];\r
123 UINTN BlockSize;\r
124 UINTN CardSize;\r
125 UINTN NumBlocks;\r
126 EFI_STATUS Status;\r
127 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
128\r
129 MmcHost = MmcHostInstance->MmcHost;\r
130\r
131 // Send a command to get Card specific data\r
132 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
133 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
134 if (EFI_ERROR (Status)) {\r
135 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
136 return Status;\r
137 }\r
138\r
139 // Read Response\r
140 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
141 if (EFI_ERROR (Status)) {\r
142 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(): Failed to receive CSD, Status=%r\n", Status));\r
143 return Status;\r
144 }\r
145 PrintCSD (Response);\r
146\r
147 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
148 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
149 NumBlocks = ((CardSize + 1) * 1024);\r
150 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
151 } else {\r
152 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
153 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
154 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
155 }\r
156\r
157 // For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
158 if (BlockSize > 512) {\r
159 NumBlocks = MultU64x32 (NumBlocks, BlockSize / 512);\r
160 BlockSize = 512;\r
161 }\r
162\r
163 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
164 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
165 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
166 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
167 MmcHostInstance->BlockIo.Media->MediaId++;\r
168\r
169 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
170 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
171 if (EFI_ERROR (Status)) {\r
172 DEBUG((EFI_D_ERROR, "InitializeSdMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
173 return Status;\r
174 }\r
175\r
176 return EFI_SUCCESS;\r
177}\r
178\r
179STATIC\r
180EFI_STATUS\r
181EFIAPI\r
182MmcIdentificationMode (\r
183 IN MMC_HOST_INSTANCE *MmcHostInstance\r
184 )\r
185{\r
186 EFI_STATUS Status;\r
187 UINT32 Response[4];\r
188 UINTN Timeout;\r
189 UINTN CmdArg;\r
190 BOOLEAN IsHCS;\r
191 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
192 OCR_RESPONSE OcrResponse;\r
193\r
194 MmcHost = MmcHostInstance->MmcHost;\r
195 CmdArg = 0;\r
196 IsHCS = FALSE;\r
197\r
198 if (MmcHost == NULL) {\r
199 return EFI_INVALID_PARAMETER;\r
200 }\r
201\r
202 // We can get into this function if we restart the identification mode\r
203 if (MmcHostInstance->State == MmcHwInitializationState) {\r
204 // Initialize the MMC Host HW\r
205 Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
206 if (EFI_ERROR (Status)) {\r
207 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState, Status=%r.\n", Status));\r
208 return Status;\r
209 }\r
210 }\r
211\r
212 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
213 if (EFI_ERROR (Status)) {\r
214 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error, Status=%r.\n", Status));\r
215 return Status;\r
216 }\r
217 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
218 if (EFI_ERROR (Status)) {\r
219 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState, Status=%r.\n", Status));\r
220 return Status;\r
221 }\r
222\r
139b5773
OM
223 // Send CMD1 to get OCR (MMC)\r
224 // This command only valid for MMC and eMMC\r
b4fdedc2
OM
225 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, EMMC_CMD1_CAPACITY_GREATER_THAN_2GB);\r
226 if (Status == EFI_SUCCESS) {\r
227 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, (UINT32 *)&OcrResponse);\r
228 if (EFI_ERROR (Status)) {\r
229 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
230 return Status;\r
231 }\r
232\r
233 if (!OcrResponse.Ocr.PowerUp) {\r
234 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD1): Card initialisation failure, Status=%r.\n", Status));\r
235 return EFI_DEVICE_ERROR;\r
236 }\r
237 OcrResponse.Ocr.PowerUp = 0;\r
238 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB) {\r
239 MmcHostInstance->CardInfo.OCRData.AccessMode = BIT1;\r
240 }\r
241 else {\r
242 MmcHostInstance->CardInfo.OCRData.AccessMode = 0x0;\r
243 }\r
139b5773 244 // Check whether MMC or eMMC\r
b4fdedc2
OM
245 if (OcrResponse.Raw == EMMC_CMD1_CAPACITY_GREATER_THAN_2GB ||\r
246 OcrResponse.Raw == EMMC_CMD1_CAPACITY_LESS_THAN_2GB) {\r
247 return EmmcIdentificationMode (MmcHostInstance, OcrResponse);\r
248 }\r
b4fdedc2
OM
249 }\r
250\r
251 // Are we using SDIO ?\r
252 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
253 if (Status == EFI_SUCCESS) {\r
254 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported, Status=%r.\n", Status));\r
255 return EFI_UNSUPPORTED;\r
256 }\r
257\r
258 // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
259 CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
260 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
261 if (Status == EFI_SUCCESS) {\r
262 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
263 IsHCS = TRUE;\r
264 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
265 if (EFI_ERROR (Status)) {\r
266 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive response to CMD8, Status=%r.\n", Status));\r
267 return Status;\r
268 }\r
269 PrintResponseR1 (Response[0]);\r
270 // Check if it is valid response\r
271 if (Response[0] != CmdArg) {\r
272 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
273 return EFI_UNSUPPORTED;\r
274 }\r
275 } else {\r
276 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
277 }\r
278\r
279 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
280 Timeout = MAX_RETRY_COUNT;\r
281 while (Timeout > 0) {\r
282 // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
283 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
284 if (Status == EFI_SUCCESS) {\r
285 DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
286 if (IsHCS) {\r
287 MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
288 } else {\r
289 MmcHostInstance->CardInfo.CardType = SD_CARD;\r
290 }\r
291\r
292 // Note: The first time CmdArg will be zero\r
293 CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
294 if (IsHCS) {\r
295 CmdArg |= BIT30;\r
296 }\r
297 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
298 if (!EFI_ERROR (Status)) {\r
299 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
300 if (EFI_ERROR (Status)) {\r
301 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
302 return Status;\r
303 }\r
304 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
305 }\r
306 } else {\r
307 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
308 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
309\r
310 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
311 if (!EFI_ERROR (Status)) {\r
312 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
313 if (EFI_ERROR (Status)) {\r
314 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive OCR, Status=%r.\n", Status));\r
315 return Status;\r
316 }\r
317 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
318 }\r
319 }\r
320\r
321 if (!EFI_ERROR (Status)) {\r
322 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
eff98cf9 323 gBS->Stall (1);\r
b4fdedc2
OM
324 Timeout--;\r
325 } else {\r
326 if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
327 MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
328 DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
329 }\r
330 break; // The MMC/SD card is ready. Continue the Identification Mode\r
331 }\r
332 } else {\r
eff98cf9 333 gBS->Stall (1);\r
b4fdedc2
OM
334 Timeout--;\r
335 }\r
336 }\r
337\r
338 if (Timeout == 0) {\r
339 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
340 return EFI_NO_MEDIA;\r
341 } else {\r
342 PrintOCR (Response[0]);\r
343 }\r
344\r
345 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
346 if (EFI_ERROR (Status)) {\r
347 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
348 return Status;\r
349 }\r
350\r
351 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
352 if (EFI_ERROR (Status)) {\r
353 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
354 return Status;\r
355 }\r
356 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
357 if (EFI_ERROR (Status)) {\r
358 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive CID, Status=%r.\n", Status));\r
359 return Status;\r
360 }\r
361\r
362 PrintCID (Response);\r
363\r
364 Status = MmcHost->NotifyState (MmcHost, MmcIdentificationState);\r
365 if (EFI_ERROR (Status)) {\r
366 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
367 return Status;\r
368 }\r
369\r
370 //\r
371 // Note, SD specifications say that "if the command execution causes a state change, it\r
372 // will be visible to the host in the response to the next command"\r
373 // The status returned for this CMD3 will be 2 - identification\r
374 //\r
375 CmdArg = 1;\r
376 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
377 if (EFI_ERROR (Status)) {\r
378 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
379 return Status;\r
380 }\r
381\r
382 Status = MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
383 if (EFI_ERROR (Status)) {\r
384 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Failed to receive RCA, Status=%r.\n", Status));\r
385 return Status;\r
386 }\r
387 PrintRCA (Response[0]);\r
388\r
389 // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
390 if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
391 MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
392 } else {\r
393 MmcHostInstance->CardInfo.RCA = CmdArg;\r
394 }\r
395 Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
396 if (EFI_ERROR (Status)) {\r
397 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
398 return Status;\r
399 }\r
400\r
401 return EFI_SUCCESS;\r
402}\r
403\r
404EFI_STATUS\r
405InitializeMmcDevice (\r
406 IN MMC_HOST_INSTANCE *MmcHostInstance\r
407 )\r
408{\r
409 EFI_STATUS Status;\r
410 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
411 UINTN BlockCount;\r
412\r
413 BlockCount = 1;\r
414 MmcHost = MmcHostInstance->MmcHost;\r
415\r
416 Status = MmcIdentificationMode (MmcHostInstance);\r
417 if (EFI_ERROR (Status)) {\r
418 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error in Identification Mode, Status=%r\n", Status));\r
419 return Status;\r
420 }\r
421\r
422 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
423 if (EFI_ERROR (Status)) {\r
424 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState, Status=%r\n", Status));\r
425 return Status;\r
426 }\r
427\r
428 if (MmcHostInstance->CardInfo.CardType != EMMC_CARD) {\r
429 Status = InitializeSdMmcDevice (MmcHostInstance);\r
430 if (EFI_ERROR (Status)) {\r
431 return Status;\r
432 }\r
433 }\r
434\r
435 // Set Block Length\r
436 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
437 if (EFI_ERROR (Status)) {\r
438 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
439 MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
440 return Status;\r
441 }\r
442\r
443 // Block Count (not used). Could return an error for SD card\r
444 if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
445 Status = MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
446 if (EFI_ERROR (Status)) {\r
447 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD23): Error, Status=%r\n", Status));\r
448 return Status;\r
449 }\r
450 }\r
451\r
452 return EFI_SUCCESS;\r
453}\r