Skip to content

Commit 2fefc7c

Browse files
alcooperstorulf
authored andcommitted
mmc: sdhci-brcmstb: Fix incorrect switch to HS mode
When switching from any MMC speed mode that requires 1.8v (HS200, HS400 and HS400ES) to High Speed (HS) mode, the system ends up configured for SDR12 with a 50MHz clock which is an illegal mode. This happens because the SDHCI_CTRL_VDD_180 bit in the SDHCI_HOST_CONTROL2 register is left set and when this bit is set, the speed mode is controlled by the SDHCI_CTRL_UHS field in the SDHCI_HOST_CONTROL2 register. The SDHCI_CTRL_UHS field will end up being set to 0 (SDR12) by sdhci_set_uhs_signaling() because there is no UHS mode being set. The fix is to change sdhci_set_uhs_signaling() to set the SDHCI_CTRL_UHS field to SDR25 (which is the same as HS) for any switch to HS mode. This was found on a new eMMC controller that does strict checking of the speed mode and the corresponding clock rate. It caused the switch to HS400 mode to fail because part of the sequence to switch to HS400 requires a switch from HS200 to HS before going to HS400. This issue was previously fixed by commit c894e33 ("mmc: sdhci: Fix incorrect switch to HS mode") and later removed by commit 07bcc41 ("Revert \"mmc: sdhci: Fix incorrect switch to HS mode\"") because it caused failures with some SD cards on AM65X systems. The fix will now be done in a platform specific callback instead of common sdhci code. Signed-off-by: Al Cooper <[email protected]> Suggested-by: Adrian Hunter <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ulf Hansson <[email protected]>
1 parent d46ba2d commit 2fefc7c

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

drivers/mmc/host/sdhci-brcmstb.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@ static void sdhci_brcmstb_set_clock(struct sdhci_host *host, unsigned int clock)
6565
sdhci_enable_clk(host, clk);
6666
}
6767

68+
static void sdhci_brcmstb_set_uhs_signaling(struct sdhci_host *host,
69+
unsigned int timing)
70+
{
71+
u16 ctrl_2;
72+
73+
dev_dbg(mmc_dev(host->mmc), "%s: Setting UHS signaling for %d timing\n",
74+
__func__, timing);
75+
ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
76+
/* Select Bus Speed Mode for host */
77+
ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
78+
if ((timing == MMC_TIMING_MMC_HS200) ||
79+
(timing == MMC_TIMING_UHS_SDR104))
80+
ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
81+
else if (timing == MMC_TIMING_UHS_SDR12)
82+
ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
83+
else if (timing == MMC_TIMING_SD_HS ||
84+
timing == MMC_TIMING_MMC_HS ||
85+
timing == MMC_TIMING_UHS_SDR25)
86+
ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
87+
else if (timing == MMC_TIMING_UHS_SDR50)
88+
ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
89+
else if ((timing == MMC_TIMING_UHS_DDR50) ||
90+
(timing == MMC_TIMING_MMC_DDR52))
91+
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
92+
else if (timing == MMC_TIMING_MMC_HS400)
93+
ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
94+
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
95+
}
96+
6897
static void sdhci_brcmstb_dumpregs(struct mmc_host *mmc)
6998
{
7099
sdhci_dumpregs(mmc_priv(mmc));
@@ -101,7 +130,7 @@ static struct sdhci_ops sdhci_brcmstb_ops_7216 = {
101130
.set_clock = sdhci_brcmstb_set_clock,
102131
.set_bus_width = sdhci_set_bus_width,
103132
.reset = sdhci_reset,
104-
.set_uhs_signaling = sdhci_set_uhs_signaling,
133+
.set_uhs_signaling = sdhci_brcmstb_set_uhs_signaling,
105134
};
106135

107136
static struct brcmstb_match_priv match_priv_7425 = {

0 commit comments

Comments
 (0)