disp: msm: sde: add support for TE level trigger

During qsync frequency step down, it is possible for the changing
frame window to lead to frame buffers being transferred when it
is unsafe to update. Pineapple r2 hardware supports using the
panel's TE level, instead of the start window, to trigger the
frame transfer.

This change enables using TE level during QSYNC or AVR, if the
hardware supports it.

Change-Id: Ie675edaaeb80921c639905395b709f4c67134fc7
Signed-off-by: Amine Najahi <quic_anajahi@quicinc.com>
This commit is contained in:
Amine Najahi
2023-05-16 15:19:54 -04:00
committed by Gerrit - the friendly Code Review server
parent e280657f7f
commit fea2f25ccf
7 changed files with 59 additions and 9 deletions

View File

@@ -6779,6 +6779,7 @@ int dsi_display_get_info(struct drm_connector *connector,
info->has_qsync_min_fps_list = (display->panel->qsync_caps.qsync_min_fps_list_len > 0);
info->avr_step_fps = display->panel->avr_caps.avr_step_fps;
info->poms_align_vsync = display->panel->poms_align_vsync;
info->is_te_using_watchdog_timer = is_sim_panel(display);
switch (display->panel->panel_mode) {
case DSI_OP_VIDEO_MODE:
@@ -6792,7 +6793,6 @@ int dsi_display_get_info(struct drm_connector *connector,
info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
if (display->panel->panel_mode_switch_enabled)
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
info->is_te_using_watchdog_timer = is_sim_panel(display);
break;
default:
DSI_ERR("unknwown dsi panel mode %d\n",

View File

@@ -1599,7 +1599,8 @@ static void sde_encoder_phys_cmd_enable_helper(
sde_enc = to_sde_encoder_virt(phys_enc->parent);
if (sde_enc->idle_pc_restore) {
qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
if (qsync_mode)
if (qsync_mode && !test_bit(SDE_INTF_TE_LEVEL_TRIGGER,
&phys_enc->hw_intf->cap->features))
sde_enc->restore_te_rd_ptr = true;
}
@@ -1804,6 +1805,8 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
struct sde_encoder_virt *sde_enc;
int ret = 0;
bool recovery_events;
u32 qsync_mode = 0;
bool panel_dead = false;
if (!phys_enc || !phys_enc->hw_pp) {
SDE_ERROR("invalid encoder\n");
@@ -1811,6 +1814,7 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
}
SDE_DEBUG_CMDENC(cmd_enc, "pp %d\n", phys_enc->hw_pp->idx - PINGPONG_0);
sde_enc = to_sde_encoder_virt(phys_enc->parent);
phys_enc->frame_trigger_mode = params->frame_trigger_mode;
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
atomic_read(&phys_enc->pending_kickoff_cnt),
@@ -1859,11 +1863,20 @@ static int sde_encoder_phys_cmd_prepare_for_kickoff(
else if (phys_enc->hw_pp->ops.update_tearcheck)
phys_enc->hw_pp->ops.update_tearcheck(
phys_enc->hw_pp, &tc_cfg);
qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
panel_dead = sde_connector_panel_dead(phys_enc->connector);
if (cmd_enc->base.hw_intf->ops.enable_te_level_trigger &&
!sde_enc->disp_info.is_te_using_watchdog_timer)
cmd_enc->base.hw_intf->ops.enable_te_level_trigger(cmd_enc->base.hw_intf,
qsync_mode && !panel_dead);
SDE_EVT32(DRMID(phys_enc->parent), tc_cfg.sync_threshold_start, tc_cfg.start_pos,
SDE_EVTLOG_FUNC_CASE3);
qsync_mode, sde_enc->disp_info.is_te_using_watchdog_timer,
panel_dead, SDE_EVTLOG_FUNC_CASE3);
}
sde_enc = to_sde_encoder_virt(phys_enc->parent);
if (sde_enc->restore_te_rd_ptr) {
sde_encoder_restore_tearcheck_rd_ptr(phys_enc);
sde_enc->restore_te_rd_ptr = false;
@@ -2051,13 +2064,20 @@ static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
bool switch_te;
int ret = -ETIMEDOUT;
unsigned long lock_flags;
struct sde_encoder_virt *sde_enc;
switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
phys_enc, profile_timestamp);
sde_enc = to_sde_encoder_virt(phys_enc->parent);
SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_FUNC_ENTRY);
if (sde_connector_panel_dead(phys_enc->connector)) {
if (cmd_enc->base.hw_intf->ops.enable_te_level_trigger &&
!sde_enc->disp_info.is_te_using_watchdog_timer)
cmd_enc->base.hw_intf->ops.enable_te_level_trigger(cmd_enc->base.hw_intf,
false);
ret = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
} else if (switch_te) {
SDE_DEBUG_CMDENC(cmd_enc,

View File

@@ -393,8 +393,14 @@ static void _sde_encoder_phys_vid_avr_ctrl(struct sde_encoder_phys *phys_enc)
if (vid_enc->base.hw_intf->ops.avr_ctrl)
vid_enc->base.hw_intf->ops.avr_ctrl(vid_enc->base.hw_intf, &avr_params);
if (vid_enc->base.hw_intf->ops.enable_te_level_trigger &&
!sde_enc->disp_info.is_te_using_watchdog_timer)
vid_enc->base.hw_intf->ops.enable_te_level_trigger(vid_enc->base.hw_intf,
(avr_step_state == AVR_STEP_ENABLE));
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_intf->idx - INTF_0, avr_params.avr_mode,
avr_params.avr_step_lines, info->avr_step_fps, avr_step_state);
avr_params.avr_step_lines, info->avr_step_fps, avr_step_state,
sde_enc->disp_info.is_te_using_watchdog_timer);
}
static void sde_encoder_phys_vid_setup_timing_engine(

View File

@@ -2508,6 +2508,7 @@ static int sde_intf_parse_dt(struct device_node *np,
set_bit(SDE_INTF_WD_LTJ_CTL, &intf->features);
set_bit(SDE_INTF_TE_DEASSERT_DETECT, &intf->features);
set_bit(SDE_INTF_VSYNC_TS_SRC_EN, &intf->features);
set_bit(SDE_INTF_TE_LEVEL_TRIGGER, &intf->features);
}
}

View File

@@ -636,6 +636,7 @@ enum {
* @SDE_INTF_WD_LTJ_CTL INTF block has WD long term jitter control support
* @SDE_INTF_TE_DEASSERT_DETECT INTF block has TE Deassert detect support
* @SDE_INTF_VSYNC_TS_SRC_EN INTF block has VSYNC timestamp source selection support
* @SDE_INTF_TE_LEVEL_TRIGGER INTF block has TE Level trigger gating support
* @SDE_INTF_MAX
*/
enum {
@@ -655,6 +656,7 @@ enum {
SDE_INTF_WD_LTJ_CTL,
SDE_INTF_TE_DEASSERT_DETECT,
SDE_INTF_VSYNC_TS_SRC_EN,
SDE_INTF_TE_LEVEL_TRIGGER,
SDE_INTF_MAX
};

View File

@@ -451,6 +451,21 @@ static void sde_hw_intf_enable_timing_engine(struct sde_hw_intf *intf, u8 enable
}
}
static void sde_hw_intf_enable_te_level_trigger(struct sde_hw_intf *intf, bool enable)
{
struct sde_hw_blk_reg_map *c = &intf->hw;
u32 intf_cfg = 0;
intf_cfg = SDE_REG_READ(c, INTF_CONFIG);
if (enable)
intf_cfg |= BIT(22);
else
intf_cfg &= ~BIT(22);
SDE_REG_WRITE(c, INTF_CONFIG, intf_cfg);
}
static void sde_hw_intf_setup_prg_fetch(
struct sde_hw_intf *intf,
const struct intf_prog_fetch *fetch)
@@ -1081,10 +1096,11 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
ops->get_autorefresh = sde_hw_intf_get_autorefresh_config;
ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr;
ops->vsync_sel = sde_hw_intf_vsync_sel;
ops->check_and_reset_tearcheck =
sde_hw_intf_v1_check_and_reset_tearcheck;
ops->override_tear_rd_ptr_val =
sde_hw_intf_override_tear_rd_ptr_val;
ops->check_and_reset_tearcheck = sde_hw_intf_v1_check_and_reset_tearcheck;
ops->override_tear_rd_ptr_val = sde_hw_intf_override_tear_rd_ptr_val;
if (cap & BIT(SDE_INTF_TE_LEVEL_TRIGGER))
ops->enable_te_level_trigger = sde_hw_intf_enable_te_level_trigger;
}
if (cap & BIT(SDE_INTF_RESET_COUNTER))

View File

@@ -222,6 +222,11 @@ struct sde_hw_intf_ops {
void (*avr_ctrl)(struct sde_hw_intf *intf,
const struct intf_avr_params *avr_params);
/**
* Enable trigger based on TE level
*/
void (*enable_te_level_trigger)(struct sde_hw_intf *intf, bool enable);
/**
* Indicates the AVR armed status
*