Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 517eb3e9 authored by Bao D. Nguyen's avatar Bao D. Nguyen
Browse files

mmc: sdhci-msm: Fix the retention of DLL regs from CX Collapse



When exit from CX collapse event, the DLL registers lose their
contents because there is no SDCC registers retention support
during CX Collapse event. In case the SDCC is operating in
SDR104/HS200/HS400 modes, before resuming from CX Collapse event,
the DLL registers need to be saved and restored followed by
the SDCC's DLL initialization sequence in order for the DLL to be
fully functional again.

Change-Id: I9a870e783ce9b7271038fa5ce6e1d2f48a67d162
Signed-off-by: default avatarBao D. Nguyen <nguyenb@codeaurora.org>
parent 94da5973
Loading
Loading
Loading
Loading
+75 −28
Original line number Diff line number Diff line
@@ -369,6 +369,11 @@ enum vdd_io_level {
	VDD_IO_SET_LEVEL,
};

enum dll_init_context {
	DLL_INIT_NORMAL = 0,
	DLL_INIT_FROM_CX_COLLAPSE_EXIT,
};

/* MSM platform specific tuning */
static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
						u8 poll)
@@ -713,7 +718,8 @@ static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
}

/* Initialize the DLL (Programmable Delay Line ) */
static int msm_init_cm_dll(struct sdhci_host *host)
static int msm_init_cm_dll(struct sdhci_host *host,
				enum dll_init_context init_context)
{
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
@@ -770,6 +776,14 @@ static int msm_init_cm_dll(struct sdhci_host *host)
	if (msm_host->use_updated_dll_reset) {
		u32 mclk_freq = 0;

		/*
		 * Only configure the mclk_freq in normal DLL init
		 * context. If the DLL init is coming from
		 * CX Collapse Exit context, the host->clock may be zero.
		 * The DLL_CONFIG_2 register has already been restored to
		 * proper value prior to getting here.
		 */
		if (init_context == DLL_INIT_NORMAL) {
			switch (host->clock) {
			case 208000000:
			case 202000000:
@@ -796,6 +810,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)
			   msm_host_offset->CORE_DLL_CONFIG_2)
			   & ~(0xFF << 10)) | (mclk_freq << 10)),
			   host->ioaddr + msm_host_offset->CORE_DLL_CONFIG_2);
		}
		/* wait for 5us before enabling DLL clock */
		udelay(5);
	}
@@ -1082,7 +1097,7 @@ static int sdhci_msm_enhanced_strobe(struct sdhci_host *host)
	/*
	 * Reset the tuning block.
	 */
	ret = msm_init_cm_dll(host);
	ret = msm_init_cm_dll(host, DLL_INIT_NORMAL);
	if (ret)
		goto out;

@@ -1109,7 +1124,7 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
	 * Retuning in HS400 (DDR mode) will fail, just reset the
	 * tuning block and restore the saved tuning phase.
	 */
	ret = msm_init_cm_dll(host);
	ret = msm_init_cm_dll(host, DLL_INIT_NORMAL);
	if (ret)
		goto out;

@@ -1232,7 +1247,7 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
	tuned_phase_cnt = 0;

	/* first of all reset the tuning block */
	rc = msm_init_cm_dll(host);
	rc = msm_init_cm_dll(host, DLL_INIT_NORMAL);
	if (rc)
		goto kfree;

@@ -3078,6 +3093,19 @@ static void sdhci_msm_registers_save(struct sdhci_host *host)
		sdhci_readl(host, SDHCI_CAPABILITIES_1);
	msm_host->regs_restore.testbus_config = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_TESTBUS_CONFIG);
	msm_host->regs_restore.dll_config = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG);
	msm_host->regs_restore.dll_config2 = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG_2);
	msm_host->regs_restore.dll_config = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG);
	msm_host->regs_restore.dll_config2 = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG_2);
	msm_host->regs_restore.dll_config3 = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG_3);
	msm_host->regs_restore.dll_usr_ctl = readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_USR_CTL);

	msm_host->regs_restore.is_valid = true;

	pr_debug("%s: %s: registers saved. PWRCTL_MASK = 0x%x\n",
@@ -3093,6 +3121,7 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host)
	u8 irq_status;
	const struct sdhci_msm_offset *msm_host_offset =
					msm_host->offset;
	struct mmc_ios ios = host->mmc->ios;

	if (!msm_host->regs_restore.is_supported ||
		!msm_host->regs_restore.is_valid)
@@ -3144,6 +3173,24 @@ static void sdhci_msm_registers_restore(struct sdhci_host *host)
	writel_relaxed(msm_host->regs_restore.vendor_pwrctl_mask,
			host->ioaddr + msm_host_offset->CORE_PWRCTL_MASK);

	if (((ios.timing == MMC_TIMING_MMC_HS400) ||
			(ios.timing == MMC_TIMING_MMC_HS200) ||
			(ios.timing == MMC_TIMING_UHS_SDR104))
			&& (ios.clock > CORE_FREQ_100MHZ)) {
		writel_relaxed(msm_host->regs_restore.dll_config2,
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG_2);
		writel_relaxed(msm_host->regs_restore.dll_config3,
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG_3);
		writel_relaxed(msm_host->regs_restore.dll_usr_ctl,
			host->ioaddr + msm_host_offset->CORE_DLL_USR_CTL);
		writel_relaxed(msm_host->regs_restore.dll_config &
			~(CORE_DLL_RST | CORE_DLL_PDN),
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);

		msm_init_cm_dll(host, DLL_INIT_FROM_CX_COLLAPSE_EXIT);
		msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
	}

	pr_debug("%s: %s: registers restored. PWRCTL_MASK = 0x%x\n",
		mmc_hostname(host->mmc), __func__,
		readl_relaxed(host->ioaddr +
+4 −0
Original line number Diff line number Diff line
@@ -195,6 +195,10 @@ struct sdhci_msm_regs_restore {
	u32 hc_3c_3e;
	u32 hc_caps_1;
	u32 testbus_config;
	u32 dll_config;
	u32 dll_config2;
	u32 dll_config3;
	u32 dll_usr_ctl;
};

struct sdhci_msm_debug_data {