diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mmc/stm32_sdmmc2.c | 61 | 
1 files changed, 55 insertions, 6 deletions
| diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index bab7efe754a..ed31ca126e9 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); | 
