diff options
| author | Pavan Anamula <pavana@codeaurora.org> | 2015-07-22 21:46:32 +0530 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:27:15 -0700 |
| commit | 3c9889c0fb7a71610573846c7204a135158b5eca (patch) | |
| tree | 3bd62376a23e07d2ee8bfee35f383313df2afab1 /drivers/mmc | |
| parent | 9bc36b07a2c375ad4fac740f273cf2b83b5cd4e8 (diff) | |
mmc: sdhci-msm: Fix HW issue with power IRQ handling during reset
There is a rare scenario in HW, where the first clear pulse could
be lost when the actual reset and clear/read of status register
are happening at the same time. Fix this by retrying upto 10 times
to ensure the status register gets cleared. Otherwise, this will
lead to a spurious power IRQ which results in system instability.
Change-Id: I1c4f27e131992ef036ebe64fbb2c52613ba396cc
Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Signed-off-by: Pavan Anamula <pavana@codeaurora.org>
Diffstat (limited to 'drivers/mmc')
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index d35cc16436ba..f5d59124b222 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2088,6 +2088,18 @@ static int sdhci_msm_set_vdd_io_vol(struct sdhci_msm_pltfm_data *pdata, return ret; } +void sdhci_msm_dump_pwr_ctrl_regs(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + + pr_err("%s: PWRCTL_STATUS: 0x%08x | PWRCTL_MASK: 0x%08x | PWRCTL_CTL: 0x%08x\n", + mmc_hostname(host->mmc), + readl_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS), + readl_relaxed(msm_host->core_mem + CORE_PWRCTL_MASK), + readl_relaxed(msm_host->core_mem + CORE_PWRCTL_CTL)); +} + static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) { struct sdhci_host *host = (struct sdhci_host *)data; @@ -2098,6 +2110,7 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) int ret = 0; int pwr_state = 0, io_level = 0; unsigned long flags; + int retry = 10; irq_status = readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS); pr_debug("%s: Received IRQ(%d), status=0x%x\n", @@ -2112,6 +2125,29 @@ static irqreturn_t sdhci_msm_pwr_irq(int irq, void *data) * completed before its next update to registers within hc_mem. */ mb(); + /* + * There is a rare HW scenario where the first clear pulse could be + * lost when actual reset and clear/read of status register is + * happening at a time. Hence, retry for at least 10 times to make + * sure status register is cleared. Otherwise, this will result in + * a spurious power IRQ resulting in system instability. + */ + while (irq_status & + readb_relaxed(msm_host->core_mem + CORE_PWRCTL_STATUS)) { + if (retry == 0) { + pr_err("%s: Timedout clearing (0x%x) pwrctl status register\n", + mmc_hostname(host->mmc), irq_status); + sdhci_msm_dump_pwr_ctrl_regs(host); + BUG_ON(1); + } + writeb_relaxed(irq_status, + (msm_host->core_mem + CORE_PWRCTL_CLEAR)); + retry--; + udelay(10); + } + if (likely(retry < 10)) + pr_debug("%s: success clearing (0x%x) pwrctl status register, retries left %d\n", + mmc_hostname(host->mmc), irq_status, retry); /* Handle BUS ON/OFF*/ if (irq_status & CORE_PWRCTL_BUS_ON) { |
