From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=205.220.180.131 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794286565; b=GEKT6YNAbfPPV4XUctEN/3vR0laMS60xf33iNQbt+deE1+vwUZdp4S3iUPk9FHZlP2q7 QD1uWjfUMQrABrz7vh45ZdSjFOT/CKVC40FZrVsFFbNGDheVtD8cTw7O6kG0Lb12ayhzH EadgU3yEtWnrKCFKVcqoL4qGUtcvH3r7cZOtFKVVbsLEgTuup+X3kIbUZEm7fSt5H51NZ mwdF6Nn2PcVIosVUMdCSwW7S1MHAH2RyDZ4QibxFBrd9IAsuY3CgTEdDJtbkN7UeWJaRf ZejbGx42w6330F4U1j9EjENQJsCoXy5jp8hxY1nRNLMmNRhT2j65HTiyd/M7qQ5MRaA== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794286565; h=DMARC-Filter:Received:DKIM-Signature:Received:Received: DKIM-Signature:X-Google-DKIM-Signature:X-Forwarded-Encrypted: X-Gm-Message-State:X-Gm-Gg:X-Received:X-Received:Received:From:Date: Subject:MIME-Version:Content-Type:Content-Transfer-Encoding: Message-Id:References:In-Reply-To:To:Cc:X-Mailer: X-Developer-Signature:X-Developer-Key:X-Authority-Analysis: X-Proofpoint-GUID:X-Proofpoint-ORIG-GUID:X-Proofpoint-Spam-Info: X-Proofpoint-Spam-Details-Enc:X-Proofpoint-Virus-Version: X-Proofpoint-Spam-Details; bh=hvMgLa0MYW9wbki1F8tn6DWOHCXs9IbHwhX8WJ2OVcE=; b=Mn5I03Txt4QxrAVbIfJusb6a5GTjTb7IJgcUdd6HAvZ1kQNxUWCjhxlzuiJ0+/jnBYTB 8Ole3xHdxYv82KdBL606zcW1zFCs76pIdc1A+hF/J55UXt93ZV4rlFuELbyHqInHrlTa3 wcqUcTYywQhNDzWQqMvnlf5687yt+ESX9YF7YZqW+uvd8arPJwd+imKZFB8WHEDNixGTm Npsg+rue8hfLq9EeurD15VabkeVPtNL3HsVP7Ec+EUXYqs1rya4n5u0Ja2T1Rqcm2f+jv 21AP5vi1W4Bd1JxGGJVP3Rwmolkg1aq87ymYfkIk2fVcZPnmYnKMo5HG3eDxmXLaYww== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass header.d=qualcomm.com header.i=@qualcomm.com header.a=rsa-sha256 header.s=qcppdkim1 header.b=TQ1MsoRm; dkim=pass header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.a=rsa-sha256 header.s=google header.b=S5ZasiSa; arc=none smtp.remote-ip=205.220.180.131 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05B15606A335 for ; Tue, 10 Nov 2026 04:56:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org 05B15606A335 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.a=rsa-sha256 header.s=qcppdkim1 header.b=TQ1MsoRm; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.a=rsa-sha256 header.s=google header.b=S5ZasiSa Received: from pps.filterd (m0279871.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 6AA4AAMc2928603 for ; Tue, 10 Nov 2026 04:56:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=qcppdkim1; bh= hvMgLa0MYW9wbki1F8tn6DWOHCXs9IbHwhX8WJ2OVcE=; b=TQ1MsoRm61ZaPCbH LXhIkwGj/z9/UtquHGok3I1nE2F4IXw+MgA6q2mZBhGf+UakOKJ/ZP0auoVRKbEA KpZj9iaxgGx0ojjALAZ09GNkZ6h89i3oHjg/eQYnWRC7AweShxXIStU92VvKw47P w6lCxwRqwqUm8XJfY1y4+4xZHP0KpcXjsDuTKgxA2+tChiGzAk4lMDWh5KMpjb8H DR5KqfSm4hggix3/G0zRKT+BcYcW+zgTGTw4/lV66qVA7zPEjclvvoGg8DmMOQ/t plnnrpF/f/bSfrupRxFRoEtqapvf0YbJMMVsRbN84Os1PJ9tw7yww0E7m82kMhQ/ 0ftsGA== Received: from mail-qk1-f200.google.com (mail-qk1-f200.google.com [209.85.222.200]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4hufx830c6-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 10 Nov 2026 04:56:03 +0000 (GMT) Received: by mail-qk1-f200.google.com with SMTP id af79cd13be357-93f559420f3so185252985a.0 for ; Mon, 09 Nov 2026 20:56:03 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1794286563; x=1794891363; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=hvMgLa0MYW9wbki1F8tn6DWOHCXs9IbHwhX8WJ2OVcE=; b=S5ZasiSaEiQX5zAaaYKQaq7CD5FcmB+bBC/EiJMoaP8B0vUpkxJofmLQvNIvuCKQuP pq5jBiKmuYsaQNXzCiC0RLLLgw4LoGQY/UspdeKN9bHU/S9YIkSskZFwiGetwQDAATW6 mqcEngc+1LSu8ZXThWk8rJ9tKoSBtw1rKQLehyiI0ScdphcxiNmw/8PA6cHw4PDZQAt3 dNn1eRrbzVVNP71ci5kZX38MB/2T4+JHxTGtNtlXNahQVSw5GKznpN5X6f44qQNcYVfY FfqFkVnD5pqxUooKeIDCpUcD+izEwTpxOxe9mtx98Hq4vszyHd46yrK5QqfYD78udKyg uMBQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1794286563; x=1794891363; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=hvMgLa0MYW9wbki1F8tn6DWOHCXs9IbHwhX8WJ2OVcE=; b=bpZdAHB9oc5lOEMzAhWOIa75qj1WeX58SIyio/xC6gSGBwttN9nEuw6B08UbARr5ou qLsZLy/g7bYVEy5qh4ZLjDj50zXR2F8Apn4rcJOiStGPPqMjkyaic5u2w9BYZ5m+I1dZ 5CKLbFRPPe/S2POvZO610wByfPR/HF8hPJChgLoJSVoh4ME3vgq9737nQVzJ9kmzEwDR MXvyUVLZ90lDXupHJYrSI0m/qP6YN1cYsdtNI2WEnTrs22QVKNkxZsAKlNWaJJPctKgh MecjWMHqr+yBSu/THl2B/oR8SGP2EPs/tg30S3yG4P6MFqoGbkwfeHDwE6e3dfnDaIDI 3oRQ== X-Forwarded-Encrypted: i=1; AL+hErGXfCsSI2CUIQRj6gUx22/RwLk3DVU/zK6Ojyy77SiSCCkWKFgn+D/c87FTLFjVsI8AcKs4L2/hR4f0dAA=@vger.kernel.org X-Gm-Message-State: APuU4Z9pHkwoOnfEms3SjgvPJWk6QtBwrSrpaPdnl9iIm0seYhH7xd+l M9Xf5LpTOjAzAWCks8pYRK+e1ZED0a+iPVAOi1lMdxJRdheJc61JO3f03HBveL9M+dfM1uI8JgX DGcjbOKScP54wQJgS84uErkfeJnaZz0Kkhv3l0pee00qAWwRX3wXGinQisMOLyyksDo4= X-Gm-Gg: AYBFou0P+Pjn6VPuvlqAn/r8p2wPsaBeImfXDjxTk/DXDmH9Mx0nlJ0hBFPmAPesd9F t9VGrlhIkuBtsSvDEZCBUA0WgeFKMSVkQNwf5O7HQqJNNOYHI3iCM5UC9cjGxwpcbEiaB69Jc0A ENZ02FJF5yp+TbJmRT50mVt9nO2I3YMmjx3ILdaZKpl1ZpSPM0yA+kn5hNWa0YtwR4wVHq3gBzj fVUqpqmUXH7GJOHr8NSx8DKWWO+NoH6Ftl0UvgqTsd9zih84uPLmlL9T8FHJJCul9GBGBysZRtG 1RM8/xjc0/7hV95mgqVcAZxEVJcS2VMlC9mONXyuv6StMdp4ZWPf2L2fhTIRzU+Rz93NGkdKvG8 EV3B9SI+bJW+JpGSrAu7MGXcSMP1KffvPfT8uzrCAiS8x+ZffAN2QFGOCpiWwfKJqr+QmMZQAtk W6tEXVvwENxvoRg6/w36GOkKsGgIzOw5uu8zb1 X-Received: by 2002:a05:620a:370b:b0:944:9dd:b6 with SMTP id af79cd13be357-9479f38e472mr256312085a.80.1794286563138; Mon, 09 Nov 2026 20:56:03 -0800 (PST) X-Received: by 2002:a05:620a:370b:b0:944:9dd:b6 with SMTP id af79cd13be357-9479f38e472mr256308885a.80.1794286562592; Mon, 09 Nov 2026 20:56:02 -0800 (PST) Received: from yongmou2.ap.qualcomm.com (Global_NAT1_IAD_FW.qualcomm.com. [129.46.232.65]) by smtp.gmail.com with ESMTPSA id af79cd13be357-9479e73b2d2sm138653985a.10.2026.11.09.20.55.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 09 Nov 2026 20:56:02 -0800 (PST) From: Yongxing Mou Date: Tue, 10 Nov 2026 12:54:39 +0800 Subject: [PATCH v8 18/29] drm/msm/dp: add atomic stream handling for MST X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20261110-msm-dp-mst-v8-18-d040fb33db5f@oss.qualcomm.com> References: <20261110-msm-dp-mst-v8-0-d040fb33db5f@oss.qualcomm.com> In-Reply-To: <20261110-msm-dp-mst-v8-0-d040fb33db5f@oss.qualcomm.com> To: Rob Clark , Dmitry Baryshkov , Abhinav Kumar , Sean Paul , Marijn Suijten , David Airlie , Simona Vetter , Jessica Zhang Cc: linux-arm-msm@vger.kernel.org, dri-devel@lists.freedesktop.org, freedreno@lists.freedesktop.org, linux-kernel@vger.kernel.org, Yongxing Mou , Abhinav Kumar X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1794286469; l=17263; i=yongxing.mou@oss.qualcomm.com; s=20250910; h=from:subject:message-id; bh=bSy4akCHmwL0aCueMGp178tP2mownq/AFah6yYdVPa8=; b=UT7B2Fhivbh0gd3+jzG4IhnU1AhFDEnvrnos/InaWnCCl+o4h2U+DhyXwmdpPeGBENVZOAzj7 Cj2DYgfd+LLAa7Td6rhkeJ77pXD2irvYMkAmIAYO9oBIEH7GOeIoupg X-Developer-Key: i=yongxing.mou@oss.qualcomm.com; a=ed25519; pk=rAy5J1eP+V7OXqH5FJ7ngMCtUrnHhut30ZTldOj52UM= X-Authority-Analysis: v=2.4 cv=AbYkjHXG c=1 sm=1 tr=0 ts=6af2a3e4 cx=c_pps a=hnmNkyzTK/kJ09Xio7VxxA==:117 a=C3Dk8TwHQYyIj7nOf9RCJw==:17 a=IkcTkHD0fZMA:10 a=zJRp6_cAMcgA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=3WHJM1ZQz_JShphwDgj5:22 a=COk6AnOGAAAA:8 a=EUspDBNiAAAA:8 a=5XbiwH4P-ntBLZg0oosA:9 a=QEXdDO2ut3YA:10 a=PEH46H7Ffwr30OY-TuGO:22 a=TjNXssC_j7lpFel5tvFf:22 X-Proofpoint-GUID: I-ovWbGk55XJPPW_Ke-SnAben2ufA41O X-Proofpoint-ORIG-GUID: I-ovWbGk55XJPPW_Ke-SnAben2ufA41O X-Proofpoint-Spam-Info: AW1haW4tMjYxMTEwMDAxOSBTYWx0ZWRfX1M+i3b6512v6 prTQffY1OdHooAwnL/k0dc+n5iXHiiRyDGh0gnh+sJ0hsmmS3BX94TfTPYPCcznY74qvQYnN6QR 9RGioNE9DpCYIOuPNh320BsGGTxKSFQ= X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYxMTEwMDAxOSBTYWx0ZWRfX0XHlaM7V27iR a3+z8N3fDddBTAT7vo4UmhRhvcdTNw5sJm2sE3IFsRjRIZVQj3QBJPGgUcD///a1Yu2MI/Y2w// P28cDeZCysUgULPGjk0yCcggmeEqvuaMPIN+tWrOtouQnIrcs95ctUUM9RfnvJGs9ye13nb66Cf Vb6+PqZ3DzG8OKaxtDwxcsAtt4jyVQNcKcALBwsdq32T+GDY6NrDxYVWZ1YpxQazk/Plet+FfGP 8iNl77MRITbon1PsVQXR0U8uJ0eNZzm46GNzxa+tLvPoXIEv1C9VdpCMzRSkoZJefbaTpiQqDsR mE41JSADOw3IOzZI0asTbnmYpKaDBkG7+J5erpK5z9/OTLeY4Zy+a8DsrWv4U9X0YgEBfiFhMQ4 C/2TwUmnrzRYqyOulDnDVAVZuZnXvhp6YKWfL+FPMu1zV4FHWRK3V29XnnNJWWTawr6HoGADe1k eznO4ixkmsRMdcDUs0Q== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.138,FMLib:17.12.100.49 definitions=2026-11-10_02,2026-11-06_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 impostorscore=0 bulkscore=0 spamscore=0 clxscore=1015 adultscore=0 malwarescore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2611040001 definitions=main-2611100019 Add the atomic check, enable and disable operations for MST streams. Reserve VC payload bandwidth based on the negotiated link parameters, and update the MST payload when enabling or disabling each DP stream. Serialize stream updates that access the shared MST link state. Signed-off-by: Abhinav Kumar Signed-off-by: Yongxing Mou --- drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c | 11 ++ drivers/gpu/drm/msm/dp/dp_display.c | 45 +++++-- drivers/gpu/drm/msm/dp/dp_display.h | 7 +- drivers/gpu/drm/msm/dp/dp_mst_drm.c | 197 +++++++++++++++++++++++++++- drivers/gpu/drm/msm/dp/dp_mst_drm.h | 3 +- drivers/gpu/drm/msm/msm_drv.h | 20 +++ 6 files changed, 264 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index 802cb62fc010..edf30d7d3d16 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -2745,16 +2745,27 @@ static const struct drm_encoder_helper_funcs dpu_encoder_helper_funcs = { static void dpu_encoder_mst_atomic_enable(struct drm_encoder *enc, struct drm_atomic_commit *state) { + msm_dp_mst_stream_enable(enc, state); dpu_encoder_virt_atomic_enable(enc, state); } static void dpu_encoder_mst_atomic_disable(struct drm_encoder *enc, struct drm_atomic_commit *state) { + msm_dp_mst_stream_disable(enc, state); dpu_encoder_virt_atomic_disable(enc, state); + msm_dp_mst_stream_post_disable(enc, state); +} + +static int dpu_encoder_mst_atomic_check(struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + return msm_dp_mst_stream_atomic_check(enc, crtc_state, conn_state); } static const struct drm_encoder_helper_funcs dpu_mst_encoder_helper_funcs = { + .atomic_check = dpu_encoder_mst_atomic_check, .atomic_mode_set = dpu_encoder_virt_atomic_mode_set, .atomic_enable = dpu_encoder_mst_atomic_enable, .atomic_disable = dpu_encoder_mst_atomic_disable, diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c index 1d8eef466e79..af8d22fd4fc5 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ b/drivers/gpu/drm/msm/dp/dp_display.c @@ -457,6 +457,16 @@ static void msm_dp_display_handle_plugged_change(struct msm_dp *msm_dp_display, plugged); } +bool msm_dp_display_is_plugged(struct msm_dp *msm_dp_display) +{ + struct msm_dp_display_private *dp; + + dp = container_of(msm_dp_display, + struct msm_dp_display_private, msm_dp_display); + + return READ_ONCE(dp->plugged); +} + static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp) { struct platform_device *pdev = dp->msm_dp_display.pdev; @@ -1302,7 +1312,8 @@ int msm_dp_mst_register(struct msm_dp *msm_dp_display) dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - return msm_dp_mst_mgr_init(msm_dp_display, msm_dp_ctrl_get_stream_cnt(dp->ctrl), dp->aux); + return msm_dp_mst_mgr_init(msm_dp_display, dp->link, + msm_dp_ctrl_get_stream_cnt(dp->ctrl), dp->aux); } void msm_dp_mst_unregister(struct msm_dp *msm_dp_display) @@ -1564,28 +1575,34 @@ void msm_dp_display_atomic_pre_enable(struct msm_dp *msm_dp_display, DRM_ERROR("DP display prepare failed, rc=%d\n", rc); } -void msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, - struct msm_dp_panel *msm_dp_panel, - const struct msm_dp_mst_slot_info *slots) +int msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel, + const struct msm_dp_mst_slot_info *slots) { - int rc = 0; + int rc; struct msm_dp_display_private *dp; dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display); - if (msm_dp_display->link_ready) { - rc = msm_dp_display_enable(dp, msm_dp_panel, slots); - if (rc) - DRM_ERROR("DP display enable failed, rc=%d\n", rc); + if (!msm_dp_display->link_ready) + return -ENOLINK; - rc = msm_dp_display_post_enable(msm_dp_display); - if (rc) { - DRM_ERROR("DP display post enable failed, rc=%d\n", rc); - msm_dp_display_disable(dp, msm_dp_panel); - } + rc = msm_dp_display_enable(dp, msm_dp_panel, slots); + if (rc) { + DRM_ERROR("DP display enable failed, rc=%d\n", rc); + return rc; + } + + rc = msm_dp_display_post_enable(msm_dp_display); + if (rc) { + DRM_ERROR("DP display post enable failed, rc=%d\n", rc); + msm_dp_display_disable(dp, msm_dp_panel); + return rc; } drm_dbg_dp(msm_dp_display->drm_dev, "type=%d Done\n", msm_dp_display->connector_type); + + return 0; } void msm_dp_display_atomic_enable(struct msm_dp *msm_dp_display, diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h index 7b6d76f33ac6..62400547e01a 100644 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ b/drivers/gpu/drm/msm/dp/dp_display.h @@ -46,9 +46,9 @@ void msm_dp_display_atomic_enable(struct msm_dp *dp_display, enum drm_mode_status msm_dp_display_mode_valid(struct msm_dp *dp, const struct drm_display_info *info, const struct drm_display_mode *mode); -void msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, - struct msm_dp_panel *msm_dp_panel, - const struct msm_dp_mst_slot_info *slots); +int msm_dp_display_enable_helper(struct msm_dp *msm_dp_display, + struct msm_dp_panel *msm_dp_panel, + const struct msm_dp_mst_slot_info *slots); void msm_dp_display_disable_helper(struct msm_dp *msm_dp_display, struct msm_dp_panel *msm_dp_panel, const struct msm_dp_mst_slot_info *slots); @@ -66,4 +66,5 @@ int msm_dp_mst_register(struct msm_dp *msm_dp_display); void msm_dp_mst_unregister(struct msm_dp *msm_dp_display); struct msm_dp_panel *msm_dp_display_get_panel(struct msm_dp *msm_dp_display, enum msm_dp_stream_id stream_id); +bool msm_dp_display_is_plugged(struct msm_dp *msm_dp_display); #endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c b/drivers/gpu/drm/msm/dp/dp_mst_drm.c index ef5fb70863b8..eae82e857c84 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c @@ -31,8 +31,11 @@ struct msm_dp_mst { struct drm_dp_mst_topology_mgr mst_mgr; struct msm_dp_mst_encoder mst_encoders[DP_STREAM_MAX]; struct msm_dp *msm_dp; + struct msm_dp_link *link; struct drm_dp_aux *dp_aux; u32 max_streams; + /* Serializes concurrent stream link-state access across streams. */ + struct mutex mst_lock; }; static void dp_mst_connector_destroy(struct drm_connector *connector) @@ -135,6 +138,42 @@ static int msm_dp_mst_connector_atomic_check(struct drm_connector *connector, return drm_dp_atomic_release_time_slots(state, &mst->mst_mgr, mst_conn->mst_port); } +static struct msm_dp_panel *msm_dp_mst_panel_from_encoder(struct msm_dp_mst *mst, + struct drm_encoder *enc) +{ + int i; + + for (i = 0; i < mst->max_streams; i++) { + if (mst->mst_encoders[i].enc == enc) + return mst->mst_encoders[i].dp_panel; + } + return NULL; +} + +static void msm_dp_mst_collect_slots(struct msm_dp_mst *mst, + struct drm_dp_mst_topology_state *mst_state, + struct msm_dp_mst_slot_info *slots) +{ + int i; + + for (i = 0; i < mst->max_streams; i++) { + struct msm_dp_panel *dp_panel = mst->mst_encoders[i].dp_panel; + struct drm_dp_mst_atomic_payload *payload; + + if (!dp_panel->connector) + continue; + + payload = drm_atomic_get_mst_payload_state(mst_state, + to_dp_mst_connector(dp_panel->connector)->mst_port); + if (!payload || payload->vc_start_slot < 0) + continue; + + slots[dp_panel->stream_id].start_slot = payload->vc_start_slot; + slots[dp_panel->stream_id].tot_slots = payload->time_slots; + slots[dp_panel->stream_id].pbn = payload->pbn; + } +} + static int msm_dp_mst_encoder_stream_id(struct msm_dp_mst *mst, struct drm_encoder *enc) { @@ -147,6 +186,158 @@ static int msm_dp_mst_encoder_stream_id(struct msm_dp_mst *mst, return -1; } +void msm_dp_mst_stream_enable(struct drm_encoder *encoder, + struct drm_atomic_commit *state) +{ + struct drm_connector *connector = + drm_atomic_get_new_connector_for_encoder(state, encoder); + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp *dp_display = mst->msm_dp; + struct msm_dp_panel *panel = msm_dp_mst_panel_from_encoder(mst, encoder); + struct drm_dp_mst_port *port = mst_conn->mst_port; + struct drm_dp_mst_topology_state *mst_state = + drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr); + struct drm_dp_mst_atomic_payload *payload = + drm_atomic_get_mst_payload_state(mst_state, port); + struct msm_dp_mst_slot_info slots[DP_STREAM_MAX] = {}; + int rc; + + guard(mutex)(&mst->mst_lock); + + drm_connector_get(connector); + panel->connector = connector; + + rc = msm_dp_display_set_mode_helper(dp_display, state, encoder, panel); + if (rc) { + drm_err(dp_display->drm_dev, + "[MST] stream:%u set_mode failed rc=%d\n", panel->stream_id, rc); + return; + } + + rc = msm_dp_display_prepare_link(dp_display); + if (rc) { + drm_err(dp_display->drm_dev, + "[MST] stream:%u prepare_link failed rc=%d\n", panel->stream_id, rc); + return; + } + + drm_dp_mst_update_slots(mst_state, DP_CAP_ANSI_8B10B); + + rc = drm_dp_add_payload_part1(&mst->mst_mgr, mst_state, payload); + if (rc) + return; + + msm_dp_mst_collect_slots(mst, mst_state, slots); + + drm_dbg_kms(dp_display->drm_dev, + "[MST] stream:%u timeslots vc_start:%d slots:%d pbn:%d\n", + panel->stream_id, payload->vc_start_slot, + payload->time_slots, payload->pbn); + + rc = msm_dp_display_enable_helper(dp_display, panel, slots); + if (rc) + return; + + drm_dp_check_act_status(&mst->mst_mgr); + + drm_dp_add_payload_part2(&mst->mst_mgr, payload); +} + +void msm_dp_mst_stream_disable(struct drm_encoder *encoder, + struct drm_atomic_commit *state) +{ + struct drm_connector *connector = drm_atomic_get_old_connector_for_encoder(state, encoder); + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp_panel *panel = msm_dp_mst_panel_from_encoder(mst, encoder); + struct drm_dp_mst_topology_state *old_mst_state = + drm_atomic_get_old_mst_topology_state(state, &mst->mst_mgr); + struct drm_dp_mst_topology_state *new_mst_state = + drm_atomic_get_new_mst_topology_state(state, &mst->mst_mgr); + struct drm_dp_mst_atomic_payload *old_payload = + drm_atomic_get_mst_payload_state(old_mst_state, mst_conn->mst_port); + struct drm_dp_mst_atomic_payload *new_payload = + drm_atomic_get_mst_payload_state(new_mst_state, mst_conn->mst_port); + struct msm_dp_mst_slot_info slots[DP_STREAM_MAX] = {}; + + guard(mutex)(&mst->mst_lock); + + drm_dp_remove_payload_part1(&mst->mst_mgr, new_mst_state, new_payload); + + drm_dp_remove_payload_part2(&mst->mst_mgr, new_mst_state, old_payload, new_payload); + + msm_dp_mst_collect_slots(mst, new_mst_state, slots); + + drm_dbg_kms(mst->msm_dp->drm_dev, + "[MST] stream:%u timeslots vc_start:%d slots:%d pbn:%d\n", + panel->stream_id, new_payload->vc_start_slot, + new_payload->time_slots, new_payload->pbn); + + if (!msm_dp_display_is_plugged(mst->msm_dp)) + return; + + msm_dp_display_disable_helper(mst->msm_dp, panel, slots); + + drm_dp_check_act_status(&mst->mst_mgr); +} + +void msm_dp_mst_stream_post_disable(struct drm_encoder *encoder, + struct drm_atomic_commit *state) +{ + struct drm_connector *connector = drm_atomic_get_old_connector_for_encoder(state, encoder); + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct msm_dp_panel *panel = msm_dp_mst_panel_from_encoder(mst, encoder); + + guard(mutex)(&mst->mst_lock); + + msm_dp_display_atomic_post_disable_helper(mst->msm_dp, panel); + + if (!mst->msm_dp->mst_active) + msm_dp_display_unprepare(mst->msm_dp); + + panel->connector = NULL; + + drm_connector_put(connector); +} + +int msm_dp_mst_stream_atomic_check(struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct msm_dp_mst_connector *mst_conn = to_dp_mst_connector(conn_state->connector); + struct msm_dp_mst *mst = mst_conn->dp_mst; + struct drm_dp_mst_topology_state *mst_state; + int bpp, pbn, slots; + + if (!conn_state->crtc) + return 0; + + if (!drm_atomic_crtc_needs_modeset(crtc_state) || !crtc_state->active) + return 0; + + bpp = (conn_state->connector->display_info.bpc * 3) ?: 24; /* fallback: assume 8bpc */ + pbn = drm_dp_calc_pbn_mode(crtc_state->mode.clock, bpp << 4); + + mst_state = drm_atomic_get_mst_topology_state(crtc_state->state, &mst->mst_mgr); + if (IS_ERR(mst_state)) + return PTR_ERR(mst_state); + + if (!dfixed_trunc(mst_state->pbn_div)) { + mst_state->pbn_div = + drm_dp_get_vc_payload_bw(mst->link->link_caps.rate, + mst->link->link_caps.num_lanes); + } + + slots = drm_dp_atomic_find_time_slots(crtc_state->state, &mst->mst_mgr, + mst_conn->mst_port, pbn); + if (slots < 0) + return slots; + + return 0; +} + int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id, struct drm_encoder *encoder) { @@ -286,7 +477,8 @@ static const struct drm_dp_mst_topology_cbs msm_dp_mst_drm_cbs = { .add_connector = msm_dp_mst_add_connector, }; -int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux) +int msm_dp_mst_mgr_init(struct msm_dp *dp_display, struct msm_dp_link *link, + u32 max_streams, struct drm_dp_aux *drm_aux) { struct drm_device *dev = dp_display->drm_dev; struct msm_dp_mst *mst; @@ -298,6 +490,7 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_d mst->mst_mgr.cbs = &msm_dp_mst_drm_cbs; mst->msm_dp = dp_display; + mst->link = link; mst->max_streams = max_streams; mst->dp_aux = drm_aux; @@ -312,6 +505,7 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_d return ret; } + mutex_init(&mst->mst_lock); dp_display->msm_dp_mst = mst; return 0; } @@ -324,6 +518,7 @@ void msm_dp_mst_mgr_destroy(struct msm_dp *dp_display) return; drm_dp_mst_topology_mgr_destroy(&mst->mst_mgr); + mutex_destroy(&mst->mst_lock); dp_display->msm_dp_mst = NULL; kfree(mst); } diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h b/drivers/gpu/drm/msm/dp/dp_mst_drm.h index 3cbd2a674675..822d34cd6ff5 100644 --- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h +++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h @@ -7,7 +7,8 @@ #include "dp_display.h" -int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct drm_dp_aux *drm_aux); +int msm_dp_mst_mgr_init(struct msm_dp *dp_display, struct msm_dp_link *link, + u32 max_streams, struct drm_dp_aux *drm_aux); void msm_dp_mst_mgr_destroy(struct msm_dp *dp_display); int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id, struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index cc665888ce7f..597728ec6f3b 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -362,6 +362,12 @@ int msm_dp_mst_register(struct msm_dp *dp_display); void msm_dp_mst_unregister(struct msm_dp *dp_display); int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int stream_id, struct drm_encoder *encoder); +void msm_dp_mst_stream_enable(struct drm_encoder *enc, struct drm_atomic_commit *state); +void msm_dp_mst_stream_disable(struct drm_encoder *enc, struct drm_atomic_commit *state); +void msm_dp_mst_stream_post_disable(struct drm_encoder *enc, struct drm_atomic_commit *state); +int msm_dp_mst_stream_atomic_check(struct drm_encoder *enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state); #else static inline int __init msm_dp_register(void) @@ -415,6 +421,20 @@ static inline int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, return -EINVAL; } +static inline void msm_dp_mst_stream_enable(struct drm_encoder *enc, + struct drm_atomic_commit *state) +{} +static inline void msm_dp_mst_stream_disable(struct drm_encoder *enc, + struct drm_atomic_commit *state) {} +static inline void msm_dp_mst_stream_post_disable(struct drm_encoder *enc, + struct drm_atomic_commit *state) {} +static inline int msm_dp_mst_stream_atomic_check(struct drm_encoder *enc, + struct drm_crtc_state *cs, + struct drm_connector_state *cos) +{ + return -EINVAL; +} + #endif #ifdef CONFIG_DRM_MSM_MDP4 -- 2.43.0