Omap35xxPkg/Library/RealTimeClockLib: Add RTC Support

Omap35xxPkg/MmcHostDxe: Implement MmcHost protocol for Omap35xx

BeagleBoardPkg: Use Omap35xx RTC and MmcHost drivers




git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12161 6f19259b-4bc3-4df7-8a09-765794883524
diff --git a/BeagleBoardPkg/BeagleBoardPkg-next.dsc b/BeagleBoardPkg/BeagleBoardPkg-next.dsc
index 696825c..29b462a 100755
--- a/BeagleBoardPkg/BeagleBoardPkg-next.dsc
+++ b/BeagleBoardPkg/BeagleBoardPkg-next.dsc
@@ -58,7 +58,7 @@
   PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
   PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
   
-  EblCmdLib|BeagleBoardPkg/Library/EblCmdLib/EblCmdLib.inf
+  EblCmdLib|ArmPlatformPkg/Library/EblCmdLib/EblCmdLib.inf
   
   EfiFileLib|EmbeddedPkg/Library/EfiFileLib/EfiFileLib.inf
   
@@ -83,7 +83,7 @@
   SerialPortLib|Omap35xxPkg/Library/SerialPortLib/SerialPortLib.inf
   SemihostLib|ArmPkg/Library/SemihostLib/SemihostLib.inf
   
-  RealTimeClockLib|EmbeddedPkg/Library/TemplateRealTimeClockLib/TemplateRealTimeClockLib.inf
+  RealTimeClockLib|Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.inf
 
   IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
   
@@ -462,10 +462,8 @@
   #
   # MMC/SD
   #
-  Omap35xxPkg/MMCHSDxe/MMCHS.inf {
-    <PcdsFixedAtBuild>
-      gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x800fffff
-  }
+  EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
+  Omap35xxPkg/MmcHostDxe/MmcHostDxe.inf
   
   #
   # I2C
diff --git a/BeagleBoardPkg/BeagleBoardPkg-next.fdf b/BeagleBoardPkg/BeagleBoardPkg-next.fdf
index a3695bb..15c7968 100755
--- a/BeagleBoardPkg/BeagleBoardPkg-next.fdf
+++ b/BeagleBoardPkg/BeagleBoardPkg-next.fdf
@@ -123,7 +123,8 @@
   #
   # MMC/SD
   #
-  INF Omap35xxPkg/MMCHSDxe/MMCHS.inf
+  INF EmbeddedPkg/Universal/MmcDxe/MmcDxe.inf
+  INF Omap35xxPkg/MmcHostDxe/MmcHostDxe.inf
   
   #
   # I2C
diff --git a/Omap35xxPkg/Include/TPS65950.h b/Omap35xxPkg/Include/TPS65950.h
index 8ba9dba..977219f 100644
--- a/Omap35xxPkg/Include/TPS65950.h
+++ b/Omap35xxPkg/Include/TPS65950.h
@@ -19,14 +19,14 @@
 #define EXTERNAL_DEVICE_REGISTER_TO_REGISTER(x)          ((x) & 0xFF)
 #define EXTERNAL_DEVICE_REGISTER(SlaveAddress, Register) (((SlaveAddress) & 0xFF) << 8 | ((Register) & 0xFF))
 
-//I2C Address group
+// I2C Address group
 #define I2C_ADDR_GRP_ID1      0x48
 #define I2C_ADDR_GRP_ID2      0x49
 #define I2C_ADDR_GRP_ID3      0x4A
 #define I2C_ADDR_GRP_ID4      0x4B
 #define I2C_ADDR_GRP_ID5      0x12
 
-//MMC definitions.
+// MMC definitions.
 #define VMMC1_DEV_GRP         0x82
 #define DEV_GRP_P1            BIT5
 
@@ -43,13 +43,23 @@
 #define GPIODATAIN1           0x98  //I2C_ADDR_GRP_ID2
 #define CARD_DETECT_BIT       BIT0
 
-//LEDEN register
+// LEDEN register
 #define LEDEN                 0xEE
 #define LEDAON                BIT0
 #define LEDBON                BIT1
 #define LEDAPWM               BIT4
 #define LEDBPWM               BIT5
 
+// RTC registers
+#define SECONDS_REG           0x1C
+#define MINUTES_REG           0x1D
+#define HOURS_REG             0x1E
+#define DAYS_REG              0x1F
+#define MONTHS_REG            0x20
+#define YEARS_REG             0x21
+#define WEEKS_REG             0x22
+#define RTC_CTRL_REG          0x29
+
 // USB PHY power
 #define VAUX2_DEDICATED       0x79
 #define VAUX2_DEV_GRP         0x76
diff --git a/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c b/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c
new file mode 100755
index 0000000..e1d5c9c
--- /dev/null
+++ b/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.c
@@ -0,0 +1,297 @@
+/** @file
+*
+*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  
+*  This program and the accompanying materials                          
+*  are licensed and made available under the terms and conditions of the BSD License         
+*  which accompanies this distribution.  The full text of the license may be found at        
+*  http://opensource.org/licenses/bsd-license.php                                            
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+*
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+
+#include <Protocol/RealTimeClock.h>
+#include <Protocol/EmbeddedExternalDevice.h>
+
+#include <Omap3530/Omap3530.h>
+#include <TPS65950.h>
+
+
+EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
+INT16                      TimeZone = EFI_UNSPECIFIED_TIMEZONE;
+
+/**
+  Returns the current time and date information, and the time-keeping capabilities
+  of the hardware platform.
+
+  @param  Time                  A pointer to storage to receive a snapshot of the current time.
+  @param  Capabilities          An optional pointer to a buffer to receive the real time clock
+                                device's capabilities.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER Time is NULL.
+  @retval EFI_DEVICE_ERROR      The time could not be retrieved due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetTime (
+  OUT EFI_TIME                *Time,
+  OUT EFI_TIME_CAPABILITIES   *Capabilities
+  )
+{
+  EFI_STATUS            Status;
+  UINT8                 Data;
+  EFI_TPL               OldTpl;
+
+  if (Time == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+
+  /* Get time and date */
+  ZeroMem(Time, sizeof(EFI_TIME));
+
+  // Latch values
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Data |= BIT6;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  // Read registers
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Year = 2000 + ((Data >> 4) & 0xF) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Month = ((Data >> 4) & 0x1) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Day = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Hour = ((Data >> 4) & 0x3) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Minute = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
+
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+  Time->Second = ((Data >> 4) & 0x7) * 10 + (Data & 0xF);
+
+  Time->TimeZone = TimeZone;
+  // TODO: check what to use here
+  Time->Daylight = EFI_TIME_ADJUST_DAYLIGHT;
+
+  // Set capabilities
+
+  // TODO: Set real capabilities
+  if (Capabilities != NULL) {
+    Capabilities->Resolution = 1;
+    Capabilities->Accuracy = 50000000;
+    Capabilities->SetsToZero = FALSE;
+  }
+
+EXIT:
+  gBS->RestoreTPL(OldTpl);
+
+  return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
+}
+
+/**
+  Sets the current local time and date information.
+
+  @param  Time                  A pointer to the current time.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The time could not be set due due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetTime (
+  IN EFI_TIME                *Time
+  )
+{
+  EFI_STATUS Status;
+  UINT8      Data;
+  UINT8      MonthDayCount[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+  EFI_TPL    OldTpl;
+
+  // Input validation according both to UEFI spec and hardware constraints
+  // UEFI spec says valid year range is 1900-9999 but TPS only supports 2000-2099
+  if ( (Time == NULL)
+    || (Time->Year < 2000 || Time->Year > 2099)
+    || (Time->Month < 1 || Time->Month > 12)
+    || (Time->Day < 1 || Time->Day > MonthDayCount[Time->Month])
+    || (Time->Hour > 23)
+    || (Time->Minute > 59)
+    || (Time->Second > 59)
+    || (Time->Nanosecond > 999999999)
+    || ((Time->TimeZone < -1440 || Time->TimeZone > 1440) && Time->TimeZone != 2047)
+  ) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+
+  Data = Time->Year - 2000;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, YEARS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Month / 10) << 4) | (Time->Month % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MONTHS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Day / 10) << 4) | (Time->Day % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, DAYS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Hour / 10) << 4) | (Time->Hour % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, HOURS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Minute / 10) << 4) | (Time->Minute % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, MINUTES_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  Data = ((Time->Second / 10) << 4) | (Time->Second % 10);
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, SECONDS_REG), 1, &Data);
+  if (Status != EFI_SUCCESS) goto EXIT;
+
+  TimeZone = Time->TimeZone;
+
+EXIT:
+  gBS->RestoreTPL(OldTpl);
+
+  return (Status == EFI_SUCCESS) ? Status : EFI_DEVICE_ERROR;
+}
+
+/**
+  Returns the current wakeup alarm clock setting.
+
+  @param  Enabled               Indicates if the alarm is currently enabled or disabled.
+  @param  Pending               Indicates if the alarm signal is pending and requires acknowledgement.
+  @param  Time                  The current alarm setting.
+
+  @retval EFI_SUCCESS           The alarm settings were returned.
+  @retval EFI_INVALID_PARAMETER Any parameter is NULL.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be retrieved due to a hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+LibGetWakeupTime (
+  OUT BOOLEAN     *Enabled,
+  OUT BOOLEAN     *Pending,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Sets the system wakeup alarm clock time.
+
+  @param  Enabled               Enable or disable the wakeup alarm.
+  @param  Time                  If Enable is TRUE, the time to set the wakeup alarm for.
+
+  @retval EFI_SUCCESS           If Enable is TRUE, then the wakeup alarm was enabled. If
+                                Enable is FALSE, then the wakeup alarm was disabled.
+  @retval EFI_INVALID_PARAMETER A time field is out of range.
+  @retval EFI_DEVICE_ERROR      The wakeup time could not be set due to a hardware error.
+  @retval EFI_UNSUPPORTED       A wakeup timer is not supported on this platform.
+
+**/
+EFI_STATUS
+EFIAPI
+LibSetWakeupTime (
+  IN BOOLEAN      Enabled,
+  OUT EFI_TIME    *Time
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  This is the declaration of an EFI image entry point. This can be the entry point to an application
+  written to this specification, an EFI boot service driver, or an EFI runtime driver.
+
+  @param  ImageHandle           Handle that identifies the loaded image.
+  @param  SystemTable           System Table for this image.
+
+  @retval EFI_SUCCESS           The operation completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LibRtcInitialize (
+  IN EFI_HANDLE                            ImageHandle,
+  IN EFI_SYSTEM_TABLE                      *SystemTable
+  )
+{
+  EFI_STATUS    Status;
+  EFI_HANDLE    Handle;
+  UINT8         Data;
+  EFI_TPL       OldTpl;
+
+  Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
+  ASSERT_EFI_ERROR(Status);
+
+  OldTpl = gBS->RaiseTPL(TPL_NOTIFY);
+  Data = 1;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, RTC_CTRL_REG), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+  gBS->RestoreTPL(OldTpl);
+
+  // Setup the setters and getters
+  gRT->GetTime       = LibGetTime;
+  gRT->SetTime       = LibSetTime;
+  gRT->GetWakeupTime = LibGetWakeupTime;
+  gRT->SetWakeupTime = LibSetWakeupTime;
+
+  // Install the protocol
+  Handle = NULL;
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle,
+                  &gEfiRealTimeClockArchProtocolGuid,  NULL,
+                  NULL
+                 );
+
+  return Status;
+}
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+LibRtcVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  return;
+}
diff --git a/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.inf b/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.inf
new file mode 100755
index 0000000..c62257d
--- /dev/null
+++ b/Omap35xxPkg/Library/RealTimeClockLib/RealTimeClockLib.inf
@@ -0,0 +1,38 @@
+#  Copyright (c) 2011, ARM Limited. All rights reserved.
+#  
+#  This program and the accompanying materials                          
+#  are licensed and made available under the terms and conditions of the BSD License         
+#  which accompanies this distribution.  The full text of the license may be found at        
+#  http://opensource.org/licenses/bsd-license.php                                            
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+#
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = RealTimeClockLib 
+  FILE_GUID                      = EC1713DB-7DB5-4c99-8FE2-6F52F95A1132
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = RealTimeClockLib
+
+[Sources.common]
+  RealTimeClockLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Omap35xxPkg/Omap35xxPkg.dec
+  
+[LibraryClasses]
+  IoLib
+  UefiLib
+  DebugLib
+  PcdLib
+
+[Protocols]
+  gEmbeddedExternalDeviceProtocolGuid
+
+[depex]
+  gEmbeddedExternalDeviceProtocolGuid
diff --git a/Omap35xxPkg/MmcHostDxe/MmcHostDxe.c b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.c
new file mode 100755
index 0000000..92b8ea2
--- /dev/null
+++ b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.c
@@ -0,0 +1,667 @@
+/** @file
+*
+*  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.
+*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  
+*  This program and the accompanying materials                          
+*  are licensed and made available under the terms and conditions of the BSD License         
+*  which accompanies this distribution.  The full text of the license may be found at        
+*  http://opensource.org/licenses/bsd-license.php                                            
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+*
+**/
+
+#include "MmcHostDxe.h"
+
+EMBEDDED_EXTERNAL_DEVICE   *gTPS65950;
+UINT8                      MaxDataTransferRate = 0;
+UINT32                     Rca = 0;
+BOOLEAN                    BitModeSet = FALSE;
+
+
+typedef struct {
+  VENDOR_DEVICE_PATH  Mmc;
+  EFI_DEVICE_PATH     End;
+} MMCHS_DEVICE_PATH;
+
+MMCHS_DEVICE_PATH gMMCDevicePath = {
+  {
+    HARDWARE_DEVICE_PATH,
+    HW_VENDOR_DP,
+    (UINT8)(sizeof(VENDOR_DEVICE_PATH)),
+    (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8),
+    0xb615f1f5, 0x5088, 0x43cd, 0x80, 0x9c, 0xa1, 0x6e, 0x52, 0x48, 0x7d, 0x00 
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    sizeof (EFI_DEVICE_PATH_PROTOCOL),
+    0
+  }
+};
+
+BOOLEAN
+IgnoreCommand (
+  UINT32 Command
+  )
+{
+  switch(Command) {
+    case MMC_CMD12:
+      return TRUE;
+    case MMC_CMD13:
+      return TRUE;
+    default:
+      return FALSE;
+  }
+}
+
+UINT32
+TranslateCommand (
+  UINT32 Command
+  )
+{
+  UINT32 Translation;
+
+  switch(Command) {
+    case MMC_CMD2:
+      Translation = CMD2;
+      break;
+    case MMC_CMD3:
+      Translation = CMD3;
+      break;
+    /*case MMC_CMD6:
+      Translation = CMD6;
+      break;*/
+    case MMC_CMD7:
+      Translation = CMD7;
+      break;
+    case MMC_CMD8:
+      Translation = CMD8;
+      break;
+    case MMC_CMD9:
+      Translation = CMD9;
+      break;
+    /*case MMC_CMD12:
+      Translation = CMD12;
+      break;
+    case MMC_CMD13:
+      Translation = CMD13;
+      break;*/
+    case MMC_CMD16:
+      Translation = CMD16;
+      break;
+    case MMC_CMD17:
+      Translation = 0x113A0014;//CMD17;
+      break;
+    case MMC_CMD24:
+      Translation = CMD24 | 4;
+      break;
+    case MMC_CMD55:
+      Translation = CMD55;
+      break;
+    case MMC_ACMD41:
+      Translation = ACMD41;
+      break;
+    default:
+      Translation = Command;
+  }
+
+  return Translation;
+}
+
+VOID
+CalculateCardCLKD (
+  UINTN *ClockFrequencySelect
+  )
+{
+  DEBUG((EFI_D_ERROR, "CalculateCardCLKD()\n"));
+  UINTN    TransferRateValue = 0;
+  UINTN    TimeValue = 0 ;
+  UINTN    Frequency = 0;
+
+  // For SD Cards  we would need to send CMD6 to set
+  // speeds abouve 25MHz. High Speed mode 50 MHz and up
+
+  //Calculate Transfer rate unit (Bits 2:0 of TRAN_SPEED)
+  switch (MaxDataTransferRate & 0x7) { // 2
+    case 0:
+      TransferRateValue = 100 * 1000;
+      break;
+
+    case 1:
+      TransferRateValue = 1 * 1000 * 1000;
+      break;
+
+    case 2:
+      TransferRateValue = 10 * 1000 * 1000;
+      break;
+
+    case 3:
+      TransferRateValue = 100 * 1000 * 1000;
+      break;
+
+    default:
+      DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
+      ASSERT(FALSE);
+  }
+
+  //Calculate Time value (Bits 6:3 of TRAN_SPEED)
+  switch ((MaxDataTransferRate >> 3) & 0xF) { // 6
+    case 1:
+      TimeValue = 10;
+      break;
+
+    case 2:
+      TimeValue = 12;
+      break;
+
+    case 3:
+      TimeValue = 13;
+      break;
+
+    case 4:
+      TimeValue = 15;
+      break;
+
+    case 5:
+      TimeValue = 20;
+      break;
+
+    case 6:
+      TimeValue = 25;
+      break;
+
+    case 7:
+      TimeValue = 30;
+      break;
+
+    case 8:
+      TimeValue = 35;
+      break;
+
+    case 9:
+      TimeValue = 40;
+      break;
+
+    case 10:
+      TimeValue = 45;
+      break;
+
+    case 11:
+      TimeValue = 50;
+      break;
+
+    case 12:
+      TimeValue = 55;
+      break;
+
+    case 13:
+      TimeValue = 60;
+      break;
+
+    case 14:
+      TimeValue = 70;
+      break;
+
+    case 15:
+      TimeValue = 80;
+      break;
+
+    default:
+      DEBUG((EFI_D_ERROR, "Invalid parameter.\n"));
+      ASSERT(FALSE);
+  }
+
+  Frequency = TransferRateValue * TimeValue/10;
+
+  //Calculate Clock divider value to program in MMCHS_SYSCTL[CLKD] field.
+  *ClockFrequencySelect = ((MMC_REFERENCE_CLK/Frequency) + 1);
+
+  DEBUG ((EFI_D_INFO, "MaxDataTransferRate: 0x%x, Frequency: %d KHz, ClockFrequencySelect: %x\n", MaxDataTransferRate, Frequency/1000, *ClockFrequencySelect));
+}
+
+VOID
+UpdateMMCHSClkFrequency (
+  UINTN NewCLKD
+  )
+{
+  DEBUG((EFI_D_ERROR, "UpdateMMCHSClkFrequency()\n"));
+  //Set Clock enable to 0x0 to not provide the clock to the card
+  MmioAnd32 (MMCHS_SYSCTL, ~CEN);
+
+  //Set new clock frequency.
+  MmioAndThenOr32 (MMCHS_SYSCTL, ~CLKD_MASK, NewCLKD << 6); 
+
+  //Poll till Internal Clock Stable
+  while ((MmioRead32 (MMCHS_SYSCTL) & ICS_MASK) != ICS);
+
+  //Set Clock enable to 0x1 to provide the clock to the card
+  MmioOr32 (MMCHS_SYSCTL, CEN);
+}
+
+EFI_STATUS
+InitializeMMCHS (
+  VOID
+  )
+{
+  DEBUG((EFI_D_ERROR, "InitializeMMCHS()\n"));
+  UINT8      Data = 0;
+  EFI_STATUS Status;
+
+  //Select Device group to belong to P1 device group in Power IC.
+  Data = DEV_GRP_P1;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEV_GRP), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+
+  //Configure voltage regulator for MMC1 in Power IC to output 3.0 voltage.
+  Data = VSEL_3_00V;
+  Status = gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID4, VMMC1_DEDICATED_REG), 1, &Data);
+  ASSERT_EFI_ERROR(Status);
+  
+  //After ramping up voltage, set VDDS stable bit to indicate that voltage level is stable.
+  MmioOr32 (CONTROL_PBIAS_LITE, (PBIASLITEVMODE0 | PBIASLITEPWRDNZ0 | PBIASSPEEDCTRL0 | PBIASLITEVMODE1 | PBIASLITEWRDNZ1));
+
+  // Enable WP GPIO
+  MmioAndThenOr32 (GPIO1_BASE + GPIO_OE, ~BIT23, BIT23);
+
+  // Enable Card Detect
+  Data = CARD_DETECT_ENABLE;
+  gTPS65950->Write (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, TPS65950_GPIO_CTRL), 1, &Data);
+
+
+  return Status;
+}
+
+BOOLEAN
+MMCIsCardPresent (
+  VOID
+  )
+{
+  //DEBUG((EFI_D_ERROR, "MMCIsCardPresent()\n"));
+  EFI_STATUS  Status;
+  UINT8       Data;
+
+  //
+  // Card detect is a GPIO0 on the TPS65950
+  //
+  Status = gTPS65950->Read (gTPS65950, EXTERNAL_DEVICE_REGISTER(I2C_ADDR_GRP_ID2, GPIODATAIN1), 1, &Data);
+  if (EFI_ERROR (Status)) {
+    return FALSE;
+  }
+
+  return !(Data & CARD_DETECT_BIT);
+}
+
+BOOLEAN
+MMCIsReadOnly (
+  VOID
+  )
+{
+  /* Note:
+   * On our BeagleBoard the SD card WP pin is always read as TRUE. 
+   * Probably something wrong with GPIO configuration.
+   * BeagleBoard-xM uses microSD cards so there is no write protect at all.
+   * Hence commenting out SD card WP pin read status.  
+   */
+  //return (MmioRead32 (GPIO1_BASE + GPIO_DATAIN) & BIT23) == BIT23;
+  return 0;
+
+}
+
+// TODO
+EFI_GUID mPL180MciDevicePathGuid = EFI_CALLER_ID_GUID;
+
+EFI_STATUS
+MMCBuildDevicePath (
+  IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL    *NewDevicePathNode;
+
+  NewDevicePathNode = CreateDeviceNode(HARDWARE_DEVICE_PATH,HW_VENDOR_DP,sizeof(VENDOR_DEVICE_PATH));
+  CopyGuid(&((VENDOR_DEVICE_PATH*)NewDevicePathNode)->Guid,&mPL180MciDevicePathGuid);
+  *DevicePath = NewDevicePathNode;
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCSendCommand (
+  IN MMC_CMD MmcCmd,
+  IN UINT32 Argument
+  )
+{
+  if (IgnoreCommand(MmcCmd))
+    return EFI_SUCCESS;
+
+  MmcCmd = TranslateCommand(MmcCmd);
+
+  //DEBUG((EFI_D_ERROR, "MMCSendCommand(%d)\n", MmcCmd));
+  UINTN MmcStatus;
+  UINTN RetryCount = 0;
+
+  //Check if command line is in use or not. Poll till command line is available.
+  while ((MmioRead32 (MMCHS_PSTATE) & DATI_MASK) == DATI_NOT_ALLOWED);
+
+  //Provide the block size.
+  MmioWrite32 (MMCHS_BLK, BLEN_512BYTES);
+
+  //Setting Data timeout counter value to max value.
+  MmioAndThenOr32 (MMCHS_SYSCTL, ~DTO_MASK, DTO_VAL);
+
+  //Clear Status register.
+  MmioWrite32 (MMCHS_STAT, 0xFFFFFFFF);
+
+  //Set command argument register
+  MmioWrite32 (MMCHS_ARG, Argument);
+
+  //TODO: fix this
+  //Enable interrupt enable events to occur
+  //MmioWrite32 (MMCHS_IE, CmdInterruptEnableVal);
+
+  //Send a command
+  MmioWrite32 (MMCHS_CMD, MmcCmd);
+
+  //Check for the command status.
+  while (RetryCount < MAX_RETRY_COUNT) {
+    do {
+      MmcStatus = MmioRead32 (MMCHS_STAT);
+    } while (MmcStatus == 0);
+
+    //Read status of command response
+    if ((MmcStatus & ERRI) != 0) {
+
+      //Perform soft-reset for mmci_cmd line.
+      MmioOr32 (MMCHS_SYSCTL, SRC);
+      while ((MmioRead32 (MMCHS_SYSCTL) & SRC));
+
+      //DEBUG ((EFI_D_INFO, "MmcStatus: 0x%x\n", MmcStatus));
+      return EFI_DEVICE_ERROR;
+    }
+
+    //Check if command is completed.
+    if ((MmcStatus & CC) == CC) {
+      MmioWrite32 (MMCHS_STAT, CC);
+      break;
+    }
+
+    RetryCount++;
+  }
+
+  if (RetryCount == MAX_RETRY_COUNT) {
+    DEBUG((EFI_D_ERROR, "MMCSendCommand: Timeout\n"));
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCNotifyState (
+  IN MMC_STATE State
+  )
+{
+  EFI_STATUS              Status;
+  UINTN freqSel;
+  switch(State) {
+    case MmcInvalidState:
+      ASSERT(0);
+      break;
+    case MmcHwInitializationState:
+      BitModeSet = FALSE;
+
+      DEBUG((EFI_D_ERROR, "MMCHwInitializationState()\n"));
+      Status = InitializeMMCHS ();
+      if (EFI_ERROR(Status)) {
+        DEBUG ((EFI_D_ERROR, "Initialize MMC host controller fails. Status: %x\n", Status));
+        return Status;
+      }
+
+      //Software reset of the MMCHS host controller.
+      MmioWrite32 (MMCHS_SYSCONFIG, SOFTRESET);
+      gBS->Stall(1000);
+      while ((MmioRead32 (MMCHS_SYSSTATUS) & RESETDONE_MASK) != RESETDONE);
+
+      //Soft reset for all.
+      MmioWrite32 (MMCHS_SYSCTL, SRA);
+      gBS->Stall(1000);
+      while ((MmioRead32 (MMCHS_SYSCTL) & SRA) != 0x0);
+
+      //Voltage capabilities initialization. Activate VS18 and VS30.
+      MmioOr32 (MMCHS_CAPA, (VS30 | VS18));
+
+      //Wakeup configuration
+      MmioOr32 (MMCHS_SYSCONFIG, ENAWAKEUP);
+      MmioOr32 (MMCHS_HCTL, IWE);
+
+      //MMCHS Controller default initialization
+      MmioOr32 (MMCHS_CON, (OD | DW8_1_4_BIT | CEATA_OFF));
+
+      MmioWrite32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_OFF));
+
+      //Enable internal clock
+      MmioOr32 (MMCHS_SYSCTL, ICE);
+
+      //Set the clock frequency to 80KHz.
+      UpdateMMCHSClkFrequency (CLKD_80KHZ);
+
+      //Enable SD bus power.
+      MmioOr32 (MMCHS_HCTL, (SDBP_ON));
+
+      //Poll till SD bus power bit is set.
+      while ((MmioRead32 (MMCHS_HCTL) & SDBP_MASK) != SDBP_ON);
+
+      //Enable interrupts.
+      MmioWrite32 (MMCHS_IE, (BADA_EN | CERR_EN | DEB_EN | DCRC_EN | DTO_EN | CIE_EN |
+        CEB_EN | CCRC_EN | CTO_EN | BRR_EN | BWR_EN | TC_EN | CC_EN));
+
+      //Controller INIT procedure start.
+      MmioOr32 (MMCHS_CON, INIT);
+      MmioWrite32 (MMCHS_CMD, 0x00000000);
+      while (!(MmioRead32 (MMCHS_STAT) & CC));
+
+      //Wait for 1 ms
+      gBS->Stall(1000);
+
+      //Set CC bit to 0x1 to clear the flag
+      MmioOr32 (MMCHS_STAT, CC);
+
+      //Retry INIT procedure.
+      MmioWrite32 (MMCHS_CMD, 0x00000000);
+      while (!(MmioRead32 (MMCHS_STAT) & CC));
+
+      //End initialization sequence
+      MmioAnd32 (MMCHS_CON, ~INIT);
+
+      MmioOr32 (MMCHS_HCTL, (SDVS_3_0_V | DTW_1_BIT | SDBP_ON));
+
+      //Change clock frequency to 400KHz to fit protocol
+      UpdateMMCHSClkFrequency(CLKD_400KHZ);
+
+      MmioOr32 (MMCHS_CON, OD);
+      break;
+    case MmcIdleState:
+      break;
+    case MmcReadyState:
+      break;
+    case MmcIdentificationState:
+      break;
+    case MmcStandByState:
+      CalculateCardCLKD(&freqSel);
+      UpdateMMCHSClkFrequency(freqSel);
+      break;
+    case MmcTransferState:
+      if (!BitModeSet) {
+        Status = MMCSendCommand (CMD55, Rca << 16);
+        if (!EFI_ERROR (Status)) {
+          // set device into 4-bit data bus mode
+          Status = MMCSendCommand (ACMD6, 0x2);
+          if (!EFI_ERROR (Status)) {
+          // Set host controler into 4-bit mode
+            MmioOr32 (MMCHS_HCTL, DTW_4_BIT);
+            DEBUG ((EFI_D_INFO, "SD Memory Card set to 4-bit mode\n"));
+            BitModeSet = TRUE;
+          }
+        }
+      }
+      break;
+    case MmcSendingDataState:
+      break;
+    case MmcReceiveDataState:
+      break;
+    case MmcProgrammingState:
+      break;
+    case MmcDisconnectState:
+    default:
+      ASSERT(0);
+  }
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCReceiveResponse (
+  IN MMC_RESPONSE_TYPE Type,
+  IN UINT32* Buffer
+  )
+{
+  //DEBUG((EFI_D_ERROR, "MMCReceiveResponse()\n"));
+  if (Buffer == NULL) {
+    DEBUG((EFI_D_ERROR, "Buffer was NULL\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Type == MMC_RESPONSE_TYPE_R2) {
+    Buffer[0] = MmioRead32 (MMCHS_RSP10);
+    Buffer[1] = MmioRead32 (MMCHS_RSP32);
+    Buffer[2] = MmioRead32 (MMCHS_RSP54);
+    Buffer[3] = MmioRead32 (MMCHS_RSP76);
+  } else {
+    Buffer[0] = MmioRead32 (MMCHS_RSP10);
+  }
+
+  if (Type == MMC_RESPONSE_TYPE_CSD) {
+    MaxDataTransferRate = Buffer[3] & 0xFF;
+  } else if (Type == MMC_RESPONSE_TYPE_RCA) {
+    Rca = Buffer[0] >> 16;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCReadBlockData (
+  IN EFI_LBA Lba,
+  IN UINTN Length,
+  IN UINT32* Buffer
+  )
+{
+  //DEBUG((EFI_D_ERROR, "MMCReadBlockData(LBA: 0x%x, ", Lba));
+  //DEBUG((EFI_D_ERROR, "Length: 0x%x, ", Length));
+  //DEBUG((EFI_D_ERROR, "Buffer: 0x%x)\n", Buffer));
+  UINTN MmcStatus;
+  UINTN Count;
+  UINTN RetryCount = 0;
+
+  //Check controller status to make sure there is no error.
+  while (RetryCount < MAX_RETRY_COUNT) {
+    do {
+      //Read Status.
+      MmcStatus = MmioRead32 (MMCHS_STAT);
+    } while(MmcStatus == 0);
+
+    //Check if Buffer read ready (BRR) bit is set?
+    if (MmcStatus & BRR) {
+
+      //Clear BRR bit
+      MmioOr32 (MMCHS_STAT, BRR);
+
+      for (Count = 0; Count < Length / 4; Count++) {
+        *Buffer++ = MmioRead32(MMCHS_DATA);
+      }
+      break;
+    }
+    RetryCount++;
+  }
+
+  if (RetryCount == MAX_RETRY_COUNT) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+MMCWriteBlockData (
+  IN EFI_LBA Lba,
+  IN UINTN Length,
+  IN UINT32* Buffer
+  )
+{
+  UINTN MmcStatus;
+  UINTN Count;
+  UINTN RetryCount = 0;
+
+  //Check controller status to make sure there is no error.
+  while (RetryCount < MAX_RETRY_COUNT) {
+    do {
+      //Read Status.
+      MmcStatus = MmioRead32 (MMCHS_STAT);
+    } while(MmcStatus == 0);
+
+    //Check if Buffer write ready (BWR) bit is set?
+    if (MmcStatus & BWR) {
+
+      //Clear BWR bit
+      MmioOr32 (MMCHS_STAT, BWR);
+
+      //Write block worth of data.
+      for (Count = 0; Count < Length / 4; Count++) {
+        MmioWrite32 (MMCHS_DATA, *Buffer++);
+      }
+
+      break;
+    }
+    RetryCount++;
+  }
+
+  if (RetryCount == MAX_RETRY_COUNT) {
+    return EFI_TIMEOUT;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_MMC_HOST_PROTOCOL gMMCHost = {
+  MMCIsCardPresent,
+  MMCIsReadOnly,
+  MMCBuildDevicePath,
+  MMCNotifyState,
+  MMCSendCommand,
+  MMCReceiveResponse,
+  MMCReadBlockData,
+  MMCWriteBlockData
+};
+
+EFI_STATUS
+MMCInitialize (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  DEBUG((EFI_D_ERROR, "MMCInitialize()\n"));
+  EFI_STATUS    Status;
+  EFI_HANDLE    Handle = NULL;
+
+  Status = gBS->LocateProtocol (&gEmbeddedExternalDeviceProtocolGuid, NULL, (VOID **)&gTPS65950);
+  ASSERT_EFI_ERROR(Status);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &Handle, 
+                  &gEfiMmcHostProtocolGuid,         &gMMCHost,
+                  NULL
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
diff --git a/Omap35xxPkg/MmcHostDxe/MmcHostDxe.h b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.h
new file mode 100755
index 0000000..940087f
--- /dev/null
+++ b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.h
@@ -0,0 +1,44 @@
+/** @file
+*
+*  Copyright (c) 2011, ARM Limited. All rights reserved.
+*  
+*  This program and the accompanying materials                          
+*  are licensed and made available under the terms and conditions of the BSD License         
+*  which accompanies this distribution.  The full text of the license may be found at        
+*  http://opensource.org/licenses/bsd-license.php                                            
+*
+*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+*
+**/
+
+#ifndef _MMC_HOST_DXE_H_
+#define _MMC_HOST_DXE_H_
+
+#include <Uefi.h>
+
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/OmapLib.h>
+#include <Library/OmapDmaLib.h>
+#include <Library/DmaLib.h>
+
+#include <Protocol/EmbeddedExternalDevice.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/MmcHost.h>
+
+#include <Omap3530/Omap3530.h>
+#include <TPS65950.h>
+
+#define MAX_RETRY_COUNT  (100*5)
+
+extern EFI_BLOCK_IO_PROTOCOL gBlockIo;
+
+#endif
diff --git a/Omap35xxPkg/MmcHostDxe/MmcHostDxe.inf b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.inf
new file mode 100755
index 0000000..a15b6f7
--- /dev/null
+++ b/Omap35xxPkg/MmcHostDxe/MmcHostDxe.inf
@@ -0,0 +1,53 @@
+#  Copyright (c) 2011, ARM Limited. All rights reserved.
+#  
+#  This program and the accompanying materials                          
+#  are licensed and made available under the terms and conditions of the BSD License         
+#  which accompanies this distribution.  The full text of the license may be found at        
+#  http://opensource.org/licenses/bsd-license.php                                            
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
+#
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = MMC
+  FILE_GUID                      = 100c2cfa-b586-4198-9b4c-1683d195b1da
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+
+  ENTRY_POINT                    = MMCInitialize
+
+
+[Sources.common]
+  MmcHostDxe.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  EmbeddedPkg/EmbeddedPkg.dec
+  Omap35xxPkg/Omap35xxPkg.dec
+
+[LibraryClasses]
+  PcdLib
+  UefiLib
+  UefiDriverEntryPoint
+  MemoryAllocationLib
+  IoLib
+  OmapDmaLib
+  DmaLib
+
+[Guids]
+  
+[Protocols]
+  gEfiBlockIoProtocolGuid
+  gEfiCpuArchProtocolGuid
+  gEfiDevicePathProtocolGuid
+  gEmbeddedExternalDeviceProtocolGuid
+  gEfiMmcHostProtocolGuid
+
+[Pcd]
+  gOmap35xxTokenSpaceGuid.PcdOmap35xxMMCHS1Base
+  gOmap35xxTokenSpaceGuid.PcdMmchsTimerFreq100NanoSeconds
+
+[depex]
+  gEmbeddedExternalDeviceProtocolGuid