diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 64fec36fc3fc..959eb9fd691a 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -76,19 +76,21 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable) panel_data); pr_debug("%s: enable=%d\n", __func__, enable); - if (pdata->panel_info.dynamic_switch_pending) { - /* - * Current implementation of dynamic mode switch - * relies on the GDSC to be disabled while switching. - */ - msm_dss_enable_vreg( - ctrl_pdata->power_data[DSI_CORE_PM].vreg_config, - ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable); + /* + * If a dynamic mode switch is pending, the regulators should not + * be turned off or on. + */ + if (pdata->panel_info.dynamic_switch_pending) return 0; - } if (enable) { for (i = 0; i < DSI_MAX_PM; i++) { + /* + * Core power module will be enabled when the + * clocks are enabled + */ + if (DSI_CORE_PM == i) + continue; ret = msm_dss_enable_vreg( ctrl_pdata->power_data[i].vreg_config, ctrl_pdata->power_data[i].num_vreg, 1); @@ -121,6 +123,12 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable) pr_debug("reset disable: pinctrl not enabled\n"); for (i = DSI_MAX_PM - 1; i >= 0; i--) { + /* + * Core power module will be disabled when the + * clocks are disabled + */ + if (DSI_CORE_PM == i) + continue; ret = msm_dss_enable_vreg( ctrl_pdata->power_data[i].vreg_config, ctrl_pdata->power_data[i].num_vreg, 0); @@ -483,85 +491,93 @@ static void __mdss_dsi_ctrl_setup(struct mdss_panel_data *pdata) } } -static inline bool __mdss_dsi_ulps_feature_enabled( - struct mdss_panel_data *pdata) -{ - return pdata->panel_info.ulps_feature_enabled; -} - -static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, - int enable) +int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int enable) { int ret = 0; struct mdss_panel_data *pdata = NULL; - struct mipi_panel_info *pinfo = NULL; - u32 lane_status = 0; - u32 active_lanes = 0; - u32 regval = 0; + struct mdss_panel_info *pinfo; + struct mipi_panel_info *mipi; + u32 lane_status = 0, regval; + u32 active_lanes = 0, clamp_reg; 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 = &pdata->panel_info; + mipi = &pinfo->mipi; - if (!__mdss_dsi_ulps_feature_enabled(pdata)) { + 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) { - /* No need to configure ULPS mode when entering suspend state */ - if (!pdata->panel_info.panel_power_on) { - pr_err("%s: panel off. returning\n", __func__); - goto error; - } - - if (__mdss_dsi_clk_enabled(ctrl_pdata, DSI_LINK_CLKS)) { - pr_err("%s: cannot enter ulps mode if dsi clocks are on\n", - __func__); - ret = -EPERM; - goto error; - } - - ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); - if (ret) { - pr_err("%s: Failed to enable clocks. rc=%d\n", - __func__, ret); - goto error; - } - /* * ULPS Entry Request. * Wait for a short duration to ensure that the lanes * enter ULP state. */ - MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F); + MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes); usleep(100); /* Check to make sure that all active data lanes are in ULPS */ - if (pinfo->data_lane3) - active_lanes |= BIT(11); - if (pinfo->data_lane2) - active_lanes |= BIT(10); - if (pinfo->data_lane1) - active_lanes |= BIT(9); - if (pinfo->data_lane0) - active_lanes |= BIT(8); - active_lanes |= BIT(12); /* clock lane */ lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); - if (lane_status & active_lanes) { - pr_err("%s: ULPS entry req failed. Lane status=0x%08x\n", - __func__, lane_status); + 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; - mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); goto error; } @@ -569,15 +585,15 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, if (ctrl_pdata->ndx == DSI_CTRL_0) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval | 0x3FF); + regval | clamp_reg); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval | 0x83FF); + regval | (clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval | 0x3FF0000); + regval | (clamp_reg << 16)); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval | 0x83FF0000); + regval | ((clamp_reg << 16) | BIT(31))); } wmb(); @@ -588,19 +604,8 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, * out of power collapse */ MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x1); - /* disable DSI controller */ - mdss_dsi_controller_cfg(0, pdata); - - mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); ctrl_pdata->ulps = true; } else if (ctrl_pdata->ulps) { - 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); - goto error; - } - MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x108, 0x0); mdss_dsi_phy_init(pdata); @@ -617,33 +622,26 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, * Wait for a short duration to ensure that the lanes * enter ULP state. */ - MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x01F); + 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 + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval & ~0x83FF); + regval & ~(clamp_reg | BIT(15))); } else if (ctrl_pdata->ndx == DSI_CTRL_1) { regval = MIPI_INP(ctrl_pdata->mmss_misc_io.base + 0x14); MIPI_OUTP(ctrl_pdata->mmss_misc_io.base + 0x14, - regval & ~0x83FF0000); + regval & ~((clamp_reg << 16) | BIT(31))); } - ret = mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 1); - if (ret) { - pr_err("%s: Failed to enable link clocks. rc=%d\n", - __func__, ret); - mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); - goto error; - } /* * ULPS Exit Request * Hardware requirement is to wait for at least 1ms */ - MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x1F00); + MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, active_lanes << 8); usleep(1000); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x0AC, 0x0); @@ -654,8 +652,6 @@ static int mdss_dsi_ulps_config_sub(struct mdss_dsi_ctrl_pdata *ctrl_pdata, usleep(100); lane_status = MIPI_INP(ctrl_pdata->ctrl_base + 0xA8); - mdss_dsi_clk_ctrl(ctrl_pdata, DSI_LINK_CLKS, 0); - mdss_dsi_clk_ctrl(ctrl_pdata, DSI_BUS_CLKS, 0); ctrl_pdata->ulps = false; } @@ -691,78 +687,6 @@ static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, return ret; } -static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, - int enable) -{ - int rc; - struct mdss_dsi_ctrl_pdata *mctrl = NULL; - struct mdss_dsi_ctrl_pdata *sctrl = NULL; - - if (&ctrl->mmss_misc_io == NULL) { - pr_err("%s: mmss_misc_io is NULL. ULPS not valid\n", __func__); - return -EINVAL; - } - - if (mdss_dsi_is_master_ctrl(ctrl)) { - if (enable) { - pr_debug("%s: skipping enable for master ctrl%d\n", - __func__, ctrl->ndx); - rc = 0; - goto error; - } else { - sctrl = mdss_dsi_get_slave_ctrl(); - if (!sctrl) { - pr_err("%s: Unable to get slave control\n", - __func__); - rc = -EINVAL; - goto error; - } - } - } - - if (mdss_dsi_is_slave_ctrl(ctrl)) { - if (enable) { - mctrl = mdss_dsi_get_master_ctrl(); - if (!mctrl) { - pr_err("%s: Unable to get master control\n", - __func__); - rc = -EINVAL; - goto error; - } - } else { - pr_debug("%s: skipping disable for slave ctrl%d\n", - __func__, ctrl->ndx); - rc = 0; - goto error; - } - } - - if (mctrl) { - pr_debug("%s: configuring ulps (%s) for master ctrl%d\n", - __func__, (enable ? "on" : "off"), mctrl->ndx); - rc = mdss_dsi_ulps_config_sub(mctrl, enable); - if (rc) - goto error; - } - - pr_debug("%s: configuring ulps (%s) for ctrl%d\n", - __func__, (enable ? "on" : "off"), ctrl->ndx); - rc = mdss_dsi_ulps_config_sub(ctrl, enable); - if (rc) - goto error; - - if (sctrl) { - pr_debug("%s: configuring ulps (%s) for slave ctrl%d\n", - __func__, (enable ? "on" : "off"), sctrl->ndx); - rc = mdss_dsi_ulps_config_sub(sctrl, enable); - } - -error: - if (rc) - pr_err("%s: Failed to configure ulps (%s) for ctrl%d\n", - __func__, (enable ? "on" : "off"), ctrl->ndx); - return rc; -} int mdss_dsi_on(struct mdss_panel_data *pdata) { @@ -920,13 +844,15 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) panel_data); mipi = &pdata->panel_info.mipi; + mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); + if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { if (!pdata->panel_info.dynamic_switch_pending) { ret = ctrl_pdata->on(pdata); if (ret) { pr_err("%s: unable to initialize the panel\n", __func__); - return ret; + goto error; } } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; @@ -936,6 +862,8 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) mipi->vsync_enable && mipi->hw_vsync_mode) mdss_dsi_set_tear_on(ctrl_pdata); +error: + mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); pr_debug("%s-:\n", __func__); return ret; @@ -958,16 +886,7 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata) panel_data); mipi = &pdata->panel_info.mipi; - 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_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); if (pdata->panel_info.type == MIPI_VIDEO_PANEL && ctrl_pdata->off_cmds.link_state == DSI_LP_MODE) { @@ -997,12 +916,14 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata) ret = ctrl_pdata->off(pdata); if (ret) { pr_err("%s: Panel OFF failed\n", __func__); - return ret; + goto error; } } ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; } +error: + mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); pr_debug("%s-:End\n", __func__); return ret; } @@ -1270,9 +1191,6 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_DSI_STREAM_SIZE: rc = mdss_dsi_set_stream_size(pdata); break; - case MDSS_EVENT_DSI_ULPS_CTRL: - rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg); - break; case MDSS_EVENT_DSI_DYNAMIC_SWITCH: rc = mdss_dsi_update_panel_config(ctrl_pdata, (int)(unsigned long) arg); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index c36a4853ece0..c6a0423f919d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -398,6 +398,7 @@ 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); int mdss_dsi_panel_init(struct device_node *node, struct mdss_dsi_ctrl_pdata *ctrl_pdata, @@ -468,4 +469,11 @@ static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx) return ctrl_list[ndx]; } + +static inline bool mdss_dsi_ulps_feature_enabled( + struct mdss_panel_data *pdata) +{ + return pdata->panel_info.ulps_feature_enabled; +} + #endif /* MDSS_DSI_H */ diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 8a4448f2da45..2cde227b6fdf 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -18,7 +18,7 @@ #include "mdss_debug.h" #include "mdss_mdp_trace.h" -#define VSYNC_EXPIRE_TICK 4 +#define VSYNC_EXPIRE_TICK 6 #define MAX_SESSIONS 2 @@ -26,7 +26,7 @@ #define KOFF_TIMEOUT msecs_to_jiffies(84) #define STOP_TIMEOUT(hz) msecs_to_jiffies((1000 / hz) * (VSYNC_EXPIRE_TICK + 2)) -#define ULPS_ENTER_TIME msecs_to_jiffies(100) +#define POWER_COLLAPSE_TIME msecs_to_jiffies(100) struct mdss_mdp_cmd_ctx { struct mdss_mdp_ctl *ctl; @@ -43,12 +43,12 @@ struct mdss_mdp_cmd_ctx { struct mutex clk_mtx; spinlock_t clk_lock; struct work_struct clk_work; - struct delayed_work ulps_work; + struct delayed_work pc_work; struct work_struct pp_done_work; atomic_t pp_done_cnt; struct mdss_panel_recovery recovery; - bool ulps; struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */ + bool idle_pc; }; struct mdss_mdp_cmd_ctx mdss_mdp_cmd_ctx_list[MAX_SESSIONS]; @@ -195,17 +195,15 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx) ctx->rdptr_enabled); if (!ctx->clk_enabled) { ctx->clk_enabled = 1; - if (cancel_delayed_work_sync(&ctx->ulps_work)) - pr_debug("deleted pending ulps work\n"); + if (cancel_delayed_work_sync(&ctx->pc_work)) + pr_debug("deleted pending power collapse work\n"); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false); - if (ctx->ulps) { + if (ctx->idle_pc) { if (mdss_mdp_cmd_tearcheck_setup(ctx->ctl)) pr_warn("tearcheck setup failed\n"); - mdss_mdp_ctl_intf_event(ctx->ctl, - MDSS_EVENT_DSI_ULPS_CTRL, (void *)0); - ctx->ulps = false; + ctx->idle_pc = false; } mdss_mdp_ctl_intf_event @@ -241,8 +239,9 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx) mdss_mdp_ctl_intf_event (ctx->ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF, false); - if (ctx->panel_on) - schedule_delayed_work(&ctx->ulps_work, ULPS_ENTER_TIME); + if ((ctx->panel_on) && (mdata->idle_pc_enabled)) + schedule_delayed_work(&ctx->pc_work, + POWER_COLLAPSE_TIME); } mutex_unlock(&ctx->clk_mtx); } @@ -388,12 +387,11 @@ static void clk_ctrl_work(struct work_struct *work) mdss_mdp_cmd_clk_off(ctx); } -static void __mdss_mdp_cmd_ulps_work(struct work_struct *work) +static void __mdss_mdp_cmd_pc_work(struct work_struct *work) { struct delayed_work *dw = to_delayed_work(work); - struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_cmd_ctx *ctx = - container_of(dw, struct mdss_mdp_cmd_ctx, ulps_work); + container_of(dw, struct mdss_mdp_cmd_ctx, pc_work); if (!ctx) { pr_err("%s: invalid ctx\n", __func__); @@ -401,19 +399,13 @@ static void __mdss_mdp_cmd_ulps_work(struct work_struct *work) } if (!ctx->panel_on) { - pr_err("Panel is off. skipping ULPS configuration\n"); + pr_err("Panel is off. skipping power collapse\n"); return; } - if (!mdss_mdp_ctl_intf_event(ctx->ctl, MDSS_EVENT_DSI_ULPS_CTRL, - (void *)1)) { - ctx->ulps = true; - if (mdata->idle_pc_enabled) { - ctx->ctl->play_cnt = 0; - mdss_mdp_footswitch_ctrl_idle_pc(0, - &ctx->ctl->mfd->pdev->dev); - } - } + ctx->idle_pc = true; + ctx->ctl->play_cnt = 0; + mdss_mdp_footswitch_ctrl_idle_pc(0, &ctx->ctl->mfd->pdev->dev); } static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl, @@ -504,10 +496,10 @@ int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff) pdata = ctl->panel_data; - pdata->panel_info.cont_splash_enabled = 0; - mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL, (void *)0); + pdata->panel_info.cont_splash_enabled = 0; + return ret; } @@ -797,8 +789,8 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) if (cancel_work_sync(&ctx->clk_work)) pr_debug("no pending clk work\n"); - if (cancel_delayed_work_sync(&ctx->ulps_work)) - pr_debug("deleted pending ulps work\n"); + if (cancel_delayed_work_sync(&ctx->pc_work)) + pr_debug("deleted pending power collapse work\n"); ctx->panel_on = 0; mdss_mdp_cmd_clk_off(ctx); @@ -811,9 +803,6 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num, NULL, NULL); - memset(ctx, 0, sizeof(*ctx)); - ctl->priv_data = NULL; - if (ctl->num == 0) { ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_BLANK, NULL); WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret); @@ -822,6 +811,9 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) WARN(ret, "intf %d unblank error (%d)\n", ctl->intf_num, ret); } + memset(ctx, 0, sizeof(*ctx)); + ctl->priv_data = NULL; + ctl->stop_fnc = NULL; ctl->display_fnc = NULL; ctl->wait_pingpong = NULL; @@ -874,7 +866,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl) spin_lock_init(&ctx->clk_lock); mutex_init(&ctx->clk_mtx); INIT_WORK(&ctx->clk_work, clk_ctrl_work); - INIT_DELAYED_WORK(&ctx->ulps_work, __mdss_mdp_cmd_ulps_work); + INIT_DELAYED_WORK(&ctx->pc_work, __mdss_mdp_cmd_pc_work); INIT_WORK(&ctx->pp_done_work, pingpong_done_work); atomic_set(&ctx->pp_done_cnt, 0); INIT_LIST_HEAD(&ctx->vsync_handlers); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 8ced70aa7509..e8da81db0798 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -135,11 +135,6 @@ struct mdss_panel_recovery { * @MDSS_EVENT_DSI_CMDLIST_KOFF: acquire dsi_mdp_busy lock before kickoff. * @MDSS_EVENT_ENABLE_PARTIAL_ROI: Event to update ROI of the panel. * @MDSS_EVENT_DSI_STREAM_SIZE: Event to update DSI controller's stream size - * @MDSS_EVENT_DSI_ULPS_CTRL: Event to configure Ultra Lower Power Saving - * mode for the DSI data and clock lanes. The - * event arguments can have one of these values: - * - 0: Disable ULPS mode - * - 1: Enable ULPS mode * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures * based on the dsi mode passed as argument. * - 0: update to video mode @@ -163,7 +158,6 @@ enum mdss_intf_events { MDSS_EVENT_DSI_CMDLIST_KOFF, MDSS_EVENT_ENABLE_PARTIAL_ROI, MDSS_EVENT_DSI_STREAM_SIZE, - MDSS_EVENT_DSI_ULPS_CTRL, MDSS_EVENT_DSI_DYNAMIC_SWITCH, }; diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 1edd23284c87..f0d5201ed58c 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -509,22 +509,37 @@ 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; + goto error_vreg; } } if (clk_type & DSI_LINK_CLKS) { @@ -532,18 +547,61 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, if (rc) { pr_err("Failed to start link clocks. rc=%d\n", rc); - if (clk_type & DSI_BUS_CLKS) - mdss_dsi_bus_clk_stop(ctrl); - goto error; + 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 (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) + } + 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; } @@ -569,7 +627,8 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; - int changed = 0, m_changed = 0; + int link_changed = 0, bus_changed = 0; + int m_link_changed = 0, m_bus_changed = 0; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (!ctrl) { @@ -588,62 +647,78 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, pr_warn("%s: Unable to get master control\n", __func__); } - pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d", + pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, ctrl->link_clk_cnt); - pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, enable=%d\n", + pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, enable); mutex_lock(&dsi_clk_lock); + if (clk_type & DSI_BUS_CLKS) { - changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, + bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable); - if (changed && mctrl) - m_changed = __mdss_dsi_update_clk_cnt( + if (bus_changed && mctrl) + m_bus_changed = __mdss_dsi_update_clk_cnt( &mctrl->bus_clk_cnt, enable); } if (clk_type & DSI_LINK_CLKS) { - changed += __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, + link_changed = __mdss_dsi_update_clk_cnt(&ctrl->link_clk_cnt, enable); - if (changed && mctrl) - m_changed += __mdss_dsi_update_clk_cnt( + if (link_changed && mctrl) + m_link_changed = __mdss_dsi_update_clk_cnt( &mctrl->link_clk_cnt, enable); } - if (changed) { - if (enable && m_changed) { - rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); - if (rc) { - pr_err("Failed to start mctrl clocks. rc=%d\n", - rc); - goto error_mctrl_start; - } - } + if (!link_changed && !bus_changed) + goto no_error; /* clk cnts updated, nothing else needed */ - rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); + /* + * If updating link clock, need to make sure that the bus + * clocks are enabled + */ + if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) { + pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", + __func__, mctrl->ndx); + goto error_mctrl_start; + } + + if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) { + pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", + __func__, ctrl->ndx); + goto error_mctrl_start; + } + + if (enable && (m_bus_changed || m_link_changed)) { + rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); if (rc) { - pr_err("Failed to %s ctrl clocks. rc=%d\n", - (enable ? "start" : "stop"), rc); - goto error_ctrl; - } - - if (!enable && m_changed) { - rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); - if (rc) { - pr_err("Failed to stop mctrl clocks. rc=%d\n", - rc); - goto error_mctrl_stop; - } + pr_err("Failed to start mctrl clocks. rc=%d\n", rc); + goto error_mctrl_start; } } + + if (!enable && (m_bus_changed || m_link_changed)) { + rc = mdss_dsi_clk_ctrl_sub(mctrl, clk_type, enable); + if (rc) { + pr_err("Failed to stop mctrl clocks. rc=%d\n", rc); + goto error_mctrl_stop; + } + } + rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); + if (rc) { + pr_err("Failed to %s ctrl clocks. rc=%d\n", + (enable ? "start" : "stop"), rc); + goto error_ctrl; + } + goto no_error; error_mctrl_stop: mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable ? 0 : 1); error_ctrl: - if (enable && m_changed) + if (enable && (m_bus_changed || m_link_changed)) mdss_dsi_clk_ctrl_sub(mctrl, clk_type, 0); error_mctrl_start: if (clk_type & DSI_BUS_CLKS) { @@ -661,12 +736,13 @@ error_mctrl_start: no_error: mutex_unlock(&dsi_clk_lock); - pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d", + pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n", __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, - ctrl->link_clk_cnt, changed); - pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d\n, m_changed=%d, enable=%d\n", + ctrl->link_clk_cnt, link_changed && bus_changed); + pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n", __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, - mctrl ? mctrl->link_clk_cnt : -1, m_changed, enable); + mctrl ? mctrl->link_clk_cnt : -1, + m_link_changed && m_bus_changed, enable); return rc; }