in host/sdhci-msm.c [619:772]
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, xo_clk = 0;
u32 config;
const struct sdhci_msm_offset *msm_offset =
msm_host->offset;
if (msm_host->use_14lpp_dll_reset && !IS_ERR_OR_NULL(msm_host->xo_clk))
xo_clk = clk_get_rate(msm_host->xo_clk);
spin_lock_irqsave(&host->lock, flags);
/*
* Make sure that clock is always enabled when DLL
* tuning is in progress. Keeping PWRSAVE ON may
* turn off the clock.
*/
config = readl_relaxed(host->ioaddr + msm_offset->core_vendor_spec);
config &= ~CORE_CLK_PWRSAVE;
writel_relaxed(config, host->ioaddr + msm_offset->core_vendor_spec);
if (msm_host->dll_config)
writel_relaxed(msm_host->dll_config,
host->ioaddr + msm_offset->core_dll_config);
if (msm_host->use_14lpp_dll_reset) {
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config &= ~CORE_CK_OUT_EN;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_2);
config |= CORE_DLL_CLOCK_DISABLE;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config_2);
}
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config |= CORE_DLL_RST;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config |= CORE_DLL_PDN;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
if (!msm_host->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 +
msm_offset->core_dll_config_2);
config &= CORE_FLL_CYCLE_CNT;
if (config)
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 8),
xo_clk);
else
mclk_freq = DIV_ROUND_CLOSEST_ULL((host->clock * 4),
xo_clk);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_2);
config &= ~(0xFF << 10);
config |= mclk_freq << 10;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config_2);
/* wait for 5us before enabling DLL clock */
udelay(5);
}
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config &= ~CORE_DLL_RST;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config &= ~CORE_DLL_PDN;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
if (msm_host->use_14lpp_dll_reset) {
if (!msm_host->dll_config)
msm_cm_dll_set_freq(host);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_2);
config &= ~CORE_DLL_CLOCK_DISABLE;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config_2);
}
/*
* Configure DLL user control register to enable DLL status.
* This setting is applicable to SDCC v5.1 onwards only.
*/
if (msm_host->uses_tassadar_dll) {
config = DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN |
ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_usr_ctl);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config_3);
config &= ~0xFF;
if (msm_host->clk_rate < 150000000)
config |= DLL_CONFIG_3_LOW_FREQ_VAL;
else
config |= DLL_CONFIG_3_HIGH_FREQ_VAL;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config_3);
}
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config |= CORE_DLL_EN;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
config = readl_relaxed(host->ioaddr +
msm_offset->core_dll_config);
config |= CORE_CK_OUT_EN;
writel_relaxed(config, host->ioaddr +
msm_offset->core_dll_config);
/* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
while (!(readl_relaxed(host->ioaddr + msm_offset->core_dll_status) &
CORE_DLL_LOCK)) {
/* max. wait for 50us sec for LOCK bit to be set */
if (--wait_cnt == 0) {
dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
mmc_hostname(mmc));
spin_unlock_irqrestore(&host->lock, flags);
return -ETIMEDOUT;
}
udelay(1);
}
spin_unlock_irqrestore(&host->lock, flags);
return 0;
}