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

Commit a58f91f5 authored by Venkat Gopalakrishnan's avatar Venkat Gopalakrishnan Committed by xiaonian
Browse files

mmc: sdhci: Add SW workarounds for HW bugs



Initial version of Qualcomm SDHC has the following two h/w
issues. This patch adds s/w workarounds for the same.

H/W issue: Read Transfer Active/ Write Transfer Active may be not
       de-asserted after end of transaction.
S/W workaround: Set Software Reset for DAT line in Software Reset
	Register (Bit 2).

Added a quirk SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT to enable this workaround.

H/W issue: Slow interrupt clearance at 400KHz may cause host controller
       driver interrupt handler to be called twice.
S/W Workaround: Add 40us delay in interrupt handler when operating at
	initialization frequency(400KHz).

Added a quirk SDHCI_QUIRK2_SLOW_INT_CLR to enable this workaround.

Change-Id: I8b4062f101085adadd66560f77b98b04d75cb836
Signed-off-by: default avatarVenkat Gopalakrishnan <venkatg@codeaurora.org>
Signed-off-by: default avatarAsutosh Das <asutoshd@codeaurora.org>
Signed-off-by: default avatarSahitya Tummala <stummala@codeaurora.org>
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
[xiaonian@codeaurora.org: fix trivial merge conflict]
Signed-off-by: default avatarXiaonian Wang <xiaonian@codeaurora.org>
parent 0ef2481c
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include "sdhci-pltfm.h"

#define SDHCI_VER_100		0x2B
#define CORE_HC_MODE		0x78
#define HC_MODE_EN		0x1

@@ -772,6 +773,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
	struct sdhci_msm_host *msm_host;
	struct resource *core_memres = NULL;
	int ret = 0, pwr_irq = 0, dead = 0;
	u32 host_version;

	pr_debug("%s: Enter %s\n", dev_name(&pdev->dev), __func__);
	msm_host = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_msm_host),
@@ -870,6 +872,25 @@ static int sdhci_msm_probe(struct platform_device *pdev)
	host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
	host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;

	host_version = readl_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
	dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
		host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
		  SDHCI_VENDOR_VER_SHIFT));
	if (((host_version & SDHCI_VENDOR_VER_MASK) >>
		SDHCI_VENDOR_VER_SHIFT) == SDHCI_VER_100) {
		/*
		 * Add 40us delay in interrupt handler when
		 * operating at initialization frequency(400KHz).
		 */
		host->quirks2 |= SDHCI_QUIRK2_SLOW_INT_CLR;
		/*
		 * Set Software Reset for DAT line in Software
		 * Reset Register (Bit 2).
		 */
		host->quirks2 |= SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT;
	}

	/* Setup PWRCTL irq */
	pwr_irq = platform_get_irq_byname(pdev, "pwr_irq");
	if (pwr_irq < 0) {
		dev_err(&pdev->dev, "Failed to get pwr_irq by name (%d)\n",
+13 −2
Original line number Diff line number Diff line
@@ -2367,6 +2367,9 @@ static bool sdhci_request_done(struct sdhci_host *host)
		sdhci_do_reset(host, SDHCI_RESET_DATA);

		host->pending_reset = false;
	} else {
		if (host->quirks2 & SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT)
			sdhci_reset(host, SDHCI_RESET_DATA);
	}

	if (!sdhci_has_requests(host))
@@ -2713,11 +2716,19 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
			result = IRQ_WAKE_THREAD;
		}

		if (intmask & SDHCI_INT_CMD_MASK)
		if (intmask & SDHCI_INT_CMD_MASK) {
			if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
				(host->clock <= 400000))
				udelay(40);
			sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
		}

		if (intmask & SDHCI_INT_DATA_MASK)
		if (intmask & SDHCI_INT_DATA_MASK) {
			if ((host->quirks2 & SDHCI_QUIRK2_SLOW_INT_CLR) &&
			    (host->clock <= 400000))
				udelay(40);
			sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
		}

		if (intmask & SDHCI_INT_BUS_POWER)
			pr_err("%s: Card is consuming too much power!\n",
+11 −0
Original line number Diff line number Diff line
@@ -425,6 +425,17 @@ struct sdhci_host {
#define SDHCI_QUIRK2_ACMD23_BROKEN			(1<<14)
/* Broken Clock divider zero in controller */
#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN		(1<<15)
/*
 * Read Transfer Active/ Write Transfer Active may be not
 * de-asserted after end of transaction. Issue reset for DAT line.
 */
#define SDHCI_QUIRK2_RDWR_TX_ACTIVE_EOT                 (1<<17)
/*
 * Slow interrupt clearance at 400KHz may cause
 * host controller driver interrupt handler to
 * be called twice.
*/
#define SDHCI_QUIRK2_SLOW_INT_CLR			(1<<18)

	int irq;		/* Device IRQ */
	void __iomem *ioaddr;	/* Mapped address */