|
@@ -59,6 +59,10 @@
|
|
|
#define CORE_DLL_CONFIG 0x100
|
|
|
#define CORE_DLL_STATUS 0x108
|
|
|
|
|
|
+#define CORE_DLL_CONFIG_2 0x1b4
|
|
|
+#define CORE_FLL_CYCLE_CNT BIT(18)
|
|
|
+#define CORE_DLL_CLOCK_DISABLE BIT(21)
|
|
|
+
|
|
|
#define CORE_VENDOR_SPEC 0x10c
|
|
|
#define CORE_CLK_PWRSAVE BIT(1)
|
|
|
|
|
@@ -77,7 +81,9 @@ struct sdhci_msm_host {
|
|
|
struct clk *clk; /* main SD/MMC bus clock */
|
|
|
struct clk *pclk; /* SDHC peripheral bus clock */
|
|
|
struct clk *bus_clk; /* SDHC bus voter clock */
|
|
|
+ struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/
|
|
|
struct mmc_host *mmc;
|
|
|
+ bool use_14lpp_dll_reset;
|
|
|
};
|
|
|
|
|
|
/* Platform specific tuning */
|
|
@@ -305,6 +311,8 @@ static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
|
|
|
static int msm_init_cm_dll(struct sdhci_host *host)
|
|
|
{
|
|
|
struct mmc_host *mmc = host->mmc;
|
|
|
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
|
|
+ struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
|
|
|
int wait_cnt = 50;
|
|
|
unsigned long flags;
|
|
|
u32 config;
|
|
@@ -320,6 +328,16 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|
|
config &= ~CORE_CLK_PWRSAVE;
|
|
|
writel_relaxed(config, host->ioaddr + CORE_VENDOR_SPEC);
|
|
|
|
|
|
+ if (msm_host->use_14lpp_dll_reset) {
|
|
|
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
|
|
+ config &= ~CORE_CK_OUT_EN;
|
|
|
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
|
+
|
|
|
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ config |= CORE_DLL_CLOCK_DISABLE;
|
|
|
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ }
|
|
|
+
|
|
|
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
|
|
config |= CORE_DLL_RST;
|
|
|
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
@@ -329,6 +347,28 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|
|
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
|
msm_cm_dll_set_freq(host);
|
|
|
|
|
|
+ if (msm_host->use_14lpp_dll_reset &&
|
|
|
+ !IS_ERR_OR_NULL(msm_host->xo_clk)) {
|
|
|
+ u32 mclk_freq = 0;
|
|
|
+
|
|
|
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ config &= CORE_FLL_CYCLE_CNT;
|
|
|
+ if (config)
|
|
|
+ mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
|
|
|
+ clk_get_rate(msm_host->xo_clk));
|
|
|
+ else
|
|
|
+ mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
|
|
|
+ clk_get_rate(msm_host->xo_clk));
|
|
|
+
|
|
|
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ config &= ~(0xFF << 10);
|
|
|
+ config |= mclk_freq << 10;
|
|
|
+
|
|
|
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ /* wait for 5us before enabling DLL clock */
|
|
|
+ udelay(5);
|
|
|
+ }
|
|
|
+
|
|
|
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
|
|
config &= ~CORE_DLL_RST;
|
|
|
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
@@ -337,6 +377,13 @@ static int msm_init_cm_dll(struct sdhci_host *host)
|
|
|
config &= ~CORE_DLL_PDN;
|
|
|
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
|
|
|
|
+ if (msm_host->use_14lpp_dll_reset) {
|
|
|
+ msm_cm_dll_set_freq(host);
|
|
|
+ config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ config &= ~CORE_DLL_CLOCK_DISABLE;
|
|
|
+ writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG_2);
|
|
|
+ }
|
|
|
+
|
|
|
config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
|
|
|
config |= CORE_DLL_EN;
|
|
|
writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
|
|
@@ -590,6 +637,16 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|
|
goto pclk_disable;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * xo clock is needed for FLL feature of cm_dll.
|
|
|
+ * In case if xo clock is not mentioned in DT, warn and proceed.
|
|
|
+ */
|
|
|
+ msm_host->xo_clk = devm_clk_get(&pdev->dev, "xo");
|
|
|
+ if (IS_ERR(msm_host->xo_clk)) {
|
|
|
+ ret = PTR_ERR(msm_host->xo_clk);
|
|
|
+ dev_warn(&pdev->dev, "TCXO clk not present (%d)\n", ret);
|
|
|
+ }
|
|
|
+
|
|
|
/* Vote for maximum clock rate for maximum performance */
|
|
|
ret = clk_set_rate(msm_host->clk, INT_MAX);
|
|
|
if (ret)
|
|
@@ -635,6 +692,9 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|
|
dev_dbg(&pdev->dev, "MCI Version: 0x%08x, major: 0x%04x, minor: 0x%02x\n",
|
|
|
core_version, core_major, core_minor);
|
|
|
|
|
|
+ if (core_major == 1 && core_minor >= 0x42)
|
|
|
+ msm_host->use_14lpp_dll_reset = true;
|
|
|
+
|
|
|
/*
|
|
|
* Support for some capabilities is not advertised by newer
|
|
|
* controller versions and must be explicitly enabled.
|