]> git.proxmox.com Git - mirror_edk2.git/blobdiff - QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
QuarkSocPkg: Add new package for Quark SoC X1000
[mirror_edk2.git] / QuarkSocPkg / QuarkSouthCluster / Sdio / Dxe / SDControllerDxe / SDController.c
diff --git a/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c b/QuarkSocPkg/QuarkSouthCluster/Sdio/Dxe/SDControllerDxe/SDController.c
new file mode 100644 (file)
index 0000000..18e85c8
--- /dev/null
@@ -0,0 +1,1789 @@
+/** @file\r
+\r
+The SD host controller driver model and HC protocol routines.\r
+\r
+Copyright (c) 2013-2015 Intel Corporation.\r
+\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+\r
+\r
+#include "SDController.h"\r
+\r
+\r
+EFI_DRIVER_BINDING_PROTOCOL gSDControllerDriverBinding = {\r
+  SDControllerSupported,\r
+  SDControllerStart,\r
+  SDControllerStop,\r
+  0x20,\r
+  NULL,\r
+  NULL\r
+};\r
+\r
+\r
+EFI_SD_HOST_IO_PROTOCOL  mSDHostIo = {\r
+  EFI_SD_HOST_IO_PROTOCOL_REVISION_01,\r
+  {\r
+    0, // HighSpeedSupport\r
+    0, // V18Support\r
+    0, // V30Support\r
+    0, // V33Support\r
+    0, // Reserved0\r
+    0, // BusWidth4\r
+    0, // BusWidth8\r
+    0, // Reserved1\r
+    0, // Reserved1\r
+    (512 * 1024) //BoundarySize\r
+  },\r
+  SendCommand,\r
+  SetClockFrequency,\r
+  SetBusWidth,\r
+  SetHostVoltage,\r
+  ResetSDHost,\r
+  EnableAutoStopCmd,\r
+  DetectCardAndInitHost,\r
+  SetBlockLength,\r
+  SetHighSpeedMode,\r
+  SetDDRMode\r
+};\r
+\r
+/**\r
+  Find sdclk_freq_sel and upr_sdclk_freq_sel bits\r
+  for Clock Control Register (CLK_CTL)Offset 2Ch when using 8bit or 10bit\r
+  divided clock mode.\r
+\r
+  @param  BaseClockFreg        Base Clock Frequency in Hz For SD Clock in the\r
+                               Capabilities register.\r
+  @param  TargetFreq           Target Frequency in Hz to reach.\r
+  @param  Is8BitMode           True if 8-bit Divided Clock Mode else 10bit mode.\r
+  @param  Bits                 sdclk_freq_sel and upr_sdclk_freq_sel bits for\r
+                               TargetFreq.\r
+\r
+  @return EFI_SUCCESS          // Bits setup.\r
+  @return EFI_UNSUPPORTED      // Cannot divide base clock to reach target clock.\r
+**/\r
+EFI_STATUS\r
+DividedClockModeBits (\r
+  IN CONST UINTN                          BaseClockFreg,\r
+  IN CONST UINTN                          TargetFreq,\r
+  IN CONST BOOLEAN                        Is8BitMode,\r
+  OUT UINT16                              *Bits\r
+  )\r
+{\r
+  UINTN                             N;\r
+  UINTN                             CurrFreq;\r
+\r
+ *Bits = 0;\r
+  CurrFreq = BaseClockFreg;\r
+  N = 0;\r
+  //\r
+  // N == 0 same for 8bit & 10bit mode i.e. BaseClockFreg of controller.\r
+  //\r
+  if (TargetFreq < CurrFreq) {\r
+    if (Is8BitMode) {\r
+      N = 1;\r
+      do {\r
+        //\r
+        // N values for 8bit mode when N > 0.\r
+        //  Bit[15:8] SDCLK Frequency Select at offset 2Ch\r
+        //    80h - base clock divided by 256\r
+        //    40h - base clock divided by 128\r
+        //    20h - base clock divided by 64\r
+        //    10h - base clock divided by 32\r
+        //    08h - base clock divided by 16\r
+        //    04h - base clock divided by 8\r
+        //    02h - base clock divided by 4\r
+        //    01h - base clock divided by 2\r
+        //\r
+        CurrFreq = BaseClockFreg / (2 * N);\r
+        if (TargetFreq >= CurrFreq) {\r
+          break;\r
+        }\r
+        N *= 2;\r
+        if (N > V_MMIO_CLKCTL_MAX_8BIT_FREQ_SEL) {\r
+          return EFI_UNSUPPORTED;\r
+        }\r
+      } while (TRUE);\r
+    } else {\r
+      N = 1;\r
+      CurrFreq = BaseClockFreg / (2 * N);\r
+      //\r
+      // (try N = 0 or 1 first since don't want divide by 0).\r
+      //\r
+      if (TargetFreq < CurrFreq) {\r
+        //\r
+        // If still no match then calculate it for 10bit.\r
+        // N values for 10bit mode.\r
+        // N 1/2N Divided Clock (Duty 50%).\r
+        // from Spec "The length of divider is extended to 10 bits and all\r
+        // divider values shall be supported.\r
+        //\r
+        N = (BaseClockFreg / TargetFreq) / 2;\r
+\r
+        //\r
+        // Can only be N or N+1;\r
+        //\r
+        CurrFreq = BaseClockFreg / (2 * N);\r
+        if (TargetFreq < CurrFreq) {\r
+          N++;\r
+          CurrFreq = BaseClockFreg / (2 * N);\r
+        }\r
+\r
+        if (N > V_MMIO_CLKCTL_MAX_10BIT_FREQ_SEL) {\r
+          return EFI_UNSUPPORTED;\r
+        }\r
+\r
+        //\r
+        // Set upper bits of SDCLK Frequency Select (bits 7:6 of reg 0x2c).\r
+        //\r
+        *Bits |= ((UINT16) ((N >> 2) & B_MMIO_CLKCTL_UPR_SDCLK_FREQ_SEL_MASK));\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set lower bits of SDCLK Frequency Select (bits 15:8 of reg 0x2c).\r
+  //\r
+  *Bits |= ((UINT16) ((UINT8) N) << 8);\r
+  DEBUG (\r
+    (EFI_D_INFO,\r
+    "SDIO:DividedClockModeBits: %dbit mode Want %dHz Got %dHz bits = %04x\r\n",\r
+    (Is8BitMode) ? 8 : 10,\r
+    TargetFreq,\r
+    CurrFreq,\r
+    (UINTN) *Bits\r
+     ));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Print type of error and command index\r
+\r
+  @param  CommandIndex         Command index to set the command index field of command register.\r
+  @param  ErrorCode            Error interrupt status read from host controller\r
+\r
+  @return EFI_DEVICE_ERROR\r
+  @return EFI_TIMEOUT\r
+  @return EFI_CRC_ERROR\r
+\r
+**/\r
+EFI_STATUS\r
+GetErrorReason (\r
+  IN  UINT16    CommandIndex,\r
+  IN  UINT16    ErrorCode\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  DEBUG((EFI_D_ERROR, "[%2d] -- ", CommandIndex));\r
+\r
+  if (ErrorCode & BIT0) {\r
+    Status = EFI_TIMEOUT;\r
+    DEBUG((EFI_D_ERROR, "Command Timeout Erro"));\r
+  }\r
+\r
+  if (ErrorCode & BIT1) {\r
+    Status = EFI_CRC_ERROR;\r
+    DEBUG((EFI_D_ERROR, "Command CRC Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT2) {\r
+    DEBUG((EFI_D_ERROR, "Command End Bit Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT3) {\r
+    DEBUG((EFI_D_ERROR, "Command Index Error"));\r
+  }\r
+  if (ErrorCode & BIT4) {\r
+    Status = EFI_TIMEOUT;\r
+    DEBUG((EFI_D_ERROR, "Data Timeout Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT5) {\r
+    Status = EFI_CRC_ERROR;\r
+    DEBUG((EFI_D_ERROR, "Data CRC Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT6) {\r
+    DEBUG((EFI_D_ERROR, "Data End Bit Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT7) {\r
+    DEBUG((EFI_D_ERROR, "Current Limit Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT8) {\r
+    DEBUG((EFI_D_ERROR, "Auto CMD12 Error"));\r
+  }\r
+\r
+  if (ErrorCode & BIT9) {\r
+    DEBUG((EFI_D_ERROR, "ADMA Error"));\r
+  }\r
+\r
+  DEBUG((EFI_D_ERROR, "\n"));\r
+\r
+  return Status;\r
+}\r
+/**\r
+  Enable/Disable High Speed transfer mode\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  Enable                TRUE to Enable, FALSE to Disable\r
+\r
+  @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+SetHighSpeedMode (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  BOOLEAN                    Enable\r
+  )\r
+{\r
+  UINT32                 Data;\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  if (Enable) {\r
+    if (PcdGetBool(PcdSdHciQuirkNoHiSpd)) {\r
+      DEBUG ((EFI_D_INFO, "SDIO: Quirk never set High Speed Enable bit\r\n"));\r
+      return EFI_SUCCESS;\r
+    }\r
+    DEBUG ((EFI_D_INFO, "Enable High Speed transfer mode ... \r\n"));\r
+    Data |= BIT2;\r
+  } else {\r
+    Data &= ~BIT2;\r
+  }\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+              (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+              );\r
+  return EFI_SUCCESS;\r
+}\r
+EFI_STATUS\r
+EFIAPI\r
+SetDDRMode (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  BOOLEAN                    Enable\r
+  )\r
+{\r
+  UINT16                 Data;\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL2,\r
+               1,\r
+               &Data\r
+               );\r
+  Data &= 0xFFF0;\r
+  if (Enable) {\r
+    Data |= 0x0004; // Enable DDR50 by default, later should enable other mode like HS200/400\r
+    Data |= BIT3;   // Enable 1.8V Signaling\r
+  }\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+              (UINT64)MMIO_HOSTCTL2,\r
+               1,\r
+               &Data\r
+              );\r
+  return EFI_SUCCESS;\r
+}\r
+/**\r
+  Power on/off the LED associated with the slot\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  Enable                TRUE to set LED on, FALSE to set LED off\r
+\r
+  @return EFI_SUCCESS\r
+**/\r
+EFI_STATUS\r
+HostLEDEnable (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  BOOLEAN                    Enable\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT32                 Data;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  if (Enable) {\r
+    //\r
+    //LED On\r
+    //\r
+    Data |= BIT0;\r
+  } else {\r
+    //\r
+    //LED Off\r
+    //\r
+    Data &= ~BIT0;\r
+  }\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  The main function used to send the command to the card inserted into the SD host slot.\r
+  It will assemble the arguments to set the command register and wait for the command\r
+  and transfer completed until timeout. Then it will read the response register to fill\r
+  the ResponseData.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  CommandIndex          The command index to set the command index field of command register.\r
+  @param  Argument              Command argument to set the argument field of command register.\r
+  @param  DataType              TRANSFER_TYPE, indicates no data, data in or data out.\r
+  @param  Buffer                Contains the data read from / write to the device.\r
+  @param  BufferSize            The size of the buffer.\r
+  @param  ResponseType          RESPONSE_TYPE.\r
+  @param  TimeOut               Time out value in 1 ms unit.\r
+  @param  ResponseData          Depending on the ResponseType, such as CSD or card status.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_INVALID_PARAMETER\r
+  @retval EFI_OUT_OF_RESOURCES\r
+  @retval EFI_TIMEOUT\r
+  @retval EFI_DEVICE_ERROR\r
+\r
+**/\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+SendCommand (\r
+  IN   EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN   UINT16                     CommandIndex,\r
+  IN   UINT32                     Argument,\r
+  IN   TRANSFER_TYPE              DataType,\r
+  IN   UINT8                      *Buffer, OPTIONAL\r
+  IN   UINT32                     BufferSize,\r
+  IN   RESPONSE_TYPE              ResponseType,\r
+  IN   UINT32                     TimeOut,\r
+  OUT  UINT32                     *ResponseData OPTIONAL\r
+  )\r
+/*++\r
+\r
+  Routine Description:\r
+    The main function used to send the command to the card inserted into the SD host\r
+    slot.\r
+    It will assemble the arguments to set the command register and wait for the command\r
+    and transfer completed until timeout. Then it will read the response register to fill\r
+    the ResponseData\r
+\r
+  Arguments:\r
+    This           - Pointer to EFI_SD_HOST_IO_PROTOCOL\r
+    CommandIndex   - The command index to set the command index field of command register\r
+    Argument       - Command argument to set the argument field of command register\r
+    DataType       - TRANSFER_TYPE, indicates no data, data in or data out\r
+    Buffer         - Contains the data read from / write to the device\r
+    BufferSize     - The size of the buffer\r
+    ResponseType   - RESPONSE_TYPE\r
+    TimeOut        - Time out value in 1 ms unit\r
+    ResponseData   - Depending on the ResponseType, such as CSD or card status\r
+\r
+  Returns:\r
+    EFI_SUCCESS\r
+    EFI_INVALID_PARAMETER\r
+    EFI_OUT_OF_RESOURCES\r
+    EFI_TIMEOUT\r
+    EFI_DEVICE_ERROR\r
+\r
+--*/\r
+{\r
+  EFI_STATUS            Status;\r
+  SDHOST_DATA           *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  UINT32                ResponseDataCount;\r
+  UINT32                Data;\r
+  UINT64                Data64;\r
+  UINT8                 Index;\r
+  INTN                  TimeOut2;\r
+  BOOLEAN               AutoCMD12Enable = FALSE;\r
+\r
+\r
+  Status             = EFI_SUCCESS;\r
+  ResponseDataCount  = 1;\r
+  SDHostData         = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo              = SDHostData->PciIo;\r
+  AutoCMD12Enable    =  (CommandIndex & AUTO_CMD12_ENABLE) ? TRUE : FALSE;\r
+  CommandIndex       = CommandIndex & CMD_INDEX_MASK;\r
+\r
+  if (Buffer != NULL && DataType == NoData) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+    goto Exit;\r
+  }\r
+\r
+  if (((UINTN)Buffer & (This->HostCapability.BoundarySize - 1)) != (UINTN)NULL) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+    DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+    goto Exit;\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "SendCommand: Command Index = %d \r\n", CommandIndex));\r
+  //\r
+  TimeOut2 = 1000; // 10 ms\r
+  do {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 (UINT64)MMIO_PSTATE,\r
+                 1,\r
+                 &Data\r
+                 );\r
+     gBS->Stall (10);\r
+  }while ((TimeOut2-- > 0) && (Data & BIT0));\r
+  TimeOut2 = 1000; // 10 ms\r
+  do {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 (UINT64)MMIO_PSTATE,\r
+                 1,\r
+                 &Data\r
+                 );\r
+    gBS->Stall (10);\r
+  }while ((TimeOut2-- > 0) && (Data & BIT1));\r
+  //Clear status bits\r
+  //\r
+  Data = 0xFFFF;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_NINTSTS,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  Data = 0xFFFF;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_ERINTSTS,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+\r
+  if (Buffer != NULL) {\r
+     PciIo->Mem.Write (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint32,\r
+                  0,\r
+                  (UINT64)MMIO_DMAADR,\r
+                  1,\r
+                  &Buffer\r
+                  );\r
+\r
+     PciIo->Mem.Read (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint16,\r
+                  0,\r
+                  (UINT64)MMIO_BLKSZ,\r
+                  1,\r
+                  &Data\r
+                  );\r
+     Data &= ~(0xFFF);\r
+     if (BufferSize <= SDHostData->BlockLength) {\r
+       Data |= (BufferSize | 0x7000);\r
+     } else {\r
+       Data |= (SDHostData->BlockLength | 0x7000);\r
+     }\r
+\r
+\r
+     PciIo->Mem.Write (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint16,\r
+                  0,\r
+                  (UINT64)MMIO_BLKSZ,\r
+                  1,\r
+                  &Data\r
+                  );\r
+     if (BufferSize <= SDHostData->BlockLength) {\r
+       Data = 1;\r
+     } else {\r
+       Data = BufferSize / SDHostData->BlockLength;\r
+     }\r
+     PciIo->Mem.Write (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint16,\r
+                  0,\r
+                  (UINT64)MMIO_BLKCNT,\r
+                  1,\r
+                  &Data\r
+                  );\r
+\r
+  } else {\r
+    Data = 0;\r
+    PciIo->Mem.Write (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint16,\r
+                  0,\r
+                  (UINT64)MMIO_BLKSZ,\r
+                  1,\r
+                  &Data\r
+                  );\r
+    PciIo->Mem.Write (\r
+                  PciIo,\r
+                  EfiPciIoWidthUint16,\r
+                  0,\r
+                  (UINT64)MMIO_BLKCNT,\r
+                  1,\r
+                  &Data\r
+                  );\r
+  }\r
+\r
+  //\r
+  //Argument\r
+  //\r
+  Data = Argument;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               (UINT64)MMIO_CMDARG,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_XFRMODE,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+\r
+  DEBUG ((EFI_D_INFO, "Transfer mode read  = 0x%x \r\n", (Data & 0xFFFF)));\r
+  //\r
+  //BIT0 - DMA Enable\r
+  //BIT2 - Auto Cmd12\r
+  //\r
+  if (DataType == InData) {\r
+    Data |= BIT4 | BIT0;\r
+  } else if (DataType == OutData){\r
+    Data &= ~BIT4;\r
+    Data |= BIT0;\r
+  } else {\r
+    Data &= ~(BIT4 | BIT0);\r
+  }\r
+\r
+  if (BufferSize <= SDHostData->BlockLength) {\r
+    Data &= ~ (BIT5 | BIT1 | BIT2);\r
+    Data |= BIT1; // Enable block count always\r
+  } else {\r
+     if (SDHostData->IsAutoStopCmd && AutoCMD12Enable) {\r
+      Data |= (BIT5 | BIT1 | BIT2);\r
+     } else {\r
+      Data |= (BIT5 | BIT1);\r
+     }\r
+  }\r
+\r
+  DEBUG ((EFI_D_INFO, "Transfer mode write = 0x%x \r\n", (Data & 0xffff)));\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_XFRMODE,\r
+               1,\r
+               &Data\r
+               );\r
+  //\r
+  //Command\r
+  //\r
+  //ResponseTypeSelect    IndexCheck    CRCCheck    ResponseType\r
+  //  00                     0            0           NoResponse\r
+  //  01                     0            1           R2\r
+  //  10                     0            0           R3, R4\r
+  //  10                     1            1           R1, R5, R6, R7\r
+  //  11                     1            1           R1b, R5b\r
+  //\r
+  switch (ResponseType) {\r
+    case ResponseNo:\r
+      Data = (CommandIndex << 8);\r
+      ResponseDataCount = 0;\r
+      break;\r
+\r
+    case ResponseR1:\r
+    case ResponseR5:\r
+    case ResponseR6:\r
+    case ResponseR7:\r
+      Data = (CommandIndex << 8) | BIT1 | BIT4| BIT3;\r
+      ResponseDataCount = 1;\r
+      break;\r
+\r
+    case ResponseR1b:\r
+    case ResponseR5b:\r
+      Data = (CommandIndex << 8) | BIT0 | BIT1 | BIT4| BIT3;\r
+      ResponseDataCount = 1;\r
+      break;\r
+\r
+    case ResponseR2:\r
+      Data = (CommandIndex << 8) | BIT0 | BIT3;\r
+      ResponseDataCount = 4;\r
+      break;\r
+\r
+    case ResponseR3:\r
+    case ResponseR4:\r
+      Data = (CommandIndex << 8) | BIT1;\r
+      ResponseDataCount = 1;\r
+      break;\r
+\r
+    default:\r
+      ASSERT (0);\r
+      Status = EFI_INVALID_PARAMETER;\r
+      DEBUG ((EFI_D_ERROR, "SendCommand: invalid parameter \r\n"));\r
+      goto Exit;\r
+  }\r
+\r
+  if (DataType != NoData) {\r
+    Data |= BIT5;\r
+  }\r
+\r
+  HostLEDEnable (This, TRUE);\r
+\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_SDCMD,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+\r
+  Data = 0;\r
+  do {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0,\r
+                 (UINT64)MMIO_ERINTSTS,\r
+                 1,\r
+                 &Data\r
+                 );\r
+\r
+    if ((Data & 0x07FF) != 0) {\r
+      Status = GetErrorReason (CommandIndex, (UINT16)Data);\r
+      DEBUG ((EFI_D_ERROR, "SendCommand: Error happens \r\n"));\r
+      goto Exit;\r
+    }\r
+\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0,\r
+                 (UINT64)MMIO_NINTSTS,\r
+                 1,\r
+                 &Data\r
+                 );\r
+\r
+    if ((Data & BIT0) == BIT0) {\r
+       //\r
+       //Command completed, can read response\r
+       //\r
+       if (DataType == NoData) {\r
+         break;\r
+       } else {\r
+         //\r
+         //Transfer completed\r
+         //\r
+         if ((Data & BIT1) == BIT1) {\r
+           break;\r
+         }\r
+       }\r
+    }\r
+\r
+    gBS->Stall (1 * 1000);\r
+\r
+    TimeOut --;\r
+\r
+  } while (TimeOut > 0);\r
+\r
+  if (TimeOut == 0) {\r
+    Status = EFI_TIMEOUT;\r
+    DEBUG ((EFI_D_ERROR, "SendCommand: Time out \r\n"));\r
+    goto Exit;\r
+  }\r
+\r
+  if (ResponseData != NULL) {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint32,\r
+                 0,\r
+                 (UINT64)MMIO_RESP,\r
+                 ResponseDataCount,\r
+                 ResponseData\r
+                 );\r
+    if (ResponseType == ResponseR2) {\r
+      //\r
+      // Adjustment for R2 response\r
+      //\r
+      Data = 1;\r
+      for (Index = 0; Index < ResponseDataCount; Index++) {\r
+        Data64 = LShiftU64(*ResponseData, 8);\r
+        *ResponseData = (UINT32)((Data64 & 0xFFFFFFFF) | Data);\r
+        Data =  (UINT32)RShiftU64 (Data64, 32);\r
+        ResponseData++;\r
+      }\r
+    }\r
+  }\r
+\r
+Exit:\r
+  HostLEDEnable (This, FALSE);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set max clock frequency of the host, the actual frequency may not be the same as MaxFrequency.\r
+  It depends on the max frequency the host can support, divider, and host speed mode.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  MaxFrequency          Max frequency in HZ.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetClockFrequency (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  UINT32                     MaxFrequency\r
+  )\r
+{\r
+  UINT32                 Data;\r
+  UINT16                 FreqSelBits;\r
+  EFI_STATUS             Status;\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT32                 TimeOutCount;\r
+  UINT32                 Revision;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+  Data = 0;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  PciIo->Mem.Read (\r
+                PciIo,\r
+                EfiPciIoWidthUint8,\r
+                0,\r
+                (UINT64)MMIO_CTRLRVER,\r
+                1,\r
+                &Revision\r
+                );\r
+  Revision &= 0x000000FF;\r
+\r
+  Status = DividedClockModeBits (\r
+             SDHostData->BaseClockInMHz * 1000 * 1000,\r
+             MaxFrequency,\r
+             (Revision < SDHCI_SPEC_300),\r
+             &FreqSelBits\r
+             );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    //\r
+    // Cannot reach MaxFrequency with SDHostData->BaseClockInMHz.\r
+    //\r
+    ASSERT_EFI_ERROR (Status);\r
+    return Status;\r
+  }\r
+\r
+  Data = 0;\r
+\r
+  //\r
+  //Enable internal clock and Stop Clock Enable\r
+  //\r
+  Data = BIT0;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  TimeOutCount = TIME_OUT_1S;\r
+  do {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0,\r
+                 (UINT64)MMIO_CLKCTL,\r
+                 1,\r
+                 &Data\r
+                 );\r
+    gBS->Stall (1 * 1000);\r
+    TimeOutCount --;\r
+    if (TimeOutCount == 0) {\r
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+      return EFI_TIMEOUT;\r
+    }\r
+  } while ((Data & BIT1) != BIT1);\r
+\r
+  DEBUG ((EFI_D_INFO, "Base Clock In MHz: %d\r\n", SDHostData->BaseClockInMHz));\r
+\r
+  Data = (BIT0 | ((UINT32) FreqSelBits));\r
+  DEBUG ((EFI_D_INFO, "Data write to MMIO_CLKCTL: 0x%04x \r\n", Data));\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  TimeOutCount = TIME_OUT_1S;\r
+  do {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0,\r
+                 (UINT64)MMIO_CLKCTL,\r
+                 1,\r
+                 &Data\r
+                 );\r
+    gBS->Stall (1 * 1000);\r
+    TimeOutCount --;\r
+    if (TimeOutCount == 0) {\r
+      DEBUG ((EFI_D_ERROR, "SetClockFrequency: Time out \r\n"));\r
+      return EFI_TIMEOUT;\r
+    }\r
+  } while ((Data & BIT1) != BIT1);\r
+  gBS->Stall (20 * 1000);\r
+  Data |= BIT2;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set bus width of the host controller\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  BusWidth              Bus width in 1, 4, 8 bits.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBusWidth (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  UINT32                     BusWidth\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT8                  Data;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+\r
+  if ((BusWidth != 1) && (BusWidth != 4) && (BusWidth != 8)) {\r
+    DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((SDHostData->SDHostIo.HostCapability.BusWidth8 == FALSE) && (BusWidth == 8)) {\r
+     DEBUG ((EFI_D_ERROR, "SetBusWidth: Invalid parameter \r\n"));\r
+     return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  PciIo      = SDHostData->PciIo;\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+               );\r
+  //\r
+  // BIT5 8-bit MMC Support (MMC8):\r
+  // If set, IOH supports 8-bit MMC. When cleared, IOH does not support this feature\r
+  //\r
+  if (BusWidth == 8) {\r
+    DEBUG ((EFI_D_INFO, "Bus Width is 8-bit ... \r\n"));\r
+    Data |= BIT5;\r
+  } else if (BusWidth == 4) {\r
+    DEBUG ((EFI_D_INFO, "Bus Width is 4-bit ... \r\n"));\r
+    Data &= ~BIT5;\r
+    Data |= BIT1;\r
+  } else {\r
+    DEBUG ((EFI_D_INFO, "Bus Width is 1-bit ... \r\n"));\r
+    Data &= ~BIT5;\r
+    Data &= ~BIT1;\r
+  }\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_HOSTCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Set voltage which could supported by the host controller.\r
+  Support 0(Power off the host), 1.8V, 3.0V, 3.3V\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  Voltage               Units in 0.1 V.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_INVALID_PARAMETER\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetHostVoltage (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  UINT32                     Voltage\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT8                  Data;\r
+  EFI_STATUS             Status;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+  Status     = EFI_SUCCESS;\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_PWRCTL,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  if (Voltage == 0) {\r
+    //\r
+    //Power Off the host\r
+    //\r
+    Data &= ~BIT0;\r
+  } else if (Voltage <= 18 && This->HostCapability.V18Support) {\r
+     //\r
+     //1.8V\r
+     //\r
+     Data |= (BIT1 | BIT3 | BIT0);\r
+  } else if (Voltage > 18 &&  Voltage <= 30 && This->HostCapability.V30Support) {\r
+     //\r
+     //3.0V\r
+     //\r
+     Data |= (BIT2 | BIT3 | BIT0);\r
+  } else if (Voltage > 30 && Voltage <= 33 && This->HostCapability.V33Support) {\r
+     //\r
+     //3.3V\r
+     //\r
+     Data |= (BIT1 | BIT2 | BIT3 | BIT0);\r
+  } else {\r
+     Status = EFI_UNSUPPORTED;\r
+     goto Exit;\r
+  }\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_PWRCTL,\r
+               1,\r
+               &Data\r
+               );\r
+  gBS->Stall (10 * 1000);\r
+\r
+Exit:\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Reset the host controller.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  ResetAll              TRUE to reset all.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ResetSDHost (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  RESET_TYPE                 ResetType\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT32                 Data;\r
+  UINT16                 ErrStatus;\r
+  UINT32                 Mask;\r
+  UINT32                 TimeOutCount;\r
+  UINT16                 SaveClkCtl;\r
+  UINT16                 ZeroClkCtl;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+  Mask       = 0;\r
+  ErrStatus  = 0;\r
+\r
+  if (ResetType == Reset_Auto) {\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint16,\r
+                 0,\r
+                 (UINT64)MMIO_ERINTSTS,\r
+                 1,\r
+                 &ErrStatus\r
+                 );\r
+    if ((ErrStatus & 0xF) != 0) {\r
+      //\r
+      //Command Line\r
+      //\r
+      Mask |= BIT1;\r
+    }\r
+    if ((ErrStatus & 0x70) != 0) {\r
+      //\r
+      //Data Line\r
+      //\r
+      Mask |= BIT2;\r
+    }\r
+  }\r
+\r
+\r
+  if (ResetType == Reset_DAT || ResetType == Reset_DAT_CMD) {\r
+    Mask |= BIT2;\r
+  }\r
+  if (ResetType == Reset_CMD || ResetType == Reset_DAT_CMD) {\r
+    Mask |= BIT1;\r
+  }\r
+  if (ResetType == Reset_All) {\r
+    Mask = BIT0;\r
+  }\r
+\r
+  if (Mask == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  //\r
+  // To improve SD stability, we zero the MMIO_CLKCTL register and\r
+  // stall for 50 microseconds before reseting the controller.  We\r
+  // restore the register setting following the reset operation.\r
+  //\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &SaveClkCtl\r
+               );\r
+\r
+  ZeroClkCtl = (UINT16) 0;\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &ZeroClkCtl\r
+               );\r
+\r
+  gBS->Stall (50);\r
+\r
+  //\r
+  // Reset the SD host controller\r
+  //\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_SWRST,\r
+               1,\r
+               &Mask\r
+               );\r
+\r
+  Data          = 0;\r
+  TimeOutCount  = TIME_OUT_1S;\r
+  do {\r
+\r
+    gBS->Stall (1 * 1000);\r
+\r
+    TimeOutCount --;\r
+\r
+    PciIo->Mem.Read (\r
+                 PciIo,\r
+                 EfiPciIoWidthUint8,\r
+                 0,\r
+                 (UINT64)MMIO_SWRST,\r
+                 1,\r
+                 &Data\r
+                 );\r
+    if ((Data & Mask) == 0) {\r
+      break;\r
+    }\r
+  } while (TimeOutCount > 0);\r
+\r
+  //\r
+  // We now restore the MMIO_CLKCTL register which we set to 0 above.\r
+  //\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_CLKCTL,\r
+               1,\r
+               &SaveClkCtl\r
+               );\r
+\r
+  if (TimeOutCount == 0) {\r
+    DEBUG ((EFI_D_ERROR, "ResetSDHost: Time out \r\n"));\r
+    return EFI_TIMEOUT;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Enable auto stop on the host controller.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  Enable                TRUE to enable, FALSE to disable.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EnableAutoStopCmd (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  BOOLEAN                    Enable\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+  SDHostData->IsAutoStopCmd = Enable;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Set the Block length on the host controller.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+  @param  BlockLength           card supportes block length.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_TIMEOUT\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetBlockLength (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This,\r
+  IN  UINT32                     BlockLength\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+\r
+  DEBUG ((EFI_D_INFO, "Block length on the host controller: %d \r\n", BlockLength));\r
+  SDHostData->BlockLength = BlockLength;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Find whether these is a card inserted into the slot. If so init the host.\r
+  If not, return EFI_NOT_FOUND.\r
+\r
+  @param  This                  A pointer to the EFI_SD_HOST_IO_PROTOCOL instance.\r
+\r
+  @retval EFI_SUCCESS\r
+  @retval EFI_NOT_FOUND\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DetectCardAndInitHost (\r
+  IN  EFI_SD_HOST_IO_PROTOCOL    *This\r
+  )\r
+{\r
+  SDHOST_DATA            *SDHostData;\r
+  EFI_PCI_IO_PROTOCOL    *PciIo;\r
+  UINT32                 Data;\r
+  EFI_STATUS             Status;\r
+  UINT8                  Voltages[] = { 33, 30, 18 };\r
+  UINTN                  Loop;\r
+\r
+  SDHostData = SDHOST_DATA_FROM_THIS (This);\r
+  PciIo      = SDHostData->PciIo;\r
+  Status     = EFI_NOT_FOUND;\r
+\r
+  Data = 0;\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               (UINT64)MMIO_PSTATE,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  if ((Data & (BIT16 | BIT17 | BIT18)) != (BIT16 | BIT17 | BIT18)) {\r
+    //\r
+    // Has no card inserted\r
+    //\r
+    DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: No Cards \r\n"));\r
+    Status =  EFI_NOT_FOUND;\r
+    goto Exit;\r
+  }\r
+  DEBUG ((EFI_D_INFO, "DetectCardAndInitHost: Find Cards \r\n"));\r
+\r
+  Status =  EFI_NOT_FOUND;\r
+  for (Loop = 0; Loop < sizeof (Voltages); Loop++) {\r
+    DEBUG ((\r
+      EFI_D_INFO,\r
+      "DetectCardAndInitHost: SetHostVoltage %d.%dV \r\n",\r
+      Voltages[Loop] / 10,\r
+      Voltages[Loop] % 10\r
+      ));\r
+    Status = SetHostVoltage (This, Voltages[Loop]);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [failed]\n"));\r
+    } else {\r
+      DEBUG ((EFI_D_INFO, "DetectCardAndInitHost set voltages: [success]\n"));\r
+      break;\r
+    }\r
+  }\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set voltage \r\n"));\r
+    goto Exit;\r
+  }\r
+\r
+  Status = SetClockFrequency (This, FREQUENCY_OD);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "DetectCardAndInitHost: Fail to set frequency \r\n"));\r
+    goto Exit;\r
+  }\r
+  SetBusWidth (This, 1);\r
+\r
+  //\r
+  //Enable normal status change\r
+  //\r
+\r
+  Data = (BIT0 | BIT1);\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_NINTEN,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  //\r
+  //Enable error status change\r
+  //\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_ERINTEN,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  Data |= (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7 | BIT8);\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint16,\r
+               0,\r
+               (UINT64)MMIO_ERINTEN,\r
+               1,\r
+               &Data\r
+               );\r
+\r
+  //\r
+  //Data transfer Timeout control\r
+  //\r
+  Data = 0x0E;\r
+\r
+  PciIo->Mem.Write (\r
+               PciIo,\r
+               EfiPciIoWidthUint8,\r
+               0,\r
+               (UINT64)MMIO_TOCTL,\r
+               1,\r
+               &Data\r
+               );\r
+  //\r
+  //Set Default Bus width as 1 bit\r
+  //\r
+\r
+Exit:\r
+  return Status;\r
+\r
+}\r
+\r
+/**\r
+  Entry point for EFI drivers.\r
+\r
+  @param  ImageHandle      EFI_HANDLE.\r
+  @param  SystemTable      EFI_SYSTEM_TABLE.\r
+\r
+  @retval EFI_SUCCESS      Driver is successfully loaded.\r
+  @return Others           Failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InitializeSDController (\r
+  IN EFI_HANDLE           ImageHandle,\r
+  IN EFI_SYSTEM_TABLE     *SystemTable\r
+  )\r
+{\r
+  return EfiLibInstallDriverBindingComponentName2 (\r
+           ImageHandle,\r
+           SystemTable,\r
+           &gSDControllerDriverBinding,\r
+           ImageHandle,\r
+           &gSDControllerName,\r
+           &gSDControllerName2\r
+           );\r
+}\r
+\r
+\r
+/**\r
+  Test to see if this driver supports ControllerHandle. Any\r
+  ControllerHandle that has SDHostIoProtocol installed will be supported.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test.\r
+  @param  RemainingDevicePath  Not used.\r
+\r
+  @return EFI_SUCCESS          This driver supports this device.\r
+  @return EFI_UNSUPPORTED      This driver does not support this device.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerSupported (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS            OpenStatus;\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  PCI_CLASSC            PciClass;\r
+  EFI_SD_HOST_IO_PROTOCOL   *SdHostIo;\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSDHostIoProtocolGuid,\r
+                  (VOID **)&SdHostIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    DEBUG (( DEBUG_INFO, "SdHost controller is already started\n"));\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  //\r
+  // Test whether there is PCI IO Protocol attached on the controller handle.\r
+  //\r
+  OpenStatus = gBS->OpenProtocol (\r
+                      Controller,\r
+                      &gEfiPciIoProtocolGuid,\r
+                      (VOID **) &PciIo,\r
+                      This->DriverBindingHandle,\r
+                      Controller,\r
+                      EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                      );\r
+\r
+  if (EFI_ERROR (OpenStatus)) {\r
+    return OpenStatus;\r
+  }\r
+\r
+  Status = PciIo->Pci.Read (\r
+                        PciIo,\r
+                        EfiPciIoWidthUint8,\r
+                        PCI_CLASSCODE_OFFSET,\r
+                        sizeof (PCI_CLASSC) / sizeof (UINT8),\r
+                        &PciClass\r
+                        );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_UNSUPPORTED;\r
+    goto ON_EXIT;\r
+  }\r
+\r
+  //\r
+  // Test whether the controller belongs to SD type\r
+  //\r
+  if ((PciClass.BaseCode != PCI_CLASS_SYSTEM_PERIPHERAL) ||\r
+      (PciClass.SubClassCode != PCI_SUBCLASS_SD_HOST_CONTROLLER) ||\r
+      ((PciClass.PI != PCI_IF_STANDARD_HOST_NO_DMA) && (PciClass.PI != PCI_IF_STANDARD_HOST_SUPPORT_DMA))\r
+      ) {\r
+\r
+    Status = EFI_UNSUPPORTED;\r
+  }\r
+\r
+ON_EXIT:\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return Status;\r
+}\r
+/**\r
+  Starting the SD Host Controller Driver.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to test.\r
+  @param  RemainingDevicePath  Not used.\r
+\r
+  @retval EFI_SUCCESS          This driver supports this device.\r
+  @retval EFI_UNSUPPORTED      This driver does not support this device.\r
+  @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.\r
+                               EFI_OUT_OF_RESOURCES- Failed due to resource shortage.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStart (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PCI_IO_PROTOCOL   *PciIo;\r
+  SDHOST_DATA           *SDHostData;\r
+  UINT32                Data;\r
+\r
+\r
+  SDHostData = NULL;\r
+  Data       = 0;\r
+\r
+  //\r
+  // Open PCI I/O Protocol and save pointer to open protocol\r
+  // in private data area.\r
+  //\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiPciIoProtocolGuid,\r
+                  (VOID **) &PciIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Enable the SD Host Controller MMIO space\r
+  //\r
+  Status = PciIo->Attributes (\r
+                    PciIo,\r
+                    EfiPciIoAttributeOperationEnable,\r
+                    EFI_PCI_DEVICE_ENABLE,\r
+                    NULL\r
+                    );\r
+  if (EFI_ERROR (Status)) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+\r
+  SDHostData = (SDHOST_DATA*)AllocateZeroPool(sizeof (SDHOST_DATA));\r
+  if (SDHostData == NULL) {\r
+    Status =  EFI_OUT_OF_RESOURCES;\r
+    goto Exit;\r
+  }\r
+\r
+  SDHostData->Signature   = SDHOST_DATA_SIGNATURE;\r
+  SDHostData->PciIo       = PciIo;\r
+\r
+  CopyMem (&SDHostData->SDHostIo, &mSDHostIo, sizeof (EFI_SD_HOST_IO_PROTOCOL));\r
+\r
+  ResetSDHost (&SDHostData->SDHostIo, Reset_All);\r
+\r
+  PciIo->Mem.Read (\r
+              PciIo,\r
+              EfiPciIoWidthUint16,\r
+              0,\r
+              (UINT64)MMIO_CTRLRVER,\r
+              1,\r
+              &Data\r
+              );\r
+  SDHostData->SDHostIo.HostCapability.HostVersion = Data & 0xFF;\r
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: HostVersion 0x%x \r\n", SDHostData->SDHostIo.HostCapability.HostVersion));\r
+\r
+  PciIo->Mem.Read (\r
+               PciIo,\r
+               EfiPciIoWidthUint32,\r
+               0,\r
+               (UINT64)MMIO_CAP,\r
+               1,\r
+               &Data\r
+               );\r
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: MMIO_CAP 0x%x \r\n", Data));\r
+  if ((Data & BIT18) != 0) {\r
+    SDHostData->SDHostIo.HostCapability.BusWidth8 = TRUE;\r
+  }\r
+\r
+  if ((Data & BIT21) != 0) {\r
+    SDHostData->SDHostIo.HostCapability.HighSpeedSupport = TRUE;\r
+  }\r
+\r
+  if ((Data & BIT24) != 0) {\r
+    SDHostData->SDHostIo.HostCapability.V33Support = TRUE;\r
+  }\r
+\r
+  if ((Data & BIT25) != 0) {\r
+    SDHostData->SDHostIo.HostCapability.V30Support = TRUE;\r
+  }\r
+\r
+  if ((Data & BIT26) != 0) {\r
+    SDHostData->SDHostIo.HostCapability.V18Support = TRUE;\r
+  }\r
+\r
+  SDHostData->SDHostIo.HostCapability.BusWidth4 = TRUE;\r
+\r
+  if(SDHostData->SDHostIo.HostCapability.HostVersion < SDHCI_SPEC_300) {\r
+\r
+\r
+\r
+      SDHostData->BaseClockInMHz = (Data >> 8) & 0x3F;\r
+   }\r
+   else {\r
+      SDHostData->BaseClockInMHz = (Data >> 8) & 0xFF;\r
+\r
+   }\r
+\r
+  SDHostData->BlockLength = 512 << ((Data >> 16) & 0x03);\r
+  DEBUG ((EFI_D_INFO, "SdHostDriverBindingStart: BlockLength 0x%x \r\n", SDHostData->BlockLength));\r
+  SDHostData->IsAutoStopCmd  = TRUE;\r
+\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &Controller,\r
+                  &gEfiSDHostIoProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &SDHostData->SDHostIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    goto Exit;\r
+  }\r
+\r
+  //\r
+  // Install the component name protocol\r
+  //\r
+  SDHostData->ControllerNameTable = NULL;\r
+\r
+  AddUnicodeString2 (\r
+    "eng",\r
+    gSDControllerName.SupportedLanguages,\r
+    &SDHostData->ControllerNameTable,\r
+    L"SD Host Controller",\r
+    TRUE\r
+    );\r
+  AddUnicodeString2 (\r
+    "en",\r
+    gSDControllerName2.SupportedLanguages,\r
+    &SDHostData->ControllerNameTable,\r
+    L"SD Host Controller",\r
+    FALSE\r
+    );\r
+\r
+Exit:\r
+  if (EFI_ERROR (Status)) {\r
+    if (SDHostData != NULL) {\r
+      FreePool (SDHostData);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Stop this driver on ControllerHandle. Support stoping any child handles\r
+  created by this driver.\r
+\r
+  @param  This                 Protocol instance pointer.\r
+  @param  Controller           Handle of device to stop driver on.\r
+  @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.\r
+  @param  ChildHandleBuffer    List of handles for the children we need to stop.\r
+\r
+  @return EFI_SUCCESS\r
+  @return others\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SDControllerStop (\r
+  IN EFI_DRIVER_BINDING_PROTOCOL     *This,\r
+  IN EFI_HANDLE                      Controller,\r
+  IN UINTN                           NumberOfChildren,\r
+  IN EFI_HANDLE                      *ChildHandleBuffer\r
+  )\r
+{\r
+  EFI_STATUS               Status;\r
+  EFI_SD_HOST_IO_PROTOCOL  *SDHostIo;\r
+  SDHOST_DATA              *SDHostData;\r
+\r
+  Status = gBS->OpenProtocol (\r
+                  Controller,\r
+                  &gEfiSDHostIoProtocolGuid,\r
+                  (VOID **) &SDHostIo,\r
+                  This->DriverBindingHandle,\r
+                  Controller,\r
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                  );\r
+\r
+  //\r
+  // Test whether the Controller handler passed in is a valid\r
+  // Usb controller handle that should be supported, if not,\r
+  // return the error status directly\r
+  //\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  SetHostVoltage (SDHostIo, 0);\r
+\r
+  SDHostData  = SDHOST_DATA_FROM_THIS(SDHostIo);\r
+\r
+  //\r
+  // Uninstall Block I/O protocol from the device handle\r
+  //\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  Controller,\r
+                  &gEfiSDHostIoProtocolGuid,\r
+                  SDHostIo\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FreeUnicodeStringTable (SDHostData->ControllerNameTable);\r
+\r
+  FreePool (SDHostData);\r
+\r
+  gBS->CloseProtocol (\r
+         Controller,\r
+         &gEfiPciIoProtocolGuid,\r
+         This->DriverBindingHandle,\r
+         Controller\r
+         );\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r