Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci-of-esdhc: workaround for unreliable pulse width detection

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@nxp.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Yangbo Lu and committed by
Ulf Hansson
48e304cc 58d0bf84

+23
+4
drivers/mmc/host/sdhci-esdhc.h
··· 78 78 #define ESDHC_DLL_ENABLE 0x80000000 79 79 #define ESDHC_DLL_FREQ_SEL 0x08000000 80 80 81 + /* DLL Config 1 Register */ 82 + #define ESDHC_DLLCFG1 0x164 83 + #define ESDHC_DLL_PD_PULSE_STRETCH_SEL 0x80000000 84 + 81 85 /* DLL Status 0 Register */ 82 86 #define ESDHC_DLLSTAT0 0x170 83 87 #define ESDHC_DLL_STS_SLV_LOCK 0x08000000
+19
drivers/mmc/host/sdhci-of-esdhc.c
··· 79 79 u8 spec_ver; 80 80 bool quirk_incorrect_hostver; 81 81 bool quirk_limited_clk_division; 82 + bool quirk_unreliable_pulse_detection; 82 83 bool quirk_fixup_tuning; 83 84 unsigned int peripheral_clock; 84 85 const struct esdhc_clk_fixup *clk_fixup; ··· 677 676 678 677 static void esdhc_reset(struct sdhci_host *host, u8 mask) 679 678 { 679 + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 680 + struct sdhci_esdhc *esdhc = sdhci_pltfm_priv(pltfm_host); 680 681 u32 val; 681 682 682 683 sdhci_reset(host, mask); ··· 690 687 val = sdhci_readl(host, ESDHC_TBCTL); 691 688 val &= ~ESDHC_TB_EN; 692 689 sdhci_writel(host, val, ESDHC_TBCTL); 690 + 691 + if (esdhc->quirk_unreliable_pulse_detection) { 692 + val = sdhci_readl(host, ESDHC_DLLCFG1); 693 + val &= ~ESDHC_DLL_PD_PULSE_STRETCH_SEL; 694 + sdhci_writel(host, val, ESDHC_DLLCFG1); 695 + } 693 696 } 694 697 } 695 698 ··· 950 941 { }, 951 942 }; 952 943 944 + static struct soc_device_attribute soc_unreliable_pulse_detection[] = { 945 + { .family = "QorIQ LX2160A", .revision = "1.0", }, 946 + { }, 947 + }; 948 + 953 949 static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) 954 950 { 955 951 const struct of_device_id *match; ··· 981 967 esdhc->quirk_limited_clk_division = true; 982 968 else 983 969 esdhc->quirk_limited_clk_division = false; 970 + 971 + if (soc_device_match(soc_unreliable_pulse_detection)) 972 + esdhc->quirk_unreliable_pulse_detection = true; 973 + else 974 + esdhc->quirk_unreliable_pulse_detection = false; 984 975 985 976 match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node); 986 977 if (match)