]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/MmcDxe: Make the driver more compliant with the UEFI specification
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / MmcBlockIo.c
CommitLineData
1bfda055 1/** @file\r
2*\r
6f711615 3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
1bfda055 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 <Protocol/MmcHost.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/TimerLib.h>\r
19\r
20#include "Mmc.h"\r
21\r
22// Untested ...\r
23//#define USE_STREAM\r
24\r
a1ab9143 25#define MAX_RETRY_COUNT 1000\r
26#define CMD_RETRY_COUNT 20\r
1bfda055 27\r
28EFI_STATUS\r
29MmcNotifyState (\r
e8e95df4 30 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
31 IN MMC_STATE State\r
32 )\r
33{\r
34 MmcHostInstance->State = State;\r
16d88c2d 35 return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);\r
1bfda055 36}\r
37\r
e8e95df4 38VOID\r
39PrintOCR (\r
40 IN UINT32 Ocr\r
41 )\r
42{\r
6f711615 43 UINTN MinV;\r
44 UINTN MaxV;\r
45 UINTN Volts;\r
46 UINTN Loop;\r
e8e95df4 47\r
6f711615 48 MinV = 36; // 3.6\r
49 MaxV = 20; // 2.0\r
50 Volts = 20; // 2.0\r
e8e95df4 51\r
52 // The MMC register bits [23:8] indicate the working range of the card\r
6f711615 53 for (Loop = 8; Loop < 24; Loop++) {\r
54 if (Ocr & (1 << Loop)) {\r
55 if (MinV > Volts) MinV = Volts;\r
56 if (MaxV < Volts) MaxV = Volts + 1;\r
1bfda055 57 }\r
6f711615 58 Volts = Volts + 1;\r
e8e95df4 59 }\r
60\r
6f711615 61 DEBUG ((EFI_D_ERROR, "- PrintOCR Ocr (0x%X)\n",Ocr));\r
62 DEBUG ((EFI_D_ERROR, "\t- Card operating voltage: %d.%d to %d.%d\n", MinV/10, MinV % 10, MaxV/10, MaxV % 10));\r
e8e95df4 63 if (((Ocr >> 29) & 3) == 0) {\r
6f711615 64 DEBUG ((EFI_D_ERROR, "\t- AccessMode: Byte Mode\n"));\r
e8e95df4 65 } else {\r
6f711615 66 DEBUG ((EFI_D_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 29) & 3)));\r
e8e95df4 67 }\r
68\r
69 if (Ocr & MMC_OCR_POWERUP) {\r
6f711615 70 DEBUG ((EFI_D_ERROR, "\t- PowerUp\n"));\r
e8e95df4 71 } else {\r
6f711615 72 DEBUG ((EFI_D_ERROR, "\t- Voltage Not Supported\n"));\r
e8e95df4 73 }\r
1bfda055 74}\r
75\r
e8e95df4 76VOID PrintCID (\r
77 IN UINT32* Cid\r
78 )\r
79{\r
6f711615 80 DEBUG ((EFI_D_ERROR, "- PrintCID\n"));\r
81 DEBUG ((EFI_D_ERROR, "\t- Manufacturing date: %d/%d\n", (Cid[0] >> 8) & 0xF, (Cid[0] >> 12) & 0xFF));\r
82 DEBUG ((EFI_D_ERROR, "\t- Product serial number: 0x%X%X\n", Cid[1] & 0xFFFFFF, (Cid[0] >> 24) & 0xFF));\r
83 DEBUG ((EFI_D_ERROR, "\t- Product revision: %d\n", Cid[1] >> 24));\r
84 //DEBUG ((EFI_D_ERROR, "\t- Product name: %s\n", (char*)(Cid + 2)));\r
85 DEBUG ((EFI_D_ERROR, "\t- OEM ID: %c%c\n", (Cid[3] >> 8) & 0xFF, (Cid[3] >> 16) & 0xFF));\r
1bfda055 86}\r
87\r
8f964e8d 88#if !defined(MDEPKG_NDEBUG)\r
6f711615 89CONST CHAR8* mStrUnit[] = { "100kbit/s", "1Mbit/s", "10Mbit/s", "100MBit/s",\r
90 "Unknown", "Unknown", "Unknown", "Unknown" };\r
91CONST CHAR8* mStrValue[] = { "1.0", "1.2", "1.3", "1.5", "2.0", "2.5", "3.0", "3.5", "4.0", "4.5", "5.0",\r
92 "Unknown", "Unknown", "Unknown", "Unknown" };\r
8f964e8d 93#endif\r
94\r
e8e95df4 95VOID\r
96PrintCSD (\r
97 IN UINT32* Csd\r
98 )\r
99{\r
100 UINTN Value;\r
e8e95df4 101\r
102 if (((Csd[2] >> 30) & 0x3) == 0) {\r
6f711615 103 DEBUG ((EFI_D_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n"));\r
e8e95df4 104 } else if (((Csd[2] >> 30) & 0x3) == 1) {\r
6f711615 105 DEBUG ((EFI_D_ERROR, "- PrintCSD Version 2.00/High Capacity\n"));\r
e8e95df4 106 } else {\r
6f711615 107 DEBUG ((EFI_D_ERROR, "- PrintCSD Version Higher than v3.3\n"));\r
e8e95df4 108 }\r
109\r
6f711615 110 DEBUG ((EFI_D_ERROR, "\t- Supported card command class: 0x%X\n", MMC_CSD_GET_CCC(Csd)));\r
111 DEBUG ((EFI_D_ERROR, "\t- Speed: %a %a\n",mStrValue[(MMC_CSD_GET_TRANSPEED(Csd) >> 3) & 0xF],mStrUnit[MMC_CSD_GET_TRANSPEED(Csd) & 7]));\r
112 DEBUG ((EFI_D_ERROR, "\t- Maximum Read Data Block: %d\n",2 << (MMC_CSD_GET_READBLLEN(Csd)-1)));\r
113 DEBUG ((EFI_D_ERROR, "\t- Maximum Write Data Block: %d\n",2 << (MMC_CSD_GET_WRITEBLLEN(Csd)-1)));\r
e8e95df4 114\r
115 if (!MMC_CSD_GET_FILEFORMATGRP(Csd)) {\r
6f711615 116 Value = MMC_CSD_GET_FILEFORMAT (Csd);\r
117 if (Value == 0) DEBUG ((EFI_D_ERROR, "\t- Format (0): Hard disk-like file system with partition table\n"));\r
118 else if (Value == 1) DEBUG ((EFI_D_ERROR, "\t- Format (1): DOS FAT (floppy-like) with boot sector only (no partition table)\n"));\r
119 else if (Value == 2) DEBUG ((EFI_D_ERROR, "\t- Format (2): Universal File Format\n"));\r
120 else DEBUG ((EFI_D_ERROR, "\t- Format (3): Others/Unknown\n"));\r
e8e95df4 121 } else {\r
6f711615 122 DEBUG ((EFI_D_ERROR, "\t- Format: Reserved\n"));\r
e8e95df4 123 }\r
1bfda055 124}\r
125\r
e8e95df4 126VOID\r
127PrintRCA (\r
128 IN UINT32 Rca\r
129 )\r
130{\r
6f711615 131 DEBUG ((EFI_D_ERROR, "- PrintRCA: 0x%X\n", Rca));\r
132 DEBUG ((EFI_D_ERROR, "\t- Status: 0x%X\n", Rca & 0xFFFF));\r
133 DEBUG ((EFI_D_ERROR, "\t- RCA: 0x%X\n", (Rca >> 16) & 0xFFFF));\r
1bfda055 134}\r
135\r
e8e95df4 136VOID\r
137PrintResponseR1 (\r
138 IN UINT32 Response\r
139 )\r
140{\r
6f711615 141 DEBUG ((EFI_D_INFO, "Response: 0x%X\n", Response));\r
142 if (Response & MMC_R0_READY_FOR_DATA) {\r
143 DEBUG ((EFI_D_INFO, "\t- READY_FOR_DATA\n"));\r
144 }\r
145\r
146 if (((Response >> 9) & 0xF) == 0) DEBUG ((EFI_D_INFO, "\t- State: Idle\n"));\r
147 else if (((Response >> 9) & 0xF) == 1) DEBUG ((EFI_D_INFO, "\t- State: Ready\n"));\r
148 else if (((Response >> 9) & 0xF) == 2) DEBUG ((EFI_D_INFO, "\t- State: Ident\n"));\r
149 else if (((Response >> 9) & 0xF) == 3) DEBUG ((EFI_D_INFO, "\t- State: StandBy\n"));\r
150 else if (((Response >> 9) & 0xF) == 4) DEBUG ((EFI_D_INFO, "\t- State: Tran\n"));\r
151 else if (((Response >> 9) & 0xF) == 5) DEBUG ((EFI_D_INFO, "\t- State: Data\n"));\r
152 else if (((Response >> 9) & 0xF) == 6) DEBUG ((EFI_D_INFO, "\t- State: Rcv\n"));\r
153 else if (((Response >> 9) & 0xF) == 7) DEBUG ((EFI_D_INFO, "\t- State: Prg\n"));\r
154 else if (((Response >> 9) & 0xF) == 8) DEBUG ((EFI_D_INFO, "\t- State: Dis\n"));\r
155 else DEBUG ((EFI_D_INFO, "\t- State: Reserved\n"));\r
a1ab9143 156}\r
157\r
158EFI_STATUS\r
159EFIAPI\r
160MmcGetCardStatus(\r
e8e95df4 161 IN MMC_HOST_INSTANCE *MmcHostInstance\r
162 )\r
163{\r
164 EFI_STATUS Status;\r
165 UINT32 Response[4];\r
166 UINTN CmdArg;\r
167 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
168\r
169 Status = EFI_SUCCESS;\r
170 MmcHost = MmcHostInstance->MmcHost;\r
171 CmdArg = 0;\r
172\r
173 if (MmcHost == NULL) {\r
174 return EFI_INVALID_PARAMETER;\r
175 }\r
176 if(MmcHostInstance->State != MmcHwInitializationState){\r
177 //Get the Status of the card.\r
178 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 179 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 180 if (EFI_ERROR (Status)) {\r
181 DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
e8e95df4 182 return Status;\r
a1ab9143 183 }\r
184\r
e8e95df4 185 //Read Response\r
6f711615 186 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
187 PrintResponseR1 (Response[0]);\r
e8e95df4 188 }\r
189\r
190 return Status;\r
1bfda055 191}\r
192\r
193EFI_STATUS\r
194EFIAPI\r
195MmcIdentificationMode (\r
e8e95df4 196 IN MMC_HOST_INSTANCE *MmcHostInstance\r
197 )\r
198{\r
199 EFI_STATUS Status;\r
200 UINT32 Response[4];\r
201 UINTN Timeout;\r
202 UINTN CmdArg;\r
203 BOOLEAN IsHCS;\r
204 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
e8e95df4 205\r
206 MmcHost = MmcHostInstance->MmcHost;\r
207 CmdArg = 0;\r
208 IsHCS = FALSE;\r
209\r
210 if (MmcHost == NULL) {\r
211 return EFI_INVALID_PARAMETER;\r
212 }\r
213\r
214 // We can get into this function if we restart the identification mode\r
215 if (MmcHostInstance->State == MmcHwInitializationState) {\r
216 // Initialize the MMC Host HW\r
217 Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
6f711615 218 if (EFI_ERROR (Status)) {\r
219 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));\r
e8e95df4 220 return Status;\r
1bfda055 221 }\r
fc78c48e 222 }\r
223\r
224 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
6f711615 225 if (EFI_ERROR (Status)) {\r
226 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));\r
fc78c48e 227 return Status;\r
e8e95df4 228 }\r
229\r
230 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
6f711615 231 if (EFI_ERROR (Status)) {\r
232 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));\r
e8e95df4 233 return Status;\r
234 }\r
235\r
236 // Are we using SDIO ?\r
16d88c2d 237 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
e8e95df4 238 if (Status == EFI_SUCCESS) {\r
6f711615 239 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));\r
e8e95df4 240 return EFI_UNSUPPORTED;\r
241 }\r
242\r
243 // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
244 CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
16d88c2d 245 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
e8e95df4 246 if (Status == EFI_SUCCESS) {\r
247 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
248 IsHCS = TRUE;\r
6f711615 249 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
250 PrintResponseR1 (Response[0]);\r
e8e95df4 251 //check if it is valid response\r
252 if(Response[0] != CmdArg){\r
253 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
254 return EFI_UNSUPPORTED;\r
1bfda055 255 }\r
e8e95df4 256 } else {\r
257 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
258 }\r
259\r
492e34a5 260 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
e8e95df4 261 Timeout = MAX_RETRY_COUNT;\r
262 while (Timeout > 0) {\r
263 // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
16d88c2d 264 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
1bfda055 265 if (Status == EFI_SUCCESS) {\r
e8e95df4 266 DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
267 if (IsHCS) {\r
268 MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
1bfda055 269 } else {\r
e8e95df4 270 MmcHostInstance->CardInfo.CardType = SD_CARD;\r
1bfda055 271 }\r
272\r
e8e95df4 273 // Note: The first time CmdArg will be zero\r
274 CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
275 if (IsHCS) {\r
276 CmdArg |= BIT30;\r
277 }\r
16d88c2d 278 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
6f711615 279 if (!EFI_ERROR (Status)) {\r
280 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
e8e95df4 281 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
1bfda055 282 }\r
1bfda055 283 } else {\r
e8e95df4 284 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
285 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
1bfda055 286\r
16d88c2d 287 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
6f711615 288 if (!EFI_ERROR (Status)) {\r
289 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
e8e95df4 290 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
a1ab9143 291 }\r
1bfda055 292 }\r
1bfda055 293\r
6f711615 294 if (!EFI_ERROR (Status)) {\r
492e34a5 295 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
6f711615 296 MicroSecondDelay (1);\r
e8e95df4 297 Timeout--;\r
298 } else {\r
299 if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
300 MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
301 DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
302 }\r
303 break; // The MMC/SD card is ready. Continue the Identification Mode\r
304 }\r
1bfda055 305 } else {\r
6f711615 306 MicroSecondDelay (1);\r
e8e95df4 307 Timeout--;\r
1bfda055 308 }\r
e8e95df4 309 }\r
310\r
311 if (Timeout == 0) {\r
6f711615 312 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
e8e95df4 313 return EFI_NO_MEDIA;\r
314 } else {\r
6f711615 315 PrintOCR (Response[0]);\r
e8e95df4 316 }\r
317\r
318 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
6f711615 319 if (EFI_ERROR (Status)) {\r
320 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
e8e95df4 321 return Status;\r
322 }\r
323\r
16d88c2d 324 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
6f711615 325 if (EFI_ERROR (Status)) {\r
326 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
e8e95df4 327 return Status;\r
328 }\r
6f711615 329 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
e8e95df4 330 PrintCID(Response);\r
331\r
332 Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);\r
6f711615 333 if (EFI_ERROR (Status)) {\r
334 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
e8e95df4 335 return Status;\r
336 }\r
337\r
d8ad4736 338 //\r
339 // Note, SD specifications say that "if the command execution causes a state change, it\r
340 // will be visible to the host in the response to the next command"\r
341 // The status returned for this CMD3 will be 2 - identification\r
342 //\r
343 CmdArg = 1;\r
16d88c2d 344 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
6f711615 345 if (EFI_ERROR (Status)) {\r
346 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
d8ad4736 347 return Status;\r
e8e95df4 348 }\r
349\r
6f711615 350 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
351 PrintRCA (Response[0]);\r
d8ad4736 352\r
e8e95df4 353 // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
354 if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
355 MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
356 } else {\r
357 MmcHostInstance->CardInfo.RCA = CmdArg;\r
358 }\r
359\r
360 Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
6f711615 361 if (EFI_ERROR (Status)) {\r
362 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
e8e95df4 363 return Status;\r
364 }\r
365\r
366 return EFI_SUCCESS;\r
1bfda055 367}\r
368\r
16d88c2d 369EFI_STATUS InitializeMmcDevice (\r
40842a5e 370 IN MMC_HOST_INSTANCE *MmcHostInstance\r
371 )\r
372{\r
373 UINT32 Response[4];\r
374 EFI_STATUS Status;\r
375 UINTN CardSize, NumBlocks, BlockSize, CmdArg;\r
376 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
377 UINTN BlockCount = 1;\r
378 \r
379 MmcHost = MmcHostInstance->MmcHost;\r
380\r
381 MmcIdentificationMode (MmcHostInstance);\r
382\r
383 //Send a command to get Card specific data\r
384 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 385 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
6f711615 386 if (EFI_ERROR (Status)) {\r
387 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD9): Error, Status=%r\n", Status));\r
40842a5e 388 return Status;\r
389 }\r
390 //Read Response\r
6f711615 391 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
40842a5e 392 PrintCSD(Response);\r
393\r
394 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
6f711615 395 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
40842a5e 396 NumBlocks = ((CardSize + 1) * 1024);\r
397 BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);\r
398 } else {\r
6f711615 399 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
400 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
40842a5e 401 BlockSize = 1 << MMC_CSD_GET_READBLLEN(Response);\r
402 }\r
403\r
404 //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
405 if (BlockSize > 512) {\r
6f711615 406 NumBlocks = MultU64x32 (NumBlocks, BlockSize/512);\r
40842a5e 407 BlockSize = 512;\r
408 }\r
409\r
410 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
411 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
16d88c2d 412 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
40842a5e 413 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
414 MmcHostInstance->BlockIo.Media->MediaId++;\r
415\r
416 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 417 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
6f711615 418 if (EFI_ERROR (Status)) {\r
419 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD7): Error and Status = %r\n", Status));\r
40842a5e 420 return Status;\r
421 }\r
422\r
423 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
6f711615 424 if (EFI_ERROR (Status)) {\r
425 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcTransferState\n"));\r
40842a5e 426 return Status;\r
427 }\r
428\r
429 // Set Block Length\r
16d88c2d 430 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
6f711615 431 if (EFI_ERROR (Status)) {\r
432 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n", MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
40842a5e 433 return Status;\r
434 }\r
435\r
436 // Block Count (not used). Could return an error for SD card\r
437 if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
16d88c2d 438 MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
40842a5e 439 }\r
440\r
441 return EFI_SUCCESS;\r
442}\r
443\r
1bfda055 444EFI_STATUS\r
445EFIAPI\r
446MmcReset (\r
447 IN EFI_BLOCK_IO_PROTOCOL *This,\r
448 IN BOOLEAN ExtendedVerification\r
e8e95df4 449 )\r
450{\r
3de99375 451 MMC_HOST_INSTANCE *MmcHostInstance;\r
452\r
6f711615 453 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
3de99375 454\r
455 if (MmcHostInstance->MmcHost == NULL) {\r
456 // Nothing to do\r
457 return EFI_SUCCESS;\r
458 }\r
459\r
460 // If a card is not present then clear all media settings\r
16d88c2d 461 if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {\r
3de99375 462 MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;\r
463 MmcHostInstance->BlockIo.Media->LastBlock = 0;\r
464 MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo\r
465 MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;\r
466\r
467 // Indicate that the driver requires initialization\r
468 MmcHostInstance->State = MmcHwInitializationState;\r
469\r
470 return EFI_SUCCESS;\r
471 }\r
472\r
e8e95df4 473 // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn\r
474 // on power and restart Identification mode\r
475 return EFI_SUCCESS;\r
1bfda055 476}\r
477\r
478EFI_STATUS\r
479MmcDetectCard (\r
480 EFI_MMC_HOST_PROTOCOL *MmcHost\r
481 )\r
482{\r
16d88c2d 483 if (!MmcHost->IsCardPresent (MmcHost)) {\r
e8e95df4 484 return EFI_NO_MEDIA;\r
485 } else {\r
486 return EFI_SUCCESS;\r
487 }\r
1bfda055 488}\r
489\r
490#define MMCI0_BLOCKLEN 512\r
491#define MMCI0_TIMEOUT 10000\r
492\r
e8e95df4 493EFI_STATUS\r
494MmcIoBlocks (\r
1bfda055 495 IN EFI_BLOCK_IO_PROTOCOL *This,\r
496 IN UINTN Transfer,\r
497 IN UINT32 MediaId,\r
498 IN EFI_LBA Lba,\r
499 IN UINTN BufferSize,\r
500 OUT VOID *Buffer\r
e8e95df4 501 )\r
502{\r
503 UINT32 Response[4];\r
504 EFI_STATUS Status;\r
40842a5e 505 UINTN CmdArg;\r
969ece79 506 INTN Timeout;\r
e8e95df4 507 UINTN Cmd;\r
508 MMC_HOST_INSTANCE *MmcHostInstance;\r
509 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
510 UINTN BytesRemainingToBeTransfered;\r
511 UINTN BlockCount = 1;\r
512\r
6f711615 513 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
514 ASSERT (MmcHostInstance != 0);\r
e8e95df4 515 MmcHost = MmcHostInstance->MmcHost;\r
6f711615 516 ASSERT (MmcHost);\r
e8e95df4 517\r
5ab765a7 518 if (This->Media->MediaId != MediaId) {\r
519 return EFI_MEDIA_CHANGED;\r
520 }\r
521\r
969ece79 522 if ((MmcHost == 0)|| (Buffer == NULL)) {\r
e8e95df4 523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
526 // Check if a Card is Present\r
3de99375 527 if (!MmcHostInstance->BlockIo.Media->MediaPresent) {\r
e8e95df4 528 return EFI_NO_MEDIA;\r
529 }\r
530\r
969ece79 531 // All blocks must be within the device\r
532 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)){\r
969ece79 533 return EFI_INVALID_PARAMETER;\r
e8e95df4 534 }\r
535\r
5ab765a7 536 if((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
537 return EFI_WRITE_PROTECTED;\r
969ece79 538 }\r
539\r
5ab765a7 540 // Reading 0 Byte is valid\r
541 if (BufferSize == 0) {\r
542 return EFI_SUCCESS;\r
969ece79 543 }\r
544\r
5ab765a7 545 // The buffer size must be an exact multiple of the block size\r
546 if ((BufferSize % This->Media->BlockSize) != 0) {\r
547 return EFI_BAD_BUFFER_SIZE;\r
548 }\r
549\r
550 // Check the alignment\r
551 if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {\r
552 return EFI_INVALID_PARAMETER;\r
e8e95df4 553 }\r
554\r
555 BytesRemainingToBeTransfered = BufferSize;\r
556 while (BytesRemainingToBeTransfered > 0) {\r
557\r
558 // Check if the Card is in Ready status\r
559 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
560 Response[0] = 0;\r
561 Timeout = 20;\r
260675b0 562 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
6f711615 563 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
260675b0 564 && Timeout--) {\r
16d88c2d 565 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 566 if (!EFI_ERROR (Status)) {\r
567 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
e8e95df4 568 }\r
1bfda055 569 }\r
570\r
e8e95df4 571 if (0 == Timeout) {\r
6f711615 572 DEBUG ((EFI_D_ERROR, "The Card is busy\n"));\r
e8e95df4 573 return EFI_NOT_READY;\r
b9d5fe03 574 }\r
575\r
e8e95df4 576 //Set command argument based on the card access mode (Byte mode or Block mode)\r
577 if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {\r
578 CmdArg = Lba;\r
579 } else {\r
580 CmdArg = Lba * This->Media->BlockSize;\r
581 }\r
1bfda055 582\r
e8e95df4 583 if (Transfer == MMC_IOBLOCKS_READ) {\r
1bfda055 584#ifndef USE_STREAM\r
e8e95df4 585 // Read a single block\r
586 Cmd = MMC_CMD17;\r
1bfda055 587#else\r
e8e95df4 588 //TODO: Should we support read stream (MMC_CMD11)\r
1bfda055 589#endif\r
e8e95df4 590 } else {\r
1bfda055 591#ifndef USE_STREAM\r
e8e95df4 592 // Write a single block\r
593 Cmd = MMC_CMD24;\r
1bfda055 594#else\r
e8e95df4 595 //TODO: Should we support write stream (MMC_CMD20)\r
1bfda055 596#endif\r
e8e95df4 597 }\r
16d88c2d 598 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
6f711615 599 if (EFI_ERROR (Status)) {\r
600 DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
e8e95df4 601 return Status;\r
602 }\r
1bfda055 603\r
e8e95df4 604 if (Transfer == MMC_IOBLOCKS_READ) {\r
1bfda055 605#ifndef USE_STREAM\r
e8e95df4 606 // Read one block of Data\r
6f711615 607 Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
608 if (EFI_ERROR (Status)) {\r
609 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
e8e95df4 610 return Status;\r
611 }\r
1bfda055 612#else\r
260675b0 613 //TODO: Read a stream\r
6f711615 614 ASSERT (0);\r
1bfda055 615#endif\r
e8e95df4 616 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
6f711615 617 if (EFI_ERROR (Status)) {\r
618 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
e8e95df4 619 return Status;\r
620 }\r
621 } else {\r
1bfda055 622#ifndef USE_STREAM\r
e8e95df4 623 // Write one block of Data\r
6f711615 624 Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
625 if (EFI_ERROR (Status)) {\r
626 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
e8e95df4 627 return Status;\r
628 }\r
1bfda055 629#else\r
260675b0 630 //TODO: Write a stream\r
6f711615 631 ASSERT (0);\r
1bfda055 632#endif\r
e8e95df4 633 }\r
1bfda055 634\r
e8e95df4 635 // Command 12 - Stop transmission (ends read)\r
16d88c2d 636 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
6f711615 637 if (!EFI_ERROR (Status)) {\r
638 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
e8e95df4 639 }\r
1bfda055 640\r
e8e95df4 641 // Command 13 - Read status and wait for programming to complete (return to tran)\r
642 Timeout = MMCI0_TIMEOUT;\r
643 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
644 Response[0] = 0;\r
260675b0 645 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
6f711615 646 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
260675b0 647 && Timeout--) {\r
16d88c2d 648 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 649 if (!EFI_ERROR (Status)) {\r
699e34ad 650 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
651 if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
652 break; // Prevents delay once finished\r
653 }\r
e8e95df4 654 }\r
6f711615 655 NanoSecondDelay (100);\r
e8e95df4 656 }\r
1bfda055 657\r
e8e95df4 658 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
6f711615 659 if (EFI_ERROR (Status)) {\r
660 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
e8e95df4 661 return Status;\r
1bfda055 662 }\r
663\r
e8e95df4 664 BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
665 Lba += BlockCount;\r
666 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
667 }\r
668\r
669 return EFI_SUCCESS;\r
1bfda055 670}\r
671\r
672EFI_STATUS\r
673EFIAPI\r
674MmcReadBlocks (\r
675 IN EFI_BLOCK_IO_PROTOCOL *This,\r
676 IN UINT32 MediaId,\r
677 IN EFI_LBA Lba,\r
678 IN UINTN BufferSize,\r
679 OUT VOID *Buffer\r
e8e95df4 680 )\r
681{\r
682 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 683}\r
684\r
685EFI_STATUS\r
686EFIAPI\r
687MmcWriteBlocks (\r
688 IN EFI_BLOCK_IO_PROTOCOL *This,\r
689 IN UINT32 MediaId,\r
690 IN EFI_LBA Lba,\r
691 IN UINTN BufferSize,\r
692 IN VOID *Buffer\r
e8e95df4 693 )\r
694{\r
695 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 696}\r
697\r
698EFI_STATUS\r
699EFIAPI\r
700MmcFlushBlocks (\r
701 IN EFI_BLOCK_IO_PROTOCOL *This\r
e8e95df4 702 )\r
703{\r
704 return EFI_SUCCESS;\r
1bfda055 705}\r