Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20073c50 authored by Pavan Anamula's avatar Pavan Anamula
Browse files

mmc: sdhci-msm: Implement reset workaround and enable it



The SDHCI reset for data is getting stuck on some of sdhci-msm
controllers. The SDHCI reset usually waits for any pending transfers
on the bus before proceeding with the controller reset. But in the
failure cases, the data transfer seems to be stuck on the bus and
thus preventing the controller from being reset. The workaround is
to force the controller to be reset under such scenarios. This seems
to be helping the controller to return back to good state at least
for the next commands following the failure.
This issue is found on SDCC5 controller of 8916/8939 and 8992 chipsets.
Hence, enable the quirk SDHCI_QUIRK2_USE_RESET_WORKAROUND only on those
controllers.

Change-Id: Id49009736beb410ccb2535d614786a7c48098f85
Signed-off-by: default avatarSahitya Tummala <stummala@codeaurora.org>
Signed-off-by: default avatarPavan Anamula <pavana@codeaurora.org>
parent 43d6be80
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -119,6 +119,8 @@
#define CORE_VENDOR_SPEC_ADMA_ERR_ADDR1	0x118

#define CORE_VENDOR_SPEC_FUNC2 0x110
#define HC_SW_RST_WAIT_IDLE_DIS	(1 << 20)
#define HC_SW_RST_REQ (1 << 21)
#define CORE_ONE_MID_EN     (1 << 25)

#define CORE_VENDOR_SPEC_CAPABILITIES0	0x11C
@@ -2893,6 +2895,48 @@ int sdhci_msm_notify_load(struct sdhci_host *host, enum mmc_load state)
	return 0;
}

void sdhci_msm_reset_workaround(struct sdhci_host *host, u32 enable)
{
	u32 vendor_func2;
	unsigned long timeout;

	vendor_func2 = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2);

	if (enable) {
		writel_relaxed(vendor_func2 | HC_SW_RST_REQ, host->ioaddr +
				CORE_VENDOR_SPEC_FUNC2);
		timeout = 10000;
		while (readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2) &
				HC_SW_RST_REQ) {
			if (timeout == 0) {
				pr_info("%s: Applying wait idle disable workaround\n",
					mmc_hostname(host->mmc));
				/*
				 * Apply the reset workaround to not wait for
				 * pending data transfers on AXI before
				 * resetting the controller. This could be
				 * risky if the transfers were stuck on the
				 * AXI bus.
				 */
				vendor_func2 = readl_relaxed(host->ioaddr +
						CORE_VENDOR_SPEC_FUNC2);
				writel_relaxed(vendor_func2 |
					HC_SW_RST_WAIT_IDLE_DIS,
					host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
				host->reset_wa_t = ktime_get();
				return;
			}
			timeout--;
			udelay(10);
		}
		pr_info("%s: waiting for SW_RST_REQ is successful\n",
				mmc_hostname(host->mmc));
	} else {
		writel_relaxed(vendor_func2 & ~HC_SW_RST_WAIT_IDLE_DIS,
				host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
	}
}

static struct sdhci_ops sdhci_msm_ops = {
	.crypto_engine_cfg = sdhci_msm_ice_cfg,
	.crypto_engine_reset = sdhci_msm_ice_reset,
@@ -2914,6 +2958,7 @@ static struct sdhci_ops sdhci_msm_ops = {
	.enhanced_strobe_mask = sdhci_msm_enhanced_strobe_mask,
	.detect = sdhci_msm_detect,
	.notify_load = sdhci_msm_notify_load,
	.reset_workaround = sdhci_msm_reset_workaround,
};

static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
@@ -2956,6 +3001,7 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
	 * on 8992 (minor 0x3e) as a workaround to reset for data stuck issue.
	 */
	if (major == 1 && (minor == 0x2e || minor == 0x3e)) {
		host->quirks2 |= SDHCI_QUIRK2_USE_RESET_WORKAROUND;
		val = readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC_FUNC2);
		writel_relaxed((val | CORE_ONE_MID_EN),
			host->ioaddr + CORE_VENDOR_SPEC_FUNC2);