Home | History | Annotate | Download | only in DwEmmcDxe
      1 /** @file
      2   This file implement the MMC Host Protocol for the DesignWare eMMC.
      3 
      4   Copyright (c) 2014-2016, Linaro Limited. All rights reserved.
      5   Copyright (c) 2014-2016, Hisilicon Limited. All rights reserved.
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/CacheMaintenanceLib.h>
     19 #include <Library/DebugLib.h>
     20 #include <Library/DevicePathLib.h>
     21 #include <Library/IoLib.h>
     22 #include <Library/MemoryAllocationLib.h>
     23 #include <Library/PcdLib.h>
     24 #include <Library/TimerLib.h>
     25 #include <Library/UefiBootServicesTableLib.h>
     26 #include <Library/UefiLib.h>
     27 #include <Protocol/MmcHost.h>
     28 
     29 #include <Library/PrintLib.h>
     30 #include <Library/SerialPortLib.h>
     31 
     32 #include "DwEmmc.h"
     33 
     34 #define DWEMMC_DESC_PAGE		1
     35 #define DWEMMC_BLOCK_SIZE		512
     36 #define DWEMMC_DMA_BUF_SIZE		(512 * 8)
     37 #define DWEMMC_MAX_DESC_PAGES   	512
     38 
     39 typedef struct {
     40   UINT32		Des0;
     41   UINT32		Des1;
     42   UINT32		Des2;
     43   UINT32		Des3;
     44 } DWEMMC_IDMAC_DESCRIPTOR;
     45 
     46 EFI_MMC_HOST_PROTOCOL     *gpMmcHost;
     47 DWEMMC_IDMAC_DESCRIPTOR   *gpIdmacDesc;
     48 EFI_GUID mDwEmmcDevicePathGuid = EFI_CALLER_ID_GUID;
     49 STATIC UINT32 mDwEmmcCommand;
     50 STATIC UINT32 mDwEmmcArgument;
     51 
     52 EFI_STATUS
     53 DwEmmcReadBlockData (
     54   IN EFI_MMC_HOST_PROTOCOL     *This,
     55   IN EFI_LBA                    Lba,
     56   IN UINTN                      Length,
     57   IN UINT32*                    Buffer
     58   );
     59 
     60 BOOLEAN
     61 DwEmmcIsPowerOn (
     62   VOID
     63   )
     64 {
     65     return TRUE;
     66 }
     67 
     68 EFI_STATUS
     69 DwEmmcInitialize (
     70   VOID
     71   )
     72 {
     73     DEBUG ((EFI_D_BLKIO, "DwEmmcInitialize()"));
     74     return EFI_SUCCESS;
     75 }
     76 
     77 BOOLEAN
     78 DwEmmcIsCardPresent (
     79   IN EFI_MMC_HOST_PROTOCOL     *This
     80   )
     81 {
     82   return TRUE;
     83 }
     84 
     85 BOOLEAN
     86 DwEmmcIsReadOnly (
     87   IN EFI_MMC_HOST_PROTOCOL     *This
     88   )
     89 {
     90   return FALSE;
     91 }
     92 
     93 BOOLEAN
     94 DwEmmcIsDmaSupported (
     95   IN EFI_MMC_HOST_PROTOCOL     *This
     96   )
     97 {
     98   return TRUE;
     99 }
    100 
    101 EFI_STATUS
    102 DwEmmcBuildDevicePath (
    103   IN EFI_MMC_HOST_PROTOCOL      *This,
    104   IN EFI_DEVICE_PATH_PROTOCOL   **DevicePath
    105   )
    106 {
    107   EFI_DEVICE_PATH_PROTOCOL *NewDevicePathNode;
    108 
    109   NewDevicePathNode = CreateDeviceNode (HARDWARE_DEVICE_PATH, HW_VENDOR_DP, sizeof (VENDOR_DEVICE_PATH));
    110   CopyGuid (& ((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid, &mDwEmmcDevicePathGuid);
    111 
    112   *DevicePath = NewDevicePathNode;
    113   return EFI_SUCCESS;
    114 }
    115 
    116 EFI_STATUS
    117 DwEmmcUpdateClock (
    118   VOID
    119   )
    120 {
    121   UINT32 Data;
    122 
    123   /* CMD_UPDATE_CLK */
    124   Data = BIT_CMD_WAIT_PRVDATA_COMPLETE | BIT_CMD_UPDATE_CLOCK_ONLY |
    125 	 BIT_CMD_START;
    126   MmioWrite32 (DWEMMC_CMD, Data);
    127   while (1) {
    128     Data = MmioRead32 (DWEMMC_CMD);
    129     if (!(Data & CMD_START_BIT))
    130       break;
    131     Data = MmioRead32 (DWEMMC_RINTSTS);
    132     if (Data & DWEMMC_INT_HLE)
    133     {
    134       Print (L"failed to update mmc clock frequency\n");
    135       return EFI_DEVICE_ERROR;
    136     }
    137   }
    138   return EFI_SUCCESS;
    139 }
    140 
    141 EFI_STATUS
    142 DwEmmcSetClock (
    143   IN UINTN                     ClockFreq
    144   )
    145 {
    146   UINT32 Divider, Rate, Data;
    147   EFI_STATUS Status;
    148   BOOLEAN Found = FALSE;
    149 
    150   for (Divider = 1; Divider < 256; Divider++) {
    151     Rate = PcdGet32 (PcdDwEmmcDxeClockFrequencyInHz);
    152     if ((Rate / (2 * Divider)) <= ClockFreq) {
    153       Found = TRUE;
    154       break;
    155     }
    156   }
    157   if (Found == FALSE)
    158     return EFI_NOT_FOUND;
    159 
    160   // Wait until MMC is idle
    161   do {
    162     Data = MmioRead32 (DWEMMC_STATUS);
    163   } while (Data & DWEMMC_STS_DATA_BUSY);
    164 
    165   // Disable MMC clock first
    166   MmioWrite32 (DWEMMC_CLKENA, 0);
    167   Status = DwEmmcUpdateClock ();
    168   ASSERT (!EFI_ERROR (Status));
    169 
    170   MmioWrite32 (DWEMMC_CLKDIV, Divider);
    171   Status = DwEmmcUpdateClock ();
    172   ASSERT (!EFI_ERROR (Status));
    173 
    174   // Enable MMC clock
    175   MmioWrite32 (DWEMMC_CLKENA, 1);
    176   MmioWrite32 (DWEMMC_CLKSRC, 0);
    177   Status = DwEmmcUpdateClock ();
    178   ASSERT (!EFI_ERROR (Status));
    179   return EFI_SUCCESS;
    180 }
    181 
    182 EFI_STATUS
    183 DwEmmcNotifyState (
    184   IN EFI_MMC_HOST_PROTOCOL     *This,
    185   IN MMC_STATE                 State
    186   )
    187 {
    188   UINT32      Data;
    189   EFI_STATUS  Status;
    190 
    191   switch (State) {
    192   case MmcInvalidState:
    193     ASSERT (0);
    194     break;
    195   case MmcHwInitializationState:
    196     MmioWrite32 (DWEMMC_PWREN, 1);
    197 
    198     // If device already turn on then restart it
    199     Data = DWEMMC_CTRL_RESET_ALL;
    200     MmioWrite32 (DWEMMC_CTRL, Data);
    201     do {
    202       // Wait until reset operation finished
    203       Data = MmioRead32 (DWEMMC_CTRL);
    204     } while (Data & DWEMMC_CTRL_RESET_ALL);
    205 
    206     // Setup clock that could not be higher than 400KHz.
    207     Status = DwEmmcSetClock (400000);
    208     ASSERT (!EFI_ERROR (Status));
    209     MicroSecondDelay (100);
    210 
    211     MmioWrite32 (DWEMMC_RINTSTS, ~0);
    212     MmioWrite32 (DWEMMC_INTMASK, 0);
    213     MmioWrite32 (DWEMMC_TMOUT, ~0);
    214     MmioWrite32 (DWEMMC_IDINTEN, 0);
    215     MmioWrite32 (DWEMMC_BMOD, DWEMMC_IDMAC_SWRESET);
    216 
    217     MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
    218     do {
    219       Data = MmioRead32 (DWEMMC_BMOD);
    220     } while (Data & DWEMMC_IDMAC_SWRESET);
    221     break;
    222   case MmcIdleState:
    223     break;
    224   case MmcReadyState:
    225     break;
    226   case MmcIdentificationState:
    227     break;
    228   case MmcStandByState:
    229     break;
    230   case MmcTransferState:
    231     break;
    232   case MmcSendingDataState:
    233     break;
    234   case MmcReceiveDataState:
    235     break;
    236   case MmcProgrammingState:
    237     break;
    238   case MmcDisconnectState:
    239     break;
    240   default:
    241     ASSERT (0);
    242   }
    243   return EFI_SUCCESS;
    244 }
    245 
    246 // Need to prepare DMA buffer first before sending commands to MMC card
    247 BOOLEAN
    248 IsPendingReadCommand (
    249   IN MMC_CMD                    MmcCmd
    250   )
    251 {
    252   UINTN  Mask;
    253 
    254   Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_READ;
    255   if ((MmcCmd & Mask) == Mask)
    256     return TRUE;
    257   return FALSE;
    258 }
    259 
    260 BOOLEAN
    261 IsPendingWriteCommand (
    262   IN MMC_CMD                    MmcCmd
    263   )
    264 {
    265   UINTN  Mask;
    266 
    267   Mask = BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE;
    268   if ((MmcCmd & Mask) == Mask)
    269     return TRUE;
    270   return FALSE;
    271 }
    272 
    273 EFI_STATUS
    274 SendCommand (
    275   IN MMC_CMD                    MmcCmd,
    276   IN UINT32                     Argument
    277   )
    278 {
    279   UINT32      Data, ErrMask;
    280 
    281   // Wait until MMC is idle
    282   do {
    283     Data = MmioRead32 (DWEMMC_STATUS);
    284   } while (Data & DWEMMC_STS_DATA_BUSY);
    285 
    286   MmioWrite32 (DWEMMC_RINTSTS, ~0);
    287   MmioWrite32 (DWEMMC_CMDARG, Argument);
    288   MmioWrite32 (DWEMMC_CMD, MmcCmd);
    289 
    290   ErrMask = DWEMMC_INT_EBE | DWEMMC_INT_HLE | DWEMMC_INT_RTO |
    291             DWEMMC_INT_RCRC | DWEMMC_INT_RE;
    292   ErrMask |= DWEMMC_INT_DCRC | DWEMMC_INT_DRT | DWEMMC_INT_SBE;
    293   do {
    294     MicroSecondDelay(500);
    295     Data = MmioRead32 (DWEMMC_RINTSTS);
    296 
    297     if (Data & ErrMask)
    298       return EFI_DEVICE_ERROR;
    299     if (Data & DWEMMC_INT_DTO)	// Transfer Done
    300       break;
    301   } while (!(Data & DWEMMC_INT_CMD_DONE));
    302   return EFI_SUCCESS;
    303 }
    304 
    305 EFI_STATUS
    306 DwEmmcSendCommand (
    307   IN EFI_MMC_HOST_PROTOCOL     *This,
    308   IN MMC_CMD                    MmcCmd,
    309   IN UINT32                     Argument
    310   )
    311 {
    312   UINT32       Cmd = 0;
    313   EFI_STATUS   Status = EFI_SUCCESS;
    314 
    315   switch (MMC_GET_INDX(MmcCmd)) {
    316   case MMC_INDX(0):
    317     Cmd = BIT_CMD_SEND_INIT;
    318     break;
    319   case MMC_INDX(1):
    320     Cmd = BIT_CMD_RESPONSE_EXPECT;
    321     break;
    322   case MMC_INDX(2):
    323     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_LONG_RESPONSE |
    324            BIT_CMD_CHECK_RESPONSE_CRC | BIT_CMD_SEND_INIT;
    325     break;
    326   case MMC_INDX(3):
    327     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    328            BIT_CMD_SEND_INIT;
    329     break;
    330   case MMC_INDX(7):
    331     if (Argument)
    332         Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
    333     else
    334         Cmd = 0;
    335     break;
    336   case MMC_INDX(8):
    337     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    338            BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
    339            BIT_CMD_WAIT_PRVDATA_COMPLETE;
    340     break;
    341   case MMC_INDX(9):
    342     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    343            BIT_CMD_LONG_RESPONSE;
    344     break;
    345   case MMC_INDX(12):
    346     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    347            BIT_CMD_STOP_ABORT_CMD;
    348     break;
    349   case MMC_INDX(13):
    350     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    351            BIT_CMD_WAIT_PRVDATA_COMPLETE;
    352     break;
    353   case MMC_INDX(16):
    354     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    355            BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
    356            BIT_CMD_WAIT_PRVDATA_COMPLETE;
    357     break;
    358   case MMC_INDX(17):
    359   case MMC_INDX(18):
    360     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    361            BIT_CMD_DATA_EXPECTED | BIT_CMD_READ |
    362            BIT_CMD_WAIT_PRVDATA_COMPLETE;
    363     break;
    364   case MMC_INDX(24):
    365   case MMC_INDX(25):
    366     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    367            BIT_CMD_DATA_EXPECTED | BIT_CMD_WRITE |
    368            BIT_CMD_WAIT_PRVDATA_COMPLETE;
    369     break;
    370   case MMC_INDX(30):
    371     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC |
    372            BIT_CMD_DATA_EXPECTED;
    373     break;
    374   default:
    375     Cmd = BIT_CMD_RESPONSE_EXPECT | BIT_CMD_CHECK_RESPONSE_CRC;
    376     break;
    377   }
    378 
    379   Cmd |= MMC_GET_INDX(MmcCmd) | BIT_CMD_USE_HOLD_REG | BIT_CMD_START;
    380   if (IsPendingReadCommand (Cmd) || IsPendingWriteCommand (Cmd)) {
    381     mDwEmmcCommand = Cmd;
    382     mDwEmmcArgument = Argument;
    383   } else {
    384     Status = SendCommand (Cmd, Argument);
    385   }
    386   return Status;
    387 }
    388 
    389 EFI_STATUS
    390 DwEmmcReceiveResponse (
    391   IN EFI_MMC_HOST_PROTOCOL     *This,
    392   IN MMC_RESPONSE_TYPE          Type,
    393   IN UINT32*                    Buffer
    394   )
    395 {
    396   if (Buffer == NULL) {
    397     return EFI_INVALID_PARAMETER;
    398   }
    399 
    400   if (   (Type == MMC_RESPONSE_TYPE_R1)
    401       || (Type == MMC_RESPONSE_TYPE_R1b)
    402       || (Type == MMC_RESPONSE_TYPE_R3)
    403       || (Type == MMC_RESPONSE_TYPE_R6)
    404       || (Type == MMC_RESPONSE_TYPE_R7))
    405   {
    406     Buffer[0] = MmioRead32 (DWEMMC_RESP0);
    407   } else if (Type == MMC_RESPONSE_TYPE_R2) {
    408     Buffer[0] = MmioRead32 (DWEMMC_RESP0);
    409     Buffer[1] = MmioRead32 (DWEMMC_RESP1);
    410     Buffer[2] = MmioRead32 (DWEMMC_RESP2);
    411     Buffer[3] = MmioRead32 (DWEMMC_RESP3);
    412   }
    413   return EFI_SUCCESS;
    414 }
    415 
    416 EFI_STATUS
    417 PrepareDmaData (
    418   IN DWEMMC_IDMAC_DESCRIPTOR*    IdmacDesc,
    419   IN UINTN                      Length,
    420   IN UINT32*                    Buffer
    421   )
    422 {
    423   UINTN  Cnt, Blks, Idx, LastIdx;
    424 
    425   Cnt = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
    426   Blks = (Length + DWEMMC_BLOCK_SIZE - 1) / DWEMMC_BLOCK_SIZE;
    427   Length = DWEMMC_BLOCK_SIZE * Blks;
    428 
    429   for (Idx = 0; Idx < Cnt; Idx++) {
    430     (IdmacDesc + Idx)->Des0 = DWEMMC_IDMAC_DES0_OWN | DWEMMC_IDMAC_DES0_CH |
    431 	    		      DWEMMC_IDMAC_DES0_DIC;
    432     (IdmacDesc + Idx)->Des1 = DWEMMC_IDMAC_DES1_BS1(DWEMMC_DMA_BUF_SIZE);
    433     /* Buffer Address */
    434     (IdmacDesc + Idx)->Des2 = (UINT32)((UINTN)Buffer + DWEMMC_DMA_BUF_SIZE * Idx);
    435     /* Next Descriptor Address */
    436     (IdmacDesc + Idx)->Des3 = (UINT32)((UINTN)IdmacDesc +
    437    	                               (sizeof(DWEMMC_IDMAC_DESCRIPTOR) * (Idx + 1)));
    438   }
    439   /* First Descriptor */
    440   IdmacDesc->Des0 |= DWEMMC_IDMAC_DES0_FS;
    441   /* Last Descriptor */
    442   LastIdx = Cnt - 1;
    443   (IdmacDesc + LastIdx)->Des0 |= DWEMMC_IDMAC_DES0_LD;
    444   (IdmacDesc + LastIdx)->Des0 &= ~(DWEMMC_IDMAC_DES0_DIC | DWEMMC_IDMAC_DES0_CH);
    445   (IdmacDesc + LastIdx)->Des1 = DWEMMC_IDMAC_DES1_BS1(Length -
    446    		                (LastIdx * DWEMMC_DMA_BUF_SIZE));
    447   /* Set the Next field of Last Descriptor */
    448   (IdmacDesc + LastIdx)->Des3 = 0;
    449   MmioWrite32 (DWEMMC_DBADDR, (UINT32)((UINTN)IdmacDesc));
    450 
    451   return EFI_SUCCESS;
    452 }
    453 
    454 VOID
    455 StartDma (
    456   UINTN    Length
    457   )
    458 {
    459   UINT32 Data;
    460 
    461   Data = MmioRead32 (DWEMMC_CTRL);
    462   Data |= DWEMMC_CTRL_INT_EN | DWEMMC_CTRL_DMA_EN | DWEMMC_CTRL_IDMAC_EN;
    463   MmioWrite32 (DWEMMC_CTRL, Data);
    464   Data = MmioRead32 (DWEMMC_BMOD);
    465   Data |= DWEMMC_IDMAC_ENABLE | DWEMMC_IDMAC_FB;
    466   MmioWrite32 (DWEMMC_BMOD, Data);
    467 
    468   MmioWrite32 (DWEMMC_BLKSIZ, DWEMMC_BLOCK_SIZE);
    469   MmioWrite32 (DWEMMC_BYTCNT, Length);
    470 }
    471 
    472 EFI_STATUS
    473 DwEmmcReadBlockData (
    474   IN EFI_MMC_HOST_PROTOCOL     *This,
    475   IN EFI_LBA                    Lba,
    476   IN UINTN                      Length,
    477   IN UINT32*                   Buffer
    478   )
    479 {
    480   EFI_STATUS  Status;
    481   UINT32      DescPages, CountPerPage, Count;
    482   EFI_TPL     Tpl;
    483 
    484   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    485 
    486   CountPerPage = EFI_PAGE_SIZE / 16;
    487   Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
    488   DescPages = (Count + CountPerPage - 1) / CountPerPage;
    489 
    490   InvalidateDataCacheRange (Buffer, Length);
    491 
    492   Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
    493   if (EFI_ERROR (Status))
    494     goto out;
    495 
    496   WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
    497   StartDma (Length);
    498 
    499   Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
    500   if (EFI_ERROR (Status)) {
    501     DEBUG ((EFI_D_ERROR, "Failed to read data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
    502     goto out;
    503   }
    504 out:
    505   // Restore Tpl
    506   gBS->RestoreTPL (Tpl);
    507   return Status;
    508 }
    509 
    510 EFI_STATUS
    511 DwEmmcWriteBlockData (
    512   IN EFI_MMC_HOST_PROTOCOL     *This,
    513   IN EFI_LBA                    Lba,
    514   IN UINTN                      Length,
    515   IN UINT32*                    Buffer
    516   )
    517 {
    518   EFI_STATUS  Status;
    519   UINT32      DescPages, CountPerPage, Count;
    520   EFI_TPL     Tpl;
    521 
    522   Tpl = gBS->RaiseTPL (TPL_NOTIFY);
    523 
    524   CountPerPage = EFI_PAGE_SIZE / 16;
    525   Count = (Length + DWEMMC_DMA_BUF_SIZE - 1) / DWEMMC_DMA_BUF_SIZE;
    526   DescPages = (Count + CountPerPage - 1) / CountPerPage;
    527 
    528   WriteBackDataCacheRange (Buffer, Length);
    529 
    530   Status = PrepareDmaData (gpIdmacDesc, Length, Buffer);
    531   if (EFI_ERROR (Status))
    532     goto out;
    533 
    534   WriteBackDataCacheRange (gpIdmacDesc, DescPages * EFI_PAGE_SIZE);
    535   StartDma (Length);
    536 
    537   Status = SendCommand (mDwEmmcCommand, mDwEmmcArgument);
    538   if (EFI_ERROR (Status)) {
    539     DEBUG ((EFI_D_ERROR, "Failed to write data, mDwEmmcCommand:%x, mDwEmmcArgument:%x, Status:%r\n", mDwEmmcCommand, mDwEmmcArgument, Status));
    540     goto out;
    541   }
    542 out:
    543   // Restore Tpl
    544   gBS->RestoreTPL (Tpl);
    545   return Status;
    546 }
    547 
    548 EFI_STATUS
    549 DwEmmcSetIos (
    550   IN EFI_MMC_HOST_PROTOCOL      *This,
    551   IN  UINT32                    BusClockFreq,
    552   IN  UINT32                    BusWidth,
    553   IN  UINT32                    TimingMode
    554   )
    555 {
    556   EFI_STATUS Status = EFI_SUCCESS;
    557   UINT32    Data;
    558 
    559   if (TimingMode != EMMCBACKWARD) {
    560     Data = MmioRead32 (DWEMMC_UHSREG);
    561     switch (TimingMode) {
    562     case EMMCHS52DDR1V2:
    563     case EMMCHS52DDR1V8:
    564       Data |= 1 << 16;
    565       break;
    566     case EMMCHS52:
    567     case EMMCHS26:
    568       Data &= ~(1 << 16);
    569       break;
    570     default:
    571       return EFI_UNSUPPORTED;
    572     }
    573     MmioWrite32 (DWEMMC_UHSREG, Data);
    574   }
    575 
    576   switch (BusWidth) {
    577   case 1:
    578     MmioWrite32 (DWEMMC_CTYPE, 0);
    579     break;
    580   case 4:
    581     MmioWrite32 (DWEMMC_CTYPE, 1);
    582     break;
    583   case 8:
    584     MmioWrite32 (DWEMMC_CTYPE, 1 << 16);
    585     break;
    586   default:
    587     return EFI_UNSUPPORTED;
    588   }
    589   if (BusClockFreq) {
    590     Status = DwEmmcSetClock (BusClockFreq);
    591   }
    592   return Status;
    593 }
    594 
    595 BOOLEAN
    596 DwEmmcIsMultiBlock (
    597   IN EFI_MMC_HOST_PROTOCOL      *This
    598   )
    599 {
    600   return TRUE;
    601 }
    602 
    603 EFI_MMC_HOST_PROTOCOL gMciHost = {
    604   MMC_HOST_PROTOCOL_REVISION,
    605   DwEmmcIsCardPresent,
    606   DwEmmcIsReadOnly,
    607   DwEmmcBuildDevicePath,
    608   DwEmmcNotifyState,
    609   DwEmmcSendCommand,
    610   DwEmmcReceiveResponse,
    611   DwEmmcReadBlockData,
    612   DwEmmcWriteBlockData,
    613   DwEmmcSetIos,
    614   DwEmmcIsMultiBlock
    615 };
    616 
    617 EFI_STATUS
    618 DwEmmcDxeInitialize (
    619   IN EFI_HANDLE         ImageHandle,
    620   IN EFI_SYSTEM_TABLE   *SystemTable
    621   )
    622 {
    623   EFI_STATUS    Status;
    624   EFI_HANDLE    Handle;
    625 
    626   Handle = NULL;
    627 
    628   gpIdmacDesc = (DWEMMC_IDMAC_DESCRIPTOR *)AllocatePages (DWEMMC_MAX_DESC_PAGES);
    629   if (gpIdmacDesc == NULL)
    630     return EFI_BUFFER_TOO_SMALL;
    631 
    632   DEBUG ((EFI_D_BLKIO, "DwEmmcDxeInitialize()\n"));
    633 
    634   //Publish Component Name, BlockIO protocol interfaces
    635   Status = gBS->InstallMultipleProtocolInterfaces (
    636                   &Handle,
    637                   &gEfiMmcHostProtocolGuid,         &gMciHost,
    638                   NULL
    639                   );
    640   ASSERT_EFI_ERROR (Status);
    641 
    642   return EFI_SUCCESS;
    643 }
    644