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