diff options
author | Tom Rini <trini@konsulko.com> | 2019-04-24 12:26:39 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2019-04-24 12:26:39 -0400 |
commit | c2bb9c5b9e333c200e3702d9ed5ac9b6095191b6 (patch) | |
tree | f3a017fe861211d45c8965aeac2f488f06c989d5 /drivers/mmc/stm32_sdmmc2.c | |
parent | ceb6ddbc73607e9395bb5f0ad94159755f049e77 (diff) | |
parent | c406a474311c1ee3c4303a7e85db4a8e45966e31 (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/stm32_sdmmc2.c')
-rw-r--r-- | drivers/mmc/stm32_sdmmc2.c | 67 |
1 files changed, 58 insertions, 9 deletions
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); |