Loading drivers/video/msm/mdss/mdss_dsi_panel.c +1 −0 Original line number Diff line number Diff line Loading @@ -1325,6 +1325,7 @@ static void mdss_panel_parse_te_params(struct device_node *np, rc = of_property_read_u32 (np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp); te->rd_ptr_irq = (!rc ? tmp : timing->yres + 1); te->wr_ptr_irq = 0; } Loading drivers/video/msm/mdss/mdss_mdp.h +50 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,12 @@ struct mdss_mdp_vsync_handler { struct list_head list; }; struct mdss_mdp_lineptr_handler { bool enabled; mdp_vsync_handler_t lineptr_handler; struct list_head list; }; enum mdss_mdp_wb_ctl_type { MDSS_MDP_WB_CTL_TYPE_BLOCK = 1, MDSS_MDP_WB_CTL_TYPE_LINE Loading Loading @@ -342,6 +348,8 @@ struct mdss_mdp_ctl { struct work_struct recover_work; struct work_struct remove_underrun_handler; struct mdss_mdp_lineptr_handler lineptr_handler; /* * This ROI is aligned to as per following guidelines and * sent to the panel driver. Loading Loading @@ -659,7 +667,9 @@ struct mdss_mdp_wfd; struct mdss_overlay_private { ktime_t vsync_time; ktime_t lineptr_time; struct kernfs_node *vsync_event_sd; struct kernfs_node *lineptr_event_sd; struct kernfs_node *hist_event_sd; struct kernfs_node *bl_event_sd; struct kernfs_node *ad_event_sd; Loading Loading @@ -1186,6 +1196,46 @@ static inline int mdss_mdp_get_display_id(struct mdss_mdp_pipe *pipe) return (pipe && pipe->mfd) ? pipe->mfd->index : -1; } static inline bool mdss_mdp_is_full_frame_update(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_mixer *mixer; struct mdss_rect *roi; if (mdss_mdp_get_pu_type(ctl) != MDSS_MDP_DEFAULT_UPDATE) return false; if (ctl->mixer_left->valid_roi) { mixer = ctl->mixer_left; roi = &mixer->roi; if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width) || (roi->h != mixer->height)) return false; } if (ctl->mixer_right && ctl->mixer_right->valid_roi) { mixer = ctl->mixer_right; roi = &mixer->roi; if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width) || (roi->h != mixer->height)) return false; } return true; } static inline bool mdss_mdp_is_lineptr_supported(struct mdss_mdp_ctl *ctl) { struct mdss_panel_info *pinfo; if (!ctl || !ctl->mixer_left || !ctl->is_master) return false; pinfo = &ctl->panel_data->panel_info; return (((pinfo->type == MIPI_CMD_PANEL) && (pinfo->te.tear_check_en)) ? true : false); } irqreturn_t mdss_mdp_isr(int irq, void *ptr); void mdss_mdp_irq_clear(struct mdss_data_type *mdata, u32 intr_type, u32 intf_num); Loading drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +233 −3 Original line number Diff line number Diff line Loading @@ -64,10 +64,12 @@ struct mdss_mdp_cmd_ctx { struct completion pp_done; wait_queue_head_t pp_waitq; struct list_head vsync_handlers; struct list_head lineptr_handlers; int panel_power_state; atomic_t koff_cnt; u32 intf_stopped; struct mutex mdp_rdptr_lock; struct mutex mdp_wrptr_lock; struct mutex clk_mtx; spinlock_t clk_lock; spinlock_t koff_lock; Loading @@ -90,6 +92,9 @@ struct mdss_mdp_cmd_ctx { struct completion autorefresh_done; int vsync_irq_cnt; int lineptr_irq_cnt; bool lineptr_enabled; u32 prev_wr_ptr_irq; struct mdss_intf_recovery intf_recovery; struct mdss_intf_recovery intf_mdp_callback; Loading Loading @@ -286,9 +291,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, cfg |= vclks_line; pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d\n", pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d wr=%d\n", __func__, pinfo->yres, vclks_line, te->sync_cfg_height, te->vsync_init_val, te->rd_ptr_irq, te->start_pos); te->vsync_init_val, te->rd_ptr_irq, te->start_pos, te->wr_ptr_irq); pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d\n", te->sync_threshold_start, te->sync_threshold_continue, ctx->pingpong_split_slave); Loading @@ -309,6 +315,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_RD_PTR_IRQ, te ? te->rd_ptr_irq : 0); mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_WR_PTR_IRQ, te ? te->wr_ptr_irq : 0); mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_START_POS, te ? te->start_pos : 0); Loading Loading @@ -1060,6 +1069,28 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) } } static void mdss_mdp_cmd_writeptr_done(void *arg) { struct mdss_mdp_ctl *ctl = arg; struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_lineptr_handler *tmp; ktime_t lineptr_time; if (!ctx) { pr_err("invalid ctx\n"); return; } lineptr_time = ktime_get(); spin_lock(&ctx->clk_lock); list_for_each_entry(tmp, &ctx->lineptr_handlers, list) { if (tmp->enabled) tmp->lineptr_handler(ctl, lineptr_time); } spin_unlock(&ctx->clk_lock); } static void mdss_mdp_cmd_intf_recovery(void *data, int event) { struct mdss_mdp_cmd_ctx *ctx = data; Loading Loading @@ -1172,6 +1203,178 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) spin_unlock(&ctx->koff_lock); } static int mdss_mdp_setup_lineptr(struct mdss_mdp_cmd_ctx *ctx, bool enable) { int changed = 0; mutex_lock(&ctx->mdp_wrptr_lock); if (enable) { if (ctx->lineptr_irq_cnt == 0) changed++; ctx->lineptr_irq_cnt++; } else { if (ctx->lineptr_irq_cnt) { ctx->lineptr_irq_cnt--; if (ctx->lineptr_irq_cnt == 0) changed++; } else { pr_warn("%pS->%s: wr_ptr can not be turned off\n", __builtin_return_address(0), __func__); } } if (changed) MDSS_XLOG(ctx->lineptr_irq_cnt, enable, current->pid); pr_debug("%pS->%s: lineptr_irq_cnt=%d changed=%d enable=%d ctl:%d pp:%d\n", __builtin_return_address(0), __func__, ctx->lineptr_irq_cnt, changed, enable, ctx->ctl->num, ctx->default_pp_num); if (changed) { if (enable) { /* enable clocks and irq */ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); } else { /* disable clocks and irq */ mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); /* * check the intr status and clear the irq before * disabling the clocks */ mdss_mdp_intr_check_and_clear( MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); } } mutex_unlock(&ctx->mdp_wrptr_lock); return ctx->lineptr_irq_cnt; } static int mdss_mdp_cmd_add_lineptr_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_lineptr_handler *handle) { struct mdss_mdp_cmd_ctx *ctx; unsigned long flags; int ret = 0; mutex_lock(&ctl->offlock); ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master) { ret = -EINVAL; goto done; } pr_debug("%pS->%s: ctl=%d\n", __builtin_return_address(0), __func__, ctl->num); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); spin_lock_irqsave(&ctx->clk_lock, flags); if (!handle->enabled) { handle->enabled = true; list_add(&handle->list, &ctx->lineptr_handlers); } spin_unlock_irqrestore(&ctx->clk_lock, flags); if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) mutex_lock(&cmd_clk_mtx); mdss_mdp_setup_lineptr(ctx, true); ctx->lineptr_enabled = true; if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) mutex_unlock(&cmd_clk_mtx); done: mutex_unlock(&ctl->offlock); return ret; } static int mdss_mdp_cmd_remove_lineptr_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_lineptr_handler *handle) { struct mdss_mdp_cmd_ctx *ctx; unsigned long flags; bool disabled = true; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master || !ctx->lineptr_enabled) return -EINVAL; pr_debug("%pS->%s: ctl=%d\n", __builtin_return_address(0), __func__, ctl->num); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); spin_lock_irqsave(&ctx->clk_lock, flags); if (handle->enabled) { handle->enabled = false; list_del_init(&handle->list); } else { disabled = false; } spin_unlock_irqrestore(&ctx->clk_lock, flags); if (disabled) mdss_mdp_setup_lineptr(ctx, false); ctx->lineptr_enabled = false; ctx->prev_wr_ptr_irq = 0; return 0; } static int mdss_mdp_cmd_lineptr_ctrl(struct mdss_mdp_ctl *ctl, bool enable) { struct mdss_mdp_pp_tear_check *te; struct mdss_mdp_cmd_ctx *ctx; int rc = 0; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master) return -EINVAL; te = &ctl->panel_data->panel_info.te; pr_debug("%pS->%s: ctl=%d en=%d, prev_lineptr=%d, lineptr=%d\n", __builtin_return_address(0), __func__, ctl->num, enable, ctx->prev_wr_ptr_irq, te->wr_ptr_irq); if (enable) { /* update reg only if the value has changed */ if (ctx->prev_wr_ptr_irq != te->wr_ptr_irq) { ctx->prev_wr_ptr_irq = te->wr_ptr_irq; mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base, MDSS_MDP_REG_PP_WR_PTR_IRQ, te->wr_ptr_irq); } /* * add handler only when lineptr is not enabled * and wr ptr is non zero */ if (!ctx->lineptr_enabled && te->wr_ptr_irq) rc = mdss_mdp_cmd_add_lineptr_handler(ctl, &ctl->lineptr_handler); /* Disable handler when the value is zero */ else if (ctx->lineptr_enabled && !te->wr_ptr_irq) rc = mdss_mdp_cmd_remove_lineptr_handler(ctl, &ctl->lineptr_handler); } else { if (ctx->lineptr_enabled) rc = mdss_mdp_cmd_remove_lineptr_handler(ctl, &ctl->lineptr_handler); } return rc; } /** * mdss_mdp_cmd_autorefresh_pp_done() - pp done irq callback for autorefresh * @arg: void pointer to the controller context. Loading Loading @@ -1207,14 +1410,20 @@ static void pingpong_done_work(struct work_struct *work) u32 status; struct mdss_mdp_cmd_ctx *ctx = container_of(work, typeof(*ctx), pp_done_work); struct mdss_mdp_ctl *ctl = ctx->ctl; if (ctx->ctl) { if (ctl) { while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0)) mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE); status = mdss_mdp_ctl_perf_get_transaction_status(ctx->ctl); if (status == 0) mdss_mdp_ctl_perf_release_bw(ctx->ctl); if (!ctl->is_master) ctl = mdss_mdp_get_main_ctl(ctl); if (mdss_mdp_is_lineptr_supported(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, false); } } Loading Loading @@ -2468,6 +2677,13 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) PERF_SW_COMMIT_STATE, PERF_STATUS_DONE); } if (mdss_mdp_is_lineptr_supported(ctl)) { if (mdss_mdp_is_full_frame_update(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, true); else if (ctx->lineptr_enabled) mdss_mdp_cmd_lineptr_ctrl(ctl, false); } /* Kickoff */ __mdss_mdp_kickoff(ctl, ctx); Loading Loading @@ -2556,6 +2772,11 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, while (mdss_mdp_setup_vsync(ctx, false)) ; } if (ctx->lineptr_irq_cnt) { WARN(1, "lineptr irq still enabled\n"); while (mdss_mdp_setup_lineptr(ctx, false)) ; } if (!ctl->pending_mode_switch) { mdss_mdp_ctl_intf_event(ctl, Loading Loading @@ -2583,6 +2804,8 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->default_pp_num, NULL, NULL); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num, NULL, NULL); mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->default_pp_num, NULL, NULL); Loading Loading @@ -2639,6 +2862,8 @@ static int mdss_mdp_cmd_stop_sub(struct mdss_mdp_ctl *ctl, list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list) mdss_mdp_cmd_remove_vsync_handler(ctl, handle); if (mdss_mdp_is_lineptr_supported(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, false); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), XLOG_FUNC_ENTRY); /* Command mode is supported only starting at INTF1 */ Loading Loading @@ -2888,6 +3113,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, spin_lock_init(&ctx->koff_lock); mutex_init(&ctx->clk_mtx); mutex_init(&ctx->mdp_rdptr_lock); mutex_init(&ctx->mdp_wrptr_lock); INIT_WORK(&ctx->gate_clk_work, clk_ctrl_gate_work); INIT_DELAYED_WORK(&ctx->delayed_off_clk_work, clk_ctrl_delayed_off_work); Loading @@ -2897,6 +3123,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, ctx->autorefresh_state = MDP_AUTOREFRESH_OFF; ctx->autorefresh_frame_cnt = 0; INIT_LIST_HEAD(&ctx->vsync_handlers); INIT_LIST_HEAD(&ctx->lineptr_handlers); ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery; ctx->intf_recovery.data = ctx; Loading @@ -2913,6 +3140,9 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->default_pp_num, mdss_mdp_cmd_readptr_done, ctl); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num, mdss_mdp_cmd_writeptr_done, ctl); ret = mdss_mdp_cmd_tearcheck_setup(ctx, false); if (ret) pr_err("tearcheck setup failed\n"); Loading drivers/video/msm/mdss/mdss_mdp_overlay.c +112 −0 Original line number Diff line number Diff line Loading @@ -2619,6 +2619,30 @@ static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, sysfs_notify_dirent(mdp5_data->vsync_event_sd); } /* function is called in irq context should have minimum processing */ static void mdss_mdp_overlay_handle_lineptr(struct mdss_mdp_ctl *ctl, ktime_t t) { struct mdss_overlay_private *mdp5_data = NULL; if (!ctl || !ctl->mfd) { pr_warn("Invalid handle for lineptr\n"); return; } mdp5_data = mfd_to_mdp5_data(ctl->mfd); if (!mdp5_data) { pr_err("mdp5_data is NULL\n"); return; } pr_debug("lineptr irq on fb%d play_cnt=%d\n", ctl->mfd->index, ctl->play_cnt); mdp5_data->lineptr_time = t; sysfs_notify_dirent(mdp5_data->lineptr_event_sd); } int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); Loading Loading @@ -2891,6 +2915,78 @@ static ssize_t mdss_mdp_vsync_show_event(struct device *dev, return ret; } static ssize_t mdss_mdp_lineptr_show_event(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); u64 lineptr_ticks; int ret; if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; lineptr_ticks = ktime_to_ns(mdp5_data->lineptr_time); pr_debug("fb%d lineptr=%llu\n", mfd->index, lineptr_ticks); ret = scnprintf(buf, PAGE_SIZE, "LINEPTR=%llu\n", lineptr_ticks); return ret; } static ssize_t mdss_mdp_lineptr_show_value(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int ret, lineptr_val; if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; lineptr_val = mfd->panel_info->te.wr_ptr_irq; ret = scnprintf(buf, PAGE_SIZE, "%d\n", lineptr_val); return ret; } static ssize_t mdss_mdp_lineptr_set_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int ret, lineptr_value; ret = kstrtoint(buf, 10, &lineptr_value); if (ret) { pr_err("Invalid input for ad\n"); return -EINVAL; } if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; if (!mdss_mdp_is_lineptr_supported(mdp5_data->ctl)) { pr_err("lineptr not supported\n"); return -ENOTSUPP; } /* the new lineptr value will take effect in the next kickoff */ mfd->panel_info->te.wr_ptr_irq = lineptr_value; return count; } static ssize_t mdss_mdp_bl_show_event(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -3224,6 +3320,9 @@ static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR, static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR, mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store); static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL); static DEVICE_ATTR(lineptr_event, S_IRUGO, mdss_mdp_lineptr_show_event, NULL); static DEVICE_ATTR(lineptr_value, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_lineptr_show_value, mdss_mdp_lineptr_set_value); static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show, mdss_mdp_ad_store); static DEVICE_ATTR(dyn_pu, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_dyn_pu_show, Loading @@ -3235,6 +3334,8 @@ static DEVICE_ATTR(ad_bl_event, S_IRUGO, mdss_mdp_ad_bl_show_event, NULL); static struct attribute *mdp_overlay_sysfs_attrs[] = { &dev_attr_vsync_event.attr, &dev_attr_lineptr_event.attr, &dev_attr_lineptr_value.attr, &dev_attr_ad.attr, &dev_attr_dyn_pu.attr, &dev_attr_msm_misr_en.attr, Loading Loading @@ -4597,6 +4698,9 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init( mdss_mdp_recover_underrun_handler; ctl->recover_underrun_handler.cmd_post_flush = false; ctl->lineptr_handler.lineptr_handler = mdss_mdp_overlay_handle_lineptr; INIT_WORK(&ctl->remove_underrun_handler, remove_underrun_vsync_handler); Loading Loading @@ -5361,6 +5465,14 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) goto init_fail; } mdp5_data->lineptr_event_sd = sysfs_get_dirent(dev->kobj.sd, "lineptr_event"); if (!mdp5_data->lineptr_event_sd) { pr_err("lineptr_event sysfs lookup failed\n"); rc = -ENODEV; goto init_fail; } mdp5_data->hist_event_sd = sysfs_get_dirent(dev->kobj.sd, "hist_event"); if (!mdp5_data->hist_event_sd) { Loading drivers/video/msm/mdss/mdss_mdp_util.c +19 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ enum { MDP_INTR_PING_PONG_1_RD_PTR, MDP_INTR_PING_PONG_2_RD_PTR, MDP_INTR_PING_PONG_3_RD_PTR, MDP_INTR_PING_PONG_0_WR_PTR, MDP_INTR_PING_PONG_1_WR_PTR, MDP_INTR_PING_PONG_2_WR_PTR, MDP_INTR_PING_PONG_3_WR_PTR, MDP_INTR_WB_0, MDP_INTR_WB_1, MDP_INTR_WB_2, Loading Loading @@ -83,6 +87,9 @@ static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num) case MDSS_MDP_IRQ_PING_PONG_RD_PTR: index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num; break; case MDSS_MDP_IRQ_PING_PONG_WR_PTR: index = MDP_INTR_PING_PONG_0_WR_PTR + intf_num; break; case MDSS_MDP_IRQ_WB_ROT_COMP: index = MDP_INTR_WB_0 + intf_num; break; Loading Loading @@ -216,6 +223,18 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_PING_PONG_3_RD_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_RD_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_0_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_1_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_2_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_3_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_WR_PTR); if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true); Loading Loading
drivers/video/msm/mdss/mdss_dsi_panel.c +1 −0 Original line number Diff line number Diff line Loading @@ -1325,6 +1325,7 @@ static void mdss_panel_parse_te_params(struct device_node *np, rc = of_property_read_u32 (np, "qcom,mdss-tear-check-rd-ptr-trigger-intr", &tmp); te->rd_ptr_irq = (!rc ? tmp : timing->yres + 1); te->wr_ptr_irq = 0; } Loading
drivers/video/msm/mdss/mdss_mdp.h +50 −0 Original line number Diff line number Diff line Loading @@ -190,6 +190,12 @@ struct mdss_mdp_vsync_handler { struct list_head list; }; struct mdss_mdp_lineptr_handler { bool enabled; mdp_vsync_handler_t lineptr_handler; struct list_head list; }; enum mdss_mdp_wb_ctl_type { MDSS_MDP_WB_CTL_TYPE_BLOCK = 1, MDSS_MDP_WB_CTL_TYPE_LINE Loading Loading @@ -342,6 +348,8 @@ struct mdss_mdp_ctl { struct work_struct recover_work; struct work_struct remove_underrun_handler; struct mdss_mdp_lineptr_handler lineptr_handler; /* * This ROI is aligned to as per following guidelines and * sent to the panel driver. Loading Loading @@ -659,7 +667,9 @@ struct mdss_mdp_wfd; struct mdss_overlay_private { ktime_t vsync_time; ktime_t lineptr_time; struct kernfs_node *vsync_event_sd; struct kernfs_node *lineptr_event_sd; struct kernfs_node *hist_event_sd; struct kernfs_node *bl_event_sd; struct kernfs_node *ad_event_sd; Loading Loading @@ -1186,6 +1196,46 @@ static inline int mdss_mdp_get_display_id(struct mdss_mdp_pipe *pipe) return (pipe && pipe->mfd) ? pipe->mfd->index : -1; } static inline bool mdss_mdp_is_full_frame_update(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_mixer *mixer; struct mdss_rect *roi; if (mdss_mdp_get_pu_type(ctl) != MDSS_MDP_DEFAULT_UPDATE) return false; if (ctl->mixer_left->valid_roi) { mixer = ctl->mixer_left; roi = &mixer->roi; if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width) || (roi->h != mixer->height)) return false; } if (ctl->mixer_right && ctl->mixer_right->valid_roi) { mixer = ctl->mixer_right; roi = &mixer->roi; if ((roi->x != 0) || (roi->y != 0) || (roi->w != mixer->width) || (roi->h != mixer->height)) return false; } return true; } static inline bool mdss_mdp_is_lineptr_supported(struct mdss_mdp_ctl *ctl) { struct mdss_panel_info *pinfo; if (!ctl || !ctl->mixer_left || !ctl->is_master) return false; pinfo = &ctl->panel_data->panel_info; return (((pinfo->type == MIPI_CMD_PANEL) && (pinfo->te.tear_check_en)) ? true : false); } irqreturn_t mdss_mdp_isr(int irq, void *ptr); void mdss_mdp_irq_clear(struct mdss_data_type *mdata, u32 intr_type, u32 intf_num); Loading
drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +233 −3 Original line number Diff line number Diff line Loading @@ -64,10 +64,12 @@ struct mdss_mdp_cmd_ctx { struct completion pp_done; wait_queue_head_t pp_waitq; struct list_head vsync_handlers; struct list_head lineptr_handlers; int panel_power_state; atomic_t koff_cnt; u32 intf_stopped; struct mutex mdp_rdptr_lock; struct mutex mdp_wrptr_lock; struct mutex clk_mtx; spinlock_t clk_lock; spinlock_t koff_lock; Loading @@ -90,6 +92,9 @@ struct mdss_mdp_cmd_ctx { struct completion autorefresh_done; int vsync_irq_cnt; int lineptr_irq_cnt; bool lineptr_enabled; u32 prev_wr_ptr_irq; struct mdss_intf_recovery intf_recovery; struct mdss_intf_recovery intf_mdp_callback; Loading Loading @@ -286,9 +291,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, cfg |= vclks_line; pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d\n", pr_debug("%s: yres=%d vclks=%x height=%d init=%d rd=%d start=%d wr=%d\n", __func__, pinfo->yres, vclks_line, te->sync_cfg_height, te->vsync_init_val, te->rd_ptr_irq, te->start_pos); te->vsync_init_val, te->rd_ptr_irq, te->start_pos, te->wr_ptr_irq); pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d\n", te->sync_threshold_start, te->sync_threshold_continue, ctx->pingpong_split_slave); Loading @@ -309,6 +315,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer, mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_RD_PTR_IRQ, te ? te->rd_ptr_irq : 0); mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_WR_PTR_IRQ, te ? te->wr_ptr_irq : 0); mdss_mdp_pingpong_write(pingpong_base, MDSS_MDP_REG_PP_START_POS, te ? te->start_pos : 0); Loading Loading @@ -1060,6 +1069,28 @@ static void mdss_mdp_cmd_intf_callback(void *data, int event) } } static void mdss_mdp_cmd_writeptr_done(void *arg) { struct mdss_mdp_ctl *ctl = arg; struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_lineptr_handler *tmp; ktime_t lineptr_time; if (!ctx) { pr_err("invalid ctx\n"); return; } lineptr_time = ktime_get(); spin_lock(&ctx->clk_lock); list_for_each_entry(tmp, &ctx->lineptr_handlers, list) { if (tmp->enabled) tmp->lineptr_handler(ctl, lineptr_time); } spin_unlock(&ctx->clk_lock); } static void mdss_mdp_cmd_intf_recovery(void *data, int event) { struct mdss_mdp_cmd_ctx *ctx = data; Loading Loading @@ -1172,6 +1203,178 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) spin_unlock(&ctx->koff_lock); } static int mdss_mdp_setup_lineptr(struct mdss_mdp_cmd_ctx *ctx, bool enable) { int changed = 0; mutex_lock(&ctx->mdp_wrptr_lock); if (enable) { if (ctx->lineptr_irq_cnt == 0) changed++; ctx->lineptr_irq_cnt++; } else { if (ctx->lineptr_irq_cnt) { ctx->lineptr_irq_cnt--; if (ctx->lineptr_irq_cnt == 0) changed++; } else { pr_warn("%pS->%s: wr_ptr can not be turned off\n", __builtin_return_address(0), __func__); } } if (changed) MDSS_XLOG(ctx->lineptr_irq_cnt, enable, current->pid); pr_debug("%pS->%s: lineptr_irq_cnt=%d changed=%d enable=%d ctl:%d pp:%d\n", __builtin_return_address(0), __func__, ctx->lineptr_irq_cnt, changed, enable, ctx->ctl->num, ctx->default_pp_num); if (changed) { if (enable) { /* enable clocks and irq */ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); } else { /* disable clocks and irq */ mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); /* * check the intr status and clear the irq before * disabling the clocks */ mdss_mdp_intr_check_and_clear( MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num); mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF); } } mutex_unlock(&ctx->mdp_wrptr_lock); return ctx->lineptr_irq_cnt; } static int mdss_mdp_cmd_add_lineptr_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_lineptr_handler *handle) { struct mdss_mdp_cmd_ctx *ctx; unsigned long flags; int ret = 0; mutex_lock(&ctl->offlock); ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master) { ret = -EINVAL; goto done; } pr_debug("%pS->%s: ctl=%d\n", __builtin_return_address(0), __func__, ctl->num); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); spin_lock_irqsave(&ctx->clk_lock, flags); if (!handle->enabled) { handle->enabled = true; list_add(&handle->list, &ctx->lineptr_handlers); } spin_unlock_irqrestore(&ctx->clk_lock, flags); if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) mutex_lock(&cmd_clk_mtx); mdss_mdp_setup_lineptr(ctx, true); ctx->lineptr_enabled = true; if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) mutex_unlock(&cmd_clk_mtx); done: mutex_unlock(&ctl->offlock); return ret; } static int mdss_mdp_cmd_remove_lineptr_handler(struct mdss_mdp_ctl *ctl, struct mdss_mdp_lineptr_handler *handle) { struct mdss_mdp_cmd_ctx *ctx; unsigned long flags; bool disabled = true; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master || !ctx->lineptr_enabled) return -EINVAL; pr_debug("%pS->%s: ctl=%d\n", __builtin_return_address(0), __func__, ctl->num); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); spin_lock_irqsave(&ctx->clk_lock, flags); if (handle->enabled) { handle->enabled = false; list_del_init(&handle->list); } else { disabled = false; } spin_unlock_irqrestore(&ctx->clk_lock, flags); if (disabled) mdss_mdp_setup_lineptr(ctx, false); ctx->lineptr_enabled = false; ctx->prev_wr_ptr_irq = 0; return 0; } static int mdss_mdp_cmd_lineptr_ctrl(struct mdss_mdp_ctl *ctl, bool enable) { struct mdss_mdp_pp_tear_check *te; struct mdss_mdp_cmd_ctx *ctx; int rc = 0; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx || !ctl->is_master) return -EINVAL; te = &ctl->panel_data->panel_info.te; pr_debug("%pS->%s: ctl=%d en=%d, prev_lineptr=%d, lineptr=%d\n", __builtin_return_address(0), __func__, ctl->num, enable, ctx->prev_wr_ptr_irq, te->wr_ptr_irq); if (enable) { /* update reg only if the value has changed */ if (ctx->prev_wr_ptr_irq != te->wr_ptr_irq) { ctx->prev_wr_ptr_irq = te->wr_ptr_irq; mdss_mdp_pingpong_write(ctl->mixer_left->pingpong_base, MDSS_MDP_REG_PP_WR_PTR_IRQ, te->wr_ptr_irq); } /* * add handler only when lineptr is not enabled * and wr ptr is non zero */ if (!ctx->lineptr_enabled && te->wr_ptr_irq) rc = mdss_mdp_cmd_add_lineptr_handler(ctl, &ctl->lineptr_handler); /* Disable handler when the value is zero */ else if (ctx->lineptr_enabled && !te->wr_ptr_irq) rc = mdss_mdp_cmd_remove_lineptr_handler(ctl, &ctl->lineptr_handler); } else { if (ctx->lineptr_enabled) rc = mdss_mdp_cmd_remove_lineptr_handler(ctl, &ctl->lineptr_handler); } return rc; } /** * mdss_mdp_cmd_autorefresh_pp_done() - pp done irq callback for autorefresh * @arg: void pointer to the controller context. Loading Loading @@ -1207,14 +1410,20 @@ static void pingpong_done_work(struct work_struct *work) u32 status; struct mdss_mdp_cmd_ctx *ctx = container_of(work, typeof(*ctx), pp_done_work); struct mdss_mdp_ctl *ctl = ctx->ctl; if (ctx->ctl) { if (ctl) { while (atomic_add_unless(&ctx->pp_done_cnt, -1, 0)) mdss_mdp_ctl_notify(ctx->ctl, MDP_NOTIFY_FRAME_DONE); status = mdss_mdp_ctl_perf_get_transaction_status(ctx->ctl); if (status == 0) mdss_mdp_ctl_perf_release_bw(ctx->ctl); if (!ctl->is_master) ctl = mdss_mdp_get_main_ctl(ctl); if (mdss_mdp_is_lineptr_supported(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, false); } } Loading Loading @@ -2468,6 +2677,13 @@ static int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) PERF_SW_COMMIT_STATE, PERF_STATUS_DONE); } if (mdss_mdp_is_lineptr_supported(ctl)) { if (mdss_mdp_is_full_frame_update(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, true); else if (ctx->lineptr_enabled) mdss_mdp_cmd_lineptr_ctrl(ctl, false); } /* Kickoff */ __mdss_mdp_kickoff(ctl, ctx); Loading Loading @@ -2556,6 +2772,11 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, while (mdss_mdp_setup_vsync(ctx, false)) ; } if (ctx->lineptr_irq_cnt) { WARN(1, "lineptr irq still enabled\n"); while (mdss_mdp_setup_lineptr(ctx, false)) ; } if (!ctl->pending_mode_switch) { mdss_mdp_ctl_intf_event(ctl, Loading Loading @@ -2583,6 +2804,8 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->default_pp_num, NULL, NULL); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num, NULL, NULL); mdss_mdp_set_intr_callback_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->default_pp_num, NULL, NULL); Loading Loading @@ -2639,6 +2862,8 @@ static int mdss_mdp_cmd_stop_sub(struct mdss_mdp_ctl *ctl, list_for_each_entry_safe(handle, tmp, &ctx->vsync_handlers, list) mdss_mdp_cmd_remove_vsync_handler(ctl, handle); if (mdss_mdp_is_lineptr_supported(ctl)) mdss_mdp_cmd_lineptr_ctrl(ctl, false); MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), XLOG_FUNC_ENTRY); /* Command mode is supported only starting at INTF1 */ Loading Loading @@ -2888,6 +3113,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, spin_lock_init(&ctx->koff_lock); mutex_init(&ctx->clk_mtx); mutex_init(&ctx->mdp_rdptr_lock); mutex_init(&ctx->mdp_wrptr_lock); INIT_WORK(&ctx->gate_clk_work, clk_ctrl_gate_work); INIT_DELAYED_WORK(&ctx->delayed_off_clk_work, clk_ctrl_delayed_off_work); Loading @@ -2897,6 +3123,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, ctx->autorefresh_state = MDP_AUTOREFRESH_OFF; ctx->autorefresh_frame_cnt = 0; INIT_LIST_HEAD(&ctx->vsync_handlers); INIT_LIST_HEAD(&ctx->lineptr_handlers); ctx->intf_recovery.fxn = mdss_mdp_cmd_intf_recovery; ctx->intf_recovery.data = ctx; Loading @@ -2913,6 +3140,9 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->default_pp_num, mdss_mdp_cmd_readptr_done, ctl); mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_WR_PTR, ctx->default_pp_num, mdss_mdp_cmd_writeptr_done, ctl); ret = mdss_mdp_cmd_tearcheck_setup(ctx, false); if (ret) pr_err("tearcheck setup failed\n"); Loading
drivers/video/msm/mdss/mdss_mdp_overlay.c +112 −0 Original line number Diff line number Diff line Loading @@ -2619,6 +2619,30 @@ static void mdss_mdp_overlay_handle_vsync(struct mdss_mdp_ctl *ctl, sysfs_notify_dirent(mdp5_data->vsync_event_sd); } /* function is called in irq context should have minimum processing */ static void mdss_mdp_overlay_handle_lineptr(struct mdss_mdp_ctl *ctl, ktime_t t) { struct mdss_overlay_private *mdp5_data = NULL; if (!ctl || !ctl->mfd) { pr_warn("Invalid handle for lineptr\n"); return; } mdp5_data = mfd_to_mdp5_data(ctl->mfd); if (!mdp5_data) { pr_err("mdp5_data is NULL\n"); return; } pr_debug("lineptr irq on fb%d play_cnt=%d\n", ctl->mfd->index, ctl->play_cnt); mdp5_data->lineptr_time = t; sysfs_notify_dirent(mdp5_data->lineptr_event_sd); } int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en) { struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); Loading Loading @@ -2891,6 +2915,78 @@ static ssize_t mdss_mdp_vsync_show_event(struct device *dev, return ret; } static ssize_t mdss_mdp_lineptr_show_event(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); u64 lineptr_ticks; int ret; if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; lineptr_ticks = ktime_to_ns(mdp5_data->lineptr_time); pr_debug("fb%d lineptr=%llu\n", mfd->index, lineptr_ticks); ret = scnprintf(buf, PAGE_SIZE, "LINEPTR=%llu\n", lineptr_ticks); return ret; } static ssize_t mdss_mdp_lineptr_show_value(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int ret, lineptr_val; if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; lineptr_val = mfd->panel_info->te.wr_ptr_irq; ret = scnprintf(buf, PAGE_SIZE, "%d\n", lineptr_val); return ret; } static ssize_t mdss_mdp_lineptr_set_value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct fb_info *fbi = dev_get_drvdata(dev); struct msm_fb_data_type *mfd = fbi->par; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); int ret, lineptr_value; ret = kstrtoint(buf, 10, &lineptr_value); if (ret) { pr_err("Invalid input for ad\n"); return -EINVAL; } if (!mdp5_data->ctl || (!mdp5_data->ctl->panel_data->panel_info.cont_splash_enabled && !mdss_mdp_ctl_is_power_on(mdp5_data->ctl))) return -EAGAIN; if (!mdss_mdp_is_lineptr_supported(mdp5_data->ctl)) { pr_err("lineptr not supported\n"); return -ENOTSUPP; } /* the new lineptr value will take effect in the next kickoff */ mfd->panel_info->te.wr_ptr_irq = lineptr_value; return count; } static ssize_t mdss_mdp_bl_show_event(struct device *dev, struct device_attribute *attr, char *buf) { Loading Loading @@ -3224,6 +3320,9 @@ static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR, static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR, mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store); static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL); static DEVICE_ATTR(lineptr_event, S_IRUGO, mdss_mdp_lineptr_show_event, NULL); static DEVICE_ATTR(lineptr_value, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_lineptr_show_value, mdss_mdp_lineptr_set_value); static DEVICE_ATTR(ad, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_ad_show, mdss_mdp_ad_store); static DEVICE_ATTR(dyn_pu, S_IRUGO | S_IWUSR | S_IWGRP, mdss_mdp_dyn_pu_show, Loading @@ -3235,6 +3334,8 @@ static DEVICE_ATTR(ad_bl_event, S_IRUGO, mdss_mdp_ad_bl_show_event, NULL); static struct attribute *mdp_overlay_sysfs_attrs[] = { &dev_attr_vsync_event.attr, &dev_attr_lineptr_event.attr, &dev_attr_lineptr_value.attr, &dev_attr_ad.attr, &dev_attr_dyn_pu.attr, &dev_attr_msm_misr_en.attr, Loading Loading @@ -4597,6 +4698,9 @@ static struct mdss_mdp_ctl *__mdss_mdp_overlay_ctl_init( mdss_mdp_recover_underrun_handler; ctl->recover_underrun_handler.cmd_post_flush = false; ctl->lineptr_handler.lineptr_handler = mdss_mdp_overlay_handle_lineptr; INIT_WORK(&ctl->remove_underrun_handler, remove_underrun_vsync_handler); Loading Loading @@ -5361,6 +5465,14 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) goto init_fail; } mdp5_data->lineptr_event_sd = sysfs_get_dirent(dev->kobj.sd, "lineptr_event"); if (!mdp5_data->lineptr_event_sd) { pr_err("lineptr_event sysfs lookup failed\n"); rc = -ENODEV; goto init_fail; } mdp5_data->hist_event_sd = sysfs_get_dirent(dev->kobj.sd, "hist_event"); if (!mdp5_data->hist_event_sd) { Loading
drivers/video/msm/mdss/mdss_mdp_util.c +19 −0 Original line number Diff line number Diff line Loading @@ -49,6 +49,10 @@ enum { MDP_INTR_PING_PONG_1_RD_PTR, MDP_INTR_PING_PONG_2_RD_PTR, MDP_INTR_PING_PONG_3_RD_PTR, MDP_INTR_PING_PONG_0_WR_PTR, MDP_INTR_PING_PONG_1_WR_PTR, MDP_INTR_PING_PONG_2_WR_PTR, MDP_INTR_PING_PONG_3_WR_PTR, MDP_INTR_WB_0, MDP_INTR_WB_1, MDP_INTR_WB_2, Loading Loading @@ -83,6 +87,9 @@ static int mdss_mdp_intr2index(u32 intr_type, u32 intf_num) case MDSS_MDP_IRQ_PING_PONG_RD_PTR: index = MDP_INTR_PING_PONG_0_RD_PTR + intf_num; break; case MDSS_MDP_IRQ_PING_PONG_WR_PTR: index = MDP_INTR_PING_PONG_0_WR_PTR + intf_num; break; case MDSS_MDP_IRQ_WB_ROT_COMP: index = MDP_INTR_WB_0 + intf_num; break; Loading Loading @@ -216,6 +223,18 @@ irqreturn_t mdss_mdp_isr(int irq, void *ptr) if (isr & MDSS_MDP_INTR_PING_PONG_3_RD_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_RD_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_0_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_0_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_1_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_1_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_2_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_2_WR_PTR); if (isr & MDSS_MDP_INTR_PING_PONG_3_WR_PTR) mdss_mdp_intr_done(MDP_INTR_PING_PONG_3_WR_PTR); if (isr & MDSS_MDP_INTR_INTF_0_VSYNC) { mdss_mdp_intr_done(MDP_INTR_VSYNC_INTF_0); mdss_misr_crc_collect(mdata, DISPLAY_MISR_EDP, true); Loading