From nobody Sun May 24 21:37:02 2026 Received: from smtpbgsg2.qq.com (smtpbgsg2.qq.com [54.254.200.128]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE62037A4AF for ; Thu, 21 May 2026 03:29:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.254.200.128 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334175; cv=none; b=NkzBiaVhL1rSiROSSd1bfqN9gyKZL4qEqTwtcFkAjv5vc7AXi+HTb1l7Ozy7EnKj9gTG+hhznzxQHVLFIdkTzRYpeCTG00qmc7/dSxQ3nXLfE7wajLTzoIdXEh1S6fIoMjfO1BtRwSa2gaBjNT70jGSqEz+Igmi+YG8prJBnFjg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334175; c=relaxed/simple; bh=Zajhc4mKey88ZOCQQgVvm3OH3f2SnJym6GktLOnTRjw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=apCIN5JGjcUUJMTDm0DNLYtjmJ9ThB7ReRcSFN62fi5ZeRV0ARktRj1FZ+4j0aNttr2/ob/VbqN7VWky1SXxToQeVqDZ8/Q05/+lvX6cvdt6IH4MydKT3qGlUnLlHBIuw+nfLLhYcnvernedtCB13JjUfgj2vFqq1SgjUvnQaWk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com; spf=pass smtp.mailfrom=airkyi.com; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b=TTRGK0g7; arc=none smtp.client-ip=54.254.200.128 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=airkyi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b="TTRGK0g7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1779334164; bh=dvxDCR9NEJvWoy2vX4KZL4araFw0lNuTo/DvCOAIkrU=; h=From:To:Subject:Date:Message-Id; b=TTRGK0g7MmO+YjZdd6jhUV5OUjQwOd85Peij7Rz0BevqIkR217AfvwN+mV2YCTfGG D2YOVLSsEPpM2QbSTLHFoZaV4JEtpnNun0feILr/v6rTLuvMW2pFVZiBkJxNp731uc 1SjK/SDhGcsYENaspGe4+gOupqxV7qLPIRoWqKdA= X-QQ-mid: zesmtpsz7t1779334159t70c25ab6 X-QQ-Originating-IP: ADiEYj7Uo9gkcTDRzLm44seRmsr0fa8KAQZuAK83eDk= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 21 May 2026 11:29:13 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 1170275653122731540 From: Chaoyi Chen To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , Andy Yan , Vinod Koul Cc: Heikki Krogerus , Dmitry Baryshkov , Luca Ceresoli , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-phy@lists.infradead.org, Chaoyi Chen Subject: [PATCH 1/5] drm/bridge: Implement generic USB Type-C DP HPD bridge Date: Thu, 21 May 2026 11:28:50 +0800 Message-Id: <20260521032854.103-2-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260521032854.103-1-kernel@airkyi.com> References: <20260521032854.103-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: N/Ph2bJENH2/HnBZFih2ROBWN+5NEoWy8UKltru42O/TX4zohGk0yS0P WEewwHRUuOq3JYu8rWFwHfaY+OtpEZj5P3evA5btQnO6CAU1DweukCZArojmaRBjONGawlU N0QXImwc5iaLx/3Yj6UDjtKR0hbhjDAibwznsmIx9sOVc9WshrqtslPFW1JZOMcHpY0MXRL w5DrrQVvkoim+FLCibFd0Dt23S6z4V7CEUoXFj+gVtQmvT/+qkHWPOtTQVPk2MWzFXCgQuK 9vVS2MhnKRDaOC++XlFL1C5tN1JPIsoZG4bKTosLBVHrfporo+s6scAKPEhvn909s/uWfNl pTdBvNNl3ZwdEpXjfB82AWVg1GfeuBSKxA+/nsy8Y3Ef7JYX+A926xekwJ9Xkgd/7QV4fzv BJ5HMZyCdYRXSjTrb7yx1G+HUT6g7PEqodLFDo/t8++NUa3s1Epf53lluYE+ZDGuOT+pBbf p+v7yPds66eh6IErqnHE+Ijg/0p8c5f5q4C5dwnr4anWOyruhSwpwqM/ou3hosSgbMvO5Xl OHX3CHFY6tV8eM3ExJHeU3GxbuW82qkpCczlzel5FxHiFbhhFm+wcjgJSNksZRI6WwA30Ee X47EiXV8rJWMGZ4vXjCsQzLjWwa9QHulbL9Da/fvCpuPE3HdB6frxcWnth+MdUwcAmTWhS4 8muozBJXbYznbFANiVxXfrV/GyaJ0GImDivWFEl8xOSd9GnCP/GiIeHW8uk4+/pEEMKF8yt kPsjBR84Wn4QOOKvYKhMAzKRKlPTo62O9Xqm5Pg6hywDi3Ff3BiQVsOFi+ujiAAqf7XbJka VigEwKqRjx9G8GSiTP81ckQMhBksBMCOuc7EFiTHMT5dcEXG1nje3UkZHXVChDG4ctn9q05 RyRDQswm+e6Mbyl5tNKinWwTjdks+WCjcUyQ0K6ydm0i5F01Rf/VYekB4lYzlyI/QQ6CiJ1 amfkECRE1QoShEvlZ6b6ArSyl3g4kLwHrCqpLQk63OFQzlY29AQrYqgKpNhR3MTfHAbXwjk 8tdqiO1jG93YdUCeJofyiHNye6TxWGvm+jGlNXwqQehc0/qWVg X-QQ-XMRINFO: M/715EihBoGS47X28/vv4NpnfpeBLnr4Qg== X-QQ-RECHKSPAM: 0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Chaoyi Chen The HPD function of Type-C DP is implemented through drm_connector_oob_hotplug_event(). For embedded DP, it is required that the DRM connector fwnode corresponds to the Type-C port fwnode. To describe the relationship between the DP controller and the Type-C port device, we usually using drm_bridge to build a bridge chain. Now several USB-C controller drivers have already implemented the DP HPD bridge function provided by aux-hpd-bridge.c, it will build a DP HPD bridge on USB-C connector port device. But this requires the USB-C controller driver to manually register the HPD bridge. If the driver does not implement this feature, the bridge will not be create. So this patch implements a generic DP HPD bridge based on aux-hpd-bridge.c. It will monitor Type-C bus events, and when a Type-C port device containing the DP svid is registered, it will create an HPD bridge for it without the need for the USB-C controller driver to implement it. Signed-off-by: Chaoyi Chen Reviewed-by: Heikki Krogerus --- drivers/gpu/drm/bridge/Kconfig | 10 ++++ drivers/gpu/drm/bridge/Makefile | 1 + .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c | 49 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index c3209b0f4678..d92e93875793 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -30,6 +30,16 @@ config DRM_AUX_HPD_BRIDGE Simple bridge that terminates the bridge chain and provides HPD support. =20 +if DRM_AUX_HPD_BRIDGE +config DRM_AUX_HPD_TYPEC_BRIDGE + tristate + depends on TYPEC || !TYPEC + default TYPEC + help + Simple bridge that terminates the bridge chain and provides HPD + support. It build bridge on each USB-C connector device node. +endif + menu "Display Interface Bridges" depends on DRM && DRM_BRIDGE =20 diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makef= ile index beab5b695a6e..c4761526ba0a 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_DRM_AUX_BRIDGE) +=3D aux-bridge.o obj-$(CONFIG_DRM_AUX_HPD_BRIDGE) +=3D aux-hpd-bridge.o +obj-$(CONFIG_DRM_AUX_HPD_TYPEC_BRIDGE) +=3D aux-hpd-typec-dp-bridge.o obj-$(CONFIG_DRM_CHIPONE_ICN6211) +=3D chipone-icn6211.o obj-$(CONFIG_DRM_CHRONTEL_CH7033) +=3D chrontel-ch7033.o obj-$(CONFIG_DRM_CROS_EC_ANX7688) +=3D cros-ec-anx7688.o diff --git a/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c b/drivers/gpu= /drm/bridge/aux-hpd-typec-dp-bridge.c new file mode 100644 index 000000000000..d915e0fb0668 --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +#include +#include +#include + +#include + +static int drm_typec_bus_event(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev =3D (struct device *)data; + struct typec_altmode *alt =3D to_typec_altmode(dev); + + if (action !=3D BUS_NOTIFY_ADD_DEVICE) + goto done; + + /* + * alt->dev.parent->parent : USB-C controller device + * alt->dev.parent : USB-C connector device + */ + if (is_typec_port_altmode(&alt->dev) && alt->svid =3D=3D USB_TYPEC_DP_SID) + drm_dp_hpd_bridge_register(alt->dev.parent->parent, + to_of_node(alt->dev.parent->fwnode)); + +done: + return NOTIFY_OK; +} + +static struct notifier_block drm_typec_event_nb =3D { + .notifier_call =3D drm_typec_bus_event, +}; + +static void drm_aux_hpd_typec_dp_bridge_module_exit(void) +{ + bus_unregister_notifier(&typec_bus, &drm_typec_event_nb); +} + +static int __init drm_aux_hpd_typec_dp_bridge_module_init(void) +{ + bus_register_notifier(&typec_bus, &drm_typec_event_nb); + + return 0; +} + +module_init(drm_aux_hpd_typec_dp_bridge_module_init); +module_exit(drm_aux_hpd_typec_dp_bridge_module_exit); + +MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE"); +MODULE_LICENSE("GPL"); --=20 2.53.0 From nobody Sun May 24 21:37:02 2026 Received: from smtpbgau1.qq.com (smtpbgau1.qq.com [54.206.16.166]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A873B371D0A for ; Thu, 21 May 2026 03:29:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.206.16.166 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334176; cv=none; b=KZw/4d5gfX6l9LqbWHYZjNsD0kETg8VeVrZUUb726t3ngdEnn6+jhpFgCmn50ItNgmYs5N2vOop6PPT4hZq1qiOfTGraHorEe1L5j6kUnHHrBHO/3Qwkl+cAfBihLQauF+B7y/lFzKSsCAnlm1pkbIaetwNgoLgJFpe06l8Vx0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334176; c=relaxed/simple; bh=lMIafWtlfkOyuKEqD6EYHnLnuD7hBs1GYcs/VV5ZZ8g=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=CjiTQQlGEcl1iaYvJIiMsWfTLZNoqkQsD+kuUNcLX33VdwU6u6qnSqmlzupltuKLrS4k88DPGdrTP2qBM51hmXRPp3c+mfry4QqaUPOcnA1PorpUZgZ1Y5q+36L1R5JbIxC4rvEZOceUn3oE+NucRY5bQSx6c3190W26awNR8/w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com; spf=pass smtp.mailfrom=airkyi.com; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b=Vv/PiX58; arc=none smtp.client-ip=54.206.16.166 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=airkyi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b="Vv/PiX58" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1779334169; bh=NA3zWcCN+LNcIiy4LfRk+qi3M7FDJHrSG6hmfEKlJsw=; h=From:To:Subject:Date:Message-Id; b=Vv/PiX58MJerlFRn2Qs5gJxPJM9ZrsdXt2J+kV/N31UDgojuk/315Z7uJ6M1Nnf9y TsoLGiufhOWH99ugnkirR4+de6FOTsLUkdmqfuS+JIU0og8mykXv9L3w8he3BQfstg PEpPWlhAq/oWaBIU623N3YH08rvMju18MZQifJXo= X-QQ-mid: zesmtpsz7t1779334164ta5a04dd0 X-QQ-Originating-IP: hBQ95K8MTql32AYs7HMJrJ6z3IXUmXk+VXXcCPVKIvY= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 21 May 2026 11:29:20 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 3257350597745359929 From: Chaoyi Chen To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , Andy Yan , Vinod Koul Cc: Heikki Krogerus , Dmitry Baryshkov , Luca Ceresoli , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-phy@lists.infradead.org, Chaoyi Chen Subject: [PATCH 2/5] drm/bridge: aux: Add drm_aux_bridge_register_from_node() Date: Thu, 21 May 2026 11:28:51 +0800 Message-Id: <20260521032854.103-3-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260521032854.103-1-kernel@airkyi.com> References: <20260521032854.103-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: NFzQ23lyTybaEIrf5VDCKo5q7qyGA3J4ItmG9BT55A0PbP6Zbp6YfmkU a62mNSe2VhfIL2EGmz/EYcYfP0Fih23NLZy0ddK3sw1r3D3ql8qq6hhlEpVV56IiIH2Efwe +HOmZZOmQVlui9dgeNrtq/LCpZ5d3YKdols+dbZadfmfzuPRKG/StR3zxW0/wYFEy5ROcXt 670q1rPIBCCSKPTxbryofv/beK4+hSSadoqJizU7TJn4sk2/qrVb+SSTbcNktmdVlw/JjtN Z9CIV1JEJiG/PzQxmrjTq3xJ7P4vBP1+eBIDlm9vKNjNjv3KWDzyOjP6GoaGbffBkqrLglf oJWArhXefMBCBUCDwZeSed2r2mUQA3lnUGopYZXYbEZLB7OOpan+u2+4B3HFPyizE8ZzgZz mPEmL4g8RdM6tjwxFaKbH1babpa7Xb46lJbZuFCSTaQqhbq4ltnvPJ426QOh3Jd44SMAy6w 9gxoWx7EfLwJM6Ff1TOLBocVpbKu+QmnicFA46qUU0tKUVjCJa6QxnrJ2rpcJ8PHnGCRIUv Z5UprkZ2Kjcb+BMW9Fir186swBZmx4iDWJHl4N4dOqXeXj54c6uyyf3apdKW3cqXWkOmiVb 6REKaR41fmMBzMCu49U905Eg2Jwu0hzk4WyhpGRQICBQ3AbnYd3W6Dpt0sGNxKqZP8IOcju /iED65KEH50Q9ot42Qkp/TxceMIRjneTGwFADpjItcz2bELslsZ+C8YmOoGaDTTnK8BDF3a 7oA9daYYS51G3Vj/QGkJnC0KAoqrL0z7AsCvp1p7++J96yhPgARBTgh4/dqRsfAgraWReHl 7ek+0d6L6K/aXCyhfL3Sjh8n2OMgZ4x2XBSKxuj3pw+0LpTR4UwvPPZ16LV9cVAQz/xPkDA Tkw4nPTPNWQgs7ukYhfsA2G5VI6MexhKBQ2Mu3h0n7M2R4OUKMQNrVBAviUMcM5rU03GL7A hwpEZRjEftHwnVz+6bb+59DgyY1lK2BV2KEFCWMKYl6vXcb9E1zXbEr8YQy580oaWX3rXgD WpFb1STmPMsbrMZSt5X2LwLATzV+o= X-QQ-XMRINFO: NS+P29fieYNwqS3WCnRCOn9D1NpZuCnCRA== X-QQ-RECHKSPAM: 0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Chaoyi Chen The drm_aux_bridge_register() uses the device->of_node as the bridge->of_node. This patch adds drm_aux_bridge_register_from_node() to allow specifying the of_node corresponding to the bridge. Signed-off-by: Chaoyi Chen Reviewed-by: Neil Armstrong --- drivers/gpu/drm/bridge/aux-bridge.c | 24 ++++++++++++++++++++++-- include/drm/bridge/aux-bridge.h | 6 ++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/a= ux-bridge.c index 1ed21a8713bf..f50283abed5f 100644 --- a/drivers/gpu/drm/bridge/aux-bridge.c +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -35,6 +35,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev) /** * drm_aux_bridge_register - Create a simple bridge device to link the cha= in * @parent: device instance providing this bridge + * @np: device node pointer corresponding to this bridge instance * * Creates a simple DRM bridge that doesn't implement any drm_bridge * operations. Such bridges merely fill a place in the bridge chain linking @@ -42,7 +43,7 @@ static void drm_aux_bridge_unregister_adev(void *_adev) * * Return: zero on success, negative error code on failure */ -int drm_aux_bridge_register(struct device *parent) +int drm_aux_bridge_register_from_node(struct device *parent, struct device= _node *np) { struct auxiliary_device *adev; int ret; @@ -62,7 +63,10 @@ int drm_aux_bridge_register(struct device *parent) adev->dev.parent =3D parent; adev->dev.release =3D drm_aux_bridge_release; =20 - device_set_of_node_from_dev(&adev->dev, parent); + if (np) + device_set_node(&adev->dev, of_fwnode_handle(np)); + else + device_set_of_node_from_dev(&adev->dev, parent); =20 ret =3D auxiliary_device_init(adev); if (ret) { @@ -80,6 +84,22 @@ int drm_aux_bridge_register(struct device *parent) =20 return devm_add_action_or_reset(parent, drm_aux_bridge_unregister_adev, a= dev); } +EXPORT_SYMBOL_GPL(drm_aux_bridge_register_from_node); + +/** + * drm_aux_bridge_register - Create a simple bridge device to link the cha= in + * @parent: device instance providing this bridge + * + * Creates a simple DRM bridge that doesn't implement any drm_bridge + * operations. Such bridges merely fill a place in the bridge chain linking + * surrounding DRM bridges. + * + * Return: zero on success, negative error code on failure + */ +int drm_aux_bridge_register(struct device *parent) +{ + return drm_aux_bridge_register_from_node(parent, NULL); +} EXPORT_SYMBOL_GPL(drm_aux_bridge_register); =20 struct drm_aux_bridge_data { diff --git a/include/drm/bridge/aux-bridge.h b/include/drm/bridge/aux-bridg= e.h index c2f5a855512f..7dd1f17a1354 100644 --- a/include/drm/bridge/aux-bridge.h +++ b/include/drm/bridge/aux-bridge.h @@ -13,11 +13,17 @@ struct auxiliary_device; =20 #if IS_ENABLED(CONFIG_DRM_AUX_BRIDGE) int drm_aux_bridge_register(struct device *parent); +int drm_aux_bridge_register_from_node(struct device *parent, struct device= _node *np); #else static inline int drm_aux_bridge_register(struct device *parent) { return 0; } + +static inline int drm_aux_bridge_register_from_node(struct device *parent,= struct device_node *np) +{ + return 0; +} #endif =20 #if IS_ENABLED(CONFIG_DRM_AUX_HPD_BRIDGE) --=20 2.53.0 From nobody Sun May 24 21:37:02 2026 Received: from smtpbgau2.qq.com (smtpbgau2.qq.com [54.206.34.216]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 44180358381 for ; Thu, 21 May 2026 03:29:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.206.34.216 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334183; cv=none; b=kpKTzaODhqTHVROhigrHIFyJsLw51A77E7sEP9j2kgzDcUjTADaHa+feyWvTMOn4/EvKqRUiLbw6xcQcw5tMiHUEEpCh4Rkz+oYRzdANwriDuOdOaYdE3kAy6Hznzh2K4lIw2B1XwiaCZT2UR1TPLsQaKu2NLmSWdoInsinmSJI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334183; c=relaxed/simple; bh=K3S3SM0o3VhkDzcVeuXIdjRAFO/jMTImhuQalPMfs3M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=SfOAqS7VDIoTShD9kuodvyiz7TIahhy3UNMakfX9y4246SICKZtSMSBlucr4CAUxx2Dwi2TqwPeAM+wuVELnGaFNOtg6zy+7NVV1XW/ipBY8CT7OqJ0gpgEhXJuql46G2imgONSQkY4TbGhuK4l8C0r9NJbBvpFZWwBDWc2r93s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com; spf=pass smtp.mailfrom=airkyi.com; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b=fcDrGuvq; arc=none smtp.client-ip=54.206.34.216 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=airkyi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b="fcDrGuvq" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1779334176; bh=sPcwxXMSU/erMkNaNCyJUycUJ9YzZFBvUoXZx1f7aPU=; h=From:To:Subject:Date:Message-Id; b=fcDrGuvqvVX8+QourBLay0Ignx/eL9oH6SaGNRfBiIsDNnPhv+S5/RBSe68rChkyX +hrUCiiHC5QdpCs6YT1+5qKcW0CnDHGyeaN4kHywf/I9IjGxFIuM4bx9MRHarkM4Sw 5fXbPcaHR40kj5nNePKZZCX0tfXs/sHjeBU1kek4= X-QQ-mid: zesmtpsz7t1779334170t6c882390 X-QQ-Originating-IP: GfJMTq5avx9zXlwCEn2XSvRswGjVTkoW/bW3+O1LL9k= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 21 May 2026 11:29:26 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 11043512005840582340 From: Chaoyi Chen To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , Andy Yan , Vinod Koul Cc: Heikki Krogerus , Dmitry Baryshkov , Luca Ceresoli , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-phy@lists.infradead.org, Chaoyi Chen Subject: [PATCH 3/5] phy: rockchip: phy-rockchip-typec: Add DRM AUX bridge Date: Thu, 21 May 2026 11:28:52 +0800 Message-Id: <20260521032854.103-4-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260521032854.103-1-kernel@airkyi.com> References: <20260521032854.103-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: McJfg7Aee/FZX0cVBuKrme2Fq1f3R4XdJ91FL4xgsokoTez5DGYo+MJP zKmESnt5Rc06bMCTZHkf3LZFiGbTifoXMhIKlmpZmmlM+ZjqfEFJ89EsheRz+m58dFe6LK8 woln9f+7o+4WHcx49+X6pEzmrhmoMuoGriwBhC8gTlQj8IKqAseD6vqvumFId0JwfOhgHzr SYVoiuxr2MU+AN1x90jTMK8I3ltxF+dRK9AhbESUhLYn+W7FjZD/h8Z2gBBR/FTbba0cIko spnO81cHsIZlWU+ZlQvwCLptQ8K9EY/2ViM0kRCf5IjD/43ZmBSFtnYyP18cPFdwki2XbCW tvCJa2AzwkEO11lZnCDFSZc6vLOIPidmHNmV5b+ipN3gr5axpX/eDwBni/baqsY2VTYMQvp Uc+8moQmCDtHXrZZfxfBb9RqU1N7dr15H6WdYHh5txD+k/K4etvLFR0yntu/aopbitgplBW xHKSra6AJ+rnXkFJUSp2cDXeRUq3/VEbHkFv61j3MHXEYnygdleMO1rGql9bbRl3x4Gn4u+ +lEPfnPvXAiByMYN4wCGjb23F6Tkl6GvkQOdTEKfQ5pi0WJ+6piy1sCCZqeMois6wnXi521 xevJmvgk2wkRsaoiau0fGRB7Uaa9f7WpMSe3qc6I6Mu8LmSMyyqBi0HuLraNBvLhBsAmxhN ZwsbUm9MTHG2xJC22QQJkB1EICApBgap4xgKcMj8Nqz4BYSJ1Iy9UwJ9v/WVIJp/d9gkrh8 6lMICzL24qcfKBaOHyJ4GM2wRW3mBAVQKI6gpUmii9O/I7SDlXc6s5wIZltRN33C9VZ4MQ2 Vz3J/YY6NurOzGPTxmTODVpWFuX7V/LEJuZGKq9hMkjAekuKUZquNB2A90tfKMCZnwQIk9I 9jpySVE70FfcX+u2F/zDLBogJp5igFR0Fhm+rV/ac9gqjYZNHWtS1ITbun+O6IZRSdH+SOV 8+WzQsc5sfL2/ld9fjCst6dvFORF74k/GuA4wdI/OdTYnmQ2+kyfGsWmH7ZkJZbkaCEI9Ul GhasWX9ihVTeFZvfxuQrPiw9xjI+k= X-QQ-XMRINFO: NS+P29fieYNwqS3WCnRCOn9D1NpZuCnCRA== X-QQ-RECHKSPAM: 0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Chaoyi Chen Using the DRM_AUX_BRIDGE helper to create the transparent DRM bridge device. Signed-off-by: Chaoyi Chen Reviewed-by: Neil Armstrong Reviewed-by: Heiko Stuebner --- drivers/phy/rockchip/Kconfig | 2 ++ drivers/phy/rockchip/phy-rockchip-typec.c | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig index 14698571b607..9173d3b4fef4 100644 --- a/drivers/phy/rockchip/Kconfig +++ b/drivers/phy/rockchip/Kconfig @@ -119,6 +119,8 @@ config PHY_ROCKCHIP_SNPS_PCIE3 config PHY_ROCKCHIP_TYPEC tristate "Rockchip TYPEC PHY Driver" depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) + depends on DRM || DRM=3Dn + select DRM_AUX_BRIDGE if DRM_BRIDGE select EXTCON select GENERIC_PHY select RESET_CONTROLLER diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockch= ip/phy-rockchip-typec.c index d9701b6106d5..48070b50416e 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -54,6 +54,7 @@ =20 #include #include +#include =20 #define CMN_SSM_BANDGAP (0x21 << 2) #define CMN_SSM_BIAS (0x22 << 2) @@ -1162,16 +1163,24 @@ static int rockchip_typec_phy_probe(struct platform= _device *pdev) =20 for_each_available_child_of_node(np, child_np) { struct phy *phy; + ret =3D 0; =20 - if (of_node_name_eq(child_np, "dp-port")) + if (of_node_name_eq(child_np, "dp-port")) { phy =3D devm_phy_create(dev, child_np, &rockchip_dp_phy_ops); - else if (of_node_name_eq(child_np, "usb3-port")) + ret =3D drm_aux_bridge_register_from_node(dev, child_np); + } else if (of_node_name_eq(child_np, "usb3-port")) phy =3D devm_phy_create(dev, child_np, &rockchip_usb3_phy_ops); else continue; =20 + if (ret) { + pm_runtime_disable(dev); + of_node_put(child_np); + return ret; + } + if (IS_ERR(phy)) { dev_err(dev, "failed to create phy: %pOFn\n", child_np); --=20 2.53.0 From nobody Sun May 24 21:37:02 2026 Received: from smtpbg150.qq.com (smtpbg150.qq.com [18.132.163.193]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7BE3331A555 for ; Thu, 21 May 2026 03:29:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=18.132.163.193 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334192; cv=none; b=jr49bTfbh5NA85ZJ3U3mXuGkgMhPZS9g6jPUPxuqftU7ycAVyiYbxDsxEf6hTlYp66/0y4Sgm3JG/JsfBfikz6/Xnkj+WrZSdTjXZY0Qa2/V015kXBDD8EZTIuY1DwNQlJcwcm0/lJHc9AglR5adMr/8/P6iOtGpgL1VGUI7kKw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334192; c=relaxed/simple; bh=V4gqn46/PO9ggwSFkf+U1CFoSsmbcF/eMfFoLYteR7U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=pwMA2y5ZhAm8UUThDEsJMUXTV37ToG5btmL3Bt1EnmcQe5o/zvW85g3elorEuzjWFWfQM7EYhUuSrEEjBjNXph5JTrd8kHtcmMk286E9PEmSFUy/tYnrJlhRISlPOZDk0DNwKaN0HegU+5bmcbYThut/SbGo22/1KwBxAjy4MiI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com; spf=pass smtp.mailfrom=airkyi.com; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b=T4P2EfHr; arc=none smtp.client-ip=18.132.163.193 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=airkyi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b="T4P2EfHr" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1779334180; bh=6Blt27VidEVpijM8X7bK9ygiXu5vv9uysAwWQfZr3MA=; h=From:To:Subject:Date:Message-Id; b=T4P2EfHrgUc44IkUOpxB+bf5Z2QCD8zvET+Ja07cZdvZv96W2SV0WY5bK4q8sqN1b 5hf6VviyuX5j3S9ijQI37WDoKG/A8Irnj9xz2rxURDLDEz8aIrQ0Tx0+mWyYr4GHl7 vNIaC8vb50wGEr7U59KApUtutusF3z383VsTjnSE= X-QQ-mid: zesmtpsz7t1779334176t8f9eb7f1 X-QQ-Originating-IP: d9IETWuCTenKIZFLByWwMHwi0SPZNsWnhksHBq1ofsE= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 21 May 2026 11:29:31 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 16407384103375472347 From: Chaoyi Chen To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , Andy Yan , Vinod Koul Cc: Heikki Krogerus , Dmitry Baryshkov , Luca Ceresoli , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-phy@lists.infradead.org, Chaoyi Chen Subject: [PATCH 4/5] drm/rockchip: cdn-dp: Support handle lane info without extcon Date: Thu, 21 May 2026 11:28:53 +0800 Message-Id: <20260521032854.103-5-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260521032854.103-1-kernel@airkyi.com> References: <20260521032854.103-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: Mw3/skGyA4U5MInulD1Hcv01TiVOzXbDmVOKFoPU0bqwf3zj7egolJZj 9SjtKKe6saqbmwlVeo5YKYi9BTvC+gRt+U0y9Bn5oWyhWGEob+40yrO/Qokomi0g3nvwh9Y D21YuqySN2LF9lrZyvihnxi8Zz3/u98FcD5otf1Rp2ScdzCvtujNWMWapc6Z97O7iLY3G4D ir8XnrHLHbcw8Ylpwe20XsoOrsgPnRlrRgjyPY6fqPHXoKdfXLxdNJOltpoGajQbG66ocYG BwaYX8jh1AHwHRtGKplfpqYVp0yl155SNEY7B1I+EOqQIfirv96alujqPzFQk263EpIrv2u znuIZ1OEbe9BNmLuXpPafrh1WWc5mzuURp5m79NGUJP9693PJVTVXRyWfAbNurMvsTh7EQL KuBtx40QuSkM1tN9Kv6GLHf7qFdXpQ4RWDG1KzPJEzXPSTxAUI0mhfXucK7VJCtuYEd4hE6 bD4n+uYqmfGeuPgkJSbT34+TK641LmJlKotnIsav5iKKlF8MSrugRfwshExUd0w0gwOD671 qT6znEa9bq3QVDu93RvCXupYTZb/ix8isbVF8Xl+js0gBdd62MS5P5wMFOO+hLeEXWrNcMu iMS7svd602j9zCr7k+51kjaTz//z6RTYWEqRP5nTrFgzuhD23wBWMRkOUXnv7BbNCJ1kxLO ++1A9Kp1Gg1PbdWXdHiI55wSvpNBicbmRklzzcwV/VtotVoJU53WNCUhhRSEtgp4+9umyWt c+LWd6txYWffqnm1/cJjG8GRzzJ+2fr7ziCklVi4+5gK/lsz79GE9cJYd+AjIPN6SfkJxsl 5uOzzA7d/baHu9YWD4XYH5vHjviN3PTt1369WjVNUlodaoCaMh1lUChPFJtzlg9Un4TauX1 FwbgFm5RdM9RTJ07Ddhp6+bNGiz//BP/INbA2iDTW4KeIZEq8qAqtrJkzNx900mjidoueAI sxdZlLoQP1aGfjQLh0PDGPo/0deN9udgA+/IJzseNl2qXJMUidmH7YVoIIT2tY7FSo9erfQ UbZq1N6T+lq4bbP5Y7YTzdYSCDqVnB7//ojLw5J0zNxp2fG036pSrYGgfdTT8= X-QQ-XMRINFO: Mp0Kj//9VHAxzExpfF+O8yhSrljjwrznVg== X-QQ-RECHKSPAM: 0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Chaoyi Chen This patch add support for get PHY lane info without help of extcon. There is no extcon needed if the Type-C controller is present. In this case, the lane info can be get from PHY instead of extcon. The extcon device should still be supported if Type-C controller is not present. Signed-off-by: Chaoyi Chen Reviewed-by: Heiko Stuebner --- drivers/gpu/drm/rockchip/cdn-dp-core.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockc= hip/cdn-dp-core.c index 177e30445ee8..9068118859e2 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -157,6 +157,9 @@ static int cdn_dp_get_port_lanes(struct cdn_dp_port *po= rt) int dptx; u8 lanes; =20 + if (!edev) + return phy_get_bus_width(port->phy); + dptx =3D extcon_get_state(edev, EXTCON_DISP_DP); if (dptx > 0) { extcon_get_property(edev, EXTCON_DISP_DP, @@ -220,7 +223,7 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_= device *dp) * some docks need more time to power up. */ while (time_before(jiffies, timeout)) { - if (!extcon_get_state(port->extcon, EXTCON_DISP_DP)) + if (port->extcon && !extcon_get_state(port->extcon, EXTCON_DISP_DP)) return false; =20 if (!cdn_dp_get_sink_count(dp, &sink_count)) @@ -386,11 +389,14 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp= , struct cdn_dp_port *port) goto err_power_on; } =20 - ret =3D extcon_get_property(port->extcon, EXTCON_DISP_DP, - EXTCON_PROP_USB_TYPEC_POLARITY, &property); - if (ret) { - DRM_DEV_ERROR(dp->dev, "get property failed\n"); - goto err_power_on; + property.intval =3D 0; + if (port->extcon) { + ret =3D extcon_get_property(port->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, &property); + if (ret) { + DRM_DEV_ERROR(dp->dev, "get property failed\n"); + goto err_power_on; + } } =20 port->lanes =3D cdn_dp_get_port_lanes(port); @@ -1029,6 +1035,9 @@ static int cdn_dp_bind(struct device *dev, struct dev= ice *master, void *data) for (i =3D 0; i < dp->ports; i++) { port =3D dp->port[i]; =20 + if (!port->extcon) + continue; + port->event_nb.notifier_call =3D cdn_dp_pd_event; ret =3D devm_extcon_register_notifier(dp->dev, port->extcon, EXTCON_DISP_DP, @@ -1121,14 +1130,14 @@ static int cdn_dp_probe(struct platform_device *pde= v) PTR_ERR(phy) =3D=3D -EPROBE_DEFER) return -EPROBE_DEFER; =20 - if (IS_ERR(extcon) || IS_ERR(phy)) + if (IS_ERR(phy) || PTR_ERR(extcon) !=3D -ENODEV) continue; =20 port =3D devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; =20 - port->extcon =3D extcon; + port->extcon =3D IS_ERR(extcon) ? NULL : extcon; port->phy =3D phy; port->dp =3D dp; port->id =3D i; --=20 2.53.0 From nobody Sun May 24 21:37:02 2026 Received: from smtpbgbr2.qq.com (smtpbgbr2.qq.com [54.207.22.56]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7125634EF05 for ; Thu, 21 May 2026 03:29:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.207.22.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334205; cv=none; b=Q72xj3WperKzsW5jpI+y1UzjfjojVH8aRINIMQ8hxPPsrJ4Tg0YDnsvb4WKqr96kGS3HHNAMfRDBA55Lj/foU60PKq+BPmxFae0osjY0ubUlxh7AfamaFI1g7xavCN4atnRswfRzN0x2mp9WpGcq/gdDw1vCSLGPJIWJB3RwXVg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779334205; c=relaxed/simple; bh=OC/2uyN1kqw5QaSRZ3MChfJMxlf0w3HnLn13WvN9luE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=Mxit5qoMJaCevhQTKIswDw+dGAo52CvggpCqy8fn0T1pbdJKcrvTojlPfnCW7KbnYYCVLY9oxxCKDF3mbhZ2KRwxTVDxtu1bBKsMSeGfbkBU2ce1xyokF3IfflIeVPpK5rUTvFoZ9I0NQgc5c7jiTdI67Ba8mxn1hm+DCorNV/c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com; spf=pass smtp.mailfrom=airkyi.com; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b=lxyhFXGd; arc=none smtp.client-ip=54.207.22.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=airkyi.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=airkyi.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=airkyi.com header.i=@airkyi.com header.b="lxyhFXGd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1779334187; bh=nRLwXf2fynemFaAJA3GfQxmDTSTYM0YSwxBPrtpakdA=; h=From:To:Subject:Date:Message-Id; b=lxyhFXGdmAqANYrccUIqtNC+4HJ/ynnHpwXJP0ttKcRgb5+UYXoW6i7uPNMy6C4mC GIMs4TmUZ5RSTGSeFeR4Zg2BMhpTWj2mTIJn/hnB1KqrQq/vF9pyA3tqgYWMHkdCQo bqXRk4cHYDzclObCXI84UBi8j/3zWcNdiqVp0EYY= X-QQ-mid: zesmtpsz7t1779334183t3152ee39 X-QQ-Originating-IP: L3DBTUqxJlFirPV5PibmznIwuRqLqB1LFGE/ZLP53qw= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Thu, 21 May 2026 11:29:38 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 5852278641908192897 From: Chaoyi Chen To: Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Sandy Huang , =?UTF-8?q?Heiko=20St=C3=BCbner?= , Andy Yan , Vinod Koul Cc: Heikki Krogerus , Dmitry Baryshkov , Luca Ceresoli , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-phy@lists.infradead.org, Chaoyi Chen Subject: [PATCH 5/5] drm/rockchip: cdn-dp: Add multiple bridges to support PHY port selection Date: Thu, 21 May 2026 11:28:54 +0800 Message-Id: <20260521032854.103-6-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260521032854.103-1-kernel@airkyi.com> References: <20260521032854.103-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: zesmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: NamDlXnbz6wM8o0TmSOoUoEbjl136Si5x+c8H/A12EhbNI0fh9xE71pR KTJW+7FxqI6JHytC+0BV4ll0CuKuhSLBD6/j3OIftIf6NA6vmj9I4AnhB+/lq6VFR6KV8jE g7Wr0sHHTvIpAQh+5+AR3p5DiPCB8K29G3vxUcg76qcxbS1SDvHgtoAeC1xONw19IVQ/ZmB 61GD1YyaeO/oAtBm0AWeDx90/aUTx1gc6F9rYNQwFUQB2IcQIM6Jwi5IHfA3/eVr60Jy6ft gbFnLlT/LjDUHcy7QFAEoFEZei/Qh7sesUfVsg6ELmCmPvSfrMU4xvZXEOqs16cSD9zP92l I6Q5Q17Lz7PjTXvdQQrmtBXxzAlpCW7r27Z4KqnwtoG7T8k73sxuK6RkviJ3pHmBcVFozut pRDUkhea/Hmit8BHyFEwXgaudUT2/e4XVkCU95dukpjeofWQJ9vq25RWR7gTVuYvhNgDWR5 tQWZ0cHKv2oHqLZAZMMMIa3LsBzCHgmoBwBHueKBR2c40ucWN+Vqqul5g/06Qb9Qssb60E0 Vy8zb+O+CoJsvnxmt6y+93z8hOCZ1TcrJuBdCGf9usEKK9Bh/UwAGJOVJtUO6WkOPPwFivY I/yFe1+jjOnzr9+Q9S50pVKgILtnOr7w2lF2Zj5TrFTIWmxvoCLB/vaamvhWgfteXOOq2LW e9BDvzzjknKw0BzhxhRr5+GmYBF6w+biKJ6ZHBFdD7LaC3R1AHETkWNJ2Ss5NrxVrK1PEFi 1DfUg4+ApXDuBLl043ocOIufZRDEcDQhc4OY5oMRBcGHKanuSlqDCKOMBZGYyNODfdmdBde ZTDaNail3xJGad1JZ/vrNDE2K/kQv2waUV8JLZndL3mOxLsmBnITMco6NRvdcCk96IAh66L KzYG+muploYbDf1G5ojPGSny6DEzGj2QUFkx/4fxORZriXZLMmtnXo9Cj5nB9GcJNnM0dx0 xeu8h2nbc5tPJC37wPcyKaqj9QCCelCMFNmp1Jb6GawGpVl+pkgI+cipVtUSKNt4WAwUSxN OnL5KsmrxwHVnPN0uHYFs5vDMy7Nx0DEZJ7LQPxYmF5gD8V+sX X-QQ-XMRINFO: OD9hHCdaPRBwH5bRRRw8tsiH4UAatJqXfg== X-QQ-RECHKSPAM: 0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Chaoyi Chen The RK3399 has two USB/DP combo PHY and one CDN-DP controller. And the CDN-DP can be switched to output to one of the PHYs. If both ports are plugged into DP, DP will select the first port for output. This patch adds support for multiple bridges, enabling users to flexibly select the output port. For each PHY port, a separate encoder and bridge are registered. The change is based on the DRM AUX HPD bridge, rather than the extcon approach. This requires the DT to correctly describe the connections between the first bridge in bridge chain and DP controller. For example, the bridge chain may be like this: PHY aux birdge -> fsa4480 analog audio switch bridge -> onnn,nb7vpq904m USB reminder bridge -> USB-C controller AUX HPD bridge In this case, the connection relationships among the PHY aux bridge and the DP contorller need to be described in DT. In addition, the cdn_dp_parse_next_bridge_dt() will parses it and determines whether to register one or two bridges. Since there is only one DP controller, only one of the PHY ports can output at a time. The key is how to switch between different PHYs, which is handled by cdn_dp_switch_port() and cdn_dp_enable(). There are two cases: 1. Neither bridge is enabled. In this case, both bridges can independently read the EDID, and the PHY port may switch before reading the EDID. 2. One bridge is already enabled. In this case, other bridges are not allowed to read the EDID. So we will try to return the cached EDID. Since the scenario of two ports plug in at the same time is rare, I don't have a board which support two TypeC connector to test this. Therefore, I tested forced switching on a single PHY port, as well as output using a fake PHY port alongside a real PHY port. Signed-off-by: Chaoyi Chen Reviewed-by: Luca Ceresoli Reviewed-by: Heiko Stuebner --- drivers/gpu/drm/rockchip/Kconfig | 1 + drivers/gpu/drm/rockchip/cdn-dp-core.c | 324 ++++++++++++++++++++----- drivers/gpu/drm/rockchip/cdn-dp-core.h | 18 +- 3 files changed, 286 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kc= onfig index 1479b8c4ed40..cb97690c5a5d 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -59,6 +59,7 @@ config ROCKCHIP_CDN_DP select DRM_DISPLAY_HELPER select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_DP_HELPER + select DRM_AUX_HPD_BRIDGE help This selects support for Rockchip SoC specific extensions for the cdn DP driver. If you want to enable Dp on diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockc= hip/cdn-dp-core.c index 9068118859e2..b9ba279ca653 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -28,16 +28,17 @@ #include "cdn-dp-core.h" #include "cdn-dp-reg.h" =20 -static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge) +static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port= *prev_port, + struct cdn_dp_port *port); + +static inline struct cdn_dp_bridge *bridge_to_dp_bridge(struct drm_bridge = *bridge) { - return container_of(bridge, struct cdn_dp_device, bridge); + return container_of(bridge, struct cdn_dp_bridge, bridge); } =20 -static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *enco= der) +static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge) { - struct rockchip_encoder *rkencoder =3D to_rockchip_encoder(encoder); - - return container_of(rkencoder, struct cdn_dp_device, encoder); + return bridge_to_dp_bridge(bridge)->parent; } =20 #define GRF_SOC_CON9 0x6224 @@ -192,14 +193,27 @@ static int cdn_dp_get_sink_count(struct cdn_dp_device= *dp, u8 *sink_count) static struct cdn_dp_port *cdn_dp_connected_port(struct cdn_dp_device *dp) { struct cdn_dp_port *port; - int i, lanes; + int i, lanes[MAX_PHY]; =20 for (i =3D 0; i < dp->ports; i++) { port =3D dp->port[i]; - lanes =3D cdn_dp_get_port_lanes(port); - if (lanes) + lanes[i] =3D cdn_dp_get_port_lanes(port); + if (!dp->next_bridge_valid) return port; } + + if (dp->next_bridge_valid) { + /* If more than one port is available, pick the last active port */ + if (dp->active_port > 0 && lanes[dp->active_port]) + return dp->port[dp->active_port]; + + /* If the last active port is not available, pick an available port in o= rder */ + for (i =3D 0; i < dp->bridge_count; i++) { + if (lanes[i]) + return dp->port[i]; + } + } + return NULL; } =20 @@ -254,12 +268,45 @@ static const struct drm_edid * cdn_dp_bridge_edid_read(struct drm_bridge *bridge, struct drm_connector *c= onnector) { struct cdn_dp_device *dp =3D bridge_to_dp(bridge); - const struct drm_edid *drm_edid; + struct cdn_dp_bridge *dp_bridge =3D bridge_to_dp_bridge(bridge); + struct cdn_dp_port *port =3D dp->port[dp_bridge->id]; + struct cdn_dp_port *prev_port; + const struct drm_edid *drm_edid =3D NULL; + int i, ret; =20 mutex_lock(&dp->lock); + + /* More than one port is available */ + if (dp->bridge_count > 1 && !port->phy_enabled) { + for (i =3D 0; i < dp->bridge_count; i++) { + /* Another port already enable */ + if (dp->bridge_list[i] !=3D dp_bridge && dp->bridge_list[i]->enabled) + goto get_cache; + /* Find already enabled port */ + if (dp->port[i]->phy_enabled) + prev_port =3D dp->port[i]; + } + + /* Switch to current port */ + if (prev_port) { + ret =3D cdn_dp_switch_port(dp, prev_port, port); + if (ret) + goto get_cache; + } + } + drm_edid =3D drm_edid_read_custom(connector, cdn_dp_get_edid_block, dp); + /* replace edid cache */ + if (dp->edid_cache[dp_bridge->id]) + drm_edid_free(dp->edid_cache[dp_bridge->id]); + dp->edid_cache[dp_bridge->id] =3D drm_edid_dup(drm_edid); + mutex_unlock(&dp->lock); + return drm_edid; =20 +get_cache: + drm_edid =3D drm_edid_dup(dp->edid_cache[dp_bridge->id]); + mutex_unlock(&dp->lock); return drm_edid; } =20 @@ -268,12 +315,13 @@ cdn_dp_bridge_mode_valid(struct drm_bridge *bridge, const struct drm_display_info *display_info, const struct drm_display_mode *mode) { + struct cdn_dp_bridge *dp_bridge =3D bridge_to_dp_bridge(bridge); struct cdn_dp_device *dp =3D bridge_to_dp(bridge); u32 requested, actual, rate, sink_max, source_max =3D 0; u8 lanes, bpc; =20 /* If DP is disconnected, every mode is invalid */ - if (!dp->connected) + if (!dp_bridge->connected || !dp->connected) return MODE_BAD; =20 switch (display_info->bpc) { @@ -551,6 +599,54 @@ static bool cdn_dp_check_link_status(struct cdn_dp_dev= ice *dp) return drm_dp_channel_eq_ok(link_status, min(port->lanes, sink_lanes)); } =20 +static int cdn_dp_switch_port(struct cdn_dp_device *dp, struct cdn_dp_port= *prev_port, + struct cdn_dp_port *port) +{ + int ret; + + if (dp->active) + return 0; + + ret =3D cdn_dp_disable_phy(dp, prev_port); + if (ret) + goto out; + ret =3D cdn_dp_enable_phy(dp, port); + if (ret) + goto out; + + ret =3D cdn_dp_get_sink_capability(dp); + if (ret) { + cdn_dp_disable_phy(dp, port); + goto out; + } + + dp->active =3D true; + dp->lanes =3D port->lanes; + + if (!cdn_dp_check_link_status(dp)) { + dev_info(dp->dev, "Connected with sink; re-train link\n"); + + ret =3D cdn_dp_train_link(dp); + if (ret) { + dev_err(dp->dev, "Training link failed: %d\n", ret); + goto out; + } + + ret =3D cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE); + if (ret) { + dev_err(dp->dev, "Failed to idle video %d\n", ret); + goto out; + } + + ret =3D cdn_dp_config_video(dp); + if (ret) + dev_err(dp->dev, "Failed to configure video: %d\n", ret); + } + +out: + return ret; +} + static void cdn_dp_display_info_update(struct cdn_dp_device *dp, struct drm_display_info *display_info) { @@ -572,6 +668,7 @@ static void cdn_dp_display_info_update(struct cdn_dp_de= vice *dp, static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct = drm_atomic_state *state) { struct cdn_dp_device *dp =3D bridge_to_dp(bridge); + struct cdn_dp_bridge *dp_bridge =3D bridge_to_dp_bridge(bridge); struct drm_connector *connector; int ret, val; =20 @@ -581,7 +678,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_brid= ge *bridge, struct drm_at =20 cdn_dp_display_info_update(dp, &connector->display_info); =20 - ret =3D drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.= encoder); + ret =3D drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp_bridge->e= ncoder.encoder); if (ret < 0) { DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret); return; @@ -600,6 +697,9 @@ static void cdn_dp_bridge_atomic_enable(struct drm_brid= ge *bridge, struct drm_at =20 mutex_lock(&dp->lock); =20 + if (dp->next_bridge_valid) + dp->active_port =3D dp_bridge->id; + ret =3D cdn_dp_enable(dp); if (ret) { DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n", @@ -632,6 +732,7 @@ static void cdn_dp_bridge_atomic_enable(struct drm_brid= ge *bridge, struct drm_at goto out; } =20 + dp_bridge->enabled =3D true; out: mutex_unlock(&dp->lock); } @@ -639,9 +740,11 @@ static void cdn_dp_bridge_atomic_enable(struct drm_bri= dge *bridge, struct drm_at static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct= drm_atomic_state *state) { struct cdn_dp_device *dp =3D bridge_to_dp(bridge); + struct cdn_dp_bridge *dp_bridge =3D bridge_to_dp_bridge(bridge); int ret; =20 mutex_lock(&dp->lock); + dp_bridge->enabled =3D false; =20 if (dp->active) { ret =3D cdn_dp_disable(dp); @@ -828,6 +931,16 @@ static int cdn_dp_audio_mute_stream(struct drm_bridge = *bridge, return ret; } =20 +static void cdn_dp_bridge_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) +{ + struct cdn_dp_bridge *dp_bridge =3D bridge_to_dp_bridge(bridge); + struct cdn_dp_device *dp =3D bridge_to_dp(bridge); + + dp->bridge_list[dp_bridge->id]->connected =3D status =3D=3D connector_sta= tus_connected; + schedule_work(&dp->event_work); +} + static const struct drm_bridge_funcs cdn_dp_bridge_funcs =3D { .atomic_duplicate_state =3D drm_atomic_helper_bridge_duplicate_state, .atomic_destroy_state =3D drm_atomic_helper_bridge_destroy_state, @@ -838,6 +951,7 @@ static const struct drm_bridge_funcs cdn_dp_bridge_func= s =3D { .atomic_disable =3D cdn_dp_bridge_atomic_disable, .mode_valid =3D cdn_dp_bridge_mode_valid, .mode_set =3D cdn_dp_bridge_mode_set, + .hpd_notify =3D cdn_dp_bridge_hpd_notify, =20 .dp_audio_prepare =3D cdn_dp_audio_prepare, .dp_audio_mute_stream =3D cdn_dp_audio_mute_stream, @@ -886,7 +1000,8 @@ static void cdn_dp_pd_event_work(struct work_struct *w= ork) { struct cdn_dp_device *dp =3D container_of(work, struct cdn_dp_device, event_work); - int ret; + bool connected; + int i, ret; =20 mutex_lock(&dp->lock); =20 @@ -945,9 +1060,12 @@ static void cdn_dp_pd_event_work(struct work_struct *= work) =20 out: mutex_unlock(&dp->lock); - drm_bridge_hpd_notify(&dp->bridge, - dp->connected ? connector_status_connected - : connector_status_disconnected); + for (i =3D 0; i < dp->bridge_count; i++) { + connected =3D dp->connected && dp->bridge_list[i]->connected; + drm_bridge_hpd_notify(&dp->bridge_list[i]->bridge, + connected ? connector_status_connected + : connector_status_disconnected); + } } =20 static int cdn_dp_pd_event(struct notifier_block *nb, @@ -967,28 +1085,16 @@ static int cdn_dp_pd_event(struct notifier_block *nb, return NOTIFY_DONE; } =20 -static int cdn_dp_bind(struct device *dev, struct device *master, void *da= ta) +static int cdn_bridge_add(struct device *dev, + struct drm_bridge *bridge, + struct drm_bridge *next_bridge, + struct drm_encoder *encoder) { struct cdn_dp_device *dp =3D dev_get_drvdata(dev); - struct drm_encoder *encoder; + struct drm_device *drm_dev =3D dp->drm_dev; + struct drm_bridge *last_bridge __free(drm_bridge_put) =3D NULL; struct drm_connector *connector; - struct cdn_dp_port *port; - struct drm_device *drm_dev =3D data; - int ret, i; - - ret =3D cdn_dp_parse_dt(dp); - if (ret < 0) - return ret; - - dp->drm_dev =3D drm_dev; - dp->connected =3D false; - dp->active =3D false; - dp->active_port =3D -1; - dp->fw_loaded =3D false; - - INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); - - encoder =3D &dp->encoder.encoder; + int ret; =20 encoder->possible_crtcs =3D drm_of_find_possible_crtcs(drm_dev, dev->of_node); @@ -1003,26 +1109,35 @@ static int cdn_dp_bind(struct device *dev, struct d= evice *master, void *data) =20 drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs); =20 - dp->bridge.ops =3D - DRM_BRIDGE_OP_DETECT | - DRM_BRIDGE_OP_EDID | - DRM_BRIDGE_OP_HPD | - DRM_BRIDGE_OP_DP_AUDIO; - dp->bridge.of_node =3D dp->dev->of_node; - dp->bridge.type =3D DRM_MODE_CONNECTOR_DisplayPort; - dp->bridge.hdmi_audio_dev =3D dp->dev; - dp->bridge.hdmi_audio_max_i2s_playback_channels =3D 8; - dp->bridge.hdmi_audio_spdif_playback =3D 1; - dp->bridge.hdmi_audio_dai_port =3D -1; - - ret =3D devm_drm_bridge_add(dev, &dp->bridge); + bridge->ops =3D + DRM_BRIDGE_OP_DETECT | + DRM_BRIDGE_OP_EDID | + DRM_BRIDGE_OP_HPD | + DRM_BRIDGE_OP_DP_AUDIO; + bridge->of_node =3D dp->dev->of_node; + bridge->type =3D DRM_MODE_CONNECTOR_DisplayPort; + bridge->hdmi_audio_dev =3D dp->dev; + bridge->hdmi_audio_max_i2s_playback_channels =3D 8; + bridge->hdmi_audio_spdif_playback =3D 1; + bridge->hdmi_audio_dai_port =3D -1; + + ret =3D devm_drm_bridge_add(dev, bridge); if (ret) return ret; =20 - ret =3D drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_N= O_CONNECTOR); + ret =3D drm_bridge_attach(encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CON= NECTOR); if (ret) return ret; =20 + if (next_bridge) { + ret =3D drm_bridge_attach(encoder, next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); + if (ret) + return ret; + + last_bridge =3D drm_bridge_chain_get_last_bridge(bridge->encoder); + } + connector =3D drm_bridge_connector_init(drm_dev, encoder); if (IS_ERR(connector)) { ret =3D PTR_ERR(connector); @@ -1030,8 +1145,99 @@ static int cdn_dp_bind(struct device *dev, struct de= vice *master, void *data) return ret; } =20 + if (last_bridge) + connector->fwnode =3D fwnode_handle_get(of_fwnode_handle(last_bridge->of= _node)); + drm_connector_attach_encoder(connector, encoder); =20 + return 0; +} + +static int cdn_dp_parse_next_bridge_dt(struct cdn_dp_device *dp) +{ + struct device_node *np =3D dp->dev->of_node; + struct device_node *port __free(device_node) =3D of_graph_get_port_by_id(= np, 1); + struct drm_bridge *bridge; + int count =3D 0; + int ret =3D 0; + int i; + + /* If device use extcon, do not use hpd bridge */ + for (i =3D 0; i < dp->ports; i++) { + if (dp->port[i]->extcon) { + dp->bridge_count =3D 1; + return 0; + } + } + + /* One endpoint may correspond to one next bridge. */ + for_each_of_graph_port_endpoint(port, dp_ep) { + struct device_node *next_bridge_node __free(device_node) =3D + of_graph_get_remote_port_parent(dp_ep); + + bridge =3D of_drm_find_bridge(next_bridge_node); + if (!bridge) { + ret =3D -EPROBE_DEFER; + goto out; + } + + dp->next_bridge_valid =3D true; + dp->next_bridge_list[count] =3D drm_bridge_get(bridge); + count++; + } + +out: + dp->bridge_count =3D count ? count : 1; + return ret; +} + +static int cdn_dp_bind(struct device *dev, struct device *master, void *da= ta) +{ + struct cdn_dp_device *dp =3D dev_get_drvdata(dev); + struct drm_bridge *bridge, *next_bridge; + struct drm_encoder *encoder; + struct cdn_dp_port *port; + struct drm_device *drm_dev =3D data; + struct cdn_dp_bridge *dp_bridge; + int ret, i; + + ret =3D cdn_dp_parse_dt(dp); + if (ret < 0) + return ret; + + ret =3D cdn_dp_parse_next_bridge_dt(dp); + if (ret) + return ret; + + dp->drm_dev =3D drm_dev; + dp->connected =3D false; + dp->active =3D false; + dp->active_port =3D -1; + dp->fw_loaded =3D false; + + for (i =3D 0; i < dp->bridge_count; i++) { + dp_bridge =3D devm_drm_bridge_alloc(dev, struct cdn_dp_bridge, bridge, + &cdn_dp_bridge_funcs); + if (IS_ERR(dp_bridge)) + return PTR_ERR(dp_bridge); + dp_bridge->id =3D i; + dp_bridge->parent =3D dp; + if (!dp->next_bridge_valid) + dp_bridge->connected =3D true; + dp->bridge_list[i] =3D dp_bridge; + } + + for (i =3D 0; i < dp->bridge_count; i++) { + encoder =3D &dp->bridge_list[i]->encoder.encoder; + bridge =3D &dp->bridge_list[i]->bridge; + next_bridge =3D dp->next_bridge_list[i]; + ret =3D cdn_bridge_add(dev, bridge, next_bridge, encoder); + if (ret) + return ret; + } + + INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); + for (i =3D 0; i < dp->ports; i++) { port =3D dp->port[i]; =20 @@ -1059,10 +1265,18 @@ static int cdn_dp_bind(struct device *dev, struct d= evice *master, void *data) static void cdn_dp_unbind(struct device *dev, struct device *master, void = *data) { struct cdn_dp_device *dp =3D dev_get_drvdata(dev); - struct drm_encoder *encoder =3D &dp->encoder.encoder; + struct drm_encoder *encoder; + int i; =20 cancel_work_sync(&dp->event_work); - encoder->funcs->destroy(encoder); + for (i =3D 0; i < dp->bridge_count; i++) { + encoder =3D &dp->bridge_list[i]->encoder.encoder; + encoder->funcs->destroy(encoder); + drm_bridge_put(dp->next_bridge_list[i]); + } + + for (i =3D 0; i < MAX_PHY; i++) + drm_edid_free(dp->edid_cache[i]); =20 pm_runtime_disable(dev); if (dp->fw_loaded) @@ -1113,10 +1327,10 @@ static int cdn_dp_probe(struct platform_device *pde= v) int ret; int i; =20 - dp =3D devm_drm_bridge_alloc(dev, struct cdn_dp_device, bridge, - &cdn_dp_bridge_funcs); - if (IS_ERR(dp)) - return PTR_ERR(dp); + dp =3D devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL); + if (!dp) + return -ENOMEM; + dp->dev =3D dev; =20 match =3D of_match_node(cdn_dp_dt_ids, pdev->dev.of_node); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockc= hip/cdn-dp-core.h index e9c30b9fd543..c10e423bbf06 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -38,6 +38,8 @@ enum vic_pxl_encoding_format { Y_ONLY =3D 0x10, }; =20 +struct cdn_dp_device; + struct video_info { bool h_sync_polarity; bool v_sync_polarity; @@ -63,16 +65,28 @@ struct cdn_dp_port { u8 id; }; =20 +struct cdn_dp_bridge { + struct cdn_dp_device *parent; + struct drm_bridge bridge; + struct rockchip_encoder encoder; + bool connected; + bool enabled; + int id; +}; + struct cdn_dp_device { struct device *dev; struct drm_device *drm_dev; - struct drm_bridge bridge; - struct rockchip_encoder encoder; + int bridge_count; + struct cdn_dp_bridge *bridge_list[MAX_PHY]; + struct drm_bridge *next_bridge_list[MAX_PHY]; + const struct drm_edid *edid_cache[MAX_PHY]; struct drm_display_mode mode; struct platform_device *audio_pdev; struct work_struct event_work; =20 struct mutex lock; + bool next_bridge_valid; bool connected; bool active; bool suspended; --=20 2.53.0