aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig6
-rw-r--r--drivers/mmc/mv_sdhci.c41
-rw-r--r--drivers/mmc/omap_hsmmc.c124
-rw-r--r--drivers/mmc/s5p_sdhci.c50
4 files changed, 198 insertions, 23 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 6277f92ef5..ceae7bcaec 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -1,5 +1,11 @@
menu "MMC Host controller Support"
+config MMC
+ bool "Enable MMC support"
+ depends on ARCH_SUNXI
+ help
+ TODO: Move all architectures to use this option
+
config DM_MMC
bool "Enable MMC controllers using Driver Model"
depends on DM
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index 75fa014931..82c695f906 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -1,6 +1,41 @@
+/*
+ * Marvell SD Host Controller Interface
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
#include <common.h>
#include <malloc.h>
#include <sdhci.h>
+#include <linux/mbus.h>
+
+#define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
+#define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
+
+static void sdhci_mvebu_mbus_config(void __iomem *base)
+{
+ const struct mbus_dram_target_info *dram;
+ int i;
+
+ dram = mvebu_mbus_dram_info();
+
+ for (i = 0; i < 4; i++) {
+ writel(0, base + SDHCI_WINDOW_CTRL(i));
+ writel(0, base + SDHCI_WINDOW_BASE(i));
+ }
+
+ for (i = 0; i < dram->num_cs; i++) {
+ const struct mbus_dram_window *cs = dram->cs + i;
+
+ /* Write size, attributes and target id to control register */
+ writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + SDHCI_WINDOW_CTRL(i));
+
+ /* Write base address to base register */
+ writel(cs->base, base + SDHCI_WINDOW_BASE(i));
+ }
+}
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
static struct sdhci_ops mv_ops;
@@ -47,6 +82,12 @@ int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks)
mv_ops.write_b = mv_sdhci_writeb;
host->ops = &mv_ops;
#endif
+
+ if (CONFIG_IS_ENABLED(ARCH_MVEBU)) {
+ /* Configure SDHCI MBUS mbus bridge windows */
+ sdhci_mvebu_mbus_config((void __iomem *)regbase);
+ }
+
if (quirks & SDHCI_QUIRK_REG32_RW)
host->version = sdhci_readl(host, SDHCI_HOST_VERSION - 2) >> 16;
else
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index d7b388f3f4..5038a9f55f 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -31,10 +31,15 @@
#include <twl4030.h>
#include <twl6030.h>
#include <palmas.h>
-#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/mmc_host_def.h>
+#if !defined(CONFIG_SOC_KEYSTONE)
+#include <asm/gpio.h>
#include <asm/arch/sys_proto.h>
+#endif
+#include <dm.h>
+
+DECLARE_GLOBAL_DATA_PTR;
/* simplify defines to OMAP_HSMMC_USE_GPIO */
#if (defined(CONFIG_OMAP_GPIO) && !defined(CONFIG_SPL_BUILD)) || \
@@ -52,9 +57,15 @@ struct omap_hsmmc_data {
struct hsmmc *base_addr;
struct mmc_config cfg;
#ifdef OMAP_HSMMC_USE_GPIO
+#ifdef CONFIG_DM_MMC
+ struct gpio_desc cd_gpio; /* Change Detect GPIO */
+ struct gpio_desc wp_gpio; /* Write Protect GPIO */
+ bool cd_inverted;
+#else
int cd_gpio;
int wp_gpio;
#endif
+#endif
};
/* If we fail after 1 second wait, something is really bad */
@@ -64,7 +75,7 @@ static int mmc_read_data(struct hsmmc *mmc_base, char *buf, unsigned int size);
static int mmc_write_data(struct hsmmc *mmc_base, const char *buf,
unsigned int siz);
-#ifdef OMAP_HSMMC_USE_GPIO
+#if defined(OMAP_HSMMC_USE_GPIO) && !defined(CONFIG_DM_MMC)
static int omap_mmc_setup_gpio_in(int gpio, const char *label)
{
int ret;
@@ -600,6 +611,34 @@ static void omap_hsmmc_set_ios(struct mmc *mmc)
}
#ifdef OMAP_HSMMC_USE_GPIO
+#ifdef CONFIG_DM_MMC
+static int omap_hsmmc_getcd(struct mmc *mmc)
+{
+ struct omap_hsmmc_data *priv = mmc->priv;
+ int value;
+
+ value = dm_gpio_get_value(&priv->cd_gpio);
+ /* if no CD return as 1 */
+ if (value < 0)
+ return 1;
+
+ if (priv->cd_inverted)
+ return !value;
+ return value;
+}
+
+static int omap_hsmmc_getwp(struct mmc *mmc)
+{
+ struct omap_hsmmc_data *priv = mmc->priv;
+ int value;
+
+ value = dm_gpio_get_value(&priv->wp_gpio);
+ /* if no WP return as 0 */
+ if (value < 0)
+ return 0;
+ return value;
+}
+#else
static int omap_hsmmc_getcd(struct mmc *mmc)
{
struct omap_hsmmc_data *priv_data = mmc->priv;
@@ -628,6 +667,7 @@ static int omap_hsmmc_getwp(struct mmc *mmc)
return gpio_get_value(wp_gpio);
}
#endif
+#endif
static const struct mmc_ops omap_hsmmc_ops = {
.send_cmd = omap_hsmmc_send_cmd,
@@ -639,6 +679,7 @@ static const struct mmc_ops omap_hsmmc_ops = {
#endif
};
+#ifndef CONFIG_DM_MMC
int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
int wp_gpio)
{
@@ -662,7 +703,8 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
priv_data->base_addr = (struct hsmmc *)OMAP_HSMMC2_BASE;
#if (defined(CONFIG_OMAP44XX) || defined(CONFIG_OMAP54XX) || \
defined(CONFIG_DRA7XX) || defined(CONFIG_AM57XX) || \
- defined(CONFIG_AM43XX)) && defined(CONFIG_HSMMC2_8BIT)
+ defined(CONFIG_AM43XX) || defined(CONFIG_SOC_KEYSTONE)) && \
+ defined(CONFIG_HSMMC2_8BIT)
/* Enable 8-bit interface for eMMC on OMAP4/5 or DRA7XX */
host_caps_val |= MMC_MODE_8BIT;
#endif
@@ -724,3 +766,79 @@ int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
return 0;
}
+#else
+static int omap_hsmmc_ofdata_to_platdata(struct udevice *dev)
+{
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
+ const void *fdt = gd->fdt_blob;
+ int node = dev->of_offset;
+ struct mmc_config *cfg;
+ int val;
+
+ priv->base_addr = (struct hsmmc *)dev_get_addr(dev);
+ cfg = &priv->cfg;
+
+ cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
+ val = fdtdec_get_int(fdt, node, "bus-width", -1);
+ if (val < 0) {
+ printf("error: bus-width property missing\n");
+ return -ENOENT;
+ }
+
+ switch (val) {
+ case 0x8:
+ cfg->host_caps |= MMC_MODE_8BIT;
+ case 0x4:
+ cfg->host_caps |= MMC_MODE_4BIT;
+ break;
+ default:
+ printf("error: invalid bus-width property\n");
+ return -ENOENT;
+ }
+
+ cfg->f_min = 400000;
+ cfg->f_max = fdtdec_get_int(fdt, node, "max-frequency", 52000000);
+ cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+ cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+ priv->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
+
+ return 0;
+}
+
+static int omap_hsmmc_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct omap_hsmmc_data *priv = dev_get_priv(dev);
+ struct mmc_config *cfg;
+ struct mmc *mmc;
+
+ cfg = &priv->cfg;
+ cfg->name = "OMAP SD/MMC";
+ cfg->ops = &omap_hsmmc_ops;
+
+ mmc = mmc_create(cfg, priv);
+ if (mmc == NULL)
+ return -1;
+
+ upriv->mmc = mmc;
+
+ return 0;
+}
+
+static const struct udevice_id omap_hsmmc_ids[] = {
+ { .compatible = "ti,omap3-hsmmc" },
+ { .compatible = "ti,omap4-hsmmc" },
+ { .compatible = "ti,am33xx-hsmmc" },
+ { }
+};
+
+U_BOOT_DRIVER(omap_hsmmc) = {
+ .name = "omap_hsmmc",
+ .id = UCLASS_MMC,
+ .of_match = omap_hsmmc_ids,
+ .ofdata_to_platdata = omap_hsmmc_ofdata_to_platdata,
+ .probe = omap_hsmmc_probe,
+ .priv_auto_alloc_size = sizeof(struct omap_hsmmc_data),
+};
+#endif
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index 4db51d6488..15ecfee961 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -84,9 +84,9 @@ static int s5p_sdhci_core_init(struct sdhci_host *host)
int s5p_sdhci_init(u32 regbase, int index, int bus_width)
{
- struct sdhci_host *host = malloc(sizeof(struct sdhci_host));
+ struct sdhci_host *host = calloc(1, sizeof(struct sdhci_host));
if (!host) {
- printf("sdhci__host malloc fail!\n");
+ printf("sdhci__host allocation fail!\n");
return 1;
}
host->ioaddr = (void *)regbase;
@@ -101,29 +101,31 @@ struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS];
static int do_sdhci_init(struct sdhci_host *host)
{
- int dev_id, flag;
- int err = 0;
+ int dev_id, flag, ret;
flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
dev_id = host->index + PERIPH_ID_SDMMC0;
if (dm_gpio_is_valid(&host->pwr_gpio)) {
dm_gpio_set_value(&host->pwr_gpio, 1);
- err = exynos_pinmux_config(dev_id, flag);
- if (err) {
+ ret = exynos_pinmux_config(dev_id, flag);
+ if (ret) {
debug("MMC not configured\n");
- return err;
+ return ret;
}
}
if (dm_gpio_is_valid(&host->cd_gpio)) {
- if (dm_gpio_get_value(&host->cd_gpio))
+ ret = dm_gpio_get_value(&host->cd_gpio);
+ if (ret) {
+ debug("no SD card detected (%d)\n", ret);
return -ENODEV;
+ }
- err = exynos_pinmux_config(dev_id, flag);
- if (err) {
+ ret = exynos_pinmux_config(dev_id, flag);
+ if (ret) {
printf("external SD not configured\n");
- return err;
+ return ret;
}
}
@@ -170,7 +172,8 @@ static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host)
static int process_nodes(const void *blob, int node_list[], int count)
{
struct sdhci_host *host;
- int i, node;
+ int i, node, ret;
+ int failed = 0;
debug("%s: count = %d\n", __func__, count);
@@ -182,13 +185,22 @@ static int process_nodes(const void *blob, int node_list[], int count)
host = &sdhci_host[i];
- if (sdhci_get_config(blob, node, host)) {
- printf("%s: failed to decode dev %d\n", __func__, i);
- return -1;
+ ret = sdhci_get_config(blob, node, host);
+ if (ret) {
+ printf("%s: failed to decode dev %d (%d)\n", __func__, i, ret);
+ failed++;
+ continue;
+ }
+
+ ret = do_sdhci_init(host);
+ if (ret) {
+ printf("%s: failed to initialize dev %d (%d)\n", __func__, i, ret);
+ failed++;
}
- do_sdhci_init(host);
}
- return 0;
+
+ /* we only consider it an error when all nodes fail */
+ return (failed == count ? -1 : 0);
}
int exynos_mmc_init(const void *blob)
@@ -200,8 +212,6 @@ int exynos_mmc_init(const void *blob)
COMPAT_SAMSUNG_EXYNOS_MMC, node_list,
SDHCI_MAX_HOSTS);
- process_nodes(blob, node_list, count);
-
- return 0;
+ return process_nodes(blob, node_list, count);
}
#endif