static int mdss_dsi_blank(struct mdss_panel_data *pdata) { int ret = 0; struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; pr_debug("%s+:\n", __func__); if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL && ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) { mdss_dsi_sw_reset(pdata); mdss_dsi_host_init(pdata); } if (__mdss_dsi_ulps_feature_enabled(pdata) && (ctrl_pdata->ulps)) { /* Disable ULPS mode before blanking the panel */ ret = mdss_dsi_ulps_config(ctrl_pdata, 0); if (ret) { pr_err("%s: failed to exit ULPS mode. rc=%d\n", __func__, ret); return ret; } } mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); if (pdata->panel_info.type == MIPI_CMD_PANEL) { if (mipi->vsync_enable && mipi->hw_vsync_mode && gpio_is_valid(ctrl_pdata->disp_te_gpio)) { mdss_dsi_set_tear_off(ctrl_pdata); } } if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { ret = ctrl_pdata->off(pdata); if (ret) { pr_err("%s: Panel OFF failed\n", __func__); return ret; } ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; } pr_debug("%s-:End\n", __func__); return ret; }
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+:event=%d\n", __func__, event); switch (event) { case MDSS_EVENT_UNBLANK: rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_PANEL_ON: ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_BLANK: if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_blank(pdata); break; case MDSS_EVENT_PANEL_OFF: ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); rc = mdss_dsi_off(pdata); break; case MDSS_EVENT_CONT_SPLASH_FINISH: if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; rc = mdss_dsi_cont_splash_on(pdata); break; case MDSS_EVENT_PANEL_CONT_SPLASH_FINISH: if (ctrl_pdata->cont_splash_on) rc = ctrl_pdata->cont_splash_on(pdata); break; case MDSS_EVENT_PANEL_CLK_CTRL: mdss_dsi_clk_req(ctrl_pdata, (int)arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: mdss_dsi_cmdlist_commit(ctrl_pdata, 1, NULL); break; case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { rc = mdss_dsi_dfps_config(pdata, (int)arg); pr_debug("%s:update fps to = %d\n", __func__, (int)arg); } break; case MDSS_EVENT_CONT_SPLASH_BEGIN: /* * TODO: Stubbed out for now until we can remove whole * black screen when kernel starts. */ break; case MDSS_EVENT_ENABLE_PARTIAL_UPDATE: rc = mdss_dsi_ctl_partial_update(pdata); break; case MDSS_EVENT_DSI_ULPS_CTRL: rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg); break; case MDSS_EVENT_REGISTER_RECOVERY_HANDLER: rc = mdss_dsi_register_recovery_handler(ctrl_pdata, (struct mdss_panel_recovery *)arg); break; case MDSS_EVENT_SET_CABC: if (ctrl_pdata->set_cabc) rc = ctrl_pdata->set_cabc(ctrl_pdata, (int)arg); break; case MDSS_EVENT_ENABLE_TE: rc = mdss_dsi_hndl_enable_te(ctrl_pdata, (int) arg); break; case MDSS_EVENT_ENABLE_HBM: rc = mdss_dsi_hndl_enable_hbm(ctrl_pdata, (int) arg); break; default: pr_debug("%s: unhandled event=%d\n", __func__, event); break; } pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); return rc; }
static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; struct mdss_panel_data *pdata; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__, ctrl->ndx, clk_type, enable); if (enable) { if (clk_type & DSI_BUS_CLKS) { rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: Failed to enable core power. rc=%d\n", __func__, rc); goto error; } } if (clk_type & DSI_LINK_CLKS) { rc = mdss_dsi_link_clk_start(ctrl); if (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("%s: Failed to exit ulps. rc=%d\n", __func__, rc); goto error_ulps_exit; } } } } else { if (clk_type & DSI_LINK_CLKS) { /* * If ULPS feature is enabled, enter ULPS first. * If ULPS during suspend is not enabled, no need * to enable ULPS when turning off the clocks * while blanking the panel. */ if (((mdss_dsi_ulps_feature_enabled(pdata)) && (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK)) || (pdata->panel_info.ulps_suspend_enabled)) mdss_dsi_ulps_config(ctrl, 1); mdss_dsi_link_clk_stop(ctrl); } if (clk_type & DSI_BUS_CLKS) { rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: Failed to disable core power. rc=%d\n", __func__, rc); } } } return rc; error_ulps_exit: mdss_dsi_link_clk_stop(ctrl); error_link_clk_start: if ((clk_type & DSI_BUS_CLKS) && (mdss_dsi_core_power_ctrl(ctrl, !enable))) pr_warn("%s: Failed to disable core power. rc=%d\n", __func__, rc); error: return rc; }
/** * 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: * 1.) Idle screen power collapse use-case. Issue a phy software * reset only when unblanking the panel in this case. * 2.) When ULPS during suspend is enabled. */ if (pdata->panel_info.blank_state == MDSS_PANEL_BLANK_BLANK && !pdata->panel_info.ulps_suspend_enabled) mdss_dsi_phy_sw_reset(ctrl); /* * Phy and controller setup need not be done during bootup * when continuous splash screen is enabled. */ if (!pdata->panel_info.cont_splash_enabled) { mdss_dsi_phy_init(ctrl); mdss_dsi_ctrl_setup(ctrl); } 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. * * Also, reset the ulps flag so that ulps_config * function would reconfigure the controller state to * ULPS. */ ctrl->ulps = false; 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 or * when ULPS during suspend is enabled. */ if ((pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK) || pdata->panel_info.ulps_suspend_enabled) { 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_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; struct mdss_panel_data *pdata; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__, ctrl->ndx, clk_type, enable); 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); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); 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; } } 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); 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); goto error_ulps_exit; } } } } else { if (clk_type & DSI_LINK_CLKS) { /* * If ULPS feature is enabled, enter ULPS first. * No need to enable ULPS when turning off clocks * while blanking the panel. */ if ((mdss_dsi_ulps_feature_enabled(pdata)) && (pdata->panel_info.panel_power_on)) mdss_dsi_ulps_config(ctrl, 1); 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); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; } } } return rc; 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)); } error: return rc; }
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, int event, void *arg) { int rc = 0; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+:event=%d\n", __func__, event); MDSS_XLOG(event, arg, ctrl_pdata->ndx, 0x3333); switch (event) { case MDSS_EVENT_UNBLANK: rc = mdss_dsi_on(pdata); mdss_dsi_op_mode_config(pdata->panel_info.mipi.mode, pdata); if (ctrl_pdata->on_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_PANEL_ON: ctrl_pdata->ctrl_state |= CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->on_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_unblank(pdata); break; case MDSS_EVENT_BLANK: if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) rc = mdss_dsi_blank(pdata); break; case MDSS_EVENT_PANEL_OFF: ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); rc = mdss_dsi_off(pdata); break; case MDSS_EVENT_CONT_SPLASH_FINISH: if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) rc = mdss_dsi_blank(pdata); ctrl_pdata->ctrl_state &= ~CTRL_STATE_MDP_ACTIVE; rc = mdss_dsi_cont_splash_on(pdata); break; case MDSS_EVENT_PANEL_CLK_CTRL: mdss_dsi_clk_req(ctrl_pdata, (int)arg); break; case MDSS_EVENT_DSI_CMDLIST_KOFF: mdss_dsi_cmdlist_commit(ctrl_pdata, 1); break; case MDSS_EVENT_PANEL_UPDATE_FPS: if (arg != NULL) { rc = mdss_dsi_dfps_config(pdata, (int)arg); pr_debug("%s:update fps to = %d\n", __func__, (int)arg); } break; case MDSS_EVENT_CONT_SPLASH_BEGIN: if (ctrl_pdata->off_cmds.link_state == DSI_HS_MODE) { /* Panel is Enabled in Bootloader */ rc = mdss_dsi_blank(pdata); } break; case MDSS_EVENT_ENABLE_PARTIAL_UPDATE: rc = mdss_dsi_ctl_partial_update(pdata); break; case MDSS_EVENT_DSI_ULPS_CTRL: rc = mdss_dsi_ulps_config(ctrl_pdata, (int)arg); break; case MDSS_EVENT_REGISTER_RECOVERY_HANDLER: rc = mdss_dsi_register_recovery_handler(ctrl_pdata, (struct mdss_panel_recovery *)arg); break; case MDSS_EVENT_DSI_DYNAMIC_SWITCH: rc = mdss_dsi_update_panel_config(ctrl_pdata, (int)(unsigned long) arg); break; default: pr_debug("%s: unhandled event=%d\n", __func__, event); break; } pr_debug("%s-:event=%d, rc=%d\n", __func__, event, rc); return rc; }
static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; struct mdss_panel_data *pdata; if (!ctrl) { pr_err("%s: Invalid arg\n", __func__); return -EINVAL; } pdata = &ctrl->panel_data; pr_debug("%s: ndx=%d clk_type=%08x enable=%d\n", __func__, ctrl->ndx, clk_type, enable); 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); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); 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; } } if (clk_type & DSI_LINK_CLKS) { if (ctrl->mmss_clamp) { mdss_dsi_phy_init(pdata); mdss_dsi_ctrl_setup(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. */ mdss_dsi_ulps_config(ctrl, 1); mdss_dsi_clamp_ctrl(ctrl, 0); } rc = mdss_dsi_link_clk_start(ctrl); if (rc) { pr_err("Failed to start link clocks. rc=%d\n", 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); goto error_ulps_exit; } } } } else { if (clk_type & DSI_LINK_CLKS) { /* * If ULPS feature is enabled, enter ULPS first. * No need to enable ULPS when turning off clocks * while blanking the panel. */ if (((mdss_dsi_ulps_feature_enabled(pdata)) && (pdata->panel_info.panel_power_on)) || (pdata->panel_info.ulps_suspend_enabled && !pdata->panel_info.panel_power_on)) { mdss_dsi_ulps_config(ctrl, 1); mdss_dsi_link_clk_stop(ctrl); mdss_dsi_clamp_ctrl(ctrl, 1); } else { 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); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_CORE_PM)); rc = 0; } } } return rc; 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)); } error: return rc; }
/** * 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; u32 ctrl_rev; 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; } /* * temp workaround until framework issues pertaining to LP2 * power state transitions are fixed. For now, if we intend to * send a frame update when in LP1, we have to explicitly exit * LP2 state here */ if (mdss_dsi_is_panel_on_ulp(pdata)) mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP1); 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 and controller setup is needed if coming out of idle * power collapse with clamps enabled. */ if (ctrl->mmss_clamp) { ctrl_rev = MIPI_INP(ctrl->ctrl_base); if (ctrl_rev == MDSS_DSI_HW_REV_103) mdss_dsi_20nm_phy_init(pdata); else mdss_dsi_phy_init(pdata); mdss_dsi_ctrl_setup(ctrl); } 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. * * Also, reset the ulps flag so that ulps_config * function would reconfigure the controller state to * ULPS. */ ctrl->ulps = false; 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 (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK) { rc = mdss_dsi_clamp_ctrl(ctrl, 1); if (rc) pr_err("%s: Failed to enable dsi clamps. rc=%d\n", __func__, rc); } else { /* * Make sure that controller is not in ULPS state when * the DSI link is not active. */ rc = mdss_dsi_ulps_config(ctrl, 0); if (rc) pr_err("%s: failed to disable ulps. 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; } } /* * temp workaround until framework issues pertaining to LP2 * power state transitions are fixed. For now, we internally * transition to LP2 state whenever core power is turned off * in LP1 state */ if (mdss_dsi_is_panel_on_lp(pdata)) mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_LP2); } 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; }