summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c224
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h7
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c420
3 files changed, 402 insertions, 249 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 3ddced201124..38436e06d244 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -430,7 +430,7 @@ static int mdss_dsi_off(struct mdss_panel_data *pdata)
return ret;
}
-static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
+void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
@@ -515,185 +515,16 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata)
}
}
-int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable)
+void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl)
{
- int ret = 0;
- struct mdss_panel_data *pdata = NULL;
- struct mdss_panel_info *pinfo;
- struct mipi_panel_info *mipi;
- u32 lane_status = 0, regval;
- u32 active_lanes = 0, clamp_reg;
- u32 clamp_reg_off, phyrst_reg_off;
-
- if (!ctrl_pdata) {
- pr_err("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- if (&ctrl_pdata->mmss_misc_io == NULL) {
- pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__);
- return -EINVAL;
- }
-
- pdata = &ctrl_pdata->panel_data;
- if (!pdata) {
- pr_err("%s: Invalid panel data\n", __func__);
- return -EINVAL;
- }
- pinfo = &pdata->panel_info;
- mipi = &pinfo->mipi;
- clamp_reg_off = ctrl_pdata->ulps_clamp_ctrl_off;
- phyrst_reg_off = ctrl_pdata->ulps_phyrst_ctrl_off;
-
- if (!mdss_dsi_ulps_feature_enabled(pdata)) {
- pr_debug("%s: ULPS feature not supported. enable=%d\n",
- __func__, enable);
- return -ENOTSUPP;
- }
-
- /*
- * No need to enter ULPS when transitioning from splash screen to
- * boot animation since it is expected that the clocks would be turned
- * right back on.
- */
- if (pinfo->cont_splash_enabled) {
- pr_debug("%s: skip ULPS config with splash screen enabled\n",
- __func__);
- return 0;
- }
-
- /* clock lane will always be programmed for ulps and will be clamped */
- active_lanes = BIT(4);
- clamp_reg = BIT(8) | BIT(9);
- /*
- * make a note of all active data lanes for which ulps entry/exit
- * as well as DSI clamps are needed
- */
- if (mipi->data_lane0) {
- active_lanes |= BIT(0);
- clamp_reg |= (BIT(0) | BIT(1));
- }
- if (mipi->data_lane1) {
- active_lanes |= BIT(1);
- clamp_reg |= (BIT(2) | BIT(3));
- }
- if (mipi->data_lane2) {
- active_lanes |= BIT(2);
- clamp_reg |= (BIT(4) | BIT(5));
- }
- if (mipi->data_lane3) {
- active_lanes |= BIT(3);
- clamp_reg |= (BIT(6) | BIT(7));
- }
-
- pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n",
- __func__, (enable ? "on" : "off"), ctrl_pdata->ndx,
- active_lanes);
-
- if (enable && !ctrl_pdata->ulps) {
- /*
- * ULPS Entry Request.
- * Wait for a short duration to ensure that the lanes
- * enter ULP state.
- */
- MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
- usleep(100);
-
- /* Check to make sure that all active data lanes are in ULPS */
- lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
- if (lane_status & (active_lanes << 8)) {
- pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n",
- __func__, ctrl_pdata->ndx, lane_status);
- ret = -EINVAL;
- goto error;
- }
-
- /* Enable MMSS DSI Clamps */
- if (ctrl_pdata->ndx == DSI_CTRL_0) {
- regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base +
- clamp_reg_off);
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval | clamp_reg);
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval | (clamp_reg | BIT(15)));
- } else if (ctrl_pdata->ndx == DSI_CTRL_1) {
- regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base +
- clamp_reg_off);
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval | (clamp_reg << 16));
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval | ((clamp_reg << 16) | BIT(31)));
- }
-
- wmb();
-
- /*
- * This register write ensures that DSI PHY will not be
- * reset when mdss ahb clock reset is asserted while coming
- * out of power collapse
- */
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x1);
- ctrl_pdata->ulps = true;
- } else if (ctrl_pdata->ulps) {
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + phyrst_reg_off, 0x0);
- if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103)
- mdss_dsi_20nm_phy_init(pdata);
- else
- mdss_dsi_phy_init(pdata);
+ struct mdss_panel_data *pdata = &ctrl->panel_data;
- __mdss_dsi_ctrl_setup(pdata);
- mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(pdata);
- mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode,
- pdata);
-
- /*
- * ULPS Entry Request. This is needed because, after power
- * collapse and reset, the DSI controller resets back to
- * idle state and not ULPS.
- * Wait for a short duration to ensure that the lanes
- * enter ULP state.
- */
- MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes);
- usleep(100);
-
- /* Disable MMSS DSI Clamps */
- if (ctrl_pdata->ndx == DSI_CTRL_0) {
- regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base +
- clamp_reg_off);
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval & ~(clamp_reg | BIT(15)));
- } else if (ctrl_pdata->ndx == DSI_CTRL_1) {
- regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base +
- clamp_reg_off);
- MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + clamp_reg_off,
- regval & ~((clamp_reg << 16) | BIT(31)));
- }
-
-
- /*
- * ULPS Exit Request
- * Hardware requirement is to wait for at least 1ms
- */
- MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8);
- usleep(1000);
- MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0);
-
- /*
- * Wait for a short duration before enabling
- * data transmission
- */
- usleep(100);
-
- lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8);
- ctrl_pdata->ulps = false;
- }
+ pr_debug("%s: called for ctrl%d\n", __func__, ctrl->ndx);
- pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
- lane_status, enable ? "enabled" : "disabled");
-
-error:
- return ret;
+ /* DSI controller reset and init */
+ mdss_dsi_sw_reset(pdata);
+ mdss_dsi_host_init(pdata);
+ mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata);
}
static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
@@ -754,36 +585,13 @@ int mdss_dsi_on(struct mdss_panel_data *pdata)
return ret;
}
- mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 1);
- if (ret) {
- pr_err("%s: failed to enable bus clocks. rc=%d\n", __func__,
- ret);
- ret = mdss_dsi_panel_power_on(pdata, 0);
- if (ret) {
- pr_err("%s: Panel reset failed. rc=%d\n",
- __func__, ret);
- return ret;
- }
- pdata->panel_info.panel_power_on = 0;
- return ret;
- }
- pdata->panel_info.panel_power_on = 1;
-
- ctrl_pdata->ctrl_rev = MIPI_INP(ctrl_pdata->ctrl_base);
-
- mdss_dsi_phy_sw_reset((ctrl_pdata->ctrl_base));
- if (ctrl_pdata->ctrl_rev == MDSS_DSI_HW_REV_103)
- mdss_dsi_20nm_phy_init(pdata);
- else
- mdss_dsi_phy_init(pdata);
-
- mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0);
-
+ /*
+ * Enable DSI clocks.
+ * This is also enable the DSI core power block and reset/setup
+ * DSI phy
+ */
mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1);
-
- __mdss_dsi_ctrl_setup(pdata);
- mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(pdata);
+ pdata->panel_info.panel_power_on = 1;
/*
* Issue hardware reset line after enabling the DSI clocks and data
@@ -992,9 +800,7 @@ int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata)
WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT),
"Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state);
- mdss_dsi_sw_reset(pdata);
- mdss_dsi_host_init(pdata);
- mdss_dsi_op_mode_config(mipi->mode, pdata);
+ mdss_dsi_reset(ctrl_pdata);
pr_debug("%s-:End\n", __func__);
return ret;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index d7197fa4178c..62df757052d4 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -336,9 +336,11 @@ struct mdss_dsi_ctrl_pdata {
struct mutex mutex;
struct mutex cmd_mutex;
- bool ulps;
u32 ulps_clamp_ctrl_off;
u32 ulps_phyrst_ctrl_off;
+ bool ulps;
+ bool core_power;
+ bool mmss_clamp;
struct dsi_buf tx_buf;
struct dsi_buf rx_buf;
@@ -410,7 +412,8 @@ void mdss_dsi_cmdlist_kickoff(int intf);
int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
int mdss_dsi_reg_status_check(struct mdss_dsi_ctrl_pdata *ctrl);
bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type);
-int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable);
+void mdss_dsi_reset(struct mdss_dsi_ctrl_pdata *ctrl);
+void mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata);
int mdss_dsi_panel_init(struct device_node *node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata,
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index ba8099cfd488..e906e5d09016 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -484,6 +484,366 @@ static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl)
mdss_dsi_link_clk_unprepare(ctrl);
}
+/**
+ * mdss_dsi_ulps_config() - Program DSI lanes to enter/exit ULPS mode
+ * @ctrl: pointer to DSI controller structure
+ * @enable: 1 to enter ULPS, 0 to exit ULPS
+ *
+ * This function executes the necessary programming sequence to enter/exit
+ * DSI Ultra-Low Power State (ULPS). This function assumes that the link and
+ * bus clocks are already on.
+ */
+static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ int ret = 0;
+ struct mdss_panel_data *pdata = NULL;
+ struct mdss_panel_info *pinfo;
+ struct mipi_panel_info *mipi;
+ u32 lane_status = 0;
+ u32 active_lanes = 0;
+
+ if (!ctrl) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &ctrl->panel_data;
+ if (!pdata) {
+ pr_err("%s: Invalid panel data\n", __func__);
+ return -EINVAL;
+ }
+ pinfo = &pdata->panel_info;
+ mipi = &pinfo->mipi;
+
+ if (!mdss_dsi_ulps_feature_enabled(pdata)) {
+ pr_debug("%s: ULPS feature not supported. enable=%d\n",
+ __func__, enable);
+ return -ENOTSUPP;
+ }
+
+ /*
+ * No need to enter ULPS when transitioning from splash screen to
+ * boot animation since it is expected that the clocks would be turned
+ * right back on.
+ */
+ if (pinfo->cont_splash_enabled) {
+ pr_debug("%s: skip ULPS config with splash screen enabled\n",
+ __func__);
+ return 0;
+ }
+
+ /* clock lane will always be programmed for ulps */
+ active_lanes = BIT(4);
+ /*
+ * make a note of all active data lanes for which ulps entry/exit
+ * is needed
+ */
+ if (mipi->data_lane0)
+ active_lanes |= BIT(0);
+ if (mipi->data_lane1)
+ active_lanes |= BIT(1);
+ if (mipi->data_lane2)
+ active_lanes |= BIT(2);
+ if (mipi->data_lane3)
+ active_lanes |= BIT(3);
+
+ pr_debug("%s: configuring ulps (%s) for ctrl%d, active lanes=0x%08x\n",
+ __func__, (enable ? "on" : "off"), ctrl->ndx,
+ active_lanes);
+
+ if (enable && !ctrl->ulps) {
+ /*
+ * ULPS Entry Request.
+ * Wait for a short duration to ensure that the lanes
+ * enter ULP state.
+ */
+ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes);
+ usleep(100);
+
+ /* Check to make sure that all active data lanes are in ULPS */
+ lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8);
+ if (lane_status & (active_lanes << 8)) {
+ pr_err("%s: ULPS entry req failed for ctrl%d. Lane status=0x%08x\n",
+ __func__, ctrl->ndx, lane_status);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ctrl->ulps = true;
+ } else if (!enable && ctrl->ulps) {
+ /*
+ * ULPS Exit Request
+ * Hardware requirement is to wait for at least 1ms
+ */
+ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, active_lanes << 8);
+ usleep(1000);
+ MIPI_OUTP(ctrl->ctrl_base + 0x0AC, 0x0);
+
+ /*
+ * Wait for a short duration before enabling
+ * data transmission
+ */
+ usleep(100);
+
+ lane_status = MIPI_INP(ctrl->ctrl_base + 0xA8);
+ ctrl->ulps = false;
+ } else {
+ pr_debug("%s: No change requested: %s -> %s\n", __func__,
+ ctrl->ulps ? "enabled" : "disabled",
+ enable ? "enabled" : "disabled");
+ }
+
+ pr_debug("%s: DSI lane status = 0x%08x. Ulps %s\n", __func__,
+ lane_status, enable ? "enabled" : "disabled");
+
+error:
+ return ret;
+}
+
+/**
+ * mdss_dsi_clamp_ctrl() - Program DSI clamps for supporting power collapse
+ * @ctrl: pointer to DSI controller structure
+ * @enable: 1 to enable clamps, 0 to disable clamps
+ *
+ * For idle-screen usecases with command mode panels, MDSS can be power
+ * collapsed. However, DSI phy needs to remain on. To avoid any mismatch
+ * between the DSI controller state, DSI phy needs to be clamped before
+ * power collapsing. This function executes the required programming
+ * sequence to configure these DSI clamps. This function should only be called
+ * when the DSI link clocks are disabled.
+ */
+static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable)
+{
+ struct mipi_panel_info *mipi = NULL;
+ u32 clamp_reg, regval = 0;
+ u32 clamp_reg_off, phyrst_reg_off;
+
+ if (!ctrl) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ if (!ctrl->mmss_misc_io.base) {
+ pr_err("%s: mmss_misc_io not mapped\nn", __func__);
+ return -EINVAL;
+ }
+
+ clamp_reg_off = ctrl->ulps_clamp_ctrl_off;
+ phyrst_reg_off = ctrl->ulps_phyrst_ctrl_off;
+ mipi = &ctrl->panel_data.panel_info.mipi;
+
+ /* clock lane will always be clamped */
+ clamp_reg = BIT(9);
+ if (ctrl->ulps)
+ clamp_reg |= BIT(8);
+ /* make a note of all active data lanes which need to be clamped */
+ if (mipi->data_lane0) {
+ clamp_reg |= BIT(7);
+ if (ctrl->ulps)
+ clamp_reg |= BIT(6);
+ }
+ if (mipi->data_lane1) {
+ clamp_reg |= BIT(5);
+ if (ctrl->ulps)
+ clamp_reg |= BIT(4);
+ }
+ if (mipi->data_lane2) {
+ clamp_reg |= BIT(3);
+ if (ctrl->ulps)
+ clamp_reg |= BIT(2);
+ }
+ if (mipi->data_lane3) {
+ clamp_reg |= BIT(1);
+ if (ctrl->ulps)
+ clamp_reg |= BIT(0);
+ }
+ pr_debug("%s: called for ctrl%d, enable=%d, clamp_reg=0x%08x\n",
+ __func__, ctrl->ndx, enable, clamp_reg);
+ if (enable && !ctrl->mmss_clamp) {
+ /* Enable MMSS DSI Clamps */
+ if (ctrl->ndx == DSI_CTRL_0) {
+ regval = MIPI_INP(ctrl->mmss_misc_io.base +
+ clamp_reg_off);
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval | clamp_reg);
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval | (clamp_reg | BIT(15)));
+ } else if (ctrl->ndx == DSI_CTRL_1) {
+ regval = MIPI_INP(ctrl->mmss_misc_io.base +
+ clamp_reg_off);
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval | (clamp_reg << 16));
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval | ((clamp_reg << 16) | BIT(31)));
+ }
+
+ /*
+ * This register write ensures that DSI PHY will not be
+ * reset when mdss ahb clock reset is asserted while coming
+ * out of power collapse
+ */
+ MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x1);
+ ctrl->mmss_clamp = true;
+ } else if (!enable && ctrl->mmss_clamp) {
+ MIPI_OUTP(ctrl->mmss_misc_io.base + phyrst_reg_off, 0x0);
+ /* Disable MMSS DSI Clamps */
+ if (ctrl->ndx == DSI_CTRL_0) {
+ regval = MIPI_INP(ctrl->mmss_misc_io.base +
+ clamp_reg_off);
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval & ~(clamp_reg | BIT(15)));
+ } else if (ctrl->ndx == DSI_CTRL_1) {
+ regval = MIPI_INP(ctrl->mmss_misc_io.base +
+ clamp_reg_off);
+ MIPI_OUTP(ctrl->mmss_misc_io.base + clamp_reg_off,
+ regval & ~((clamp_reg << 16) | BIT(31)));
+ }
+ ctrl->mmss_clamp = false;
+ } else {
+ pr_debug("%s: No change requested: %s -> %s\n", __func__,
+ ctrl->mmss_clamp ? "enabled" : "disabled",
+ enable ? "enabled" : "disabled");
+ }
+
+ return 0;
+}
+
+/**
+ * mdss_dsi_core_power_ctrl() - Enable/disable DSI core power
+ * @ctrl: pointer to DSI controller structure
+ * @enable: 1 to enable power, 0 to disable power
+ *
+ * When all DSI bus clocks are disabled, DSI core power module can be turned
+ * off to save any leakage current. This function implements the necessary
+ * programming sequence for the same. For command mode panels, the core power
+ * can be turned off for idle-screen usecases, where additional programming is
+ * needed to clamp DSI phy.
+ */
+static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
+ int enable)
+{
+ int rc = 0;
+ struct mdss_panel_data *pdata = NULL;
+
+ if (!ctrl) {
+ pr_err("%s: invalid input\n", __func__);
+ return -EINVAL;
+ }
+
+ pdata = &ctrl->panel_data;
+ if (!pdata) {
+ pr_err("%s: Invalid panel data\n", __func__);
+ return -EINVAL;
+ }
+
+ if (enable) {
+ if (!ctrl->core_power) {
+ /* enable mdss gdsc */
+ pr_debug("%s: Enable MDP FS\n", __func__);
+ rc = msm_dss_enable_vreg(
+ ctrl->power_data[DSI_CORE_PM].vreg_config,
+ ctrl->power_data[DSI_CORE_PM].num_vreg, 1);
+ if (rc) {
+ pr_err("%s: failed to enable vregs for %s\n",
+ __func__,
+ __mdss_dsi_pm_name(DSI_CORE_PM));
+ goto error;
+ }
+ ctrl->core_power = true;
+ }
+
+ rc = mdss_dsi_bus_clk_start(ctrl);
+ if (rc) {
+ pr_err("%s: Failed to start bus clocks. rc=%d\n",
+ __func__, rc);
+ goto error_bus_clk_start;
+ }
+
+ /*
+ * Phy software reset should not be done for idle screen power
+ * collapse use-case. Issue a phy software reset only when
+ * unblanking the panel.
+ */
+ if (!pdata->panel_info.panel_power_on)
+ mdss_dsi_phy_sw_reset(ctrl->ctrl_base);
+ mdss_dsi_phy_init(pdata);
+
+ mdss_dsi_ctrl_setup(pdata);
+
+ if (ctrl->ulps) {
+ /*
+ * ULPS Entry Request. This is needed if the lanes were
+ * in ULPS prior to power collapse, since after
+ * power collapse and reset, the DSI controller resets
+ * back to idle state and not ULPS. This ulps entry
+ * request will transition the state of the DSI
+ * controller to ULPS which will match the state of the
+ * DSI phy. This needs to be done prior to disabling
+ * the DSI clamps.
+ */
+ rc = mdss_dsi_ulps_config(ctrl, 1);
+ if (rc) {
+ pr_err("%s: Failed to enter ULPS. rc=%d\n",
+ __func__, rc);
+ goto error_ulps;
+ }
+ }
+
+ rc = mdss_dsi_clamp_ctrl(ctrl, 0);
+ if (rc) {
+ pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
+ __func__, rc);
+ goto error_ulps;
+ }
+ } else {
+ /* Enable DSI clamps only if entering idle power collapse */
+ if (ctrl->panel_data.panel_info.panel_power_on) {
+ rc = mdss_dsi_clamp_ctrl(ctrl, 1);
+ if (rc)
+ pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
+ __func__, rc);
+ }
+
+ /*
+ * disable bus clocks irrespective of whether dsi phy was
+ * successfully clamped or not
+ */
+ mdss_dsi_bus_clk_stop(ctrl);
+
+ /* disable mdss gdsc only if dsi phy was successfully clamped*/
+ if (rc) {
+ pr_debug("%s: leaving mdss gdsc on\n", __func__);
+ } else {
+ pr_debug("%s: Disable MDP FS\n", __func__);
+ rc = msm_dss_enable_vreg(
+ ctrl->power_data[DSI_CORE_PM].vreg_config,
+ ctrl->power_data[DSI_CORE_PM].num_vreg, 0);
+ if (rc) {
+ pr_warn("%s: failed to disable vregs for %s\n",
+ __func__,
+ __mdss_dsi_pm_name(DSI_CORE_PM));
+ rc = 0;
+ } else {
+ ctrl->core_power = false;
+ }
+ }
+ }
+ return rc;
+
+error_ulps:
+ mdss_dsi_bus_clk_stop(ctrl);
+error_bus_clk_start:
+ if (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config,
+ ctrl->power_data[DSI_CORE_PM].num_vreg, 0))
+ pr_warn("%s: failed to disable vregs for %s\n",
+ __func__, __mdss_dsi_pm_name(DSI_CORE_PM));
+ else
+ ctrl->core_power = false;
+error:
+ return rc;
+}
+
static int __mdss_dsi_update_clk_cnt(u32 *clk_cnt, int enable)
{
int changed = 0;
@@ -510,6 +870,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
{
int rc = 0;
struct mdss_panel_data *pdata;
+ bool core_power_enabled = false;
if (!ctrl) {
pr_err("%s: Invalid arg\n", __func__);
@@ -523,41 +884,37 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
if (enable) {
if (clk_type & DSI_BUS_CLKS) {
- /* enable mdss gdsc */
- pr_debug("%s: Enable MDP FS\n", __func__);
- rc = msm_dss_enable_vreg(
- ctrl->power_data[DSI_CORE_PM].vreg_config,
- ctrl->power_data[DSI_CORE_PM].num_vreg, 1);
+ rc = mdss_dsi_core_power_ctrl(ctrl, enable);
if (rc) {
- pr_err("%s: failed to enable vregs for %s\n",
- __func__,
- __mdss_dsi_pm_name(DSI_CORE_PM));
+ pr_err("%s: Failed to enable core power. rc=%d\n",
+ __func__, rc);
goto error;
}
-
- rc = mdss_dsi_bus_clk_start(ctrl);
- if (rc) {
- pr_err("Failed to start bus clocks. rc=%d\n",
- rc);
- goto error_vreg;
- }
+ core_power_enabled = true;
}
if (clk_type & DSI_LINK_CLKS) {
rc = mdss_dsi_link_clk_start(ctrl);
if (rc) {
- pr_err("Failed to start link clocks. rc=%d\n",
- rc);
+ pr_err("%s: Failed to start link clocks. rc=%d\n",
+ __func__, rc);
goto error_link_clk_start;
}
/* Disable ULPS, if enabled */
if (ctrl->ulps) {
rc = mdss_dsi_ulps_config(ctrl, 0);
if (rc) {
- pr_err("Failed to exit ulps. rc=%d\n",
- rc);
+ pr_err("%s: Failed to exit ulps. rc=%d\n",
+ __func__, rc);
goto error_ulps_exit;
}
}
+
+ /*
+ * If we are coming out of idle power collapse, then
+ * reset DSI controller state
+ */
+ if (core_power_enabled)
+ mdss_dsi_reset(ctrl);
}
} else {
if (clk_type & DSI_LINK_CLKS) {
@@ -572,18 +929,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
mdss_dsi_link_clk_stop(ctrl);
}
if (clk_type & DSI_BUS_CLKS) {
- mdss_dsi_bus_clk_stop(ctrl);
-
- /* disable mdss gdsc */
- pr_debug("%s: Disable MDP FS\n", __func__);
- rc = msm_dss_enable_vreg(
- ctrl->power_data[DSI_CORE_PM].vreg_config,
- ctrl->power_data[DSI_CORE_PM].num_vreg, 0);
+ rc = mdss_dsi_core_power_ctrl(ctrl, enable);
if (rc) {
- pr_warn("%s: failed to disable vregs for %s\n",
- __func__,
- __mdss_dsi_pm_name(DSI_CORE_PM));
- rc = 0;
+ pr_err("%s: Failed to disable core power. rc=%d\n",
+ __func__, rc);
}
}
}
@@ -593,15 +942,10 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl,
error_ulps_exit:
mdss_dsi_link_clk_stop(ctrl);
error_link_clk_start:
- if (clk_type & DSI_BUS_CLKS)
- mdss_dsi_bus_clk_stop(ctrl);
-error_vreg:
if ((clk_type & DSI_BUS_CLKS) &&
- (msm_dss_enable_vreg(ctrl->power_data[DSI_CORE_PM].vreg_config,
- ctrl->power_data[DSI_CORE_PM].num_vreg, 0))) {
- pr_warn("%s: failed to disable vregs for %s\n", __func__,
- __mdss_dsi_pm_name(DSI_CORE_PM));
- }
+ (mdss_dsi_core_power_ctrl(ctrl, !enable)))
+ pr_warn("%s: Failed to disable core power. rc=%d\n",
+ __func__, rc);
error:
return rc;
}