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

Commit 51b62aee authored by Veerabhadrarao Badiganti's avatar Veerabhadrarao Badiganti
Browse files

mmc: sdhci-msm: Support for getting DLL HSR values from dt file



Add support for getting dll hsr setting from device tree file and
to update the dll registers with these HSR settings.

HSR(Hardware Settings Reference) values of DLL specific registers in
SDHC controller would vary based on the process node. Getting these
values through device tree ensure the driver is agnostic of process
node changes.

Use actual clock instead of standard clock rate while configuring DLL
frequency. Otherwise, DLL frequency doesn't match with recommended
HSR value.

With this changes DDR config dt property redundant. So deleting it.

Change-Id: Id5da6189074ed365bef820262563dcb411bf22eb
Signed-off-by: default avatarBao D. Nguyen <nguyenb@codeaurora.org>
Signed-off-by: default avatarCan Guo <cang@codeaurora.org>
Signed-off-by: default avatarVeerabhadrarao Badiganti <vbadigan@codeaurora.org>
parent 3541909b
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -91,11 +91,9 @@ Optional Properties:
	  contents will not be retained. It is software responsibility to restore the
	  SDCC registers before resuming to normal operation.
	- qcom,force-sdhc1-probe: Force probing sdhc1 even if it is not the boot device.
	- qcom,ddr-config: Certain chipsets and platforms require particular settings for
			   the RCLK delay DLL configuration register for HS400 mode to work.
			   This value can vary between platforms and msms. If a msm/platform
			   require a different DLL setting than the default/POR setting for
			   HS400 mode, it can be specified using this field.
	- qcom,dll-hsr-list: List of DLL-HSR values which are tuned for given process-node
			 and platform. The sequence of values in this list must follow the
			 sequence listed in sdhci_msm_dll_hsr data structure.
In the following, <supply> can be vdd (flash core voltage) or vdd-io (I/O voltage).
	- qcom,<supply>-always-on - specifies whether supply should be kept "on" always.
	- qcom,<supply>-lpm_sup - specifies whether supply can be kept in low power mode (lpm).
+131 −44
Original line number Diff line number Diff line
@@ -2,7 +2,7 @@
 * drivers/mmc/host/sdhci-msm.c - Qualcomm Technologies, Inc. MSM SDHCI Platform
 * driver source file
 *
 * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -155,12 +155,12 @@
#define CORE_FLL_CYCLE_CNT	(1 << 18)
#define CORE_DLL_CLOCK_DISABLE	(1 << 21)

#define DDR_CONFIG_POR_VAL		0x80040853
#define DDR_CONFIG_PRG_RCLK_DLY_MASK	0x1FF
#define DDR_CONFIG_PRG_RCLK_DLY		115
#define DDR_CONFIG_2_POR_VAL		0x80040873
#define DDR_CONFIG_POR_VAL		0x80040873
#define DLL_USR_CTL_POR_VAL		0x10800
#define ENABLE_DLL_LOCK_STATUS		(1 << 26)
#define FINE_TUNE_MODE_EN		(1 << 27)
#define BIAS_OK_SIGNAL			(1 << 29)
#define DLL_CONFIG_3_POR_VAL		0x10

/* 512 descriptors */
#define SDHCI_MSM_MAX_SEGMENTS  (1 << 9)
@@ -203,8 +203,9 @@ struct sdhci_msm_offset {
	u32 CORE_DDR_200_CFG;
	u32 CORE_VENDOR_SPEC3;
	u32 CORE_DLL_CONFIG_2;
	u32 CORE_DLL_CONFIG_3;
	u32 CORE_DDR_CONFIG;
	u32 CORE_DDR_CONFIG_2;
	u32 CORE_DDR_CONFIG_OLD; /* Applcable to sddcc minor ver < 0x49 only */
	u32 CORE_DLL_USR_CTL; /* Present on SDCC5.1 onwards */
};

@@ -233,8 +234,8 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_removed = {
	.CORE_DDR_200_CFG = 0x224,
	.CORE_VENDOR_SPEC3 = 0x250,
	.CORE_DLL_CONFIG_2 = 0x254,
	.CORE_DDR_CONFIG = 0x258,
	.CORE_DDR_CONFIG_2 = 0x25C,
	.CORE_DLL_CONFIG_3 = 0x258,
	.CORE_DDR_CONFIG = 0x25C,
	.CORE_DLL_USR_CTL = 0x388,
};

@@ -263,8 +264,9 @@ struct sdhci_msm_offset sdhci_msm_offset_mci_present = {
	.CORE_DDR_200_CFG = 0x184,
	.CORE_VENDOR_SPEC3 = 0x1B0,
	.CORE_DLL_CONFIG_2 = 0x1B4,
	.CORE_DDR_CONFIG = 0x1B8,
	.CORE_DDR_CONFIG_2 = 0x1BC,
	.CORE_DLL_CONFIG_3 = 0x1B8,
	.CORE_DDR_CONFIG_OLD = 0x1B8, /* Applicable to sdcc minor ver < 0x49 */
	.CORE_DDR_CONFIG = 0x1BC,
};

u8 sdhci_msm_readb_relaxed(struct sdhci_host *host, u32 offset)
@@ -366,6 +368,9 @@ enum vdd_io_level {
	VDD_IO_SET_LEVEL,
};

static unsigned int sdhci_msm_get_sup_clk_rate(struct sdhci_host *host,
						u32 req_clk);

/* MSM platform specific tuning */
static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host,
						u8 poll)
@@ -530,11 +535,13 @@ static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
	 * Write the selected DLL clock output phase (0 ... 15)
	 * to CDR_SELEXT bit field of DLL_CONFIG register.
	 */
	if (msm_host->dll_hsr->dll_config & (0xF << 20)) {
		writel_relaxed(((readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_CONFIG)
			& ~(0xF << 20))
			| (grey_coded_phase_table[phase] << 20)),
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
	}

	/* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
	writel_relaxed((readl_relaxed(host->ioaddr +
@@ -763,17 +770,30 @@ static int msm_init_cm_dll(struct sdhci_host *host)
	writel_relaxed((readl_relaxed(host->ioaddr +
		msm_host_offset->CORE_DLL_CONFIG) | CORE_DLL_PDN),
		host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
	msm_cm_dll_set_freq(host);

	if (msm_host->use_updated_dll_reset) {
		u32 mclk_freq = 0;
		u32 actual_clk = sdhci_msm_get_sup_clk_rate(host, host->clock);

		switch (actual_clk) {
		case 202000000:
		case 201500000:
		case 200000000:
			mclk_freq = 42;
			break;
		case 192000000:
			mclk_freq = 40;
			break;
		default:
			mclk_freq = (u32)((actual_clk / TCXO_FREQ) * 4);
			pr_info_once("%s: %s: Non standard clk freq =%u\n",
			mmc_hostname(mmc), __func__, actual_clk);
		}

		if ((readl_relaxed(host->ioaddr +
					msm_host_offset->CORE_DLL_CONFIG_2)
					& CORE_FLL_CYCLE_CNT))
			mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 8);
		else
			mclk_freq = (u32) ((host->clock / TCXO_FREQ) * 4);
			mclk_freq *= 2;

		writel_relaxed(((readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_CONFIG_2)
@@ -794,7 +814,6 @@ static int msm_init_cm_dll(struct sdhci_host *host)
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);

	if (msm_host->use_updated_dll_reset) {
		msm_cm_dll_set_freq(host);
		/* Enable the DLL clock */
		writel_relaxed((readl_relaxed(host->ioaddr +
				msm_host_offset->CORE_DLL_CONFIG_2)
@@ -804,11 +823,39 @@ static int msm_init_cm_dll(struct sdhci_host *host)

	/*
	 * Configure DLL user control register to enable DLL status
	 * This setting is applicable to SDCC v5.1 onwards only
	 * This setting is applicable to SDCC v5.1 onwards only.
	 *
	 * Configure Tassadar DLL (Only applicable for 7FF projects)
	 *
	 */
	if (msm_host->need_dll_user_ctl) {
		writel_relaxed(DLL_USR_CTL_POR_VAL | ENABLE_DLL_LOCK_STATUS,
			host->ioaddr + msm_host_offset->CORE_DLL_USR_CTL);
		if (msm_host->dll_hsr) {
			writel_relaxed(msm_host->dll_hsr->dll_usr_ctl,
					host->ioaddr +
					msm_host_offset->CORE_DLL_USR_CTL);
			writel_relaxed(msm_host->dll_hsr->dll_config_3,
					host->ioaddr +
					msm_host_offset->CORE_DLL_CONFIG_3);
		} else {
			writel_relaxed(DLL_USR_CTL_POR_VAL | FINE_TUNE_MODE_EN |
					ENABLE_DLL_LOCK_STATUS | BIAS_OK_SIGNAL,
					host->ioaddr +
					msm_host_offset->CORE_DLL_USR_CTL);

			writel_relaxed(DLL_CONFIG_3_POR_VAL, host->ioaddr +
				msm_host_offset->CORE_DLL_CONFIG_3);
		}
	}

	/*
	 * Update the lower byte of DLL_CONFIG only with HSR values.
	 * Since these are the static settings.
	 */
	if (msm_host->dll_hsr) {
		writel_relaxed(((readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_CONFIG) & (~0xff)) |
			(msm_host->dll_hsr->dll_config & 0xff)),
			host->ioaddr + msm_host_offset->CORE_DLL_CONFIG);
	}

	/* Set DLL_EN bit to 1. */
@@ -976,7 +1023,7 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
	struct sdhci_msm_host *msm_host = pltfm_host->priv;
	const struct sdhci_msm_offset *msm_host_offset =
					msm_host->offset;
	u32 dll_status, ddr_config;
	u32 dll_status;
	int ret = 0;

	pr_debug("%s: Enter %s\n", mmc_hostname(host->mmc), __func__);
@@ -987,16 +1034,16 @@ static int sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
	 */
	if (msm_host->pdata->rclk_wa) {
		writel_relaxed(msm_host->pdata->ddr_config, host->ioaddr +
			msm_host_offset->CORE_DDR_CONFIG_2);
			msm_host_offset->CORE_DDR_CONFIG);
	} else if (msm_host->dll_hsr && msm_host->dll_hsr->ddr_config) {
		writel_relaxed(msm_host->dll_hsr->ddr_config, host->ioaddr +
			msm_host_offset->CORE_DDR_CONFIG);
	} else if (msm_host->rclk_delay_fix) {
		writel_relaxed(DDR_CONFIG_2_POR_VAL, host->ioaddr +
			msm_host_offset->CORE_DDR_CONFIG_2);
	} else {
		ddr_config = DDR_CONFIG_POR_VAL &
				~DDR_CONFIG_PRG_RCLK_DLY_MASK;
		ddr_config |= DDR_CONFIG_PRG_RCLK_DLY;
		writel_relaxed(ddr_config, host->ioaddr +
		writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr +
			msm_host_offset->CORE_DDR_CONFIG);
	} else {
		writel_relaxed(DDR_CONFIG_POR_VAL, host->ioaddr +
			msm_host_offset->CORE_DDR_CONFIG_OLD);
	}

	if (msm_host->enhanced_strobe && mmc_card_strobe(msm_host->mmc->card))
@@ -1100,12 +1147,13 @@ static int sdhci_msm_hs400_dll_calibration(struct sdhci_host *host)
	ret = msm_config_cm_dll_phase(host, msm_host->saved_tuning_phase);
	if (ret)
		goto out;

	if (msm_host->dll_hsr->dll_config & CORE_CMD_DAT_TRACK_SEL) {
		/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
		writel_relaxed((readl_relaxed(host->ioaddr +
				msm_host_offset->CORE_DLL_CONFIG)
				| CORE_CMD_DAT_TRACK_SEL), host->ioaddr +
				msm_host_offset->CORE_DLL_CONFIG);
	}

	if (msm_host->use_cdclp533)
		/* Calibrate CDCLP533 DLL HW */
@@ -1965,6 +2013,32 @@ static int sdhci_msm_get_socrev(struct device *dev,
}
#endif

static int sdhci_msm_dt_parse_hsr_info(struct device *dev,
		struct sdhci_msm_host *msm_host)

{
	u32 *dll_hsr_table = NULL;
	int dll_hsr_table_len, dll_hsr_reg_count;
	int ret = 0;

	if (sdhci_msm_dt_get_array(dev, "qcom,dll-hsr-list",
			&dll_hsr_table, &dll_hsr_table_len, 0))
		goto skip_hsr;

	dll_hsr_reg_count = sizeof(struct sdhci_msm_dll_hsr) / sizeof(u32);
	if (dll_hsr_table_len != dll_hsr_reg_count) {
		dev_err(dev, "Number of HSR entries are not matching\n");
		ret = -EINVAL;
	} else {
		msm_host->dll_hsr = (struct sdhci_msm_dll_hsr *)dll_hsr_table;
	}

skip_hsr:
	if (!msm_host->dll_hsr)
		dev_info(dev, "Failed to get dll hsr settings from dt\n");
	return ret;
}

/* Parse platform data */
static
struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
@@ -2142,6 +2216,9 @@ struct sdhci_msm_pltfm_data *sdhci_msm_populate_pdata(struct device *dev,
	if (!of_property_read_u32(np, "qcom,ddr-config", &pdata->ddr_config))
		pdata->rclk_wa = true;

	if (sdhci_msm_dt_parse_hsr_info(dev, msm_host))
		goto out;

	/*
	 * rclk_wa is not required if soc version is mentioned and
	 * is not base version.
@@ -3512,9 +3589,9 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
			 * DLL input clock
			 */
			writel_relaxed(((readl_relaxed(host->ioaddr +
				msm_host_offset->CORE_DDR_CONFIG))
				msm_host_offset->CORE_DLL_CONFIG_3))
				| RCLK_TOGGLE), host->ioaddr +
				msm_host_offset->CORE_DDR_CONFIG);
				msm_host_offset->CORE_DLL_CONFIG_3);
			/* ensure above write as toggling same bit quickly */
			wmb();
			udelay(2);
@@ -3523,9 +3600,9 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
			 * DLL input clock
			 */
			writel_relaxed(((readl_relaxed(host->ioaddr +
				msm_host_offset->CORE_DDR_CONFIG))
				msm_host_offset->CORE_DLL_CONFIG_3))
				& ~RCLK_TOGGLE), host->ioaddr +
				msm_host_offset->CORE_DDR_CONFIG);
				msm_host_offset->CORE_DLL_CONFIG_3);
		}
		if (!host->mmc->ios.old_rate && !msm_host->use_cdclp533) {
			/*
@@ -3768,24 +3845,34 @@ void sdhci_msm_dump_vendor_regs(struct sdhci_host *host)
			msm_host_offset->CORE_MCI_FIFO_CNT),
		sdhci_msm_readl_relaxed(host,
			msm_host_offset->CORE_MCI_STATUS));
	pr_info("DLL cfg:  0x%08x | DLL sts:  0x%08x | SDCC ver: 0x%08x\n",
	pr_info("DLL sts: 0x%08x | DLL cfg:  0x%08x | DLL cfg2: 0x%08x\n",
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_STATUS),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_CONFIG),
		sdhci_msm_readl_relaxed(host,
			msm_host_offset->CORE_DLL_CONFIG_2));
	pr_info("DLL cfg3: 0x%08x | DLL usr ctl:  0x%08x | DDR cfg: 0x%08x\n",
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_STATUS),
			msm_host_offset->CORE_DLL_CONFIG_3),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_DLL_USR_CTL),
		sdhci_msm_readl_relaxed(host,
			msm_host_offset->CORE_MCI_VERSION));
	pr_info("Vndr func: 0x%08x | Vndr adma err : addr0: 0x%08x addr1: 0x%08x\n",
			msm_host_offset->CORE_DDR_CONFIG));
	pr_info("SDCC ver: 0x%08x | Vndr adma err : addr0: 0x%08x addr1: 0x%08x\n",
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC),
			msm_host_offset->CORE_MCI_VERSION),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC_ADMA_ERR_ADDR0),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC_ADMA_ERR_ADDR1));
	pr_info("Vndr func2: 0x%08x\n",
	pr_info("Vndr func: 0x%08x | Vndr func2 : 0x%08x Vndr func3: 0x%08x\n",
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC_FUNC2));

			msm_host_offset->CORE_VENDOR_SPEC),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC_FUNC2),
		readl_relaxed(host->ioaddr +
			msm_host_offset->CORE_VENDOR_SPEC3));
	/*
	 * tbsel indicates [2:0] bits and tbsel2 indicates [7:4] bits
	 * of CORE_TESTBUS_CONFIG register.
+15 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -197,6 +197,19 @@ struct sdhci_msm_regs_restore {
	u32 testbus_config;
};

/*
 * DLL registers which needs be programmed with HSR settings.
 * Add any new register only at the end and don't change the
 * seqeunce.
 */
struct sdhci_msm_dll_hsr {
	u32 dll_config;
	u32 dll_config_2;
	u32 dll_config_3;
	u32 dll_usr_ctl;
	u32 ddr_config;
};

struct sdhci_msm_debug_data {
	struct mmc_host copy_mmc;
	struct mmc_card copy_card;
@@ -258,6 +271,7 @@ struct sdhci_msm_host {
	int soc_min_rev;
	struct workqueue_struct *pm_qos_wq;
	bool need_dll_user_ctl;
	struct sdhci_msm_dll_hsr *dll_hsr;
};

extern char *saved_command_line;