]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - EmbeddedPkg/Universal/MmcDxe/MmcBlockIo.c
EmbeddedPkg/MmcDxe: Update Mmc code to conform to coding standard
[mirror_edk2.git] / EmbeddedPkg / Universal / MmcDxe / MmcBlockIo.c
... / ...
CommitLineData
1/** @file\r
2*\r
3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
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#define MAX_RETRY_COUNT 1000\r
23#define CMD_RETRY_COUNT 20\r
24\r
25EFI_STATUS\r
26MmcNotifyState (\r
27 IN MMC_HOST_INSTANCE *MmcHostInstance,\r
28 IN MMC_STATE State\r
29 )\r
30{\r
31 MmcHostInstance->State = State;\r
32 return MmcHostInstance->MmcHost->NotifyState (MmcHostInstance->MmcHost, State);\r
33}\r
34\r
35VOID\r
36PrintOCR (\r
37 IN UINT32 Ocr\r
38 )\r
39{\r
40 UINTN MinV;\r
41 UINTN MaxV;\r
42 UINTN Volts;\r
43 UINTN Loop;\r
44\r
45 MinV = 36; // 3.6\r
46 MaxV = 20; // 2.0\r
47 Volts = 20; // 2.0\r
48\r
49 // The MMC register bits [23:8] indicate the working range of the card\r
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
54 }\r
55 Volts = Volts + 1;\r
56 }\r
57\r
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
60 if (((Ocr >> 29) & 3) == 0) {\r
61 DEBUG ((EFI_D_ERROR, "\t- AccessMode: Byte Mode\n"));\r
62 } else {\r
63 DEBUG ((EFI_D_ERROR, "\t- AccessMode: Block Mode (0x%X)\n", ((Ocr >> 29) & 3)));\r
64 }\r
65\r
66 if (Ocr & MMC_OCR_POWERUP) {\r
67 DEBUG ((EFI_D_ERROR, "\t- PowerUp\n"));\r
68 } else {\r
69 DEBUG ((EFI_D_ERROR, "\t- Voltage Not Supported\n"));\r
70 }\r
71}\r
72\r
73VOID PrintCID (\r
74 IN UINT32* Cid\r
75 )\r
76{\r
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
83}\r
84\r
85#if !defined(MDEPKG_NDEBUG)\r
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
90#endif\r
91\r
92VOID\r
93PrintCSD (\r
94 IN UINT32* Csd\r
95 )\r
96{\r
97 UINTN Value;\r
98\r
99 if (((Csd[2] >> 30) & 0x3) == 0) {\r
100 DEBUG ((EFI_D_ERROR, "- PrintCSD Version 1.01-1.10/Version 2.00/Standard Capacity\n"));\r
101 } else if (((Csd[2] >> 30) & 0x3) == 1) {\r
102 DEBUG ((EFI_D_ERROR, "- PrintCSD Version 2.00/High Capacity\n"));\r
103 } else {\r
104 DEBUG ((EFI_D_ERROR, "- PrintCSD Version Higher than v3.3\n"));\r
105 }\r
106\r
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
111\r
112 if (!MMC_CSD_GET_FILEFORMATGRP (Csd)) {\r
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
118 } else {\r
119 DEBUG ((EFI_D_ERROR, "\t- Format: Reserved\n"));\r
120 }\r
121}\r
122\r
123VOID\r
124PrintRCA (\r
125 IN UINT32 Rca\r
126 )\r
127{\r
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
131}\r
132\r
133VOID\r
134PrintResponseR1 (\r
135 IN UINT32 Response\r
136 )\r
137{\r
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
153}\r
154\r
155EFI_STATUS\r
156EFIAPI\r
157MmcGetCardStatus (\r
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
173 if (MmcHostInstance->State != MmcHwInitializationState) {\r
174 //Get the Status of the card.\r
175 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
176 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
177 if (EFI_ERROR (Status)) {\r
178 DEBUG ((EFI_D_ERROR, "MmcGetCardStatus(MMC_CMD13): Error and Status = %r\n", Status));\r
179 return Status;\r
180 }\r
181\r
182 //Read Response\r
183 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
184 PrintResponseR1 (Response[0]);\r
185 }\r
186\r
187 return Status;\r
188}\r
189\r
190EFI_STATUS\r
191EFIAPI\r
192MmcIdentificationMode (\r
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
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
215 if (EFI_ERROR (Status)) {\r
216 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcHwInitializationState\n"));\r
217 return Status;\r
218 }\r
219 }\r
220\r
221 Status = MmcHost->SendCommand (MmcHost, MMC_CMD0, 0);\r
222 if (EFI_ERROR (Status)) {\r
223 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD0): Error\n"));\r
224 return Status;\r
225 }\r
226\r
227 Status = MmcNotifyState (MmcHostInstance, MmcIdleState);\r
228 if (EFI_ERROR (Status)) {\r
229 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdleState\n"));\r
230 return Status;\r
231 }\r
232\r
233 // Are we using SDIO ?\r
234 Status = MmcHost->SendCommand (MmcHost, MMC_CMD5, 0);\r
235 if (Status == EFI_SUCCESS) {\r
236 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD5): Error - SDIO not supported.\n"));\r
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
242 Status = MmcHost->SendCommand (MmcHost, MMC_CMD8, CmdArg);\r
243 if (Status == EFI_SUCCESS) {\r
244 DEBUG ((EFI_D_ERROR, "Card is SD2.0 => Supports high capacity\n"));\r
245 IsHCS = TRUE;\r
246 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R7, Response);\r
247 PrintResponseR1 (Response[0]);\r
248 //check if it is valid response\r
249 if (Response[0] != CmdArg) {\r
250 DEBUG ((EFI_D_ERROR, "The Card is not usable\n"));\r
251 return EFI_UNSUPPORTED;\r
252 }\r
253 } else {\r
254 DEBUG ((EFI_D_ERROR, "Not a SD2.0 Card\n"));\r
255 }\r
256\r
257 // We need to wait for the MMC or SD card is ready => (gCardInfo.OCRData.PowerUp == 1)\r
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
261 Status = MmcHost->SendCommand (MmcHost, MMC_CMD55, 0);\r
262 if (Status == EFI_SUCCESS) {\r
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
269\r
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
280 } else {\r
281 DEBUG ((EFI_D_INFO, "Card should be MMC\n"));\r
282 MmcHostInstance->CardInfo.CardType = MMC_CARD;\r
283\r
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
289 }\r
290\r
291 if (!EFI_ERROR (Status)) {\r
292 if (!MmcHostInstance->CardInfo.OCRData.PowerUp) {\r
293 MicroSecondDelay (1);\r
294 Timeout--;\r
295 } else {\r
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
301 }\r
302 } else {\r
303 MicroSecondDelay (1);\r
304 Timeout--;\r
305 }\r
306 }\r
307\r
308 if (Timeout == 0) {\r
309 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(): No Card\n"));\r
310 return EFI_NO_MEDIA;\r
311 } else {\r
312 PrintOCR (Response[0]);\r
313 }\r
314\r
315 Status = MmcNotifyState (MmcHostInstance, MmcReadyState);\r
316 if (EFI_ERROR (Status)) {\r
317 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcReadyState\n"));\r
318 return Status;\r
319 }\r
320\r
321 Status = MmcHost->SendCommand (MmcHost, MMC_CMD2, 0);\r
322 if (EFI_ERROR (Status)) {\r
323 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD2): Error\n"));\r
324 return Status;\r
325 }\r
326 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CID, Response);\r
327 PrintCID (Response);\r
328\r
329 Status = MmcNotifyState (MmcHostInstance, MmcIdentificationState);\r
330 if (EFI_ERROR (Status)) {\r
331 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcIdentificationState\n"));\r
332 return Status;\r
333 }\r
334\r
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
341 Status = MmcHost->SendCommand (MmcHost, MMC_CMD3, CmdArg);\r
342 if (EFI_ERROR (Status)) {\r
343 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode(MMC_CMD3): Error\n"));\r
344 return Status;\r
345 }\r
346\r
347 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_RCA, Response);\r
348 PrintRCA (Response[0]);\r
349\r
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
358 if (EFI_ERROR (Status)) {\r
359 DEBUG ((EFI_D_ERROR, "MmcIdentificationMode() : Error MmcStandByState\n"));\r
360 return Status;\r
361 }\r
362\r
363 return EFI_SUCCESS;\r
364}\r
365\r
366EFI_STATUS InitializeMmcDevice (\r
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
374 UINTN BlockCount;\r
375\r
376 BlockCount = 1;\r
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
383 Status = MmcHost->SendCommand (MmcHost, MMC_CMD9, CmdArg);\r
384 if (EFI_ERROR (Status)) {\r
385 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD9): Error, Status=%r\n", Status));\r
386 return Status;\r
387 }\r
388 //Read Response\r
389 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_CSD, Response);\r
390 PrintCSD (Response);\r
391\r
392 if (MmcHostInstance->CardInfo.CardType == SD_CARD_2_HIGH) {\r
393 CardSize = HC_MMC_CSD_GET_DEVICESIZE (Response);\r
394 NumBlocks = ((CardSize + 1) * 1024);\r
395 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
396 } else {\r
397 CardSize = MMC_CSD_GET_DEVICESIZE (Response);\r
398 NumBlocks = (CardSize + 1) * (1 << (MMC_CSD_GET_DEVICESIZEMULT (Response) + 2));\r
399 BlockSize = 1 << MMC_CSD_GET_READBLLEN (Response);\r
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
404 NumBlocks = MultU64x32 (NumBlocks, BlockSize/512);\r
405 BlockSize = 512;\r
406 }\r
407\r
408 MmcHostInstance->BlockIo.Media->LastBlock = (NumBlocks - 1);\r
409 MmcHostInstance->BlockIo.Media->BlockSize = BlockSize;\r
410 MmcHostInstance->BlockIo.Media->ReadOnly = MmcHost->IsReadOnly (MmcHost);\r
411 MmcHostInstance->BlockIo.Media->MediaPresent = TRUE;\r
412 MmcHostInstance->BlockIo.Media->MediaId++;\r
413\r
414 CmdArg = MmcHostInstance->CardInfo.RCA << 16;\r
415 Status = MmcHost->SendCommand (MmcHost, MMC_CMD7, CmdArg);\r
416 if (EFI_ERROR (Status)) {\r
417 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(MMC_CMD7): Error and Status = %r\n", Status));\r
418 return Status;\r
419 }\r
420\r
421 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
422 if (EFI_ERROR (Status)) {\r
423 DEBUG((EFI_D_ERROR, "InitializeMmcDevice(): Error MmcTransferState\n"));\r
424 return Status;\r
425 }\r
426\r
427 // Set Block Length\r
428 Status = MmcHost->SendCommand (MmcHost, MMC_CMD16, MmcHostInstance->BlockIo.Media->BlockSize);\r
429 if (EFI_ERROR (Status)) {\r
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
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
437 MmcHost->SendCommand (MmcHost, MMC_CMD23, BlockCount);\r
438 }\r
439\r
440 return EFI_SUCCESS;\r
441}\r
442\r
443EFI_STATUS\r
444EFIAPI\r
445MmcReset (\r
446 IN EFI_BLOCK_IO_PROTOCOL *This,\r
447 IN BOOLEAN ExtendedVerification\r
448 )\r
449{\r
450 MMC_HOST_INSTANCE *MmcHostInstance;\r
451\r
452 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
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
460 if (!MmcHostInstance->MmcHost->IsCardPresent (MmcHostInstance->MmcHost)) {\r
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
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
475}\r
476\r
477EFI_STATUS\r
478MmcDetectCard (\r
479 EFI_MMC_HOST_PROTOCOL *MmcHost\r
480 )\r
481{\r
482 if (!MmcHost->IsCardPresent (MmcHost)) {\r
483 return EFI_NO_MEDIA;\r
484 } else {\r
485 return EFI_SUCCESS;\r
486 }\r
487}\r
488\r
489#define MMCI0_BLOCKLEN 512\r
490#define MMCI0_TIMEOUT 10000\r
491\r
492EFI_STATUS\r
493MmcIoBlocks (\r
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
500 )\r
501{\r
502 UINT32 Response[4];\r
503 EFI_STATUS Status;\r
504 UINTN CmdArg;\r
505 INTN Timeout;\r
506 UINTN Cmd;\r
507 MMC_HOST_INSTANCE *MmcHostInstance;\r
508 EFI_MMC_HOST_PROTOCOL *MmcHost;\r
509 UINTN BytesRemainingToBeTransfered;\r
510 UINTN BlockCount;\r
511\r
512 BlockCount = 1;\r
513 MmcHostInstance = MMC_HOST_INSTANCE_FROM_BLOCK_IO_THIS (This);\r
514 ASSERT (MmcHostInstance != NULL);\r
515 MmcHost = MmcHostInstance->MmcHost;\r
516 ASSERT (MmcHost);\r
517\r
518 if (This->Media->MediaId != MediaId) {\r
519 return EFI_MEDIA_CHANGED;\r
520 }\r
521\r
522 if ((MmcHost == NULL) || (Buffer == NULL)) {\r
523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
526 // Check if a Card is Present\r
527 if (!MmcHostInstance->BlockIo.Media->MediaPresent) {\r
528 return EFI_NO_MEDIA;\r
529 }\r
530\r
531 // All blocks must be within the device\r
532 if ((Lba + (BufferSize / This->Media->BlockSize)) > (This->Media->LastBlock + 1)) {\r
533 return EFI_INVALID_PARAMETER;\r
534 }\r
535\r
536 if ((Transfer == MMC_IOBLOCKS_WRITE) && (This->Media->ReadOnly == TRUE)) {\r
537 return EFI_WRITE_PROTECTED;\r
538 }\r
539\r
540 // Reading 0 Byte is valid\r
541 if (BufferSize == 0) {\r
542 return EFI_SUCCESS;\r
543 }\r
544\r
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
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
562 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
563 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
564 && Timeout--) {\r
565 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
566 if (!EFI_ERROR (Status)) {\r
567 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1, Response);\r
568 }\r
569 }\r
570\r
571 if (0 == Timeout) {\r
572 DEBUG ((EFI_D_ERROR, "The Card is busy\n"));\r
573 return EFI_NOT_READY;\r
574 }\r
575\r
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
582\r
583 if (Transfer == MMC_IOBLOCKS_READ) {\r
584 // Read a single block\r
585 Cmd = MMC_CMD17;\r
586 } else {\r
587 // Write a single block\r
588 Cmd = MMC_CMD24;\r
589 }\r
590 Status = MmcHost->SendCommand (MmcHost, Cmd, CmdArg);\r
591 if (EFI_ERROR (Status)) {\r
592 DEBUG ((EFI_D_ERROR, "MmcIoBlocks(MMC_CMD%d): Error %r\n", Cmd, Status));\r
593 return Status;\r
594 }\r
595\r
596 if (Transfer == MMC_IOBLOCKS_READ) {\r
597 // Read one block of Data\r
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
601 return Status;\r
602 }\r
603 Status = MmcNotifyState (MmcHostInstance, MmcProgrammingState);\r
604 if (EFI_ERROR (Status)) {\r
605 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcProgrammingState\n"));\r
606 return Status;\r
607 }\r
608 } else {\r
609 // Write one block of Data\r
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
613 return Status;\r
614 }\r
615 }\r
616\r
617 // Command 12 - Stop transmission (ends read)\r
618 Status = MmcHost->SendCommand (MmcHost, MMC_CMD12, 0);\r
619 if (!EFI_ERROR (Status)) {\r
620 MmcHost->ReceiveResponse (MmcHost, MMC_RESPONSE_TYPE_R1b, Response);\r
621 }\r
622\r
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
627 while( (!(Response[0] & MMC_R0_READY_FOR_DATA))\r
628 && (MMC_R0_CURRENTSTATE (Response) != MMC_R0_STATE_TRAN)\r
629 && Timeout--) {\r
630 Status = MmcHost->SendCommand (MmcHost, MMC_CMD13, CmdArg);\r
631 if (!EFI_ERROR (Status)) {\r
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
636 }\r
637 NanoSecondDelay (100);\r
638 }\r
639\r
640 Status = MmcNotifyState (MmcHostInstance, MmcTransferState);\r
641 if (EFI_ERROR (Status)) {\r
642 DEBUG ((EFI_D_ERROR, "MmcIoBlocks() : Error MmcTransferState\n"));\r
643 return Status;\r
644 }\r
645\r
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
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
662 )\r
663{\r
664 return MmcIoBlocks (This, MMC_IOBLOCKS_READ, MediaId, Lba, BufferSize, Buffer);\r
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
675 )\r
676{\r
677 return MmcIoBlocks (This, MMC_IOBLOCKS_WRITE, MediaId, Lba, BufferSize, Buffer);\r
678}\r
679\r
680EFI_STATUS\r
681EFIAPI\r
682MmcFlushBlocks (\r
683 IN EFI_BLOCK_IO_PROTOCOL *This\r
684 )\r
685{\r
686 return EFI_SUCCESS;\r
687}\r