mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 20:33:58 -04:00
mmc: sdhci-msm: Add support for gcc hw reset for sdcc
Add support for gcc hw reset for sdcc. This feature would help recover emmc host controller and card cleanly in case software recovery fails. This would also help reset hwkm key during probe for crypto when called during probe. Change-Id: I32c7fbfb1a97bb69924e1a0c6ea90a400dd35c43 Signed-off-by: Ram Prakash Gupta <rampraka@codeaurora.org>
This commit is contained in:
parent
37cdb7af00
commit
e2a34cfbfb
1 changed files with 88 additions and 5 deletions
|
|
@ -19,9 +19,13 @@
|
|||
#include <linux/cpumask.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
#include "cqhci.h"
|
||||
#if defined(CONFIG_SDC_QTI)
|
||||
#include "../core/core.h"
|
||||
#endif
|
||||
|
||||
#define CORE_MCI_VERSION 0x50
|
||||
#define CORE_VERSION_MAJOR_SHIFT 28
|
||||
|
|
@ -451,6 +455,8 @@ struct sdhci_msm_host {
|
|||
u32 clk_gating_delay;
|
||||
u32 pm_qos_delay;
|
||||
bool cqhci_offset_changed;
|
||||
bool reg_store;
|
||||
struct reset_control *core_reset;
|
||||
};
|
||||
|
||||
static struct sdhci_msm_host *sdhci_slot[2];
|
||||
|
|
@ -1708,6 +1714,23 @@ skip_hsr:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int sdhci_msm_parse_reset_data(struct device *dev,
|
||||
struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
msm_host->core_reset = devm_reset_control_get(dev,
|
||||
"core_reset");
|
||||
if (IS_ERR(msm_host->core_reset)) {
|
||||
ret = PTR_ERR(msm_host->core_reset);
|
||||
dev_err(dev, "core_reset unavailable,err = %d\n",
|
||||
ret);
|
||||
msm_host->core_reset = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Parse platform data */
|
||||
static bool sdhci_msm_populate_pdata(struct device *dev,
|
||||
struct sdhci_msm_host *msm_host)
|
||||
|
|
@ -1761,6 +1784,8 @@ static bool sdhci_msm_populate_pdata(struct device *dev,
|
|||
}
|
||||
}
|
||||
|
||||
sdhci_msm_parse_reset_data(dev, msm_host);
|
||||
|
||||
return false;
|
||||
out:
|
||||
return true;
|
||||
|
|
@ -2428,7 +2453,8 @@ static void sdhci_msm_registers_save(struct sdhci_host *host)
|
|||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
const struct sdhci_msm_offset *msm_offset = msm_host->offset;
|
||||
|
||||
if (!msm_host->regs_restore.is_supported)
|
||||
if (!msm_host->regs_restore.is_supported &&
|
||||
!msm_host->reg_store)
|
||||
return;
|
||||
|
||||
msm_host->regs_restore.vendor_func = readl_relaxed(host->ioaddr +
|
||||
|
|
@ -2491,8 +2517,9 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host)
|
|||
u32 irq_status;
|
||||
struct mmc_ios ios = host->mmc->ios;
|
||||
|
||||
if (!msm_host->regs_restore.is_supported ||
|
||||
!msm_host->regs_restore.is_valid)
|
||||
if ((!msm_host->regs_restore.is_supported ||
|
||||
!msm_host->regs_restore.is_valid) &&
|
||||
!msm_host->reg_store)
|
||||
return;
|
||||
|
||||
writel_relaxed(0, host->ioaddr + msm_offset->core_pwrctl_mask);
|
||||
|
|
@ -3266,6 +3293,56 @@ static const struct of_device_id sdhci_msm_dt_match[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
|
||||
|
||||
static void sdhci_msm_hw_reset(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
||||
struct platform_device *pdev = msm_host->pdev;
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
if (!msm_host->core_reset) {
|
||||
dev_err(&pdev->dev, "%s: failed, err = %d\n", __func__,
|
||||
ret);
|
||||
return;
|
||||
}
|
||||
|
||||
msm_host->reg_store = true;
|
||||
sdhci_msm_registers_save(host);
|
||||
if (host->mmc->caps2 & MMC_CAP2_CQE) {
|
||||
host->mmc->cqe_ops->cqe_disable(host->mmc);
|
||||
host->mmc->cqe_enabled = false;
|
||||
}
|
||||
|
||||
ret = reset_control_assert(msm_host->core_reset);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: core_reset assert failed, err = %d\n",
|
||||
__func__, ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hardware requirement for delay between assert/deassert
|
||||
* is at least 3-4 sleep clock (32.7KHz) cycles, which comes to
|
||||
* ~125us (4/32768). To be on the safe side add 200us delay.
|
||||
*/
|
||||
usleep_range(200, 210);
|
||||
|
||||
ret = reset_control_deassert(msm_host->core_reset);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "%s: core_reset deassert failed, err = %d\n",
|
||||
__func__, ret);
|
||||
|
||||
sdhci_msm_registers_restore(host);
|
||||
msm_host->reg_store = false;
|
||||
|
||||
#if defined(CONFIG_SDC_QTI)
|
||||
if (host->mmc->card)
|
||||
mmc_power_cycle(host->mmc, host->mmc->card->ocr);
|
||||
#endif
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
static const struct sdhci_ops sdhci_msm_ops = {
|
||||
.reset = sdhci_msm_reset,
|
||||
.set_clock = sdhci_msm_set_clock,
|
||||
|
|
@ -3284,6 +3361,7 @@ static const struct sdhci_ops sdhci_msm_ops = {
|
|||
#if defined(CONFIG_SDC_QTI)
|
||||
.get_current_limit = sdhci_msm_get_current_limit,
|
||||
#endif
|
||||
.hw_reset = sdhci_msm_hw_reset,
|
||||
};
|
||||
|
||||
static const struct sdhci_pltfm_data sdhci_msm_pdata = {
|
||||
|
|
@ -3918,6 +3996,12 @@ static int sdhci_msm_init_sysfs(struct platform_device *pdev)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void sdhci_msm_set_caps(struct sdhci_msm_host *msm_host)
|
||||
{
|
||||
msm_host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM | MMC_CAP_SYNC_RUNTIME_PM;
|
||||
msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
|
||||
}
|
||||
|
||||
static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sdhci_host *host;
|
||||
|
|
@ -4168,8 +4252,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|||
goto vreg_deinit;
|
||||
}
|
||||
|
||||
msm_host->mmc->caps |= MMC_CAP_AGGRESSIVE_PM | MMC_CAP_SYNC_RUNTIME_PM;
|
||||
msm_host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_NEED_RSP_BUSY;
|
||||
sdhci_msm_set_caps(msm_host);
|
||||
|
||||
#if defined(CONFIG_SDC_QTI)
|
||||
host->timeout_clk_div = 4;
|
||||
|
|
|
|||
Loading…
Reference in a new issue