From cd1e996b44ab32ffa7b525806c122367115e2fe5 Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Mon, 3 Feb 2020 19:51:36 -0800 Subject: [PATCH 1/2] disp: msm: defer panel TE disable with poms switch DSI host vsync is expected to align with panel internal vsync during transition from command mode to video mode operation. In order to facilitate this, keep panel TE enabled in video mode operation until it is aligned with vysnc. Change-Id: I3fc59b01336b30cd436be332af6953c5a01be7fd Signed-off-by: Narendra Muppalla --- msm/dsi/dsi_display.c | 37 +++++++++++++++++++++++++++++++++++++ msm/dsi/dsi_display.h | 6 +++++- msm/dsi/dsi_panel.c | 2 ++ msm/dsi/dsi_panel.h | 1 + 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/msm/dsi/dsi_display.c b/msm/dsi/dsi_display.c index b002c0e9f990..b2af75e510ee 100644 --- a/msm/dsi/dsi_display.c +++ b/msm/dsi/dsi_display.c @@ -5819,6 +5819,7 @@ int dsi_display_get_info(struct drm_connector *connector, info->max_height = 1080; info->qsync_min_fps = display->panel->qsync_min_fps; + info->poms_align_vsync = display->panel->poms_align_vsync; switch (display->panel->panel_mode) { case DSI_OP_VIDEO_MODE: @@ -7357,6 +7358,25 @@ int dsi_display_pre_disable(struct dsi_display *display) return rc; } +static void dsi_display_handle_poms_te(struct work_struct *work) +{ + struct dsi_display *display = NULL; + struct delayed_work *dw = to_delayed_work(work); + struct mipi_dsi_device *dsi; + int rc = 0; + + display = container_of(dw, struct dsi_display, poms_te_work); + if (!display || !display->panel) { + DSI_ERR("Invalid params\n"); + return; + } + + dsi = &display->panel->mipi_device; + rc = mipi_dsi_dcs_set_tear_off(dsi); + if (rc < 0) + DSI_ERR("failed to set tear off\n"); +} + int dsi_display_disable(struct dsi_display *display) { int rc = 0; @@ -7369,6 +7389,11 @@ int dsi_display_disable(struct dsi_display *display) SDE_EVT32(SDE_EVTLOG_FUNC_ENTRY); mutex_lock(&display->display_lock); + /* cancel delayed work */ + if (display->poms_pending && + display->panel->poms_align_vsync) + cancel_delayed_work_sync(&display->poms_te_work); + rc = dsi_display_wake_up(display); if (rc) DSI_ERR("[%s] display wake up failed, rc=%d\n", @@ -7380,6 +7405,18 @@ int dsi_display_disable(struct dsi_display *display) DSI_ERR("[%s]failed to disable DSI vid engine, rc=%d\n", display->name, rc); } else if (display->config.panel_mode == DSI_OP_CMD_MODE) { + /** + * On POMS request , disable panel TE through + * delayed work queue. + */ + if (display->poms_pending && + display->panel->poms_align_vsync) { + INIT_DELAYED_WORK(&display->poms_te_work, + dsi_display_handle_poms_te); + queue_delayed_work(system_wq, + &display->poms_te_work, + msecs_to_jiffies(100)); + } rc = dsi_display_cmd_engine_disable(display); if (rc) DSI_ERR("[%s]failed to disable DSI cmd engine, rc=%d\n", diff --git a/msm/dsi/dsi_display.h b/msm/dsi/dsi_display.h index 4c41f3dd7316..21762c891c86 100644 --- a/msm/dsi/dsi_display.h +++ b/msm/dsi/dsi_display.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved. */ #ifndef _DSI_DISPLAY_H_ @@ -180,6 +180,7 @@ struct dsi_display_ext_bridge { * @misr_enable Frame MISR enable/disable * @misr_frame_count Number of frames to accumulate the MISR value * @esd_trigger field indicating ESD trigger through debugfs + * @poms_te_work POMS delayed work for disabling panel TE * @te_source vsync source pin information * @clk_gating_config Clocks for which clock gating needs to be enabled * @queue_cmd_waits Indicates if wait for dma commands done has to be queued. @@ -261,6 +262,9 @@ struct dsi_display { struct work_struct fifo_overflow_work; struct work_struct lp_rx_timeout_work; + /* panel te delayed work */ + struct delayed_work poms_te_work; + /* firmware panel data */ const struct firmware *fw; void *parser; diff --git a/msm/dsi/dsi_panel.c b/msm/dsi/dsi_panel.c index 1085801d56dd..3e872e04f113 100644 --- a/msm/dsi/dsi_panel.c +++ b/msm/dsi/dsi_panel.c @@ -1479,6 +1479,8 @@ static int dsi_panel_parse_panel_mode(struct dsi_panel *panel) } } + panel->poms_align_vsync = utils->read_bool(utils->data, + "qcom,poms-align-panel-vsync"); panel->panel_mode = panel_mode; panel->panel_mode_switch_enabled = panel_mode_switch_enabled; error: diff --git a/msm/dsi/dsi_panel.h b/msm/dsi/dsi_panel.h index 4b10e457a224..946bbf0bcb89 100644 --- a/msm/dsi/dsi_panel.h +++ b/msm/dsi/dsi_panel.h @@ -171,6 +171,7 @@ struct dsi_panel { struct dsi_cmd_engine_cfg cmd_config; enum dsi_op_mode panel_mode; bool panel_mode_switch_enabled; + bool poms_align_vsync; struct dsi_dfps_capabilities dfps_caps; struct dsi_dyn_clk_caps dyn_clk_caps; From 68ee65353b46a7533d9538ff459a3f2866ebe051 Mon Sep 17 00:00:00 2001 From: Narendra Muppalla Date: Mon, 3 Feb 2020 19:52:24 -0800 Subject: [PATCH 2/2] disp: msm: sde: align timing engine vsync based on panel vsync This change adds logic to align timing engine vsync with panel tear check if it is supported. Change-Id: I3f881f392929589848c893f567822b21c0650000 Signed-off-by: Narendra Muppalla --- msm/msm_drv.h | 2 ++ msm/sde/sde_encoder.c | 1 + msm/sde/sde_encoder_phys.h | 2 ++ msm/sde/sde_encoder_phys_vid.c | 1 + msm/sde/sde_hw_catalog.c | 4 ++++ msm/sde/sde_hw_catalog.h | 2 ++ msm/sde/sde_hw_intf.c | 5 +++++ msm/sde/sde_hw_intf.h | 1 + 8 files changed, 18 insertions(+) diff --git a/msm/msm_drv.h b/msm/msm_drv.h index d8fb43e25b31..59c72000b2af 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -679,6 +679,7 @@ struct msm_resource_caps_info { * @display_type: Enum for type of display * @is_te_using_watchdog_timer: Boolean to indicate watchdog TE is * used instead of panel TE in cmd mode panels + * @poms_align_vsync: poms with vsync aligned * @roi_caps: Region of interest capability info * @qsync_min_fps Minimum fps supported by Qsync feature * @te_source vsync source pin information @@ -701,6 +702,7 @@ struct msm_display_info { uint32_t display_type; bool is_te_using_watchdog_timer; + bool poms_align_vsync; struct msm_roi_caps roi_caps; uint32_t qsync_min_fps; diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index b72fa2f08ddf..48a05273e3ee 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -2582,6 +2582,7 @@ static void sde_encoder_virt_enable(struct drm_encoder *drm_enc) phys->comp_ratio = comp_info->comp_ratio; phys->wide_bus_en = sde_enc->mode_info.wide_bus_en; phys->frame_trigger_mode = sde_enc->frame_trigger_mode; + phys->poms_align_vsync = disp_info->poms_align_vsync; if (phys->comp_type == MSM_DISPLAY_COMPRESSION_DSC) { phys->dsc_extra_pclk_cycle_cnt = comp_info->dsc_info.pclk_per_line; diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 698aab7b1d66..8a4eff00deb6 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -271,6 +271,7 @@ struct sde_encoder_irq { * @dsc_extra_pclk_cycle_cnt: Extra pclk cycle count for DSC over DP * @dsc_extra_disp_width: Additional display width for DSC over DP * @wide_bus_en: Wide-bus configuraiton + * @poms_align_vsync: poms with vsync aligned * @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes * @enable_state: Enable state tracking * @vblank_refcount: Reference count of vblank request @@ -317,6 +318,7 @@ struct sde_encoder_phys { u32 dsc_extra_pclk_cycle_cnt; u32 dsc_extra_disp_width; bool wide_bus_en; + bool poms_align_vsync; spinlock_t *enc_spinlock; enum sde_enc_enable_state enable_state; struct mutex *vblank_ctl_lock; diff --git a/msm/sde/sde_encoder_phys_vid.c b/msm/sde/sde_encoder_phys_vid.c index fb3ee711eb25..a9dbc173868a 100644 --- a/msm/sde/sde_encoder_phys_vid.c +++ b/msm/sde/sde_encoder_phys_vid.c @@ -88,6 +88,7 @@ static void drm_mode_to_intf_timing_params( vid_enc->base.comp_ratio); } + timing->poms_align_vsync = phys_enc->poms_align_vsync; timing->height = mode->vdisplay; /* active height */ timing->xres = timing->width; timing->yres = timing->height; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index c42b492e047d..64faa253be29 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -2150,6 +2150,10 @@ static int sde_intf_parse_dt(struct device_node *np, set_bit(SDE_INTF_TE, &intf->features); } + + if (SDE_HW_MAJOR(sde_cfg->hwversion) >= + SDE_HW_MAJOR(SDE_HW_VER_700)) + set_bit(SDE_INTF_TE_ALIGN_VSYNC, &intf->features); } end: diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 2b0008974eef..d1d53888f8d7 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -446,11 +446,13 @@ enum { * @SDE_INTF_INPUT_CTRL Supports the setting of pp block from which * pixel data arrives to this INTF * @SDE_INTF_TE INTF block has TE configuration support + * @SDE_INTF_TE_ALIGN_VSYNC INTF block has POMS Align vsync support * @SDE_INTF_MAX */ enum { SDE_INTF_INPUT_CTRL = 0x1, SDE_INTF_TE, + SDE_INTF_TE_ALIGN_VSYNC, SDE_INTF_MAX }; diff --git a/msm/sde/sde_hw_intf.c b/msm/sde/sde_hw_intf.c index 8024aadc0b48..7f6c9afdb40e 100644 --- a/msm/sde/sde_hw_intf.c +++ b/msm/sde/sde_hw_intf.c @@ -309,6 +309,11 @@ static void sde_hw_intf_setup_timing_engine(struct sde_hw_intf *ctx, if (p->wide_bus_en) intf_cfg2 |= BIT(0); + /* Synchronize timing engine enable to TE */ + if ((ctx->cap->features & BIT(SDE_INTF_TE_ALIGN_VSYNC)) + && p->poms_align_vsync) + intf_cfg2 |= BIT(16); + if (ctx->cfg.split_link_en) SDE_REG_WRITE(c, INTF_REG_SPLIT_LINK, 0x3); diff --git a/msm/sde/sde_hw_intf.h b/msm/sde/sde_hw_intf.h index 790147103f9d..c7e32d44e2d0 100644 --- a/msm/sde/sde_hw_intf.h +++ b/msm/sde/sde_hw_intf.h @@ -37,6 +37,7 @@ struct intf_timing_params { bool compression_en; u32 extra_dto_cycles; /* for DP only */ bool dsc_4hs_merge; /* DSC 4HS merge */ + bool poms_align_vsync; /* poms with vsync aligned */ }; struct intf_prog_fetch {