Loading drivers/video/msm/mdss/mdss_dsi.c +88 −170 Original line number Diff line number Diff line Loading @@ -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. * If a dynamic mode switch is pending, the regulators should not * be turned off or on. */ msm_dss_enable_vreg( ctrl_pdata->power_data[DSI_CORE_PM].vreg_config, ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable); 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); Loading Loading @@ -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); Loading Loading @@ -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; } 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", /* * 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__); ret = -EPERM; goto error; return 0; } 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; /* 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, 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; } Loading @@ -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(); Loading @@ -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); Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; } Loading Loading @@ -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); Loading drivers/video/msm/mdss/mdss_dsi.h +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 */ drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +25 −33 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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__); Loading @@ -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->idle_pc = true; ctx->ctl->play_cnt = 0; mdss_mdp_footswitch_ctrl_idle_pc(0, &ctx->ctl->mfd->pdev->dev); } } 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, Loading Loading @@ -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; } Loading Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading drivers/video/msm/mdss/mdss_panel.h +0 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, }; Loading drivers/video/msm/mdss/msm_mdss_io_8974.c +116 −40 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } Loading @@ -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) { Loading @@ -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); if (!link_changed && !bus_changed) goto no_error; /* clk cnts updated, nothing else needed */ /* * 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; } rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); 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; pr_err("Failed to start mctrl clocks. rc=%d\n", rc); goto error_mctrl_start; } } if (!enable && m_changed) { 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); 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) { Loading @@ -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; } Loading Loading
drivers/video/msm/mdss/mdss_dsi.c +88 −170 Original line number Diff line number Diff line Loading @@ -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. * If a dynamic mode switch is pending, the regulators should not * be turned off or on. */ msm_dss_enable_vreg( ctrl_pdata->power_data[DSI_CORE_PM].vreg_config, ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable); 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); Loading Loading @@ -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); Loading Loading @@ -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; } 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", /* * 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__); ret = -EPERM; goto error; return 0; } 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; /* 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, 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; } Loading @@ -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(); Loading @@ -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); Loading @@ -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); Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading Loading @@ -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; } Loading Loading @@ -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); Loading
drivers/video/msm/mdss/mdss_dsi.h +8 −0 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -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 */
drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +25 −33 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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 Loading Loading @@ -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); } Loading Loading @@ -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__); Loading @@ -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->idle_pc = true; ctx->ctl->play_cnt = 0; mdss_mdp_footswitch_ctrl_idle_pc(0, &ctx->ctl->mfd->pdev->dev); } } 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, Loading Loading @@ -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; } Loading Loading @@ -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); Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading
drivers/video/msm/mdss/mdss_panel.h +0 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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, }; Loading
drivers/video/msm/mdss/msm_mdss_io_8974.c +116 −40 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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; } Loading @@ -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) { Loading @@ -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); if (!link_changed && !bus_changed) goto no_error; /* clk cnts updated, nothing else needed */ /* * 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; } rc = mdss_dsi_clk_ctrl_sub(ctrl, clk_type, enable); 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; pr_err("Failed to start mctrl clocks. rc=%d\n", rc); goto error_mctrl_start; } } if (!enable && m_changed) { 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); 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) { Loading @@ -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; } Loading