diff options
author | Haibo Chen <haibo.chen@nxp.com> | 2016-02-01 18:15:27 +0800 |
---|---|---|
committer | Leonard Crestez <leonard.crestez@nxp.com> | 2018-08-24 12:41:33 +0300 |
commit | 291538d2c44317d4c96fbead786a28325285542f (patch) | |
tree | f92d6a480573c0877e6d0d042bd7c2c3637010e5 /drivers/mmc/host/sdhci-esdhc-imx.c | |
parent | c2a207d63ecf6acd8a20ed941110771c67c15958 (diff) |
MLK-12345 mmc: sdhci-esdhc-imx: reset tuning circurt when insert sd card
Current driver do not clear the tuning related register setting,
this will impact the timing and let the card inserted later meet
CRC error.
Take the DDR50 card as example, if plug out an SDR104 card and
then plug in this DDR50 card, we will meet the following error log:
mmc2: new ultra high speed DDR50 SDHC card at address aaaa
mmcblk2: mmc2:aaaa SE08G 7.40 GiB
mmcblk2: error -84 transferring data, sector 0, nr 8, cmd response 0x900, card status 0xb00
mmc2: tried to reset card
mmcblk2: p1 p2
Logictally, we should reset the tuning circurt everytime when we
plug in a sd card.
Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Diffstat (limited to 'drivers/mmc/host/sdhci-esdhc-imx.c')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 28 |
1 files changed, 27 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index fcab1bc4e8e9..9ad633bf1de3 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -968,6 +968,30 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask) sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); } +static void esdhc_hw_reset(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host); + u16 ctrl; + + sdhci_reset(host, SDHCI_RESET_ALL); + + /* Rest the tuning circurt */ + if (esdhc_is_usdhc(imx_data)) { + if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { + ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL); + ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + ctrl &= ~ESDHC_MIX_CTRL_FBCLK_SEL; + writel(ctrl, host->ioaddr + ESDHC_MIX_CTRL); + writel(0 << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS); + } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { + ctrl = readl(host->ioaddr + SDHCI_ACMD12_ERR); + ctrl &= ~ESDHC_MIX_CTRL_SMPCLK_SEL; + writel(ctrl, host->ioaddr + SDHCI_ACMD12_ERR); + } + } +} + static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -1004,6 +1028,7 @@ static struct sdhci_ops sdhci_esdhc_ops = { .set_bus_width = esdhc_pltfm_set_bus_width, .set_uhs_signaling = esdhc_set_uhs_signaling, .reset = esdhc_reset, + .hw_reset = esdhc_hw_reset, }; static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { @@ -1279,7 +1304,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (esdhc_is_usdhc(imx_data)) { host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; - host->mmc->caps |= MMC_CAP_1_8V_DDR; + host->mmc->caps |= MMC_CAP_1_8V_DDR | MMC_CAP_HW_RESET; + if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; |