diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index 111f9fe6d9..7f34b8d915 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2014-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -3504,7 +3505,8 @@ static void sde_encoder_frame_done_callback( if (event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR - | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode) { + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) && is_cmd_mode + && !sde_encoder_check_ctl_done_support(drm_enc)) { if (ready_phys->connector) topology = sde_connector_get_topology_name( @@ -5099,6 +5101,9 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, sde_enc->input_event_enabled = test_bit(SDE_FEATURE_TOUCH_WAKEUP, sde_kms->catalog->features); + sde_enc->ctl_done_supported = test_bit(SDE_FEATURE_CTL_DONE, + sde_kms->catalog->features); + mutex_lock(&sde_enc->enc_lock); for (i = 0; i < disp_info->num_of_h_tiles && !ret; i++) { /* diff --git a/msm/sde/sde_encoder.h b/msm/sde/sde_encoder.h index eaf1eb24c7..e1255a6175 100644 --- a/msm/sde/sde_encoder.h +++ b/msm/sde/sde_encoder.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark @@ -182,6 +183,8 @@ enum sde_enc_rc_states { * next update is triggered. * @autorefresh_solver_disable It tracks if solver state is disabled from this * encoder due to autorefresh concurrency. + * @ctl_done_supported boolean flag to indicate the availability of + * ctl done irq support for the hardware */ struct sde_encoder_virt { struct drm_encoder base; @@ -248,6 +251,7 @@ struct sde_encoder_virt { struct msm_mode_info mode_info; bool delay_kickoff; bool autorefresh_solver_disable; + bool ctl_done_supported; }; #define to_sde_encoder_virt(x) container_of(x, struct sde_encoder_virt, base) @@ -524,6 +528,19 @@ bool sde_encoder_is_primary_display(struct drm_encoder *enc); */ bool sde_encoder_is_built_in_display(struct drm_encoder *enc); +/** + * sde_encoder_check_ctl_done_support - checks if ctl_done irq is available + * for the display + * @drm_enc: Pointer to drm encoder structure + * @Return: true if scheduler update is enabled + */ +static inline bool sde_encoder_check_ctl_done_support(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc && sde_enc->ctl_done_supported; +} + /** * sde_encoder_is_dsi_display - checks if underlying display is DSI * display or not. diff --git a/msm/sde/sde_encoder_phys.h b/msm/sde/sde_encoder_phys.h index 672324fc21..1aa37247b5 100644 --- a/msm/sde/sde_encoder_phys.h +++ b/msm/sde/sde_encoder_phys.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -195,6 +196,8 @@ struct sde_encoder_phys_ops { * @INTR_IDX_VSYNC: Vsync interrupt for video mode panel * @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel * @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel + * @INTR_IDX_CTL_START:Control start interrupt to indicate the frame start + * @INTR_IDX_CTL_DONE: Control done interrupt indicating the control path being idle * @INTR_IDX_RDPTR: Readpointer done interrupt for cmd mode panel * @INTR_IDX_WB_DONE: Writeback done interrupt for WB * @INTR_IDX_PP1_OVFL: Pingpong overflow interrupt on PP1 for Concurrent WB @@ -213,6 +216,7 @@ enum sde_intr_idx { INTR_IDX_PINGPONG, INTR_IDX_UNDERRUN, INTR_IDX_CTL_START, + INTR_IDX_CTL_DONE, INTR_IDX_RDPTR, INTR_IDX_AUTOREFRESH_DONE, INTR_IDX_WB_DONE, @@ -400,7 +404,7 @@ struct sde_encoder_phys_cmd_te_timestamp { * mode specific operations * @base: Baseclass physical encoder structure * @stream_sel: Stream selection for multi-stream interfaces - * @pp_timeout_report_cnt: number of pingpong done irq timeout errors + * @frame_tx_timeout_report_cnt: number of pp_done/ctl_done irq timeout errors * @autorefresh: autorefresh feature state * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK * @pending_vblank_wq: Wait queue for blocking until VBLANK received @@ -411,7 +415,7 @@ struct sde_encoder_phys_cmd_te_timestamp { struct sde_encoder_phys_cmd { struct sde_encoder_phys base; int stream_sel; - int pp_timeout_report_cnt; + int frame_tx_timeout_report_cnt; struct sde_encoder_phys_cmd_autorefresh autorefresh; atomic_t pending_vblank_cnt; wait_queue_head_t pending_vblank_wq; diff --git a/msm/sde/sde_encoder_phys_cmd.c b/msm/sde/sde_encoder_phys_cmd.c index 7ee1c53b0e..a8120f9659 100644 --- a/msm/sde/sde_encoder_phys_cmd.c +++ b/msm/sde/sde_encoder_phys_cmd.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -170,30 +171,24 @@ static void _sde_encoder_phys_cmd_update_intf_cfg( } } -static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) +static void _sde_encoder_phys_signal_frame_done(struct sde_encoder_phys *phys_enc) { - struct sde_encoder_phys *phys_enc = arg; struct sde_encoder_phys_cmd *cmd_enc; struct sde_hw_ctl *ctl; u32 scheduler_status = INVALID_CTL_STATUS, event = 0; - if (!phys_enc || !phys_enc->hw_pp) - return; - cmd_enc = to_sde_encoder_phys_cmd(phys_enc); ctl = phys_enc->hw_ctl; - SDE_ATRACE_BEGIN("pp_done_irq"); - /* notify all synchronous clients first, then asynchronous clients */ if (phys_enc->parent_ops.handle_frame_done && - atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) { + atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) { event = SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; spin_lock(phys_enc->enc_spinlock); phys_enc->parent_ops.handle_frame_done(phys_enc->parent, phys_enc, event); - if (cmd_enc->pp_timeout_report_cnt) + if (cmd_enc->frame_tx_timeout_report_cnt) phys_enc->recovered = true; spin_unlock(phys_enc->enc_spinlock); } @@ -201,11 +196,38 @@ static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) if (ctl && ctl->ops.get_scheduler_status) scheduler_status = ctl->ops.get_scheduler_status(ctl); - SDE_EVT32_IRQ(DRMID(phys_enc->parent), - phys_enc->hw_pp->idx - PINGPONG_0, event, scheduler_status); + SDE_EVT32_IRQ(DRMID(phys_enc->parent), ctl->idx - CTL_0, + phys_enc->hw_pp->idx - PINGPONG_0, event, scheduler_status); /* Signal any waiting atomic commit thread */ wake_up_all(&phys_enc->pending_kickoff_wq); +} + +static void sde_encoder_phys_cmd_ctl_done_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + + if (!phys_enc) + return; + + SDE_ATRACE_BEGIN("ctl_done_irq"); + + _sde_encoder_phys_signal_frame_done(phys_enc); + + SDE_ATRACE_END("ctl_done_irq"); +} + +static void sde_encoder_phys_cmd_pp_tx_done_irq(void *arg, int irq_idx) +{ + struct sde_encoder_phys *phys_enc = arg; + + if (!phys_enc || !phys_enc->hw_pp) + return; + + SDE_ATRACE_BEGIN("pp_done_irq"); + + _sde_encoder_phys_signal_frame_done(phys_enc); + SDE_ATRACE_END("pp_done_irq"); } @@ -337,6 +359,9 @@ static void _sde_encoder_phys_cmd_setup_irq_hw_idx( irq = &phys_enc->irq[INTR_IDX_CTL_START]; irq->hw_idx = phys_enc->hw_ctl->idx; + irq = &phys_enc->irq[INTR_IDX_CTL_DONE]; + irq->hw_idx = phys_enc->hw_ctl->idx; + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; irq->hw_idx = phys_enc->hw_pp->idx; @@ -457,7 +482,7 @@ static void sde_encoder_phys_cmd_mode_set( sde_encoder_helper_get_kickoff_timeout_ms(phys_enc->parent); } -static int _sde_encoder_phys_cmd_handle_ppdone_timeout( +static int _sde_encoder_phys_cmd_handle_framedone_timeout( struct sde_encoder_phys *phys_enc) { struct sde_encoder_phys_cmd *cmd_enc = @@ -479,11 +504,11 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)) return 0; - cmd_enc->pp_timeout_report_cnt++; + cmd_enc->frame_tx_timeout_report_cnt++; pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1; SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, - cmd_enc->pp_timeout_report_cnt, + cmd_enc->frame_tx_timeout_report_cnt, pending_kickoff_cnt, frame_event); @@ -492,7 +517,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( goto exit; /* to avoid flooding, only log first time, and "dead" time */ - if (cmd_enc->pp_timeout_report_cnt == 1) { + if (cmd_enc->frame_tx_timeout_report_cnt == 1) { SDE_ERROR_CMDENC(cmd_enc, "pp:%d kickoff timed out ctl %d koff_cnt %d\n", phys_enc->hw_pp->idx - PINGPONG_0, @@ -517,7 +542,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout( if (recovery_events) sde_connector_event_notify(conn, DRM_EVENT_SDE_HW_RECOVERY, sizeof(uint8_t), SDE_RECOVERY_CAPTURE); - else if (cmd_enc->pp_timeout_report_cnt) + else if (cmd_enc->frame_tx_timeout_report_cnt) SDE_DBG_DUMP(0x0, "panic"); /* request a ctl reset before the next kickoff */ @@ -701,6 +726,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle( struct sde_encoder_phys *phys_enc) { struct sde_encoder_wait_info wait_info = {0}; + enum sde_intr_idx intr_idx; int ret; if (!phys_enc) { @@ -722,13 +748,14 @@ static int _sde_encoder_phys_cmd_wait_for_idle( if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) return 0; - ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG, - &wait_info); + intr_idx = sde_encoder_check_ctl_done_support(phys_enc->parent) ? + INTR_IDX_CTL_DONE : INTR_IDX_PINGPONG; + + ret = sde_encoder_helper_wait_for_irq(phys_enc, intr_idx, &wait_info); if (ret == -ETIMEDOUT) { if (_sde_encoder_phys_cmd_is_scheduler_idle(phys_enc)) return 0; - - _sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc); + _sde_encoder_phys_cmd_handle_framedone_timeout(phys_enc); } return ret; @@ -834,6 +861,7 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, bool enable) { struct sde_encoder_phys_cmd *cmd_enc; + bool ctl_done_supported = false; if (!phys_enc) return; @@ -851,8 +879,12 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0, enable, atomic_read(&phys_enc->vblank_refcount)); + ctl_done_supported = sde_encoder_check_ctl_done_support(phys_enc->parent); + if (enable) { - sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG); + if (!ctl_done_supported) + sde_encoder_helper_register_irq(phys_enc, INTR_IDX_PINGPONG); + sde_encoder_phys_cmd_control_vblank_irq(phys_enc, true); if (sde_encoder_phys_cmd_is_master(phys_enc)) { @@ -860,6 +892,8 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, INTR_IDX_WRPTR); sde_encoder_helper_register_irq(phys_enc, INTR_IDX_AUTOREFRESH_DONE); + if (ctl_done_supported) + sde_encoder_helper_register_irq(phys_enc, INTR_IDX_CTL_DONE); } } else { @@ -868,10 +902,14 @@ void sde_encoder_phys_cmd_irq_control(struct sde_encoder_phys *phys_enc, INTR_IDX_WRPTR); sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_AUTOREFRESH_DONE); + if (ctl_done_supported) + sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_CTL_DONE); } sde_encoder_phys_cmd_control_vblank_irq(phys_enc, false); - sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG); + + if (!ctl_done_supported) + sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_PINGPONG); } } @@ -1337,13 +1375,13 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff( if (phys_enc->recovered) { recovery_events = sde_encoder_recovery_events_enabled( phys_enc->parent); - if (cmd_enc->pp_timeout_report_cnt && recovery_events) + if (cmd_enc->frame_tx_timeout_report_cnt && recovery_events) sde_connector_event_notify(phys_enc->connector, DRM_EVENT_SDE_HW_RECOVERY, sizeof(uint8_t), SDE_RECOVERY_SUCCESS); - cmd_enc->pp_timeout_report_cnt = 0; + cmd_enc->frame_tx_timeout_report_cnt = 0; phys_enc->recovered = false; } @@ -1988,6 +2026,12 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( irq->intr_idx = INTR_IDX_CTL_START; irq->cb.func = NULL; + irq = &phys_enc->irq[INTR_IDX_CTL_DONE]; + irq->name = "ctl_done"; + irq->intr_type = SDE_IRQ_TYPE_CTL_DONE; + irq->intr_idx = INTR_IDX_CTL_DONE; + irq->cb.func = sde_encoder_phys_cmd_ctl_done_irq; + irq = &phys_enc->irq[INTR_IDX_PINGPONG]; irq->name = "pp_done"; irq->intr_type = SDE_IRQ_TYPE_PING_PONG_COMP; diff --git a/msm/sde/sde_hw_catalog.c b/msm/sde/sde_hw_catalog.c index 1b78d05da7..dae861c884 100644 --- a/msm/sde/sde_hw_catalog.c +++ b/msm/sde/sde_hw_catalog.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -5226,6 +5227,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) set_bit(SDE_FEATURE_HW_VSYNC_TS, sde_cfg->features); set_bit(SDE_FEATURE_AVR_STEP, sde_cfg->features); set_bit(SDE_FEATURE_VBIF_CLK_SPLIT, sde_cfg->features); + set_bit(SDE_FEATURE_CTL_DONE, sde_cfg->features); sde_cfg->sc_cfg[SDE_SYS_CACHE_DISP].has_sys_cache = true; sde_cfg->allowed_dsc_reservation_switch = SDE_DP_DSC_RESERVATION_SWITCH; sde_cfg->autorefresh_disable_seq = AUTOREFRESH_DISABLE_SEQ2; diff --git a/msm/sde/sde_hw_catalog.h b/msm/sde/sde_hw_catalog.h index 8135c52f71..86f54685a9 100644 --- a/msm/sde/sde_hw_catalog.h +++ b/msm/sde/sde_hw_catalog.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2015-2021, The Linux Foundation. All rights reserved. */ @@ -676,6 +677,7 @@ enum { * @SDE_FEATURE_TRUSTED_VM Trusted VM supported * @SDE_FEATURE_UBWC_STATS UBWC statistics supported * @SDE_FEATURE_VBIF_CLK_SPLIT VBIF clock split supported + * @SDE_FEATURE_CTL_DONE Support for CTL DONE irq * @SDE_FEATURE_MAX: MAX features value */ enum sde_mdss_features { @@ -716,6 +718,7 @@ enum sde_mdss_features { SDE_FEATURE_TRUSTED_VM, SDE_FEATURE_UBWC_STATS, SDE_FEATURE_VBIF_CLK_SPLIT, + SDE_FEATURE_CTL_DONE, SDE_FEATURE_MAX }; diff --git a/msm/sde/sde_hw_interrupts.c b/msm/sde/sde_hw_interrupts.c index b4ec16bcb4..ceac3e02bd 100644 --- a/msm/sde/sde_hw_interrupts.c +++ b/msm/sde/sde_hw_interrupts.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. */ @@ -91,6 +92,16 @@ #define SDE_INTR_CTL_4_START BIT(13) #define SDE_INTR_CTL_5_START BIT(23) +/** + * Ctl done interrupt status bit definitions + */ +#define SDE_INTR_CTL_0_DONE BIT(0) +#define SDE_INTR_CTL_1_DONE BIT(1) +#define SDE_INTR_CTL_2_DONE BIT(2) +#define SDE_INTR_CTL_3_DONE BIT(3) +#define SDE_INTR_CTL_4_DONE BIT(4) +#define SDE_INTR_CTL_5_DONE BIT(5) + /** * Concurrent WB overflow interrupt status bit definitions */ @@ -283,6 +294,19 @@ static struct sde_irq_type sde_irq_intr2_map[] = { { SDE_IRQ_TYPE_CTL_START, CTL_5, SDE_INTR_CTL_5_START, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_0, + SDE_INTR_CTL_0_DONE, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_1, + SDE_INTR_CTL_1_DONE, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_2, + SDE_INTR_CTL_2_DONE, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_3, + SDE_INTR_CTL_3_DONE, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_4, + SDE_INTR_CTL_4_DONE, -1}, + { SDE_IRQ_TYPE_CTL_DONE, CTL_5, + SDE_INTR_CTL_5_DONE, -1}, + { SDE_IRQ_TYPE_CWB_OVERFLOW, PINGPONG_CWB_0, SDE_INTR_CWB_OVERFLOW, -1}, { SDE_IRQ_TYPE_PING_PONG_COMP, PINGPONG_4, diff --git a/msm/sde/sde_hw_interrupts.h b/msm/sde/sde_hw_interrupts.h index 812395031f..aab65a510f 100644 --- a/msm/sde/sde_hw_interrupts.h +++ b/msm/sde/sde_hw_interrupts.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. */ @@ -49,6 +50,7 @@ * @SDE_IRQ_TYPE_PROG_LINE: Programmable Line interrupt * @SDE_IRQ_TYPE_AD4_BL_DONE: AD4 backlight * @SDE_IRQ_TYPE_CTL_START: Control start + * @SDE_IRQ_TYPE_CTL_DONE: Frame transfer complete * @SDE_IRQ_TYPE_INTF_TEAR_RD_PTR: INTF Tear read pointer * @SDE_IRQ_TYPE_INTF_TEAR_WR_PTR: INTF Tear write pointer * @SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF: INTF Tear auto refresh @@ -87,6 +89,7 @@ enum sde_intr_type { SDE_IRQ_TYPE_PROG_LINE, SDE_IRQ_TYPE_AD4_BL_DONE, SDE_IRQ_TYPE_CTL_START, + SDE_IRQ_TYPE_CTL_DONE, SDE_IRQ_TYPE_INTF_TEAR_RD_PTR, SDE_IRQ_TYPE_INTF_TEAR_WR_PTR, SDE_IRQ_TYPE_INTF_TEAR_AUTO_REF,