diff options
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 224 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/msm_mdss_io_8974.c | 420 |
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; } |
