int mdss_dsi_cont_splash_on(struct mdss_panel_data *pdata) { int ret = 0; struct mipi_panel_info *mipi; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; pr_info("%s:%d DSI on for continuous splash.\n", __func__, __LINE__); if (pdata == NULL) { pr_err("%s: Invalid input data\n", __func__); return -EINVAL; } mipi = &pdata->panel_info.mipi; ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); pr_debug("%s+: ctrl=%p ndx=%d\n", __func__, ctrl_pdata, ctrl_pdata->ndx); WARN((ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT), "Incorrect Ctrl state=0x%x\n", ctrl_pdata->ctrl_state); mdss_dsi_ctrl_setup(ctrl_pdata); mdss_dsi_sw_reset(ctrl_pdata, true); pr_debug("%s-:End\n", __func__); return ret; }
/** * 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) { 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; }