From nobody Fri Apr 3 00:00:52 2026 Received: from mail-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4ACFB2FFDDE for ; Thu, 12 Mar 2026 08:28:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773304130; cv=none; b=mCe8764V3aN1Jv8YUwCDr5ZiIcWgLtB1nvJ8HTHWvAy/4FvOYiZrVUGGfiRfBzaa5pKCvh3K3q6FK0X4ej7j5SnXU3TG4ow0speWSHl+hKxddsJPtzQHABuNg1Pf8X+mm7U+joiBZgEUVY6Lx7flWQ4DsYOqwlPAOZhDpUcB9OE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773304130; c=relaxed/simple; bh=mLiQ8kq+Hoe6yZbmNWCYHtVl5NbNfCazswthJQplHr8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=EcHZwRZrehIRxuM5/takAiab5KdUauGfcme88Ca7DQkrL7P+HUszbP5GFCLLMeZbOe/eFoquDaUfKmCruSrG9FkdVLb0INc98zLjIZSZs+McXUzQB2dLPA67LE5/mfZ1uufqojOzeBnbs3s3NEtPNvHg8B6XI75ApBd0YB0AxKg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=VHNszzxe; arc=none smtp.client-ip=209.85.221.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="VHNszzxe" Received: by mail-wr1-f43.google.com with SMTP id ffacd0b85a97d-439c944bb62so536586f8f.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=vger.kernel.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=VHNszzxeY/kQ1IOlq99kU4kV/h6dWZYvRUCDPUb5P1nLg2/4WF3xH9ik+9IjMxoEag cjc08eVzVmoDAx6lSChDB4a9L20XnmnqQVEt1USmAwd823heZgJOdk0saGEZ8VAQSdBV Bz7dFxFEUKx8sHJfSuddoBveoS1QAIEY0eFwxlQtQcJkgIICBgjCBbYUNf8jDcPZgvma ihL1GZJIATBr5BdO66seTlUWyKL1b9dnbuDUZYnNK2tNNZPY3achvtVXY/rcRY3gtJu8 z+UtQHm9ObZcQk+Qf1jh2kLvPacdMMoejjI/gtxVtByQMZpjvb0XDB6NbMTHyaJ4k5LU CRbA== 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=UI9btq5PMV/E1ikHX8HY8bIRQ2YcveIaq2CDHb9E8eJ7FzmOtl7RGMUmVG1Qx1yCao wqry+X3Uj1ECNgR57BCAjWZKLt5l8Oaqe9Y4Vtdn7ESP/PfytrKJxFmF5CZzlN5enzN5 7bVqwGPYde9ymqNxnsYzRJxXgcKMsyOABWlvwZerS17F7lqTPGPlvEP6p3gEAqkSzjHs nthQkPpvKXed8io2WuH0Wl/nupaKJKTy+w/HYZzVrhribUNAKo8d2+gqCuxhzS9+paY5 nOYx+O9srdEbuDUzqRrXif0a7SH3FjQt1RnfUojZyhK+dayNjUBZ7/iXsPKaize6dgqt f5Ng== X-Forwarded-Encrypted: i=1; AJvYcCUSiq6rW9mgUea2ePaqreJbhG/o7Pfbm1MQ3duLSFW4uzU+5BFy3r9dCTdfqqNwFzHNAlIdkmi72NRPDaY=@vger.kernel.org X-Gm-Message-State: AOJu0YxWO9ViZut1wdibn6ImO5py6XFFZqQmUlhTzevsRdcntaReDUBQ p/3R9fIwQ7vS84pOKLvEt88EbWRRoHH1tuE9FnhfkY0khwQ7WIMRjXl31pH7KdAkHYA= X-Gm-Gg: ATEYQzwBxfw9g7MFQRoY2ZDCBwGv8E5rneRCu1sFC+4hqSJbgODqw5J5RprJBOQd0sL UNT+B6hsrV80YIJzSAo96Num3X1ISCF2xcZzJ3iuQ1cj+bTh9LHUHLIne35BxJeqXfCKjap6gVr gsYVaSrDmKAI17Y9CRpmzdlaoDWXO3G2rHTR05bDb5HuY4aAXtKH1J8EWphRZMMy06RnCpMnd0M 4LPGaXvpaiCBp4dkn7U92zw70vTRD86MGJP+i5KUpdrxNpim7oCjEUEFoO1XJmcJCLmMc12mLSh jWWYGCpEu1WixUksLYO16ZvRH9n0iJhJLwq3zdbgrD50JsQKdmaLbebBsch3T3YdHhElvgmsVOJ 1YDYWzWmS9cfzcANweQPpqexv87P0BEWXXTQrnU/0UMmSz2DQvYCyNZrDjbrfx1PRBDDSY2QNCL YwNac= 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 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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= 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; } =20 +/** + * 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 =3D 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_cl= ient_type( =20 void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); =20 +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/ms= m/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 =3D 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 =3D &crtc_state->adjusted_mode; uint32_t max_linewidth; + u32 num_lm; + int stage_id, num_stages; =20 - /* move the assignment here, to ease handling to another pairs later */ - pipe_cfg =3D &pstate->pipe_cfg[0]; - r_pipe_cfg =3D &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 =3D pdpu->catalog->caps->max_linewidth; =20 - pipe_cfg->dst_rect =3D new_plane_state->dst; + /* In non-virtual plane case, one mixer pair is always needed. */ + num_lm =3D dpu_crtc_get_num_lm(crtc_state); + if (dpu_use_virtual_planes) + num_stages =3D (num_lm + 1) / 2; + else + num_stages =3D 1; =20 - max_linewidth =3D 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 =3D 0; stage_id < num_stages; stage_id++) { + struct drm_rect mixer_rect =3D { + .x1 =3D stage_id * mode->hdisplay / num_stages, + .y1 =3D 0, + .x2 =3D (stage_id + 1) * mode->hdisplay / num_stages, + .y2 =3D mode->vdisplay + }; + int cfg_idx =3D stage_id * PIPES_PER_STAGE; =20 - drm_rect_rotate(&pipe_cfg->src_rect, - new_plane_state->fb->width, new_plane_state->fb->height, - new_plane_state->rotation); + pipe_cfg =3D &pstate->pipe_cfg[cfg_idx]; + r_pipe_cfg =3D &pstate->pipe_cfg[cfg_idx + 1]; =20 - 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 =3D 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; } =20 - *r_pipe_cfg =3D *pipe_cfg; - pipe_cfg->src_rect.x2 =3D (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2= ) >> 1; - pipe_cfg->dst_rect.x2 =3D (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2= ) >> 1; - r_pipe_cfg->src_rect.x1 =3D pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 =3D pipe_cfg->dst_rect.x2; - } else { - memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); - } + pipe_cfg->dst_rect.x1 -=3D mixer_rect.x1; + pipe_cfg->dst_rect.x2 -=3D 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 =3D (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x= 2) >> 1; + pipe_cfg->dst_rect.x2 =3D (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x= 2) >> 1; + r_pipe_cfg->src_rect.x1 =3D pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 =3D 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)); + } =20 - 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) !=3D 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); =20 + if (drm_rect_width(&r_pipe_cfg->src_rect) !=3D 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; } =20 @@ -995,20 +1059,18 @@ static int dpu_plane_atomic_check_sspp(struct drm_pl= ane *plane, drm_atomic_get_new_plane_state(state, plane); struct dpu_plane *pdpu =3D to_dpu_plane(plane); struct dpu_plane_state *pstate =3D to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe =3D &pstate->pipe[0]; - struct dpu_sw_pipe *r_pipe =3D &pstate->pipe[1]; - struct dpu_sw_pipe_cfg *pipe_cfg =3D &pstate->pipe_cfg[0]; - struct dpu_sw_pipe_cfg *r_pipe_cfg =3D &pstate->pipe_cfg[1]; - int ret =3D 0; =20 - ret =3D 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 =3D 0, i; =20 - if (drm_rect_width(&r_pipe_cfg->src_rect) !=3D 0) { - ret =3D dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, + for (i =3D 0; i < PIPES_PER_PLANE; i++) { + pipe =3D &pstate->pipe[i]; + pipe_cfg =3D &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 =3D dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) --=20 2.43.0