@@ -127,6 +127,8 @@
#define CQHCI_VENDOR_CFG1 0xA00
#define CQHCI_VENDOR_DIS_RST_ON_CQ_EN (0x3 << 13)
+#define RCLK_TOGGLE 0x2
+
struct sdhci_msm_offset {
u32 core_hc_mode;
u32 core_mci_data_cnt;
@@ -1554,6 +1556,43 @@ static void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_enable_clk(host, clk);
}
+/*
+ * After MCLK ugating, toggle the FIFO write clock to get
+ * the FIFO pointers and flags to valid state.
+ */
+static void sdhci_msm_toggle_fifo_write_clk(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
+ const struct sdhci_msm_offset *msm_offset =
+ msm_host->offset;
+ struct mmc_card *card = host->mmc->card;
+
+ if (msm_host->tuning_done ||
+ (card && card->ext_csd.strobe_support &&
+ card->host->ios.enhanced_strobe)) {
+ /*
+ * set HC_REG_DLL_CONFIG_3[1] to select MCLK as
+ * DLL input clock
+ */
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_offset->core_dll_config_3))
+ | RCLK_TOGGLE), host->ioaddr +
+ msm_offset->core_dll_config_3);
+ /* ensure above write as toggling same bit quickly */
+ wmb();
+ udelay(2);
+ /*
+ * clear HC_REG_DLL_CONFIG_3[1] to select RCLK as
+ * DLL input clock
+ */
+ writel_relaxed(((readl_relaxed(host->ioaddr +
+ msm_offset->core_dll_config_3))
+ & ~RCLK_TOGGLE), host->ioaddr +
+ msm_offset->core_dll_config_3);
+ }
+}
+
/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
{
@@ -2149,6 +2188,10 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev)
msm_host->bulk_clks);
if (ret)
return ret;
+ if (host->mmc &&
+ (host->mmc->ios.timing == MMC_TIMING_MMC_HS400))
+ sdhci_msm_toggle_fifo_write_clk(host);
+
/*
* Whenever core-clock is gated dynamically, it's needed to
* restore the SDR DLL settings when the clock is ungated.