MmcHostDxe.c 16 KB

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