diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mmc/mv_sdhci.c | 41 | ||||
-rw-r--r-- | drivers/mmc/omap_hsmmc.c | 124 | ||||
-rw-r--r-- | drivers/mmc/s5p_sdhci.c | 50 |
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 |