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