diff --git a/msm/dsi/dsi_drm.c b/msm/dsi/dsi_drm.c index 52b2ac9626..baf2efae7a 100644 --- a/msm/dsi/dsi_drm.c +++ b/msm/dsi/dsi_drm.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. */ @@ -395,6 +396,63 @@ static void dsi_bridge_mode_set(struct drm_bridge *bridge, DSI_DEBUG("clk_rate: %llu\n", c_bridge->dsi_mode.timing.clk_rate_hz); } +static bool _dsi_bridge_mode_validate_and_fixup(struct drm_bridge *bridge, + struct drm_crtc_state *crtc_state, struct dsi_display *display, + struct dsi_display_mode *adj_mode) +{ + int rc = 0; + struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + struct dsi_display_mode cur_dsi_mode; + struct sde_connector_state *old_conn_state; + struct drm_display_mode *cur_mode; + + if (!bridge->encoder || !bridge->encoder->crtc || !crtc_state->crtc) { + DSI_ERR("invalid params\n"); + return -EINVAL; + } + + cur_mode = &crtc_state->crtc->state->mode; + old_conn_state = to_sde_connector_state(display->drm_conn->state); + + convert_to_dsi_mode(cur_mode, &cur_dsi_mode); + msm_parse_mode_priv_info(&old_conn_state->msm_mode, &cur_dsi_mode); + + rc = dsi_display_validate_mode_change(c_bridge->display, &cur_dsi_mode, adj_mode); + if (rc) { + DSI_ERR("[%s] seamless mode mismatch failure rc=%d\n", c_bridge->display->name, rc); + return rc; + } + + /* + * DMS Flag if set during active changed condition cannot be + * treated as seamless. Hence, removing DMS flag in such cases. + */ + if ((adj_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) && + crtc_state->active_changed) + adj_mode->dsi_mode_flags &= ~DSI_MODE_FLAG_DMS; + + /* No DMS/VRR when drm pipeline is changing */ + if (!dsi_display_mode_match(&cur_dsi_mode, adj_mode, + DSI_MODE_MATCH_FULL_TIMINGS) && + (!(adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR)) && + (!(adj_mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) && + (!(adj_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS_TO_VID)) && + (!(adj_mode->dsi_mode_flags & DSI_MODE_FLAG_POMS_TO_CMD)) && + (!crtc_state->active_changed || + display->is_cont_splash_enabled)) { + adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; + + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, + adj_mode->timing.h_active, + adj_mode->timing.v_active, + adj_mode->timing.refresh_rate, + adj_mode->pixel_clk_khz, + adj_mode->panel_mode_caps); + } + + return rc; +} + static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -402,10 +460,10 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, int rc = 0; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); struct dsi_display *display; - struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; + struct dsi_display_mode dsi_mode, *panel_dsi_mode; struct drm_crtc_state *crtc_state; struct drm_connector_state *drm_conn_state; - struct sde_connector_state *conn_state, *old_conn_state; + struct sde_connector_state *conn_state; struct msm_sub_mode new_sub_mode; crtc_state = container_of(mode, struct drm_crtc_state, mode); @@ -481,49 +539,10 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, return false; } - if (bridge->encoder && bridge->encoder->crtc && - crtc_state->crtc) { - const struct drm_display_mode *cur_mode = - &crtc_state->crtc->state->mode; - old_conn_state = to_sde_connector_state(display->drm_conn->state); - - convert_to_dsi_mode(cur_mode, &cur_dsi_mode); - msm_parse_mode_priv_info(&old_conn_state->msm_mode, &cur_dsi_mode); - - rc = dsi_display_validate_mode_change(c_bridge->display, - &cur_dsi_mode, &dsi_mode); - if (rc) { - DSI_ERR("[%s] seamless mode mismatch failure rc=%d\n", - c_bridge->display->name, rc); - return false; - } - - /* - * DMS Flag if set during active changed condition cannot be - * treated as seamless. Hence, removing DMS flag in such cases. - */ - if ((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DMS) && - crtc_state->active_changed) - dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_DMS; - - /* No DMS/VRR when drm pipeline is changing */ - if (!dsi_display_mode_match(&cur_dsi_mode, &dsi_mode, - DSI_MODE_MATCH_FULL_TIMINGS) && - (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && - (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK)) && - (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS_TO_VID)) && - (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS_TO_CMD)) && - (!crtc_state->active_changed || - display->is_cont_splash_enabled)) { - dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS; - - SDE_EVT32(SDE_EVTLOG_FUNC_CASE2, - dsi_mode.timing.h_active, - dsi_mode.timing.v_active, - dsi_mode.timing.refresh_rate, - dsi_mode.pixel_clk_khz, - dsi_mode.panel_mode_caps); - } + rc = _dsi_bridge_mode_validate_and_fixup(bridge, crtc_state, display, &dsi_mode); + if (rc) { + DSI_ERR("[%s] failed to validate dsi bridge mode.\n", display->name); + return false; } /* Reject seamless transition when active changed */ diff --git a/msm/sde/sde_encoder.c b/msm/sde/sde_encoder.c index c93a36b051..e4426242fe 100644 --- a/msm/sde/sde_encoder.c +++ b/msm/sde/sde_encoder.c @@ -1481,6 +1481,61 @@ static int _sde_encoder_rsc_client_update_vsync_wait( return ret; } +static int _sde_encoder_rsc_state_trigger(struct drm_encoder *drm_enc, enum sde_rsc_state rsc_state) +{ + struct sde_encoder_virt *sde_enc; + struct msm_display_info *disp_info; + struct sde_rsc_cmd_config *rsc_config; + struct drm_crtc *crtc; + int wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID; + int ret; + + /** + * Already checked drm_enc, sde_enc is valid in function + * _sde_encoder_update_rsc_client() which pass the parameters + * to this function. + */ + sde_enc = to_sde_encoder_virt(drm_enc); + crtc = sde_enc->crtc; + disp_info = &sde_enc->disp_info; + rsc_config = &sde_enc->rsc_config; + + if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init + && (disp_info->display_type == SDE_CONNECTOR_PRIMARY)) { + /* update it only once */ + sde_enc->rsc_state_init = true; + + ret = sde_rsc_client_state_update(sde_enc->rsc_client, + rsc_state, rsc_config, crtc->base.id, + &wait_vblank_crtc_id); + } else { + ret = sde_rsc_client_state_update(sde_enc->rsc_client, + rsc_state, NULL, crtc->base.id, + &wait_vblank_crtc_id); + } + + /** + * if RSC performed a state change that requires a VBLANK wait, it will + * set wait_vblank_crtc_id to the CRTC whose VBLANK we must wait on. + * + * if we are the primary display, we will need to enable and wait + * locally since we hold the commit thread + * + * if we are an external display, we must send a signal to the primary + * to enable its VBLANK and wait one, since the RSC hardware is driven + * by the primary panel's VBLANK signals + */ + SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id); + if (ret) { + SDE_ERROR_ENC(sde_enc, "sde rsc client update failed ret:%d\n", ret); + } else if (wait_vblank_crtc_id != SDE_RSC_INVALID_CRTC_ID) { + ret = _sde_encoder_rsc_client_update_vsync_wait(drm_enc, + sde_enc, wait_vblank_crtc_id); + } + + return ret; +} + static int _sde_encoder_update_rsc_client( struct drm_encoder *drm_enc, bool enable) { @@ -1491,7 +1546,6 @@ static int _sde_encoder_update_rsc_client( int ret; struct msm_display_info *disp_info; struct msm_mode_info *mode_info; - int wait_vblank_crtc_id = SDE_RSC_INVALID_CRTC_ID; u32 qsync_mode = 0, v_front_porch; struct drm_display_mode *mode; bool is_vid_mode; @@ -1575,42 +1629,7 @@ static int _sde_encoder_update_rsc_client( SDE_EVT32(DRMID(drm_enc), rsc_state, qsync_mode, rsc_config->fps, sde_enc->rsc_state_init); - if (rsc_state != SDE_RSC_IDLE_STATE && !sde_enc->rsc_state_init - && (disp_info->display_type == SDE_CONNECTOR_PRIMARY)) { - /* update it only once */ - sde_enc->rsc_state_init = true; - - ret = sde_rsc_client_state_update(sde_enc->rsc_client, - rsc_state, rsc_config, crtc->base.id, - &wait_vblank_crtc_id); - } else { - ret = sde_rsc_client_state_update(sde_enc->rsc_client, - rsc_state, NULL, crtc->base.id, - &wait_vblank_crtc_id); - } - - /** - * if RSC performed a state change that requires a VBLANK wait, it will - * set wait_vblank_crtc_id to the CRTC whose VBLANK we must wait on. - * - * if we are the primary display, we will need to enable and wait - * locally since we hold the commit thread - * - * if we are an external display, we must send a signal to the primary - * to enable its VBLANK and wait one, since the RSC hardware is driven - * by the primary panel's VBLANK signals - */ - SDE_EVT32_VERBOSE(DRMID(drm_enc), wait_vblank_crtc_id); - if (ret) { - SDE_ERROR_ENC(sde_enc, - "sde rsc client update failed ret:%d\n", ret); - return ret; - } else if (wait_vblank_crtc_id == SDE_RSC_INVALID_CRTC_ID) { - return ret; - } - - ret = _sde_encoder_rsc_client_update_vsync_wait(drm_enc, - sde_enc, wait_vblank_crtc_id); + ret = _sde_encoder_rsc_state_trigger(drm_enc, rsc_state); return ret; } @@ -4281,6 +4300,50 @@ void sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc) } } +static int _sde_encoder_prepare_for_kickoff_processing(struct drm_encoder *drm_enc, + struct sde_encoder_kickoff_params *params, + struct sde_encoder_virt *sde_enc, + struct sde_kms *sde_kms, + bool needs_hw_reset, bool is_cmd_mode) +{ + int rc, ret = 0; + + /* if any phys needs reset, reset all phys, in-order */ + if (needs_hw_reset) + sde_encoder_needs_hw_reset(drm_enc); + + _sde_encoder_update_master(drm_enc, params); + + _sde_encoder_update_roi(drm_enc); + + if (sde_enc->cur_master && sde_enc->cur_master->connector) { + rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); + if (rc) { + SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n", + sde_enc->cur_master->connector->base.id, rc); + ret = rc; + } + } + + if (sde_enc->cur_master && + ((is_cmd_mode && sde_enc->cur_master->cont_splash_enabled) || + !sde_enc->cur_master->cont_splash_enabled)) { + rc = sde_encoder_dce_setup(sde_enc, params); + if (rc) { + SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc); + ret = rc; + } + } + + sde_encoder_dce_flush(sde_enc); + + if (sde_enc->cur_master && !sde_enc->cur_master->cont_splash_enabled) + sde_configure_qdss(sde_enc, sde_enc->cur_master->hw_qdss, + sde_enc->cur_master, sde_kms->qdss_enabled); + + return ret; +} + int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, struct sde_encoder_kickoff_params *params) { @@ -4354,39 +4417,8 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, goto end; } - /* if any phys needs reset, reset all phys, in-order */ - if (needs_hw_reset) - sde_encoder_needs_hw_reset(drm_enc); - - _sde_encoder_update_master(drm_enc, params); - - _sde_encoder_update_roi(drm_enc); - - if (sde_enc->cur_master && sde_enc->cur_master->connector) { - rc = sde_connector_pre_kickoff(sde_enc->cur_master->connector); - if (rc) { - SDE_ERROR_ENC(sde_enc, "kickoff conn%d failed rc %d\n", - sde_enc->cur_master->connector->base.id, - rc); - ret = rc; - } - } - - if (sde_enc->cur_master && - ((is_cmd_mode && sde_enc->cur_master->cont_splash_enabled) || - !sde_enc->cur_master->cont_splash_enabled)) { - rc = sde_encoder_dce_setup(sde_enc, params); - if (rc) { - SDE_ERROR_ENC(sde_enc, "failed to setup DSC: %d\n", rc); - ret = rc; - } - } - - sde_encoder_dce_flush(sde_enc); - - if (sde_enc->cur_master && !sde_enc->cur_master->cont_splash_enabled) - sde_configure_qdss(sde_enc, sde_enc->cur_master->hw_qdss, - sde_enc->cur_master, sde_kms->qdss_enabled); + ret = _sde_encoder_prepare_for_kickoff_processing(drm_enc, params, sde_enc, sde_kms, + needs_hw_reset, is_cmd_mode); end: SDE_ATRACE_END("sde_encoder_prepare_for_kickoff");