[PATCH v1] mmc: sdhci-of-esdhc: workaround for unreliable pulse width detection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Yangbo Lu <yangbo.lu@xxxxxxx>

This was a SoC issue on LX2160A Rev1.0.
eSDHC_DLLCFG1[DLL_PD_PULSE_STRETCH_SEL] must be set to 0 to
get 4 delay cells in the pulse width detection logic for eMMC
HS400 mode. Otherwise it would cause unexpected HS400 issue.
This patch is to clear this bit always for affected SoC when
reset for all, since this bit doesn't affect other speed modes.

Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxx>
---
 drivers/mmc/host/sdhci-esdhc.h    |    4 ++++
 drivers/mmc/host/sdhci-of-esdhc.c |   19 +++++++++++++++++++
 2 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index a28ebe8..f96422d 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -76,6 +76,10 @@
 #define ESDHC_DLL_ENABLE		0x80000000
 #define ESDHC_DLL_FREQ_SEL		0x08000000
 
+/* DLL Config 1 Register */
+#define ESDHC_DLLCFG1			0x164
+#define ESDHC_DLL_PD_PULSE_STRETCH_SEL	0x80000000
+
 /* DLL Status 0 Register */
 #define ESDHC_DLLSTAT0			0x170
 #define ESDHC_DLL_STS_SLV_LOCK		0x08000000
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 8fdd970..efae07c 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -34,6 +34,7 @@ struct sdhci_esdhc {
 	u8 spec_ver;
 	bool quirk_incorrect_hostver;
 	bool quirk_limited_clk_division;
+	bool quirk_unreliable_pulse_detection;
 	unsigned int peripheral_clock;
 };
 
@@ -640,6 +641,8 @@ static void esdhc_clock_enable(struct sdhci_host *host, bool enable)
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
 {
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host);
 	u32 val;
 
 	sdhci_reset(host, mask);
@@ -651,6 +654,12 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
 		val = sdhci_readl(host, ESDHC_TBCTL);
 		val &= ~ESDHC_TB_EN;
 		sdhci_writel(host, val, ESDHC_TBCTL);
+
+		if (esdhc->quirk_unreliable_pulse_detection) {
+			val = sdhci_readl(host, ESDHC_DLLCFG1);
+			val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL;
+			sdhci_writel(host, val, ESDHC_DLLCFG1);
+		}
 	}
 }
 
@@ -891,6 +900,11 @@ static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops,
 	{ },
 };
 
+static struct soc_device_attribute soc_unreliable_pulse_detection[] = {
+	{ .family = "QorIQ LX2160A", .revision = "1.0", },
+	{ },
+};
+
 static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
 {
 	struct sdhci_pltfm_host *pltfm_host;
@@ -917,6 +931,11 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host)
 	else
 		esdhc->quirk_limited_clk_division = false;
 
+	if (soc_device_match(soc_unreliable_pulse_detection))
+		esdhc->quirk_unreliable_pulse_detection = true;
+	else
+		esdhc->quirk_unreliable_pulse_detection = false;
+
 	np = pdev->dev.of_node;
 	clk = of_clk_get(np, 0);
 	if (!IS_ERR(clk)) {
-- 
1.7.1




[Index of Archives]     [Linux Memonry Technology]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux