summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorHaijun.Zhang <haijun.zhang@freescale.com>2013-03-22 05:57:23 (GMT)
committerFleming Andrew-AFLEMING <AFLEMING@freescale.com>2013-03-27 23:29:15 (GMT)
commit7b49dde0fbf317a40d33b6baddfa59b06911a769 (patch)
tree43b13edf8945de33d11eb789e0c6b8dacd972250 /drivers/mmc
parent9a7eb472e799ecc754717a7f8db598bc35356fc4 (diff)
downloadlinux-fsl-qoriq-7b49dde0fbf317a40d33b6baddfa59b06911a769.tar.xz
ESDHC-powerpc mmc:host workaround for glitch generated when clock changed
A-005055: SDHC: Glitch is generated on the card clock with software reset or clock divider change. A simple workaround is to disable the SD card clock before the software reset, and enable it when the module resumes normal operation.The Host and the SD card are in a master-slave relationship. The Host provides clock and control transfer across the interface. Therefore, any existing operation is discarded when the Host controller is reset. The recommended flow is as follows: 1. Software disable bit[3], SDCLKEN, of the System Control Register 2. Trigger software reset and/or set clock divider 3. Check bit[3], SDSTB, of the Present State Register for stable clock 4. Enable bit[3], SDCLKEN, of the System Control Register Using the above method, the eSDHC cannot send command or transfer data when there is a glitch in the clock line, and the glitch does not cause any issue. In case the reason of Reset All command, we use reset data and reset command to instead. In case the reason of Clock change, this situation can only be occurred in card setup phases, so just go idle state and re-init the card(Card detect can do this for us). Signed-off-by: Jerry Huang <Chang-Ming.Huang@freescale.com> Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com> Change-Id: I1add2738ecf77369adc9f30718bd6a6e08ee4f17 Reviewed-on: http://git.am.freescale.net:8181/569 Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com> Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c24
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c13
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h1
3 files changed, 37 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index dbb32a5..5f1e20a 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -131,6 +131,15 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
if (reg == SDHCI_HOST_CONTROL)
val &= ~ESDHC_HOST_CONTROL_RES;
+
+ /* If we have this quirk just use reset cmd and reset data to
+ * instead of reset all.
+ */
+ if ((reg == SDHCI_SOFTWARE_RESET) &&
+ (host->quirks2 & SDHCI_QUIRK2_BROKEN_RESET_ALL) &&
+ (val & SDHCI_RESET_ALL))
+ val = SDHCI_RESET_CMD | SDHCI_RESET_DATA;
+
sdhci_be32bs_writeb(host, val, reg);
}
@@ -217,6 +226,19 @@ static void esdhc_of_resume(struct sdhci_host *host)
}
#endif
+static u32 clock;
+static void esdhc_of_platform_reset_enter(struct sdhci_host *host, u8 mask)
+{
+ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_RESET_ALL)
+ clock = host->clock;
+}
+
+static void esdhc_of_platform_reset_exit(struct sdhci_host *host, u8 mask)
+{
+ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_RESET_ALL)
+ host->clock = clock;
+}
+
static void esdhc_of_platform_init(struct sdhci_host *host)
{
u32 vvn;
@@ -266,6 +288,8 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.enable_dma = esdhc_of_enable_dma,
.get_max_clock = esdhc_of_get_max_clock,
.get_min_clock = esdhc_of_get_min_clock,
+ .platform_reset_enter = esdhc_of_platform_reset_enter,
+ .platform_reset_exit = esdhc_of_platform_reset_exit,
.platform_init = esdhc_of_platform_init,
.get_cd = esdhc_of_get_cd,
#ifdef CONFIG_PM
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index e44c1e4..22b2e02 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -90,6 +90,15 @@ void sdhci_get_of_property(struct platform_device *pdev)
of_device_is_compatible(np, "fsl,mpc8536-esdhc"))
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
+ if (of_device_is_compatible(np, "fsl,t4240-esdhc"))
+ host->quirks2 |= SDHCI_QUIRK2_BROKEN_RESET_ALL;
+
+ if (of_device_is_compatible(np, "fsl,p4860-rev1-esdhc") ||
+ of_device_is_compatible(np, "fsl,p1010-esdhc") ||
+ of_device_is_compatible(np, "fsl,p2041-esdhc") ||
+ of_device_is_compatible(np, "fsl,p3041-esdhc"))
+ host->quirks2 |= SDHCI_QUIRK2_BROKEN_RESET_ALL;
+
clk = of_get_property(np, "clock-frequency", &size);
if (clk && size == sizeof(*clk) && *clk)
pltfm_host->clock = be32_to_cpup(clk);
@@ -142,8 +151,10 @@ struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
host->ops = pdata->ops;
else
host->ops = &sdhci_pltfm_ops;
- if (pdata)
+ if (pdata) {
host->quirks = pdata->quirks;
+ host->quirks2 = pdata->quirks2;
+ }
host->irq = platform_get_irq(pdev, 0);
if (!request_mem_region(iomem->start, resource_size(iomem),
diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h
index 37e0e18..283d54a 100644
--- a/drivers/mmc/host/sdhci-pltfm.h
+++ b/drivers/mmc/host/sdhci-pltfm.h
@@ -18,6 +18,7 @@
struct sdhci_pltfm_data {
struct sdhci_ops *ops;
unsigned int quirks;
+ unsigned int quirks2;
};
struct sdhci_pltfm_host {