platform: msm_shared: Add support for cm_dll calibration

Sdcc version 3.3.0 uses cm dll4 circuit for hs400 calibration,
add support to perform the calibration based on the sdcc version.
Also ignore the cmd end bit mask during tuning.

CRs-Fixed: 636132
Change-Id: I3ee0d3dbe5acd3fcd3a948d736a83431a309ee52
diff --git a/platform/msm_shared/include/sdhci.h b/platform/msm_shared/include/sdhci.h
index 1a61ee3..beebb09 100644
--- a/platform/msm_shared/include/sdhci.h
+++ b/platform/msm_shared/include/sdhci.h
@@ -68,6 +68,9 @@
 	uint32_t cur_clk_rate;   /* Running clock rate */
 	uint32_t timing;         /* current timing for the host */
 	bool tuning_in_progress; /* Tuning is being executed */
+	uint8_t major;           /* host controller minor ver */
+	uint16_t minor;          /* host controller major ver */
+	bool use_cdclp533;       /* Use cdclp533 calibration circuit */
 	event_t* sdhc_event;     /* Event for power control irqs */
 	struct host_caps caps;   /* Host capabilities */
 	struct sdhci_msm_data *msm_host; /* MSM specific host info */
diff --git a/platform/msm_shared/include/sdhci_msm.h b/platform/msm_shared/include/sdhci_msm.h
index ea8a1a3..897a988 100644
--- a/platform/msm_shared/include/sdhci_msm.h
+++ b/platform/msm_shared/include/sdhci_msm.h
@@ -58,6 +58,17 @@
 #define SDCC_CDC_SLAVE_DDA_CFG                   0x160
 #define SDCC_CSR_CDC_STATUS0                     0x164
 
+/* Macros for CM_DLL_SDC4 related macros */
+#define SDCC_HC_VENDOR_SPECIFIC_FUNC3            0x1B0
+#define SDCC_HC_REG_DLL_CONFIG_2                 0x1B4
+#define SDCC_HC_REG_DDR_CONFIG                   0x1B8
+
+#define DDR_CAL_EN                               BIT(0)
+#define DDR_CAL_TIMEOUT_MAX                      50
+#define DDR_DLL_LOCK_JDR                         BIT(11)
+#define PWRSAVE_DLL                              BIT(3)
+#define DDR_CONFIG_VAL                           0x80040853
+
 /* DLL & CDC helper macros */
 #define SDCC_DLL_PWR_SAVE_EN                      BIT(1)
 #define SDCC_DLL_LOCK_STAT                        BIT(7)
@@ -102,6 +113,7 @@
 #define MCI_VERSION                               0x50
 #define CORE_VERSION_MAJOR_MASK                   0xF0000000
 #define CORE_VERSION_MAJOR_SHIFT                  0x1C
+#define CORE_VERSION_MINOR_MASK                   0x000000FF
 
 #define SDHCI_DLL_TIMEOUT                         50
 #define CDC_STATUS_TIMEOUT                        50
diff --git a/platform/msm_shared/sdhci.c b/platform/msm_shared/sdhci.c
index ebaf942..a7f2258 100644
--- a/platform/msm_shared/sdhci.c
+++ b/platform/msm_shared/sdhci.c
@@ -449,7 +449,7 @@
 		if (host->tuning_in_progress)
 		{
 			err_status = REG_READ16(host, SDHCI_ERR_INT_STS_REG);
-			if ((err_status & SDHCI_CMD_CRC_MASK) || (err_status & SDHCI_DAT_END_BIT_MASK)
+			if ((err_status & SDHCI_CMD_CRC_MASK) || (err_status & SDHCI_CMD_END_BIT_MASK)
 				|| err_status & SDHCI_CMD_TIMEOUT_MASK)
 			{
 				sdhci_reset(host, (SOFT_RESET_CMD | SOFT_RESET_DATA));
@@ -899,6 +899,7 @@
 void sdhci_init(struct sdhci_host *host)
 {
 	uint32_t caps[2];
+	uint32_t version;
 
 	/* Read the capabilities register & store the info */
 	caps[0] = REG_READ32(host, SDHCI_CAPS_REG1);
@@ -938,6 +939,16 @@
 	/* SDR104 mode support */
 	host->caps.sdr104_support = (caps[1] & SDHCI_SDR104_MODE_MASK) ? 1 : 0;
 
+	version = readl(host->msm_host->pwrctl_base + MCI_VERSION);
+
+	host->major = (version & CORE_VERSION_MAJOR_MASK) >> CORE_VERSION_MAJOR_SHIFT;
+	host->minor = (version & CORE_VERSION_MINOR_MASK);
+
+	if (host->major == 0x1 && host->minor < 0x34)
+		host->use_cdclp533 = true;
+	else
+		host->use_cdclp533 = false;
+
 	/* Set bus power on */
 	sdhci_set_bus_power_on(host);
 
diff --git a/platform/msm_shared/sdhci_msm.c b/platform/msm_shared/sdhci_msm.c
index 5c1a09e..fcf2f4b 100644
--- a/platform/msm_shared/sdhci_msm.c
+++ b/platform/msm_shared/sdhci_msm.c
@@ -454,6 +454,39 @@
 	return selected_phase;
 }
 
+static uint32_t sdhci_msm_cm_dll_sdc4_calibration(struct sdhci_host *host)
+{
+	uint32_t timeout = 0;
+
+	DBG("\n CM_DLL_SDC4 Calibration Start\n");
+
+	/*1.Write the default value to  SDCC_HC_REG_DDR_CONFIG register*/
+	REG_WRITE32(host, DDR_CONFIG_VAL, SDCC_HC_REG_DDR_CONFIG);
+
+	/*2. Write DDR_CAL_EN to '1' */
+	REG_WRITE32(host, (REG_READ32(host, SDCC_HC_REG_DLL_CONFIG_2) | DDR_CAL_EN), SDCC_HC_REG_DLL_CONFIG_2);
+
+	/*3. Wait for DLL_LOCK for hs400 to be set */
+	timeout = DDR_CAL_TIMEOUT_MAX;
+	while (!(REG_READ32(host, SDCC_REG_DLL_STATUS) & DDR_DLL_LOCK_JDR))
+	{
+		timeout--;
+		mdelay(1);
+		if (!timeout)
+		{
+			dprintf(CRITICAL, "Error: DLL lock for hs400 operation is not set\n");
+			return 1;
+		}
+	}
+
+	/*4. Set powersave dll */
+	REG_WRITE32(host, (REG_READ32(host, SDCC_HC_VENDOR_SPECIFIC_FUNC3) | PWRSAVE_DLL), SDCC_HC_VENDOR_SPECIFIC_FUNC3);
+
+	DBG("\n CM_DLL_SDC4 Calibration Done\n");
+
+	return 0;
+}
+
 static uint32_t sdhci_msm_cdclp533_calibration(struct sdhci_host *host)
 {
 	uint32_t timeout;
@@ -461,17 +494,6 @@
 
 	DBG("\n CDCLP533 Calibration Start\n");
 
-	/* Reset & Initialize the DLL block */
-	if (sdhci_msm_init_dll(host))
-		return 1;
-
-	/* Write the save phase */
-	if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
-		return 1;
-
-	/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
-	REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
-
 	/* Write 0 to CDC_T4_DLY_SEL field in VENDOR_SPEC_DDR200_CFG */
 	REG_WRITE32(host, (REG_READ32(host, SDCC_CDC_DDR200_CFG) & ~CDC_T4_DLY_SEL), SDCC_CDC_DDR200_CFG);
 
@@ -548,11 +570,37 @@
 	return 0;
 }
 
+
+static uint32_t sdhci_msm_hs400_calibration(struct sdhci_host *host)
+{
+	DBG("\n HS400 Calibration Start\n");
+
+	/* Reset & Initialize the DLL block */
+	if (sdhci_msm_init_dll(host))
+		return 1;
+
+	/* Write the save phase */
+	if (sdhci_msm_config_dll(host, host->msm_host->saved_phase))
+		return 1;
+
+	/* Write 1 to CMD_DAT_TRACK_SEL field in DLL_CONFIG */
+	REG_WRITE32(host, (REG_READ32(host, SDCC_DLL_CONFIG_REG) | CMD_DAT_TRACK_SEL), SDCC_DLL_CONFIG_REG);
+
+	if (host->use_cdclp533)
+		return sdhci_msm_cdclp533_calibration(host);
+	else
+		return sdhci_msm_cm_dll_sdc4_calibration(host);
+
+	DBG("\n HS400 Calibration Done\n");
+
+	return 0;
+}
+
 /*
  * Function: sdhci msm execute tuning
  * Arg     : Host structure & bus width
  * Return  : 0 on Success, 1 on Failure
- * Flow:   : Execute Tuning sequence for HS200
+ * Flow:   : Execute Tuning sequence for HS200 and calibration for hs400
  */
 uint32_t sdhci_msm_execute_tuning(struct sdhci_host *host, struct mmc_card *card, uint32_t bus_width)
 {
@@ -576,7 +624,7 @@
 	/* Calibration for CDCLP533 needed for HS400 mode */
 	if (msm_host->tuning_done && !msm_host->calibration_done && host->timing == MMC_HS400_TIMING)
 	{
-		ret = sdhci_msm_cdclp533_calibration(host);
+		ret = sdhci_msm_hs400_calibration(host);
 		if (!ret)
 			msm_host->calibration_done = true;
 		goto out;