diff options
author | Patrice Chotard <patrice.chotard@st.com> | 2017-02-21 13:37:09 +0100 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2017-03-14 20:40:20 -0400 |
commit | eee20f813272c2e731ba5f88c4eb099705894534 (patch) | |
tree | 9e54bf59d362745c7db8fb2f40b81050d81f12de /drivers | |
parent | d4184952320a52e415d4814f1b3144e13ab94b82 (diff) |
STiH410: Add STi SDHCI driver
Add SDHCI host controller found on STMicroelectronics SoCs
On some ST SoCs, i.e. STiH407/STiH410, the MMC devices can live
inside a dedicated flashSS sub-system that provides an extend subset
of registers that can be used to configure the Arasan MMC/SD Host
Controller.
This means, that the SDHCI Arasan Controller can be configured to be
eMMC4.5 or 4.3 spec compliant.
W/o these settings the SDHCI will configure and use the MMC/SD
controller with limited features e.g. PIO mode, no DMA, no HS etc.
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mmc/Makefile | 1 | ||||
-rw-r--r-- | drivers/mmc/sti_sdhci.c | 141 |
3 files changed, 149 insertions, 0 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 01d1dbfb1b..ea5ea087f3 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -299,6 +299,13 @@ config MMC_SDHCI_SPEAR If unsure, say N. +config MMC_SDHCI_STI + bool "SDHCI support for STMicroelectronics SoC" + depends on MMC_SDHCI + help + This selects the Secure Digital Host Controller Interface (SDHCI) + on STMicroelectronics STiH410 SoC. + config MMC_SDHCI_XENON bool "SDHCI support for the Xenon SDHCI controller" depends on MMC_SDHCI && DM_MMC && OF_CONTROL diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index 8e922db3f1..6a488f1db9 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -61,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_PIC32) += pic32_sdhci.o obj-$(CONFIG_MMC_SDHCI_ROCKCHIP) += rockchip_sdhci.o obj-$(CONFIG_MMC_SDHCI_S5P) += s5p_sdhci.o obj-$(CONFIG_MMC_SDHCI_SPEAR) += spear_sdhci.o +obj-$(CONFIG_MMC_SDHCI_STI) += sti_sdhci.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += tegra_mmc.o obj-$(CONFIG_MMC_SDHCI_XENON) += xenon_sdhci.o obj-$(CONFIG_MMC_SDHCI_ZYNQ) += zynq_sdhci.o diff --git a/drivers/mmc/sti_sdhci.c b/drivers/mmc/sti_sdhci.c new file mode 100644 index 0000000000..2a07082036 --- /dev/null +++ b/drivers/mmc/sti_sdhci.c @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017 + * Patrice Chotard <patrice.chotard@st.com> + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#include <common.h> +#include <dm.h> +#include <mmc.h> +#include <sdhci.h> +#include <asm/arch/sdhci.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct sti_sdhci_plat { + struct mmc_config cfg; + struct mmc mmc; +}; + +/* + * used to get access to MMC1 reset, + * will be removed when STi reset driver will be available + */ +#define STIH410_SYSCONF5_BASE 0x092b0000 + +/** + * sti_mmc_core_config: configure the Arasan HC + * @regbase: base address + * @mmc_instance: mmc instance id + * Description: this function is to configure the Arasan MMC HC. + * This should be called when the system starts in case of, on the SoC, + * it is needed to configure the host controller. + * This happens on some SoCs, i.e. StiH410, where the MMC0 inside the flashSS + * needs to be configured as MMC 4.5 to have full capabilities. + * W/o these settings the SDHCI could configure and use the embedded controller + * with limited features. + */ +static void sti_mmc_core_config(const u32 regbase, int mmc_instance) +{ + unsigned long *sysconf; + + /* only MMC1 has a reset line */ + if (mmc_instance) { + sysconf = (unsigned long *)(STIH410_SYSCONF5_BASE + + ST_MMC_CCONFIG_REG_5); + generic_set_bit(SYSCONF_MMC1_ENABLE_BIT, sysconf); + } + + writel(STI_FLASHSS_MMC_CORE_CONFIG_1, + regbase + FLASHSS_MMC_CORE_CONFIG_1); + + if (mmc_instance) { + writel(STI_FLASHSS_MMC_CORE_CONFIG2, + regbase + FLASHSS_MMC_CORE_CONFIG_2); + writel(STI_FLASHSS_MMC_CORE_CONFIG3, + regbase + FLASHSS_MMC_CORE_CONFIG_3); + } else { + writel(STI_FLASHSS_SDCARD_CORE_CONFIG2, + regbase + FLASHSS_MMC_CORE_CONFIG_2); + writel(STI_FLASHSS_SDCARD_CORE_CONFIG3, + regbase + FLASHSS_MMC_CORE_CONFIG_3); + } + writel(STI_FLASHSS_MMC_CORE_CONFIG4, + regbase + FLASHSS_MMC_CORE_CONFIG_4); +} + +static int sti_sdhci_probe(struct udevice *dev) +{ + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + struct sti_sdhci_plat *plat = dev_get_platdata(dev); + struct sdhci_host *host = dev_get_priv(dev); + int ret, mmc_instance; + + /* + * identify current mmc instance, mmc1 has a reset, not mmc0 + * MMC0 is wired to the SD slot, + * MMC1 is wired on the high speed connector + */ + + if (fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "resets", NULL)) + mmc_instance = 1; + else + mmc_instance = 0; + + sti_mmc_core_config((const u32) host->ioaddr, mmc_instance); + + host->quirks = SDHCI_QUIRK_WAIT_SEND_CMD | + SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_NO_HISPD_BIT; + + host->host_caps = MMC_MODE_DDR_52MHz; + + ret = sdhci_setup_cfg(&plat->cfg, host, 50000000, 400000); + if (ret) + return ret; + + host->mmc = &plat->mmc; + host->mmc->priv = host; + host->mmc->dev = dev; + upriv->mmc = host->mmc; + + return sdhci_probe(dev); +} + +static int sti_sdhci_ofdata_to_platdata(struct udevice *dev) +{ + struct sdhci_host *host = dev_get_priv(dev); + + host->name = strdup(dev->name); + host->ioaddr = (void *)dev_get_addr(dev); + + host->bus_width = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "bus-width", 4); + + return 0; +} + +static int sti_sdhci_bind(struct udevice *dev) +{ + struct sti_sdhci_plat *plat = dev_get_platdata(dev); + + return sdhci_bind(dev, &plat->mmc, &plat->cfg); +} + +static const struct udevice_id sti_sdhci_ids[] = { + { .compatible = "st,sdhci" }, + { } +}; + +U_BOOT_DRIVER(sti_mmc) = { + .name = "sti_sdhci", + .id = UCLASS_MMC, + .of_match = sti_sdhci_ids, + .bind = sti_sdhci_bind, + .ops = &sdhci_ops, + .ofdata_to_platdata = sti_sdhci_ofdata_to_platdata, + .probe = sti_sdhci_probe, + .priv_auto_alloc_size = sizeof(struct sdhci_host), + .platdata_auto_alloc_size = sizeof(struct sti_sdhci_plat), +}; |