]> git.proxmox.com Git - mirror_edk2.git/blame - Omap35xxPkg/MmcHostDxe/MmcHostDxe.c
Omap35xxPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / Omap35xxPkg / MmcHostDxe / MmcHostDxe.c
CommitLineData
1e57a462 1/** @file\r
2*\r
3* Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.\r
b0fdce95 4* Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.\r
1e57a462 5*\r
538311f7 6* SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 7*\r
8**/\r
9\r
10#include "MmcHostDxe.h"\r
11\r
12EMBEDDED_EXTERNAL_DEVICE *gTPS65950;\r
13UINT8 mMaxDataTransferRate = 0;\r
14UINT32 mRca = 0;\r
15BOOLEAN mBitModeSet = FALSE;\r
16\r
17\r
18typedef struct {\r
19 VENDOR_DEVICE_PATH Mmc;\r
20 EFI_DEVICE_PATH End;\r
21} MMCHS_DEVICE_PATH;\r
22\r
23MMCHS_DEVICE_PATH gMMCDevicePath = {\r
24 {\r
b0fdce95
OM
25 {\r
26 HARDWARE_DEVICE_PATH,\r
27 HW_VENDOR_DP,\r
28 { (UINT8)(sizeof(VENDOR_DEVICE_PATH)), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) },\r
29 },\r
30 { 0xb615f1f5, 0x5088, 0x43cd, { 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 } }\r
1e57a462 31 },\r
32 {\r
33 END_DEVICE_PATH_TYPE,\r
34 END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
b0fdce95 35 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
1e57a462 36 }\r
37};\r
38\r
39BOOLEAN\r
40IgnoreCommand (\r
41 UINT32 Command\r
42 )\r
43{\r
44 switch(Command) {\r
45 case MMC_CMD12:\r
46 return TRUE;\r
47 case MMC_CMD13:\r
48 return TRUE;\r
49 default:\r
50 return FALSE;\r
51 }\r
52}\r
53\r
54UINT32\r
55TranslateCommand (\r
56 UINT32 Command\r
57 )\r
58{\r
59 UINT32 Translation;\r
60\r
61 switch(Command) {\r
62 case MMC_CMD2:\r
63 Translation = CMD2;\r
64 break;\r
65 case MMC_CMD3:\r
66 Translation = CMD3;\r
67 break;\r
68 /*case MMC_CMD6:\r
69 Translation = CMD6;\r
70 break;*/\r
71 case MMC_CMD7:\r
72 Translation = CMD7;\r
73 break;\r
74 case MMC_CMD8:\r
75 Translation = CMD8;\r
76 break;\r
77 case MMC_CMD9:\r
78 Translation = CMD9;\r
79 break;\r
80 /*case MMC_CMD12:\r
81 Translation = CMD12;\r
82 break;\r
83 case MMC_CMD13:\r
84 Translation = CMD13;\r
85 break;*/\r
86 case MMC_CMD16:\r
87 Translation = CMD16;\r
88 break;\r
89 case MMC_CMD17:\r
90 Translation = 0x113A0014;//CMD17;\r
91 break;\r
92 case MMC_CMD24:\r
93 Translation = CMD24 | 4;\r
94 break;\r
95 case MMC_CMD55:\r
96 Translation = CMD55;\r
97 break;\r
98 case MMC_ACMD41:\r
99 Translation = ACMD41;\r
100 break;\r
101 default:\r
102 Translation = Command;\r
103 }\r
104\r
105 return Translation;\r
106}\r
107\r
108VOID\r
109CalculateCardCLKD (\r
110 UINTN *ClockFrequencySelect\r
111 )\r
112{\r
113 UINTN TransferRateValue = 0;\r
114 UINTN TimeValue = 0 ;\r
115 UINTN Frequency = 0;\r
116\r
117 DEBUG ((DEBUG_BLKIO, "CalculateCardCLKD()\n"));\r
118\r
119 // For SD Cards we would need to send CMD6 to set\r
120 // speeds abouve 25MHz. High Speed mode 50 MHz and up\r
121\r
122 // Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)\r
123 switch (mMaxDataTransferRate & 0x7) { // 2\r
124 case 0:\r
125 TransferRateValue = 100 * 1000;\r
126 break;\r
127\r
128 case 1:\r
129 TransferRateValue = 1 * 1000 * 1000;\r
130 break;\r
131\r
132 case 2:\r
133 TransferRateValue = 10 * 1000 * 1000;\r
134 break;\r
135\r
136 case 3:\r
137 TransferRateValue = 100 * 1000 * 1000;\r
138 break;\r
139\r
140 default:\r
141 DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));\r
142 ASSERT(FALSE);\r
143 return;\r
144 }\r
145\r
146 //Calculate Time value (Bits 6:3 of TRAN_SPEED)\r
147 switch ((mMaxDataTransferRate >> 3) & 0xF) { // 6\r
148 case 1:\r
149 TimeValue = 10;\r
150 break;\r
151\r
152 case 2:\r
153 TimeValue = 12;\r
154 break;\r
155\r
156 case 3:\r
157 TimeValue = 13;\r
158 break;\r
159\r
160 case 4:\r
161 TimeValue = 15;\r
162 break;\r
163\r
164 case 5:\r
165 TimeValue = 20;\r
166 break;\r
167\r
168 case 6:\r
169 TimeValue = 25;\r
170 break;\r
171\r
172 case 7:\r
173 TimeValue = 30;\r
174 break;\r
175\r
176 case 8:\r
177 TimeValue = 35;\r
178 break;\r
179\r
180 case 9:\r
181 TimeValue = 40;\r
182 break;\r
183\r
184 case 10:\r
185 TimeValue = 45;\r
186 break;\r
187\r
188 case 11:\r
189 TimeValue = 50;\r
190 break;\r
191\r
192 case 12:\r
193 TimeValue = 55;\r
194 break;\r
195\r
196 case 13:\r
197 TimeValue = 60;\r
198 break;\r
199\r
200 case 14:\r
201 TimeValue = 70;\r
202 break;\r
203\r
204 case 15:\r
205 TimeValue = 80;\r
206 break;\r
207\r
208 default:\r
209 DEBUG ((DEBUG_BLKIO, "Invalid parameter.\n"));\r
210 ASSERT(FALSE);\r
211 return;\r
212 }\r
213\r
214 Frequency = TransferRateValue * TimeValue/10;\r
215\r
216 // Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.\r
217 *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);\r
218\r
219 DEBUG ((DEBUG_BLKIO, "mMaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", mMaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));\r
220}\r
221\r
222VOID\r
223UpdateMMCHSClkFrequency (\r
224 UINTN NewCLKD\r
225 )\r
226{\r
227 DEBUG ((DEBUG_BLKIO, "UpdateMMCHSClkFrequency()\n"));\r
228\r
229 // Set Clock enable to 0x0 to not provide the clock to the card\r
230 MmioAnd32 (MMCHS_SYSCTL, ~CEN);\r
231\r
232 // Set new clock frequency.\r
3402aac7 233 MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6);\r
1e57a462 234\r
235 // Poll till Internal Clock Stable\r
236 while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);\r
237\r
238 // Set Clock enable to 0x1 to provide the clock to the card\r
239 MmioOr32 (MMCHS_SYSCTL, CEN);\r
240}\r
241\r
242EFI_STATUS\r
243InitializeMMCHS (\r
244 VOID\r
245 )\r
246{\r
247 UINT8 Data;\r
248 EFI_STATUS Status;\r
249\r
250 DEBUG ((DEBUG_BLKIO, "InitializeMMCHS()\n"));\r
251\r
252 // Select Device group to belong to P1 device group in Power IC.\r
253 Data = DEV_GRP_P1;\r
254 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);\r
255 ASSERT_EFI_ERROR(Status);\r
256\r
257 // Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.\r
258 Data = VSEL_3_00V;\r
259 Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);\r
260 ASSERT_EFI_ERROR(Status);\r
3402aac7 261\r
1e57a462 262 // After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.\r
263 MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));\r
264\r
265 // Enable WP GPIO\r
266 MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);\r
267\r
268 // Enable Card Detect\r
269 Data = CARD_DETECT_ENABLE;\r
270 gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);\r
271\r
272 return Status;\r
273}\r
274\r
275BOOLEAN\r
276MMCIsCardPresent (\r
277 IN EFI_MMC_HOST_PROTOCOL *This\r
278 )\r
279{\r
280 EFI_STATUS Status;\r
281 UINT8 Data;\r
282\r
283 //\r
284 // Card detect is a GPIO0 on the TPS65950\r
285 //\r
286 Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);\r
287 if (EFI_ERROR (Status)) {\r
288 return FALSE;\r
289 }\r
290\r
291 return !(Data & CARD_DETECT_BIT);\r
292}\r
293\r
294BOOLEAN\r
295MMCIsReadOnly (\r
296 IN EFI_MMC_HOST_PROTOCOL *This\r
297 )\r
298{\r
299 /* Note:\r
3402aac7 300 * On our BeagleBoard the SD card WP pin is always read as TRUE.\r
1e57a462 301 * Probably something wrong with GPIO configuration.\r
302 * BeagleBoard-xM uses microSD cards so there is no write protect at all.\r
3402aac7 303 * Hence commenting out SD card WP pin read status.\r
1e57a462 304 */\r
305 //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;\r
306 return 0;\r
307\r
308}\r
309\r
310// TODO\r
311EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;\r
312\r
313EFI_STATUS\r
314MMCBuildDevicePath (\r
315 IN EFI_MMC_HOST_PROTOCOL *This,\r
316 IN EFI_DEVICE_PATH_PROTOCOL **DevicePath\r
317 )\r
318{\r
319 EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;\r
320\r
321 NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));\r
322 CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);\r
323 *DevicePath = NewDevicePathNode;\r
324 return EFI_SUCCESS;\r
325}\r
326\r
327EFI_STATUS\r
328MMCSendCommand (\r
329 IN EFI_MMC_HOST_PROTOCOL *This,\r
330 IN MMC_CMD MmcCmd,\r
331 IN UINT32 Argument\r
332 )\r
333{\r
334 UINTN MmcStatus;\r
335 UINTN RetryCount = 0;\r
336\r
337 if (IgnoreCommand(MmcCmd))\r
338 return EFI_SUCCESS;\r
339\r
340 MmcCmd = TranslateCommand(MmcCmd);\r
341\r
342 //DEBUG ((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));\r
343\r
344 // Check if command line is in use or not. Poll till command line is available.\r
345 while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);\r
346\r
347 // Provide the block size.\r
348 MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);\r
349\r
350 // Setting Data timeout counter value to max value.\r
351 MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);\r
352\r
353 // Clear Status register.\r
354 MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);\r
355\r
356 // Set command argument register\r
357 MmioWrite32 (MMCHS_ARG, Argument);\r
358\r
359 //TODO: fix this\r
360 //Enable interrupt enable events to occur\r
361 //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);\r
362\r
363 // Send a command\r
364 MmioWrite32 (MMCHS_CMD, MmcCmd);\r
365\r
366 // Check for the command status.\r
367 while (RetryCount < MAX_RETRY_COUNT) {\r
368 do {\r
369 MmcStatus = MmioRead32 (MMCHS_STAT);\r
370 } while (MmcStatus == 0);\r
371\r
372 // Read status of command response\r
373 if ((MmcStatus & ERRI) != 0) {\r
374\r
375 // Perform soft-reset for mmci_cmd line.\r
376 MmioOr32 (MMCHS_SYSCTL, SRC);\r
377 while ((MmioRead32 (MMCHS_SYSCTL) & SRC));\r
378\r
379 //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));\r
380 return EFI_DEVICE_ERROR;\r
381 }\r
382\r
383 // Check if command is completed.\r
384 if ((MmcStatus & CC) == CC) {\r
385 MmioWrite32 (MMCHS_STAT, CC);\r
386 break;\r
387 }\r
388\r
389 RetryCount++;\r
390 }\r
391\r
392 if (RetryCount == MAX_RETRY_COUNT) {\r
393 DEBUG ((DEBUG_BLKIO, "MMCSendCommand: Timeout\n"));\r
394 return EFI_TIMEOUT;\r
395 }\r
396\r
397 return EFI_SUCCESS;\r
398}\r
399\r
400EFI_STATUS\r
401MMCNotifyState (\r
402 IN EFI_MMC_HOST_PROTOCOL *This,\r
403 IN MMC_STATE State\r
404 )\r
405{\r
406 EFI_STATUS Status;\r
407 UINTN FreqSel;\r
408\r
409 switch(State) {\r
410 case MmcInvalidState:\r
411 ASSERT(0);\r
412 break;\r
413 case MmcHwInitializationState:\r
414 mBitModeSet = FALSE;\r
415\r
416 DEBUG ((DEBUG_BLKIO, "MMCHwInitializationState()\n"));\r
417 Status = InitializeMMCHS ();\r
418 if (EFI_ERROR(Status)) {\r
419 DEBUG ((DEBUG_BLKIO, "Initialize MMC host controller fails. Status: %x\n", Status));\r
420 return Status;\r
421 }\r
422\r
423 // Software reset of the MMCHS host controller.\r
424 MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);\r
425 gBS->Stall(1000);\r
426 while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);\r
427\r
428 // Soft reset for all.\r
429 MmioWrite32 (MMCHS_SYSCTL, SRA);\r
430 gBS->Stall(1000);\r
431 while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);\r
432\r
433 //Voltage capabilities initialization. Activate VS18 and VS30.\r
434 MmioOr32 (MMCHS_CAPA, (VS30 | VS18));\r
435\r
436 // Wakeup configuration\r
437 MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);\r
438 MmioOr32 (MMCHS_HCTL, IWE);\r
439\r
440 // MMCHS Controller default initialization\r
441 MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));\r
442\r
443 MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));\r
444\r
445 // Enable internal clock\r
446 MmioOr32 (MMCHS_SYSCTL, ICE);\r
447\r
448 // Set the clock frequency to 80KHz.\r
449 UpdateMMCHSClkFrequency (CLKD_80KHZ);\r
450\r
451 // Enable SD bus power.\r
452 MmioOr32 (MMCHS_HCTL, (SDBP_ON));\r
453\r
454 // Poll till SD bus power bit is set.\r
455 while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);\r
456\r
457 // Enable interrupts.\r
458 MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |\r
459 CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));\r
460\r
461 // Controller INIT procedure start.\r
462 MmioOr32 (MMCHS_CON, INIT);\r
463 MmioWrite32 (MMCHS_CMD, 0x00000000);\r
464 while (!(MmioRead32 (MMCHS_STAT) & CC));\r
465\r
466 // Wait for 1 ms\r
467 gBS->Stall (1000);\r
468\r
469 // Set CC bit to 0x1 to clear the flag\r
470 MmioOr32 (MMCHS_STAT, CC);\r
471\r
472 // Retry INIT procedure.\r
473 MmioWrite32 (MMCHS_CMD, 0x00000000);\r
474 while (!(MmioRead32 (MMCHS_STAT) & CC));\r
475\r
476 // End initialization sequence\r
477 MmioAnd32 (MMCHS_CON, ~INIT);\r
478\r
479 MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));\r
480\r
481 // Change clock frequency to 400KHz to fit protocol\r
482 UpdateMMCHSClkFrequency(CLKD_400KHZ);\r
483\r
484 MmioOr32 (MMCHS_CON, OD);\r
485 break;\r
486 case MmcIdleState:\r
487 break;\r
488 case MmcReadyState:\r
489 break;\r
490 case MmcIdentificationState:\r
491 break;\r
492 case MmcStandByState:\r
493 CalculateCardCLKD (&FreqSel);\r
494 UpdateMMCHSClkFrequency (FreqSel);\r
495 break;\r
496 case MmcTransferState:\r
497 if (!mBitModeSet) {\r
498 Status = MMCSendCommand (This, CMD55, mRca << 16);\r
499 if (!EFI_ERROR (Status)) {\r
500 // Set device into 4-bit data bus mode\r
501 Status = MMCSendCommand (This, ACMD6, 0x2);\r
502 if (!EFI_ERROR (Status)) {\r
503 // Set host controler into 4-bit mode\r
504 MmioOr32 (MMCHS_HCTL, DTW_4_BIT);\r
505 DEBUG ((DEBUG_BLKIO, "SD Memory Card set to 4-bit mode\n"));\r
506 mBitModeSet = TRUE;\r
507 }\r
508 }\r
509 }\r
510 break;\r
511 case MmcSendingDataState:\r
512 break;\r
513 case MmcReceiveDataState:\r
514 break;\r
515 case MmcProgrammingState:\r
516 break;\r
517 case MmcDisconnectState:\r
518 default:\r
519 ASSERT(0);\r
520 }\r
521 return EFI_SUCCESS;\r
522}\r
523\r
524EFI_STATUS\r
525MMCReceiveResponse (\r
526 IN EFI_MMC_HOST_PROTOCOL *This,\r
527 IN MMC_RESPONSE_TYPE Type,\r
528 IN UINT32* Buffer\r
529 )\r
530{\r
531 if (Buffer == NULL) {\r
532 return EFI_INVALID_PARAMETER;\r
533 }\r
534\r
535 if (Type == MMC_RESPONSE_TYPE_R2) {\r
536 Buffer[0] = MmioRead32 (MMCHS_RSP10);\r
537 Buffer[1] = MmioRead32 (MMCHS_RSP32);\r
538 Buffer[2] = MmioRead32 (MMCHS_RSP54);\r
539 Buffer[3] = MmioRead32 (MMCHS_RSP76);\r
540 } else {\r
541 Buffer[0] = MmioRead32 (MMCHS_RSP10);\r
542 }\r
543\r
544 if (Type == MMC_RESPONSE_TYPE_CSD) {\r
545 mMaxDataTransferRate = Buffer[3] & 0xFF;\r
546 } else if (Type == MMC_RESPONSE_TYPE_RCA) {\r
547 mRca = Buffer[0] >> 16;\r
548 }\r
549\r
550 return EFI_SUCCESS;\r
551}\r
552\r
553EFI_STATUS\r
554MMCReadBlockData (\r
555 IN EFI_MMC_HOST_PROTOCOL *This,\r
556 IN EFI_LBA Lba,\r
557 IN UINTN Length,\r
558 IN UINT32* Buffer\r
559 )\r
560{\r
561 UINTN MmcStatus;\r
562 UINTN Count;\r
563 UINTN RetryCount = 0;\r
564\r
565 DEBUG ((DEBUG_BLKIO, "MMCReadBlockData(LBA: 0x%x, Length: 0x%x, Buffer: 0x%x)\n", Lba, Length, Buffer));\r
566\r
567 // Check controller status to make sure there is no error.\r
568 while (RetryCount < MAX_RETRY_COUNT) {\r
569 do {\r
570 // Read Status.\r
571 MmcStatus = MmioRead32 (MMCHS_STAT);\r
572 } while(MmcStatus == 0);\r
573\r
574 // Check if Buffer read ready (BRR) bit is set?\r
575 if (MmcStatus & BRR) {\r
576\r
577 // Clear BRR bit\r
578 MmioOr32 (MMCHS_STAT, BRR);\r
579\r
580 for (Count = 0; Count < Length / 4; Count++) {\r
581 *Buffer++ = MmioRead32(MMCHS_DATA);\r
582 }\r
583 break;\r
584 }\r
585 RetryCount++;\r
586 }\r
587\r
588 if (RetryCount == MAX_RETRY_COUNT) {\r
589 return EFI_TIMEOUT;\r
590 }\r
591\r
592 return EFI_SUCCESS;\r
593}\r
594\r
595EFI_STATUS\r
596MMCWriteBlockData (\r
597 IN EFI_MMC_HOST_PROTOCOL *This,\r
598 IN EFI_LBA Lba,\r
599 IN UINTN Length,\r
600 IN UINT32* Buffer\r
601 )\r
602{\r
603 UINTN MmcStatus;\r
604 UINTN Count;\r
605 UINTN RetryCount = 0;\r
606\r
607 // Check controller status to make sure there is no error.\r
608 while (RetryCount < MAX_RETRY_COUNT) {\r
609 do {\r
610 // Read Status.\r
611 MmcStatus = MmioRead32 (MMCHS_STAT);\r
612 } while(MmcStatus == 0);\r
613\r
614 // Check if Buffer write ready (BWR) bit is set?\r
615 if (MmcStatus & BWR) {\r
616\r
617 // Clear BWR bit\r
618 MmioOr32 (MMCHS_STAT, BWR);\r
619\r
620 // Write block worth of data.\r
621 for (Count = 0; Count < Length / 4; Count++) {\r
622 MmioWrite32 (MMCHS_DATA, *Buffer++);\r
623 }\r
624\r
625 break;\r
626 }\r
627 RetryCount++;\r
628 }\r
629\r
630 if (RetryCount == MAX_RETRY_COUNT) {\r
631 return EFI_TIMEOUT;\r
632 }\r
633\r
634 return EFI_SUCCESS;\r
635}\r
636\r
637EFI_MMC_HOST_PROTOCOL gMMCHost = {\r
638 MMC_HOST_PROTOCOL_REVISION,\r
639 MMCIsCardPresent,\r
640 MMCIsReadOnly,\r
641 MMCBuildDevicePath,\r
642 MMCNotifyState,\r
643 MMCSendCommand,\r
644 MMCReceiveResponse,\r
645 MMCReadBlockData,\r
646 MMCWriteBlockData\r
647};\r
648\r
649EFI_STATUS\r
650MMCInitialize (\r
651 IN EFI_HANDLE ImageHandle,\r
652 IN EFI_SYSTEM_TABLE *SystemTable\r
653 )\r
654{\r
655 EFI_STATUS Status;\r
656 EFI_HANDLE Handle = NULL;\r
657\r
658 DEBUG ((DEBUG_BLKIO, "MMCInitialize()\n"));\r
659\r
660 Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);\r
661 ASSERT_EFI_ERROR(Status);\r
662\r
663 Status = gBS->InstallMultipleProtocolInterfaces (\r
3402aac7 664 &Handle,\r
1e57a462 665 &gEfiMmcHostProtocolGuid, &gMMCHost,\r
666 NULL\r
667 );\r
668 ASSERT_EFI_ERROR (Status);\r
669\r
670 return Status;\r
671}\r