]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/MmcDxe: Moved all the 'Print*()' functions to MmcDebug.c
[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
842b02d8
OM
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
1bfda055 12*\r
13**/\r
14\r
1bfda055 15#include <Library/BaseMemoryLib.h>\r
16#include <Library/TimerLib.h>\r
17\r
18#include "Mmc.h"\r
19\r
a1ab9143 20#define MAX_RETRY_COUNT 1000\r
21#define CMD_RETRY_COUNT 20\r
1bfda055 22\r
23EFI_STATUS\r
24MmcNotifyState (\r
e8e95df4 25 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
26 IN MMC_STATE State\r
27 )\r
28{\r
29 MmcHostInstance->State = State;\r
16d88c2d 30 return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);\r
1bfda055 31}\r
32\r
a1ab9143 33EFI_STATUS\r
34EFIAPI\r
842b02d8 35MmcGetCardStatus (\r
4ca3c688 36 IN MMC_HOST_INSTANCE *MmcHostInstance\r
e8e95df4 37 )\r
38{\r
39 EFI_STATUS Status;\r
40 UINT32 Response[4];\r
41 UINTN CmdArg;\r
42 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
43\r
44 Status = EFI_SUCCESS;\r
45 MmcHost = MmcHostInstance->MmcHost;\r
46 CmdArg = 0;\r
47\r
48 if (MmcHost == NULL) {\r
49 return EFI_INVALID_PARAMETER;\r
50 }\r
842b02d8 51 if (MmcHostInstance->State != MmcHwInitializationState) {\r
e8e95df4 52 //Get the Status of the card.\r
53 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 54 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 55 if (EFI_ERROR (Status)) {\r
56 DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
e8e95df4 57 return Status;\r
a1ab9143 58 }\r
59\r
e8e95df4 60 //Read Response\r
6f711615 61 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
62 PrintResponseR1 (Response[0]);\r
e8e95df4 63 }\r
64\r
65 return Status;\r
1bfda055 66}\r
67\r
68EFI_STATUS\r
69EFIAPI\r
70MmcIdentificationMode (\r
e8e95df4 71 IN MMC_HOST_INSTANCE *MmcHostInstance\r
72 )\r
73{\r
74 EFI_STATUS Status;\r
75 UINT32 Response[4];\r
76 UINTN Timeout;\r
77 UINTN CmdArg;\r
78 BOOLEAN IsHCS;\r
79 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
e8e95df4 80\r
81 MmcHost = MmcHostInstance->MmcHost;\r
82 CmdArg = 0;\r
83 IsHCS = FALSE;\r
84\r
85 if (MmcHost == NULL) {\r
86 return EFI_INVALID_PARAMETER;\r
87 }\r
88\r
89 // We can get into this function if we restart the identification mode\r
90 if (MmcHostInstance->State == MmcHwInitializationState) {\r
91 // Initialize the MMC Host HW\r
92 Status = MmcNotifyState (MmcHostInstance, MmcHwInitializationState);\r
6f711615 93 if (EFI_ERROR (Status)) {\r
94 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));\r
e8e95df4 95 return Status;\r
1bfda055 96 }\r
fc78c48e 97 }\r
98\r
99 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
6f711615 100 if (EFI_ERROR (Status)) {\r
101 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));\r
fc78c48e 102 return Status;\r
e8e95df4 103 }\r
104\r
105 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
6f711615 106 if (EFI_ERROR (Status)) {\r
107 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));\r
e8e95df4 108 return Status;\r
109 }\r
110\r
111 // Are we using SDIO ?\r
16d88c2d 112 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
e8e95df4 113 if (Status == EFI_SUCCESS) {\r
6f711615 114 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));\r
e8e95df4 115 return EFI_UNSUPPORTED;\r
116 }\r
117\r
118 // Check which kind of card we are using. Ver2.00 or later SD Memory Card (PL180 is SD v1.1)\r
119 CmdArg = (0x0UL << 12 | BIT8 | 0xCEUL << 0);\r
16d88c2d 120 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
e8e95df4 121 if (Status == EFI_SUCCESS) {\r
122 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
123 IsHCS = TRUE;\r
6f711615 124 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
125 PrintResponseR1 (Response[0]);\r
e8e95df4 126 //check if it is valid response\r
842b02d8 127 if (Response[0] != CmdArg) {\r
e8e95df4 128 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
129 return EFI_UNSUPPORTED;\r
1bfda055 130 }\r
e8e95df4 131 } else {\r
132 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
133 }\r
134\r
492e34a5 135 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
e8e95df4 136 Timeout = MAX_RETRY_COUNT;\r
137 while (Timeout > 0) {\r
138 // SD Card or MMC Card ? CMD55 indicates to the card that the next command is an application specific command\r
16d88c2d 139 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
1bfda055 140 if (Status == EFI_SUCCESS) {\r
842b02d8
OM
141 DEBUG ((EFI_D_INFO, "Card should be SD\n"));\r
142 if (IsHCS) {\r
143 MmcHostInstance->CardInfo.CardType = SD_CARD_2;\r
144 } else {\r
145 MmcHostInstance->CardInfo.CardType = SD_CARD;\r
146 }\r
1bfda055 147\r
842b02d8
OM
148 // Note: The first time CmdArg will be zero\r
149 CmdArg = ((UINTN *) &(MmcHostInstance->CardInfo.OCRData))[0];\r
150 if (IsHCS) {\r
151 CmdArg |= BIT30;\r
152 }\r
153 Status = MmcHost->SendCommand (MmcHost, MMC_ACMD41, CmdArg);\r
154 if (!EFI_ERROR (Status)) {\r
155 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
156 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
157 }\r
1bfda055 158 } else {\r
842b02d8
OM
159 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
160 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
1bfda055 161\r
842b02d8
OM
162 Status = MmcHost->SendCommand (MmcHost, MMC_CMD1, 0x800000);\r
163 if (!EFI_ERROR (Status)) {\r
164 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_OCR, Response);\r
165 ((UINT32 *) &(MmcHostInstance->CardInfo.OCRData))[0] = Response[0];\r
166 }\r
1bfda055 167 }\r
1bfda055 168\r
6f711615 169 if (!EFI_ERROR (Status)) {\r
492e34a5 170 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
842b02d8
OM
171 MicroSecondDelay (1);\r
172 Timeout--;\r
e8e95df4 173 } else {\r
842b02d8
OM
174 if ((MmcHostInstance->CardInfo.CardType == SD_CARD_2) && (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1)) {\r
175 MmcHostInstance->CardInfo.CardType = SD_CARD_2_HIGH;\r
176 DEBUG ((EFI_D_ERROR, "High capacity card.\n"));\r
177 }\r
178 break; // The MMC/SD card is ready. Continue the Identification Mode\r
e8e95df4 179 }\r
1bfda055 180 } else {\r
6f711615 181 MicroSecondDelay (1);\r
e8e95df4 182 Timeout--;\r
1bfda055 183 }\r
e8e95df4 184 }\r
185\r
186 if (Timeout == 0) {\r
6f711615 187 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
e8e95df4 188 return EFI_NO_MEDIA;\r
189 } else {\r
6f711615 190 PrintOCR (Response[0]);\r
e8e95df4 191 }\r
192\r
193 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
6f711615 194 if (EFI_ERROR (Status)) {\r
195 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
e8e95df4 196 return Status;\r
197 }\r
198\r
16d88c2d 199 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
6f711615 200 if (EFI_ERROR (Status)) {\r
201 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
e8e95df4 202 return Status;\r
203 }\r
6f711615 204 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
842b02d8 205 PrintCID (Response);\r
e8e95df4 206\r
207 Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);\r
6f711615 208 if (EFI_ERROR (Status)) {\r
209 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
e8e95df4 210 return Status;\r
211 }\r
212\r
d8ad4736 213 //\r
214 // Note, SD specifications say that "if the command execution causes a state change, it\r
215 // will be visible to the host in the response to the next command"\r
216 // The status returned for this CMD3 will be 2 - identification\r
217 //\r
218 CmdArg = 1;\r
16d88c2d 219 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
6f711615 220 if (EFI_ERROR (Status)) {\r
221 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
d8ad4736 222 return Status;\r
e8e95df4 223 }\r
224\r
6f711615 225 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
226 PrintRCA (Response[0]);\r
d8ad4736 227\r
e8e95df4 228 // For MMC card, RCA is assigned by CMD3 while CMD3 dumps the RCA for SD card\r
229 if (MmcHostInstance->CardInfo.CardType != MMC_CARD) {\r
230 MmcHostInstance->CardInfo.RCA = Response[0] >> 16;\r
231 } else {\r
232 MmcHostInstance->CardInfo.RCA = CmdArg;\r
233 }\r
234\r
235 Status = MmcNotifyState (MmcHostInstance, MmcStandByState);\r
6f711615 236 if (EFI_ERROR (Status)) {\r
237 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
e8e95df4 238 return Status;\r
239 }\r
240\r
241 return EFI_SUCCESS;\r
1bfda055 242}\r
243\r
16d88c2d 244EFI_STATUS InitializeMmcDevice (\r
40842a5e 245 IN MMC_HOST_INSTANCE *MmcHostInstance\r
246 )\r
247{\r
248 UINT32 Response[4];\r
249 EFI_STATUS Status;\r
250 UINTN CardSize, NumBlocks, BlockSize, CmdArg;\r
251 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
842b02d8
OM
252 UINTN BlockCount;\r
253\r
254 BlockCount = 1;\r
40842a5e 255 MmcHost = MmcHostInstance->MmcHost;\r
256\r
257 MmcIdentificationMode (MmcHostInstance);\r
258\r
259 //Send a command to get Card specific data\r
260 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 261 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
6f711615 262 if (EFI_ERROR (Status)) {\r
842b02d8 263 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
40842a5e 264 return Status;\r
265 }\r
266 //Read Response\r
6f711615 267 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
842b02d8 268 PrintCSD (Response);\r
40842a5e 269\r
270 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
6f711615 271 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
40842a5e 272 NumBlocks = ((CardSize + 1) * 1024);\r
842b02d8 273 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
40842a5e 274 } else {\r
6f711615 275 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
276 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
842b02d8 277 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
40842a5e 278 }\r
279\r
280 //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
281 if (BlockSize > 512) {\r
6f711615 282 NumBlocks = MultU64x32 (NumBlocks, BlockSize/512);\r
40842a5e 283 BlockSize = 512;\r
284 }\r
285\r
286 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
287 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
16d88c2d 288 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
40842a5e 289 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
290 MmcHostInstance->BlockIo.Media->MediaId++;\r
291\r
292 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
16d88c2d 293 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
6f711615 294 if (EFI_ERROR (Status)) {\r
842b02d8 295 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
40842a5e 296 return Status;\r
297 }\r
298\r
299 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
6f711615 300 if (EFI_ERROR (Status)) {\r
842b02d8 301 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState\n"));\r
40842a5e 302 return Status;\r
303 }\r
304\r
305 // Set Block Length\r
16d88c2d 306 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
6f711615 307 if (EFI_ERROR (Status)) {\r
842b02d8
OM
308 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD16): Error MmcHostInstance->BlockIo.Media->BlockSize: %d and Error = %r\n",\r
309 MmcHostInstance->BlockIo.Media->BlockSize, Status));\r
40842a5e 310 return Status;\r
311 }\r
312\r
313 // Block Count (not used). Could return an error for SD card\r
314 if (MmcHostInstance->CardInfo.CardType == MMC_CARD) {\r
16d88c2d 315 MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
40842a5e 316 }\r
317\r
318 return EFI_SUCCESS;\r
319}\r
320\r
1bfda055 321EFI_STATUS\r
322EFIAPI\r
323MmcReset (\r
324 IN EFI_BLOCK_IO_PROTOCOL *This,\r
325 IN BOOLEAN ExtendedVerification\r
e8e95df4 326 )\r
327{\r
3de99375 328 MMC_HOST_INSTANCE *MmcHostInstance;\r
329\r
6f711615 330 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
3de99375 331\r
332 if (MmcHostInstance->MmcHost == NULL) {\r
333 // Nothing to do\r
334 return EFI_SUCCESS;\r
335 }\r
336\r
337 // If a card is not present then clear all media settings\r
16d88c2d 338 if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {\r
3de99375 339 MmcHostInstance->BlockIo.Media->MediaPresent = FALSE;\r
340 MmcHostInstance->BlockIo.Media->LastBlock = 0;\r
341 MmcHostInstance->BlockIo.Media->BlockSize = 512; // Should be zero but there is a bug in DiskIo\r
342 MmcHostInstance->BlockIo.Media->ReadOnly = FALSE;\r
343\r
344 // Indicate that the driver requires initialization\r
345 MmcHostInstance->State = MmcHwInitializationState;\r
346\r
347 return EFI_SUCCESS;\r
348 }\r
349\r
e8e95df4 350 // Implement me. Either send a CMD0 (could not work for some MMC host) or just turn off/turn\r
351 // on power and restart Identification mode\r
352 return EFI_SUCCESS;\r
1bfda055 353}\r
354\r
355EFI_STATUS\r
356MmcDetectCard (\r
357 EFI_MMC_HOST_PROTOCOL *MmcHost\r
358 )\r
359{\r
16d88c2d 360 if (!MmcHost->IsCardPresent (MmcHost)) {\r
e8e95df4 361 return EFI_NO_MEDIA;\r
362 } else {\r
363 return EFI_SUCCESS;\r
364 }\r
1bfda055 365}\r
366\r
9532373b
OM
367EFI_STATUS\r
368MmcStopTransmission (\r
369 EFI_MMC_HOST_PROTOCOL *MmcHost\r
370 )\r
371{\r
372 EFI_STATUS Status;\r
373 UINT32 Response[4];\r
374 // Command 12 - Stop transmission (ends read or write)\r
375 // Normally only needed for streaming transfers or after error.\r
376 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
377 if (!EFI_ERROR (Status)) {\r
378 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
379 }\r
380 return Status;\r
381}\r
382\r
1bfda055 383#define MMCI0_BLOCKLEN 512\r
384#define MMCI0_TIMEOUT 10000\r
385\r
e8e95df4 386EFI_STATUS\r
387MmcIoBlocks (\r
1bfda055 388 IN EFI_BLOCK_IO_PROTOCOL *This,\r
389 IN UINTN Transfer,\r
390 IN UINT32 MediaId,\r
391 IN EFI_LBA Lba,\r
392 IN UINTN BufferSize,\r
393 OUT VOID *Buffer\r
e8e95df4 394 )\r
395{\r
396 UINT32 Response[4];\r
397 EFI_STATUS Status;\r
40842a5e 398 UINTN CmdArg;\r
969ece79 399 INTN Timeout;\r
e8e95df4 400 UINTN Cmd;\r
401 MMC_HOST_INSTANCE *MmcHostInstance;\r
402 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
403 UINTN BytesRemainingToBeTransfered;\r
842b02d8 404 UINTN BlockCount;\r
e8e95df4 405\r
842b02d8 406 BlockCount = 1;\r
6f711615 407 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
842b02d8 408 ASSERT (MmcHostInstance != NULL);\r
e8e95df4 409 MmcHost = MmcHostInstance->MmcHost;\r
6f711615 410 ASSERT (MmcHost);\r
e8e95df4 411\r
5ab765a7 412 if (This->Media->MediaId != MediaId) {\r
413 return EFI_MEDIA_CHANGED;\r
414 }\r
415\r
842b02d8 416 if ((MmcHost == NULL) || (Buffer == NULL)) {\r
e8e95df4 417 return EFI_INVALID_PARAMETER;\r
418 }\r
419\r
420 // Check if a Card is Present\r
3de99375 421 if (!MmcHostInstance->BlockIo.Media->MediaPresent) {\r
e8e95df4 422 return EFI_NO_MEDIA;\r
423 }\r
424\r
969ece79 425 // All blocks must be within the device\r
842b02d8 426 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
969ece79 427 return EFI_INVALID_PARAMETER;\r
e8e95df4 428 }\r
429\r
842b02d8 430 if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
5ab765a7 431 return EFI_WRITE_PROTECTED;\r
969ece79 432 }\r
433\r
5ab765a7 434 // Reading 0 Byte is valid\r
435 if (BufferSize == 0) {\r
436 return EFI_SUCCESS;\r
969ece79 437 }\r
438\r
5ab765a7 439 // The buffer size must be an exact multiple of the block size\r
440 if ((BufferSize % This->Media->BlockSize) != 0) {\r
441 return EFI_BAD_BUFFER_SIZE;\r
442 }\r
443\r
444 // Check the alignment\r
445 if ((This->Media->IoAlign > 2) && (((UINTN)Buffer & (This->Media->IoAlign - 1)) != 0)) {\r
446 return EFI_INVALID_PARAMETER;\r
e8e95df4 447 }\r
448\r
449 BytesRemainingToBeTransfered = BufferSize;\r
450 while (BytesRemainingToBeTransfered > 0) {\r
451\r
452 // Check if the Card is in Ready status\r
453 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
454 Response[0] = 0;\r
455 Timeout = 20;\r
260675b0 456 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
6f711615 457 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
260675b0 458 && Timeout--) {\r
16d88c2d 459 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 460 if (!EFI_ERROR (Status)) {\r
461 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
e8e95df4 462 }\r
1bfda055 463 }\r
464\r
e8e95df4 465 if (0 == Timeout) {\r
6f711615 466 DEBUG ((EFI_D_ERROR, "The Card is busy\n"));\r
e8e95df4 467 return EFI_NOT_READY;\r
b9d5fe03 468 }\r
469\r
e8e95df4 470 //Set command argument based on the card access mode (Byte mode or Block mode)\r
471 if (MmcHostInstance->CardInfo.OCRData.AccessMode & BIT1) {\r
472 CmdArg = Lba;\r
473 } else {\r
474 CmdArg = Lba * This->Media->BlockSize;\r
475 }\r
1bfda055 476\r
e8e95df4 477 if (Transfer == MMC_IOBLOCKS_READ) {\r
e8e95df4 478 // Read a single block\r
479 Cmd = MMC_CMD17;\r
e8e95df4 480 } else {\r
e8e95df4 481 // Write a single block\r
482 Cmd = MMC_CMD24;\r
e8e95df4 483 }\r
16d88c2d 484 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
6f711615 485 if (EFI_ERROR (Status)) {\r
486 DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
e8e95df4 487 return Status;\r
488 }\r
1bfda055 489\r
e8e95df4 490 if (Transfer == MMC_IOBLOCKS_READ) {\r
e8e95df4 491 // Read one block of Data\r
6f711615 492 Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
493 if (EFI_ERROR (Status)) {\r
494 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
9532373b 495 MmcStopTransmission (MmcHost);\r
e8e95df4 496 return Status;\r
497 }\r
e8e95df4 498 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
6f711615 499 if (EFI_ERROR (Status)) {\r
500 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
e8e95df4 501 return Status;\r
502 }\r
503 } else {\r
e8e95df4 504 // Write one block of Data\r
6f711615 505 Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
506 if (EFI_ERROR (Status)) {\r
507 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
9532373b 508 MmcStopTransmission (MmcHost);\r
e8e95df4 509 return Status;\r
510 }\r
e8e95df4 511 }\r
1bfda055 512\r
e8e95df4 513 // Command 13 - Read status and wait for programming to complete (return to tran)\r
514 Timeout = MMCI0_TIMEOUT;\r
515 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
516 Response[0] = 0;\r
260675b0 517 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
6f711615 518 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
260675b0 519 && Timeout--) {\r
16d88c2d 520 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 521 if (!EFI_ERROR (Status)) {\r
699e34ad 522 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
523 if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
524 break; // Prevents delay once finished\r
525 }\r
e8e95df4 526 }\r
6f711615 527 NanoSecondDelay (100);\r
e8e95df4 528 }\r
1bfda055 529\r
e8e95df4 530 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
6f711615 531 if (EFI_ERROR (Status)) {\r
532 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
e8e95df4 533 return Status;\r
1bfda055 534 }\r
535\r
e8e95df4 536 BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
537 Lba += BlockCount;\r
538 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
539 }\r
540\r
541 return EFI_SUCCESS;\r
1bfda055 542}\r
543\r
544EFI_STATUS\r
545EFIAPI\r
546MmcReadBlocks (\r
547 IN EFI_BLOCK_IO_PROTOCOL *This,\r
548 IN UINT32 MediaId,\r
549 IN EFI_LBA Lba,\r
550 IN UINTN BufferSize,\r
551 OUT VOID *Buffer\r
e8e95df4 552 )\r
553{\r
554 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 555}\r
556\r
557EFI_STATUS\r
558EFIAPI\r
559MmcWriteBlocks (\r
560 IN EFI_BLOCK_IO_PROTOCOL *This,\r
561 IN UINT32 MediaId,\r
562 IN EFI_LBA Lba,\r
563 IN UINTN BufferSize,\r
564 IN VOID *Buffer\r
e8e95df4 565 )\r
566{\r
567 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 568}\r
569\r
570EFI_STATUS\r
571EFIAPI\r
572MmcFlushBlocks (\r
573 IN EFI_BLOCK_IO_PROTOCOL *This\r
e8e95df4 574 )\r
575{\r
576 return EFI_SUCCESS;\r
1bfda055 577}\r