From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: Marcin Wojtas <mw@semihalf.com>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
"Leif Lindholm" <leif.lindholm@linaro.org>,
"Wu, Hao A" <hao.a.wu@intel.com>,
"Nadav Haklai" <nadavh@marvell.com>,
"Jan Dąbroś" <jsd@semihalf.com>,
"Grzegorz Jaszczyk" <jaz@semihalf.com>,
"Kostya Porotchkin" <kostap@marvell.com>,
"Tomasz Michalec" <tm@semihalf.com>
Subject: Re: [platforms: PATCH v5 8/8] Marvell/Drivers: XenonDxe: Switch to use generic SdMmcPciHcDxe
Date: Thu, 15 Nov 2018 16:56:42 -0800 [thread overview]
Message-ID: <CAKv+Gu_KqnjkUKHCyenfiod8pCD73Cq=CxNkdAGbthVugug3kg@mail.gmail.com> (raw)
In-Reply-To: <1542112371-32546-9-git-send-email-mw@semihalf.com>
On Tue, 13 Nov 2018 at 04:33, Marcin Wojtas <mw@semihalf.com> wrote:
>
> From: Tomasz Michalec <tm@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 <mw@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 | 432 ++++++++++++++++++++
> Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdhci.c | 408 ++++++++++++------
> 9 files changed, 1402 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..f966e5f
> --- /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 ## BY_START
Please change the annotation to ## 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
> + );
> + }
> +
I guess this is an issue that existed before in the code, but it looks
like you are only doing byte for byte reads and writes here. Is that
intentional?
> + 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..7babda1
> --- /dev/null
> +++ b/Silicon/Marvell/Drivers/SdMmc/XenonDxe/XenonSdMmcOverride.c
> @@ -0,0 +1,432 @@
> +/*******************************************************************************
> +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) {
> + BoardDescProtocol->BoardDescFree (SdMmcDescs);
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + BoardDescProtocol->BoardDescFree (SdMmcDescs);
> +
> + 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 Controler control 2 registry according to selected speed.
> +
Controller
> + @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
>
next prev parent reply other threads:[~2018-11-16 0:56 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-11-13 12:32 [platforms: PATCH v5 0/8] Armada7k8k Xenon driver rework Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 1/8] Silicon/SynQuacer/PlatformDxe: adjust to updated SdMmcOverride Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 2/8] Marvell/Library: ArmadaBoardDescLib: Extend SDMMC information Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 3/8] SolidRun/Armada80x0McBin: Introduce board description library Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 4/8] Marvell/Armada70x0Db: " Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 5/8] Marvell/Armada80x0Db: " Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 6/8] Marvell/Drivers: MvBoardDesc: Extend information for SdMmc Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 7/8] Marvell/Drivers: XenonDxe: Remove SdMmcPciHcDxe files Marcin Wojtas
2018-11-13 12:32 ` [platforms: PATCH v5 8/8] Marvell/Drivers: XenonDxe: Switch to use generic SdMmcPciHcDxe Marcin Wojtas
2018-11-16 0:56 ` Ard Biesheuvel [this message]
2018-11-18 22:20 ` Marcin Wojtas
2018-11-19 1:59 ` Ard Biesheuvel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAKv+Gu_KqnjkUKHCyenfiod8pCD73Cq=CxNkdAGbthVugug3kg@mail.gmail.com' \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox