Selaa lähdekoodia

disp: msm: dsi: turn on the PLL before switching RCG parent during clk on

When display is left on from the bootloader, disp_cc driver will put a
proxy vote on clocks to maintain the hardware configuration of bootloader.
Once all the consumers have been probed, the dispcc driver will synchronize
the hardware state of the device to match the aggregated software state
requested by all the consumers using sync_state call.

If there is an idle power collapse or a suspend before sync state call,
branch clocks and in turn RCG will not get turned off during clocks
disable sequence because of the proxy vote of disp_cc driver. This can be
the case even if there is a vote from any other disp_cc consumers.

During a subsequent call to enable the clocks from DSI driver, we are
currently switching RCG parent to PLL and then turning on the PLL.
If the sync state call doesn't happen before we enable the clocks back,
we'll be setting PLL which is off as a parent to RCG that is on.
But ideally when RCG is on, both the old and new sources should be on
while switching the RCG parent.

Avoid this by turning on the PLL before switching RCG parent during clock
enable sequence.

Change-Id: I1597cf2c8095957cd2b2a20a72bf7199e0d61809
Signed-off-by: Srihitha Tangudu <[email protected]>
Srihitha Tangudu 3 vuotta sitten
vanhempi
sitoutus
ad4b936b50
1 muutettua tiedostoa jossa 52 lisäystä ja 9 poistoa
  1. 52 9
      msm/dsi/dsi_display.c

+ 52 - 9
msm/dsi/dsi_display.c

@@ -2749,21 +2749,48 @@ static int dsi_display_set_clk_src(struct dsi_display *display, bool set_xo)
 	return 0;
 }
 
-int dsi_display_phy_pll_toggle(void *priv, bool prepare)
+static int dsi_display_phy_pll_enable(struct dsi_display *display)
 {
 	int rc = 0;
-	struct dsi_display *display = priv;
 	struct dsi_display_ctrl *m_ctrl;
 
-	if (!display) {
-		DSI_ERR("invalid arguments\n");
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+	if (!m_ctrl->phy) {
+		DSI_ERR("[%s] PHY not found\n", display->name);
 		return -EINVAL;
 	}
 
-	if (is_skip_op_required(display))
-		return 0;
+	/*
+	 * It is recommended to turn on the PLL before switching parent
+	 * of RCG to PLL because when RCG is on, both the old and new
+	 * sources should be on while switching the RCG parent.
+	 *
+	 * Note: Branch clocks and in turn RCG might not get turned off
+	 * during clock disable sequence if there is a vote from dispcc
+	 * or any of its other consumers.
+	 */
+
+	rc = dsi_phy_pll_toggle(m_ctrl->phy, true);
+	if (rc)
+		return rc;
+
+	return dsi_display_set_clk_src(display, false);
+}
+
+static int dsi_display_phy_pll_disable(struct dsi_display *display)
+{
+	int rc = 0;
+	struct dsi_display_ctrl *m_ctrl;
 
-	rc = dsi_display_set_clk_src(display, !prepare);
+	/*
+	 * It is recommended to turn off the PLL after switching parent
+	 * of RCG to PLL because when RCG is on, both the old and new
+	 * sources should be on while switching the RCG parent.
+	 */
+
+	rc = dsi_display_set_clk_src(display, true);
+	if (rc)
+		return rc;
 
 	m_ctrl = &display->ctrl[display->clk_master_idx];
 	if (!m_ctrl->phy) {
@@ -2771,9 +2798,25 @@ int dsi_display_phy_pll_toggle(void *priv, bool prepare)
 		return -EINVAL;
 	}
 
-	rc = dsi_phy_pll_toggle(m_ctrl->phy, prepare);
+	return dsi_phy_pll_toggle(m_ctrl->phy, false);
+}
 
-	return rc;
+int dsi_display_phy_pll_toggle(void *priv, bool prepare)
+{
+	struct dsi_display *display = priv;
+
+	if (!display) {
+		DSI_ERR("invalid arguments\n");
+		return -EINVAL;
+	}
+
+	if (is_skip_op_required(display))
+		return 0;
+
+	if (prepare)
+		return dsi_display_phy_pll_enable(display);
+	else
+		return dsi_display_phy_pll_disable(display);
 }
 
 int dsi_display_phy_configure(void *priv, bool commit)