diff mbox series

[06/14] mmc: sdhci-esdhci-imx: retune needed for Mega/Mix enabled SoCs

Message ID 1573816361-26535-3-git-send-email-haibo.chen@nxp.com (mailing list archive)
State New, archived
Headers show
Series [01/14] mmc: sdhci: do not enable card detect interrupt for gpio cd type | expand

Commit Message

Bough Chen Nov. 15, 2019, 11:12 a.m. UTC
From: Haibo Chen <haibo.chen@nxp.com>

For Mega/Mix enabled SoCs like MX7D and MX6SX, uSDHC will lost power in
LP mode no matter whether the MMC_KEEP_POWER flag is set or not.
This may cause state misalign between kernel and HW, especially for
SDIO3.0 WiFi cards.
e.g. SDIO WiFi driver usually will keep power during system suspend.
And after resume, no card re-enumeration called.
But the tuning state is lost due to Mega/Mix.
Then CRC error may happen during next data transfer.

So we should always fire a mmc_retune_needed() for such type SoC
to tell MMC core retuning is needed for next data transfer.
mmc: sdhci-esdhci-imx: retune needed for Mega/Mix enabled SoCs

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
---
 drivers/mmc/host/sdhci-esdhc-imx.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

Comments

Adrian Hunter Nov. 26, 2019, 12:53 p.m. UTC | #1
On 15/11/19 1:12 PM, haibo.chen@nxp.com wrote:
> From: Haibo Chen <haibo.chen@nxp.com>
> 
> For Mega/Mix enabled SoCs like MX7D and MX6SX, uSDHC will lost power in
> LP mode no matter whether the MMC_KEEP_POWER flag is set or not.
> This may cause state misalign between kernel and HW, especially for
> SDIO3.0 WiFi cards.
> e.g. SDIO WiFi driver usually will keep power during system suspend.
> And after resume, no card re-enumeration called.
> But the tuning state is lost due to Mega/Mix.
> Then CRC error may happen during next data transfer.
> 
> So we should always fire a mmc_retune_needed() for such type SoC
> to tell MMC core retuning is needed for next data transfer.
> mmc: sdhci-esdhci-imx: retune needed for Mega/Mix enabled SoCs
> 
> Signed-off-by: Haibo Chen <haibo.chen@nxp.com>

Acked-by: Adrian Hunter <adrian.hunter@intel.com>

> ---
>  drivers/mmc/host/sdhci-esdhc-imx.c | 25 ++++++++++++++++++++-----
>  1 file changed, 20 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
> index bc743f82d8c3..2c8a78218c8e 100644
> --- a/drivers/mmc/host/sdhci-esdhc-imx.c
> +++ b/drivers/mmc/host/sdhci-esdhc-imx.c
> @@ -160,6 +160,8 @@
>  #define ESDHC_FLAG_CQHCI		BIT(12)
>  /* need request pmqos during low power */
>  #define ESDHC_FLAG_PMQOS		BIT(13)
> +/* The IP state got lost in low power mode */
> +#define ESDHC_FLAG_STATE_LOST_IN_LPMODE		BIT(14)
>  
>  struct esdhc_soc_data {
>  	u32 flags;
> @@ -193,32 +195,37 @@ static const struct esdhc_soc_data usdhc_imx6sl_data = {
>  
>  static const struct esdhc_soc_data usdhc_imx6sx_data = {
>  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
> -			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
> +			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
> +			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
>  };
>  
>  static const struct esdhc_soc_data usdhc_imx6ull_data = {
>  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
>  			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
> -			| ESDHC_FLAG_ERR010450,
> +			| ESDHC_FLAG_ERR010450
> +			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
>  };
>  
>  static const struct esdhc_soc_data usdhc_imx7d_data = {
>  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
>  			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
> -			| ESDHC_FLAG_HS400,
> +			| ESDHC_FLAG_HS400
> +			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
>  };
>  
>  static struct esdhc_soc_data usdhc_imx7ulp_data = {
>  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
>  			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
> -			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400,
> +			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
> +			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
>  };
>  
>  static struct esdhc_soc_data usdhc_imx8qxp_data = {
>  	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
>  			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
>  			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
> -			| ESDHC_FLAG_CQHCI,
> +			| ESDHC_FLAG_CQHCI
> +			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
>  };
>  
>  struct pltfm_imx_data {
> @@ -1613,6 +1620,8 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
>  static int sdhci_esdhc_suspend(struct device *dev)
>  {
>  	struct sdhci_host *host = dev_get_drvdata(dev);
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
>  	int ret;
>  
>  	if (host->mmc->caps2 & MMC_CAP2_CQE) {
> @@ -1621,6 +1630,12 @@ static int sdhci_esdhc_suspend(struct device *dev)
>  			return ret;
>  	}
>  
> +	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
> +		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
> +		mmc_retune_timer_stop(host->mmc);
> +		mmc_retune_needed(host->mmc);
> +	}
> +
>  	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
>  		mmc_retune_needed(host->mmc);
>  
>
diff mbox series

Patch

diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index bc743f82d8c3..2c8a78218c8e 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -160,6 +160,8 @@ 
 #define ESDHC_FLAG_CQHCI		BIT(12)
 /* need request pmqos during low power */
 #define ESDHC_FLAG_PMQOS		BIT(13)
+/* The IP state got lost in low power mode */
+#define ESDHC_FLAG_STATE_LOST_IN_LPMODE		BIT(14)
 
 struct esdhc_soc_data {
 	u32 flags;
@@ -193,32 +195,37 @@  static const struct esdhc_soc_data usdhc_imx6sl_data = {
 
 static const struct esdhc_soc_data usdhc_imx6sx_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
-			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200,
+			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static const struct esdhc_soc_data usdhc_imx6ull_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_ERR010450,
+			| ESDHC_FLAG_ERR010450
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static const struct esdhc_soc_data usdhc_imx7d_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_HS400,
+			| ESDHC_FLAG_HS400
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static struct esdhc_soc_data usdhc_imx7ulp_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
-			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400,
+			| ESDHC_FLAG_PMQOS | ESDHC_FLAG_HS400
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 static struct esdhc_soc_data usdhc_imx8qxp_data = {
 	.flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING
 			| ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200
 			| ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES
-			| ESDHC_FLAG_CQHCI,
+			| ESDHC_FLAG_CQHCI
+			| ESDHC_FLAG_STATE_LOST_IN_LPMODE,
 };
 
 struct pltfm_imx_data {
@@ -1613,6 +1620,8 @@  static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
 static int sdhci_esdhc_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
 	int ret;
 
 	if (host->mmc->caps2 & MMC_CAP2_CQE) {
@@ -1621,6 +1630,12 @@  static int sdhci_esdhc_suspend(struct device *dev)
 			return ret;
 	}
 
+	if ((imx_data->socdata->flags & ESDHC_FLAG_STATE_LOST_IN_LPMODE) &&
+		(host->tuning_mode != SDHCI_TUNING_MODE_1)) {
+		mmc_retune_timer_stop(host->mmc);
+		mmc_retune_needed(host->mmc);
+	}
+
 	if (host->tuning_mode != SDHCI_TUNING_MODE_3)
 		mmc_retune_needed(host->mmc);