clk: mdss-dsi-pll: add support for auto PLL calculator for 20nm PHY

Add code to support DSI auto PLL calculator for 8994 platform
that uses 20nm physical layer. Update the PLL configuration
and DSI PHY regulator configurations to the recommended
settings.

Change-Id: Ia3d7042d537539491317f99d7bcc2c480f850216
Signed-off-by: Chandan Uddaraju <chandanu@codeaurora.org>
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c b/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
index ac0bbc7..c65c647 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c
@@ -53,7 +53,7 @@
 #define MMSS_DSI_PHY_PLL_KVCO_CODE			0x0074
 #define MMSS_DSI_PHY_PLL_VREF_CFG1			0x0078
 #define MMSS_DSI_PHY_PLL_VREF_CFG2			0x007C
-#define MMSS_DSI_PHY_PLL_VREF_CFG3			0x0000
+#define MMSS_DSI_PHY_PLL_VREF_CFG3			0x0080
 #define MMSS_DSI_PHY_PLL_VREF_CFG4			0x0084
 #define MMSS_DSI_PHY_PLL_VREF_CFG5			0x0088
 #define MMSS_DSI_PHY_PLL_VREF_CFG6			0x008C
@@ -99,8 +99,8 @@
 #define MMSS_DSI_PHY_PLL_PLL_VCO_HIGH			0x014C
 #define MMSS_DSI_PHY_PLL_RESET_SM			0x0150
 
-#define DSI_PLL_POLL_MAX_READS			10
-#define DSI_PLL_POLL_TIMEOUT_US			500
+#define DSI_PLL_POLL_MAX_READS			15
+#define DSI_PLL_POLL_TIMEOUT_US			1000
 
 
 int set_bypass_lp_div_mux_sel(struct mux_clk *clk, int sel)
@@ -329,7 +329,7 @@
 	dsi_pll_res->handoff_resources = false;
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x00);
+				MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x02);
 
 	mdss_pll_resource_enable(dsi_pll_res, false);
 	dsi_pll_res->pll_on = false;
@@ -337,61 +337,7 @@
 	pr_debug("DSI PLL Disabled\n");
 }
 
-void pll_20nm_dsi_phy_ctrl_config(struct mdss_pll_resources *dsi_pll_res,
-							int off)
-{
-	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x80);
-	/* memory barrier */
-	wmb();
-
-	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x00);
-	/* Strength ctrl 0 */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0184, 0x77);
-	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0170, 0x7f);
-	/* memory barrier */
-	wmb();
-
-	/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x01d4, 0x00);
-
-	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_2 */
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x00);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x02);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x03);
-}
-
-static void pll_20nm_phy_kvco_config(struct dsi_pll_vco_clk *vco)
-{
-	struct mdss_pll_resources *dsi_pll_res = vco->priv;
-
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF1, 0x00);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF2, 0x00);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_KVCO_COUNT1, 0x00);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL, 0x00);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_KVCO_CODE, 0x2A);
-}
-
-static void pll_20nm_phy_loop_bw_config(struct mdss_pll_resources *dsi_pll_res)
-{
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_IP_SETI, 0x01);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_CP_SETI, 0x2F);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_IP_SETP, 0x13);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_CP_SETP, 0x0F);
-	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_CRCTRL, 0x24);
-}
-
-static void pll_20nm_phy_reset_st_machine_ctrl
+static inline void pll_20nm_phy_reset_state_machine_ctrl
 			(struct mdss_pll_resources *dsi_pll_res)
 {
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
@@ -402,15 +348,67 @@
 				MMSS_DSI_PHY_PLL_RES_TRIM_CONTROL, 0x15);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_RESETSM_CNTRL, 0xf4);
+				MMSS_DSI_PHY_PLL_RESETSM_CNTRL, 0x20);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_RESETSM_CNTRL2, 0x0f);
+				MMSS_DSI_PHY_PLL_RESETSM_CNTRL2, 0x07);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x03);
 }
 
+void dsi_pll_20nm_phy_ctrl_config(struct mdss_pll_resources *dsi_pll_res,
+							int off)
+{
+	pll_20nm_phy_reset_state_machine_ctrl(dsi_pll_res);
+	/* memory barrier */
+	wmb();
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x80);
+	udelay(1000);
+
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_1 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0174, 0x00);
+	/* Strength ctrl 0 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0184, 0x77);
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_0 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0170, 0x7f);
+
+	/* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x01d4, 0x00);
+
+	/* MMSS_DSI_0_PHY_DSIPHY_CTRL_2 */
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, off + 0x0178, 0x00);
+}
+
+static void pll_20nm_phy_kvco_config(struct dsi_pll_vco_clk *vco)
+{
+	struct mdss_pll_resources *dsi_pll_res = vco->priv;
+
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF1, 0x00);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_DIV_REF2, 0x01);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_KVCO_COUNT1, 0x8A);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_KVCO_CAL_CNTRL, 0x00);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_KVCO_CODE, 0x00);
+}
+
+static void pll_20nm_phy_loop_bw_config(struct mdss_pll_resources *dsi_pll_res)
+{
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_PLL_IP_SETI, 0x03);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_PLL_CP_SETI, 0x3F);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_PLL_IP_SETP, 0x03);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_PLL_CP_SETP, 0x1F);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_PLL_CRCTRL, 0x77);
+}
+
 static void pll_20nm_phy_config(struct dsi_pll_vco_clk *vco)
 {
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
@@ -448,11 +446,15 @@
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_VREF_CFG2, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_VREF_CFG3, 0x10);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
+				MMSS_DSI_PHY_PLL_VREF_CFG4, 0x00);
+	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_BGTC, 0x0F);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_PLL_TEST_UPDN, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_PLL_VCO_TUNE, 0x01);
+				MMSS_DSI_PHY_PLL_PLL_VCO_TUNE, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_PLL_AMP_OS, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
@@ -462,7 +464,7 @@
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_RES_CODE_DN, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_RES_CODE_CAL_CSR, 0x77);
+				MMSS_DSI_PHY_PLL_RES_CODE_CAL_CSR, 0x00);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_RES_TRIM_EN_VCOCALDONE, 0x0);
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
@@ -479,61 +481,104 @@
 int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate)
 {
 	s64 vco_clk_rate = rate;
-	s32 div_frac_start, frac_act_div;
-	s64 dec_start;
-	s64 duration, pll_comp_val;
+	s32 div_frac_start;
+	s32 div_frac_start1, div_frac_start2, div_frac_start3;
+	s64 dec_start_multiple, dec_start, multiplier = (1 << 20);
+	s64 dec_start1, dec_start2;
+	s64 duration = 128, pll_comp_val;
+	s64 pll_plllock_cmp1, pll_plllock_cmp2, pll_plllock_cmp3;
+
 	struct mdss_pll_resources *dsi_pll_res = vco->priv;
 
-	pr_debug("%s: vco set rate: %ld\n", __func__, rate);
+	pr_debug("%s: vco set rate: %lld\n", __func__, vco_clk_rate);
 	pll_20nm_phy_config(vco);
 
-	dec_start = div_s64(vco_clk_rate, 2 * vco->ref_clk_rate);
-	div_s64_rem(vco_clk_rate,
-			2 * vco->ref_clk_rate, &frac_act_div);
-	div_frac_start = frac_act_div << 18;
+	dec_start_multiple = div_s64(vco_clk_rate * multiplier,
+					2 * vco->ref_clk_rate);
+	div_s64_rem(dec_start_multiple,
+			multiplier, &div_frac_start);
+
+	dec_start = div_s64(dec_start_multiple, multiplier);
+	pr_debug("%s: dec_start_multiple = 0x%llx\n",
+				__func__, dec_start_multiple);
+	pr_debug("%s: dec_start = 0x%llx, div_frac_start = 0x%x\n",
+			__func__, dec_start, div_frac_start);
+
+	dec_start1 = (dec_start & 0x7f) | BIT(7);
+	dec_start2 = ((dec_start & 0x80) >> 7) | BIT(1);
+	pr_debug("%s: dec_start1 = 0x%llx, dec_start2 = 0x%llx\n",
+				__func__, dec_start1, dec_start2);
+
+	div_frac_start1 = (div_frac_start & 0x7f) | BIT(7);
+	div_frac_start2 = ((div_frac_start >> 7) & 0x7f) | BIT(7);
+	div_frac_start3 = ((div_frac_start >> 14) & 0x3f) | BIT(6);
+	pr_debug("%s: div_frac_start1 = 0x%x\n",
+				__func__, div_frac_start1);
+	pr_debug("%s: div_frac_start2 = 0x%x\n",
+				__func__, div_frac_start2);
+	pr_debug("%s: div_frac_start3 = 0x%x\n",
+				__func__, div_frac_start3);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_DIV_FRAC_START1, 0xd5);
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START1,
+			div_frac_start1);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_DIV_FRAC_START2, 0xaa);
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START2,
+			div_frac_start2);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-			MMSS_DSI_PHY_PLL_DIV_FRAC_START3, 0x79);
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START3,
+			div_frac_start3);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_DEC_START1, 0xac);
+			MMSS_DSI_PHY_PLL_DEC_START1,
+			dec_start1);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_DEC_START2, 0x2);
+			MMSS_DSI_PHY_PLL_DEC_START2,
+			dec_start2);
 
-	duration = 128;
-	pll_comp_val = div_s64(div_s64(vco_clk_rate,
-				2 * vco->ref_clk_rate)
-				* (duration - 1), 10);
+	pll_comp_val = div_s64(dec_start_multiple * 2 * (duration - 1),
+				10 * multiplier);
+
+	pr_debug("%s: pll_comp_val = 0x%llx\n", __func__, pll_comp_val);
+
+	pll_plllock_cmp1 = pll_comp_val & 0xff;
+	pll_plllock_cmp2 = (pll_comp_val >> 8) & 0xff;
+	pll_plllock_cmp3 = (pll_comp_val >> 16) & 0xff;
+	pr_debug("%s: pll_plllock_cmp1 = 0x%llx\n",
+				__func__, pll_plllock_cmp1);
+	pr_debug("%s: pll_plllock_cmp2 = 0x%llx\n",
+				__func__, pll_plllock_cmp2);
+	pr_debug("%s: pll_plllock_cmp3 = 0x%llx\n",
+				__func__, pll_plllock_cmp3);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_PLLLOCK_CMP1, 0x74);
+			MMSS_DSI_PHY_PLL_PLLLOCK_CMP1,
+			pll_plllock_cmp1);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_PLLLOCK_CMP2, 0x04);
+			MMSS_DSI_PHY_PLL_PLLLOCK_CMP2,
+			pll_plllock_cmp2);
 
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
-		       MMSS_DSI_PHY_PLL_PLLLOCK_CMP3, 0x00);
+			MMSS_DSI_PHY_PLL_PLLLOCK_CMP3,
+			pll_plllock_cmp3);
 
 	/*
 	 * Make sure that PLL vco configuration is complete
 	 * before controlling the state machine.
 	 */
-	mb();
 	udelay(1000);
-	pll_20nm_phy_reset_st_machine_ctrl(dsi_pll_res);
+	/* memory barrier */
+	wmb();
 	return 0;
 }
 
 unsigned long pll_20nm_vco_get_rate(struct clk *c)
 {
-	u64 vco_rate;
+	u64 vco_rate, multiplier = (1 << 20);
 	s32 div_frac_start;
 	u32 dec_start;
 	struct dsi_pll_vco_clk *vco = to_vco_clk(c);
@@ -547,27 +592,25 @@
 		return rc;
 	}
 
-	dec_start = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
-				 MMSS_DSI_PHY_PLL_DEC_START2) << 7;
-	dec_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base,
-				 MMSS_DSI_PHY_PLL_DEC_START1);
+	dec_start = (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			MMSS_DSI_PHY_PLL_DEC_START2) & BIT(0)) << 7;
+	dec_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			MMSS_DSI_PHY_PLL_DEC_START1) & 0x7f);
+	pr_debug("%s: dec_start = 0x%x\n", __func__, dec_start);
 
-	div_frac_start = MDSS_PLL_REG_R(dsi_pll_res->pll_base,
-				 MMSS_DSI_PHY_PLL_DIV_FRAC_START3) << 14;
+	div_frac_start = (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START3) & 0x3f) << 14;
 	div_frac_start |= (MDSS_PLL_REG_R(dsi_pll_res->pll_base,
-				MMSS_DSI_PHY_PLL_DIV_FRAC_START2) << 7);
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START2) & 0x7f) << 7;
 	div_frac_start |= MDSS_PLL_REG_R(dsi_pll_res->pll_base,
-				 MMSS_DSI_PHY_PLL_DIV_FRAC_START1);
+			MMSS_DSI_PHY_PLL_DIV_FRAC_START1) & 0x7f;
+	pr_debug("%s: div_frac_start = 0x%x\n",
+			__func__, div_frac_start);
 
-	vco_rate = ref_clk * 2 * (dec_start + (div_frac_start >> 18));
-	pr_debug("vco rate = %lld", vco_rate);
-
-	/*
-	 * TODO: Currently, the dyanmic vco calculator is not finalized.
-	 * Hardcoding the vco_rate for now.
-	 */
-	vco_rate = 1708439040;
-	pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate);
+	vco_rate = ref_clk * 2 * dec_start;
+	vco_rate += ((ref_clk * 2 * div_frac_start) / multiplier);
+	pr_debug("%s: returning vco rate = %lu\n",
+			__func__, (unsigned long)vco_rate);
 
 	mdss_pll_resource_enable(dsi_pll_res, false);
 
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
index 5b6b4b9..19738df 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
@@ -65,7 +65,12 @@
 	MDSS_PLL_REG_W(dsi_pll_res->pll_base,
 				MMSS_DSI_PHY_PLL_PLL_BKG_KVCO_CAL_EN, 0x00);
 	udelay(500);
-	pll_20nm_dsi_phy_ctrl_config(dsi_pll_res, 0x200); /* Ctrl 0 */
+	dsi_pll_20nm_phy_ctrl_config(dsi_pll_res, 0x200); /* Ctrl 0 */
+	/*
+	 * Make sure that the PHY controller configurations are completed
+	 * before checking the pll lock status.
+	 */
+	wmb();
 	pll_locked = dsi_20nm_pll_lock_status(dsi_pll_res);
 	if (!pll_locked) {
 		pr_err("DSI PLL lock failed\n");
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll.h b/drivers/clk/qcom/mdss/mdss-dsi-pll.h
index b0135dc..1060bc4 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll.h
@@ -68,7 +68,7 @@
 int analog_set_div(struct div_clk *clk, int div);
 int analog_get_div(struct div_clk *clk);
 int dsi_pll_lock_status(struct mdss_pll_resources *dsi_pll_res);
-void pll_20nm_dsi_phy_ctrl_config
+void dsi_pll_20nm_phy_ctrl_config
 		(struct mdss_pll_resources *dsi_pll_res, int off);
 int vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate);
 unsigned long vco_get_rate(struct clk *c);