
On 01/23/2017 07:52 PM, Stefan Roese wrote:
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 xigu@marvell.com with minor changes ported from the Linux driver which is written by Ziji Hu huziji@marvell.com.
Signed-off-by: Stefan Roese sr@denx.de Cc: Jaehoon Chung jh80.chung@samsung.com Cc: Masahiro Yamada yamada.masahiro@socionext.com
Reviewed-by: Jaehoon Chung jh80.chung@samsung.com
Beset Regards, Jaehoon Chung
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
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 9ed8da39ef..147e52d332 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -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 diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 4dca09c955..6af7f79ff8 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -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 diff --git a/drivers/mmc/xenon_sdhci.c b/drivers/mmc/xenon_sdhci.c new file mode 100644 index 0000000000..f36b482288 --- /dev/null +++ b/drivers/mmc/xenon_sdhci.c @@ -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 xigu@marvell.com
- Date: 2016-8-24
- Included parts of the Linux driver version which was written by:
- Hu Ziji huziji@marvell.com
- Ported to from Marvell 2015.01 to mainline U-Boot 2017.01:
- Stefan Roese sr@denx.de
- 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),
+};