From: Tomasz Michalec <t...@semihalf.com>

XenonDxe was copy of SdMmcPciHcDxe from edk2/MdeModulePkg.

Now it implements SdMmcOverride protocol which allows
to add quirks to the generic SdMmcPciHcDxe.

Platforms that were using XenonDxe/SdMmcPciHcDxe have fixed *.fdf
and *.dsc.inc files to use new implementation of XenonDxe.

In the new version of the driver apart from using SdMmcOverride
protocol, this patch utilizes newly added controllers'
description in MvBoardDesc protocol, as well as improved
PHY configuration sequence.

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Marcin Wojtas  <m...@semihalf.com>
---
 Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc               |   2 +
 Silicon/Marvell/Armada7k8k/Armada7k8k.fdf                   |   2 +
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf         |  55 +++
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.h        | 151 +++++++
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.h |  53 +++
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h         | 131 +++++-
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.c        | 321 
+++++++++++++++
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c | 429 
++++++++++++++++++++
 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c         | 408 
++++++++++++-------
 9 files changed, 1399 insertions(+), 153 deletions(-)
 create mode 100644 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf
 create mode 100644 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.h
 create mode 100644 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.h
 create mode 100644 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.c
 create mode 100644 Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c

diff --git a/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc 
b/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc
index 041fe90..14a1bda 100644
--- a/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc
+++ b/Silicon/Marvell/Armada7k8k/Armada7k8k.dsc.inc
@@ -509,6 +509,8 @@
   # SD/MMC
   MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
   MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+  MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
+  Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf
 
   # Console packages
   MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
diff --git a/Silicon/Marvell/Armada7k8k/Armada7k8k.fdf 
b/Silicon/Marvell/Armada7k8k/Armada7k8k.fdf
index 6ad7c87..e143517 100644
--- a/Silicon/Marvell/Armada7k8k/Armada7k8k.fdf
+++ b/Silicon/Marvell/Armada7k8k/Armada7k8k.fdf
@@ -171,6 +171,8 @@ FvNameGuid         = 5eda4200-2c5f-43cb-9da3-0baf74b1b30c
   # SD/MMC
   INF MdeModulePkg/Bus/Sd/EmmcDxe/EmmcDxe.inf
   INF MdeModulePkg/Bus/Sd/SdDxe/SdDxe.inf
+  INF MdeModulePkg/Bus/Pci/SdMmcPciHcDxe/SdMmcPciHcDxe.inf
+  INF Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf
 
   # Multiple Console IO support
   INF MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf
new file mode 100644
index 0000000..00c738a
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonDxe.inf
@@ -0,0 +1,55 @@
+## @file
+#  SdMmcPciHcDxe driver is used to manage those host controllers which comply 
with SD
+#  Host Controller Simplified Specifiction version 3.0.
+#
+#  It will produce EFI_SD_MMC_PASS_THRU_PROTOCOL to allow sending SD/MMC/eMMC 
cmds
+#  to specified devices from upper layer.
+#
+#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+#  Copyright (C) 2018, Marvell International Ltd. All rights reserved.<BR>
+#
+#  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                    = 0x0001001A
+  BASE_NAME                      = XenonDxe
+  FILE_GUID                      = 17f56b40-f7c1-435c-ab8d-404872da951e
+  MODULE_TYPE                    = UEFI_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = InitializeXenonDxe
+
+[Sources]
+  XenonPciHci.c
+  XenonPciHci.h
+  XenonSdhci.c
+  XenonSdhci.h
+  XenonSdMmcOverride.c
+  XenonSdMmcOverride.h
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Silicon/Marvell/Marvell.dec
+
+[LibraryClasses]
+  BaseLib
+  DebugLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiLib
+  UefiRuntimeServicesTableLib
+
+[Protocols]
+  gEdkiiSdMmcOverrideProtocolGuid               ## PRODUCES
+  gEdkiiNonDiscoverableDeviceProtocolGuid       ## TO_START
+  gEfiPciIoProtocolGuid                         ## TO_START
+  gMarvellBoardDescProtocolGuid                 ## TO_START
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.h 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.h
new file mode 100644
index 0000000..152ba96
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.h
@@ -0,0 +1,151 @@
+/** @file
+
+  Provides some data structure definitions used by the SD/MMC host controller 
driver.
+
+  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Marvell International, Ltd. All rights reserved.<BR>
+
+  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 _XENON_PCI_HCI_H_
+#define _XENON_PCI_HCI_H_
+
+/**
+  Read/Write specified SD/MMC host controller mmio register.
+
+  @param[in]      PciIo        The PCI IO protocol instance.
+  @param[in]      BarIndex     The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in]      Offset       The offset within the selected BAR to start the
+                               memory operation.
+  @param[in]      Read         A boolean to indicate it's read or write 
operation.
+  @param[in]      Count        The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in, out] Data         For read operations, the destination buffer to 
store
+                               the results. For write operations, the source 
buffer
+                               to write data from. The caller is responsible 
for
+                               having ownership of the data buffer and 
ensuring its
+                               size not less than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not 
valid.
+  @retval EFI_SUCCESS           The read/write operation succeeds.
+  @retval Others                The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcRwMmio (
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN     UINT8                 BarIndex,
+  IN     UINT32                Offset,
+  IN     BOOLEAN               Read,
+  IN     UINT8                 Count,
+  IN OUT VOID                  *Data
+  );
+
+/**
+  Do OR operation with the value of the specified SD/MMC host controller mmio 
register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] OrData            The pointer to the data used to do OR operation.
+                               The caller is responsible for having ownership 
of
+                               the data buffer and ensuring its size not less 
than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is 
not valid.
+  @retval EFI_SUCCESS           The OR operation succeeds.
+  @retval Others                The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcOrMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *OrData
+  );
+
+/**
+  Do AND operation with the value of the specified SD/MMC host controller mmio 
register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] AndData           The pointer to the data used to do AND 
operation.
+                               The caller is responsible for having ownership 
of
+                               the data buffer and ensuring its size not less 
than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is 
not valid.
+  @retval EFI_SUCCESS           The AND operation succeeds.
+  @retval Others                The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcAndMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *AndData
+  );
+
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  PciIo         The PCI IO protocol instance.
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration
+                            header to use as the base address for the memory
+                            operation to perform.
+  @param[in]  Offset        The offset within the selected BAR to start the
+                            memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+  @param[in]  Timeout       The time out value for wait memory set, uses 1
+                            microsecond as a unit.
+
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout
+                            range.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcWaitMmioSet (
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,
+  IN  UINT8                     BarIndex,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue,
+  IN  UINT64                    Timeout
+  );
+
+#endif
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.h 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.h
new file mode 100644
index 0000000..0c7a0b7
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.h
@@ -0,0 +1,53 @@
+/*******************************************************************************
+Copyright (C) 2018 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without 
modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+#ifndef _XENON_SD_MMC_OVERRIDE_H_
+#define _XENON_SD_MMC_OVERRIDE_H_
+
+#include <Uefi.h>
+
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+
+#include <Protocol/BoardDesc.h>
+#include <Protocol/NonDiscoverableDevice.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/SdMmcOverride.h>
+
+#include "XenonPciHci.h"
+#include "XenonSdhci.h"
+
+#endif
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
index 2be0ee6..8bf1835 100644
--- a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.h
@@ -32,15 +32,65 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
*******************************************************************************/
 
-#include "SdMmcPciHcDxe.h"
-
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
 #include <Library/IoLib.h>
 
+#include <Protocol/PciIo.h>
+#include <Protocol/SdMmcOverride.h>
+
+#include "XenonPciHci.h"
+
 #define SD_BAR_INDEX 0
 
 #define SIZE_512B    0x200
 
-/* Register Offset of SD Host Controller SOCP self-defined register */
+/* Register Offset of SD Host Controller */
+#define SDHC_SDMA_ADDR                0x0000
+#define SDHC_ARG2                     0x0000
+#define SDHC_BLK_SIZE                 0x0004
+#define SDHC_BLK_COUNT                0x0006
+#define SDHC_ARG1                     0x0008
+#define SDHC_TRANS_MOD                0x000C
+#define SDHC_COMMAND                  0x000E
+#define SDHC_RESPONSE                 0x0010
+#define SDHC_BUF_DAT_PORT             0x0020
+#define SDHC_PRESENT_STATE            0x0024
+#define SDHC_HOST_CTRL1               0x0028
+#define SDHC_POWER_CTRL               0x0029
+#define SDHC_BLK_GAP_CTRL             0x002A
+#define SDHC_WAKEUP_CTRL              0x002B
+#define SDHC_CLOCK_CTRL               0x002C
+#define SDHC_TIMEOUT_CTRL             0x002E
+#define SDHC_SW_RST                   0x002F
+#define SDHC_NOR_INT_STS              0x0030
+#define SDHC_ERR_INT_STS              0x0032
+#define SDHC_NOR_INT_STS_EN           0x0034
+#define SDHC_ERR_INT_STS_EN           0x0036
+#define SDHC_NOR_INT_SIG_EN           0x0038
+#define SDHC_ERR_INT_SIG_EN           0x003A
+#define SDHC_AUTO_CMD_ERR_STS         0x003C
+#define SDHC_HOST_CTRL2               0x003E
+#define UHS_MODE_SELECT_MASK          0x7
+#define SDHC_CAP                      0x0040
+#define SDHC_CAP_BUS_WIDTH8           BIT18
+#define SDHC_CAP_VOLTAGE_33           BIT24
+#define SDHC_CAP_VOLTAGE_30           BIT25
+#define SDHC_CAP_VOLTAGE_18           BIT26
+#define SDHC_CAP_SLOT_TYPE_OFFSET     30
+#define SDHC_CAP_SLOT_TYPE_MASK       (BIT30 | BIT31)
+#define SDHC_CAP_SDR50                BIT32
+#define SDHC_CAP_SDR104               BIT33
+#define SDHC_CAP_DDR50                BIT34
+#define SDHC_MAX_CURRENT_CAP          0x0048
+#define SDHC_FORCE_EVT_AUTO_CMD       0x0050
+#define SDHC_FORCE_EVT_ERR_INT        0x0052
+#define SDHC_ADMA_ERR_STS             0x0054
+#define SDHC_ADMA_SYS_ADDR            0x0058
+#define SDHC_PRESET_VAL               0x0060
+#define SDHC_SHARED_BUS_CTRL          0x00E0
+#define SDHC_SLOT_INT_STS             0x00FC
+#define SDHC_CTRL_VER                 0x00FE
 
 #define SDHC_IPID                     0x0100
 #define SDHC_SYS_CFG_INFO             0x0104
@@ -52,10 +102,12 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
 
 #define SDHC_SYS_OP_CTRL              0x0108
 #define AUTO_CLKGATE_DISABLE_MASK     (0x1<<20)
-#define SDCLK_IDLEOFF_ENABLE_SHIFT    8
+#define SDCLK_IDLEOFF_ENABLE_MASK     (1 << 8)
 #define SLOT_ENABLE_SHIFT             0
 
 #define SDHC_SYS_EXT_OP_CTRL          0x010c
+#define MASK_CMD_CONFLICT_ERR         (1 << 8)
+
 #define SDHC_TEST_OUT                 0x0110
 #define SDHC_TESTOUT_MUXSEL           0x0114
 
@@ -169,11 +221,27 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
 #define TMR_RETUN_NO_PRESENT          0xf
 #define XENON_MAX_TUN_COUNT           0xb
 
+#define XENON_SLOT_OP_STATUS_CTRL     0x0128
+#define TUN_CONSECUTIVE_TIMES_SHIFT   16
+#define TUN_CONSECUTIVE_TIMES_MASK    0x7
+#define TUN_CONSECUTIVE_TIMES         0x4
+#define TUNING_STEP_SHIFT             12
+#define TUNING_STEP_MASK              0xF
+
+#define XENON_SLOT_EMMC_CTRL          0x130
+#define ENABLE_DATA_STROBE            (1 << 24)
+
+#define XENON_SLOT_EXT_PRESENT_STATE  0x014C
+#define DLL_LOCK_STATE                0x1
+
+#define XENON_SLOT_DLL_CUR_DLY_VAL    0x0150
+
 #define EMMC_PHY_REG_BASE                 0x170
 #define EMMC_PHY_TIMING_ADJUST            EMMC_PHY_REG_BASE
 #define OUTPUT_QSN_PHASE_SELECT           (1 << 17)
 #define SAMPL_INV_QSP_PHASE_SELECT        (1 << 18)
 #define SAMPL_INV_QSP_PHASE_SELECT_SHIFT  18
+#define QSN_PHASE_SLOW_MODE_BIT           (1 << 29)
 #define PHY_INITIALIZAION                 (1 << 31)
 #define WAIT_CYCLE_BEFORE_USING_MASK      0xf
 #define WAIT_CYCLE_BEFORE_USING_SHIFT     12
@@ -199,20 +267,42 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
 #define FC_QSN_RECEN              (1 << 27)
 #define OEN_QSN                   (1 << 28)
 #define AUTO_RECEN_CTRL           (1 << 30)
+#define FC_ALL_CMOS_RECEIVER      0xF000
 
 #define EMMC_PHY_PAD_CONTROL1        (EMMC_PHY_REG_BASE + 0xc)
+#define EMMC5_1_FC_QSP_PD            (1 << 9)
+#define EMMC5_1_FC_QSP_PU            (1 << 25)
+#define EMMC5_1_FC_CMD_PD            (1 << 8)
+#define EMMC5_1_FC_CMD_PU            (1 << 24)
+#define EMMC5_1_FC_DQ_PD             0xFF
+#define EMMC5_1_FC_DQ_PU             (0xFF << 16)
+
 #define EMMC_PHY_PAD_CONTROL2        (EMMC_PHY_REG_BASE + 0x10)
+#define ZNR_MASK                     0x1F
+#define ZNR_SHIFT                    8
+#define ZPR_MASK                     0x1F
+#define ZNR_DEF_VALUE                0xF
+#define ZPR_DEF_VALUE                0xF
+
 #define EMMC_PHY_DLL_CONTROL         (EMMC_PHY_REG_BASE + 0x14)
-#define DLL_DELAY_TEST_LOWER_SHIFT   8
-#define DLL_DELAY_TEST_LOWER_MASK    0xff
-#define DLL_BYPASS_EN                0x1
+#define DLL_ENABLE                   (1 << 31)
+#define DLL_UPDATE_STROBE_5_0        (1 << 30)
+#define DLL_REFCLK_SEL               (1 << 30)
+#define DLL_UPDATE                   (1 << 23)
+#define DLL_PHSEL1_SHIFT             24
+#define DLL_PHSEL0_SHIFT             16
+#define DLL_PHASE_MASK               0x3F
+#define DLL_PHASE_90_DEGREE          0x1F
+#define DLL_FAST_LOCK                (1 << 5)
+#define DLL_GAIN2X                   (1 << 3)
+#define DLL_BYPASS_EN                (1 << 0)
 
 #define EMMC_LOGIC_TIMING_ADJUST       (EMMC_PHY_REG_BASE + 0x18)
 #define EMMC_LOGIC_TIMING_ADJUST_LOW   (EMMC_PHY_REG_BASE + 0x1c)
 
 #define LOGIC_TIMING_VALUE             0x5a54 /* Recommend by HW team */
 
-#define QSN_PHASE_SLOW_MODE_BIT        (1 << 29)
+#define TUNING_STEP_DIVIDER_SHIFT      6
 
 /* XENON only have one slot 0 */
 #define XENON_MMC_SLOT_ID              (0)
@@ -227,6 +317,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
DAMAGE.
 #define MMC_TIMING_UHS_DDR50  7
 #define MMC_TIMING_MMC_HS200  8
 #define MMC_TIMING_MMC_HS400  10
+#define MMC_TIMING_MMC_DDR52  11
+
+/* Custom UHS signaling field values */
+#define XENON_SD_MMC_HC_CTRL_HS200    0x5
+#define XENON_SD_MMC_HC_CTRL_HS400    0x6
 
 /* Data time out default value 0xE: TMCLK x 227 */
 #define DATA_TIMEOUT_DEF_VAL          0xE
@@ -305,7 +400,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 UINTN
 XenonSetClk (
   IN EFI_PCI_IO_PROTOCOL   *PciIo,
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
   IN UINT32 Clock
   );
 
@@ -316,14 +410,14 @@ XenonPhyInit (
 
 VOID
 XenonReset (
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
   IN UINT8 Slot,
   IN UINT8 Mask
   );
 
 EFI_STATUS
 XenonTransferData (
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
   IN UINT8 Slot,
   IN OUT VOID *Buffer,
   IN UINT32 DataLen,
@@ -334,13 +428,16 @@ XenonTransferData (
 
 EFI_STATUS
 XenonInit (
-  IN SD_MMC_HC_PRIVATE_DATA *Private
+  IN EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN BOOLEAN               Support1v8,
+  IN BOOLEAN               SlowMode,
+  IN UINT8                 TuningStepDivisor
   );
 
 EFI_STATUS
-SdCardSendStatus (
-  IN  EFI_SD_MMC_PASS_THRU_PROTOCOL  *PassThru,
-  IN  UINT8                          Slot,
-  IN  UINT16                         Rca,
-  OUT UINT32                         *DevStatus
+XenonSetPhy (
+  IN EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN BOOLEAN               SlowMode,
+  IN UINT8                 TuningStepDivisor,
+  IN SD_MMC_BUS_MODE       Timing
   );
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.c 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.c
new file mode 100644
index 0000000..8a22046
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonPciHci.c
@@ -0,0 +1,321 @@
+/** @file
+  This driver is used to manage SD/MMC PCI host controllers which are 
compliance
+  with SD Host Controller Simplified Specification version 3.00.
+
+  It would expose EFI_SD_MMC_PASS_THRU_PROTOCOL for upper layer use.
+
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Marvell International, Ltd. All rights reserved.<BR>
+
+  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 "XenonSdMmcOverride.h"
+
+/**
+  Read/Write specified SD/MMC host controller mmio register.
+
+  @param[in]      PciIo        The PCI IO protocol instance.
+  @param[in]      BarIndex     The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in]      Offset       The offset within the selected BAR to start the
+                               memory operation.
+  @param[in]      Read         A boolean to indicate it's read or write 
operation.
+  @param[in]      Count        The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in, out] Data         For read operations, the destination buffer to 
store
+                               the results. For write operations, the source 
buffer
+                               to write data from. The caller is responsible 
for
+                               having ownership of the data buffer and 
ensuring its
+                               size not less than Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or Data is NULL or the Count is not 
valid.
+  @retval EFI_SUCCESS           The read/write operation succeeds.
+  @retval Others                The read/write operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcRwMmio (
+  IN     EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN     UINT8                 BarIndex,
+  IN     UINT32                Offset,
+  IN     BOOLEAN               Read,
+  IN     UINT8                 Count,
+  IN OUT VOID                  *Data
+  )
+{
+  EFI_STATUS                   Status;
+
+  if ((PciIo == NULL) || (Data == NULL))  {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((Count != 1) && (Count != 2) && (Count != 4) && (Count != 8)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (Read) {
+    Status = PciIo->Mem.Read (
+                          PciIo,
+                          EfiPciIoWidthUint8,
+                          BarIndex,
+                          (UINT64) Offset,
+                          Count,
+                          Data
+                          );
+  } else {
+    Status = PciIo->Mem.Write (
+                          PciIo,
+                          EfiPciIoWidthUint8,
+                          BarIndex,
+                          (UINT64) Offset,
+                          Count,
+                          Data
+                          );
+  }
+
+  return Status;
+}
+
+/**
+  Do OR operation with the value of the specified SD/MMC host controller mmio 
register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] OrData            The pointer to the data used to do OR operation.
+                               The caller is responsible for having ownership 
of
+                               the data buffer and ensuring its size not less 
than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or OrData is NULL or the Count is 
not valid.
+  @retval EFI_SUCCESS           The OR operation succeeds.
+  @retval Others                The OR operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcOrMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *OrData
+  )
+{
+  EFI_STATUS                   Status;
+  UINT64                       Data;
+  UINT64                       Or;
+
+  Status = XenonHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (Count == 1) {
+    Or = *(UINT8*) OrData;
+  } else if (Count == 2) {
+    Or = *(UINT16*) OrData;
+  } else if (Count == 4) {
+    Or = *(UINT32*) OrData;
+  } else if (Count == 8) {
+    Or = *(UINT64*) OrData;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data  |= Or;
+  Status = XenonHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+  return Status;
+}
+
+/**
+  Do AND operation with the value of the specified SD/MMC host controller mmio 
register.
+
+  @param[in] PciIo             The PCI IO protocol instance.
+  @param[in] BarIndex          The BAR index of the standard PCI Configuration
+                               header to use as the base address for the memory
+                               operation to perform.
+  @param[in] Offset            The offset within the selected BAR to start the
+                               memory operation.
+  @param[in] Count             The width of the mmio register in bytes.
+                               Must be 1, 2 , 4 or 8 bytes.
+  @param[in] AndData           The pointer to the data used to do AND 
operation.
+                               The caller is responsible for having ownership 
of
+                               the data buffer and ensuring its size not less 
than
+                               Count bytes.
+
+  @retval EFI_INVALID_PARAMETER The PciIo or AndData is NULL or the Count is 
not valid.
+  @retval EFI_SUCCESS           The AND operation succeeds.
+  @retval Others                The AND operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcAndMmio (
+  IN  EFI_PCI_IO_PROTOCOL      *PciIo,
+  IN  UINT8                    BarIndex,
+  IN  UINT32                   Offset,
+  IN  UINT8                    Count,
+  IN  VOID                     *AndData
+  )
+{
+  EFI_STATUS                   Status;
+  UINT64                       Data;
+  UINT64                       And;
+
+  Status = XenonHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Data);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  if (Count == 1) {
+    And = *(UINT8*) AndData;
+  } else if (Count == 2) {
+    And = *(UINT16*) AndData;
+  } else if (Count == 4) {
+    And = *(UINT32*) AndData;
+  } else if (Count == 8) {
+    And = *(UINT64*) AndData;
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Data  &= And;
+  Status = XenonHcRwMmio (PciIo, BarIndex, Offset, FALSE, Count, &Data);
+
+  return Status;
+}
+
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  PciIo         The PCI IO protocol instance.
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration
+                            header to use as the base address for the memory
+                            operation to perform.
+  @param[in]  Offset        The offset within the selected BAR to start the
+                            memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+
+  @retval EFI_NOT_READY     The MMIO register hasn't set to the expected value.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcCheckMmioSet (
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,
+  IN  UINT8                     BarIndex,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue
+  )
+{
+  EFI_STATUS            Status;
+  UINT64                Value;
+
+  //
+  // Access PCI MMIO space to see if the value is the tested one.
+  //
+  Value  = 0;
+  Status = XenonHcRwMmio (PciIo, BarIndex, Offset, TRUE, Count, &Value);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Value &= MaskValue;
+
+  if (Value == TestValue) {
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_READY;
+}
+
+/**
+  Wait for the value of the specified MMIO register set to the test value.
+
+  @param[in]  PciIo         The PCI IO protocol instance.
+  @param[in]  BarIndex      The BAR index of the standard PCI Configuration
+                            header to use as the base address for the memory
+                            operation to perform.
+  @param[in]  Offset        The offset within the selected BAR to start the
+                            memory operation.
+  @param[in]  Count         The width of the mmio register in bytes.
+                            Must be 1, 2, 4 or 8 bytes.
+  @param[in]  MaskValue     The mask value of memory.
+  @param[in]  TestValue     The test value of memory.
+  @param[in]  Timeout       The time out value for wait memory set, uses 1
+                            microsecond as a unit.
+
+  @retval EFI_TIMEOUT       The MMIO register hasn't expected value in timeout
+                            range.
+  @retval EFI_SUCCESS       The MMIO register has expected value.
+  @retval Others            The MMIO operation fails.
+
+**/
+EFI_STATUS
+EFIAPI
+XenonHcWaitMmioSet (
+  IN  EFI_PCI_IO_PROTOCOL       *PciIo,
+  IN  UINT8                     BarIndex,
+  IN  UINT32                    Offset,
+  IN  UINT8                     Count,
+  IN  UINT64                    MaskValue,
+  IN  UINT64                    TestValue,
+  IN  UINT64                    Timeout
+  )
+{
+  EFI_STATUS            Status;
+  BOOLEAN               InfiniteWait;
+
+  if (Timeout == 0) {
+    InfiniteWait = TRUE;
+  } else {
+    InfiniteWait = FALSE;
+  }
+
+  while (InfiniteWait || (Timeout > 0)) {
+    Status = XenonHcCheckMmioSet (
+               PciIo,
+               BarIndex,
+               Offset,
+               Count,
+               MaskValue,
+               TestValue
+               );
+    if (Status != EFI_NOT_READY) {
+      return Status;
+    }
+
+    //
+    // Stall for 1 microsecond.
+    //
+    gBS->Stall (1);
+
+    Timeout--;
+  }
+
+  return EFI_TIMEOUT;
+}
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c
new file mode 100644
index 0000000..7a9266e
--- /dev/null
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c
@@ -0,0 +1,429 @@
+/*******************************************************************************
+Copyright (C) 2018 Marvell International Ltd.
+
+Marvell BSD License Option
+
+If you received this File from Marvell, you may opt to use, redistribute and/or
+modify this File under the following licensing terms.
+Redistribution and use in source and binary forms, with or without 
modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice,
+  this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+
+* Neither the name of Marvell nor the names of its contributors may be
+  used to endorse or promote products derived from this software without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*******************************************************************************/
+
+#include "XenonSdMmcOverride.h"
+
+STATIC EFI_HANDLE              mXenonSdMmcOverrideHandle;
+STATIC EDKII_SD_MMC_OVERRIDE  *mSdMmcOverride;
+
+STATIC
+EFI_STATUS
+EFIAPI
+XenonGetSdMmcDesc (
+  IN      EFI_HANDLE              ControllerHandle,
+  IN OUT  MV_BOARD_SDMMC_DESC     *SdMmcDesc
+  )
+{
+  EFI_STATUS                      Status;
+  MV_BOARD_SDMMC_DESC             *SdMmcDescs;
+  NON_DISCOVERABLE_DEVICE         *Device;
+  MARVELL_BOARD_DESC_PROTOCOL     *BoardDescProtocol;
+  UINTN                           Index;
+
+  Device = NULL;
+  Status = gBS->OpenProtocol (ControllerHandle,
+                  &gEdkiiNonDiscoverableDeviceProtocolGuid,
+                  (VOID **) &Device,
+                  mXenonSdMmcOverrideHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  BoardDescProtocol = NULL;
+  Status = gBS->LocateProtocol (&gMarvellBoardDescProtocolGuid,
+                  NULL,
+                  (VOID **) &BoardDescProtocol);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = BoardDescProtocol->BoardDescSdMmcGet (BoardDescProtocol, 
&SdMmcDescs);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  for (Index = 0; Index < SdMmcDescs->SdMmcDevCount; Index++) {
+    if (SdMmcDescs[Index].SoC->SdMmcBaseAddress ==
+        Device->Resources[0].AddrRangeMin) {
+      *SdMmcDesc = SdMmcDescs[Index];
+      break;
+    }
+  }
+
+  if (Index == SdMmcDescs->SdMmcDevCount) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+XenonGetPciIo (
+  IN      EFI_HANDLE              ControllerHandle,
+  IN OUT  EFI_PCI_IO_PROTOCOL     **PciIo
+  )
+{
+  EFI_STATUS Status;
+
+  *PciIo  = NULL;
+  Status = gBS->OpenProtocol (ControllerHandle,
+                  &gEfiPciIoProtocolGuid,
+                  (VOID **) PciIo,
+                  mXenonSdMmcOverrideHandle,
+                  ControllerHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+  return Status;
+}
+
+/**
+  Set SD Host Controller control 2 registry according to selected speed.
+
+  @param[in] ControllerHandle The EFI_HANDLE of the controller.
+  @param[in] Slot             The slot number of the SD card to send the 
command to.
+  @param[in] Timing           The timing to select.
+
+  @retval EFI_SUCCESS         The override function completed successfully.
+  @retval EFI_NOT_FOUND       The specified controller or slot does not exist.
+**/
+STATIC
+EFI_STATUS
+XenonSdMmcHcUhsSignaling (
+  IN EFI_HANDLE             ControllerHandle,
+  IN UINT8                  Slot,
+  IN SD_MMC_BUS_MODE        Timing
+  )
+{
+  EFI_PCI_IO_PROTOCOL      *PciIo;
+  EFI_STATUS                Status;
+  UINT8                     HostCtrl2;
+  UINT8                     XenonUhsSelect;
+
+  if (Slot != 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Update Host Control Register 2 only for HS200/HS400.
+  //
+  switch (Timing) {
+    case SdMmcMmcHs200:
+      XenonUhsSelect = XENON_SD_MMC_HC_CTRL_HS200;
+      break;
+    case SdMmcMmcHs400:
+      XenonUhsSelect = XENON_SD_MMC_HC_CTRL_HS400;
+      break;
+    default:
+      return EFI_SUCCESS;
+  }
+
+  Status = XenonGetPciIo (ControllerHandle, &PciIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  HostCtrl2 = (UINT8)~UHS_MODE_SELECT_MASK;
+  Status = XenonHcAndMmio (PciIo,
+             Slot,
+             SDHC_HOST_CTRL2,
+             sizeof (HostCtrl2),
+             &HostCtrl2);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = XenonHcOrMmio (PciIo,
+             Slot,
+             SDHC_HOST_CTRL2,
+             sizeof (XenonUhsSelect),
+             &XenonUhsSelect);
+
+  return Status;
+}
+
+/**
+
+  Additional operations specific for host controller
+
+  @param[in]      ControllerHandle      The EFI_HANDLE of the controller.
+  @param[in]      Slot                  The 0 based slot index.
+  @param[in]      Timing                The timing which should be set by
+                                        host controller.
+
+  @retval EFI_SUCCESS           The override function completed successfully.
+  @retval EFI_NOT_FOUND         The specified controller or slot does not 
exist.
+
+**/
+STATIC
+EFI_STATUS
+XenonSwitchClockFreqPost (
+  IN      EFI_HANDLE                      ControllerHandle,
+  IN      UINT8                           Slot,
+  IN      SD_MMC_BUS_MODE                 Timing
+  )
+{
+  EFI_STATUS                      Status;
+  MV_BOARD_SDMMC_DESC             SdMmcDesc;
+  EFI_PCI_IO_PROTOCOL             *PciIo;
+
+  if (Slot != 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  Status = XenonGetPciIo (ControllerHandle, &PciIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+  Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = XenonSetPhy (PciIo,
+             SdMmcDesc.XenonSlowModeEnabled,
+             SdMmcDesc.XenonTuningStepDivisor,
+             Timing);
+
+  return Status;
+}
+
+/**
+
+  Override function for SDHCI controller operations
+
+  @param[in]      ControllerHandle      The EFI_HANDLE of the controller.
+  @param[in]      Slot                  The 0 based slot index.
+  @param[in]      PhaseType             The type of operation and whether the
+                                        hook is invoked right before (pre) or
+                                        right after (post)
+  @param[in]      PhaseData             The pointer to a phase-specific data.
+
+  @retval EFI_SUCCESS           The override function completed successfully.
+  @retval EFI_NOT_FOUND         The specified controller or slot does not 
exist.
+  @retval EFI_UNSUPPORTED       Nothing has been done in connection of 
PhaseType
+  @retval EFI_INVALID_PARAMETER PhaseType is invalid
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+XenonSdMmcNotifyPhase (
+  IN      EFI_HANDLE                      ControllerHandle,
+  IN      UINT8                           Slot,
+  IN      EDKII_SD_MMC_PHASE_TYPE         PhaseType,
+  IN OUT  VOID                           *PhaseData
+  )
+{
+  EFI_STATUS                      Status;
+  MV_BOARD_SDMMC_DESC             SdMmcDesc;
+  EFI_PCI_IO_PROTOCOL             *PciIo;
+  SD_MMC_BUS_MODE                 *Timing;
+
+  if (Slot != 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  switch (PhaseType) {
+    case EdkiiSdMmcInitHostPre:
+      Status = XenonGetPciIo (ControllerHandle, &PciIo);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+
+      Status = XenonInit (PciIo,
+                 SdMmcDesc.Xenon1v8Enabled,
+                 SdMmcDesc.XenonSlowModeEnabled,
+                 SdMmcDesc.XenonTuningStepDivisor);
+      return Status;
+    case EdkiiSdMmcUhsSignaling:
+      if (PhaseData == NULL) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      Timing = (SD_MMC_BUS_MODE *)PhaseData;
+
+      Status = XenonSdMmcHcUhsSignaling (ControllerHandle,
+                 Slot,
+                 *Timing);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    case EdkiiSdMmcSwitchClockFreqPost:
+      if (PhaseData == NULL) {
+        return EFI_INVALID_PARAMETER;
+      }
+
+      Timing = (SD_MMC_BUS_MODE *)PhaseData;
+
+      Status = XenonSwitchClockFreqPost (ControllerHandle,
+                 Slot,
+                 *Timing);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
+      break;
+    default:
+      return EFI_SUCCESS;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  Override function for SDHCI capability bits
+
+  @param[in]      ControllerHandle      The EFI_HANDLE of the controller.
+  @param[in]      Slot                  The 0 based slot index.
+  @param[in,out]  SdMmcHcSlotCapability The SDHCI capability structure.
+  @param[in,out]  BaseClkFreq           The base clock frequency value that
+                                        optionally can be updated.
+
+  @retval EFI_SUCCESS           The override function completed successfully.
+  @retval EFI_NOT_FOUND         The specified controller or slot does not 
exist.
+  @retval EFI_INVALID_PARAMETER SdMmcHcSlotCapability is NULL
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+XenonSdMmcCapability (
+  IN      EFI_HANDLE                      ControllerHandle,
+  IN      UINT8                           Slot,
+  IN OUT  VOID                            *SdMmcHcSlotCapability,
+  IN OUT  UINT32                          *BaseClkFreq
+  )
+{
+  EFI_STATUS           Status;
+  MV_BOARD_SDMMC_DESC  SdMmcDesc;
+  UINT64               Capability;
+
+  if (SdMmcHcSlotCapability == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  if (Slot != 0) {
+    return EFI_NOT_FOUND;
+  }
+  Status = XenonGetSdMmcDesc (ControllerHandle, &SdMmcDesc);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Capability = ReadUnaligned64 (SdMmcHcSlotCapability);
+
+  //
+  // Override capabilities structure according to board configuration.
+  //
+  if (SdMmcDesc.Xenon1v8Enabled) {
+    Capability &= ~(UINT64)(SDHC_CAP_VOLTAGE_33 | SDHC_CAP_VOLTAGE_30);
+  } else {
+    Capability &= ~(UINT64)(SDHC_CAP_SDR104 | SDHC_CAP_DDR50 |
+                            SDHC_CAP_SDR50 | SDHC_CAP_VOLTAGE_18);
+  }
+
+  if (!SdMmcDesc.Xenon8BitBusEnabled) {
+    Capability &= ~(UINT64)(SDHC_CAP_BUS_WIDTH8);
+  }
+
+  if (SdMmcDesc.XenonSlowModeEnabled) {
+    Capability &= ~(UINT64)(SDHC_CAP_SDR104 | SDHC_CAP_DDR50);
+  }
+
+  Capability &= ~(UINT64)(SDHC_CAP_SLOT_TYPE_MASK);
+  Capability |= SdMmcDesc.SlotType << SDHC_CAP_SLOT_TYPE_OFFSET;
+
+  WriteUnaligned64 (SdMmcHcSlotCapability, Capability);
+
+  //
+  // Override inappropriate base clock frequency from Capabilities Register 1.
+  // Actual clock speed of Xenon controller is 400MHz.
+  //
+  *BaseClkFreq = XENON_MMC_MAX_CLK / 1000 / 1000;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The entry point for Xenon driver, used to install SdMMcOverrideProtocol
+  on the ImageHandle.
+
+  @param[in]  ImageHandle   The firmware allocated handle for this driver 
image.
+  @param[in]  SystemTable   Pointer to the EFI system table.
+
+  @retval EFI_SUCCESS   Driver loaded.
+  @retval other         Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeXenonDxe (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS Status;
+
+  mSdMmcOverride = AllocateZeroPool (sizeof (EDKII_SD_MMC_OVERRIDE));
+  if (mSdMmcOverride == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  mSdMmcOverride->Version = EDKII_SD_MMC_OVERRIDE_PROTOCOL_VERSION;
+  mSdMmcOverride->Capability = XenonSdMmcCapability;
+  mSdMmcOverride->NotifyPhase = XenonSdMmcNotifyPhase;
+
+  Status = gBS->InstallProtocolInterface (&ImageHandle,
+                  &gEdkiiSdMmcOverrideProtocolGuid,
+                  EFI_NATIVE_INTERFACE,
+                  mSdMmcOverride);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR,
+      "%a: Filed to install SdMmcOverride protocol\n",
+      __FUNCTION__));
+    return Status;
+  }
+
+  mXenonSdMmcOverrideHandle = ImageHandle;
+
+  return Status;
+}
diff --git a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c 
b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
index 6bbe5bc..0b4949d 100755
--- a/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
+++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c
@@ -41,7 +41,7 @@ XenonReadVersion (
   OUT UINT32 *ControllerVersion
   )
 {
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CTRL_VER, TRUE, 
SDHC_REG_SIZE_2B, ControllerVersion);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CTRL_VER, TRUE, SDHC_REG_SIZE_2B, 
ControllerVersion);
 }
 
 // Auto Clock Gating
@@ -54,7 +54,7 @@ XenonSetAcg (
 {
   UINT32 Var;
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
 
   if (Enable) {
     Var &= ~AUTO_CLKGATE_DISABLE_MASK;
@@ -62,7 +62,7 @@ XenonSetAcg (
     Var |= AUTO_CLKGATE_DISABLE_MASK;
   }
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 }
 
 STATIC
@@ -75,14 +75,17 @@ XenonSetSlot (
 {
   UINT32 Var;
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
   if (Enable) {
     Var |= ((0x1 << Slot) << SLOT_ENABLE_SHIFT);
   } else {
     Var &= ~((0x1 << Slot) << SLOT_ENABLE_SHIFT);
   }
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  // Enable SDCLK off while idle
+  Var |= SDCLK_IDLEOFF_ENABLE_MASK;
+
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SYS_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 }
 
 //
@@ -111,7 +114,6 @@ XenonSetPower (
   )
 {
   UINT8 Pwr = 0;
-  UINT32 Ctrl = 0;
 
   // Below statement calls routine to set voltage for SDIO devices in either 
HIGH (1) or LOW (0) mode
   switch (Vcc) {
@@ -141,39 +143,36 @@ XenonSetPower (
   }
 
   if (Pwr == 0) {
-    SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_POWER_CTRL, FALSE, 
SDHC_REG_SIZE_1B, &Pwr);
+    XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_POWER_CTRL, FALSE, 
SDHC_REG_SIZE_1B, &Pwr);
     return;
   }
 
   Pwr |= SDHCI_POWER_ON;
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX,SD_MMC_HC_POWER_CTRL, FALSE, 
SDHC_REG_SIZE_1B, &Pwr);
-
-  // Set VCCQ
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Ctrl);
-  Ctrl |= Vccq;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_SLOT_eMMC_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Ctrl);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_POWER_CTRL, FALSE, 
SDHC_REG_SIZE_1B, &Pwr);
 }
 
 UINTN
 XenonSetClk (
   IN EFI_PCI_IO_PROTOCOL   *PciIo,
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
   IN UINT32 Clock
   )
 {
   UINT32 Div;
   UINT32 Clk;
   UINT32 Retry;
+  UINT32 ControllerVersion;
   UINT16 Value = 0;
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Value);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Value);
 
   if (Clock == 0) {
     return 0;
   }
 
-  if (Private->ControllerVersion >= SDHCI_SPEC_300) {
+  XenonReadVersion (PciIo, &ControllerVersion);
+
+  if (ControllerVersion >= SDHCI_SPEC_300) {
     // Version 3.00 Divisors must be a multiple of 2
     if (XENON_MMC_MAX_CLK <= Clock) {
       Div = 1;
@@ -196,7 +195,7 @@ XenonSetClk (
   Clk |= ((Div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << 
SDHCI_DIVIDER_HI_SHIFT;
   Clk |= SDHCI_CLOCK_INT_EN;
 
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Clk);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Clk);
 
   //
   // Poll for internal controller clock to be stabilised
@@ -205,7 +204,7 @@ XenonSetClk (
   Retry = 200;
 
   do {
-    SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 
SDHC_REG_SIZE_2B, &Clk);
+    XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, TRUE, 
SDHC_REG_SIZE_2B, &Clk);
     if (Retry == 0) {
       DEBUG((DEBUG_ERROR, "SD/MMC: Internal Clock never stabilised\n"));
       return -1;
@@ -219,7 +218,7 @@ XenonSetClk (
   } while (!(Clk & SDHCI_CLOCK_INT_STABLE));
 
   Clk |= SDHCI_CLOCK_CARD_EN;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Clk);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &Clk);
 
   return 0;
 }
@@ -231,54 +230,11 @@ XenonPhyInit (
 {
   UINT32 Var, Wait, Time;
   UINT32 Clock = XENON_MMC_MAX_CLK;
-  UINT16 ClkCtrl;
-
-  // Need to disable the clock to set EMMC_PHY_TIMING_ADJUST register
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-  ClkCtrl &= ~(SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN);
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-
-  // Enable QSP PHASE SELECT
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-  Var |= SAMPL_INV_QSP_PHASE_SELECT;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
-
-  // Enable internal clock
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-  ClkCtrl |= SDHCI_CLOCK_INT_EN;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-
-  //
-  // Poll for host MMC PHY clock init to be stable
-  // Wait up to 100us
-  //
-  Time = 100;
-  while (Time--) {
-    SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-    if (Var & SDHCI_CLOCK_INT_STABLE) {
-      break;
-    }
-
-    // Poll interval for MMC PHY clock to be stable is 1us
-    gBS->Stall (1);
-  }
-  if (Time <= 0) {
-    DEBUG((DEBUG_ERROR, "SD/MMC: Failed to enable MMC internal clock in 
Time\n"));
-    return;
-  }
-
-  // Enable bus clock
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, TRUE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-  ClkCtrl |= SDHCI_CLOCK_CARD_EN;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_CLOCK_CTRL, FALSE, 
SDHC_REG_SIZE_2B, &ClkCtrl);
-
-  // Delay 200us to wait for the completion of bus clock
-  gBS->Stall (200);
 
   // Init PHY
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
   Var |= PHY_INITIALIZAION;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 
   // Add duration of FC_SYNC_RST
   Wait = ((Var >> FC_SYNC_RST_DURATION_SHIFT) & FC_SYNC_RST_DURATION_MASK);
@@ -308,7 +264,7 @@ XenonPhyInit (
   // Poll for host eMMC PHY init to complete, wait up to 100us
   Time = 100;
   while (Time--) {
-    Var = SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+    Var = XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
     Var &= PHY_INITIALIZAION;
     if (!Var) {
       break;
@@ -326,52 +282,227 @@ XenonPhyInit (
   return;
 }
 
+//
+// Enable eMMC PHY HW DLL
+// DLL should be enabled and stable before HS200/SDR104 tuning,
+// and before HS400 data strobe setting.
+//
 STATIC
-VOID
+EFI_STATUS
+EmmcPhyEnableDll (
+  IN EFI_PCI_IO_PROTOCOL   *PciIo
+  )
+{
+  UINT32 Var;
+  UINT16 SlotState;
+  UINT8 Retry;
+
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_DLL_CONTROL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  if (Var & DLL_ENABLE) {
+    return EFI_SUCCESS;
+  }
+
+  // Enable DLL
+  Var |= (DLL_ENABLE | DLL_FAST_LOCK);
+
+  //
+  // Set Phase as 90 degree, which is most common value.
+  //
+  Var &= ~((DLL_PHASE_MASK << DLL_PHSEL0_SHIFT) |
+           (DLL_PHASE_MASK << DLL_PHSEL1_SHIFT));
+  Var |= ((DLL_PHASE_90_DEGREE << DLL_PHSEL0_SHIFT) |
+          (DLL_PHASE_90_DEGREE << DLL_PHSEL1_SHIFT));
+
+  Var &= ~(DLL_BYPASS_EN | DLL_REFCLK_SEL);
+  Var |= DLL_UPDATE;
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_DLL_CONTROL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+
+  // Wait max 32 ms for the DLL to lock
+  Retry = 32;
+  do {
+    XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_EXT_PRESENT_STATE, TRUE, 
SDHC_REG_SIZE_2B, &SlotState);
+
+    if (Retry == 0) {
+      DEBUG ((DEBUG_ERROR, "SD/MMC: Fail to lock DLL\n"));
+      return EFI_TIMEOUT;
+    }
+
+    gBS->Stall (1000);
+    Retry--;
+
+  } while (!(SlotState & DLL_LOCK_STATE));
+
+  return EFI_SUCCESS;
+}
+
+//
+// Config to eMMC PHY to prepare for tuning.
+// Enable HW DLL and set the TUNING_STEP
+//
+STATIC
+EFI_STATUS
+EmmcPhyConfigTuning (
+  IN EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN UINT8 TuningStepDivisor
+  )
+{
+  UINT32 Var, TuningStep;
+  EFI_STATUS Status;
+
+  Status = EmmcPhyEnableDll (PciIo);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  // Achieve TUNING_STEP with HW DLL help
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_DLL_CUR_DLY_VAL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  TuningStep = Var / TuningStepDivisor;
+  if (TuningStep > TUNING_STEP_MASK) {
+      DEBUG ((DEBUG_ERROR, "HS200 TUNING_STEP %d is larger than MAX value\n", 
TuningStep));
+    TuningStep = TUNING_STEP_MASK;
+  }
+
+  // Set TUNING_STEP for later tuning
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_OP_STATUS_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  Var &= ~(TUN_CONSECUTIVE_TIMES_MASK << TUN_CONSECUTIVE_TIMES_SHIFT);
+  Var |= (TUN_CONSECUTIVE_TIMES << TUN_CONSECUTIVE_TIMES_SHIFT);
+  Var &= ~(TUNING_STEP_MASK << TUNING_STEP_SHIFT);
+  Var |= (TuningStep << TUNING_STEP_SHIFT);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_OP_STATUS_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+BOOLEAN
+XenonPhySlowMode (
+  IN EFI_PCI_IO_PROTOCOL   *PciIo,
+  IN SD_MMC_BUS_MODE        Timing,
+  IN BOOLEAN SlowMode
+  )
+{
+  UINT32 Var = 0;
+
+  // Check if Slow Mode is required in lower speed mode in SDR mode
+  if (((Timing == SdMmcUhsSdr50) ||
+       (Timing == SdMmcUhsSdr25) ||
+       (Timing == SdMmcUhsSdr12) ||
+       (Timing == SdMmcMmcHsDdr) ||
+       (Timing == SdMmcMmcHsSdr) ||
+       (Timing == SdMmcMmcLegacy)) && SlowMode) {
+    Var = QSN_PHASE_SLOW_MODE_BIT;
+    XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, 
SDHC_REG_SIZE_4B, &Var);
+    return TRUE;
+  }
+
+  Var = ~QSN_PHASE_SLOW_MODE_BIT;
+  XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, 
SDHC_REG_SIZE_4B, &Var);
+  return FALSE;
+}
+
+EFI_STATUS
 XenonSetPhy (
   IN EFI_PCI_IO_PROTOCOL   *PciIo,
-  UINT8 Timing
+  IN BOOLEAN               SlowMode,
+  IN UINT8                 TuningStepDivisor,
+  IN SD_MMC_BUS_MODE       Timing
   )
 {
   UINT32 Var = 0;
+  UINT16 ClkCtrl;
 
-  // Setup pad, set bit[30], bit[28] and bits[26:24]
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-  Var |= (AUTO_RECEN_CTRL | OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | 
FC_DQ_RECEN);
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  // Setup pad, bit[28] and bits[26:24]
+  Var = OEN_QSN | FC_QSP_RECEN | FC_CMD_RECEN | FC_DQ_RECEN;
+  // All FC_XX_RECEIVCE should be set as CMOS Type
+  Var |= FC_ALL_CMOS_RECEIVER;
+  XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL, SDHC_REG_SIZE_4B, 
&Var);
+
+  // Set CMD and DQ Pull Up
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL1, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  Var |= (EMMC5_1_FC_CMD_PU | EMMC5_1_FC_DQ_PU);
+  Var &= ~(EMMC5_1_FC_CMD_PD | EMMC5_1_FC_DQ_PD);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL1, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+
+  if (Timing == SdMmcUhsSdr12) {
+    if (SlowMode) {
+      XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+      Var |= QSN_PHASE_SLOW_MODE_BIT;
+      XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+    }
+
+    goto PhyInit;
+  }
 
   //
   // If Timing belongs to high speed, set bit[17] of
   // EMMC_PHY_TIMING_ADJUST register
   //
-  if ((Timing == MMC_TIMING_MMC_HS400) ||
-      (Timing == MMC_TIMING_MMC_HS200) ||
-      (Timing == MMC_TIMING_UHS_SDR50) ||
-      (Timing == MMC_TIMING_UHS_SDR104) ||
-      (Timing == MMC_TIMING_UHS_DDR50) ||
-      (Timing == MMC_TIMING_UHS_SDR25)) {
-
-    SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-
-    // Set SLOW_MODE for PHY
-    Var |= OUTPUT_QSN_PHASE_SELECT | QSN_PHASE_SLOW_MODE_BIT;
-    SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  if ((Timing == SdMmcMmcHs400) ||
+      (Timing == SdMmcMmcHs200) ||
+      (Timing == SdMmcUhsDdr50) ||
+      (Timing == SdMmcUhsSdr50) ||
+      (Timing == SdMmcUhsSdr104) ||
+      (Timing == SdMmcUhsSdr25)) {
+    Var = ~OUTPUT_QSN_PHASE_SELECT;
+    XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_TIMING_ADJUST, 
SDHC_REG_SIZE_4B, &Var);
   }
 
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-  Var |= (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  if (XenonPhySlowMode (PciIo, Timing, SlowMode)) {
+    goto PhyInit;
+  }
+
+  // Set default ZNR and ZPR value
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL2, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  Var &= ~((ZNR_MASK << ZNR_SHIFT) | ZPR_MASK);
+  Var |= ((ZNR_DEF_VALUE << ZNR_SHIFT) | ZPR_DEF_VALUE);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_PAD_CONTROL2, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+
+  // Need to disable the clock to set EMMC_PHY_FUNC_CONTROL register
+  ClkCtrl = ~SDHCI_CLOCK_CARD_EN;
+  XenonHcAndMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, SDHC_REG_SIZE_2B, 
&ClkCtrl);
+
+  if ((Timing == SdMmcMmcHs400) ||
+      (Timing == SdMmcUhsDdr50)) {
+    Var = (DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE;
+    XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, 
SDHC_REG_SIZE_4B, &Var);
+  } else {
+    Var = ~((DQ_DDR_MODE_MASK << DQ_DDR_MODE_SHIFT) | CMD_DDR_MODE);
+    XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, 
SDHC_REG_SIZE_4B, &Var);
+  }
+
+  if (Timing == SdMmcMmcHs400) {
+    Var = ~DQ_ASYNC_MODE;
+    XenonHcAndMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, 
SDHC_REG_SIZE_4B, &Var);
+  } else {
+    Var = DQ_ASYNC_MODE;
+    XenonHcOrMmio (PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, 
SDHC_REG_SIZE_4B, &Var);
+  }
 
-  if (Timing == MMC_TIMING_MMC_HS400) {
-    SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
-    Var &= ~DQ_ASYNC_MODE;
-    SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_PHY_FUNC_CONTROL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  // Enable bus clock
+  ClkCtrl = SDHCI_CLOCK_CARD_EN;
+  XenonHcOrMmio (PciIo, SD_BAR_INDEX, SDHC_CLOCK_CTRL, SDHC_REG_SIZE_2B, 
&ClkCtrl);
 
+  // Delay 200us to wait for the completion of bus clock
+  gBS->Stall (200);
+
+  if (Timing == SdMmcMmcHs400) {
     Var = LOGIC_TIMING_VALUE;
-    SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+    XenonHcRwMmio (PciIo, SD_BAR_INDEX, EMMC_LOGIC_TIMING_ADJUST, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  } else {
+    // Disable data strobe
+    Var = ~ENABLE_DATA_STROBE;
+    XenonHcAndMmio (PciIo, SD_BAR_INDEX, XENON_SLOT_EMMC_CTRL, 
SDHC_REG_SIZE_4B, &Var);
   }
 
+PhyInit:
   XenonPhyInit (PciIo);
+
+  if ((Timing == SdMmcMmcHs200) ||
+      (Timing == SdMmcUhsSdr104)) {
+    return EmmcPhyConfigTuning (PciIo, TuningStepDivisor);
+  }
+
+  return EFI_SUCCESS;
 }
 
 STATIC
@@ -384,16 +515,16 @@ XenonConfigureInterrupts (
 
   // Clear interrupt status
   Var = SDHC_CLR_ALL_IRQ_MASK;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, 
SDHC_REG_SIZE_4B, &Var);
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 
   // Enable only interrupts served by the SD controller
   Var = SDHC_CLR_ALL_IRQ_MASK & ~(NOR_INT_STS_CARD_INS | NOR_INT_STS_CARD_INT);
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_STS_EN, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_STS_EN, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 
   // Mask all sdhci interrupt sources
   Var = SDHC_CLR_ALL_IRQ_MASK & ~NOR_INT_SIG_EN_CARD_INT;
-  SdMmcHcRwMmio (PciIo, SD_BAR_INDEX, SD_MMC_HC_NOR_INT_SIG_EN, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio (PciIo, SD_BAR_INDEX, SDHC_NOR_INT_SIG_EN, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 }
 
 // Enable Parallel Transfer Mode
@@ -407,7 +538,7 @@ XenonSetParallelTransfer (
 {
   UINT32 Var;
 
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
 
   if (Enable) {
     Var |= (0x1 << Slot);
@@ -415,7 +546,10 @@ XenonSetParallelTransfer (
     Var &= ~(0x1 << Slot);
   }
 
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  // Mask command conflict error
+  Var |= MASK_CMD_CONFLICT_ERR;
+
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SYS_EXT_OP_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 }
 
 STATIC
@@ -429,7 +563,7 @@ XenonSetTuning (
   UINT32 Var;
 
   // Set the Re-Tuning Request functionality
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, TRUE, 
SDHC_REG_SIZE_4B, &Var);
 
   if (Enable) {
     Var |= RETUNING_COMPATIBLE;
@@ -437,10 +571,10 @@ XenonSetTuning (
     Var &= ~RETUNING_COMPATIBLE;
   }
 
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHC_SLOT_RETUNING_REQ_CTRL, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 
   // Set the Re-tuning Event Signal Enable
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, TRUE, 
SDHC_REG_SIZE_4B, &Var);
 
   if (Enable) {
     Var |= SDHCI_RETUNE_EVT_INTSIG;
@@ -448,12 +582,12 @@ XenonSetTuning (
     Var &= ~SDHCI_RETUNE_EVT_INTSIG;
   }
 
-  SdMmcHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, 
SDHC_REG_SIZE_4B, &Var);
+  XenonHcRwMmio(PciIo, SD_BAR_INDEX, SDHCI_SIGNAL_ENABLE, FALSE, 
SDHC_REG_SIZE_4B, &Var);
 }
 
 VOID
 XenonReset (
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
   IN UINT8 Slot,
   IN UINT8 Mask
   )
@@ -463,19 +597,19 @@ XenonReset (
 
   SwReset = Mask;
 
-  SdMmcHcRwMmio (
-          Private->PciIo,
+  XenonHcRwMmio (
+          PciIo,
           Slot,
-          SD_MMC_HC_SW_RST,
+          SDHC_SW_RST,
           FALSE,
           sizeof (SwReset),
           &SwReset
         );
 
-  SdMmcHcRwMmio (
-          Private->PciIo,
+  XenonHcRwMmio (
+          PciIo,
           Slot,
-          SD_MMC_HC_SW_RST,
+          SDHC_SW_RST,
           TRUE,
           sizeof (SwReset),
           &SwReset
@@ -491,10 +625,10 @@ XenonReset (
 
     // Poll interval for SwReset is 100us according to SDHCI spec
     gBS-> Stall (100);
-    SdMmcHcRwMmio (
-            Private->PciIo,
+    XenonHcRwMmio (
+            PciIo,
             Slot,
-            SD_MMC_HC_SW_RST,
+            SDHC_SW_RST,
             TRUE,
             sizeof (SwReset),
             &SwReset
@@ -505,7 +639,6 @@ XenonReset (
 STATIC
 VOID
 XenonTransferPio (
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
   IN UINT8 Slot,
   IN OUT VOID *Buffer,
   IN UINT16 BlockSize,
@@ -532,7 +665,7 @@ XenonTransferPio (
 
 EFI_STATUS
 XenonTransferData (
-  IN SD_MMC_HC_PRIVATE_DATA *Private,
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
   IN UINT8 Slot,
   IN OUT VOID *Buffer,
   IN UINT32 DataLen,
@@ -552,10 +685,10 @@ XenonTransferData (
   Mask = PRESENT_STATE_BUFFER_RD_EN | PRESENT_STATE_BUFFER_WR_EN;
 
   do {
-    SdMmcHcRwMmio (
-            Private->PciIo,
+    XenonHcRwMmio (
+            PciIo,
             Slot,
-            SD_MMC_HC_NOR_INT_STS,
+            SDHC_NOR_INT_STS,
             TRUE,
             sizeof (IntStatus),
             &IntStatus
@@ -567,10 +700,10 @@ XenonTransferData (
     }
 
     if (IntStatus & Rdy) {
-      SdMmcHcRwMmio (
-              Private->PciIo,
+      XenonHcRwMmio (
+              PciIo,
               Slot,
-              SD_MMC_HC_PRESENT_STATE,
+              SDHC_PRESENT_STATE,
               TRUE,
               sizeof (PresentState),
               &PresentState
@@ -580,16 +713,16 @@ XenonTransferData (
         continue;
       }
 
-      SdMmcHcRwMmio (
-              Private->PciIo,
+      XenonHcRwMmio (
+              PciIo,
               Slot,
-              SD_MMC_HC_NOR_INT_STS,
+              SDHC_NOR_INT_STS,
               FALSE,
               sizeof (Rdy),
               &Rdy
             );
 
-      XenonTransferPio (Private, Slot, Buffer, BlockSize, Read);
+      XenonTransferPio (Slot, Buffer, BlockSize, Read);
 
       Buffer += BlockSize;
       if (++Block >= Blocks) {
@@ -612,13 +745,13 @@ XenonTransferData (
 
 EFI_STATUS
 XenonInit (
-  IN SD_MMC_HC_PRIVATE_DATA *Private
+  IN EFI_PCI_IO_PROTOCOL *PciIo,
+  IN BOOLEAN             Support1v8,
+  IN BOOLEAN             SlowMode,
+  IN UINT8               TuningStepDivisor
   )
 {
-  EFI_PCI_IO_PROTOCOL *PciIo = Private->PciIo;
-
-  // Read XENON version
-  XenonReadVersion (PciIo, &Private->ControllerVersion);
+  EFI_STATUS Status;
 
   // Disable auto clock generator
   XenonSetAcg (PciIo, FALSE);
@@ -626,11 +759,11 @@ XenonInit (
   // XENON has only one port
   XenonSetSlot (PciIo, XENON_MMC_SLOT_ID, TRUE);
 
-  XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, 
XENON_MMC_MODE_SD_SDIO);
-
-  // Set MAX_CLOCK for configuring PHY
-  XenonSetClk (PciIo, Private, XENON_MMC_MAX_CLK);
-  XenonSetPhy (PciIo, MMC_TIMING_UHS_SDR50);
+  if (Support1v8) {
+    XenonSetPower (PciIo, MMC_VDD_165_195, eMMC_VCCQ_1_8V, 
XENON_MMC_MODE_SD_SDIO);
+  } else {
+    XenonSetPower (PciIo, MMC_VDD_32_33, eMMC_VCCQ_3_3V, 
XENON_MMC_MODE_SD_SDIO);
+  }
 
   XenonConfigureInterrupts (PciIo);
 
@@ -641,9 +774,12 @@ XenonInit (
   // Enable auto clock generator
   XenonSetAcg (PciIo, TRUE);
 
-  // Set proper clock for PHY configuration
-  XenonSetClk (PciIo, Private, XENON_MMC_BASE_CLK);
-  XenonPhyInit (PciIo);
+  // Set lowest clock and the PHY for the initialization phase
+  XenonSetClk (PciIo, XENON_MMC_BASE_CLK);
+  Status = XenonSetPhy (PciIo, SlowMode, TuningStepDivisor, SdMmcUhsSdr12);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
 
   return EFI_SUCCESS;
 }
-- 
2.7.4

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to