summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-04-24 12:26:39 -0400
committerTom Rini <trini@konsulko.com>2019-04-24 12:26:39 -0400
commitc2bb9c5b9e333c200e3702d9ed5ac9b6095191b6 (patch)
treef3a017fe861211d45c8965aeac2f488f06c989d5 /drivers/mmc
parentceb6ddbc73607e9395bb5f0ad94159755f049e77 (diff)
parentc406a474311c1ee3c4303a7e85db4a8e45966e31 (diff)
Merge tag 'u-boot-stm32-mcu-20190423' of https://github.com/pchotard/u-boot
STM32 MCUs update: - DT rework and alignment with DT kernel v4.20 - mmc: arm_pl180_mmci: Synchronize compatible with kernel v4.20 - mmc: stm32_sdmmc2: Synchronize properties with kernel v4.20 - configs: update for F746/769 boards
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/arm_pl180_mmci.c14
-rw-r--r--drivers/mmc/arm_pl180_mmci.h3
-rw-r--r--drivers/mmc/stm32_sdmmc2.c67
3 files changed, 71 insertions, 13 deletions
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/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);