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:

committed by
Gerrit - the friendly Code Review server

parent
e280657f7f
commit
fea2f25ccf
@@ -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->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->avr_step_fps = display->panel->avr_caps.avr_step_fps;
|
||||||
info->poms_align_vsync = display->panel->poms_align_vsync;
|
info->poms_align_vsync = display->panel->poms_align_vsync;
|
||||||
|
info->is_te_using_watchdog_timer = is_sim_panel(display);
|
||||||
|
|
||||||
switch (display->panel->panel_mode) {
|
switch (display->panel->panel_mode) {
|
||||||
case DSI_OP_VIDEO_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;
|
info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
|
||||||
if (display->panel->panel_mode_switch_enabled)
|
if (display->panel->panel_mode_switch_enabled)
|
||||||
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
|
info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
|
||||||
info->is_te_using_watchdog_timer = is_sim_panel(display);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DSI_ERR("unknwown dsi panel mode %d\n",
|
DSI_ERR("unknwown dsi panel mode %d\n",
|
||||||
|
@@ -1599,7 +1599,8 @@ static void sde_encoder_phys_cmd_enable_helper(
|
|||||||
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
sde_enc = to_sde_encoder_virt(phys_enc->parent);
|
||||||
if (sde_enc->idle_pc_restore) {
|
if (sde_enc->idle_pc_restore) {
|
||||||
qsync_mode = sde_connector_get_qsync_mode(phys_enc->connector);
|
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;
|
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;
|
struct sde_encoder_virt *sde_enc;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
bool recovery_events;
|
bool recovery_events;
|
||||||
|
u32 qsync_mode = 0;
|
||||||
|
bool panel_dead = false;
|
||||||
|
|
||||||
if (!phys_enc || !phys_enc->hw_pp) {
|
if (!phys_enc || !phys_enc->hw_pp) {
|
||||||
SDE_ERROR("invalid encoder\n");
|
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_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;
|
phys_enc->frame_trigger_mode = params->frame_trigger_mode;
|
||||||
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
|
||||||
atomic_read(&phys_enc->pending_kickoff_cnt),
|
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)
|
else if (phys_enc->hw_pp->ops.update_tearcheck)
|
||||||
phys_enc->hw_pp->ops.update_tearcheck(
|
phys_enc->hw_pp->ops.update_tearcheck(
|
||||||
phys_enc->hw_pp, &tc_cfg);
|
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_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) {
|
if (sde_enc->restore_te_rd_ptr) {
|
||||||
sde_encoder_restore_tearcheck_rd_ptr(phys_enc);
|
sde_encoder_restore_tearcheck_rd_ptr(phys_enc);
|
||||||
sde_enc->restore_te_rd_ptr = false;
|
sde_enc->restore_te_rd_ptr = false;
|
||||||
@@ -2051,13 +2064,20 @@ static int _sde_encoder_phys_cmd_handle_wr_ptr_timeout(
|
|||||||
bool switch_te;
|
bool switch_te;
|
||||||
int ret = -ETIMEDOUT;
|
int ret = -ETIMEDOUT;
|
||||||
unsigned long lock_flags;
|
unsigned long lock_flags;
|
||||||
|
struct sde_encoder_virt *sde_enc;
|
||||||
|
|
||||||
switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
|
switch_te = _sde_encoder_phys_cmd_needs_vsync_change(
|
||||||
phys_enc, profile_timestamp);
|
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);
|
SDE_EVT32(DRMID(phys_enc->parent), switch_te, SDE_EVTLOG_FUNC_ENTRY);
|
||||||
|
|
||||||
if (sde_connector_panel_dead(phys_enc->connector)) {
|
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);
|
ret = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
|
||||||
} else if (switch_te) {
|
} else if (switch_te) {
|
||||||
SDE_DEBUG_CMDENC(cmd_enc,
|
SDE_DEBUG_CMDENC(cmd_enc,
|
||||||
|
@@ -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)
|
if (vid_enc->base.hw_intf->ops.avr_ctrl)
|
||||||
vid_enc->base.hw_intf->ops.avr_ctrl(vid_enc->base.hw_intf, &avr_params);
|
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,
|
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(
|
static void sde_encoder_phys_vid_setup_timing_engine(
|
||||||
|
@@ -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_WD_LTJ_CTL, &intf->features);
|
||||||
set_bit(SDE_INTF_TE_DEASSERT_DETECT, &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_VSYNC_TS_SRC_EN, &intf->features);
|
||||||
|
set_bit(SDE_INTF_TE_LEVEL_TRIGGER, &intf->features);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -636,6 +636,7 @@ enum {
|
|||||||
* @SDE_INTF_WD_LTJ_CTL INTF block has WD long term jitter control support
|
* @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_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_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
|
* @SDE_INTF_MAX
|
||||||
*/
|
*/
|
||||||
enum {
|
enum {
|
||||||
@@ -655,6 +656,7 @@ enum {
|
|||||||
SDE_INTF_WD_LTJ_CTL,
|
SDE_INTF_WD_LTJ_CTL,
|
||||||
SDE_INTF_TE_DEASSERT_DETECT,
|
SDE_INTF_TE_DEASSERT_DETECT,
|
||||||
SDE_INTF_VSYNC_TS_SRC_EN,
|
SDE_INTF_VSYNC_TS_SRC_EN,
|
||||||
|
SDE_INTF_TE_LEVEL_TRIGGER,
|
||||||
SDE_INTF_MAX
|
SDE_INTF_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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(
|
static void sde_hw_intf_setup_prg_fetch(
|
||||||
struct sde_hw_intf *intf,
|
struct sde_hw_intf *intf,
|
||||||
const struct intf_prog_fetch *fetch)
|
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->get_autorefresh = sde_hw_intf_get_autorefresh_config;
|
||||||
ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr;
|
ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr;
|
||||||
ops->vsync_sel = sde_hw_intf_vsync_sel;
|
ops->vsync_sel = sde_hw_intf_vsync_sel;
|
||||||
ops->check_and_reset_tearcheck =
|
ops->check_and_reset_tearcheck = sde_hw_intf_v1_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->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))
|
if (cap & BIT(SDE_INTF_RESET_COUNTER))
|
||||||
|
@@ -222,6 +222,11 @@ struct sde_hw_intf_ops {
|
|||||||
void (*avr_ctrl)(struct sde_hw_intf *intf,
|
void (*avr_ctrl)(struct sde_hw_intf *intf,
|
||||||
const struct intf_avr_params *avr_params);
|
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
|
* Indicates the AVR armed status
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user