From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 995EAFED2EE for ; Thu, 12 Mar 2026 08:28:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id F329710E9EE; Thu, 12 Mar 2026 08:28:49 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="GU6y28zq"; dkim-atps=neutral Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) by gabe.freedesktop.org (Postfix) with ESMTPS id 3DF3110EA0D for ; Thu, 12 Mar 2026 08:28:49 +0000 (UTC) Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-439c944bb62so536587f8f.3 for ; Thu, 12 Mar 2026 01:28:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1773304128; x=1773908928; darn=lists.freedesktop.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=gSlDLHNlq6yl671wwnnD9Z5eWz9U89VKuVstCERaaBI=; b=GU6y28zq9zVbAH4b6W2Ts6dqkzSpQ88VRRic1Qcpk/QgucxK1s4LDQGs3THMCIFt7p 3U0d4SN2q6tT8DgeNkfITQUcnAvFvqM3nDEVBPNIM22LaFelmkZMbroj6lZSXtEj+KHQ zUVz854f6a19GeYNmG4M1IK0xgnZP9nDhnbB4SOcVp2j6HZ/7WiTnobzzLg7PNlMSXx5 35wkHrqDMAttpoQ1csOlt74yY4MvRi10DLAV3oXK0qS811xDWlo2WlL+AjeGaH8eBQDK SVlZH8NGXqAXmcYkG8FexdvD8ni91Z7oWxPOryaWszek3vjias5yjWgH9ooPu7pGOURw PRCQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1773304128; x=1773908928; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=gSlDLHNlq6yl671wwnnD9Z5eWz9U89VKuVstCERaaBI=; b=AqFmLfkH0K41g9XeporNg4WOKCq3euzaOpldoGB/jsD7vNX9WIUZT/BqCLF1EW4u43 KS8qa1e4C05S1z0nagmPYXRi/q0kegpnoZPyeGr9NXXClcfiHpbvHIxKhaprImILLtVe QMKhg+GvQMgjIKqT+5CHwubz3ITij0NKxm/NyfIonz0c+qobCV2XNYdSfmvM+xhOQYIw LnBX/Dh7VtUC/KWh5lWKZfee5aEko2fL29VkDxJYzGpZtjsaN9OJsEBtprg7Zs5bX9oM GmHEafUGDvBICfAyV8fA4CigAJSyWXo1zWwFjeps6OZclMlyJKdDuxGSvW0WkSq45aaz LEqw== X-Forwarded-Encrypted: i=1; AJvYcCUwFWrqL8fMbIkm1uV+JH7s9rUxCatplwIErlbuwDBctq+37Xb7bPHYcQbswA68AaC95rsO363/5cI=@lists.freedesktop.org X-Gm-Message-State: AOJu0Yx+Vt+slwbPONeOKuUgW0wC+GujCltPKdNMK0oaBtDcS8wIcgf2 fP5KSxRnDrJuRUdReW3RIC46DlATGDdaBfSUMQk8zHajSpF1su7lb+bx1wfBTy2sAAg= X-Gm-Gg: ATEYQzxW5169sm/6kR5fYTMXKaC6NmYOUQ8lUCRszUjEp2/Ix9atlsXb2i6zwvCcAh7 Q6kWlhwYtiHmSQM5nQ40uy+LdBs83IJg2Qa17AyYI5S3G5M9NfD+Vbg30EaqNv3LWl5B6ebJCWv Y1rzH5CgwOKEGk2nsxWO/ulMymnfsPw61qGS7On+UsV/mWwWzBvg/GVoZqP/3fVtX7xp0jft0kD AXPvonwN51SxymgYtwRPaGxbYZdjlYUWfD5HvZIwCB1hMpLMGAHo9zjp01dNwrJ8bhSmqci1UOS qJc7QadHoREhPXp3LcFUjj1lxsQgkNqxOBqM0X0EZfJb2Er9s3Ixlx2MLu3gJ+jqvNXt+K33xqW AmnhDeFp9wsxb/qUU+X7O+EbZ7GnC6YO1ZtPsxetH4dzmeE9wFbJ++a5TT3CTWpWh+PMWnNYef6 AbWNs= X-Received: by 2002:a05:6000:1845:b0:439:bddb:cc77 with SMTP id ffacd0b85a97d-439f8206d14mr10016371f8f.37.1773304127586; Thu, 12 Mar 2026 01:28:47 -0700 (PDT) Received: from [127.0.1.1] ([2a04:6f00:1::ee:b:1015]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-439fe219c41sm6273780f8f.29.2026.03.12.01.28.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Mar 2026 01:28:47 -0700 (PDT) From: Jun Nie Date: Thu, 12 Mar 2026 16:28:12 +0800 Subject: [PATCH v19 3/4] drm/msm/dpu: support plane splitting in quad-pipe case MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260312-msm-next-quad-pipe-split-v19-3-4ffa2b06c996@linaro.org> References: <20260312-msm-next-quad-pipe-split-v19-0-4ffa2b06c996@linaro.org> In-Reply-To: <20260312-msm-next-quad-pipe-split-v19-0-4ffa2b06c996@linaro.org> To: Abhinav Kumar , Dmitry Baryshkov , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Rob Clark , Neil Armstrong Cc: linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org, Jun Nie , Dmitry Baryshkov X-Mailer: b4 0.13.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1773304094; l=9858; i=jun.nie@linaro.org; s=20240403; h=from:subject:message-id; bh=mLiQ8kq+Hoe6yZbmNWCYHtVl5NbNfCazswthJQplHr8=; b=nlNdoeoKyEe5V55uxhNPCqhFMeJERNVARzQlQpo4M6Jgn4L5oaCo6VwfPLjpw3tDo50O1rmuh StSTJ5qIrSIDS9J0uOcGAEIR8Bq0oignOMG8oMd3fJtRYKExLivcZi0 X-Developer-Key: i=jun.nie@linaro.org; a=ed25519; pk=MNiBt/faLPvo+iJoP1hodyY2x6ozVXL8QMptmsKg3cc= X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 Reviewed-by: Dmitry Baryshkov Reviewed-by: Jessica Zhang Patchwork: https://patchwork.freedesktop.org/patch/675416/ Link: https://lore.kernel.org/r/20250918-v6-16-rc2-quad-pipe-upstream-4-v16-9-ff6232e3472f@linaro.org Signed-off-by: Dmitry Baryshkov --- drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c | 11 +++ drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h | 2 + drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c | 146 +++++++++++++++++++++--------- 3 files changed, 117 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index e97456d4fbb8c..321fe13ee4eb0 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -1670,6 +1670,17 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } +/** + * 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) +{ + 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 94392b9b92454..6eaba5696e8e6 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -267,4 +267,6 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); +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_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index 70992a4401d69..5d83ff689de7c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -881,47 +881,111 @@ static int dpu_plane_split(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; + const struct drm_display_mode *mode = &crtc_state->adjusted_mode; uint32_t max_linewidth; + u32 num_lm; + int stage_id, num_stages; - /* 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); + max_linewidth = pdpu->catalog->caps->max_linewidth; - pipe_cfg->dst_rect = new_plane_state->dst; + /* In non-virtual plane case, one mixer pair is always needed. */ + num_lm = dpu_crtc_get_num_lm(crtc_state); + if (dpu_use_virtual_planes) + num_stages = (num_lm + 1) / 2; + else + num_stages = 1; - max_linewidth = pdpu->catalog->caps->max_linewidth; + /* + * For wide plane that exceeds SSPP rectangle constrain, it needed to + * be split and mapped to 2 rectangles with 1 config for 2:2:1. + * For 2 interfaces cases, such as dual DSI, 2:2:2 topology is needed. + * If the width or clock exceeds hardware limitation in every half of + * screen, 4:4:2 topology is needed and virtual plane feature should + * be enabled to map plane to more than 1 SSPP. 2 stage configs are + * needed to serve 2 mixer pairs in this 4:4:2 case. So both left/right + * half of plane splitting, and splitting within the half of screen is + * needed in quad-pipe case. Check dest rectangle left/right clipping + * and iterate mixer configs for this plane first, then check wide + * rectangle splitting in every half next. + */ + for (stage_id = 0; stage_id < num_stages; stage_id++) { + struct drm_rect mixer_rect = { + .x1 = stage_id * mode->hdisplay / num_stages, + .y1 = 0, + .x2 = (stage_id + 1) * mode->hdisplay / num_stages, + .y2 = mode->vdisplay + }; + int cfg_idx = stage_id * PIPES_PER_STAGE; - drm_rect_rotate(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); + pipe_cfg = &pstate->pipe_cfg[cfg_idx]; + r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; - 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; + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + + drm_rect_rotate(&pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + + 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)); + + 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->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 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; + DPU_DEBUG_PLANE(pdpu, "Split 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)); + } - 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, - new_plane_state->fb->width, new_plane_state->fb->height, + 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, + new_plane_state->fb->width, + new_plane_state->fb->height, + new_plane_state->rotation); + } + return 0; } @@ -995,20 +1059,18 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, drm_atomic_get_new_plane_state(state, plane); 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[0]; - struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; - struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; - struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; - int ret = 0; - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, - &crtc_state->adjusted_mode, - new_plane_state); - if (ret) - return ret; + struct dpu_sw_pipe *pipe; + struct dpu_sw_pipe_cfg *pipe_cfg; + int ret = 0, i; - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { - ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, + for (i = 0; i < PIPES_PER_PLANE; i++) { + pipe = &pstate->pipe[i]; + pipe_cfg = &pstate->pipe_cfg[i]; + if (!drm_rect_width(&pipe_cfg->src_rect)) + continue; + DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) -- 2.43.0