ARM Packages: Fixed line endings
[mirror_edk2.git] / Omap35xxPkg / MMCHSDxe / MMCHS.c
CommitLineData
1e57a462 1/** @file\r
2 MMC/SD Card driver for OMAP 35xx (SDIO not supported)\r
3\r
4 This driver always produces a BlockIo protocol but it starts off with no Media\r
5 present. A TimerCallBack detects when media is inserted or removed and after \r
6 a media change event a call to BlockIo ReadBlocks/WriteBlocks will cause the \r
7 media to be detected (or removed) and the BlockIo Media structure will get\r
8 updated. No MMC/SD Card harward registers are updated until the first BlockIo\r
9 ReadBlocks/WriteBlocks after media has been insterted (booting with a card \r
10 plugged in counts as an insertion event). \r
11\r
12 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
13 \r
14 This program and the accompanying materials\r
15 are licensed and made available under the terms and conditions of the BSD License\r
16 which accompanies this distribution. The full text of the license may be found at\r
17 http://opensource.org/licenses/bsd-license.php\r
18\r
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
21\r
22**/\r
23\r
24#include "MMCHS.h"\r
25\r
26EFI_BLOCK_IO_MEDIA gMMCHSMedia = {\r
27 SIGNATURE_32('s','d','i','o'), // MediaId\r
28 TRUE, // RemovableMedia\r
29 FALSE, // MediaPresent\r
30 FALSE, // LogicalPartition\r
31 FALSE, // ReadOnly\r
32 FALSE, // WriteCaching\r
33 512, // BlockSize\r
34 4, // IoAlign\r
35 0, // Pad\r
36 0 // LastBlock\r
37};\r
38\r
39typedef struct {\r
40 VENDOR_DEVICE_PATH Mmc;\r
41 EFI_DEVICE_PATH End;\r
42} MMCHS_DEVICE_PATH;\r
43\r
44MMCHS_DEVICE_PATH gMmcHsDevicePath = {\r
45 {\r
46 HARDWARE_DEVICE_PATH,\r
47 HW_VENDOR_DP,\r
48 (UINT8)(sizeof(VENDOR_DEVICE_PATH)),\r
49 (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),\r
50 0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 \r
51 },\r
52 {\r
53 END_DEVICE_PATH_TYPE,\r
54 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
55 sizeof (EFI_DEVICE_PATH_PROTOCOL),\r
56 0\r
57 }\r
58};\r
59\r
60CARD_INFO gCardInfo;\r
61EMBEDDED_EXTERNAL_DEVICE *gTPS65950;\r
62EFI_EVENT gTimerEvent;\r
63BOOLEAN gMediaChange = FALSE;\r
64\r
65//\r
66// Internal Functions\r
67//\r
68\r
69\r
70VOID\r
71ParseCardCIDData (\r
72 UINT32 Response0, \r
73 UINT32 Response1, \r
74 UINT32 Response2,\r
75 UINT32 Response3\r
76 )\r
77{\r
78 gCardInfo.CIDData.MDT = ((Response0 >> 8) & 0xFFF);\r
79 gCardInfo.CIDData.PSN = (((Response0 >> 24) & 0xFF) | ((Response1 & 0xFFFFFF) << 8));\r
80 gCardInfo.CIDData.PRV = ((Response1 >> 24) & 0xFF);\r
81 gCardInfo.CIDData.PNM[4] = ((Response2) & 0xFF);\r
82 gCardInfo.CIDData.PNM[3] = ((Response2 >> 8) & 0xFF);\r
83 gCardInfo.CIDData.PNM[2] = ((Response2 >> 16) & 0xFF);\r
84 gCardInfo.CIDData.PNM[1] = ((Response2 >> 24) & 0xFF);\r
85 gCardInfo.CIDData.PNM[0] = ((Response3) & 0xFF);\r
86 gCardInfo.CIDData.OID = ((Response3 >> 8) & 0xFFFF);\r
87 gCardInfo.CIDData.MID = ((Response3 >> 24) & 0xFF);\r
88}\r
89\r
90\r
91VOID\r
92UpdateMMCHSClkFrequency (\r
93 UINTN NewCLKD\r
94 )\r
95{\r
96 //Set Clock enable to 0x0 to not provide the clock to the card\r
97 MmioAnd32 (MMCHS_SYSCTL, ~CEN);\r
98\r
99 //Set new clock frequency.\r
100 MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6); \r
101\r
102 //Poll till Internal Clock Stable\r
103 while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);\r
104\r
105 //Set Clock enable to 0x1 to provide the clock to the card\r
106 MmioOr32 (MMCHS_SYSCTL, CEN);\r
107}\r
108\r
109\r
110EFI_STATUS\r
111SendCmd (\r
112 UINTN Cmd,\r
113 UINTN CmdInterruptEnableVal,\r
114 UINTN CmdArgument\r
115 )\r
116{\r
117 UINTN MmcStatus;\r
118 UINTN RetryCount = 0;\r
119\r
120 //Check if command line is in use or not. Poll till command line is available.\r
121 while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);\r
122\r
123 //Provide the block size.\r
124 MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);\r
125\r
126 //Setting Data timeout counter value to max value.\r
127 MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);\r
128\r
129 //Clear Status register.\r
130 MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);\r
131\r
132 //Set command argument register\r
133 MmioWrite32 (MMCHS_ARG, CmdArgument);\r
134\r
135 //Enable interrupt enable events to occur\r
136 MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);\r
137\r
138 //Send a command\r
139 MmioWrite32 (MMCHS_CMD, Cmd);\r
140\r
141 //Check for the command status.\r
142 while (RetryCount < MAX_RETRY_COUNT) {\r
143 do {\r
144 MmcStatus = MmioRead32 (MMCHS_STAT);\r
145 } while (MmcStatus == 0);\r
146\r
147 //Read status of command response\r
148 if ((MmcStatus & ERRI) != 0) {\r
149\r
150 //Perform soft-reset for mmci_cmd line.\r
151 MmioOr32 (MMCHS_SYSCTL, SRC);\r
152 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
153\r
154 DEBUG ((EFI_D_INFO, "MmcStatus: %x\n", MmcStatus));\r
155 return EFI_DEVICE_ERROR;\r
156 }\r
157\r
158 //Check if command is completed.\r
159 if ((MmcStatus & CC) == CC) {\r
160 MmioWrite32 (MMCHS_STAT, CC);\r
161 break;\r
162 }\r
163\r
164 RetryCount++;\r
165 }\r
166\r
167 if (RetryCount == MAX_RETRY_COUNT) {\r
168 return EFI_TIMEOUT;\r
169 }\r
170\r
171 return EFI_SUCCESS;\r
172}\r
173\r
174\r
175VOID\r
176GetBlockInformation (\r
177 UINTN *BlockSize,\r
178 UINTN *NumBlocks\r
179 )\r
180{\r
181 CSD_SDV2 *CsdSDV2Data;\r
182 UINTN CardSize;\r
183\r
184 if (gCardInfo.CardType == SD_CARD_2_HIGH) {\r
185 CsdSDV2Data = (CSD_SDV2 *)&gCardInfo.CSDData;\r
186\r
187 //Populate BlockSize.\r
188 *BlockSize = (0x1UL << CsdSDV2Data->READ_BL_LEN);\r
189\r
190 //Calculate Total number of blocks.\r
191 CardSize = CsdSDV2Data->C_SIZELow16 | (CsdSDV2Data->C_SIZEHigh6 << 2);\r
192 *NumBlocks = ((CardSize + 1) * 1024);\r
193 } else {\r
194 //Populate BlockSize.\r
195 *BlockSize = (0x1UL << gCardInfo.CSDData.READ_BL_LEN);\r
196\r
197 //Calculate Total number of blocks.\r
198 CardSize = gCardInfo.CSDData.C_SIZELow2 | (gCardInfo.CSDData.C_SIZEHigh10 << 2);\r
199 *NumBlocks = (CardSize + 1) * (1 << (gCardInfo.CSDData.C_SIZE_MULT + 2));\r
200 }\r
201\r
202 //For >=2G card, BlockSize may be 1K, but the transfer size is 512 bytes.\r
203 if (*BlockSize > 512) {\r
204 *NumBlocks = MultU64x32(*NumBlocks, *BlockSize/2);\r
205 *BlockSize = 512;\r
206 }\r
207\r
208 DEBUG ((EFI_D_INFO, "Card type: %x, BlockSize: %x, NumBlocks: %x\n", gCardInfo.CardType, *BlockSize, *NumBlocks));\r
209}\r
210\r
211\r
212VOID\r
213CalculateCardCLKD (\r
214 UINTN *ClockFrequencySelect\r
215 )\r
216{\r
217 UINT8 MaxDataTransferRate;\r
218 UINTN TransferRateValue = 0;\r
219 UINTN TimeValue = 0 ;\r
220 UINTN Frequency = 0;\r
221\r
222 MaxDataTransferRate = gCardInfo.CSDData.TRAN_SPEED;\r
223\r
224 // For SD Cards we would need to send CMD6 to set\r
225 // speeds abouve 25MHz. High Speed mode 50 MHz and up\r
226\r
227 //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)\r
228 switch (MaxDataTransferRate & 0x7) {\r
229 case 0:\r
230 TransferRateValue = 100 * 1000;\r
231 break;\r
232\r
233 case 1:\r
234 TransferRateValue = 1 * 1000 * 1000;\r
235 break;\r
236\r
237 case 2:\r
238 TransferRateValue = 10 * 1000 * 1000;\r
239 break;\r
240\r
241 case 3:\r
242 TransferRateValue = 100 * 1000 * 1000;\r
243 break;\r
244\r
245 default:\r
246 DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));\r
247 ASSERT(FALSE);\r
248 }\r
249\r
250 //Calculate Time value (Bits 6:3 of TRAN_SPEED)\r
251 switch ((MaxDataTransferRate >> 3) & 0xF) {\r
252 case 1:\r
253 TimeValue = 10;\r
254 break;\r
255\r
256 case 2:\r
257 TimeValue = 12;\r
258 break;\r
259\r
260 case 3:\r
261 TimeValue = 13;\r
262 break;\r
263\r
264 case 4:\r
265 TimeValue = 15;\r
266 break;\r
267\r
268 case 5:\r
269 TimeValue = 20;\r
270 break;\r
271\r
272 case 6:\r
273 TimeValue = 25;\r
274 break;\r
275\r
276 case 7:\r
277 TimeValue = 30;\r
278 break;\r
279\r
280 case 8:\r
281 TimeValue = 35;\r
282 break;\r
283\r
284 case 9:\r
285 TimeValue = 40;\r
286 break;\r
287\r
288 case 10:\r
289 TimeValue = 45;\r
290 break;\r
291\r
292 case 11:\r
293 TimeValue = 50;\r
294 break;\r
295\r
296 case 12:\r
297 TimeValue = 55;\r
298 break;\r
299\r
300 case 13:\r
301 TimeValue = 60;\r
302 break;\r
303\r
304 case 14:\r
305 TimeValue = 70;\r
306 break;\r
307\r
308 case 15:\r
309 TimeValue = 80;\r
310 break;\r
311\r
312 default:\r
313 DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));\r
314 ASSERT(FALSE);\r
315 }\r
316\r
317 Frequency = TransferRateValue * TimeValue/10;\r
318\r
319 //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.\r
320 *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);\r
321\r
322 DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));\r
323}\r
324\r
325\r
326VOID\r
327GetCardConfigurationData (\r
328 VOID\r
329 )\r
330{\r
331 UINTN BlockSize;\r
332 UINTN NumBlocks;\r
333 UINTN ClockFrequencySelect;\r
334\r
335 //Calculate BlockSize and Total number of blocks in the detected card.\r
336 GetBlockInformation(&BlockSize, &NumBlocks);\r
337 gCardInfo.BlockSize = BlockSize;\r
338 gCardInfo.NumBlocks = NumBlocks;\r
339\r
340 //Calculate Card clock divider value.\r
341 CalculateCardCLKD(&ClockFrequencySelect);\r
342 gCardInfo.ClockFrequencySelect = ClockFrequencySelect;\r
343}\r
344\r
345\r
346EFI_STATUS\r
347InitializeMMCHS (\r
348 VOID\r
349 )\r
350{\r
351 UINT8 Data = 0;\r
352 EFI_STATUS Status;\r
353\r
354 //Select Device group to belong to P1 device group in Power IC.\r
355 Data = DEV_GRP_P1;\r
356 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);\r
357 ASSERT_EFI_ERROR(Status);\r
358\r
359 //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.\r
360 Data = VSEL_3_00V;\r
361 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);\r
362 ASSERT_EFI_ERROR(Status);\r
363 \r
364 //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.\r
365 MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));\r
366\r
367 // Enable WP GPIO\r
368 MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);\r
369\r
370 // Enable Card Detect\r
371 Data = CARD_DETECT_ENABLE;\r
372 gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);\r
373\r
374\r
375 return Status;\r
376}\r
377\r
378\r
379EFI_STATUS\r
380PerformCardIdenfication (\r
381 VOID\r
382 )\r
383{\r
384 EFI_STATUS Status;\r
385 UINTN CmdArgument = 0;\r
386 UINTN Response = 0;\r
387 UINTN RetryCount = 0;\r
388 BOOLEAN SDCmd8Supported = FALSE;\r
389\r
390 //Enable interrupts.\r
391 MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |\r
392 CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));\r
393\r
394 //Controller INIT procedure start.\r
395 MmioOr32 (MMCHS_CON, INIT);\r
396 MmioWrite32 (MMCHS_CMD, 0x00000000);\r
397 while (!(MmioRead32 (MMCHS_STAT) & CC));\r
398\r
399 //Wait for 1 ms\r
400 gBS->Stall(1000);\r
401\r
402 //Set CC bit to 0x1 to clear the flag\r
403 MmioOr32 (MMCHS_STAT, CC);\r
404\r
405 //Retry INIT procedure.\r
406 MmioWrite32 (MMCHS_CMD, 0x00000000);\r
407 while (!(MmioRead32 (MMCHS_STAT) & CC));\r
408\r
409 //End initialization sequence\r
410 MmioAnd32 (MMCHS_CON, ~INIT);\r
411\r
412 MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));\r
413\r
414 //Change clock frequency to 400KHz to fit protocol\r
415 UpdateMMCHSClkFrequency(CLKD_400KHZ);\r
416\r
417 MmioOr32 (MMCHS_CON, OD);\r
418\r
419 //Send CMD0 command.\r
420 Status = SendCmd (CMD0, CMD0_INT_EN, CmdArgument);\r
421 if (EFI_ERROR(Status)) {\r
422 DEBUG ((EFI_D_ERROR, "Cmd0 fails.\n"));\r
423 return Status;\r
424 }\r
425\r
426 DEBUG ((EFI_D_INFO, "CMD0 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
427\r
428 //Send CMD5 command. \r
429 Status = SendCmd (CMD5, CMD5_INT_EN, CmdArgument);\r
430 if (Status == EFI_SUCCESS) {\r
431 DEBUG ((EFI_D_ERROR, "CMD5 Success. SDIO card. Follow SDIO card specification.\n"));\r
432 DEBUG ((EFI_D_INFO, "CMD5 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
433 //NOTE: Returning unsupported error for now. Need to implement SDIO specification.\r
434 return EFI_UNSUPPORTED; \r
435 } else {\r
436 DEBUG ((EFI_D_INFO, "CMD5 fails. Not an SDIO card.\n"));\r
437 }\r
438\r
439 MmioOr32 (MMCHS_SYSCTL, SRC);\r
440 gBS->Stall(1000);\r
441 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
442\r
443 //Send CMD8 command. (New v2.00 command for Voltage check)\r
444 //Only 2.7V - 3.6V is supported for SD2.0, only SD 2.0 card can pass.\r
445 //MMC & SD1.1 card will fail this command.\r
446 CmdArgument = CMD8_ARG;\r
447 Status = SendCmd (CMD8, CMD8_INT_EN, CmdArgument);\r
448 if (Status == EFI_SUCCESS) {\r
449 Response = MmioRead32 (MMCHS_RSP10);\r
450 DEBUG ((EFI_D_INFO, "CMD8 success. CMD8 response: %x\n", Response));\r
451 if (Response != CmdArgument) {\r
452 return EFI_DEVICE_ERROR;\r
453 }\r
454 DEBUG ((EFI_D_INFO, "Card is SD2.0\n"));\r
455 SDCmd8Supported = TRUE; //Supports high capacity.\r
456 } else {\r
457 DEBUG ((EFI_D_INFO, "CMD8 fails. Not an SD2.0 card.\n"));\r
458 }\r
459\r
460 MmioOr32 (MMCHS_SYSCTL, SRC);\r
461 gBS->Stall(1000);\r
462 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
463\r
464 //Poll till card is busy\r
465 while (RetryCount < MAX_RETRY_COUNT) {\r
466 //Send CMD55 command. \r
467 CmdArgument = 0;\r
468 Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);\r
469 if (Status == EFI_SUCCESS) {\r
470 DEBUG ((EFI_D_INFO, "CMD55 success. CMD55 response: %x\n", MmioRead32 (MMCHS_RSP10)));\r
471 gCardInfo.CardType = SD_CARD;\r
472 } else {\r
473 DEBUG ((EFI_D_INFO, "CMD55 fails.\n"));\r
474 gCardInfo.CardType = MMC_CARD;\r
475 }\r
476\r
477 //Send appropriate command for the card type which got detected.\r
478 if (gCardInfo.CardType == SD_CARD) {\r
479 CmdArgument = ((UINTN *) &(gCardInfo.OCRData))[0];\r
480\r
481 //Set HCS bit.\r
482 if (SDCmd8Supported) {\r
483 CmdArgument |= HCS;\r
484 }\r
485\r
486 Status = SendCmd (ACMD41, ACMD41_INT_EN, CmdArgument);\r
487 if (EFI_ERROR(Status)) {\r
488 DEBUG ((EFI_D_INFO, "ACMD41 fails.\n"));\r
489 return Status;\r
490 }\r
491 ((UINT32 *) &(gCardInfo.OCRData))[0] = MmioRead32 (MMCHS_RSP10);\r
492 DEBUG ((EFI_D_INFO, "SD card detected. ACMD41 OCR: %x\n", ((UINT32 *) &(gCardInfo.OCRData))[0]));\r
493 } else if (gCardInfo.CardType == MMC_CARD) {\r
494 CmdArgument = 0;\r
495 Status = SendCmd (CMD1, CMD1_INT_EN, CmdArgument);\r
496 if (EFI_ERROR(Status)) {\r
497 DEBUG ((EFI_D_INFO, "CMD1 fails.\n"));\r
498 return Status;\r
499 }\r
500 Response = MmioRead32 (MMCHS_RSP10);\r
501 DEBUG ((EFI_D_INFO, "MMC card detected.. CMD1 response: %x\n", Response));\r
502\r
503 //NOTE: For now, I am skipping this since I only have an SD card.\r
504 //Compare card OCR and host OCR (Section 22.6.1.3.2.4)\r
505 return EFI_UNSUPPORTED; //For now, MMC is not supported.\r
506 }\r
507\r
508 //Poll the card until it is out of its power-up sequence.\r
509 if (gCardInfo.OCRData.Busy == 1) {\r
510\r
511 if (SDCmd8Supported) {\r
512 gCardInfo.CardType = SD_CARD_2;\r
513 }\r
514\r
515 //Card is ready. Check CCS (Card capacity status) bit (bit#30).\r
516 //SD 2.0 standard card will response with CCS 0, SD high capacity card will respond with CCS 1.\r
517 if (gCardInfo.OCRData.AccessMode & BIT1) {\r
518 gCardInfo.CardType = SD_CARD_2_HIGH;\r
519 DEBUG ((EFI_D_INFO, "High capacity card.\n"));\r
520 } else {\r
521 DEBUG ((EFI_D_INFO, "Standard capacity card.\n"));\r
522 }\r
523\r
524 break;\r
525 }\r
526\r
527 gBS->Stall(1000);\r
528 RetryCount++;\r
529 }\r
530\r
531 if (RetryCount == MAX_RETRY_COUNT) {\r
532 DEBUG ((EFI_D_ERROR, "Timeout error. RetryCount: %d\n", RetryCount));\r
533 return EFI_TIMEOUT;\r
534 }\r
535\r
536 //Read CID data.\r
537 CmdArgument = 0;\r
538 Status = SendCmd (CMD2, CMD2_INT_EN, CmdArgument);\r
539 if (EFI_ERROR(Status)) {\r
540 DEBUG ((EFI_D_ERROR, "CMD2 fails. Status: %x\n", Status));\r
541 return Status;\r
542 }\r
543\r
544 DEBUG ((EFI_D_INFO, "CMD2 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));\r
545\r
546 //Parse CID register data.\r
547 ParseCardCIDData(MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76));\r
548\r
549 //Read RCA\r
550 CmdArgument = 0;\r
551 Status = SendCmd (CMD3, CMD3_INT_EN, CmdArgument);\r
552 if (EFI_ERROR(Status)) {\r
553 DEBUG ((EFI_D_ERROR, "CMD3 fails. Status: %x\n", Status));\r
554 return Status;\r
555 }\r
556\r
557 //Set RCA for the detected card. RCA is CMD3 response.\r
558 gCardInfo.RCA = (MmioRead32 (MMCHS_RSP10) >> 16);\r
559 DEBUG ((EFI_D_INFO, "CMD3 response: RCA %x\n", gCardInfo.RCA));\r
560\r
561 //MMC Bus setting change after card identification.\r
562 MmioAnd32 (MMCHS_CON, ~OD);\r
563 MmioOr32 (MMCHS_HCTL, SDVS_3_0_V);\r
564 UpdateMMCHSClkFrequency(CLKD_400KHZ); //Set the clock frequency to 400KHz.\r
565\r
566 return EFI_SUCCESS;\r
567}\r
568\r
569\r
570EFI_STATUS\r
571GetCardSpecificData (\r
572 VOID\r
573 )\r
574{\r
575 EFI_STATUS Status;\r
576 UINTN CmdArgument;\r
577\r
578 //Send CMD9 to retrieve CSD.\r
579 CmdArgument = gCardInfo.RCA << 16;\r
580 Status = SendCmd (CMD9, CMD9_INT_EN, CmdArgument);\r
581 if (EFI_ERROR(Status)) {\r
582 DEBUG ((EFI_D_ERROR, "CMD9 fails. Status: %x\n", Status));\r
583 return Status;\r
584 }\r
585\r
586 //Populate 128-bit CSD register data.\r
587 ((UINT32 *)&(gCardInfo.CSDData))[0] = MmioRead32 (MMCHS_RSP10);\r
588 ((UINT32 *)&(gCardInfo.CSDData))[1] = MmioRead32 (MMCHS_RSP32);\r
589 ((UINT32 *)&(gCardInfo.CSDData))[2] = MmioRead32 (MMCHS_RSP54);\r
590 ((UINT32 *)&(gCardInfo.CSDData))[3] = MmioRead32 (MMCHS_RSP76);\r
591\r
592 DEBUG ((EFI_D_INFO, "CMD9 response: %x %x %x %x\n", MmioRead32 (MMCHS_RSP10), MmioRead32 (MMCHS_RSP32), MmioRead32 (MMCHS_RSP54), MmioRead32 (MMCHS_RSP76)));\r
593\r
594 //Calculate total number of blocks and max. data transfer rate supported by the detected card.\r
595 GetCardConfigurationData();\r
596\r
597 return Status;\r
598}\r
599\r
600\r
601EFI_STATUS\r
602PerformCardConfiguration (\r
603 VOID\r
604 )\r
605{\r
606 UINTN CmdArgument = 0;\r
607 EFI_STATUS Status;\r
608\r
609 //Send CMD7\r
610 CmdArgument = gCardInfo.RCA << 16;\r
611 Status = SendCmd (CMD7, CMD7_INT_EN, CmdArgument);\r
612 if (EFI_ERROR(Status)) {\r
613 DEBUG ((EFI_D_ERROR, "CMD7 fails. Status: %x\n", Status));\r
614 return Status;\r
615 }\r
616\r
617 if ((gCardInfo.CardType != UNKNOWN_CARD) && (gCardInfo.CardType != MMC_CARD)) {\r
618 // We could read SCR register, but SD Card Phys spec stats any SD Card shall\r
619 // set SCR.SD_BUS_WIDTHS to support 4-bit mode, so why bother?\r
620 \r
621 // Send ACMD6 (application specific commands must be prefixed with CMD55)\r
622 Status = SendCmd (CMD55, CMD55_INT_EN, CmdArgument);\r
623 if (!EFI_ERROR (Status)) {\r
624 // set device into 4-bit data bus mode\r
625 Status = SendCmd (ACMD6, ACMD6_INT_EN, 0x2);\r
626 if (!EFI_ERROR (Status)) {\r
627 // Set host controler into 4-bit mode\r
628 MmioOr32 (MMCHS_HCTL, DTW_4_BIT);\r
629 DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));\r
630 }\r
631 }\r
632 }\r
633\r
634 //Send CMD16 to set the block length\r
635 CmdArgument = gCardInfo.BlockSize;\r
636 Status = SendCmd (CMD16, CMD16_INT_EN, CmdArgument);\r
637 if (EFI_ERROR(Status)) {\r
638 DEBUG ((EFI_D_ERROR, "CMD16 fails. Status: %x\n", Status));\r
639 return Status;\r
640 }\r
641\r
642 //Change MMCHS clock frequency to what detected card can support.\r
643 UpdateMMCHSClkFrequency(gCardInfo.ClockFrequencySelect);\r
644\r
645 return EFI_SUCCESS;\r
646}\r
647\r
648\r
649EFI_STATUS\r
650ReadBlockData (\r
651 IN EFI_BLOCK_IO_PROTOCOL *This,\r
652 OUT VOID *Buffer\r
653 )\r
654{\r
655 UINTN MmcStatus;\r
656 UINTN *DataBuffer = Buffer;\r
657 UINTN DataSize = This->Media->BlockSize/4;\r
658 UINTN Count;\r
659 UINTN RetryCount = 0;\r
660\r
661 //Check controller status to make sure there is no error.\r
662 while (RetryCount < MAX_RETRY_COUNT) {\r
663 do {\r
664 //Read Status.\r
665 MmcStatus = MmioRead32 (MMCHS_STAT);\r
666 } while(MmcStatus == 0);\r
667\r
668 //Check if Buffer read ready (BRR) bit is set?\r
669 if (MmcStatus & BRR) {\r
670\r
671 //Clear BRR bit\r
672 MmioOr32 (MMCHS_STAT, BRR);\r
673\r
674 //Read block worth of data.\r
675 for (Count = 0; Count < DataSize; Count++) {\r
676 *DataBuffer++ = MmioRead32 (MMCHS_DATA);\r
677 }\r
678 break;\r
679 }\r
680 RetryCount++;\r
681 }\r
682\r
683 if (RetryCount == MAX_RETRY_COUNT) {\r
684 return EFI_TIMEOUT;\r
685 }\r
686\r
687 return EFI_SUCCESS;\r
688}\r
689\r
690\r
691EFI_STATUS\r
692WriteBlockData (\r
693 IN EFI_BLOCK_IO_PROTOCOL *This,\r
694 OUT VOID *Buffer\r
695 )\r
696{\r
697 UINTN MmcStatus;\r
698 UINTN *DataBuffer = Buffer;\r
699 UINTN DataSize = This->Media->BlockSize/4;\r
700 UINTN Count;\r
701 UINTN RetryCount = 0;\r
702\r
703 //Check controller status to make sure there is no error.\r
704 while (RetryCount < MAX_RETRY_COUNT) {\r
705 do {\r
706 //Read Status.\r
707 MmcStatus = MmioRead32 (MMCHS_STAT);\r
708 } while(MmcStatus == 0);\r
709\r
710 //Check if Buffer write ready (BWR) bit is set?\r
711 if (MmcStatus & BWR) {\r
712\r
713 //Clear BWR bit\r
714 MmioOr32 (MMCHS_STAT, BWR);\r
715\r
716 //Write block worth of data.\r
717 for (Count = 0; Count < DataSize; Count++) {\r
718 MmioWrite32 (MMCHS_DATA, *DataBuffer++);\r
719 }\r
720\r
721 break;\r
722 }\r
723 RetryCount++;\r
724 }\r
725\r
726 if (RetryCount == MAX_RETRY_COUNT) {\r
727 return EFI_TIMEOUT;\r
728 }\r
729\r
730 return EFI_SUCCESS;\r
731}\r
732\r
733EFI_STATUS\r
734DmaBlocks (\r
735 IN EFI_BLOCK_IO_PROTOCOL *This,\r
736 IN UINTN Lba,\r
737 IN OUT VOID *Buffer,\r
738 IN UINTN BlockCount,\r
739 IN OPERATION_TYPE OperationType\r
740 )\r
741{\r
742 EFI_STATUS Status;\r
743 UINTN DmaSize = 0;\r
744 UINTN Cmd = 0;\r
745 UINTN CmdInterruptEnable;\r
746 UINTN CmdArgument;\r
747 VOID *BufferMap;\r
748 EFI_PHYSICAL_ADDRESS BufferAddress;\r
749 OMAP_DMA4 Dma4;\r
750 DMA_MAP_OPERATION DmaOperation;\r
751 EFI_STATUS MmcStatus;\r
752 UINTN RetryCount = 0;\r
753\r
754CpuDeadLoop ();\r
755 // Map passed in buffer for DMA xfer\r
756 DmaSize = BlockCount * This->Media->BlockSize;\r
757 Status = DmaMap (DmaOperation, Buffer, &DmaSize, &BufferAddress, &BufferMap);\r
758 if (EFI_ERROR (Status)) {\r
759 return Status;\r
760 }\r
761\r
762 ZeroMem (&DmaOperation, sizeof (DMA_MAP_OPERATION));\r
763 \r
764\r
765 Dma4.DataType = 2; // DMA4_CSDPi[1:0] 32-bit elements from MMCHS_DATA\r
766\r
767 Dma4.SourceEndiansim = 0; // DMA4_CSDPi[21] \r
768\r
769 Dma4.DestinationEndianism = 0; // DMA4_CSDPi[19]\r
770\r
771 Dma4.SourcePacked = 0; // DMA4_CSDPi[6]\r
772\r
773 Dma4.DestinationPacked = 0; // DMA4_CSDPi[13]\r
774\r
775 Dma4.NumberOfElementPerFrame = This->Media->BlockSize/4; // DMA4_CENi (TRM 4K is optimum value) \r
776\r
777 Dma4.NumberOfFramePerTransferBlock = BlockCount; // DMA4_CFNi \r
778\r
779 Dma4.ReadPriority = 0; // DMA4_CCRi[6] Low priority read \r
780\r
781 Dma4.WritePriority = 0; // DMA4_CCRi[23] Prefetech disabled\r
782\r
783\r
784 //Populate the command information based on the operation type.\r
785 if (OperationType == READ) {\r
786 Cmd = CMD18; //Multiple block read\r
787 CmdInterruptEnable = CMD18_INT_EN;\r
788 DmaOperation = MapOperationBusMasterCommonBuffer;\r
789\r
790 Dma4.ReadPortAccessType =0 ; // DMA4_CSDPi[8:7] Can not burst MMCHS_DATA reg\r
791\r
792 Dma4.WritePortAccessType = 3; // DMA4_CSDPi[15:14] Memory burst 16x32\r
793\r
794 Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted\r
795\r
796 \r
797\r
798 Dma4.SourceStartAddress = MMCHS_DATA; // DMA4_CSSAi\r
799\r
800 Dma4.DestinationStartAddress = (UINT32)BufferAddress; // DMA4_CDSAi\r
801\r
802 Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
803\r
804 Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
805\r
806 Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
807\r
808 Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
809\r
810\r
811\r
812 Dma4.ReadPortAccessMode = 0; // DMA4_CCRi[13:12] Always read MMCHS_DATA\r
813\r
814 Dma4.WritePortAccessMode = 1; // DMA4_CCRi[15:14] Post increment memory address\r
815\r
816 Dma4.ReadRequestNumber = 0x1e; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_RX (61) \r
817\r
818 Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3e == 62 (one based)\r
819\r
820 } else if (OperationType == WRITE) { \r
821 Cmd = CMD25; //Multiple block write\r
822 CmdInterruptEnable = CMD25_INT_EN;\r
823 DmaOperation = MapOperationBusMasterRead;\r
824\r
825 Dma4.ReadPortAccessType = 3; // DMA4_CSDPi[8:7] Memory burst 16x32\r
826\r
827 Dma4.WritePortAccessType = 0; // DMA4_CSDPi[15:14] Can not burst MMCHS_DATA reg\r
828\r
829 Dma4.WriteMode = 1; // DMA4_CSDPi[17:16] Write posted ???\r
830\r
831 \r
832\r
833 Dma4.SourceStartAddress = (UINT32)BufferAddress; // DMA4_CSSAi\r
834\r
835 Dma4.DestinationStartAddress = MMCHS_DATA; // DMA4_CDSAi\r
836\r
837 Dma4.SourceElementIndex = 1; // DMA4_CSEi\r
838\r
839 Dma4.SourceFrameIndex = 0x200; // DMA4_CSFi\r
840\r
841 Dma4.DestinationElementIndex = 1; // DMA4_CDEi\r
842\r
843 Dma4.DestinationFrameIndex = 0; // DMA4_CDFi\r
844\r
845\r
846\r
847 Dma4.ReadPortAccessMode = 1; // DMA4_CCRi[13:12] Post increment memory address\r
848\r
849 Dma4.WritePortAccessMode = 0; // DMA4_CCRi[15:14] Always write MMCHS_DATA\r
850\r
851 Dma4.ReadRequestNumber = 0x1d; // DMA4_CCRi[4:0] Syncro with MMCA_DMA_TX (60) \r
852\r
853 Dma4.WriteRequestNumber = 1; // DMA4_CCRi[20:19] Syncro upper 0x3d == 61 (one based)\r
854\r
855 } else {\r
856 return EFI_INVALID_PARAMETER;\r
857 }\r
858\r
859\r
860 EnableDmaChannel (2, &Dma4);\r
861 \r
862\r
863 //Set command argument based on the card access mode (Byte mode or Block mode)\r
864 if (gCardInfo.OCRData.AccessMode & BIT1) {\r
865 CmdArgument = Lba;\r
866 } else {\r
867 CmdArgument = Lba * This->Media->BlockSize;\r
868 }\r
869\r
870 //Send Command.\r
871 Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);\r
872 if (EFI_ERROR (Status)) {\r
873 DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));\r
874 return Status;\r
875 }\r
876\r
877 //Check for the Transfer completion.\r
878 while (RetryCount < MAX_RETRY_COUNT) {\r
879 //Read Status\r
880 do {\r
881 MmcStatus = MmioRead32 (MMCHS_STAT);\r
882 } while (MmcStatus == 0);\r
883\r
884 //Check if Transfer complete (TC) bit is set?\r
885 if (MmcStatus & TC) {\r
886 break;\r
887 } else {\r
888 DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));\r
889 //Check if DEB, DCRC or DTO interrupt occured.\r
890 if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {\r
891 //There was an error during the data transfer.\r
892\r
893 //Set SRD bit to 1 and wait until it return to 0x0.\r
894 MmioOr32 (MMCHS_SYSCTL, SRD);\r
895 while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);\r
896\r
897 DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);\r
898 DmaUnmap (BufferMap);\r
899 return EFI_DEVICE_ERROR;\r
900 }\r
901 }\r
902 RetryCount++;\r
903 } \r
904\r
905 DisableDmaChannel (2, DMA4_CSR_BLOCK, DMA4_CSR_ERR);\r
906 Status = DmaUnmap (BufferMap);\r
907\r
908 if (RetryCount == MAX_RETRY_COUNT) {\r
909 DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));\r
910 return EFI_TIMEOUT;\r
911 }\r
912\r
913 return Status;\r
914}\r
915\r
916\r
917EFI_STATUS\r
918TransferBlock (\r
919 IN EFI_BLOCK_IO_PROTOCOL *This,\r
920 IN UINTN Lba,\r
921 IN OUT VOID *Buffer,\r
922 IN OPERATION_TYPE OperationType\r
923 )\r
924{\r
925 EFI_STATUS Status;\r
926 UINTN MmcStatus;\r
927 UINTN RetryCount = 0;\r
928 UINTN Cmd = 0;\r
929 UINTN CmdInterruptEnable = 0;\r
930 UINTN CmdArgument = 0;\r
931\r
932\r
933 //Populate the command information based on the operation type.\r
934 if (OperationType == READ) {\r
935 Cmd = CMD17; //Single block read\r
936 CmdInterruptEnable = CMD18_INT_EN;\r
937 } else if (OperationType == WRITE) { \r
938 Cmd = CMD24; //Single block write\r
939 CmdInterruptEnable = CMD24_INT_EN;\r
940 }\r
941\r
942 //Set command argument based on the card access mode (Byte mode or Block mode)\r
943 if (gCardInfo.OCRData.AccessMode & BIT1) {\r
944 CmdArgument = Lba;\r
945 } else {\r
946 CmdArgument = Lba * This->Media->BlockSize;\r
947 }\r
948\r
949 //Send Command.\r
950 Status = SendCmd (Cmd, CmdInterruptEnable, CmdArgument);\r
951 if (EFI_ERROR(Status)) {\r
952 DEBUG ((EFI_D_ERROR, "CMD fails. Status: %x\n", Status));\r
953 return Status;\r
954 }\r
955\r
956 //Read or Write data.\r
957 if (OperationType == READ) {\r
958 Status = ReadBlockData (This, Buffer);\r
959 if (EFI_ERROR(Status)) {\r
960 DEBUG((EFI_D_ERROR, "ReadBlockData fails.\n"));\r
961 return Status;\r
962 }\r
963 } else if (OperationType == WRITE) {\r
964 Status = WriteBlockData (This, Buffer);\r
965 if (EFI_ERROR(Status)) {\r
966 DEBUG((EFI_D_ERROR, "WriteBlockData fails.\n"));\r
967 return Status;\r
968 }\r
969 }\r
970\r
971 //Check for the Transfer completion.\r
972 while (RetryCount < MAX_RETRY_COUNT) {\r
973 //Read Status\r
974 do {\r
975 MmcStatus = MmioRead32 (MMCHS_STAT);\r
976 } while (MmcStatus == 0);\r
977\r
978 //Check if Transfer complete (TC) bit is set?\r
979 if (MmcStatus & TC) {\r
980 break;\r
981 } else {\r
982 DEBUG ((EFI_D_ERROR, "MmcStatus for TC: %x\n", MmcStatus));\r
983 //Check if DEB, DCRC or DTO interrupt occured.\r
984 if ((MmcStatus & DEB) | (MmcStatus & DCRC) | (MmcStatus & DTO)) {\r
985 //There was an error during the data transfer.\r
986\r
987 //Set SRD bit to 1 and wait until it return to 0x0.\r
988 MmioOr32 (MMCHS_SYSCTL, SRD);\r
989 while((MmioRead32 (MMCHS_SYSCTL) & SRD) != 0x0);\r
990\r
991 return EFI_DEVICE_ERROR;\r
992 }\r
993 }\r
994 RetryCount++;\r
995 } \r
996\r
997 if (RetryCount == MAX_RETRY_COUNT) {\r
998 DEBUG ((EFI_D_ERROR, "TransferBlockData timed out.\n"));\r
999 return EFI_TIMEOUT;\r
1000 }\r
1001\r
1002 return EFI_SUCCESS;\r
1003}\r
1004\r
1005BOOLEAN\r
1006CardPresent (\r
1007 VOID\r
1008 )\r
1009{\r
1010 EFI_STATUS Status;\r
1011 UINT8 Data;\r
1012\r
1013 //\r
1014 // Card detect is a GPIO0 on the TPS65950\r
1015 //\r
1016 Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);\r
1017 if (EFI_ERROR (Status)) {\r
1018 return FALSE;\r
1019 }\r
1020\r
1021 if ((Data & CARD_DETECT_BIT) == CARD_DETECT_BIT) {\r
1022 // No Card present\r
1023 return FALSE;\r
1024 } else {\r
1025 return TRUE;\r
1026 }\r
1027}\r
1028\r
1029EFI_STATUS\r
1030DetectCard (\r
1031 VOID\r
1032 )\r
1033{\r
1034 EFI_STATUS Status;\r
1035\r
1036 if (!CardPresent ()) {\r
1037 return EFI_NO_MEDIA;\r
1038 }\r
1039\r
1040 //Initialize MMC host controller clocks.\r
1041 Status = InitializeMMCHS ();\r
1042 if (EFI_ERROR(Status)) {\r
1043 DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));\r
1044 return Status;\r
1045 }\r
1046\r
1047 //Software reset of the MMCHS host controller.\r
1048 MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);\r
1049 gBS->Stall(1000);\r
1050 while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);\r
1051\r
1052 //Soft reset for all.\r
1053 MmioWrite32 (MMCHS_SYSCTL, SRA);\r
1054 gBS->Stall(1000);\r
1055 while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);\r
1056\r
1057 //Voltage capabilities initialization. Activate VS18 and VS30.\r
1058 MmioOr32 (MMCHS_CAPA, (VS30 | VS18));\r
1059\r
1060 //Wakeup configuration\r
1061 MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);\r
1062 MmioOr32 (MMCHS_HCTL, IWE);\r
1063\r
1064 //MMCHS Controller default initialization\r
1065 MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));\r
1066\r
1067 MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));\r
1068\r
1069 //Enable internal clock\r
1070 MmioOr32 (MMCHS_SYSCTL, ICE);\r
1071\r
1072 //Set the clock frequency to 80KHz.\r
1073 UpdateMMCHSClkFrequency (CLKD_80KHZ);\r
1074\r
1075 //Enable SD bus power.\r
1076 MmioOr32 (MMCHS_HCTL, (SDBP_ON));\r
1077\r
1078 //Poll till SD bus power bit is set.\r
1079 while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);\r
1080\r
1081 //Card idenfication\r
1082 Status = PerformCardIdenfication ();\r
1083 if (EFI_ERROR(Status)) {\r
1084 DEBUG ((EFI_D_ERROR, "No MMC/SD card detected.\n"));\r
1085 return Status;\r
1086 }\r
1087 \r
1088 //Get CSD (Card specific data) for the detected card.\r
1089 Status = GetCardSpecificData();\r
1090 if (EFI_ERROR(Status)) {\r
1091 return Status;\r
1092 }\r
1093 \r
1094 //Configure the card in data transfer mode.\r
1095 Status = PerformCardConfiguration();\r
1096 if (EFI_ERROR(Status)) {\r
1097 return Status;\r
1098 }\r
1099\r
1100 //Patch the Media structure.\r
1101 gMMCHSMedia.LastBlock = (gCardInfo.NumBlocks - 1);\r
1102 gMMCHSMedia.BlockSize = gCardInfo.BlockSize;\r
1103 gMMCHSMedia.ReadOnly = (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;\r
1104 gMMCHSMedia.MediaPresent = TRUE; \r
1105 gMMCHSMedia.MediaId++; \r
1106\r
1107 DEBUG ((EFI_D_INFO, "SD Card Media Change on Handle 0x%08x\n", gImageHandle));\r
1108\r
1109 return Status;\r
1110}\r
1111\r
1112#define MAX_MMCHS_TRANSFER_SIZE 0x4000\r
1113\r
1114EFI_STATUS\r
1115SdReadWrite (\r
1116 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1117 IN UINTN Lba, \r
1118 OUT VOID *Buffer, \r
1119 IN UINTN BufferSize,\r
1120 IN OPERATION_TYPE OperationType\r
1121 )\r
1122{\r
1123 EFI_STATUS Status = EFI_SUCCESS;\r
1124 UINTN RetryCount = 0;\r
1125 UINTN BlockCount;\r
1126 UINTN BytesToBeTranferedThisPass = 0;\r
1127 UINTN BytesRemainingToBeTransfered;\r
1128 EFI_TPL OldTpl;\r
1129\r
1130 BOOLEAN Update;\r
1131\r
1132\r
1133 \r
1134 Update = FALSE;\r
1135\r
1136 if (gMediaChange) {\r
1137 Update = TRUE;\r
1138 Status = DetectCard ();\r
1139 if (EFI_ERROR (Status)) {\r
1140 // We detected a removal\r
1141 gMMCHSMedia.MediaPresent = FALSE;\r
1142 gMMCHSMedia.LastBlock = 0;\r
1143 gMMCHSMedia.BlockSize = 512; // Should be zero but there is a bug in DiskIo\r
1144 gMMCHSMedia.ReadOnly = FALSE; \r
1145 }\r
1146 gMediaChange = FALSE;\r
1147 } else if (!gMMCHSMedia.MediaPresent) {\r
1148 Status = EFI_NO_MEDIA;\r
1149 goto Done;\r
1150 }\r
1151\r
1152 if (Update) {\r
1153 DEBUG ((EFI_D_INFO, "SD Card ReinstallProtocolInterface ()\n"));\r
1154 gBS->ReinstallProtocolInterface (\r
1155 gImageHandle,\r
1156 &gEfiBlockIoProtocolGuid,\r
1157 &gBlockIo,\r
1158 &gBlockIo\r
1159 );\r
1160 return EFI_MEDIA_CHANGED;\r
1161 }\r
1162\r
1163 if (EFI_ERROR (Status)) {\r
1164 goto Done;\r
1165 }\r
1166\r
1167 if (Buffer == NULL) {\r
1168 Status = EFI_INVALID_PARAMETER;\r
1169 goto Done;\r
1170 }\r
1171\r
1172 if (Lba > This->Media->LastBlock) {\r
1173 Status = EFI_INVALID_PARAMETER;\r
1174 goto Done;\r
1175 }\r
1176 \r
1177 if ((BufferSize % This->Media->BlockSize) != 0) {\r
1178 Status = EFI_BAD_BUFFER_SIZE;\r
1179 goto Done;\r
1180 }\r
1181\r
1182 //Check if the data lines are not in use.\r
1183 while ((RetryCount++ < MAX_RETRY_COUNT) && ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) != DATI_ALLOWED));\r
1184 if (RetryCount == MAX_RETRY_COUNT) {\r
1185 Status = EFI_TIMEOUT;\r
1186 goto Done;\r
1187 }\r
1188\r
1189 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1190\r
1191 BytesRemainingToBeTransfered = BufferSize;\r
1192 while (BytesRemainingToBeTransfered > 0) {\r
1193\r
1194 if (gMediaChange) {\r
1195 Status = EFI_NO_MEDIA;\r
1196 DEBUG ((EFI_D_INFO, "SdReadWrite() EFI_NO_MEDIA due to gMediaChange\n"));\r
1197 goto DoneRestoreTPL;\r
1198 }\r
1199\r
1200 // Turn OFF DMA path until it is debugged\r
1201 // BytesToBeTranferedThisPass = (BytesToBeTranferedThisPass >= MAX_MMCHS_TRANSFER_SIZE) ? MAX_MMCHS_TRANSFER_SIZE : BytesRemainingToBeTransfered;\r
1202 BytesToBeTranferedThisPass = This->Media->BlockSize;\r
1203\r
1204 BlockCount = BytesToBeTranferedThisPass/This->Media->BlockSize;\r
1205\r
1206 if (BlockCount > 1) {\r
1207 Status = DmaBlocks (This, Lba, Buffer, BlockCount, OperationType);\r
1208 } else {\r
1209 //Transfer a block worth of data.\r
1210 Status = TransferBlock (This, Lba, Buffer, OperationType);\r
1211 }\r
1212\r
1213 if (EFI_ERROR(Status)) {\r
1214 DEBUG ((EFI_D_ERROR, "TransferBlockData fails. %x\n", Status));\r
1215 goto DoneRestoreTPL;\r
1216 }\r
1217\r
1218 BytesRemainingToBeTransfered -= BytesToBeTranferedThisPass;\r
1219 Lba += BlockCount;\r
1220 Buffer = (UINT8 *)Buffer + This->Media->BlockSize;\r
1221 }\r
1222\r
1223DoneRestoreTPL:\r
1224\r
1225 gBS->RestoreTPL (OldTpl);\r
1226\r
1227Done:\r
1228\r
1229 return Status;\r
1230\r
1231}\r
1232\r
1233\r
1234/**\r
1235\r
1236 Reset the Block Device.\r
1237\r
1238\r
1239\r
1240 @param This Indicates a pointer to the calling context.\r
1241\r
1242 @param ExtendedVerification Driver may perform diagnostics on reset.\r
1243\r
1244\r
1245\r
1246 @retval EFI_SUCCESS The device was reset.\r
1247\r
1248 @retval EFI_DEVICE_ERROR The device is not functioning properly and could\r
1249\r
1250 not be reset.\r
1251\r
1252\r
1253\r
1254**/\r
1255EFI_STATUS\r
1256EFIAPI\r
1257MMCHSReset (\r
1258 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1259 IN BOOLEAN ExtendedVerification\r
1260 )\r
1261{\r
1262 return EFI_SUCCESS; \r
1263}\r
1264\r
1265\r
1266/**\r
1267\r
1268 Read BufferSize bytes from Lba into Buffer.\r
1269\r
1270\r
1271\r
1272 @param This Indicates a pointer to the calling context.\r
1273\r
1274 @param MediaId Id of the media, changes every time the media is replaced.\r
1275\r
1276 @param Lba The starting Logical Block Address to read from\r
1277\r
1278 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
1279\r
1280 @param Buffer A pointer to the destination buffer for the data. The caller is\r
1281\r
1282 responsible for either having implicit or explicit ownership of the buffer.\r
1283\r
1284\r
1285\r
1286 @retval EFI_SUCCESS The data was read correctly from the device.\r
1287\r
1288 @retval EFI_DEVICE_ERROR The device reported an error while performing the read.\r
1289\r
1290 @retval EFI_NO_MEDIA There is no media in the device.\r
1291\r
1292 @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.\r
1293\r
1294 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
1295\r
1296 @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, \r
1297\r
1298 or the buffer is not on proper alignment.\r
1299\r
1300EFI_STATUS\r
1301\r
1302**/\r
1303EFI_STATUS\r
1304EFIAPI\r
1305MMCHSReadBlocks (\r
1306 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1307 IN UINT32 MediaId,\r
1308 IN EFI_LBA Lba,\r
1309 IN UINTN BufferSize,\r
1310 OUT VOID *Buffer\r
1311 )\r
1312{\r
1313 EFI_STATUS Status;\r
1314\r
1315 //Perform Read operation.\r
1316 Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, READ);\r
1317\r
1318 return Status;\r
1319\r
1320}\r
1321\r
1322\r
1323/**\r
1324\r
1325 Write BufferSize bytes from Lba into Buffer.\r
1326\r
1327\r
1328\r
1329 @param This Indicates a pointer to the calling context.\r
1330\r
1331 @param MediaId The media ID that the write request is for.\r
1332\r
1333 @param Lba The starting logical block address to be written. The caller is\r
1334\r
1335 responsible for writing to only legitimate locations.\r
1336\r
1337 @param BufferSize Size of Buffer, must be a multiple of device block size.\r
1338\r
1339 @param Buffer A pointer to the source buffer for the data.\r
1340\r
1341\r
1342\r
1343 @retval EFI_SUCCESS The data was written correctly to the device.\r
1344\r
1345 @retval EFI_WRITE_PROTECTED The device can not be written to.\r
1346\r
1347 @retval EFI_DEVICE_ERROR The device reported an error while performing the write.\r
1348\r
1349 @retval EFI_NO_MEDIA There is no media in the device.\r
1350\r
1351 @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.\r
1352\r
1353 @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.\r
1354\r
1355 @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, \r
1356\r
1357 or the buffer is not on proper alignment.\r
1358\r
1359\r
1360\r
1361**/\r
1362EFI_STATUS\r
1363EFIAPI\r
1364MMCHSWriteBlocks (\r
1365 IN EFI_BLOCK_IO_PROTOCOL *This,\r
1366 IN UINT32 MediaId,\r
1367 IN EFI_LBA Lba,\r
1368 IN UINTN BufferSize,\r
1369 IN VOID *Buffer\r
1370 )\r
1371{\r
1372 EFI_STATUS Status;\r
1373\r
1374 //Perform write operation.\r
1375 Status = SdReadWrite (This, (UINTN)Lba, Buffer, BufferSize, WRITE);\r
1376\r
1377\r
1378 return Status;\r
1379\r
1380}\r
1381\r
1382\r
1383/**\r
1384\r
1385 Flush the Block Device.\r
1386\r
1387\r
1388\r
1389 @param This Indicates a pointer to the calling context.\r
1390\r
1391\r
1392\r
1393 @retval EFI_SUCCESS All outstanding data was written to the device\r
1394\r
1395 @retval EFI_DEVICE_ERROR The device reported an error while writting back the data\r
1396\r
1397 @retval EFI_NO_MEDIA There is no media in the device.\r
1398\r
1399\r
1400\r
1401**/\r
1402EFI_STATUS\r
1403EFIAPI\r
1404MMCHSFlushBlocks (\r
1405 IN EFI_BLOCK_IO_PROTOCOL *This\r
1406 )\r
1407{\r
1408 return EFI_SUCCESS;\r
1409}\r
1410\r
1411\r
1412EFI_BLOCK_IO_PROTOCOL gBlockIo = {\r
1413 EFI_BLOCK_IO_INTERFACE_REVISION, // Revision\r
1414 &gMMCHSMedia, // *Media\r
1415 MMCHSReset, // Reset\r
1416 MMCHSReadBlocks, // ReadBlocks\r
1417 MMCHSWriteBlocks, // WriteBlocks\r
1418 MMCHSFlushBlocks // FlushBlocks\r
1419};\r
1420\r
1421\r
1422/**\r
1423\r
1424 Timer callback to convert card present hardware into a boolean that indicates\r
1425\r
1426 a media change event has happened. If you just check the GPIO you could see \r
1427\r
1428 card 1 and then check again after card 1 was removed and card 2 was inserted\r
1429\r
1430 and you would still see media present. Thus you need the timer tick to catch\r
1431\r
1432 the toggle event.\r
1433\r
1434\r
1435\r
1436 @param Event Event whose notification function is being invoked.\r
1437\r
1438 @param Context The pointer to the notification function's context,\r
1439\r
1440 which is implementation-dependent. Not used.\r
1441\r
1442\r
1443\r
1444**/\r
1445VOID\r
1446EFIAPI\r
1447TimerCallback (\r
1448 IN EFI_EVENT Event,\r
1449 IN VOID *Context\r
1450 )\r
1451{\r
1452 BOOLEAN Present;\r
1453\r
1454 Present = CardPresent ();\r
1455 if (gMMCHSMedia.MediaPresent) {\r
1456 if (!Present && !gMediaChange) {\r
1457 gMediaChange = TRUE;\r
1458 }\r
1459 } else {\r
1460 if (Present && !gMediaChange) {\r
1461 gMediaChange = TRUE; \r
1462 }\r
1463 }\r
1464}\r
1465\r
1466\r
1467EFI_STATUS\r
1468EFIAPI\r
1469MMCHSInitialize (\r
1470 IN EFI_HANDLE ImageHandle,\r
1471 IN EFI_SYSTEM_TABLE *SystemTable\r
1472 )\r
1473{\r
1474 EFI_STATUS Status;\r
1475\r
1476 Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);\r
1477 ASSERT_EFI_ERROR(Status);\r
1478\r
1479 ZeroMem (&gCardInfo, sizeof (CARD_INFO));\r
1480\r
1481 Status = gBS->CreateEvent (EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, TimerCallback, NULL, &gTimerEvent);\r
1482 ASSERT_EFI_ERROR (Status);\r
1483 \r
1484 Status = gBS->SetTimer (gTimerEvent, TimerPeriodic, FixedPcdGet32 (PcdMmchsTimerFreq100NanoSeconds)); \r
1485 ASSERT_EFI_ERROR (Status);\r
1486\r
1487 //Publish BlockIO.\r
1488 Status = gBS->InstallMultipleProtocolInterfaces (\r
1489 &ImageHandle, \r
1490 &gEfiBlockIoProtocolGuid, &gBlockIo, \r
1491 &gEfiDevicePathProtocolGuid, &gMmcHsDevicePath,\r
1492 NULL\r
1493 );\r
1494 return Status;\r
1495}\r