mmc: Add Marvell Xenon SDHCI controller driver
PATCH v3 3/9 mmc: Add Marvell Xenon SDHCI controller driver
This driver implementes platform specific code for the Xenon SDHCI controller which is integrated in the Marvell MVEBU Armada 37xx and Armada 7k / 8K SoCs.
History:
This driver is ported from the Marvell U-Boot version 2015.01 which is written by Victor Gu <[email protected]> with minor changes ported from the Linux driver which is written by Ziji Hu <[email protected]>.
---
v3:
- Removed unreferenced macros
- Used BIT(x) consistantly
- Removed unreferenced "wait" variable from xenon_mmc_phy_init()
- Used SLOT_MASK(slot) instead of (1 << slot)
- Moved init of host_caps and shifted it to the host struct
- Removed "enable" parameter from multiple functions and made them a disable or enable function instead
- Used strncmp instead of strcmp
v2:
- Renamed MMC_XENON_SDHCI to MMC_SDHCI_XENON as requested by Masahiro for the new consistant MMC naming
drivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/xenon_sdhci.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 601 insertions(+) create mode 100644 drivers/mmc/xenon_sdhci.c
drivers/mmc/Kconfig +11 -0
@@ -287,6 +287,17 @@ config MMC_SDHCI_SPEAR If unsure, say N. +config MMC_SDHCI_XENON + bool "SDHCI support for the Xenon SDHCI controller" + depends on MMC_SDHCI && DM_MMC && OF_CONTROL + help + Support for Xenon SDHCI host controller on Marvell Armada 3700 + 7k/8k ARM SoCs platforms + + If you have a controller with this interface, say Y here. + + If unsure, say N. + config MMC_SDHCI_TEGRA bool "SDHCI platform support for the Tegra SD/MMC Controller" depends on TEGRA
drivers/mmc/Makefile +1 -0
@@ -68,6 +68,7 @@ obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += spear_sdhci.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += tegra_mmc.o +obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o
drivers/mmc/xenon_sdhci.c new file +589 -0
589 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v3 3/9 mmc: Add Marvell Xenon SDHCI controller driver
Quoted 4 lines · Stefan Roese
This driver implementes platform specific code for the Xenon SDHCI controller which is integrated in the Marvell MVEBU Armada 37xx and Armada 7k / 8K SoCs.
Quoted 8 lines
History:
This driver is ported from the Marvell U-Boot version 2015.01 which is written by Victor Gu <[email protected]> with minor changes ported from the Linux driver which is written by Ziji Hu <[email protected]>.Signed-off-by Stefan Roese <[email protected]>Cc Jaehoon Chung <[email protected]>Cc Masahiro Yamada <[email protected]>
Beset Regards,
Jaehoon Chung
Quoted 651 lines
---
v3:
- Removed unreferenced macros
- Used BIT(x) consistantly
- Removed unreferenced "wait" variable fromxenon_mmc_phy_init()
- UsedSLOT_MASK(slot)instead of (1 << slot)
- Moved init ofhost_capsand shifted it to the host struct
- Removed "enable" parameter from multiple functions and made them a disable or enable function instead
- Used strncmp instead of strcmpv2:
- RenamedMMC_XENON_SDHCItoMMC_SDHCI_XENONas requested by Masahiro for the new consistant MMC namingdrivers/mmc/Kconfig | 11 + drivers/mmc/Makefile | 1 + drivers/mmc/xenon_sdhci.c | 589 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 601 insertions(+) create mode 100644 drivers/mmc/xenon_sdhci.cdrivers/mmc/Kconfig +11
-0@@ -287,6 +287,17 @@ config MMC_SDHCI_SPEAR If unsure, say N. +config MMC_SDHCI_XENON + bool "SDHCI support for the Xenon SDHCI controller" + depends on MMC_SDHCI && DM_MMC && OF_CONTROL + help + Support for Xenon SDHCI host controller on Marvell Armada 3700 + 7k/8k ARM SoCs platforms + + If you have a controller with this interface, say Y here. + + If unsure, say N. + config MMC_SDHCI_TEGRA bool "SDHCI platform support for the Tegra SD/MMC Controller" depends on TEGRAdrivers/mmc/Makefile +1
-0@@ -68,6 +68,7 @@ obj-$(CONFIG_MMC_SDHCI_MV) += mv_sdhci.o obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += spear_sdhci.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += tegra_mmc.o +obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o obj-$(CONFIG_MMC_SUNXI) += sunxi_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.odrivers/mmc/xenon_sdhci.c new file +589
-0@@ -0,0 +1,589 @@ +/* +* Driver for Marvell SOC Platform Group Xenon SDHC as a platform device +* +* Copyright (C) 2016 Marvell, All Rights Reserved. +* +* Author: Victor Gu <[email protected]> +* Date: 2016-8-24 +* +* Included parts of the Linux driver version which was written by: +* Hu Ziji <[email protected]> +* +* Ported to from Marvell 2015.01 to mainline U-Boot 2017.01: +* Stefan Roese <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0 +*/ + +#include <common.h> +#include <dm.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <malloc.h> +#include <sdhci.h> + +DECLARE_GLOBAL_DATA_PTR ; + +/* Register Offset of SD Host Controller SOCP self-defined register */ +#define SDHC_SYS_CFG_INFO 0x0104 +#define SLOT_TYPE_SDIO_SHIFT 24 +#define SLOT_TYPE_EMMC_MASK 0xFF +#define SLOT_TYPE_EMMC_SHIFT 16 +#define SLOT_TYPE_SD_SDIO_MMC_MASK 0xFF +#define SLOT_TYPE_SD_SDIO_MMC_SHIFT 8 +#define NR_SUPPORTED_SLOT_MASK 0x7 + +#define SDHC_SYS_OP_CTRL 0x0108 +#define AUTO_CLKGATE_DISABLE_MASK BIT(20) +#define SDCLK_IDLEOFF_ENABLE_SHIFT 8 +#define SLOT_ENABLE_SHIFT 0 + +#define SDHC_SYS_EXT_OP_CTRL 0x010C +#define MASK_CMD_CONFLICT_ERROR BIT(8) + +#define SDHC_SLOT_OP_STATUS_CTRL 0x0128 +#define DELAY_90_DEGREE_MASK_EMMC5 BIT(7) +#define DELAY_90_DEGREE_SHIFT_EMMC5 7 +#define EMMC_5_0_PHY_FIXED_DELAY_MASK 0x7F +#define EMMC_PHY_FIXED_DELAY_MASK 0xFF +#define EMMC_PHY_FIXED_DELAY_WINDOW_MIN (EMMC_PHY_FIXED_DELAY_MASK >> 3) +#define SDH_PHY_FIXED_DELAY_MASK 0x1FF +#define SDH_PHY_FIXED_DELAY_WINDOW_MIN (SDH_PHY_FIXED_DELAY_MASK >> 4) + +#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 TUNING_STEP_DIVIDER BIT(6) + +#define FORCE_SEL_INVERSE_CLK_SHIFT 11 + +#define SDHC_SLOT_FIFO_CTRL 0x012c + +#define SDHC_SLOT_EMMC_CTRL 0x0130 +#define ENABLE_DATA_STROBE BIT(24) +#define SET_EMMC_RSTN BIT(16) +#define DISABLE_RD_DATA_CRC BIT(14) +#define DISABLE_CRC_STAT_TOKEN BIT(13) +#define EMMC_VCCQ_MASK 0x3 +#define EMMC_VCCQ_1_8V 0x1 +#define EMMC_VCCQ_3_3V 0x3 + +#define SDHC_SLOT_RETUNING_REQ_CTRL 0x0144 +/* retuning compatible */ +#define RETUNING_COMPATIBLE 0x1 + +#define SDHC_SLOT_EXT_PRESENT_STATE 0x014C +#define LOCK_STATE 0x1 + +#define SDHC_SLOT_DLL_CUR_DLY_VAL 0x0150 + +/* Tuning Parameter */ +#define TMR_RETUN_NO_PRESENT 0xf +#define XENON_MAX_TUN_COUNT 0xb +#define DEF_TUNING_COUNT 0x9 + +#define MMC_TIMING_FAKE 0xFF + +#define DEFAULT_SDCLK_FREQ 400000 +#define LOWEST_SDCLK_FREQ 100000 + +/* Xenon specific Mode Select value */ +#define XENON_SDHCI_CTRL_HS200 0x5 +#define XENON_SDHCI_CTRL_HS400 0x6 + +#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 EMMC_PHY_SLOW_MODE (1 << 29) +#define PHY_INITIALIZAION (1 << 31) +#define WAIT_CYCLE_BEFORE_USING_MASK 0xf +#define WAIT_CYCLE_BEFORE_USING_SHIFT 12 +#define FC_SYNC_EN_DURATION_MASK 0xf +#define FC_SYNC_EN_DURATION_SHIFT 8 +#define FC_SYNC_RST_EN_DURATION_MASK 0xf +#define FC_SYNC_RST_EN_DURATION_SHIFT 4 +#define FC_SYNC_RST_DURATION_MASK 0xf +#define FC_SYNC_RST_DURATION_SHIFT 0 + +#define EMMC_PHY_FUNC_CONTROL (EMMC_PHY_REG_BASE + 0x4) +#define DQ_ASYNC_MODE (1 << 4) +#define DQ_DDR_MODE_SHIFT 8 +#define DQ_DDR_MODE_MASK 0xff +#define CMD_DDR_MODE (1 << 16) + +#define EMMC_PHY_PAD_CONTROL (EMMC_PHY_REG_BASE + 0x8) +#define REC_EN_SHIFT 24 +#define REC_EN_MASK 0xf +#define FC_DQ_RECEN (1 << 24) +#define FC_CMD_RECEN (1 << 25) +#define FC_QSP_RECEN (1 << 26) +#define FC_QSN_RECEN (1 << 27) +#define OEN_QSN (1 << 28) +#define AUTO_RECEN_CTRL (1 << 30) + +#define EMMC_PHY_PAD_CONTROL1 (EMMC_PHY_REG_BASE + 0xc) +#define EMMC5_1_FC_QSP_PD BIT(9) +#define EMMC5_1_FC_QSP_PU BIT(25) +#define EMMC5_1_FC_CMD_PD BIT(8) +#define EMMC5_1_FC_CMD_PU BIT(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 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 EMMC_LOGIC_TIMING_ADJUST (EMMC_PHY_REG_BASE + 0x18) +#define EMMC_LOGIC_TIMING_ADJUST_LOW (EMMC_PHY_REG_BASE + 0x1c) + +/* Recommend by HW team */ +#define LOGIC_TIMING_VALUE 0x5a54 + +#define SDHCI_RETUNE_EVT_INTSIG 0x00001000 + +/* Hyperion only have one slot 0 */ +#define XENON_MMC_SLOT_ID_HYPERION 0 + +#define MMC_TIMING_LEGACY 0 +#define MMC_TIMING_MMC_HS 1 +#define MMC_TIMING_SD_HS 2 +#define MMC_TIMING_UHS_SDR12 3 +#define MMC_TIMING_UHS_SDR25 4 +#define MMC_TIMING_UHS_SDR50 5 +#define MMC_TIMING_UHS_SDR104 6 +#define MMC_TIMING_UHS_DDR50 7 +#define MMC_TIMING_MMC_DDR52 8 +#define MMC_TIMING_MMC_HS200 9 +#define MMC_TIMING_MMC_HS400 10 + +#define XENON_MMC_MAX_CLK 400000000 + +enum soc_pad_ctrl_type { +SOC_PAD_SD , +SOC_PAD_FIXED_1_8V , +}; + +struct xenon_sdhci_plat { +struct mmc_config cfg; +struct mmc mmc; +}; + +struct xenon_sdhci_priv { +struct sdhci_host host; + +u8 timing; + +unsigned int clock; + +void *pad_ctrl_reg; +int pad_type; +}; + +static int xenon_mmc_phy_init (struct sdhci_host *host) +{ +struct xenon_sdhci_priv *priv = host->mmc->priv; +u32 clock = priv->clock; +u32 wait; +u32 time; +u32 var; + +/* Enable QSP PHASE SELECT */ + var =sdhci_readl (host,EMMC_PHY_TIMING_ADJUST ); + var |=SAMPL_INV_QSP_PHASE_SELECT ; +if ((priv->timing ==MMC_TIMING_UHS_SDR50 ) || + (priv->timing ==MMC_TIMING_UHS_SDR25 ) || + (priv->timing ==MMC_TIMING_UHS_SDR12 ) || + (priv->timing ==MMC_TIMING_SD_HS ) || + (priv->timing ==MMC_TIMING_LEGACY )) + var |=EMMC_PHY_SLOW_MODE ; +sdhci_writel (host, var,EMMC_PHY_TIMING_ADJUST ); + +/* Poll for host MMC PHY clock init to be stable */ +/* Wait up to 10ms */ + time =100 ; +while (time--) { + var =sdhci_readl (host,SDHCI_CLOCK_CONTROL ); +if (var &SDHCI_CLOCK_INT_STABLE ) +break ; + +udelay (100 ); + } + +if (time <=0 ) { +error ("Failed to enable MMC internal clock in time\n" ); +return -ETIMEDOUT ; + } + +/* Init PHY */ + var =sdhci_readl (host,EMMC_PHY_TIMING_ADJUST ); + var |=PHY_INITIALIZAION ; +sdhci_writel (host, var,EMMC_PHY_TIMING_ADJUST ); + +/* Add duration of FC_SYNC_RST */ + wait = (var >>FC_SYNC_RST_DURATION_SHIFT ) &FC_SYNC_RST_DURATION_MASK ; +/* Add interval between FC_SYNC_EN and FC_SYNC_RST */ + wait += (var >>FC_SYNC_RST_EN_DURATION_SHIFT ) & +FC_SYNC_RST_EN_DURATION_MASK ; +/* Add duration of asserting FC_SYNC_EN */ + wait += (var >>FC_SYNC_EN_DURATION_SHIFT ) &FC_SYNC_EN_DURATION_MASK ; +/* Add duration of waiting for PHY */ + wait += (var >>WAIT_CYCLE_BEFORE_USING_SHIFT ) & +WAIT_CYCLE_BEFORE_USING_MASK ; +/* +* According to Moyang, 4 addtional bus clock and 4 AXI bus clock +* are required +*/ +/* left shift 20 bits */ + wait +=8 ; + wait <<=20 ; + +if (clock ==0 ) { +/* Use the possibly slowest bus frequency value */ + clock =100000 ; + } + +/* Get the wait time in unit of ms */ + wait = wait / clock; + wait++; + +/* Poll for host eMMC PHY init to complete */ +/* Wait up to 10ms */ + time =100 ; +while (time--) { + var =sdhci_readl (host,EMMC_PHY_TIMING_ADJUST ); + var &=PHY_INITIALIZAION ; +if (!var) +break ; + +/* wait for host eMMC PHY init to complete */ +udelay (100 ); + } + +if (time <=0 ) { +error ("Failed to init MMC PHY in time\n" ); +return -ETIMEDOUT ; + } + +return 0 ; +} + +#define ARMADA_3700_SOC_PAD_1_8V 0x1 +#define ARMADA_3700_SOC_PAD_3_3V 0x0 + +static void armada_3700_soc_pad_voltage_set (struct sdhci_host *host) +{ +struct xenon_sdhci_priv *priv = host->mmc->priv; + +if (priv->pad_type ==SOC_PAD_FIXED_1_8V ) +writel (ARMADA_3700_SOC_PAD_1_8V , priv->pad_ctrl_reg); +else if (priv->pad_type ==SOC_PAD_SD ) +writel (ARMADA_3700_SOC_PAD_3_3V , priv->pad_ctrl_reg); +} + +static void xenon_mmc_phy_set (struct sdhci_host *host) +{ +struct xenon_sdhci_priv *priv = host->mmc->priv; +u32 var; + +/* Setup pad, set bit[30], bit[28] and bits[26:24] */ + var =sdhci_readl (host,EMMC_PHY_PAD_CONTROL ); + var |=AUTO_RECEN_CTRL |OEN_QSN |FC_QSP_RECEN | +FC_CMD_RECEN |FC_DQ_RECEN ; +sdhci_writel (host, var,EMMC_PHY_PAD_CONTROL ); + +/* Set CMD and DQ Pull Up */ + var =sdhci_readl (host,EMMC_PHY_PAD_CONTROL1 ); + var |= (EMMC5_1_FC_CMD_PU |EMMC5_1_FC_DQ_PU ); + var &= ~(EMMC5_1_FC_CMD_PD |EMMC5_1_FC_DQ_PD ); +sdhci_writel (host, var,EMMC_PHY_PAD_CONTROL1 ); + +/* +* If timing belongs to high speed, set bit[17] of +* EMMC_PHY_TIMING_ADJUST register +*/ +if ((priv->timing ==MMC_TIMING_MMC_HS400 ) || + (priv->timing ==MMC_TIMING_MMC_HS200 ) || + (priv->timing ==MMC_TIMING_UHS_SDR50 ) || + (priv->timing ==MMC_TIMING_UHS_SDR104 ) || + (priv->timing ==MMC_TIMING_UHS_DDR50 ) || + (priv->timing ==MMC_TIMING_UHS_SDR25 ) || + (priv->timing ==MMC_TIMING_MMC_DDR52 )) { + var =sdhci_readl (host,EMMC_PHY_TIMING_ADJUST ); + var |=OUTPUT_QSN_PHASE_SELECT ; +sdhci_writel (host, var,EMMC_PHY_TIMING_ADJUST ); + } + +/* +* When setting EMMC_PHY_FUNC_CONTROL register, +* SD clock should be disabled +*/ + var =sdhci_readl (host,SDHCI_CLOCK_CONTROL ); + var &= ~SDHCI_CLOCK_CARD_EN ; +sdhci_writew (host, var,SDHCI_CLOCK_CONTROL ); + + var =sdhci_readl (host,EMMC_PHY_FUNC_CONTROL ); +if (host->mmc->ddr_mode) { + var |= (DQ_DDR_MODE_MASK <<DQ_DDR_MODE_SHIFT ) |CMD_DDR_MODE ; + }else { + var &= ~((DQ_DDR_MODE_MASK <<DQ_DDR_MODE_SHIFT ) | +CMD_DDR_MODE ); + } +sdhci_writel (host, var,EMMC_PHY_FUNC_CONTROL ); + +/* Enable bus clock */ + var =sdhci_readl (host,SDHCI_CLOCK_CONTROL ); + var |=SDHCI_CLOCK_CARD_EN ; +sdhci_writew (host, var,SDHCI_CLOCK_CONTROL ); + +xenon_mmc_phy_init (host); +} + +/* Enable/Disable the Auto Clock Gating function of this slot */ +static void xenon_mmc_set_acg (struct sdhci_host *host,bool enable) +{ +u32 var; + + var =sdhci_readl (host,SDHC_SYS_OP_CTRL ); +if (enable) + var &= ~AUTO_CLKGATE_DISABLE_MASK ; +else + var |=AUTO_CLKGATE_DISABLE_MASK ; + +sdhci_writel (host, var,SDHC_SYS_OP_CTRL ); +} + +/* Enable specific slot */ +static void xenon_mmc_set_slot (struct sdhci_host *host,u8 slot,bool enable) +{ +u32 var; + + var =sdhci_readl (host,SDHC_SYS_OP_CTRL ); +if (enable) + var |= (0x1 << slot) <<SLOT_ENABLE_SHIFT ; +else + var &= ~((0x1 << slot) <<SLOT_ENABLE_SHIFT ); +sdhci_writel (host, var,SDHC_SYS_OP_CTRL ); +} + +/* Enable Parallel Transfer Mode */ +static void xenon_mmc_set_parallel_tran (struct sdhci_host *host,u8 slot, +bool enable) +{ +u32 var; + + var =sdhci_readl (host,SDHC_SYS_EXT_OP_CTRL ); +if (enable) + var |= (0x1 << slot); +else + var &= ~(0x1 << slot); +sdhci_writel (host, var,SDHC_SYS_EXT_OP_CTRL ); +} + +static void xenon_mmc_set_tuning (struct sdhci_host *host,u8 slot,bool enable) +{ +u32 var; + +/* Set the Re-Tuning Request functionality */ + var =sdhci_readl (host,SDHC_SLOT_RETUNING_REQ_CTRL ); +if (enable) + var |=RETUNING_COMPATIBLE ; +else + var &= ~RETUNING_COMPATIBLE ; +sdhci_writel (host, var,SDHC_SLOT_RETUNING_REQ_CTRL ); + +/* Set the Re-tuning Event Signal Enable */ + var =sdhci_readl (host,SDHCI_SIGNAL_ENABLE ); +if (enable) + var |=SDHCI_RETUNE_EVT_INTSIG ; +else + var &= ~SDHCI_RETUNE_EVT_INTSIG ; +sdhci_writel (host, var,SDHCI_SIGNAL_ENABLE ); +} + +/* Mask command conflict error */ +static void xenon_mask_cmd_conflict_err (struct sdhci_host *host) +{ +u32 reg; + + reg =sdhci_readl (host,SDHC_SYS_EXT_OP_CTRL ); + reg |=MASK_CMD_CONFLICT_ERROR ; +sdhci_writel (host, reg,SDHC_SYS_EXT_OP_CTRL ); +} + +/* Platform specific function for post set_ios configuration */ +static void xenon_sdhci_set_ios_post (struct sdhci_host *host) +{ +struct xenon_sdhci_priv *priv = host->mmc->priv; +uint speed = host->mmc->tran_speed; +int pwr_18v =0 ; + +if ((sdhci_readb (host,SDHCI_POWER_CONTROL ) & ~SDHCI_POWER_ON ) == +SDHCI_POWER_180 ) + pwr_18v =1 ; + +/* Set timing variable according to the configured speed */ +if (IS_SD (host->mmc)) { +/* SD/SDIO */ +if (pwr_18v) { +if (host->mmc->ddr_mode) + priv->timing =MMC_TIMING_UHS_DDR50 ; +else if (speed <=25000000 ) + priv->timing =MMC_TIMING_UHS_SDR25 ; +else + priv->timing =MMC_TIMING_UHS_SDR50 ; + }else { +if (speed <=25000000 ) + priv->timing =MMC_TIMING_LEGACY ; +else + priv->timing =MMC_TIMING_SD_HS ; + } + }else { +/* eMMC */ +if (host->mmc->ddr_mode) + priv->timing =MMC_TIMING_MMC_DDR52 ; +else if (speed <=26000000 ) + priv->timing =MMC_TIMING_LEGACY ; +else + priv->timing =MMC_TIMING_MMC_HS ; + } + +/* Re-init the PHY */ +xenon_mmc_phy_set (host); +} + +/* Install a driver specific handler for post set_ios configuration */ +static const struct sdhci_ops xenon_sdhci_ops = { + .set_ios_post = xenon_sdhci_set_ios_post +}; + +static int xenon_sdhci_probe (struct udevice *dev) +{ +struct xenon_sdhci_plat *plat =dev_get_platdata (dev); +struct mmc_uclass_priv *upriv =dev_get_uclass_priv (dev); +struct xenon_sdhci_priv *priv =dev_get_priv (dev); +struct sdhci_host *host =dev_get_priv (dev); +int ret; + + host->mmc = &plat->mmc; + host->mmc->priv = host; + host->mmc->dev = dev; + upriv->mmc = host->mmc; + +/* Set quirks */ + host->quirks =SDHCI_QUIRK_WAIT_SEND_CMD |SDHCI_QUIRK_32BIT_DMA_ADDR ; + +/* Set default timing */ + priv->timing =MMC_TIMING_LEGACY ; + +/* Disable auto clock gating during init */ +xenon_mmc_set_acg (host, false); + +/* Enable slot */ +xenon_mmc_set_slot (host,XENON_MMC_SLOT_ID_HYPERION , true); + +/* +* Set default power on SoC PHY PAD register (currently only +* available on the Armada 3700) +*/ +if (priv->pad_ctrl_reg) +armada_3700_soc_pad_voltage_set (host); + + ret =sdhci_setup_cfg (&plat->cfg, host,XENON_MMC_MAX_CLK ,0 ); +if (ret) +return ret; + + plat->cfg.host_caps =MMC_MODE_HS | MMC_MODE_HS_52MHz | + MMC_MODE_DDR_52MHz; + +switch (fdtdec_get_int (gd->fdt_blob, dev->of_offset,"bus-width" ,1 )) { +case 8 : + plat->cfg.host_caps |=MMC_MODE_8BIT ; +break ; +case 4 : + plat->cfg.host_caps |=MMC_MODE_4BIT ; +break ; +case 1 : +break ; +default : +printf ("Invalid \"bus-width\" value\n" ); +return -EINVAL ; + } + + host->ops = &xenon_sdhci_ops; + + ret =sdhci_probe (dev); +if (ret) +return ret; + +/* Enable parallel transfer */ +xenon_mmc_set_parallel_tran (host,XENON_MMC_SLOT_ID_HYPERION , true); + +/* Disable tuning functionality of this slot */ +xenon_mmc_set_tuning (host,XENON_MMC_SLOT_ID_HYPERION , false); + +/* Enable auto clock gating after init */ +xenon_mmc_set_acg (host, true); + +xenon_mask_cmd_conflict_err (host); + +return ret; +} + +static int xenon_sdhci_ofdata_to_platdata (struct udevice *dev) +{ +struct sdhci_host *host =dev_get_priv (dev); +struct xenon_sdhci_priv *priv =dev_get_priv (dev); +const char *name; + + host->name = dev->name; + host->ioaddr = (void *)dev_get_addr (dev); + +if (of_device_is_compatible (dev,"marvell,armada-3700-sdhci" )) + priv->pad_ctrl_reg = (void *)dev_get_addr_index (dev,1 ); + + name =fdt_getprop (gd->fdt_blob, dev->of_offset,"marvell,pad-type" , +NULL ); +if (name) { +if (0 ==strcmp (name,"sd" )) { + priv->pad_type =SOC_PAD_SD ; + }else if (0 ==strcmp (name,"fixed-1-8v" )) { + priv->pad_type =SOC_PAD_FIXED_1_8V ; + }else { +printf ("Unsupported SOC PHY PAD ctrl type %s\n" , name); +return -EINVAL ; + } + } + +return 0 ; +} + +static int xenon_sdhci_bind (struct udevice *dev) +{ +struct xenon_sdhci_plat *plat =dev_get_platdata (dev); + +return sdhci_bind (dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id xenon_sdhci_ids[] = { + { .compatible ="marvell,armada-8k-sdhci" ,}, + { .compatible ="marvell,armada-3700-sdhci" ,}, + { } +}; + +U_BOOT_DRIVER (xenon_sdhci_drv) = { + .name ="xenon_sdhci" , + .id =UCLASS_MMC , + .of_match = xenon_sdhci_ids, + .ofdata_to_platdata = xenon_sdhci_ofdata_to_platdata, + .ops = &sdhci_ops, + .bind = xenon_sdhci_bind, + .probe = xenon_sdhci_probe, + .priv_auto_alloc_size =sizeof (struct xenon_sdhci_priv ), + .platdata_auto_alloc_size =sizeof (struct xenon_sdhci_plat ), +};
PATCH v3 3/9 mmc: Add Marvell Xenon SDHCI controller driver
Hi Jaehoon,
Quoted 10 lines · Jaehoon Chung
Quoted 9 lines · Stefan Roese
This driver implementes platform specific code for the Xenon SDHCI controller which is integrated in the Marvell MVEBU Armada 37xx and Armada 7k / 8K SoCs.
History:
This driver is ported from the Marvell U-Boot version 2015.01 which is written by Victor Gu <[email protected]> with minor changes ported from the Linux driver which is written by Ziji Hu <[email protected]>.
Quoted 5 lines
Quoted 3 lines
Signed-off-by Stefan Roese <[email protected]>Cc Jaehoon Chung <[email protected]>Cc Masahiro Yamada <[email protected]>Reviewed-by Jaehoon Chung <[email protected]>
Thanks. Will you pull the 3 patches (1/9 ... 3/9) via your mmc repository? Or are you okay with me pushing them via the Marvell repository?
Thanks,
Stefan
PATCH v3 3/9 mmc: Add Marvell Xenon SDHCI controller driver
Hi Stefan.
Quoted 17 lines · Stefan Roese
Hi Jaehoon,
Quoted 14 lines · Jaehoon Chung
Quoted 12 lines · Stefan Roese
This driver implementes platform specific code for the Xenon SDHCI controller which is integrated in the Marvell MVEBU Armada 37xx and Armada 7k / 8K SoCs.
History:
This driver is ported from the Marvell U-Boot version 2015.01 which is written by Victor Gu <[email protected]> with minor changes ported from the Linux driver which is written by Ziji Hu <[email protected]>.Signed-off-by Stefan Roese <[email protected]>Cc Jaehoon Chung <[email protected]>Cc Masahiro Yamada <[email protected]>
Quoted 5 lines
Quoted 1 line
Reviewed-by Jaehoon Chung <[email protected]>Thanks. Will you pull the 3 patches (1/9 ... 3/9) via your mmc repository? Or are you okay with me pushing them via the Marvell repository?
I'm ok about pushing on Marvell repository. :)
Thanks!
Best Regards,
Jaehoon Chung
Quoted 6 lines
Thanks,
Stefan