diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index d9a4bd91f3eb..796246a856b4 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -210,6 +210,15 @@ enum mdss_mdp_pipe_type { MDSS_MDP_PIPE_TYPE_MAX, }; +enum mdss_mdp_intf_index { + MDSS_MDP_NO_INTF, + MDSS_MDP_INTF0, + MDSS_MDP_INTF1, + MDSS_MDP_INTF2, + MDSS_MDP_INTF3, + MDSS_MDP_MAX_INTF +}; + struct reg_bus_client { char name[MAX_CLIENT_NAME_LEN]; short usecase_ndx; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index ed6ef75b0719..b1944a9a6323 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -2516,6 +2516,15 @@ static int mdss_dsi_register_mdp_callback(struct mdss_dsi_ctrl_pdata *ctrl, return 0; } +static int mdss_dsi_register_clamp_handler(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_intf_ulp_clamp *clamp_handler) +{ + mutex_lock(&ctrl->mutex); + ctrl->clamp_handler = clamp_handler; + mutex_unlock(&ctrl->mutex); + return 0; +} + static struct device_node *mdss_dsi_get_fb_node_cb(struct platform_device *pdev) { struct device_node *fb_node; @@ -2700,6 +2709,10 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, rc = mdss_dsi_register_mdp_callback(ctrl_pdata, (struct mdss_intf_recovery *)arg); break; + case MDSS_EVENT_REGISTER_CLAMP_HANDLER: + rc = mdss_dsi_register_clamp_handler(ctrl_pdata, + (struct mdss_intf_ulp_clamp *)arg); + break; case MDSS_EVENT_DSI_DYNAMIC_SWITCH: mode = (u32)(unsigned long) arg; mdss_dsi_switch_mode(pdata, mode); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 14c2732a5789..66c0cb029720 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -485,6 +485,7 @@ struct mdss_dsi_ctrl_pdata { struct mdss_hw *dsi_hw; struct mdss_intf_recovery *recovery; struct mdss_intf_recovery *mdp_callback; + struct mdss_intf_ulp_clamp *clamp_handler; struct dsi_panel_cmds on_cmds; struct dsi_panel_cmds post_dms_on_cmds; diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 3d5d046c536a..2fd047edd3e8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1992,6 +1992,7 @@ void mdss_mdp_disable_hw_irq(struct mdss_data_type *mdata); void mdss_mdp_set_supported_formats(struct mdss_data_type *mdata); int mdss_mdp_dest_scaler_setup_locked(struct mdss_mdp_mixer *mixer); +void *mdss_mdp_intf_get_ctx_base(struct mdss_mdp_ctl *ctl, int intf_num); #ifdef CONFIG_FB_MSM_MDP_NONE struct mdss_data_type *mdss_mdp_get_mdata(void) diff --git a/drivers/video/fbdev/msm/mdss_mdp_hwio.h b/drivers/video/fbdev/msm/mdss_mdp_hwio.h index 294e05c2fbb0..7d495232c198 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_hwio.h +++ b/drivers/video/fbdev/msm/mdss_mdp_hwio.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -634,15 +634,6 @@ enum mdss_mdp_dspp_index { #define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_SAT_MASK BIT(30) #define MDSS_MDP_DSPP_OP_PA_SIX_ZONE_VAL_MASK BIT(31) -enum mdss_mpd_intf_index { - MDSS_MDP_NO_INTF, - MDSS_MDP_INTF0, - MDSS_MDP_INTF1, - MDSS_MDP_INTF2, - MDSS_MDP_INTF3, - MDSS_MDP_MAX_INTF -}; - #define MDSS_MDP_REG_INTF_TIMING_ENGINE_EN 0x000 #define MDSS_MDP_REG_INTF_CONFIG 0x004 #define MDSS_MDP_REG_INTF_HSYNC_CTL 0x008 @@ -703,6 +694,8 @@ enum mdss_mpd_intf_index { #define MDSS_MDP_PANEL_FORMAT_RGB888 0x213F #define MDSS_MDP_PANEL_FORMAT_RGB666 0x212A +#define MDSS_MDP_REG_DSI_ULP_CLAMP_VALUE 0x064 + #define MDSS_MDP_PANEL_FORMAT_PACK_ALIGN_MSB BIT(7) enum mdss_mdp_pingpong_index { diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 583cfed598cd..c9ce56fb96a4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -103,6 +103,7 @@ struct mdss_mdp_cmd_ctx { struct mdss_intf_recovery intf_recovery; struct mdss_intf_recovery intf_mdp_callback; + struct mdss_intf_ulp_clamp intf_clamp_handler; struct mdss_mdp_cmd_ctx *sync_ctx; /* for partial update */ u32 pp_timeout_report_cnt; bool pingpong_split_slave; @@ -1281,6 +1282,32 @@ static void mdss_mdp_cmd_lineptr_done(void *arg) spin_unlock(&ctx->clk_lock); } +static int mdss_mdp_cmd_intf_clamp_ctrl(void *data, int intf_num, bool enable) +{ + struct mdss_mdp_ctl *ctl = data; + char __iomem *ctx_base = NULL; + + if (!data) { + pr_err("%s: invalid ctl\n", __func__); + return -EINVAL; + } + + ctx_base = + (char __iomem *)mdss_mdp_intf_get_ctx_base(ctl, intf_num); + if (!ctx_base) { + pr_err("%s: invalid ctx\n", __func__); + return -EINVAL; + } + + pr_debug("%s: intf num = %d, enable = %d\n", + __func__, intf_num, enable); + + writel_relaxed(enable, (ctx_base + MDSS_MDP_REG_DSI_ULP_CLAMP_VALUE)); + wmb(); /* ensure clamp is enabled */ + + return 0; +} + static int mdss_mdp_cmd_intf_recovery(void *data, int event) { struct mdss_mdp_cmd_ctx *ctx = data; @@ -3209,6 +3236,12 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, memset(ctx, 0, sizeof(*ctx)); /* intf stopped, no more kickoff */ ctx->intf_stopped = 1; + /* + * Restore clamp handler as it might get called later + * when DSI panel events are handled. + */ + ctx->intf_clamp_handler.fxn = mdss_mdp_cmd_intf_clamp_ctrl; + ctx->intf_clamp_handler.data = ctl; return 0; } @@ -3349,6 +3382,11 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl, int panel_power_state) (void *)&ctx->intf_mdp_callback, CTL_INTF_EVENT_FLAG_DEFAULT); + mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_REGISTER_CLAMP_HANDLER, + (void *)&ctx->intf_clamp_handler, + CTL_INTF_EVENT_FLAG_DEFAULT); + mdss_mdp_tearcheck_enable(ctl, true); ctx->intf_stopped = 0; @@ -3407,6 +3445,10 @@ panel_events: goto end; } + mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_REGISTER_CLAMP_HANDLER, + NULL, CTL_INTF_EVENT_FLAG_DEFAULT); + pr_debug("%s: turn off panel\n", __func__); ctl->intf_ctx[MASTER_CTX] = NULL; ctl->intf_ctx[SLAVE_CTX] = NULL; @@ -3540,6 +3582,14 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, ctx->intf_mdp_callback.fxn = mdss_mdp_cmd_intf_callback; ctx->intf_mdp_callback.data = ctx; + ctx->intf_clamp_handler.fxn = mdss_mdp_cmd_intf_clamp_ctrl; + ctx->intf_clamp_handler.data = ctl; + + mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_REGISTER_CLAMP_HANDLER, + (void *)&ctx->intf_clamp_handler, + CTL_INTF_EVENT_FLAG_DEFAULT); + ctx->intf_stopped = 0; pr_debug("%s: ctx=%pK num=%d aux=%d\n", __func__, ctx, diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 1b141f179275..3e6b576cfb6e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -84,6 +84,7 @@ struct mdss_mdp_video_ctx { struct list_head vsync_handlers; struct mdss_intf_recovery intf_recovery; struct mdss_intf_recovery intf_mdp_callback; + struct mdss_intf_ulp_clamp intf_clamp_handler; struct work_struct early_wakeup_dfps_work; atomic_t lineptr_ref; @@ -150,6 +151,23 @@ static int mdss_mdp_intf_intr2index(u32 intr_type) return index; } +void *mdss_mdp_intf_get_ctx_base(struct mdss_mdp_ctl *ctl, int intf_num) +{ + struct mdss_mdp_video_ctx *head; + int i = 0; + + if (!ctl) + return NULL; + + head = ctl->mdata->video_intf; + for (i = 0; i < ctl->mdata->nintf; i++) { + if (head[i].intf_num == intf_num) + return (void *)head[i].base; + } + + return NULL; +} + int mdss_mdp_set_intf_intr_callback(struct mdss_mdp_video_ctx *ctx, u32 intr_type, void (*fnc_ptr)(void *), void *arg) { @@ -316,6 +334,29 @@ int mdss_mdp_video_addr_setup(struct mdss_data_type *mdata, return 0; } +static int mdss_mdp_video_intf_clamp_ctrl(void *data, int intf_num, bool enable) +{ + struct mdss_mdp_video_ctx *ctx = data; + + if (!data) { + pr_err("%s: invalid ctl\n", __func__); + return -EINVAL; + } + + if (intf_num != ctx->intf_num) { + pr_err("%s: invalid intf num\n", __func__); + return -EINVAL; + } + + pr_debug("%s: ctx intf num = %d, enable = %d\n", + __func__, ctx->intf_num, enable); + + mdp_video_write(ctx, MDSS_MDP_REG_DSI_ULP_CLAMP_VALUE, enable); + wmb(); /* ensure clamp is enabled */ + + return 0; +} + static int mdss_mdp_video_intf_recovery(void *data, int event) { struct mdss_mdp_video_ctx *ctx; @@ -1998,6 +2039,13 @@ static int mdss_mdp_video_ctx_setup(struct mdss_mdp_ctl *ctl, MDSS_EVENT_REGISTER_MDP_CALLBACK, (void *)&ctx->intf_mdp_callback, CTL_INTF_EVENT_FLAG_DEFAULT); + + ctx->intf_clamp_handler.fxn = mdss_mdp_video_intf_clamp_ctrl; + ctx->intf_clamp_handler.data = ctx; + mdss_mdp_ctl_intf_event(ctl, + MDSS_EVENT_REGISTER_CLAMP_HANDLER, + (void *)&ctx->intf_clamp_handler, + CTL_INTF_EVENT_FLAG_DEFAULT); } else { ctx->intf_recovery.fxn = NULL; ctx->intf_recovery.data = NULL; diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 0daf8b0f93b4..92413e078244 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -197,6 +197,11 @@ struct mdss_intf_recovery { void *data; }; +struct mdss_intf_ulp_clamp { + int (*fxn)(void *ctx, int intf_num, bool enable); + void *data; +}; + /** * enum mdss_intf_events - Different events generated by MDP core * @@ -302,6 +307,7 @@ enum mdss_intf_events { MDSS_EVENT_UPDATE_PANEL_PPM, MDSS_EVENT_DSI_TIMING_DB_CTRL, MDSS_EVENT_AVR_MODE, + MDSS_EVENT_REGISTER_CLAMP_HANDLER, MDSS_EVENT_MAX, }; @@ -358,6 +364,8 @@ static inline char *mdss_panel_intf_event_to_string(int event) return INTF_EVENT_STR(MDSS_EVENT_REGISTER_RECOVERY_HANDLER); case MDSS_EVENT_REGISTER_MDP_CALLBACK: return INTF_EVENT_STR(MDSS_EVENT_REGISTER_MDP_CALLBACK); + case MDSS_EVENT_REGISTER_CLAMP_HANDLER: + return INTF_EVENT_STR(MDSS_EVENT_REGISTER_CLAMP_HANDLER); case MDSS_EVENT_DSI_PANEL_STATUS: return INTF_EVENT_STR(MDSS_EVENT_DSI_PANEL_STATUS); case 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 e6151b4c75a1..0e0d2621496e 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1983,6 +1983,7 @@ static int mdss_dsi_clamp_ctrl_default(struct mdss_dsi_ctrl_pdata *ctrl, struct mipi_panel_info *mipi = NULL; u32 clamp_reg, regval = 0; u32 clamp_reg_off; + u32 intf_num = 0; if (!ctrl) { pr_err("%s: invalid input\n", __func__); @@ -1994,6 +1995,21 @@ static int mdss_dsi_clamp_ctrl_default(struct mdss_dsi_ctrl_pdata *ctrl, return -EINVAL; } + /* + * For DSI HW version 2.1.0 ULPS_CLAMP register + * is moved to interface level. + */ + if (ctrl->shared_data->hw_rev == MDSS_DSI_HW_REV_201) { + intf_num = ctrl->ndx ? MDSS_MDP_INTF2 : MDSS_MDP_INTF1; + if (ctrl->clamp_handler) { + ctrl->clamp_handler->fxn(ctrl->clamp_handler->data, + intf_num, enable); + pr_debug("%s: ndx: %d enable: %d\n", + __func__, ctrl->ndx, enable); + } + return 0; + } + clamp_reg_off = ctrl->shared_data->ulps_clamp_ctrl_off; mipi = &ctrl->panel_data.panel_info.mipi;