Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

drm/msm/dpu: support plane splitting in quad-pipe case

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 in quad-pipe case, thus a LM pair should not blend any content
that cross the half of screen in this case. Clip plane into pipes per
left and right half screen ROI if topology is quad pipe case.
The clipped rectangle on every half of screen is futher handled by two
pipes if its width exceeds a limit for a single pipe.

For non-virtual-plane case, there is always one stage config to serve
a LM or LM pair. So the clipping does not occur when interating stages
in this case. The plane is mapped to 2 pipes only when width or clock
rate exceeds hardware constrain within stage check.

Signed-off-by: Jun Nie <jun.nie@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/711324/
Link: https://lore.kernel.org/r/20260312-msm-next-quad-pipe-split-v19-3-4ffa2b06c996@linaro.org
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>

authored by

Jun Nie and committed by
Dmitry Baryshkov
9c171c36 25ee1092

+118 -43
+11
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c
··· 1667 1667 return 0; 1668 1668 } 1669 1669 1670 + /** 1671 + * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline 1672 + * @state: Pointer to drm crtc state object 1673 + */ 1674 + unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) 1675 + { 1676 + struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); 1677 + 1678 + return cstate->num_mixers; 1679 + } 1680 + 1670 1681 #ifdef CONFIG_DEBUG_FS 1671 1682 static int _dpu_debugfs_status_show(struct seq_file *s, void *data) 1672 1683 {
+2
drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h
··· 267 267 268 268 void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); 269 269 270 + unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); 271 + 270 272 #endif /* _DPU_CRTC_H_ */
+105 -43
drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c
··· 878 878 struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); 879 879 struct dpu_sw_pipe_cfg *pipe_cfg; 880 880 struct dpu_sw_pipe_cfg *r_pipe_cfg; 881 + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; 881 882 uint32_t max_linewidth; 882 - 883 - /* move the assignment here, to ease handling to another pairs later */ 884 - pipe_cfg = &pstate->pipe_cfg[0]; 885 - r_pipe_cfg = &pstate->pipe_cfg[1]; 886 - /* state->src is 16.16, src_rect is not */ 887 - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); 888 - 889 - pipe_cfg->dst_rect = new_plane_state->dst; 883 + u32 num_lm; 884 + int stage_id, num_stages; 890 885 891 886 max_linewidth = pdpu->catalog->caps->max_linewidth; 892 887 893 - drm_rect_rotate(&pipe_cfg->src_rect, 894 - new_plane_state->fb->width, new_plane_state->fb->height, 895 - new_plane_state->rotation); 888 + /* In non-virtual plane case, one mixer pair is always needed. */ 889 + num_lm = dpu_crtc_get_num_lm(crtc_state); 890 + if (dpu_use_virtual_planes) 891 + num_stages = (num_lm + 1) / 2; 892 + else 893 + num_stages = 1; 896 894 897 - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || 898 - _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { 899 - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { 900 - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", 901 - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); 902 - return -E2BIG; 895 + /* 896 + * For wide plane that exceeds SSPP rectangle constrain, it needed to 897 + * be split and mapped to 2 rectangles with 1 config for 2:2:1. 898 + * For 2 interfaces cases, such as dual DSI, 2:2:2 topology is needed. 899 + * If the width or clock exceeds hardware limitation in every half of 900 + * screen, 4:4:2 topology is needed and virtual plane feature should 901 + * be enabled to map plane to more than 1 SSPP. 2 stage configs are 902 + * needed to serve 2 mixer pairs in this 4:4:2 case. So both left/right 903 + * half of plane splitting, and splitting within the half of screen is 904 + * needed in quad-pipe case. Check dest rectangle left/right clipping 905 + * and iterate mixer configs for this plane first, then check wide 906 + * rectangle splitting in every half next. 907 + */ 908 + for (stage_id = 0; stage_id < num_stages; stage_id++) { 909 + struct drm_rect mixer_rect = { 910 + .x1 = stage_id * mode->hdisplay / num_stages, 911 + .y1 = 0, 912 + .x2 = (stage_id + 1) * mode->hdisplay / num_stages, 913 + .y2 = mode->vdisplay 914 + }; 915 + int cfg_idx = stage_id * PIPES_PER_STAGE; 916 + 917 + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; 918 + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; 919 + 920 + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); 921 + 922 + drm_rect_rotate(&pipe_cfg->src_rect, 923 + new_plane_state->fb->width, new_plane_state->fb->height, 924 + new_plane_state->rotation); 925 + 926 + pipe_cfg->dst_rect = new_plane_state->dst; 927 + 928 + DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT 929 + " vs clip window " DRM_RECT_FMT "\n", 930 + DRM_RECT_ARG(&pipe_cfg->src_rect), 931 + DRM_RECT_ARG(&mixer_rect)); 932 + 933 + /* 934 + * If this plane does not fall into mixer rect, check next 935 + * mixer rect. 936 + */ 937 + if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, 938 + &pipe_cfg->dst_rect, 939 + &mixer_rect)) { 940 + memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); 941 + 942 + continue; 903 943 } 904 944 905 - *r_pipe_cfg = *pipe_cfg; 906 - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; 907 - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; 908 - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; 909 - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; 910 - } else { 911 - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); 912 - } 945 + pipe_cfg->dst_rect.x1 -= mixer_rect.x1; 946 + pipe_cfg->dst_rect.x2 -= mixer_rect.x1; 913 947 914 - drm_rect_rotate_inv(&pipe_cfg->src_rect, 915 - new_plane_state->fb->width, new_plane_state->fb->height, 916 - new_plane_state->rotation); 917 - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) 918 - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, 919 - new_plane_state->fb->width, new_plane_state->fb->height, 948 + DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", 949 + DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); 950 + 951 + /* Split wide rect into 2 rect */ 952 + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || 953 + _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { 954 + 955 + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { 956 + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", 957 + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); 958 + return -E2BIG; 959 + } 960 + 961 + memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg)); 962 + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; 963 + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; 964 + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; 965 + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; 966 + DPU_DEBUG_PLANE(pdpu, "Split wide plane into:" 967 + DRM_RECT_FMT " and " DRM_RECT_FMT "\n", 968 + DRM_RECT_ARG(&pipe_cfg->src_rect), 969 + DRM_RECT_ARG(&r_pipe_cfg->src_rect)); 970 + } else { 971 + memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); 972 + } 973 + 974 + drm_rect_rotate_inv(&pipe_cfg->src_rect, 975 + new_plane_state->fb->width, 976 + new_plane_state->fb->height, 920 977 new_plane_state->rotation); 978 + 979 + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) 980 + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, 981 + new_plane_state->fb->width, 982 + new_plane_state->fb->height, 983 + new_plane_state->rotation); 984 + } 921 985 922 986 return 0; 923 987 } ··· 1056 992 drm_atomic_get_new_plane_state(state, plane); 1057 993 struct dpu_plane *pdpu = to_dpu_plane(plane); 1058 994 struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); 1059 - struct dpu_sw_pipe *pipe = &pstate->pipe[0]; 1060 - struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; 1061 - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; 1062 - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; 1063 - int ret = 0; 1064 995 1065 - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, 1066 - &crtc_state->adjusted_mode, 1067 - new_plane_state); 1068 - if (ret) 1069 - return ret; 996 + struct dpu_sw_pipe *pipe; 997 + struct dpu_sw_pipe_cfg *pipe_cfg; 998 + int ret = 0, i; 1070 999 1071 - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { 1072 - ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, 1000 + for (i = 0; i < PIPES_PER_PLANE; i++) { 1001 + pipe = &pstate->pipe[i]; 1002 + pipe_cfg = &pstate->pipe_cfg[i]; 1003 + if (!drm_rect_width(&pipe_cfg->src_rect)) 1004 + continue; 1005 + DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); 1006 + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, 1073 1007 &crtc_state->adjusted_mode, 1074 1008 new_plane_state); 1075 1009 if (ret)