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

Commit 43d6be80 authored by Pavan Anamula's avatar Pavan Anamula
Browse files

mmc: sdhci: Add new host->op and quirk to apply reset workaround



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.

Change-Id: I487bdf3bd4afb18e69afa778aa38c3574d69e2f7
Signed-off-by: default avatarSahitya Tummala <stummala@codeaurora.org>
Signed-off-by: default avatarPavan Anamula <pavana@codeaurora.org>
parent 572b3198
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -235,6 +235,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
{
	unsigned long timeout;

retry_reset:
	sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);

	if (mask & SDHCI_RESET_ALL) {
@@ -260,12 +261,43 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
		if (timeout == 0) {
			pr_err("%s: Reset 0x%x never completed.\n",
				mmc_hostname(host->mmc), (int)mask);
			if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND)
				&& host->ops->reset_workaround) {
				if (!host->reset_wa_applied) {
					/*
					 * apply the workaround and issue
					 * reset again.
					 */
					host->ops->reset_workaround(host, 1);
					host->reset_wa_applied = 1;
					host->reset_wa_cnt++;
					goto retry_reset;
				} else {
					pr_err("%s: Reset 0x%x failed with workaround\n",
						mmc_hostname(host->mmc),
						(int)mask);
					/* clear the workaround */
					host->ops->reset_workaround(host, 0);
					host->reset_wa_applied = 0;
				}
			}

			sdhci_dumpregs(host);
			return;
		}
		timeout--;
		mdelay(1);
	}

	if ((host->quirks2 & SDHCI_QUIRK2_USE_RESET_WORKAROUND) &&
			host->ops->reset_workaround && host->reset_wa_applied) {
		pr_info("%s: Reset 0x%x successful with workaround\n",
				mmc_hostname(host->mmc), (int)mask);
		/* clear the workaround */
		host->ops->reset_workaround(host, 0);
		host->reset_wa_applied = 0;
	}

}
EXPORT_SYMBOL_GPL(sdhci_reset);

+1 −0
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ struct sdhci_ops {
	void	(*enhanced_strobe_mask)(struct sdhci_host *host, bool set);
	void	(*detect)(struct sdhci_host *host, bool detected);
	int	(*notify_load)(struct sdhci_host *host, enum mmc_load state);
	void	(*reset_workaround)(struct sdhci_host *host, u32 enable);
};

#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
+5 −1
Original line number Diff line number Diff line
@@ -167,7 +167,6 @@ struct sdhci_host {
 * calculated based on the base clock.
 */
#define SDHCI_QUIRK2_DIVIDE_TOUT_BY_4			(1<<16)

/*
 * Some SDHC controllers are unable to handle data-end bit error in
 * 1-bit mode of SDIO.
@@ -184,6 +183,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_NONSTANDARD_CLOCK			(1<<19)
/* Capability register bit-63 indicates HS400 support */
#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400		(1<<20)
/* Use reset workaround in case sdhci reset timeouts */
#define SDHCI_QUIRK2_USE_RESET_WORKAROUND		(1<<21)

	int irq;		/* Device IRQ */
	void __iomem *ioaddr;	/* Mapped address */
@@ -295,6 +296,9 @@ struct sdhci_host {
	u32 auto_cmd_err_sts;
	struct ratelimit_state dbg_dump_rs;
	struct cmdq_host *cq_host;
	int reset_wa_applied; /* reset workaround status */
	ktime_t reset_wa_t; /* time when the reset workaround is applied */
	int reset_wa_cnt; /* total number of times workaround is used */

	unsigned long private[0] ____cacheline_aligned;
};