summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/Kconfig20
-rw-r--r--drivers/mmc/arm_pl180_mmci.c14
-rw-r--r--drivers/mmc/arm_pl180_mmci.h3
-rw-r--r--drivers/mmc/dw_mmc.c38
-rw-r--r--drivers/mmc/fsl_esdhc.c41
-rw-r--r--drivers/mmc/mtk-sd.c23
-rw-r--r--drivers/mmc/mv_sdhci.c67
-rw-r--r--drivers/mmc/rockchip_dw_mmc.c4
-rw-r--r--drivers/mmc/sdhci.c188
-rw-r--r--drivers/mmc/stm32_sdmmc2.c67
10 files changed, 384 insertions, 81 deletions
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index c34dd5d187..c23299ea96 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -78,6 +78,12 @@ config SUPPORT_EMMC_RPMB
Enable support for reading, writing and programming the
key for the Replay Protection Memory Block partition in eMMC.
+config SUPPORT_EMMC_BOOT
+ bool "Support some additional features of the eMMC boot partitions"
+ help
+ Enable support for eMMC boot partitions. This also enables
+ extensions within the mmc command.
+
config MMC_IO_VOLTAGE
bool "Support IO voltage configuration"
help
@@ -385,6 +391,20 @@ config MMC_SDHCI_SDMA
This enables support for the SDMA (Single Operation DMA) defined
in the SD Host Controller Standard Specification Version 1.00 .
+config MMC_SDHCI_ADMA
+ bool "Support SDHCI ADMA2"
+ depends on MMC_SDHCI
+ help
+ This enables support for the ADMA (Advanced DMA) defined
+ in the SD Host Controller Standard Specification Version 3.00
+
+config SPL_MMC_SDHCI_ADMA
+ bool "Support SDHCI ADMA2 in SPL"
+ depends on MMC_SDHCI
+ help
+ This enables support for the ADMA (Advanced DMA) defined
+ in the SD Host Controller Standard Specification Version 3.00 in SPL.
+
config MMC_SDHCI_ATMEL
bool "Atmel SDHCI controller support"
depends on ARCH_AT91
diff --git a/drivers/mmc/arm_pl180_mmci.c b/drivers/mmc/arm_pl180_mmci.c
index f71d79ecd6..ea8eb0d509 100644
--- a/drivers/mmc/arm_pl180_mmci.c
+++ b/drivers/mmc/arm_pl180_mmci.c
@@ -422,6 +422,7 @@ static int arm_pl180_mmc_probe(struct udevice *dev)
struct mmc_config *cfg = &pdata->cfg;
struct clk clk;
u32 bus_width;
+ u32 periphid;
int ret;
ret = clk_get_by_index(dev, 0, &clk);
@@ -439,7 +440,15 @@ static int arm_pl180_mmc_probe(struct udevice *dev)
host->clkdiv_init = SDI_CLKCR_CLKDIV_INIT_V1 | SDI_CLKCR_CLKEN |
SDI_CLKCR_HWFC_EN;
host->clock_in = clk_get_rate(&clk);
- host->version2 = dev_get_driver_data(dev);
+
+ periphid = dev_read_u32_default(dev, "arm,primecell-periphid", 0);
+ switch (periphid) {
+ case STM32_MMCI_ID: /* stm32 variant */
+ host->version2 = false;
+ break;
+ default:
+ host->version2 = true;
+ }
cfg->name = dev->name;
cfg->voltages = VOLTAGE_WINDOW_SD;
@@ -526,7 +535,8 @@ static int arm_pl180_mmc_ofdata_to_platdata(struct udevice *dev)
}
static const struct udevice_id arm_pl180_mmc_match[] = {
- { .compatible = "st,stm32f4xx-sdio", .data = VERSION1 },
+ { .compatible = "arm,pl180" },
+ { .compatible = "arm,primecell" },
{ /* sentinel */ }
};
diff --git a/drivers/mmc/arm_pl180_mmci.h b/drivers/mmc/arm_pl180_mmci.h
index 36487be288..61ee96a112 100644
--- a/drivers/mmc/arm_pl180_mmci.h
+++ b/drivers/mmc/arm_pl180_mmci.h
@@ -141,8 +141,7 @@
#define SDI_FIFO_BURST_SIZE 8
-#define VERSION1 false
-#define VERSION2 true
+#define STM32_MMCI_ID 0x00880180
struct sdi_registers {
u32 power; /* 0x00*/
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index 93a836eac3..1992d61182 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -74,15 +74,15 @@ static void dwmci_prepare_data(struct dwmci_host *host,
dwmci_set_idma_desc(cur_idmac, flags, cnt,
(ulong)bounce_buffer + (i * PAGE_SIZE));
+ cur_idmac++;
if (blk_cnt <= 8)
break;
blk_cnt -= 8;
- cur_idmac++;
i++;
} while(1);
data_end = (ulong)cur_idmac;
- flush_dcache_range(data_start, data_end + ARCH_DMA_MINALIGN);
+ flush_dcache_range(data_start, roundup(data_end, ARCH_DMA_MINALIGN));
ctrl = dwmci_readl(host, DWMCI_CTRL);
ctrl |= DWMCI_IDMAC_EN | DWMCI_DMA_EN;
@@ -114,22 +114,40 @@ static int dwmci_fifo_ready(struct dwmci_host *host, u32 bit, u32 *len)
return 0;
}
+static unsigned int dwmci_get_timeout(struct mmc *mmc, const unsigned int size)
+{
+ unsigned int timeout;
+
+ timeout = size * 8 * 1000; /* counting in bits and msec */
+ timeout *= 2; /* wait twice as long */
+ timeout /= mmc->clock;
+ timeout /= mmc->bus_width;
+ timeout /= mmc->ddr_mode ? 2 : 1;
+ timeout = (timeout < 1000) ? 1000 : timeout;
+
+ return timeout;
+}
+
static int dwmci_data_transfer(struct dwmci_host *host, struct mmc_data *data)
{
+ struct mmc *mmc = host->mmc;
int ret = 0;
- u32 timeout = 240000;
- u32 mask, size, i, len = 0;
+ u32 timeout, mask, size, i, len = 0;
u32 *buf = NULL;
ulong start = get_timer(0);
u32 fifo_depth = (((host->fifoth_val & RX_WMARK_MASK) >>
RX_WMARK_SHIFT) + 1) * 2;
- size = data->blocksize * data->blocks / 4;
+ size = data->blocksize * data->blocks;
if (data->flags == MMC_DATA_READ)
buf = (unsigned int *)data->dest;
else
buf = (unsigned int *)data->src;
+ timeout = dwmci_get_timeout(mmc, size);
+
+ size /= 4;
+
for (;;) {
mask = dwmci_readl(host, DWMCI_RINTSTS);
/* Error during data transfer. */
@@ -252,14 +270,20 @@ static int dwmci_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
dwmci_wait_reset(host, DWMCI_CTRL_FIFO_RESET);
} else {
if (data->flags == MMC_DATA_READ) {
- bounce_buffer_start(&bbstate, (void*)data->dest,
+ ret = bounce_buffer_start(&bbstate,
+ (void*)data->dest,
data->blocksize *
data->blocks, GEN_BB_WRITE);
} else {
- bounce_buffer_start(&bbstate, (void*)data->src,
+ ret = bounce_buffer_start(&bbstate,
+ (void*)data->src,
data->blocksize *
data->blocks, GEN_BB_READ);
}
+
+ if (ret)
+ return ret;
+
dwmci_prepare_data(host, data, cur_idmac,
bbstate.bounce_buffer);
}
diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c
index 9e34557d16..1b7de74a72 100644
--- a/drivers/mmc/fsl_esdhc.c
+++ b/drivers/mmc/fsl_esdhc.c
@@ -297,6 +297,13 @@ static int esdhc_setup_data(struct fsl_esdhc_priv *priv, struct mmc *mmc,
printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
return -ETIMEDOUT;
}
+ } else {
+#ifdef CONFIG_DM_GPIO
+ if (dm_gpio_is_valid(&priv->wp_gpio) && dm_gpio_get_value(&priv->wp_gpio)) {
+ printf("\nThe SD card is locked. Can not write to a locked card.\n\n");
+ return -ETIMEDOUT;
+ }
+#endif
}
esdhc_clrsetbits32(&regs->wml, WML_WR_WML_MASK,
@@ -614,18 +621,31 @@ static void set_sysctl(struct fsl_esdhc_priv *priv, struct mmc *mmc, uint clock)
#else
int pre_div = 2;
#endif
- int ddr_pre_div = mmc->ddr_mode ? 2 : 1;
int sdhc_clk = priv->sdhc_clk;
uint clk;
+ /*
+ * For ddr mode, usdhc need to enable DDR mode first, after select
+ * this DDR mode, usdhc will automatically divide the usdhc clock
+ */
+ if (mmc->ddr_mode) {
+ writel(readl(&regs->mixctrl) | MIX_CTRL_DDREN, &regs->mixctrl);
+ sdhc_clk >>= 1;
+ }
+
if (clock < mmc->cfg->f_min)
clock = mmc->cfg->f_min;
- while (sdhc_clk / (16 * pre_div * ddr_pre_div) > clock && pre_div < 256)
- pre_div *= 2;
+ if (sdhc_clk / 16 > clock) {
+ for (; pre_div < 256; pre_div *= 2)
+ if ((sdhc_clk / pre_div) <= (clock * 16))
+ break;
+ } else
+ pre_div = 1;
- while (sdhc_clk / (div * pre_div * ddr_pre_div) > clock && div < 16)
- div++;
+ for (div = 1; div <= 16; div++)
+ if ((sdhc_clk / (div * pre_div)) <= clock)
+ break;
pre_div >>= 1;
div -= 1;
@@ -1489,14 +1509,15 @@ static int fsl_esdhc_probe(struct udevice *dev)
#endif
}
- priv->wp_enable = 1;
-
+ if (dev_read_prop(dev, "fsl,wp-controller", NULL)) {
+ priv->wp_enable = 1;
+ } else {
+ priv->wp_enable = 0;
#ifdef CONFIG_DM_GPIO
- ret = gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
+ gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio,
GPIOD_IS_IN);
- if (ret)
- priv->wp_enable = 0;
#endif
+ }
priv->vs18_enable = 0;
diff --git a/drivers/mmc/mtk-sd.c b/drivers/mmc/mtk-sd.c
index d3f0778368..e0ac3e9d69 100644
--- a/drivers/mmc/mtk-sd.c
+++ b/drivers/mmc/mtk-sd.c
@@ -247,6 +247,7 @@ struct msdc_host {
struct msdc_compatible *dev_comp;
struct clk src_clk; /* for SD/MMC bus clock */
+ struct clk src_clk_cg; /* optional, MSDC source clock control gate */
struct clk h_clk; /* MSDC core clock */
u32 src_clk_freq; /* source clock */
@@ -269,7 +270,7 @@ struct msdc_host {
bool builtin_cd;
/* card detection / write protection GPIOs */
-#if IS_ENABLED(DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct gpio_desc gpio_wp;
struct gpio_desc gpio_cd;
#endif
@@ -849,7 +850,7 @@ static int msdc_ops_get_cd(struct udevice *dev)
return !(val & MSDC_PS_CDSTS);
}
-#if IS_ENABLED(DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
if (!host->gpio_cd.dev)
return 1;
@@ -861,7 +862,7 @@ static int msdc_ops_get_cd(struct udevice *dev)
static int msdc_ops_get_wp(struct udevice *dev)
{
-#if IS_ENABLED(DM_GPIO)
+#if CONFIG_IS_ENABLED(DM_GPIO)
struct msdc_host *host = dev_get_priv(dev);
if (!host->gpio_wp.dev)
@@ -1269,6 +1270,8 @@ static void msdc_ungate_clock(struct msdc_host *host)
{
clk_enable(&host->src_clk);
clk_enable(&host->h_clk);
+ if (host->src_clk_cg.dev)
+ clk_enable(&host->src_clk_cg);
}
static int msdc_drv_probe(struct udevice *dev)
@@ -1332,7 +1335,9 @@ static int msdc_ofdata_to_platdata(struct udevice *dev)
if (ret < 0)
return ret;
-#if IS_ENABLED(DM_GPIO)
+ clk_get_by_name(dev, "source_cg", &host->src_clk_cg); /* optional */
+
+#if CONFIG_IS_ENABLED(DM_GPIO)
gpio_request_by_name(dev, "wp-gpios", 0, &host->gpio_wp, GPIOD_IS_IN);
gpio_request_by_name(dev, "cd-gpios", 0, &host->gpio_cd, GPIOD_IS_IN);
#endif
@@ -1376,8 +1381,18 @@ static const struct msdc_compatible mt7623_compat = {
.enhance_rx = false
};
+static const struct msdc_compatible mt8516_compat = {
+ .clk_div_bits = 12,
+ .pad_tune0 = true,
+ .async_fifo = true,
+ .data_tune = true,
+ .busy_check = true,
+ .stop_clk_fix = true,
+};
+
static const struct udevice_id msdc_ids[] = {
{ .compatible = "mediatek,mt7623-mmc", .data = (ulong)&mt7623_compat },
+ { .compatible = "mediatek,mt8516-mmc", .data = (ulong)&mt8516_compat },
{}
};
diff --git a/drivers/mmc/mv_sdhci.c b/drivers/mmc/mv_sdhci.c
index de4ae0a0e7..bf26d2e4e2 100644
--- a/drivers/mmc/mv_sdhci.c
+++ b/drivers/mmc/mv_sdhci.c
@@ -4,10 +4,13 @@
*/
#include <common.h>
+#include <dm.h>
#include <malloc.h>
#include <sdhci.h>
#include <linux/mbus.h>
+#define MVSDH_NAME "mv_sdh"
+
#define SDHCI_WINDOW_CTRL(win) (0x4080 + ((win) << 4))
#define SDHCI_WINDOW_BASE(win) (0x4084 + ((win) << 4))
@@ -36,6 +39,8 @@ static void sdhci_mvebu_mbus_config(void __iomem *base)
}
}
+#ifndef CONFIG_DM_MMC
+
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
static struct sdhci_ops mv_ops;
@@ -63,7 +68,6 @@ static inline void mv_sdhci_writeb(struct sdhci_host *host, u8 val, int reg)
#endif /* CONFIG_SHEEVA_88SV331xV5 */
#endif /* CONFIG_MMC_SDHCI_IO_ACCESSORS */
-static char *MVSDH_NAME = "mv_sdh";
int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks)
{
struct sdhci_host *host = NULL;
@@ -90,3 +94,64 @@ int mv_sdh_init(unsigned long regbase, u32 max_clk, u32 min_clk, u32 quirks)
return add_sdhci(host, 0, min_clk);
}
+
+#else
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct mv_sdhci_plat {
+ struct mmc_config cfg;
+ struct mmc mmc;
+};
+
+static int mv_sdhci_probe(struct udevice *dev)
+{
+ struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+ struct mv_sdhci_plat *plat = dev_get_platdata(dev);
+ struct sdhci_host *host = dev_get_priv(dev);
+ int ret;
+
+ host->name = MVSDH_NAME;
+ host->ioaddr = (void *)devfdt_get_addr(dev);
+ host->quirks = SDHCI_QUIRK_32BIT_DMA_ADDR | SDHCI_QUIRK_WAIT_SEND_CMD;
+
+ ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
+ if (ret)
+ return ret;
+
+ if (CONFIG_IS_ENABLED(ARCH_MVEBU)) {
+ /* Configure SDHCI MBUS mbus bridge windows */
+ sdhci_mvebu_mbus_config(host->ioaddr);
+ }
+
+ host->mmc = &plat->mmc;
+ host->mmc->dev = dev;
+ host->mmc->priv = host;
+ upriv->mmc = host->mmc;
+
+ return sdhci_probe(dev);
+}
+
+static int mv_sdhci_bind(struct udevice *dev)
+{
+ struct mv_sdhci_plat *plat = dev_get_platdata(dev);
+
+ return sdhci_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static const struct udevice_id mv_sdhci_ids[] = {
+ { .compatible = "marvell,armada-380-sdhci" },
+ { }
+};
+
+U_BOOT_DRIVER(mv_sdhci_drv) = {
+ .name = MVSDH_NAME,
+ .id = UCLASS_MMC,
+ .of_match = mv_sdhci_ids,
+ .bind = mv_sdhci_bind,
+ .probe = mv_sdhci_probe,
+ .ops = &sdhci_ops,
+ .priv_auto_alloc_size = sizeof(struct sdhci_host),
+ .platdata_auto_alloc_size = sizeof(struct mv_sdhci_plat),
+};
+#endif /* CONFIG_DM_MMC */
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index bf2d83a52c..b2a1201631 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -13,8 +13,8 @@
#include <pwrseq.h>
#include <syscon.h>
#include <asm/gpio.h>
-#include <asm/arch/clock.h>
-#include <asm/arch/periph.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/periph.h>
#include <linux/err.h>
struct rockchip_mmc_plat {
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index cdeba914f9..e2bb90abbd 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -67,17 +67,123 @@ static void sdhci_transfer_pio(struct sdhci_host *host, struct mmc_data *data)
}
}
-static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
- unsigned int start_addr)
+#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
+static void sdhci_adma_desc(struct sdhci_host *host, char *buf, u16 len,
+ bool end)
+{
+ struct sdhci_adma_desc *desc;
+ u8 attr;
+
+ desc = &host->adma_desc_table[host->desc_slot];
+
+ attr = ADMA_DESC_ATTR_VALID | ADMA_DESC_TRANSFER_DATA;
+ if (!end)
+ host->desc_slot++;
+ else
+ attr |= ADMA_DESC_ATTR_END;
+
+ desc->attr = attr;
+ desc->len = len;
+ desc->reserved = 0;
+ desc->addr_lo = (dma_addr_t)buf;
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+ desc->addr_hi = (u64)buf >> 32;
+#endif
+}
+
+static void sdhci_prepare_adma_table(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ uint trans_bytes = data->blocksize * data->blocks;
+ uint desc_count = DIV_ROUND_UP(trans_bytes, ADMA_MAX_LEN);
+ int i = desc_count;
+ char *buf;
+
+ host->desc_slot = 0;
+
+ if (data->flags & MMC_DATA_READ)
+ buf = data->dest;
+ else
+ buf = (char *)data->src;
+
+ while (--i) {
+ sdhci_adma_desc(host, buf, ADMA_MAX_LEN, false);
+ buf += ADMA_MAX_LEN;
+ trans_bytes -= ADMA_MAX_LEN;
+ }
+
+ sdhci_adma_desc(host, buf, trans_bytes, true);
+
+ flush_cache((dma_addr_t)host->adma_desc_table,
+ ROUND(desc_count * sizeof(struct sdhci_adma_desc),
+ ARCH_DMA_MINALIGN));
+}
+#elif defined(CONFIG_MMC_SDHCI_SDMA)
+static void sdhci_prepare_adma_table(struct sdhci_host *host,
+ struct mmc_data *data)
+{}
+#endif
+#if (defined(CONFIG_MMC_SDHCI_SDMA) || CONFIG_IS_ENABLED(MMC_SDHCI_ADMA))
+static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
+ int *is_aligned, int trans_bytes)
{
- unsigned int stat, rdy, mask, timeout, block = 0;
- bool transfer_done = false;
-#ifdef CONFIG_MMC_SDHCI_SDMA
unsigned char ctrl;
+
+ if (data->flags == MMC_DATA_READ)
+ host->start_addr = (dma_addr_t)data->dest;
+ else
+ host->start_addr = (dma_addr_t)data->src;
+
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
+ if (host->flags & USE_ADMA64)
+ ctrl |= SDHCI_CTRL_ADMA64;
+ else if (host->flags & USE_ADMA)
+ ctrl |= SDHCI_CTRL_ADMA32;
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+
+ if (host->flags & USE_SDMA) {
+ if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
+ (host->start_addr & 0x7) != 0x0) {
+ *is_aligned = 0;
+ host->start_addr = (unsigned long)aligned_buffer;
+ if (data->flags != MMC_DATA_READ)
+ memcpy(aligned_buffer, data->src, trans_bytes);
+ }
+
+#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
+ /*
+ * Always use this bounce-buffer when
+ * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
+ */
+ *is_aligned = 0;
+ host->start_addr = (unsigned long)aligned_buffer;
+ if (data->flags != MMC_DATA_READ)
+ memcpy(aligned_buffer, data->src, trans_bytes);
+#endif
+ sdhci_writel(host, host->start_addr, SDHCI_DMA_ADDRESS);
+
+ } else if (host->flags & (USE_ADMA | USE_ADMA64)) {
+ sdhci_prepare_adma_table(host, data);
+
+ sdhci_writel(host, (u32)host->adma_addr, SDHCI_ADMA_ADDRESS);
+ if (host->flags & USE_ADMA64)
+ sdhci_writel(host, (u64)host->adma_addr >> 32,
+ SDHCI_ADMA_ADDRESS_HI);
+ }
+
+ flush_cache(host->start_addr, ROUND(trans_bytes, ARCH_DMA_MINALIGN));
+}
+#else
+static void sdhci_prepare_dma(struct sdhci_host *host, struct mmc_data *data,
+ int *is_aligned, int trans_bytes)
+{}
#endif
+static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data)
+{
+ dma_addr_t start_addr = host->start_addr;
+ unsigned int stat, rdy, mask, timeout, block = 0;
+ bool transfer_done = false;
timeout = 1000000;
rdy = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL;
@@ -104,14 +210,17 @@ static int sdhci_transfer_data(struct sdhci_host *host, struct mmc_data *data,
continue;
}
}
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (!transfer_done && (stat & SDHCI_INT_DMA_END)) {
+ if ((host->flags & USE_DMA) && !transfer_done &&
+ (stat & SDHCI_INT_DMA_END)) {
sdhci_writel(host, SDHCI_INT_DMA_END, SDHCI_INT_STATUS);
- start_addr &= ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
- start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
- sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
+ if (host->flags & USE_SDMA) {
+ start_addr &=
+ ~(SDHCI_DEFAULT_BOUNDARY_SIZE - 1);
+ start_addr += SDHCI_DEFAULT_BOUNDARY_SIZE;
+ sdhci_writel(host, start_addr,
+ SDHCI_DMA_ADDRESS);
+ }
}
-#endif
if (timeout-- > 0)
udelay(10);
else {
@@ -149,10 +258,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
int ret = 0;
int trans_bytes = 0, is_aligned = 1;
u32 mask, flags, mode;
- unsigned int time = 0, start_addr = 0;
+ unsigned int time = 0;
int mmc_dev = mmc_get_blk_desc(mmc)->devnum;
ulong start = get_timer(0);
+ host->start_addr = 0;
/* Timeout unit - ms */
static unsigned int cmd_timeout = SDHCI_CMD_DEFAULT_TIMEOUT;
@@ -218,33 +328,11 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
if (data->flags == MMC_DATA_READ)
mode |= SDHCI_TRNS_READ;
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (data->flags == MMC_DATA_READ)
- start_addr = (unsigned long)data->dest;
- else
- start_addr = (unsigned long)data->src;
- if ((host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
- (start_addr & 0x7) != 0x0) {
- is_aligned = 0;
- start_addr = (unsigned long)aligned_buffer;
- if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
+ if (host->flags & USE_DMA) {
+ mode |= SDHCI_TRNS_DMA;
+ sdhci_prepare_dma(host, data, &is_aligned, trans_bytes);
}
-#if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER)
- /*
- * Always use this bounce-buffer when
- * CONFIG_FIXED_SDHCI_ALIGNED_BUFFER is defined
- */
- is_aligned = 0;
- start_addr = (unsigned long)aligned_buffer;
- if (data->flags != MMC_DATA_READ)
- memcpy(aligned_buffer, data->src, trans_bytes);
-#endif
-
- sdhci_writel(host, start_addr, SDHCI_DMA_ADDRESS);
- mode |= SDHCI_TRNS_DMA;
-#endif
sdhci_writew(host, SDHCI_MAKE_BLKSZ(SDHCI_DEFAULT_BOUNDARY_ARG,
data->blocksize),
SDHCI_BLOCK_SIZE);
@@ -255,12 +343,6 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
}
sdhci_writel(host, cmd->cmdarg, SDHCI_ARGUMENT);
-#ifdef CONFIG_MMC_SDHCI_SDMA
- if (data) {
- trans_bytes = ALIGN(trans_bytes, CONFIG_SYS_CACHELINE_SIZE);
- flush_cache(start_addr, trans_bytes);
- }
-#endif
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->cmdidx, flags), SDHCI_COMMAND);
start = get_timer(0);
do {
@@ -286,7 +368,7 @@ static int sdhci_send_command(struct mmc *mmc, struct mmc_cmd *cmd,
ret = -1;
if (!ret && data)
- ret = sdhci_transfer_data(host, data, start_addr);
+ ret = sdhci_transfer_data(host, data);
if (host->quirks & SDHCI_QUIRK_WAIT_SEND_CMD)
udelay(1000);
@@ -570,6 +652,24 @@ int sdhci_setup_cfg(struct mmc_config *cfg, struct sdhci_host *host,
__func__);
return -EINVAL;
}
+
+ host->flags |= USE_SDMA;
+#endif
+#if CONFIG_IS_ENABLED(MMC_SDHCI_ADMA)
+ if (!(caps & SDHCI_CAN_DO_ADMA2)) {
+ printf("%s: Your controller doesn't support SDMA!!\n",
+ __func__);
+ return -EINVAL;
+ }
+ host->adma_desc_table = (struct sdhci_adma_desc *)
+ memalign(ARCH_DMA_MINALIGN, ADMA_TABLE_SZ);
+
+ host->adma_addr = (dma_addr_t)host->adma_desc_table;
+#ifdef CONFIG_DMA_ADDR_T_64BIT
+ host->flags |= USE_ADMA64;
+#else
+ host->flags |= USE_ADMA;
+#endif
#endif
if (host->quirks & SDHCI_QUIRK_REG32_RW)
host->version =
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index a36612dd93..ed31ca126e 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -190,6 +190,7 @@ struct stm32_sdmmc2_ctx {
#define SDMMC_IDMACTRL_IDMAEN BIT(0)
#define SDMMC_CMD_TIMEOUT 0xFFFFFFFF
+#define SDMMC_BUSYD0END_TIMEOUT_US 1000000
static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv,
struct mmc_data *data,
@@ -209,9 +210,6 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv,
idmabase0 = (u32)data->src;
}
- /* Set the SDMMC Data TimeOut value */
- writel(SDMMC_CMD_TIMEOUT, priv->base + SDMMC_DTIMER);
-
/* Set the SDMMC DataLength value */
writel(ctx->data_length, priv->base + SDMMC_DLEN);
@@ -236,8 +234,11 @@ static void stm32_sdmmc2_start_data(struct stm32_sdmmc2_priv *priv,
}
static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv,
- struct mmc_cmd *cmd, u32 cmd_param)
+ struct mmc_cmd *cmd, u32 cmd_param,
+ struct stm32_sdmmc2_ctx *ctx)
{
+ u32 timeout = 0;
+
if (readl(priv->base + SDMMC_CMD) & SDMMC_CMD_CPSMEN)
writel(0, priv->base + SDMMC_CMD);
@@ -251,6 +252,26 @@ static void stm32_sdmmc2_start_cmd(struct stm32_sdmmc2_priv *priv,
cmd_param |= SDMMC_CMD_WAITRESP_1;
}
+ /*
+ * SDMMC_DTIME must be set in two case:
+ * - on data transfert.
+ * - on busy request.
+ * If not done or too short, the dtimeout flag occurs and DPSM stays
+ * enabled/busy and waits for abort (stop transmission cmd).
+ * Next data command is not possible whereas DPSM is activated.
+ */
+ if (ctx->data_length) {
+ timeout = SDMMC_CMD_TIMEOUT;
+ } else {
+ writel(0, priv->base + SDMMC_DCTRL);
+
+ if (cmd->resp_type & MMC_RSP_BUSY)
+ timeout = SDMMC_CMD_TIMEOUT;
+ }
+
+ /* Set the SDMMC Data TimeOut value */
+ writel(timeout, priv->base + SDMMC_DTIMER);
+
/* Clear flags */
writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR);
@@ -309,6 +330,31 @@ static int stm32_sdmmc2_end_cmd(struct stm32_sdmmc2_priv *priv,
cmd->response[2] = readl(priv->base + SDMMC_RESP3);
cmd->response[3] = readl(priv->base + SDMMC_RESP4);
}
+
+ /* Wait for BUSYD0END flag if busy status is detected */
+ if (cmd->resp_type & MMC_RSP_BUSY &&
+ status & SDMMC_STA_BUSYD0) {
+ mask = SDMMC_STA_DTIMEOUT | SDMMC_STA_BUSYD0END;
+
+ /* Polling status register */
+ ret = readl_poll_timeout(priv->base + SDMMC_STA,
+ status, status & mask,
+ SDMMC_BUSYD0END_TIMEOUT_US);
+
+ if (ret < 0) {
+ debug("%s: timeout reading SDMMC_STA\n",
+ __func__);
+ ctx->dpsm_abort = true;
+ return ret;
+ }
+
+ if (status & SDMMC_STA_DTIMEOUT) {
+ debug("%s: error SDMMC_STA_DTIMEOUT (0x%x)\n",
+ __func__, status);
+ ctx->dpsm_abort = true;
+ return -ETIMEDOUT;
+ }
+ }
}
return 0;
@@ -395,7 +441,7 @@ retry_cmd:
stm32_sdmmc2_start_data(priv, data, &ctx);
}
- stm32_sdmmc2_start_cmd(priv, cmd, cmdat);
+ stm32_sdmmc2_start_cmd(priv, cmd, cmdat, &ctx);
debug("%s: send cmd %d data: 0x%x @ 0x%x\n",
__func__, cmd->cmdidx,
@@ -425,7 +471,10 @@ retry_cmd:
debug("%s: send STOP command to abort dpsm treatments\n",
__func__);
- stm32_sdmmc2_start_cmd(priv, &stop_cmd, SDMMC_CMD_CMDSTOP);
+ ctx.data_length = 0;
+
+ stm32_sdmmc2_start_cmd(priv, &stop_cmd,
+ SDMMC_CMD_CMDSTOP, &ctx);
stm32_sdmmc2_end_cmd(priv, &stop_cmd, &ctx);
writel(SDMMC_ICR_STATIC_FLAGS, priv->base + SDMMC_ICR);
@@ -585,11 +634,11 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
if (priv->base == FDT_ADDR_T_NONE)
return -EINVAL;
- if (dev_read_bool(dev, "st,negedge"))
+ if (dev_read_bool(dev, "st,neg-edge"))
priv->clk_reg_msk |= SDMMC_CLKCR_NEGEDGE;
- if (dev_read_bool(dev, "st,dirpol"))
+ if (dev_read_bool(dev, "st,sig-dir"))
priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL;
- if (dev_read_bool(dev, "st,pin-ckin"))
+ if (dev_read_bool(dev, "st,use-ckin"))
priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
ret = clk_get_by_index(dev, 0, &priv->clk);