]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/MmcDxe: Update Mmc code to conform to coding standard
[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
489#define MMCI0_BLOCKLEN 512\r
490#define MMCI0_TIMEOUT 10000\r
491\r
e8e95df4 492EFI_STATUS\r
493MmcIoBlocks (\r
1bfda055 494 IN EFI_BLOCK_IO_PROTOCOL *This,\r
495 IN UINTN Transfer,\r
496 IN UINT32 MediaId,\r
497 IN EFI_LBA Lba,\r
498 IN UINTN BufferSize,\r
499 OUT VOID *Buffer\r
e8e95df4 500 )\r
501{\r
502 UINT32 Response[4];\r
503 EFI_STATUS Status;\r
40842a5e 504 UINTN CmdArg;\r
969ece79 505 INTN Timeout;\r
e8e95df4 506 UINTN Cmd;\r
507 MMC_HOST_INSTANCE *MmcHostInstance;\r
508 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
509 UINTN BytesRemainingToBeTransfered;\r
842b02d8 510 UINTN BlockCount;\r
e8e95df4 511\r
842b02d8 512 BlockCount = 1;\r
6f711615 513 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
842b02d8 514 ASSERT (MmcHostInstance != NULL);\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
842b02d8 522 if ((MmcHost == NULL) || (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
842b02d8 532 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
969ece79 533 return EFI_INVALID_PARAMETER;\r
e8e95df4 534 }\r
535\r
842b02d8 536 if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
5ab765a7 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
e8e95df4 584 // Read a single block\r
585 Cmd = MMC_CMD17;\r
e8e95df4 586 } else {\r
e8e95df4 587 // Write a single block\r
588 Cmd = MMC_CMD24;\r
e8e95df4 589 }\r
16d88c2d 590 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
6f711615 591 if (EFI_ERROR (Status)) {\r
592 DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
e8e95df4 593 return Status;\r
594 }\r
1bfda055 595\r
e8e95df4 596 if (Transfer == MMC_IOBLOCKS_READ) {\r
e8e95df4 597 // Read one block of Data\r
6f711615 598 Status = MmcHost->ReadBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
599 if (EFI_ERROR (Status)) {\r
600 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Read Block Data and Status = %r\n", Status));\r
e8e95df4 601 return Status;\r
602 }\r
e8e95df4 603 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
6f711615 604 if (EFI_ERROR (Status)) {\r
605 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
e8e95df4 606 return Status;\r
607 }\r
608 } else {\r
e8e95df4 609 // Write one block of Data\r
6f711615 610 Status = MmcHost->WriteBlockData (MmcHost, Lba, This->Media->BlockSize, Buffer);\r
611 if (EFI_ERROR (Status)) {\r
612 DEBUG ((EFI_D_BLKIO, "MmcIoBlocks(): Error Write Block Data and Status = %r\n", Status));\r
e8e95df4 613 return Status;\r
614 }\r
e8e95df4 615 }\r
1bfda055 616\r
e8e95df4 617 // Command 12 - Stop transmission (ends read)\r
16d88c2d 618 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
6f711615 619 if (!EFI_ERROR (Status)) {\r
620 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
e8e95df4 621 }\r
1bfda055 622\r
e8e95df4 623 // Command 13 - Read status and wait for programming to complete (return to tran)\r
624 Timeout = MMCI0_TIMEOUT;\r
625 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
626 Response[0] = 0;\r
260675b0 627 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
6f711615 628 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
260675b0 629 && Timeout--) {\r
16d88c2d 630 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
6f711615 631 if (!EFI_ERROR (Status)) {\r
699e34ad 632 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
633 if ((Response[0] & MMC_R0_READY_FOR_DATA)) {\r
634 break; // Prevents delay once finished\r
635 }\r
e8e95df4 636 }\r
6f711615 637 NanoSecondDelay (100);\r
e8e95df4 638 }\r
1bfda055 639\r
e8e95df4 640 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
6f711615 641 if (EFI_ERROR (Status)) {\r
642 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
e8e95df4 643 return Status;\r
1bfda055 644 }\r
645\r
e8e95df4 646 BytesRemainingToBeTransfered -= This->Media->BlockSize;\r
647 Lba += BlockCount;\r
648 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
649 }\r
650\r
651 return EFI_SUCCESS;\r
1bfda055 652}\r
653\r
654EFI_STATUS\r
655EFIAPI\r
656MmcReadBlocks (\r
657 IN EFI_BLOCK_IO_PROTOCOL *This,\r
658 IN UINT32 MediaId,\r
659 IN EFI_LBA Lba,\r
660 IN UINTN BufferSize,\r
661 OUT VOID *Buffer\r
e8e95df4 662 )\r
663{\r
664 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 665}\r
666\r
667EFI_STATUS\r
668EFIAPI\r
669MmcWriteBlocks (\r
670 IN EFI_BLOCK_IO_PROTOCOL *This,\r
671 IN UINT32 MediaId,\r
672 IN EFI_LBA Lba,\r
673 IN UINTN BufferSize,\r
674 IN VOID *Buffer\r
e8e95df4 675 )\r
676{\r
677 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r
1bfda055 678}\r
679\r
680EFI_STATUS\r
681EFIAPI\r
682MmcFlushBlocks (\r
683 IN EFI_BLOCK_IO_PROTOCOL *This\r
e8e95df4 684 )\r
685{\r
686 return EFI_SUCCESS;\r
1bfda055 687}\r