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