浏览代码

disp: msm: dp: replace dp clock trees with single nodes

The current pll driver models the entire DP clock
hierarchy using the clock framework. This creates
unnecessary dependency between the dp driver and
the clock driver and also limits the flexibility
to dp driver when configuring the DP clocks.

This change models these clocks as single nodes
and provide full control to the dp driver and
also minimizes the dependency on the clock driver.

Change-Id: Id5221441ea33b576e7c543396a12cbeb7b44d319
Signed-off-by: Yuan Zhao <[email protected]>
Yuan Zhao 4 年之前
父节点
当前提交
600416fa77
共有 5 个文件被更改,包括 277 次插入379 次删除
  1. 26 1
      msm/dp/dp_ctrl.c
  2. 2 1
      msm/dp/dp_ctrl.h
  3. 2 1
      msm/dp/dp_display.c
  4. 9 16
      msm/dp/dp_pll.h
  5. 238 360
      msm/dp/dp_pll_5nm.c

+ 26 - 1
msm/dp/dp_ctrl.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -62,6 +62,7 @@ struct dp_ctrl_private {
 	struct dp_power *power;
 	struct dp_parser *parser;
 	struct dp_catalog_ctrl *catalog;
+	struct dp_pll *pll;
 
 	struct completion idle_comp;
 	struct completion video_comp;
@@ -642,6 +643,22 @@ static int dp_ctrl_enable_link_clock(struct dp_ctrl_private *ctrl)
 
 	dp_ctrl_set_clock_rate(ctrl, "link_clk", type, rate);
 
+	if (ctrl->pll->pll_cfg) {
+		ret = ctrl->pll->pll_cfg(ctrl->pll, rate);
+		if (ret < 0) {
+			DP_ERR("DP pll cfg failed\n");
+			return ret;
+		}
+	}
+
+	if (ctrl->pll->pll_prepare) {
+		ret = ctrl->pll->pll_prepare(ctrl->pll);
+		if (ret < 0) {
+			DP_ERR("DP pll prepare failed\n");
+			return ret;
+		}
+	}
+
 	ret = ctrl->power->clk_enable(ctrl->power, type, true);
 	if (ret) {
 		DP_ERR("Unabled to start link clocks\n");
@@ -653,7 +670,14 @@ static int dp_ctrl_enable_link_clock(struct dp_ctrl_private *ctrl)
 
 static void dp_ctrl_disable_link_clock(struct dp_ctrl_private *ctrl)
 {
+	int rc = 0;
+
 	ctrl->power->clk_enable(ctrl->power, DP_LINK_PM, false);
+	if (ctrl->pll->pll_unprepare) {
+		rc = ctrl->pll->pll_unprepare(ctrl->pll);
+		if (rc < 0)
+			DP_ERR("pll unprepare failed\n");
+	}
 }
 
 static void dp_ctrl_select_training_pattern(struct dp_ctrl_private *ctrl,
@@ -1470,6 +1494,7 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
 	ctrl->aux      = in->aux;
 	ctrl->link     = in->link;
 	ctrl->catalog  = in->catalog;
+	ctrl->pll  = in->pll;
 	ctrl->dev  = in->dev;
 	ctrl->mst_mode = false;
 	ctrl->fec_mode = false;

+ 2 - 1
msm/dp/dp_ctrl.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DP_CTRL_H_
@@ -42,6 +42,7 @@ struct dp_ctrl_in {
 	struct dp_parser *parser;
 	struct dp_power *power;
 	struct dp_catalog_ctrl *catalog;
+	struct dp_pll *pll;
 };
 
 struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in);

+ 2 - 1
msm/dp/dp_display.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/module.h>
@@ -1969,6 +1969,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 	ctrl_in.power = dp->power;
 	ctrl_in.catalog = &dp->catalog->ctrl;
 	ctrl_in.parser = dp->parser;
+	ctrl_in.pll = dp->pll;
 
 	dp->ctrl = dp_ctrl_get(&ctrl_in);
 	if (IS_ERR(dp->ctrl)) {

+ 9 - 16
msm/dp/dp_pll.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __DP_PLL_H
@@ -56,24 +56,14 @@ struct dp_pll_io {
 
 struct dp_pll_vco_clk {
 	struct clk_hw hw;
-	unsigned long	rate;		/* current vco rate */
-	u64		min_rate;	/* min vco rate */
-	u64		max_rate;	/* max vco rate */
 	void		*priv;
 };
 
 struct dp_pll {
-	/*
-	 * target pll revision information
-	 */
-	u32		revision;
-
-	/*
-	 * Certain plls needs to update the same vco rate after resume in
-	 * suspend/resume scenario. Cached the vco rate for such plls.
-	 */
-	unsigned long	vco_cached_rate;
-
+	/* target pll revision information */
+	u32 revision;
+	/* save vco current rate */
+	unsigned long vco_rate;
 	/*
 	 * PLL index if multiple index are available. Eg. in case of
 	 * DSI we have 2 plls.
@@ -90,6 +80,10 @@ struct dp_pll {
 	struct dp_aux *aux;
 	struct dp_pll_io io;
 	struct clk_onecell_data *clk_data;
+
+	int (*pll_cfg)(struct dp_pll *pll, unsigned long rate);
+	int (*pll_prepare)(struct dp_pll *pll);
+	int (*pll_unprepare)(struct dp_pll *pll);
 };
 
 struct dp_pll_db {
@@ -117,7 +111,6 @@ struct dp_pll_db {
 	u32 phy_vco_div;
 };
 
-
 static inline struct dp_pll_vco_clk *to_dp_vco_hw(struct clk_hw *hw)
 {
 	return container_of(hw, struct dp_pll_vco_clk, hw);

+ 238 - 360
msm/dp/dp_pll_5nm.c

@@ -1,56 +1,19 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
  */
 
 /*
  * Display Port PLL driver block diagram for branch clocks
  *
- *		+------------------------------+
- *		|         DP_VCO_CLK           |
- *		|                              |
- *		|    +-------------------+     |
- *		|    |   (DP PLL/VCO)    |     |
- *		|    +---------+---------+     |
- *		|              v               |
- *		|   +----------+-----------+   |
- *		|   | hsclk_divsel_clk_src |   |
- *		|   +----------+-----------+   |
- *		+------------------------------+
- *				|
- *	 +------------<---------v------------>----------+
- *	 |                                              |
- * +-----v------------+                                 |
- * | dp_link_clk_src  |                                 |
- * |    divsel_ten    |                                 |
- * +---------+--------+                                 |
- *	|                                               |
- *	|                                               |
- *	v                                               v
- * Input to DISPCC block                                |
- * for link clk, crypto clk                             |
- * and interface clock                                  |
- *							|
- *							|
- *	+--------<------------+-----------------+---<---+
- *	|                     |                 |
- * +-------v------+  +--------v-----+  +--------v------+
- * | vco_divided  |  | vco_divided  |  | vco_divided   |
- * |    _clk_src  |  |    _clk_src  |  |    _clk_src   |
- * |              |  |              |  |               |
- * |divsel_six    |  |  divsel_two  |  |  divsel_four  |
- * +-------+------+  +-----+--------+  +--------+------+
- *         |	           |		        |
- *	v------->----------v-------------<------v
- *                         |
- *		+----------+---------+
- *		|   vco_divided_clk  |
- *		|       _src_mux     |
- *		+---------+----------+
- *                        |
- *                        v
- *              Input to DISPCC block
- *              for DP pixel clock
+ * +------------------------+       +------------------------+
+ * |   dp_phy_pll_link_clk  |       | dp_phy_pll_vco_div_clk |
+ * +------------------------+       +------------------------+
+ *             |                               |
+ *             |                               |
+ *             V                               V
+ *        dp_link_clk                     dp_pixel_clk
+ *
  *
  */
 
@@ -241,17 +204,16 @@ static int dp_vco_pll_init_db_5nm(struct dp_pll_db *pdb,
 	return 0;
 }
 
-static int dp_config_vco_rate_5nm(struct dp_pll_vco_clk *vco,
+static int dp_config_vco_rate_5nm(struct dp_pll *pll,
 		unsigned long rate)
 {
-	int res = 0;
-	struct dp_pll *pll = vco->priv;
+	int rc = 0;
 	struct dp_pll_db *pdb = (struct dp_pll_db *)pll->priv;
 
-	res = dp_vco_pll_init_db_5nm(pdb, rate);
-	if (res) {
+	rc = dp_vco_pll_init_db_5nm(pdb, rate);
+	if (rc < 0) {
 		DP_ERR("VCO Init DB failed\n");
-		return res;
+		return rc;
 	}
 
 	dp_pll_write(dp_phy, DP_PHY_CFG_1, 0x0F);
@@ -372,7 +334,7 @@ static int dp_config_vco_rate_5nm(struct dp_pll_vco_clk *vco,
 	/* Make sure the PHY register writes are done */
 	wmb();
 
-	return res;
+	return rc;
 }
 
 enum dp_5nm_pll_status {
@@ -451,11 +413,9 @@ static bool dp_5nm_pll_get_status(struct dp_pll *pll,
 	return success;
 }
 
-static int dp_pll_enable_5nm(struct clk_hw *hw)
+static int dp_pll_enable_5nm(struct dp_pll *pll)
 {
 	int rc = 0;
-	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
-	struct dp_pll *pll = vco->priv;
 
 	pll->aux->state &= ~DP_STATE_PLL_LOCKED;
 
@@ -497,15 +457,13 @@ static int dp_pll_enable_5nm(struct clk_hw *hw)
 
 	pll->aux->state |= DP_STATE_PLL_LOCKED;
 	DP_DEBUG("PLL is locked\n");
+
 lock_err:
 	return rc;
 }
 
-static int dp_pll_disable_5nm(struct clk_hw *hw)
+static void dp_pll_disable_5nm(struct dp_pll *pll)
 {
-	struct dp_pll_vco_clk *vco = to_dp_vco_hw(hw);
-	struct dp_pll *pll = vco->priv;
-
 	/* Assert DP PHY power down */
 	dp_pll_write(dp_phy, DP_PHY_PD_CTL, 0x2);
 	/*
@@ -513,103 +471,68 @@ static int dp_pll_disable_5nm(struct clk_hw *hw)
 	 * completed before doing any other operation
 	 */
 	wmb();
-
-	return 0;
 }
 
-static struct clk_ops mux_clk_ops;
-static struct regmap_config dp_pll_5nm_cfg = {
-	.reg_bits	= 32,
-	.reg_stride	= 4,
-	.val_bits	= 32,
-	.max_register = 0x910,
-};
-
-int dp_mux_set_parent_5nm(void *context, unsigned int reg, unsigned int val)
+static int dp_vco_clk_set_div(struct dp_pll *pll, unsigned int div)
 {
-	struct dp_pll *pll = context;
-	u32 auxclk_div;
+	u32 val = 0;
 
-	if (!context) {
+	if (!pll) {
 		DP_ERR("invalid input parameters\n");
 		return -EINVAL;
 	}
 
-	auxclk_div = dp_pll_read(dp_phy, DP_PHY_VCO_DIV);
-	auxclk_div &= ~0x03;
-
-	if (val == 0)
-		auxclk_div |= 1;
-	else if (val == 1)
-		auxclk_div |= 2;
-	else if (val == 2)
-		auxclk_div |= 0;
-
-	dp_pll_write(dp_phy, DP_PHY_VCO_DIV, auxclk_div);
-	/* Make sure the PHY registers writes are done */
-	wmb();
-	DP_DEBUG("mux=%d auxclk_div=%x\n", val, auxclk_div);
-
-	return 0;
-}
+	if (is_gdsc_disabled(pll))
+		return -EINVAL;
 
-int dp_mux_get_parent_5nm(void *context, unsigned int reg, unsigned int *val)
-{
-	u32 auxclk_div = 0;
-	struct dp_pll *pll = context;
+	val = dp_pll_read(dp_phy, DP_PHY_VCO_DIV);
+	val &= ~0x03;
 
-	if (!context || !val) {
-		DP_ERR("invalid input parameters\n");
+	switch (div) {
+	case 2:
+		val |= 1;
+		break;
+	case 4:
+		val |= 2;
+		break;
+	case 6:
+	/* When div = 6, val is 0, so do nothing here */
+		;
+		break;
+	case 8:
+		val |= 3;
+		break;
+	default:
+		DP_DEBUG("unsupported div value %d\n", div);
 		return -EINVAL;
 	}
 
-	if (is_gdsc_disabled(pll))
-		return 0;
-
-	auxclk_div = dp_pll_read(dp_phy, DP_PHY_VCO_DIV);
-	auxclk_div &= 0x03;
-
-	if (auxclk_div == 1) /* Default divider */
-		*val = 0;
-	else if (auxclk_div == 2)
-		*val = 1;
-	else if (auxclk_div == 0)
-		*val = 2;
-
-	DP_DEBUG("auxclk_div=%d, val=%d\n", auxclk_div, *val);
+	dp_pll_write(dp_phy, DP_PHY_VCO_DIV, val);
+	/* Make sure the PHY registers writes are done */
+	wmb();
 
+	DP_DEBUG("val=%d div=%x\n", val, div);
 	return 0;
 }
 
-static struct regmap_bus dp_pixel_mux_regmap_ops = {
-	.reg_write = dp_mux_set_parent_5nm,
-	.reg_read = dp_mux_get_parent_5nm,
-};
-
-static int dp_vco_set_rate_5nm(struct clk_hw *hw, unsigned long rate,
-					unsigned long parent_rate)
+static int dp_vco_set_rate_5nm(struct dp_pll *pll, unsigned long rate)
 {
-	struct dp_pll_vco_clk *vco;
-	int rc;
-	struct dp_pll *pll;
+	int rc = 0;
 
-	if (!hw) {
+	if (!pll) {
 		DP_ERR("invalid input parameters\n");
 		return -EINVAL;
 	}
 
-	vco = to_dp_vco_hw(hw);
-	pll = vco->priv;
-
 	DP_DEBUG("DP lane CLK rate=%ld\n", rate);
 
-	rc = dp_config_vco_rate_5nm(vco, rate);
-	if (rc)
+	rc = dp_config_vco_rate_5nm(pll, rate);
+	if (rc < 0) {
 		DP_ERR("Failed to set clk rate\n");
+		return rc;
+	}
 
-	vco->rate = rate;
-
-	return 0;
+	return rc;
 }
 
 static int dp_regulator_enable_5nm(struct dp_parser *parser,
@@ -638,21 +561,45 @@ static int dp_regulator_enable_5nm(struct dp_parser *parser,
 	return rc;
 }
 
-static int dp_vco_prepare_5nm(struct clk_hw *hw)
+static int dp_pll_configure(struct dp_pll *pll, unsigned long rate)
 {
 	int rc = 0;
-	struct dp_pll_vco_clk *vco;
-	struct dp_pll *pll;
 
-	if (!hw) {
-		DP_ERR("invalid input parameters\n");
+	if (!pll || !rate) {
+		DP_ERR("invalid input parameters rate = %lu\n", rate);
 		return -EINVAL;
 	}
 
-	vco = to_dp_vco_hw(hw);
-	pll = vco->priv;
+	rate = rate * 10;
 
-	DP_DEBUG("rate=%ld\n", vco->rate);
+	if (rate <= DP_VCO_HSCLK_RATE_1620MHZDIV1000)
+		rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000;
+	else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
+		rate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
+	else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+		rate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
+	else
+		rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000;
+
+	rc = dp_vco_set_rate_5nm(pll, rate);
+	if (rc < 0) {
+		DP_ERR("pll rate %s set failed\n", rate);
+		return rc;
+	}
+
+	pll->vco_rate = rate;
+	DP_DEBUG("pll rate %lu set success\n", rate);
+	return rc;
+}
+
+static int dp_pll_prepare(struct dp_pll *pll)
+{
+	int rc = 0;
+
+	if (!pll) {
+		DP_ERR("invalid input parameters\n");
+		return -EINVAL;
+	}
 
 	/*
 	 * Enable DP_PM_PLL regulator if the PLL revision is 5nm-V1 and the
@@ -660,91 +607,77 @@ static int dp_vco_prepare_5nm(struct clk_hw *hw)
 	 * turbo as required for V1 hardware PLL functionality.
 	 */
 	if (pll->revision == DP_PLL_5NM_V1 &&
-			vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
-		dp_regulator_enable_5nm(pll->parser, DP_PLL_PM, true);
-
-	if ((pll->vco_cached_rate != 0)
-		&& (pll->vco_cached_rate == vco->rate)) {
-		rc = dp_vco_set_rate_5nm(hw, pll->vco_cached_rate,
-				pll->vco_cached_rate);
-		if (rc) {
-			DP_ERR("index=%d vco_set_rate failed. rc=%d\n",
-				rc, pll->index);
-			goto error;
+	    pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) {
+		rc = dp_regulator_enable_5nm(pll->parser, DP_PLL_PM, true);
+		if (rc < 0) {
+			DP_ERR("enable pll power failed\n");
+			return rc;
 		}
 	}
 
-	rc = dp_pll_enable_5nm(hw);
-	if (rc) {
+	rc = dp_pll_enable_5nm(pll);
+	if (rc < 0)
 		DP_ERR("ndx=%d failed to enable dp pll\n", pll->index);
-		goto error;
-	}
 
-error:
 	return rc;
 }
 
-static void dp_vco_unprepare_5nm(struct clk_hw *hw)
+static int  dp_pll_unprepare(struct dp_pll *pll)
 {
-	struct dp_pll_vco_clk *vco;
-	struct dp_pll *pll;
-
-	if (!hw) {
-		DP_ERR("invalid input parameters\n");
-		return;
-	}
-
-	vco = to_dp_vco_hw(hw);
-	pll = vco->priv;
+	int rc = 0;
 
 	if (!pll) {
 		DP_ERR("invalid input parameter\n");
-		return;
+		return -EINVAL;
 	}
 
 	if (pll->revision == DP_PLL_5NM_V1 &&
-			vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
-		dp_regulator_enable_5nm(pll->parser, DP_PLL_PM, false);
+			pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000) {
+		rc = dp_regulator_enable_5nm(pll->parser, DP_PLL_PM, false);
+		if (rc < 0) {
+			DP_ERR("disable pll power failed\n");
+			return rc;
+		}
+	}
+
+	dp_pll_disable_5nm(pll);
 
-	pll->vco_cached_rate = vco->rate;
-	dp_pll_disable_5nm(hw);
+	return rc;
 }
 
-static unsigned long dp_vco_recalc_rate_5nm(struct clk_hw *hw,
-					unsigned long parent_rate)
+unsigned long dp_vco_recalc_rate_5nm(struct dp_pll *pll)
 {
-	struct dp_pll_vco_clk *vco;
 	u32 hsclk_sel, link_clk_divsel, hsclk_div, link_clk_div = 0;
-	unsigned long vco_rate;
-	struct dp_pll *pll;
+	unsigned long vco_rate = 0;
 
-	if (!hw) {
+	if (!pll) {
 		DP_ERR("invalid input parameters\n");
-		return 0;
+		return -EINVAL;
 	}
 
-	vco = to_dp_vco_hw(hw);
-	pll = vco->priv;
-
 	if (is_gdsc_disabled(pll))
 		return 0;
 
-	DP_DEBUG("input rates: parent=%lu, vco=%lu\n", parent_rate, vco->rate);
-
 	hsclk_sel = dp_pll_read(dp_pll, QSERDES_COM_HSCLK_SEL);
 	hsclk_sel &= 0x0f;
 
-	if (hsclk_sel == 5)
+	switch (hsclk_sel) {
+	case 5:
 		hsclk_div = 5;
-	else if (hsclk_sel == 3)
+		break;
+	case 3:
 		hsclk_div = 3;
-	else if (hsclk_sel == 1)
+		break;
+	case 1:
 		hsclk_div = 2;
-	else if (hsclk_sel == 0)
+		break;
+	case 0:
 		hsclk_div = 1;
-	else {
+		break;
+	default:
 		DP_DEBUG("unknown divider. forcing to default\n");
 		hsclk_div = 5;
+		break;
 	}
 
 	link_clk_divsel = dp_pll_read(dp_phy, DP_PHY_AUX_CFG2);
@@ -776,201 +709,144 @@ static unsigned long dp_vco_recalc_rate_5nm(struct clk_hw *hw,
 	DP_DEBUG("hsclk: sel=0x%x, div=0x%x; lclk: sel=%u, div=%u, rate=%lu\n",
 		hsclk_sel, hsclk_div, link_clk_divsel, link_clk_div, vco_rate);
 
-	pll->vco_cached_rate = vco->rate = vco_rate;
-
 	return vco_rate;
 }
 
-static long dp_vco_round_rate_5nm(struct clk_hw *hw, unsigned long rate,
-			unsigned long *parent_rate)
+static unsigned long dp_pll_link_clk_recalc_rate(struct clk_hw *hw,
+						 unsigned long parent_rate)
 {
-	unsigned long rrate = rate;
-	struct dp_pll_vco_clk *vco;
+	struct dp_pll *pll = NULL;
+	struct dp_pll_vco_clk *pll_link = NULL;
+	unsigned long rate = 0;
 
 	if (!hw) {
 		DP_ERR("invalid input parameters\n");
-		return 0;
+		return -EINVAL;
 	}
 
-	vco = to_dp_vco_hw(hw);
-	if (rate <= vco->min_rate)
-		rrate = vco->min_rate;
-	else if (rate <= DP_VCO_HSCLK_RATE_2700MHZDIV1000)
-		rrate = DP_VCO_HSCLK_RATE_2700MHZDIV1000;
-	else if (rate <= DP_VCO_HSCLK_RATE_5400MHZDIV1000)
-		rrate = DP_VCO_HSCLK_RATE_5400MHZDIV1000;
-	else
-		rrate = vco->max_rate;
+	pll_link = to_dp_vco_hw(hw);
+	pll = pll_link->priv;
 
-	DP_DEBUG("rrate=%ld\n", rrate);
+	rate = pll->vco_rate;
+	rate = pll->vco_rate / 10;
 
-	if (parent_rate)
-		*parent_rate = rrate;
-	return rrate;
+	return rate;
 }
 
-/* Op structures */
-static const struct clk_ops dp_5nm_vco_clk_ops = {
-	.recalc_rate = dp_vco_recalc_rate_5nm,
-	.set_rate = dp_vco_set_rate_5nm,
-	.round_rate = dp_vco_round_rate_5nm,
-	.prepare = dp_vco_prepare_5nm,
-	.unprepare = dp_vco_unprepare_5nm,
-};
-
-static struct dp_pll_vco_clk dp_vco_clk = {
-	.min_rate = DP_VCO_HSCLK_RATE_1620MHZDIV1000,
-	.max_rate = DP_VCO_HSCLK_RATE_8100MHZDIV1000,
-	.hw.init = &(struct clk_init_data){
-		.name = "dp_vco_clk",
-		.parent_names = (const char *[]){ "bi_tcxo" },
-		.num_parents = 1,
-		.ops = &dp_5nm_vco_clk_ops,
-	},
-};
-
-static struct clk_fixed_factor dp_phy_pll_link_clk = {
-	.div = 10,
-	.mult = 1,
-
-	.hw.init = &(struct clk_init_data){
-		.name = "dp_phy_pll_link_clk",
-		.parent_names =
-			(const char *[]){ "dp_vco_clk" },
-		.num_parents = 1,
-		.flags = CLK_SET_RATE_PARENT,
-		.ops = &clk_fixed_factor_ops,
-	},
-};
-
-static struct clk_fixed_factor dp_vco_divsel_two_clk_src = {
-	.div = 2,
-	.mult = 1,
+static long dp_pll_link_clk_round(struct clk_hw *hw, unsigned long rate,
+			unsigned long *parent_rate)
+{
+	struct dp_pll *pll = NULL;
+	struct dp_pll_vco_clk *pll_link = NULL;
 
-	.hw.init = &(struct clk_init_data){
-		.name = "dp_vco_divsel_two_clk_src",
-		.parent_names =
-			(const char *[]){ "dp_vco_clk" },
-		.num_parents = 1,
-		.ops = &clk_fixed_factor_ops,
-	},
-};
+	if (!hw) {
+		DP_ERR("invalid input parameters\n");
+		return -EINVAL;
+	}
 
-static struct clk_fixed_factor dp_vco_divsel_four_clk_src = {
-	.div = 4,
-	.mult = 1,
+	pll_link = to_dp_vco_hw(hw);
+	pll = pll_link->priv;
 
-	.hw.init = &(struct clk_init_data){
-		.name = "dp_vco_divsel_four_clk_src",
-		.parent_names =
-			(const char *[]){ "dp_vco_clk" },
-		.num_parents = 1,
-		.ops = &clk_fixed_factor_ops,
-	},
-};
+	rate = pll->vco_rate / 10;
 
-static struct clk_fixed_factor dp_vco_divsel_six_clk_src = {
-	.div = 6,
-	.mult = 1,
-
-	.hw.init = &(struct clk_init_data){
-		.name = "dp_vco_divsel_six_clk_src",
-		.parent_names =
-			(const char *[]){ "dp_vco_clk" },
-		.num_parents = 1,
-		.ops = &clk_fixed_factor_ops,
-	},
-};
+	return rate;
+}
 
-static struct clk_regmap_mux dp_phy_pll_vco_div_clk = {
-	.reg = 0x64,
-	.shift = 0,
-	.width = 2,
-
-	.clkr = {
-		.hw.init = &(struct clk_init_data){
-			.name = "dp_phy_pll_vco_div_clk",
-			.parent_names =
-				(const char *[]){"dp_vco_divsel_two_clk_src",
-					"dp_vco_divsel_four_clk_src",
-					"dp_vco_divsel_six_clk_src"},
-			.num_parents = 3,
-			.ops = &mux_clk_ops,
-			.flags = CLK_SET_RATE_PARENT,
-		},
-	},
-};
+static unsigned long dp_pll_vco_div_clk_get_rate(struct dp_pll *pll)
+{
+	if (pll->vco_rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
+		return (pll->vco_rate / 6);
+	else if (pll->vco_rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000)
+		return (pll->vco_rate / 4);
+	else
+		return (pll->vco_rate / 2);
+}
 
-static int clk_mux_determine_rate(struct clk_hw *hw,
-				  struct clk_rate_request *req)
+static unsigned long dp_pll_vco_div_clk_recalc_rate(struct clk_hw *hw,
+					unsigned long parent_rate)
 {
-	int ret = 0;
+	struct dp_pll *pll = NULL;
+	struct dp_pll_vco_clk *pll_link = NULL;
 
-	if (!hw || !req) {
-		DP_ERR("Invalid input parameters\n");
+	if (!hw) {
+		DP_ERR("invalid input parameters\n");
 		return -EINVAL;
 	}
 
-	ret = __clk_mux_determine_rate_closest(hw, req);
-	if (ret)
-		return ret;
+	pll_link = to_dp_vco_hw(hw);
+	pll = pll_link->priv;
 
-	/* Set the new parent of mux if there is a new valid parent */
-	if (hw->clk && req->best_parent_hw->clk)
-		clk_set_parent(hw->clk, req->best_parent_hw->clk);
+	return dp_pll_vco_div_clk_get_rate(pll);
+}
 
-	return 0;
+static long dp_pll_vco_div_clk_round(struct clk_hw *hw, unsigned long rate,
+			unsigned long *parent_rate)
+{
+	return dp_pll_vco_div_clk_recalc_rate(hw, *parent_rate);
 }
 
-static unsigned long mux_recalc_rate(struct clk_hw *hw,
-					unsigned long parent_rate)
+static int dp_pll_vco_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long parent_rate)
 {
-	struct clk *div_clk = NULL, *vco_clk = NULL;
-	struct dp_pll_vco_clk *vco = NULL;
+	struct dp_pll *pll = NULL;
+	struct dp_pll_vco_clk *pll_link = NULL;
+	int rc = 0;
 
 	if (!hw) {
-		DP_ERR("Invalid input parameter\n");
-		return 0;
+		DP_ERR("invalid input parameters\n");
+		return -EINVAL;
 	}
 
-	div_clk = clk_get_parent(hw->clk);
-	if (!div_clk)
-		return 0;
+	pll_link = to_dp_vco_hw(hw);
+	pll = pll_link->priv;
 
-	vco_clk = clk_get_parent(div_clk);
-	if (!vco_clk)
-		return 0;
+	if (rate != dp_pll_vco_div_clk_get_rate(pll)) {
+		DP_ERR("unsupported rate %lu failed\n", rate);
+		return rc;
+	}
 
-	vco = to_dp_vco_hw(__clk_get_hw(vco_clk));
-	if (!vco)
-		return 0;
+	rc = dp_vco_clk_set_div(pll, pll->vco_rate / rate);
+	if (rc < 0) {
+		DP_DEBUG("set rate %lu failed\n", rate);
+		return rc;
+	}
 
-	if (vco->rate == DP_VCO_HSCLK_RATE_8100MHZDIV1000)
-		return (vco->rate / 6);
-	else if (vco->rate == DP_VCO_HSCLK_RATE_5400MHZDIV1000)
-		return (vco->rate / 4);
-	else
-		return (vco->rate / 2);
+	DP_DEBUG("set rate %lu success\n", rate);
+	return 0;
 }
 
-static struct clk_hw *mdss_dp_pllcc_5nm[] = {
-	[DP_VCO_CLK] = &dp_vco_clk.hw,
-	[DP_LINK_CLK_DIVSEL_TEN] = &dp_phy_pll_link_clk.hw,
-	[DP_VCO_DIVIDED_TWO_CLK_SRC] = &dp_vco_divsel_two_clk_src.hw,
-	[DP_VCO_DIVIDED_FOUR_CLK_SRC] = &dp_vco_divsel_four_clk_src.hw,
-	[DP_VCO_DIVIDED_SIX_CLK_SRC] = &dp_vco_divsel_six_clk_src.hw,
-	[DP_PHY_PLL_VCO_DIV_CLK] = &dp_phy_pll_vco_div_clk.clkr.hw,
+static const struct clk_ops pll_link_clk_ops = {
+	.recalc_rate = dp_pll_link_clk_recalc_rate,
+	.round_rate = dp_pll_link_clk_round,
+};
+
+static const struct clk_ops pll_vco_div_clk_ops = {
+	.recalc_rate = dp_pll_vco_div_clk_recalc_rate,
+	.round_rate = dp_pll_vco_div_clk_round,
+	.set_rate = dp_pll_vco_div_clk_set_rate,
+};
+
+static struct dp_pll_vco_clk dp_phy_pll_link_clk = {
+	.hw.init = &(struct clk_init_data) {
+		.name = "dp_phy_pll_link_clk",
+		.ops = &pll_link_clk_ops,
+	},
+};
+
+static struct dp_pll_vco_clk dp_phy_pll_vco_div_clk = {
+	.hw.init = &(struct clk_init_data) {
+		.name = "dp_phy_pll_vco_div_clk",
+		.ops = &pll_vco_div_clk_ops,
+	},
 };
 
 static struct dp_pll_db dp_pdb;
 
 int dp_pll_clock_register_5nm(struct dp_pll *pll)
 {
-	int rc = -ENOTSUPP, i = 0;
+	int rc = 0, num_clks = 2;
 	struct platform_device *pdev;
 	struct clk *clk;
-	struct regmap *regmap;
-	int num_clks = ARRAY_SIZE(mdss_dp_pllcc_5nm);
 
 	if (!pll) {
 		DP_ERR("pll data not initialized\n");
@@ -990,42 +866,44 @@ int dp_pll_clock_register_5nm(struct dp_pll *pll)
 	}
 
 	pll->clk_data->clk_num = num_clks;
-
 	pll->priv = &dp_pdb;
 	dp_pdb.pll = pll;
 
-	/* Set client data for vco, mux and div clocks */
-	regmap = regmap_init(&pdev->dev, &dp_pixel_mux_regmap_ops,
-			pll, &dp_pll_5nm_cfg);
-	mux_clk_ops = clk_regmap_mux_closest_ops;
-	mux_clk_ops.determine_rate = clk_mux_determine_rate;
-	mux_clk_ops.recalc_rate = mux_recalc_rate;
-
-	dp_vco_clk.priv = pll;
-	dp_phy_pll_vco_div_clk.clkr.regmap = regmap;
-
-	for (i = DP_VCO_CLK; i <= DP_PHY_PLL_VCO_DIV_CLK; i++) {
-		DP_DEBUG("reg clk: %d index: %d\n", i, pll->index);
-		clk = clk_register(&pdev->dev, mdss_dp_pllcc_5nm[i]);
-		if (IS_ERR(clk)) {
-			DP_ERR("clk registration failed for DP: %d\n",
-					pll->index);
-			rc = -EINVAL;
-			goto clk_reg_fail;
-		}
-		pll->clk_data->clks[i] = clk;
+	dp_phy_pll_link_clk.priv = pll;
+	dp_phy_pll_vco_div_clk.priv = pll;
+
+	pll->pll_cfg = dp_pll_configure;
+	pll->pll_prepare = dp_pll_prepare;
+	pll->pll_unprepare = dp_pll_unprepare;
+
+	clk = clk_register(&pdev->dev, &dp_phy_pll_link_clk.hw);
+	if (IS_ERR(clk)) {
+		DP_ERR("%s registration failed for DP: %d\n",
+		       clk_hw_get_name(&dp_phy_pll_link_clk.hw), pll->index);
+		rc = -EINVAL;
+		goto clk_reg_fail;
+	}
+	pll->clk_data->clks[0] = clk;
+
+	clk = clk_register(&pdev->dev, &dp_phy_pll_vco_div_clk.hw);
+	if (IS_ERR(clk)) {
+		DP_ERR("%s registration failed for DP: %d\n",
+		       clk_hw_get_name(&dp_phy_pll_vco_div_clk.hw), pll->index);
+		rc = -EINVAL;
+		goto clk_reg_fail;
 	}
+	pll->clk_data->clks[1] = clk;
 
 	rc = of_clk_add_provider(pdev->dev.of_node,
 			of_clk_src_onecell_get, pll->clk_data);
 	if (rc) {
 		DP_ERR("Clock register failed rc=%d\n", rc);
-		rc = -EPROBE_DEFER;
 		goto clk_reg_fail;
-	} else {
-		DP_DEBUG("success\n");
 	}
+
+	DP_DEBUG("success\n");
 	return rc;
+
 clk_reg_fail:
 	dp_pll_clock_unregister_5nm(pll);
 	return rc;