static int msm_init_cm_dll()

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;
}