Message ID | 20241219-sm8650-v6-13-hmd-deckard-mdss-quad-upstream-32-v3-12-92c7c0a228e3@linaro.org |
---|---|
State | New |
Headers | show |
Series | drm/msm/dpu: Support quad pipe with dual-DSI | expand |
On Thu, Dec 19, 2024 at 03:49:30PM +0800, Jun Nie wrote: > The content of every half of screen is sent out via one interface in > dual-DSI case. The content for every interface is blended by a LM > pair, Only in case of the quad-pipe topology. > thus no content of any pipe shall cross the LM pair. You have swapped the cause and the consequence. > We need > to clip plane into pipes per left and right half screen ROI if topology > is quad pipe. > > The clipped rectangle on every half of screen will be split further > by half if its width still exceeds limit. > > Signed-off-by: Jun Nie <jun.nie@linaro.org> > --- > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 7 ++ > drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 6 ++ > drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 2 + > drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 108 +++++++++++++++++++++------- > 4 files changed, 97 insertions(+), 26 deletions(-) > > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > index 6ef7e6ed00238..bad75af4e50ab 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c > @@ -1363,6 +1363,13 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) > return 0; > } > > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) > +{ > + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); > + > + return cstate->num_mixers; > +} > + > #ifdef CONFIG_DEBUG_FS > static int _dpu_debugfs_status_show(struct seq_file *s, void *data) > { > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > index 0b148f3ce0d7a..d1bb3f84fe440 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h > @@ -264,4 +264,10 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( > > void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); > > +/** > + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline > + * state: Pointer to drm crtc state object > + */ Rewrite to be a proper kerneldoc, move it to the function body. > +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); > + > #endif /* _DPU_CRTC_H_ */ > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h > index 56a0edf2a57c6..39fe338e76691 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h > @@ -145,11 +145,13 @@ struct dpu_hw_pixel_ext { > * such as decimation, flip etc to program this field > * @dest_rect: destination ROI. > * @rotation: simplified drm rotation hint > + * @valid: notify that this pipe and config is in use > */ > struct dpu_sw_pipe_cfg { > struct drm_rect src_rect; > struct drm_rect dst_rect; > unsigned int rotation; > + bool valid; > }; > > /** > diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c > index 46c6b6126fe5c..fca6e609898a6 100644 > --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c > +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c > @@ -802,8 +802,14 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, > struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); > struct dpu_sw_pipe_cfg *pipe_cfg; > struct dpu_sw_pipe_cfg *r_pipe_cfg; > + struct dpu_sw_pipe *pipe; > + struct dpu_sw_pipe *r_pipe; > + struct dpu_sw_pipe_cfg init_pipe_cfg; > struct drm_rect fb_rect = { 0 }; > + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; > uint32_t max_linewidth; > + u32 num_lm; > + int stage_id, num_stages; > > min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); > max_scale = MAX_DOWNSCALE_RATIO << 16; > @@ -826,13 +832,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, > return -EINVAL; > } > > - /* move the assignment here, to ease handling to another pairs later */ > - pipe_cfg = &pstate->pipe_cfg[0]; > - r_pipe_cfg = &pstate->pipe_cfg[1]; > - /* state->src is 16.16, src_rect is not */ > - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); > + num_lm = dpu_crtc_get_num_lm(crtc_state); > > - pipe_cfg->dst_rect = new_plane_state->dst; > + /* state->src is 16.16, src_rect is not */ > + drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src); > > fb_rect.x2 = new_plane_state->fb->width; > fb_rect.y2 = new_plane_state->fb->height; > @@ -857,34 +860,87 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, > > max_linewidth = pdpu->catalog->caps->max_linewidth; > > - drm_rect_rotate(&pipe_cfg->src_rect, > + drm_rect_rotate(&init_pipe_cfg.src_rect, > new_plane_state->fb->width, new_plane_state->fb->height, > new_plane_state->rotation); > > - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || > - _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { > - 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; > + /* > + * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair > + * configs for left and right half screen in case of 4:4:2 topology. > + * But we may have 2 rect to split plane with 1 config for 2:2:1. > + * So need to handle super wide plane splitting, and plane on right half What is 'super wide'? > + * for quad-pipe case. Check dest rectangle left/right clipping > + * first, then check super wide rectangle splitting in every half next. > + */ > + num_stages = (num_lm + 1) / 2; > + /* iterate mixer configs for this plane, to separate left/right with the id */ > + for (stage_id = 0; stage_id < num_stages; stage_id++) { > + struct drm_rect mixer_rect = {stage_id * mode->hdisplay / num_stages, 0, > + (stage_id + 1) * mode->hdisplay / num_stages, > + mode->vdisplay}; > + int cfg_idx = stage_id * PIPES_PER_STAGE; > + > + pipe = &pstate->pipe[cfg_idx]; > + r_pipe = &pstate->pipe[cfg_idx + 1]; > + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; > + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; > + > + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); > + pipe_cfg->dst_rect = new_plane_state->dst; > + > + DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT > + " vs clip window " DRM_RECT_FMT "\n", > + DRM_RECT_ARG(&pipe_cfg->src_rect), > + DRM_RECT_ARG(&mixer_rect)); > + > + /* > + * If this plane does not fall into mixer rect, check next > + * mixer rect. > + */ > + if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, > + &pipe_cfg->dst_rect, > + &mixer_rect)) { > + memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); > + memset(pipe, 0, 2 * sizeof(struct dpu_sw_pipe)); No need to memset, just set valid to false. Also it is incorrect to memset the pipe, you've just lost the pipe->sspp, which is set if the non-virtual implementation is in play. > + continue; > } > > - *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; > - } else { > - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); > - } > + pipe_cfg->valid = true; > + pipe_cfg->dst_rect.x1 -= mixer_rect.x1; > + pipe_cfg->dst_rect.x2 -= mixer_rect.x1; > + > + DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", > + DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); > + > + /* Split super wide rect into 2 rect */ Why is it super wide? Just wide. > + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || > + _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { > + > + 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; > + } > + > + memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_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; > + r_pipe_cfg->valid = true; > + DPU_DEBUG_PLANE(pdpu, "Split super wide plane into:" > + DRM_RECT_FMT " and " DRM_RECT_FMT "\n", > + DRM_RECT_ARG(&pipe_cfg->src_rect), > + DRM_RECT_ARG(&r_pipe_cfg->src_rect)); > + } else { > + memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); > + memset(r_pipe, 0, sizeof(struct dpu_sw_pipe)); Again, drop the memsets. > + } > > - drm_rect_rotate_inv(&pipe_cfg->src_rect, > - new_plane_state->fb->width, new_plane_state->fb->height, > - new_plane_state->rotation); > - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) > - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, > + drm_rect_rotate_inv(&pipe_cfg->src_rect, > new_plane_state->fb->width, new_plane_state->fb->height, > new_plane_state->rotation); You've dropped the rotation of the right rectangle. Why? > + } > > pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); > > > -- > 2.34.1 >
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index 6ef7e6ed00238..bad75af4e50ab 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1363,6 +1363,13 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) +{ + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); + + return cstate->num_mixers; +} + #ifdef CONFIG_DEBUG_FS static int _dpu_debugfs_status_show(struct seq_file *s, void *data) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 0b148f3ce0d7a..d1bb3f84fe440 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -264,4 +264,10 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); +/** + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline + * state: Pointer to drm crtc state object + */ +unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); + #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index 56a0edf2a57c6..39fe338e76691 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -145,11 +145,13 @@ struct dpu_hw_pixel_ext { * such as decimation, flip etc to program this field * @dest_rect: destination ROI. * @rotation: simplified drm rotation hint + * @valid: notify that this pipe and config is in use */ struct dpu_sw_pipe_cfg { struct drm_rect src_rect; struct drm_rect dst_rect; unsigned int rotation; + bool valid; }; /** diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 46c6b6126fe5c..fca6e609898a6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -802,8 +802,14 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_sw_pipe_cfg *pipe_cfg; struct dpu_sw_pipe_cfg *r_pipe_cfg; + struct dpu_sw_pipe *pipe; + struct dpu_sw_pipe *r_pipe; + struct dpu_sw_pipe_cfg init_pipe_cfg; struct drm_rect fb_rect = { 0 }; + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; uint32_t max_linewidth; + u32 num_lm; + int stage_id, num_stages; min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); max_scale = MAX_DOWNSCALE_RATIO << 16; @@ -826,13 +832,10 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } - /* move the assignment here, to ease handling to another pairs later */ - pipe_cfg = &pstate->pipe_cfg[0]; - r_pipe_cfg = &pstate->pipe_cfg[1]; - /* state->src is 16.16, src_rect is not */ - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + num_lm = dpu_crtc_get_num_lm(crtc_state); - pipe_cfg->dst_rect = new_plane_state->dst; + /* state->src is 16.16, src_rect is not */ + drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src); fb_rect.x2 = new_plane_state->fb->width; fb_rect.y2 = new_plane_state->fb->height; @@ -857,34 +860,87 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - drm_rect_rotate(&pipe_cfg->src_rect, + drm_rect_rotate(&init_pipe_cfg.src_rect, new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || - _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { - 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; + /* + * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair + * configs for left and right half screen in case of 4:4:2 topology. + * But we may have 2 rect to split plane with 1 config for 2:2:1. + * So need to handle super wide plane splitting, and plane on right half + * for quad-pipe case. Check dest rectangle left/right clipping + * first, then check super wide rectangle splitting in every half next. + */ + num_stages = (num_lm + 1) / 2; + /* iterate mixer configs for this plane, to separate left/right with the id */ + for (stage_id = 0; stage_id < num_stages; stage_id++) { + struct drm_rect mixer_rect = {stage_id * mode->hdisplay / num_stages, 0, + (stage_id + 1) * mode->hdisplay / num_stages, + mode->vdisplay}; + int cfg_idx = stage_id * PIPES_PER_STAGE; + + pipe = &pstate->pipe[cfg_idx]; + r_pipe = &pstate->pipe[cfg_idx + 1]; + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; + + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + pipe_cfg->dst_rect = new_plane_state->dst; + + DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT + " vs clip window " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&mixer_rect)); + + /* + * If this plane does not fall into mixer rect, check next + * mixer rect. + */ + if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, + &pipe_cfg->dst_rect, + &mixer_rect)) { + memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); + memset(pipe, 0, 2 * sizeof(struct dpu_sw_pipe)); + continue; } - *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; - } else { - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); - } + pipe_cfg->valid = true; + pipe_cfg->dst_rect.x1 -= mixer_rect.x1; + pipe_cfg->dst_rect.x2 -= mixer_rect.x1; + + DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); + + /* Split super wide rect into 2 rect */ + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { + + 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; + } + + memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_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; + r_pipe_cfg->valid = true; + DPU_DEBUG_PLANE(pdpu, "Split super wide plane into:" + DRM_RECT_FMT " and " DRM_RECT_FMT "\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), + DRM_RECT_ARG(&r_pipe_cfg->src_rect)); + } else { + memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); + memset(r_pipe, 0, sizeof(struct dpu_sw_pipe)); + } - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + drm_rect_rotate_inv(&pipe_cfg->src_rect, new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); + } pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state);
The content of every half of screen is sent out via one interface in dual-DSI case. The content for every interface is blended by a LM pair, thus no content of any pipe shall cross the LM pair. We need to clip plane into pipes per left and right half screen ROI if topology is quad pipe. The clipped rectangle on every half of screen will be split further by half if its width still exceeds limit. Signed-off-by: Jun Nie <jun.nie@linaro.org> --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 7 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 6 ++ drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 108 +++++++++++++++++++++------- 4 files changed, 97 insertions(+), 26 deletions(-)