diff options
| author | Dmitry Baryshkov <dmitry.baryshkov@linaro.org> | 2025-02-14 16:14:25 -0800 |
|---|---|---|
| committer | Dmitry Baryshkov <dmitry.baryshkov@linaro.org> | 2025-03-05 04:33:33 +0200 |
| commit | 1ce69c265a53c61c5c29f97f542ff89af3f3d7e7 (patch) | |
| tree | dcd3cf57fade9a9c9cae7267c33f9aedb8ece805 /drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | |
| parent | 17666e764f389282fe1e35989e210401a0851980 (diff) | |
| download | linux-next-1ce69c265a53c61c5c29f97f542ff89af3f3d7e7.tar.gz linux-next-1ce69c265a53c61c5c29f97f542ff89af3f3d7e7.zip | |
drm/msm/dpu: move resource allocation to CRTC
All resource allocation is centered around the LMs. Then other blocks
(except DSCs) are allocated basing on the LMs that was selected, and LM
powers up the CRTC rather than the encoder.
Moreover if at some point the driver supports encoder cloning,
allocating resources from the encoder will be incorrect, as all clones
will have different encoder IDs, while LMs are to be shared by these
encoders.
In addition, move mode_changed() to dpu_crtc as encoder no longer has
access to topology information
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
[quic_abhinavk@quicinc.com: Refactored resource allocation for CDM]
Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
[quic_jesszhan@quicinc.com: Changed to grabbing exising global state]
Signed-off-by: Jessica Zhang <quic_jesszhan@quicinc.com>
[DB: rebased on top of msm-next]
[DB: fixed resource allcoation to ignore the active_changed flag]
Patchwork: https://patchwork.freedesktop.org/patch/637487/
Link: https://lore.kernel.org/r/20250214-concurrent-wb-v6-2-a44c293cf422@quicinc.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c')
| -rw-r--r-- | drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 167 |
1 files changed, 52 insertions, 115 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 61903f77730d..9cba23dfd86f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -58,8 +58,6 @@ #define IDLE_SHORT_TIMEOUT 1 -#define MAX_HDISPLAY_SPLIT 1080 - /* timeout in frames waiting for frame done */ #define DPU_ENCODER_FRAME_DONE_TIMEOUT_FRAMES 5 @@ -647,46 +645,29 @@ struct drm_dsc_config *dpu_encoder_get_dsc_config(struct drm_encoder *drm_enc) return NULL; } -static struct msm_display_topology dpu_encoder_get_topology( - struct dpu_encoder_virt *dpu_enc, - struct drm_display_mode *mode, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +void dpu_encoder_update_topology(struct drm_encoder *drm_enc, + struct msm_display_topology *topology, + struct drm_atomic_state *state, + const struct drm_display_mode *adj_mode) { + struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); struct msm_drm_private *priv = dpu_enc->base.dev->dev_private; struct msm_display_info *disp_info = &dpu_enc->disp_info; struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); - struct drm_dsc_config *dsc = dpu_encoder_get_dsc_config(&dpu_enc->base); - struct msm_display_topology topology = {0}; - int i, intf_count = 0; + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_framebuffer *fb; + struct drm_dsc_config *dsc; + + int i; for (i = 0; i < MAX_PHYS_ENCODERS_PER_VIRTUAL; i++) if (dpu_enc->phys_encs[i]) - intf_count++; + topology->num_intf++; - /* Datapath topology selection - * - * Dual display - * 2 LM, 2 INTF ( Split display using 2 interfaces) - * - * Single display - * 1 LM, 1 INTF - * 2 LM, 1 INTF (stream merge to support high resolution interfaces) - * - * Add dspps to the reservation requirements if ctm is requested - */ - if (intf_count == 2) - topology.num_lm = 2; - else if (!dpu_kms->catalog->caps->has_3d_merge) - topology.num_lm = 1; - else - topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; - - if (crtc_state->ctm) - topology.num_dspp = topology.num_lm; - - topology.num_intf = intf_count; + dsc = dpu_encoder_get_dsc_config(drm_enc); + /* We only support 2 DSC mode (with 2 LM and 1 INTF) */ if (dsc) { /* * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces @@ -695,112 +676,69 @@ static struct msm_display_topology dpu_encoder_get_topology( * This is power-optimal and can drive up to (including) 4k * screens. */ - WARN(topology.num_intf > 2, + WARN(topology->num_intf > 2, "DSC topology cannot support more than 2 interfaces\n"); - if (intf_count >= 2 || dpu_kms->catalog->dsc_count >= 2) { - topology.num_dsc = 2; - topology.num_lm = 2; - } else { - topology.num_dsc = 1; - topology.num_lm = 1; - } + if (topology->num_intf >= 2 || dpu_kms->catalog->dsc_count >= 2) + topology->num_dsc = 2; + else + topology->num_dsc = 1; } + connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); + if (!connector) + return; + conn_state = drm_atomic_get_new_connector_state(state, connector); + if (!conn_state) + return; + /* * Use CDM only for writeback or DP at the moment as other interfaces cannot handle it. * If writeback itself cannot handle cdm for some reason it will fail in its atomic_check() * earlier. */ if (disp_info->intf_type == INTF_WB && conn_state->writeback_job) { - struct drm_framebuffer *fb; - fb = conn_state->writeback_job->fb; if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb))) - topology.needs_cdm = true; + topology->needs_cdm = true; } else if (disp_info->intf_type == INTF_DP) { - if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], mode)) - topology.needs_cdm = true; + if (msm_dp_is_yuv_420_enabled(priv->dp[disp_info->h_tile_instance[0]], adj_mode)) + topology->needs_cdm = true; } - - return topology; } -/** - * dpu_encoder_virt_check_mode_changed: check if full modeset is required - * @drm_enc: Pointer to drm encoder structure - * @crtc_state: Corresponding CRTC state to be checked - * @conn_state: Corresponding Connector's state to be checked - * - * Check if the changes in the object properties demand full mode set. - */ -int dpu_encoder_virt_check_mode_changed(struct drm_encoder *drm_enc, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) +bool dpu_encoder_needs_modeset(struct drm_encoder *drm_enc, struct drm_atomic_state *state) { + struct drm_connector *connector; + struct drm_connector_state *conn_state; + struct drm_framebuffer *fb; struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); - struct msm_display_topology topology; - - DPU_DEBUG_ENC(dpu_enc, "\n"); - - /* Using mode instead of adjusted_mode as it wasn't computed yet */ - topology = dpu_encoder_get_topology(dpu_enc, &crtc_state->mode, crtc_state, conn_state); - - if (topology.needs_cdm && !dpu_enc->cur_master->hw_cdm) - crtc_state->mode_changed = true; - else if (!topology.needs_cdm && dpu_enc->cur_master->hw_cdm) - crtc_state->mode_changed = true; - return 0; -} + if (!drm_enc || !state) + return false; -static int dpu_encoder_virt_atomic_check( - struct drm_encoder *drm_enc, - struct drm_crtc_state *crtc_state, - struct drm_connector_state *conn_state) -{ - struct dpu_encoder_virt *dpu_enc; - struct msm_drm_private *priv; - struct dpu_kms *dpu_kms; - struct drm_display_mode *adj_mode; - struct msm_display_topology topology; - struct dpu_global_state *global_state; - int ret = 0; + connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); + if (!connector) + return false; - if (!drm_enc || !crtc_state || !conn_state) { - DPU_ERROR("invalid arg(s), drm_enc %d, crtc/conn state %d/%d\n", - drm_enc != NULL, crtc_state != NULL, conn_state != NULL); - return -EINVAL; - } - - dpu_enc = to_dpu_encoder_virt(drm_enc); - DPU_DEBUG_ENC(dpu_enc, "\n"); + conn_state = drm_atomic_get_new_connector_state(state, connector); - priv = drm_enc->dev->dev_private; - dpu_kms = to_dpu_kms(priv->kms); - adj_mode = &crtc_state->adjusted_mode; - global_state = dpu_kms_get_global_state(crtc_state->state); - if (IS_ERR(global_state)) - return PTR_ERR(global_state); - - trace_dpu_enc_atomic_check(DRMID(drm_enc)); - - topology = dpu_encoder_get_topology(dpu_enc, adj_mode, crtc_state, conn_state); - - /* - * Release and Allocate resources on every modeset + /** + * These checks are duplicated from dpu_encoder_update_topology() since + * CRTC and encoder don't hold topology information */ - if (drm_atomic_crtc_needs_modeset(crtc_state)) { - dpu_rm_release(global_state, drm_enc); - - if (crtc_state->enable) - ret = dpu_rm_reserve(&dpu_kms->rm, global_state, - drm_enc, crtc_state, &topology); + if (dpu_enc->disp_info.intf_type == INTF_WB && conn_state->writeback_job) { + fb = conn_state->writeback_job->fb; + if (fb && MSM_FORMAT_IS_YUV(msm_framebuffer_format(fb))) { + if (!dpu_enc->cur_master->hw_cdm) + return true; + } else { + if (dpu_enc->cur_master->hw_cdm) + return true; + } } - trace_dpu_enc_atomic_check_flags(DRMID(drm_enc), adj_mode->flags); - - return ret; + return false; } static void _dpu_encoder_update_vsync_source(struct dpu_encoder_virt *dpu_enc, @@ -2619,7 +2557,6 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { .atomic_mode_set = dpu_encoder_virt_atomic_mode_set, .atomic_disable = dpu_encoder_virt_atomic_disable, .atomic_enable = dpu_encoder_virt_atomic_enable, - .atomic_check = dpu_encoder_virt_atomic_check, }; static const struct drm_encoder_funcs dpu_encoder_funcs = { |
