From: Jessica Zhang <[email protected]> LM block doesn't have a hardware buffer (unlike PINGPONG and DSC encoders). As such, don't use ephemeral max_mixer_width and MAX_HDISPLAY_SPLIT to validate requested modes. Instead use PP and DSC buffer widths.
While on the DPU 8.x+ supports a max linewidth of 8960 for PINGPONG_0, there is some additional logic that needs to be added to the resource manager to specifically try and reserve PINGPONG_0 for modes that are greater than 5k. The layer-mixer count for a merge-capable, non-DSC mode is chosen by dpu_crtc_num_lm_for_mode(); feed the PINGPONG/DSC derived width to it as the split threshold in place of the removed MAX_HDISPLAY_SPLIT, so the pixel-rate floor added earlier keeps high-refresh modes that now fit within a single PINGPONG buffer split across two mixers. Signed-off-by: Jessica Zhang <[email protected]> Tested-by: Xilin Wu <[email protected]> # qcs6490-radxa-dragon-q6a [DB: reworked to drop catalog changes, updated commit message] Signed-off-by: Dmitry Baryshkov <[email protected]> [MP: rebased on msm-next; fed PINGPONG/DSC width into dpu_crtc_num_lm_for_mode() instead of open-coding the width test] Signed-off-by: Mahadevan P <[email protected]> --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 54 +++++++++++++++++++++----- drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h | 7 ++++ 2 files changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 209b25dbeb6c..41f986ca2a68 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -758,6 +758,22 @@ void dpu_crtc_complete_commit(struct drm_crtc *crtc) _dpu_crtc_complete_flip(crtc); } +static int msm_display_get_max_pingpong_width(struct dpu_kms *dpu_kms) +{ + /* + * Note: While, for DPU 8.x+, PINGPONG_0 can technically support up to + * 8k resolutions, this requires reworking the RM to try to reserve + * PINGPONG_0 for modes greater than 5k. + * + * Once this additional logic is implemented, we can probably drop this + * helper and use the reserved PINGPONG's max_linewidth + */ + if (dpu_kms->catalog->mdss_ver->core_major_ver < 6) + return DPU_1_x_MAX_PINGPONG_WIDTH; + else + return DPU_6_x_MAX_PINGPONG_WIDTH; +} + static int _dpu_crtc_check_and_setup_lm_bounds(struct drm_crtc *crtc, struct drm_crtc_state *state) { @@ -765,13 +781,14 @@ static int _dpu_crtc_check_and_setup_lm_bounds(struct drm_crtc *crtc, struct drm_display_mode *adj_mode = &state->adjusted_mode; u32 crtc_split_width = adj_mode->hdisplay / cstate->num_mixers; struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); + int max_pingpong_width = msm_display_get_max_pingpong_width(dpu_kms); int i; /* if we cannot merge 2 LMs (no 3d mux) better to fail earlier * before even checking the width after the split */ if (!dpu_kms->catalog->caps->has_3d_merge && - adj_mode->hdisplay > dpu_kms->catalog->caps->max_mixer_width) + adj_mode->hdisplay > max_pingpong_width) return -E2BIG; for (i = 0; i < cstate->num_mixers; i++) { @@ -783,7 +800,7 @@ static int _dpu_crtc_check_and_setup_lm_bounds(struct drm_crtc *crtc, trace_dpu_crtc_setup_lm_bounds(DRMID(crtc), i, r); - if (drm_rect_width(r) > dpu_kms->catalog->caps->max_mixer_width) + if (drm_rect_width(r) > max_pingpong_width) return -E2BIG; } @@ -1374,17 +1391,17 @@ static int dpu_crtc_reassign_planes(struct drm_crtc *crtc, struct drm_crtc_state } #define MAX_CHANNELS_PER_CRTC PIPES_PER_PLANE -#define MAX_HDISPLAY_SPLIT 1080 static u32 dpu_crtc_num_lm_for_mode(struct dpu_kms *dpu_kms, - const struct drm_display_mode *mode) + const struct drm_display_mode *mode, + u32 max_hdisplay_split) { u64 mode_clk; if (!dpu_kms->catalog->caps->has_3d_merge) return 1; - if (mode->hdisplay > MAX_HDISPLAY_SPLIT) + if (mode->hdisplay > max_hdisplay_split) return 2; mode_clk = dpu_core_perf_adjusted_mode_clk(mode->clock, @@ -1403,6 +1420,7 @@ static struct msm_display_topology dpu_crtc_get_topology( struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct msm_display_topology topology = {0}; struct drm_encoder *drm_enc; + u32 max_hdisplay_split; drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state, @@ -1410,6 +1428,19 @@ static struct msm_display_topology dpu_crtc_get_topology( topology.cwb_enabled = drm_crtc_in_clone_mode(crtc_state); + max_hdisplay_split = msm_display_get_max_pingpong_width(dpu_kms); + + if (topology.num_dsc > 0) { + u32 max_dsc_encoder_width; + + if (dpu_kms->catalog->mdss_ver->core_major_ver < 6) + max_dsc_encoder_width = DPU_1_x_MAX_DSC_ENCODER_WIDTH; + else + max_dsc_encoder_width = DPU_8_x_MAX_DSC_ENCODER_WIDTH; + + max_hdisplay_split = min(max_hdisplay_split, max_dsc_encoder_width); + } + /* * Datapath topology selection * @@ -1438,7 +1469,8 @@ static struct msm_display_topology dpu_crtc_get_topology( topology.num_lm = 2; else if (dpu_kms->catalog->caps->has_3d_merge && topology.num_dsc == 0) - topology.num_lm = dpu_crtc_num_lm_for_mode(dpu_kms, mode); + topology.num_lm = dpu_crtc_num_lm_for_mode(dpu_kms, mode, + max_hdisplay_split); else topology.num_lm = 1; @@ -1619,19 +1651,21 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *mode) { struct dpu_kms *dpu_kms = _dpu_crtc_get_kms(crtc); + int max_pingpong_width = msm_display_get_max_pingpong_width(dpu_kms); u64 adjusted_mode_clk; /* if there is no 3d_mux block we cannot merge LMs so we cannot * split the large layer into 2 LMs, filter out such modes */ if (!dpu_kms->catalog->caps->has_3d_merge && - mode->hdisplay > dpu_kms->catalog->caps->max_mixer_width) + mode->hdisplay > max_pingpong_width) return MODE_BAD_HVALUE; adjusted_mode_clk = dpu_core_perf_adjusted_mode_clk(mode->clock, dpu_kms->perf.perf_cfg); - adjusted_mode_clk /= dpu_crtc_num_lm_for_mode(dpu_kms, mode); + adjusted_mode_clk /= dpu_crtc_num_lm_for_mode(dpu_kms, mode, + max_pingpong_width); /* * The given mode, adjusted for the perf clock factor, should not exceed @@ -1641,10 +1675,10 @@ static enum drm_mode_status dpu_crtc_mode_valid(struct drm_crtc *crtc, return MODE_CLOCK_HIGH; /* - * max crtc width is equal to the max mixer width * 2 and max height is 4K + * max crtc width is equal to the max pingpong width * 2 and max height is 4K */ return drm_mode_validate_size(mode, - 2 * dpu_kms->catalog->caps->max_mixer_width, + 2 * max_pingpong_width, 4096); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index f45faf87333e..71e1a404e25f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -24,6 +24,13 @@ #define DPU_MAX_IMG_WIDTH 0x3fff #define DPU_MAX_IMG_HEIGHT 0x3fff +#define DPU_1_x_MAX_PINGPONG_WIDTH 4096 +#define DPU_6_x_MAX_PINGPONG_WIDTH 5120 +#define DPU_8_x_MAX_PINGPONG_0_WIDTH 8960 + +#define DPU_1_x_MAX_DSC_ENCODER_WIDTH 2048 +#define DPU_8_x_MAX_DSC_ENCODER_WIDTH 2560 + #define CRTC_DUAL_MIXERS 2 #define MAX_XIN_COUNT 16 -- 2.34.1
