It is possible to use multirect feature and split source to use the SSPP to output two consecutive rectangles. This commit brings in this capability to support wider screen resolutions. Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 19 +++- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 127 +++++++++++++++++++--- drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h | 4 + 3 files changed, 133 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 217a8112f1a2..90b406e409d3 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -481,6 +481,15 @@ static void _dpu_crtc_blend_setup_mixer(struct drm_crtc *crtc, format, fb ? fb->modifier : 0, &pstate->pipe, 0, stage_cfg); + if (pstate->r_pipe.sspp) { + set_bit(pstate->r_pipe.sspp->idx, fetch_active); + _dpu_crtc_blend_setup_pipe(crtc, plane, + mixer, cstate->num_mixers, + pstate->stage, + format, fb ? fb->modifier : 0, + &pstate->r_pipe, 1, stage_cfg); + } + /* blend config update */ for (lm_idx = 0; lm_idx < cstate->num_mixers; lm_idx++) { _dpu_crtc_setup_blend_cfg(mixer + lm_idx, pstate, format); @@ -1341,10 +1350,16 @@ static int _dpu_debugfs_status_show(struct seq_file *s, void *data) seq_printf(s, "\tdst x:%4d dst_y:%4d dst_w:%4d dst_h:%4d\n", state->crtc_x, state->crtc_y, state->crtc_w, state->crtc_h); - seq_printf(s, "\tsspp:%s\n", + seq_printf(s, "\tsspp[0]:%s\n", pstate->pipe.sspp->cap->name); - seq_printf(s, "\tmultirect: mode: %d index: %d\n", + seq_printf(s, "\tmultirect[0]: mode: %d index: %d\n", pstate->pipe.multirect_mode, pstate->pipe.multirect_index); + if (pstate->r_pipe.sspp) { + seq_printf(s, "\tsspp[1]:%s\n", + pstate->r_pipe.sspp->cap->name); + seq_printf(s, "\tmultirect[1]: mode: %d index: %d\n", + pstate->r_pipe.multirect_mode, pstate->r_pipe.multirect_index); + } seq_puts(s, "\n"); } diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index f52120b05b6e..494c1144075a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -701,6 +701,10 @@ static void _dpu_plane_color_fill(struct dpu_plane *pdpu, /* update sspp */ _dpu_plane_color_fill_pipe(pstate, &pstate->pipe, &pstate->pipe_cfg.dst_rect, fill_color, fmt); + + if (pstate->r_pipe.sspp) + _dpu_plane_color_fill_pipe(pstate, &pstate->r_pipe, &pstate->r_pipe_cfg.dst_rect, + fill_color, fmt); } int dpu_plane_validate_multirect_v2(struct dpu_multirect_plane_states *plane) @@ -959,9 +963,12 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, int ret = 0, min_scale; struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); + struct dpu_sw_pipe *pipe = &pstate->pipe; + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; const struct drm_crtc_state *crtc_state = NULL; const struct dpu_format *fmt; struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; struct drm_rect fb_rect = { 0 }; uint32_t max_linewidth; unsigned int rotation; @@ -985,8 +992,11 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, if (!new_plane_state->visible) return 0; - pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO; - pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE; + pipe->multirect_index = DPU_SSPP_RECT_SOLO; + pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + r_pipe->sspp = NULL; pstate->stage = DPU_STAGE_0 + pstate->base.normalized_zpos; if (pstate->stage >= pdpu->catalog->caps->max_mixer_blendstages) { @@ -1016,21 +1026,58 @@ static int dpu_plane_atomic_check(struct drm_plane *plane, return -E2BIG; } + fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb)); + max_linewidth = pdpu->catalog->caps->max_linewidth; + if (DPU_FORMAT_IS_UBWC(fmt)) + max_linewidth /= 2; - /* check decimated source width */ if (drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; - } + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; + } - fmt = to_dpu_format(msm_framebuffer_format(new_plane_state->fb)); + /* + * FIXME: it's not possible to check if sourcesplit is supported, + * LMs is not assigned yet. It happens in dpu_encoder_virt_mode_set + */ + if (drm_rect_width(&pipe_cfg->src_rect) != drm_rect_width(&pipe_cfg->dst_rect) || + drm_rect_height(&pipe_cfg->src_rect) != drm_rect_height(&pipe_cfg->dst_rect) || + (!test_bit(DPU_SSPP_SMART_DMA_V1, &pipe->sspp->cap->features) && + !test_bit(DPU_SSPP_SMART_DMA_V2, &pipe->sspp->cap->features)) || + DPU_FORMAT_IS_YUV(fmt)) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u, can't use split source\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; + } + + /* Use multirect for wide plane. We do not support dynamic assignment of SSPPs, so we know the configuration. */ + pipe->multirect_index = DPU_SSPP_RECT_0; + pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; - ret = dpu_plane_atomic_check_pipe(pdpu, &pstate->pipe, pipe_cfg, fmt); + r_pipe->sspp = pipe->sspp; + r_pipe->multirect_index = DPU_SSPP_RECT_1; + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_PARALLEL; + + *r_pipe_cfg = *pipe_cfg; + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + } + + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, fmt); if (ret) return ret; + if (r_pipe->sspp) { + ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, fmt); + if (ret) + return ret; + } + supported_rotations = DRM_MODE_REFLECT_MASK | DRM_MODE_ROTATE_0; if (pipe_hw_caps->features & BIT(DPU_SSPP_INLINE_ROTATION)) @@ -1097,8 +1144,10 @@ void dpu_plane_flush(struct drm_plane *plane) else if (pdpu->color_fill & DPU_PLANE_COLOR_FILL_FLAG) /* force 100% alpha */ _dpu_plane_color_fill(pdpu, pdpu->color_fill, 0xFF); - else + else { dpu_plane_flush_csc(pdpu, &pstate->pipe); + dpu_plane_flush_csc(pdpu, &pstate->r_pipe); + } /* flag h/w flush complete */ if (plane->state) @@ -1210,13 +1259,14 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) struct drm_plane_state *state = plane->state; struct dpu_plane_state *pstate = to_dpu_plane_state(state); struct dpu_sw_pipe *pipe = &pstate->pipe; + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; struct drm_crtc *crtc = state->crtc; struct drm_framebuffer *fb = state->fb; bool is_rt_pipe; const struct dpu_format *fmt = to_dpu_format(msm_framebuffer_format(fb)); struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; - + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; struct dpu_kms *kms = _dpu_plane_get_kms(&pdpu->base); struct msm_gem_address_space *aspace = kms->base.aspace; struct dpu_hw_fmt_layout layout; @@ -1244,6 +1294,12 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) drm_mode_vrefresh(&crtc->mode), layout_valid ? &layout : NULL); + if (r_pipe->sspp) { + dpu_plane_sspp_update_pipe(plane, r_pipe, r_pipe_cfg, fmt, + drm_mode_vrefresh(&crtc->mode), + layout_valid ? &layout : NULL); + } + if (pstate->needs_qos_remap) pstate->needs_qos_remap = false; @@ -1251,16 +1307,31 @@ static void dpu_plane_sspp_atomic_update(struct drm_plane *plane) &crtc->mode, pipe_cfg); pstate->plane_clk = _dpu_plane_calc_clk(&crtc->mode, pipe_cfg); + + if (r_pipe->sspp) { + pstate->plane_fetch_bw += _dpu_plane_calc_bw(pdpu->catalog, fmt, &crtc->mode, r_pipe_cfg); + + pstate->plane_clk = max(pstate->plane_clk, _dpu_plane_calc_clk(&crtc->mode, r_pipe_cfg)); + } } static void _dpu_plane_atomic_disable(struct drm_plane *plane) { struct drm_plane_state *state = plane->state; struct dpu_plane_state *pstate = to_dpu_plane_state(state); + struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; trace_dpu_plane_disable(DRMID(plane), false, pstate->pipe.multirect_mode); + if (r_pipe->sspp) { + r_pipe->multirect_index = DPU_SSPP_RECT_SOLO; + r_pipe->multirect_mode = DPU_SSPP_MULTIRECT_NONE; + + if (r_pipe->sspp->ops.setup_multirect) + r_pipe->sspp->ops.setup_multirect(r_pipe); + } + pstate->pending = true; } @@ -1293,6 +1364,9 @@ static void dpu_plane_destroy(struct drm_plane *plane) pstate = to_dpu_plane_state(plane->state); _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, false, DPU_PLANE_QOS_PANIC_CTRL); + if (pstate->r_pipe.sspp) + _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, false, DPU_PLANE_QOS_PANIC_CTRL); + mutex_destroy(&pdpu->lock); /* this will destroy the states as well */ @@ -1373,12 +1447,29 @@ static void dpu_plane_atomic_print_state(struct drm_printer *p, const struct drm_plane_state *state) { const struct dpu_plane_state *pstate = to_dpu_plane_state(state); + const struct dpu_sw_pipe *pipe = &pstate->pipe; + const struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg; + const struct dpu_sw_pipe *r_pipe = &pstate->r_pipe; + const struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->r_pipe_cfg; drm_printf(p, "\tstage=%d\n", pstate->stage); - drm_printf(p, "\tsspp=%s\n", pstate->pipe.sspp->cap->name); - drm_printf(p, "\tmultirect_mode=%s\n", dpu_get_multirect_mode(pstate->pipe.multirect_mode)); - drm_printf(p, "\tmultirect_index=%s\n", - dpu_get_multirect_index(pstate->pipe.multirect_index)); + + drm_printf(p, "\tsspp[0]=%s\n", pipe->sspp->cap->name); + drm_printf(p, "\tmultirect_mode[0]=%s\n", dpu_get_multirect_mode(pipe->multirect_mode)); + drm_printf(p, "\tmultirect_index[0]=%s\n", + dpu_get_multirect_index(pipe->multirect_index)); + drm_printf(p, "\tsrc[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->src_rect)); + drm_printf(p, "\tdst[0]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&pipe_cfg->dst_rect)); + + if (r_pipe->sspp) { + drm_printf(p, "\tsspp[1]=%s\n", r_pipe->sspp->cap->name); + drm_printf(p, "\tmultirect_mode[1]=%s\n", + dpu_get_multirect_mode(r_pipe->multirect_mode)); + drm_printf(p, "\tmultirect_index[1]=%s\n", + dpu_get_multirect_index(r_pipe->multirect_index)); + drm_printf(p, "\tsrc[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->src_rect)); + drm_printf(p, "\tdst[1]=" DRM_RECT_FMT "\n", DRM_RECT_ARG(&r_pipe_cfg->dst_rect)); + } } static void dpu_plane_reset(struct drm_plane *plane) @@ -1412,6 +1503,10 @@ static void dpu_plane_reset(struct drm_plane *plane) * This is the place where the state is allocated, so fill it fully. */ pstate->pipe.sspp = dpu_rm_get_sspp(&dpu_kms->rm, pdpu->pipe); + pstate->pipe.multirect_index = DPU_SSPP_RECT_SOLO; + pstate->pipe.multirect_mode = DPU_SSPP_MULTIRECT_NONE; + + pstate->r_pipe.sspp = NULL; __drm_atomic_helper_plane_reset(plane, &pstate->base); } @@ -1428,6 +1523,8 @@ void dpu_plane_danger_signal_ctrl(struct drm_plane *plane, bool enable) pm_runtime_get_sync(&dpu_kms->pdev->dev); _dpu_plane_set_qos_ctrl(plane, &pstate->pipe, enable, DPU_PLANE_QOS_PANIC_CTRL); + if (pstate->r_pipe.sspp) + _dpu_plane_set_qos_ctrl(plane, &pstate->r_pipe, enable, DPU_PLANE_QOS_PANIC_CTRL); pm_runtime_put_sync(&dpu_kms->pdev->dev); } #endif diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h index 0ca9002015ff..7490ffd94d03 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.h @@ -19,7 +19,9 @@ * @base: base drm plane state object * @aspace: pointer to address space for input/output buffers * @pipe: software pipe description + * @r_pipe: software pipe description of the second pipe * @pipe_cfg: software pipe configuration + * @r_pipe_cfg: software pipe configuration for the second pipe * @stage: assigned by crtc blender * @needs_qos_remap: qos remap settings need to be updated * @multirect_index: index of the rectangle of SSPP @@ -34,7 +36,9 @@ struct dpu_plane_state { struct drm_plane_state base; struct msm_gem_address_space *aspace; struct dpu_sw_pipe pipe; + struct dpu_sw_pipe r_pipe; struct dpu_sw_pipe_cfg pipe_cfg; + struct dpu_sw_pipe_cfg r_pipe_cfg; enum dpu_stage stage; bool needs_qos_remap; bool pending; -- 2.30.2