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