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