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