summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorHaijun Zhang <Haijun.Zhang@freescale.com>2013-12-19 02:22:15 (GMT)
committerJose Rivera <German.Rivera@freescale.com>2014-01-10 20:23:55 (GMT)
commitfa9e23049a60faffd165d772d784ca4ff3336148 (patch)
treec32c8c0faaa6c5bc82db298ffd7f4528993bd956 /drivers/mmc
parentbe8deebaf8a4472e204723ece841f43fabe7f98f (diff)
downloadlinux-fsl-qoriq-fa9e23049a60faffd165d772d784ca4ff3336148.tar.xz
esdhc: Workaround for eSDHC clock glitch issue
A-003980: SDHC: Glitch is generated on the card clock with software reset or clock divider change Description: A glitch may occur on the SDHC card clock when the software sets the RSTA bit (software reset) in the system control register. It can also be generated by setting the clock divider value. The glitch produced can cause the external card to switch to an unknown state. The occurrence is not deterministic. Workaround: 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. Signed-off-by: Haijun Zhang <haijun.zhang@freescale.com> Change-Id: I43a6ef8fdffeeeb13bfef215825d417778ce0bf3 Reviewed-on: http://git.am.freescale.net:8181/5916 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Xiaobo Xie <X.Xie@freescale.com> Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 419854f..9859ae7 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -407,17 +407,28 @@ 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;
+ if ((host->quirks2 & SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET) &&
+ (mask & SDHCI_RESET_ALL)) {
+ u16 clk;
+
+ clk = esdhc_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~ESDHC_CLOCK_CRDEN;
+ esdhc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ }
}
static void esdhc_of_platform_reset_exit(struct sdhci_host *host, u8 mask)
{
- if (host->quirks2 & SDHCI_QUIRK2_BROKEN_RESET_ALL)
- host->clock = clock;
+ if ((host->quirks2 & SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET) &&
+ (mask & SDHCI_RESET_ALL)) {
+ u16 clk;
+
+ clk = esdhc_readw(host, SDHCI_CLOCK_CONTROL);
+ clk |= ESDHC_CLOCK_CRDEN;
+ esdhc_writew(host, clk, SDHCI_CLOCK_CONTROL);
+ }
}
static void esdhc_of_platform_init(struct sdhci_host *host)
@@ -441,15 +452,15 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
* P2041-R1.0 P2041-R1.1 P2041-R2.0 P1010-R1.0
*/
if (((SVR_SOC_VER(svr) == SVR_T4240) && (SVR_REV(svr) == 0x10)) ||
- ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x10)) ||
- ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x20)) ||
- ((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x10)) ||
- ((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x20)) ||
- ((SVR_SOC_VER(svr) == SVR_P1010) && (SVR_REV(svr) == 0x10)) ||
- ((SVR_SOC_VER(svr) == SVR_P3041) && (SVR_REV(svr) == 0x10)) ||
- ((SVR_SOC_VER(svr) == SVR_P3041) && (SVR_REV(svr) == 0x20)) ||
- ((SVR_SOC_VER(svr) == SVR_P2041) && (SVR_REV(svr) <= 0x20)))
- host->quirks2 |= SDHCI_QUIRK2_BROKEN_RESET_ALL;
+ ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x10)) ||
+ ((SVR_SOC_VER(svr) == SVR_B4860) && (SVR_REV(svr) == 0x20)) ||
+ ((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x10)) ||
+ ((SVR_SOC_VER(svr) == SVR_B4420) && (SVR_REV(svr) == 0x20)) ||
+ ((SVR_SOC_VER(svr) == SVR_P1010) && (SVR_REV(svr) == 0x10)) ||
+ ((SVR_SOC_VER(svr) == SVR_P3041) && (SVR_REV(svr) == 0x10)) ||
+ ((SVR_SOC_VER(svr) == SVR_P3041) && (SVR_REV(svr) == 0x20)) ||
+ ((SVR_SOC_VER(svr) == SVR_P2041) && (SVR_REV(svr) <= 0x20)))
+ host->quirks2 |= SDHCI_QUIRK2_DISABLE_CLOCK_BEFORE_RESET;
}
/* Return: 1 - the card is present; 0 - card is absent */