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

Commit 6b82ef66 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "sdhci: sdhci-msm: update dll configuration" into msm-4.9

parents 92472dc7 2faa7bbe
Loading
Loading
Loading
Loading
+123 −35
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@

#define CORE_DLL_STATUS		0x108
#define CORE_DLL_LOCK		(1 << 7)
#define CORE_DDR_DLL_LOCK	(1 << 11)

#define CORE_VENDOR_SPEC	0x10C
#define CORE_CLK_PWRSAVE	(1 << 1)
@@ -138,6 +139,15 @@
#define CORE_DDR_200_CFG		0x184
#define CORE_CDC_T4_DLY_SEL		(1 << 0)
#define CORE_START_CDC_TRAFFIC		(1 << 6)
#define CORE_VENDOR_SPEC3	0x1B0
#define CORE_PWRSAVE_DLL	(1 << 3)

#define CORE_DLL_CONFIG_2	0x1B4
#define CORE_DDR_CAL_EN		(1 << 0)

#define CORE_DDR_CONFIG		0x1B8
#define DDR_CONFIG_POR_VAL	0x80040853


#define CORE_MCI_DATA_CNT 0x30
#define CORE_MCI_STATUS 0x34
@@ -301,6 +311,7 @@ struct sdhci_msm_host {
	bool en_auto_cmd21;
	struct device_attribute auto_cmd21_attr;
	atomic_t controller_clock;
	bool use_cdclp533;
};

enum vdd_io_level {
@@ -715,32 +726,12 @@ static int msm_init_cm_dll(struct sdhci_host *host)

static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
{
	u32 wait_cnt;
	u32 calib_done;
	int ret = 0;
	int cdc_err = 0;
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;

	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);

	/*
	 * Retuning in HS400 (DDR mode) will fail, just reset the
	 * tuning block and restore the saved tuning phase.
	 */
	ret = msm_init_cm_dll(host);
	if (ret)
		goto out;

	/* Set the selected phase in delay line hw block */
	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
	if (ret)
		goto out;

	/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
			| CORE_CMD_DAT_TRACK_SEL),
			host->ioaddr + CORE_DLL_CONFIG);

	/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DDR_200_CFG)
			& ~CORE_CDC_T4_DLY_SEL),
@@ -810,19 +801,14 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
	mb();

	/* Poll on CALIBRATION_DONE field in CORE_CSR_CDC_STATUS0 to be 1 */
	wait_cnt = 50;
	while (!(readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
			& CORE_CALIBRATION_DONE)) {
		/* max. wait for 50us sec for CALIBRATION_DONE bit to be set */
		if (--wait_cnt == 0) {
	ret = readl_poll_timeout(host->ioaddr + CORE_CSR_CDC_STATUS0,
		 calib_done, (calib_done & CORE_CALIBRATION_DONE), 1, 50);

	if (ret == -ETIMEDOUT) {
		pr_err("%s: %s: CDC Calibration was not completed\n",
				mmc_hostname(host->mmc), __func__);
			ret = -ETIMEDOUT;
		goto out;
	}
		/* wait for 1us before polling again */
		udelay(1);
	}

	/* Verify CDC_ERROR_CODE field in CORE_CSR_CDC_STATUS0 is 0 */
	cdc_err = readl_relaxed(host->ioaddr + CORE_CSR_CDC_STATUS0)
@@ -844,6 +830,81 @@ static int sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
	return ret;
}

static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
{
	u32 dll_status;
	int ret = 0;

	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);

	/*
	 * Currently the CORE_DDR_CONFIG register defaults to desired
	 * configuration on reset. Currently reprogramming the power on
	 * reset (POR) value in case it might have been modified by
	 * bootloaders. In the future, if this changes, then the desired
	 * values will need to be programmed appropriately.
	 */
	writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr + CORE_DDR_CONFIG);

	/* Write 1 to DDR_CAL_EN field in CORE_DLL_CONFIG_2 */
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG_2)
			| CORE_DDR_CAL_EN),
			host->ioaddr + CORE_DLL_CONFIG_2);

	/* Poll on DDR_DLL_LOCK bit in CORE_DLL_STATUS to be set */
	ret = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
		 dll_status, (dll_status & CORE_DDR_DLL_LOCK), 10, 1000);

	if (ret == -ETIMEDOUT) {
		pr_err("%s: %s: CM_DLL_SDC4 Calibration was not completed\n",
				mmc_hostname(host->mmc), __func__);
		goto out;
	}

	/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */
	writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC3)
			| CORE_PWRSAVE_DLL),
			host->ioaddr + CORE_VENDOR_SPEC3);
	mb();
out:
	pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
			__func__, ret);
	return ret;
}

static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
{
	int ret = 0;
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;

	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);

	/*
	 * Retuning in HS400 (DDR mode) will fail, just reset the
	 * tuning block and restore the saved tuning phase.
	 */
	ret = msm_init_cm_dll(host);
	if (ret)
		goto out;

	/* Set the selected phase in delay line hw block */
	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
	if (ret)
		goto out;

	if (msm_host->use_cdclp533)
		/* Calibrate CDCLP533 DLL HW */
		ret = sdhci_msm_cdclp533_calibration(host);
	else
		/* Calibrate CM_DLL_SDC4 HW */
		ret = sdhci_msm_cm_dll_sdc4_calibration(host);
out:
	pr_debug("%s: Exit %s, ret:%d\n", mmc_hostname(host->mmc),
			__func__, ret);
	return ret;
}

static void sdhci_msm_set_mmc_drv_type(struct sdhci_host *host, u32 opcode,
		u8 drv_type)
{
@@ -901,10 +962,10 @@ int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)

	pr_debug("%s: Enter %s\n", mmc_hostname(mmc), __func__);

	/* CDCLP533 HW calibration is only required for HS400 mode*/
	/* CDC/SDC4 DLL HW calibration is only required for HS400 mode*/
	if (msm_host->tuning_done && !msm_host->calibration_done &&
		(mmc->ios.timing == MMC_TIMING_MMC_HS400)) {
		rc = sdhci_msm_cdclp533_calibration(host);
		rc = sdhci_msm_hs400_dll_calibration(host);
		spin_lock_irqsave(&host->lock, flags);
		if (!rc)
			msm_host->calibration_done = true;
@@ -2382,7 +2443,7 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	struct mmc_ios	curr_ios = host->mmc->ios;
	u32 sup_clock, ddr_clock;
	u32 sup_clock, ddr_clock, dll_lock;
	bool curr_pwrsave;

	if (!clock) {
@@ -2469,7 +2530,27 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
					| CORE_HC_SELECT_IN_EN),
					host->ioaddr + CORE_VENDOR_SPEC);
		}
		if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) {
			/*
			 * Poll on DLL_LOCK and DDR_DLL_LOCK bits in
			 * CORE_DLL_STATUS to be set.  This should get set
			 * with in 15 us at 200 MHz.
			 */
			rc = readl_poll_timeout(host->ioaddr + CORE_DLL_STATUS,
					dll_lock, (dll_lock & (CORE_DLL_LOCK |
					CORE_DDR_DLL_LOCK)), 10, 1000);
			if (rc == -ETIMEDOUT)
				pr_err("%s: Unable to get DLL_LOCK/DDR_DLL_LOCK, dll_status: 0x%08x\n",
						mmc_hostname(host->mmc),
						dll_lock);
		}
	} else {
		if (!msm_host->use_cdclp533)
			/* set CORE_PWRSAVE_DLL bit in CORE_VENDOR_SPEC3 */
			writel_relaxed((readl_relaxed(host->ioaddr +
					CORE_VENDOR_SPEC3) & ~CORE_PWRSAVE_DLL),
					host->ioaddr + CORE_VENDOR_SPEC3);

		/* Select the default clock (free running MCLK) */
		writel_relaxed(((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
					& ~CORE_HC_MCLK_SEL_MASK)
@@ -2671,6 +2752,13 @@ static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
			(readl_relaxed(host->ioaddr + SDHCI_CAPABILITIES) |
			caps), host->ioaddr + CORE_VENDOR_SPEC_CAPABILITIES0);
	}

	/*
	 * SDCC 5 controller with major version 1, minor version 0x34 and later
	 * with HS 400 mode support will use CM DLL instead of CDC LP 533 DLL.
	 */
	if ((major == 1) && (minor < 0x34))
		msm_host->use_cdclp533 = true;
}

static int sdhci_msm_probe(struct platform_device *pdev)
+1 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

struct mmc_ios {
	unsigned int	clock;			/* clock rate */
	unsigned int	old_rate;       /* saved clock rate */
	unsigned short	vdd;

/* vdd stores the bit number of the selected voltage range from below. */