From nobody Thu Jun 11 17:11:28 2026 Received: from smtpbguseast3.qq.com (smtpbguseast3.qq.com [54.243.244.52]) (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 EF90F2FDC5E for ; Mon, 8 Jun 2026 07:11:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.243.244.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902681; cv=none; b=Gacm3+0rdBGIO8wa6VHC1z5+2MMAsQ08E67GPo1ySQrLw5Mlj4q+ZHx72HY9AXoZzMSaeGpEsuxynLeEKeGydHuO103bViyIYq6IVxxCuc7m0s2G2blM3Bo51iYWWP03ykxBjHKqon588Oj0Ql1KNrm2IbcfoP/4B0eNup/ALMM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902681; c=relaxed/simple; bh=MSfgcxmqx7xmt/pRNG8ZxLZnSJgVAoBcbyg9iN/r/eA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=VedlIEnU6GFC49uKYWbbnc6nWu4Usa+ewEwSz4nz9af+bPtQGilDxrs2eOeAojDWaLErxUBeUA8lEzZhv3IgS2b5hjWPz+DCOO80ime1hllhC2kMnpkw9j94fy/948R+cFp0+8BFn7q7RpaOITsLU0MLKhW4R1zDB0CXlN3fAWI= 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=eEr8jUbb; arc=none smtp.client-ip=54.243.244.52 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="eEr8jUbb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1780902646; bh=ljRwFnTKGUTVqgA3Lm3Ra0/E+sWBd9mHLzzNshq9MTA=; h=From:To:Subject:Date:Message-Id; b=eEr8jUbbYLtbt462PGeUT1v2Ij2hxcMmJr70MGJuO1rJ604ztZsMacf/povZ8/8zj ZldN86BJrb2Mqb3nUTX8qDOXPC4ClPb3EKqU2kX5WVjKi8JgVe1/puqtGVFm/ZxGwl 7zFfncvWjn9niArK01rkRYuAUr2WNIE8910WZnT4= X-QQ-mid: esmtpsz10t1780902501t3845a4dd X-QQ-Originating-IP: SZa8h0Tea+RZoA9s470z5Mkgz2dnQBWejt+O90a4Yvw= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 08 Jun 2026 15:08:15 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 14132758870929029715 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: Nicolas Frattaroli , Sebastian Reichel , 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: Mon, 8 Jun 2026 15:08:01 +0800 Message-Id: <20260608070805.88-2-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260608070805.88-1-kernel@airkyi.com> References: <20260608070805.88-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: MpJmQ90V4eWU6cn+qBOYfxIb3xzULALuXKsF8sfmUVIbYQTDD0jqg66e dtnvQYsqnS4+P3OAlJL69b+ETmKrXD6fnYo6cXRDi05Z4Dq63rFUy68PSh5FtQ5IwAmi+Pw AVBrYkGWOJz36cX4PWQELby0FlWDqEcij9FEOSQzQ0LuDt+m6B/0WmQaY/0Fm4Jucq3UWgo toSDfwADTn0PL38Xgni2AdBnxGoz5UigNgu8ny4+grxJj4NSdZzX5Z/gdioxpUi1cSHkyou +B8d7jAmyqiNVs0SELu2jVjTZgY4bPjdPcxZKT2mZy8FL4kVdLO5cswFAQlHgtRDlT2/9A4 5nlRP/IbuEc0jbSpr2rw9ifVKzZRZtdFAr4PKmIXKrQpy+d1GjMHYrn1F6ercHKaAwr0FfM Nqf+OxnPKie19yWBArvfLPuEFIh+BgzkF9kLxMHkwm/r2V9sFmXA+wx1sIn3XKv9XCwLUok 6D4twRqNYeLGOVILW+DftwLV7eeS4ExUx0gNrOI3bTDo2JhcycjWC6nT4BXVgm9kzS6zFQx Idinta2nVAvY09zQuQSiOFlAGdrKaKs1TjSH0QhZI2R4PrgHWpahQVMLgdX3AtoC3tYOx2q 2Sybd7NRm/E+Boi7d3qzCFXGF3Ucwy9eV5QJAocsBJ9M1CB9u39fi4pmyjoKz7dLxFlmVIj kd668zmgyOkba0AKKdFUxMyB16H0sQ+9Ml/adII6vtFsnXd61NW723I/mWpVWz5+6FWQwUn EcdCSeDr0dNSAJ3KCPXknfEYQvQmwHRF/I8upP7aKBCjeIaEbw8YN13cQog0jWDClDpobBe ImfQzqICRkSdTVukOX/CwaTRQeGApTdKtp079jP9h3czxaGvEPKwmLusin+NuR2juDNiKwr W0bipesS1GFoCG8wUk8MNNRFdq2zdUORfXUFdA3aXYupLZ97idFYTMOTXeeM4EvqgBQY3zo x4LOnuRxxDTc9Pq5iK/eoJ29SU48RIotyct1hx0OPAHpqSetb4twBKRNbUxyFgW2BNchrVq gI8xSQiFKbCr+DQ/HxD/0Anelgddba42V93DXKSQ== 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 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 Reviewed-by: Nicolas Frattaroli --- Changes in v2: - Add copyright text. - Remove useless goto. --- drivers/gpu/drm/bridge/Kconfig | 10 ++++ drivers/gpu/drm/bridge/Makefile | 1 + .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c | 54 +++++++++++++++++++ 3 files changed, 65 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..c09579ff7ab9 --- /dev/null +++ b/drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026 Rockchip Electronics Co., Ltd. + * + * Author: Chaoyi Chen + */ +#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) + return NOTIFY_OK; + + /* + * 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)); + + 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_AUTHOR("Chaoyi Chen "); +MODULE_DESCRIPTION("DRM TYPEC DP HPD BRIDGE"); +MODULE_LICENSE("GPL"); --=20 2.54.0 From nobody Thu Jun 11 17:11:28 2026 Received: from smtpbg151.qq.com (smtpbg151.qq.com [18.169.211.239]) (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 765322F7EE1 for ; Mon, 8 Jun 2026 07:09:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=18.169.211.239 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902546; cv=none; b=eHpvNQ3ZXaPq3JJV0/+KbGhIj1S/yZzh3s7nuEuOk53xa8D20X1f+yDXxz+f5cCz8wBpxklk3noivjzYqkPQst/EJeeGnIT07DVUDmqaYVDJCXyeEliMm8itQrFONKd3M5X6giMtyxD4kb7FU6F7XsA98Am03ez4LBx3fnNf2JA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902546; c=relaxed/simple; bh=Yy9o/swbrVekitef40RTFuev7VtZwX7+rm6FYxXw3QU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=InVtU9/RcJ151fG6FmVIjqaxaPDYV+07q1txvxNe3+qYPlkk5ceoduYrNGXSU0AfvvGZC737I+VbP6R86YZkTgKvRsxzoPDAet/Dej6TXvXmRYZchp8V9R62K7FY/r9mWh5YXwzmAfrMwNo6d6C/kp/bkO/M/XcErJUUukAjSKI= 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=osLzWiKU; arc=none smtp.client-ip=18.169.211.239 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="osLzWiKU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1780902509; bh=6tLWoBW2pFlmOerPRepxyKMqbCkBEey+ItacdvxIb0w=; h=From:To:Subject:Date:Message-Id; b=osLzWiKUyDgPN8KNr2+g6/NVVoUOkd85RKXmS9m8OioSTDkNfi5R6iAgWCNTTn3Yf yowsSmUUpdatpSNRFkL+LtBuxley89DJlWmrnp7zfqixWImon0iwYu/vgz1i8+m7wv 8WJrmB/W0JFCrqz0TrOFIDbZWAjENoKdmnP1Teho= X-QQ-mid: esmtpsz10t1780902508t7749e501 X-QQ-Originating-IP: 0Qz1Oiv8vXDmyy1J7m5t4cou6ezju/IsoBdbZ45NzL0= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 08 Jun 2026 15:08:22 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 5642729304613398450 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: Nicolas Frattaroli , Sebastian Reichel , 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: Mon, 8 Jun 2026 15:08:02 +0800 Message-Id: <20260608070805.88-3-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260608070805.88-1-kernel@airkyi.com> References: <20260608070805.88-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: OO2wLqYBHUeBjDE4iO6iyYK0/2m4Vg5YxDKTBKf7Gs8um8FTFSzbXBFK zf7xI687z59ZE3hHj7f+sI22IMtt3jWK+yy3Lwuw21rBBLF7JCmhQDn5rZxIVn42STbvB56 5MrK9xQ5ZZ6st1EofBHtkKEmqEj4H8IuoEq3Apx7LeMRh9nt8zfXCRdd7AfFxBexg+F8c2S Z3de3IXwL2/k1R8+5yW3LKCRpx93myJe0h/Wj2LCL9KtBoB8RaCdcW+pvNPzfjFaFZxYeOo F0YykDpvd/eUMpZFoDS3YtNpQeJ5X1Ha7W5PFOR40TqfY5TJG0siem9BxbEgAACUoA+F/ii M5dYTgnxbvh8AKJcYhAd98kfRtKaLLfNpnKktTGGmVAkctjeIiYldLDpXWcVohqGKV7ikhC noUcmNGWCYcP4/cNk7NXsrRgLhQALqVyEWNjgFQL1Vw2Ssj8YAdPVwpXacB7BIN2674N8i3 vNnVVpO9euiSRarmGYQpK8Zfb5ARJkAvgv6KOlfDfEpvLHdPcO+6S1CqdD8rI7Lx2mJZuUP Fq9ktnR2WGxEtaSMZehM67gsSNDnAbQ5cLoTwKurxpllt3nfCSXznima2XjTyAXEUOjYq7S QD2IdOqo7051BQ0Uc8zg+7NsznTziEfXU87zV9Pfn3V/B4cIvT8dhNm5XWeAklGXUNxzXvf mlwhgPOpyhFD3FGWL/6X1LkL0PwqqyGDsihwY0J25llwKc07NrJ2AiefDf+JBJAN8pfitHp wxLjBYArP/egvxkqXNpxtCq7y1EVTsOgLrHNcLxNl2JTCvg0Aw3cSASIKDeqlH3GojpvN8Z b7zbGiTGvpghLS42bBHbAFPKOuy+KZO8gKTH9Lh7bxEpMPKeJX4SoYjd3JviaLjWcQpYkWg AEoS0Bd/YSNx28iYABtOipRSVKdwRuuABIUdrgHsVvvY/3wLKBPpVbhs5MOLmZtvUG4oNsf z6eBpVsA5XEqZziINtF/k0EnD+yDwVaQd9cn5reoECTtuxh0007a2LbcvLREv7FeJKnwXPf jFCaXFj0EF1BUc3D700fqSfZ8IZzk= 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 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 Reviewed-by: Nicolas Frattaroli Reviewed-by: Sebastian Reichel --- Changes in v2: - Fix incorrect function names in the documentation comments. --- drivers/gpu/drm/bridge/aux-bridge.c | 26 +++++++++++++++++++++++--- include/drm/bridge/aux-bridge.h | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/a= ux-bridge.c index 1ed21a8713bf..06a1466f49bd 100644 --- a/drivers/gpu/drm/bridge/aux-bridge.c +++ b/drivers/gpu/drm/bridge/aux-bridge.c @@ -33,8 +33,9 @@ static void drm_aux_bridge_unregister_adev(void *_adev) } =20 /** - * drm_aux_bridge_register - Create a simple bridge device to link the cha= in + * drm_aux_bridge_register_from_node - Create a simple bridge device to li= nk the chain * @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.54.0 From nobody Thu Jun 11 17:11:28 2026 Received: from smtpbgbr1.qq.com (smtpbgbr1.qq.com [54.207.19.206]) (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 E49C73396F4 for ; Mon, 8 Jun 2026 07:08:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.207.19.206 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902533; cv=none; b=CE4drloQ+SaivTAwGCqHZUrp/TyWysjQqs+vO+y4hF1+5A6QXzSGe6RjWOCPBDWTfHbYgOZkh2ORLhnLFH2AyxocOLnBFD0JHU6b1RSoFiHCs+KcAKfxJVKI4lFj2KuV6qOxSnWpjfT/iJ0nK7On07xHNXNxUQrrUDgvp0F/lYw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902533; c=relaxed/simple; bh=PBZyzb9+d7SHWN/G0rllly7Q7oLL4M0GqrL3pYw6PHQ=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=hmXMPZtWV3d5v9hqtQBF1g1t+iZLSIH9iO7PAZg9EDy++jCQ5i1SnttPiTGowVCVNjwXYWoNf4Of3vSFBh7pV6V1xdDfmU/agYKMRWmQ4A8F89MGAzMibkPIwxW9s/pXQzyCWBvBpiRy5hEIRfBeKmvZvGrnnPpyfRfapoB5454= 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=D4yqfhaw; arc=none smtp.client-ip=54.207.19.206 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="D4yqfhaw" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1780902515; bh=57OXAMQqqj4xbXyszs1R+EibBlVBpUVo5uuotM2InZI=; h=From:To:Subject:Date:Message-Id; b=D4yqfhaw1nJ9J7Tkn9qy+S3c1L9sRjhDM/lRNEs4r1mPIcA6FrDBH6g/a/lSiFv2t lucZ37a2B1EtzlVIu6wBbiwsUyZUgi6KtL1+eJjI9Oz2XmEo6txB43CT1hl+Dzf0UF 5/fgqnleJwWzbV4YMnbuIt7TSgR9UREnrw/EAk6M= X-QQ-mid: esmtpsz10t1780902513t7fbbf0a9 X-QQ-Originating-IP: XF/2kaHxRqFGalrQAGZQ0zFGemSye6Cjnqw2mX0Z/Bw= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 08 Jun 2026 15:08:29 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 2467102534402940748 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: Nicolas Frattaroli , Sebastian Reichel , 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: Mon, 8 Jun 2026 15:08:03 +0800 Message-Id: <20260608070805.88-4-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260608070805.88-1-kernel@airkyi.com> References: <20260608070805.88-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: M28vnsO5i7WeO8RAd+gHknW3IMpkFDIzexGkK+IyvO3s9BzR+h9odlc7 M8Q/+gAMaQpBmOXCC5wVGotQf4X440Et+5CORQQ6RCZxepLzw0WvwFXksSH5LwgbpRmdNuF s1IufGWKRZensXcCgVeP6BtfmEGi3hvLFhquEUJU7kYMCC7wzeD4Zie0gsFA0zcRudV8EGM QkqGW9tTLkVyvrfLeZaJCpJZdRufEJSzr0U7XiXd5/l1wA47jm+9077DR8aqbo7o0JGKqwX M6ebwrPVrqIJzTsT/PgeDyeid3852nPvSUwmQ7LndtL7IynYm4wjxAgm4YafXIDOQ+u6dVK pSYmVN5K3HwCEpBxlC13cH/HT6UDQHlB9eMv6aEQxwxfPbF84BSwIno0/qFFx/cw4WUL1GK UuOnwRlLKI3pc1SiykVRQ5SimAXaHywQELg263/DsV+G2MzOxgSOJGqaturHjXxYl4aeVq7 0zMFbnfcHcPKH6RENu4984pm602odtn/xA+niTAI9lGKSRGrMDBlGKMgj1wU27JCW1QQYP1 hqu9K6PMPYETIUZQnKja3NGOpG20A/HIwA3VprMADG0KNSyOvZ3Wqh0LoMnFSXxoQFwFln1 ZNZa+2eOb8gKIEuQostlRe9HrY8qmemOWj27lH6s/wIa9A8YQelRltF8NwIahqh9CVzNGhp AkdRZXRvSiHb3X5qTG0tl6CcyI3iIm3AENKtY9SEVJ6hime7wkrQ7faKvNZQnxYR5XpJ+95 sjeOYIOiw3TtD0JHaYYTEDMVMMyboa8ZQ3Zrh+UG89JD3xgMOv16wy02HK6R/g9uc6urYFb HvWtHJ05vmuRC7OmfA3hXcdUKH2oyP0LcJr1qEzR3C6WU4p3RimuWU9OavCILHUsv9Z3Yu1 eNKot78/iYnzY6rAC3gKPxdrSEBluAEoz3pl4sSXWYPryhWhjnc8xcZQrpECDfk4Lqz0i1T vTsnZ5Cad+1Q80lJ38y8gw9lO44OSkGvDAvNy82JYTWXgKS3dUsuv2mC7KzgQCMop/xTKgu 5Aob+dKnxFp/tsDMYJowCQ1fAJpol/PaeL3xVCDQ== X-QQ-XMRINFO: MPJ6Tf5t3I/ylTmHUqvI8+Wpn+Gzalws3A== 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: Sebastian Reichel --- (no changes since v1) --- 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.54.0 From nobody Thu Jun 11 17:11:28 2026 Received: from smtpbguseast2.qq.com (smtpbguseast2.qq.com [54.204.34.130]) (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 111EA3396F4 for ; Mon, 8 Jun 2026 07:09:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=54.204.34.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902544; cv=none; b=rt3RV+/RprPHiTloUduTFw1gphWFDtuU/zqtnvlqD28jv3CwO+RThzwU2RWsQP9afL5MF+AB4Q2Yg6dfaMQaFBeyC9p5rh9Ql3+kzRvUROhXutUKWCYaXxGg6i/DYeOxp8iFwU+MiWlX8E0wIr5koYh6hRGNxrwUZTDs/j6ytu8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902544; c=relaxed/simple; bh=W8Jrw1/nCtZxBRPflr14x6Y32IimUwyusywZWytbBJo=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=Nur1c5P/efDvS5OTwlmGoWkkly7eb1LImfRKuHmNLY7ywPeID1OUzlOwN8SY0tIOU62/Zmj1KubVl6N1Qfzh8zSsbuSfeSy80PNFZhnAxMLhYHgDIwN+jkTG6w2gLocgJv6r8qQWfSw1/T1sA5OoLDs7yIrMVdtew0zYxftZGL4= 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=SD+s+nC3; arc=none smtp.client-ip=54.204.34.130 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="SD+s+nC3" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1780902525; bh=BJBXqIdMo0uJb9odMwXPl2LzKb3wWNT/icd4kKoMmsw=; h=From:To:Subject:Date:Message-Id; b=SD+s+nC3W+DsOCGoU1QcxXW4EWqB6d2JP1f95gV/OOD9gnl4cML8RdrjC/e767VwI RnEDvavwREQgWBW/bBpZAKvaBkZzQFNsDllV79kA3VWpakr95knryR7a1Qcjgc3X3m 4EwR3mUUeYcIV+DIPODzOdHU0Z/Wulk4rXsyXHEA= X-QQ-mid: esmtpsz10t1780902520t711901a3 X-QQ-Originating-IP: Jz5ZQWmRqpeGhkm7cKGk5fyrmUiArGhysVK7jI09zek= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 08 Jun 2026 15:08:35 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 15018740618981124911 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: Nicolas Frattaroli , Sebastian Reichel , 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: Mon, 8 Jun 2026 15:08:04 +0800 Message-Id: <20260608070805.88-5-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260608070805.88-1-kernel@airkyi.com> References: <20260608070805.88-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: MyirvGjpKb1jqS4w9isz6TrFDUIcYs96gFKgItT1y71LaeYwAYVjnrPI Dqil86xX6bPlIwJCtLnqHKlkvU5B/+K0+lNTzDO/G4W4lpf2HDywYACDlTgwmtF4Lud470s o6t+gv1Tir9NNOuzT166BKNEFoH6dfGsFDBI/TRy9px4VZ4gmE0b8kfeaahToG41Yoqqhmx G2nb1ezXbnEED0IrO63xsb4I1Yx/bD5s+I2oHpC/5fiTQ86acdX0Ckivc1jVevUSN+I27wJ g0WSUUNhanfiNLsYclKnluU5vYC1if1P0FuZApW/s7ScEcBDLjkVY/b2rX314tS1fQ8LO71 ckkRkvQbWqLaLVWCf+he14IJcVV4/dLhV1Iue9nILB6d1nwlow76HJNYEonKOTQIXp/+K6G HsuJJHcQktVCnVgW0oTiAZhuO9Y3GWHwQoawom4Dqy0MdSe0aY7cOz/XyDYJAgjbmVK+v4t f0n2C/nfrATD5v6chZI7qcUb1tmeRV/fDsx1dJ8uW9/zBJmYgXBPRWF7V7ZaWwUN8KIzjtX dZ6KJWZgNPvvGZ5Ji9XpzXZm4Qak6JRz5vxKxzPlwSo2jh2c489so3LGLmeWNAfg39+c76k MgO9D0GviyCTa/nvuMx9hyh5DiZjYGH/C5W31m5sxgTJt19cxLVGsmuwMwf0AqGixHqeTQe W6h4h/jmJhQquIzsN0SzR7eW/yyH6ymnOezJVdPGuTy0zgHMB/wN6f1b9YgHdsK5l7AGWvD 2/uRYryFzQ2abx2/MomI3+oMKGrY1qP7fotS0IRIZoEay1WsDCX4ElvkkvukoGMKdU/rHkI Ajg28ZIU1TmLqqZoQ0NWjuYMRpmXR8yw9Snf9BZUGIc5LtTtrXN3FbYxJfVfeBbsrmAeyaV HqpN18MhW+XytT1nHFCKV+5ubYNP5F2T3radMhNEnP6I+yGJ0YjLtGTWgtn04UNkmZ1+2Mi qyxpsvFNhNmruQkY6Si13rfymWymHqlATmPyGMxm3Ty2sIM0+cBHgFvYPKeOHfzE+yokeb3 BwYMf7xcM9dXkKfOywCqgB8IhYreYs15w1gdB2SIZND1oIcMNl 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 --- (no changes since v1) --- 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.54.0 From nobody Thu Jun 11 17:11:28 2026 Received: from smtp-usa1.onexmail.com (smtp-usa1.onexmail.com [52.205.10.60]) (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 2E8F32E6CB8 for ; Mon, 8 Jun 2026 07:09:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=52.205.10.60 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902574; cv=none; b=NpUalNoU39ffX4p0ong2Dmsn0CbaNct0I8ljPsudJGtcegg46GOvc2ILv5+b3a+OFeR47t88sYdYusoDdsv0kdnGNb4IhMGcE31nuPuXv0OcFrjRRmopWgmXnUTcdVN2WnuDTvfaRULCuZbmuGWeGWBjVx5Rqw+7o2XP1jkS1a4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780902574; c=relaxed/simple; bh=aFFbv0mVPasJ4vkv7WdyuItd2Eziqg850lmQc7oqlTE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References; b=cZYCSH/pDzaKjmhzaqTnKaDhDD/0/spX/wZBBQ3Fl0GqGGkHkO+jbgANUz0SBl4BNr562Jr/E8qsj9K41Bu4j9oelSHjq7NIVkZMofPoPHjzF2wHOfH1gzUMqtEFqXEtG8xxxjjZ3T23/ziaVcDqPk9k0X/rmjx/NxmHcnLHeb8= 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=Z+cWYcjg; arc=none smtp.client-ip=52.205.10.60 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="Z+cWYcjg" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=airkyi.com; s=altu2504; t=1780902529; bh=mHauX+D/ihkFs9NpWsK5sLJHpmTpZGy8KoVRw4UK7Wk=; h=From:To:Subject:Date:Message-Id; b=Z+cWYcjgkVXRtam6IQSG9kN2kAmtGEMxWyH7COOHaX68yHOwZQaMwBPpgU7oPl6Hy S8FukgccDIhHqPMxQxpQjmz6XE7ylbfIROxpFtgXBvQ/0jBRLclxkbK/tdx++Un5NB ZKwJ7sCszpJcwFMgqgi5FsId39M/7//b687RkDdY= X-QQ-mid: esmtpsz10t1780902528t0c0196a8 X-QQ-Originating-IP: Z5akmwnhSgVtSxE2S5oeeYmPxEpORGl4j3IzI9ZAPoM= Received: from DESKTOP-8BT1A2O.localdomain ( [58.22.7.114]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 08 Jun 2026 15:08:41 +0800 (CST) X-QQ-SSF: 0000000000000000000000000000000 X-QQ-GoodBg: 0 X-BIZMAIL-ID: 12724469660805149362 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: Nicolas Frattaroli , Sebastian Reichel , 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: Mon, 8 Jun 2026 15:08:05 +0800 Message-Id: <20260608070805.88-6-kernel@airkyi.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20260608070805.88-1-kernel@airkyi.com> References: <20260608070805.88-1-kernel@airkyi.com> X-QQ-SENDSIZE: 520 Feedback-ID: esmtpsz:airkyi.com:qybglogicsvrgz:qybglogicsvrgz6b-0 X-QQ-XMAILINFO: OarsvkCOu3SWP3sT+lkEI6JC0WIBJMHT83eXXTjDhACIGJyPeGQmrgsX m04lGkaClrMaDtv9GpdYaht98bPUku0EdFnu7X36qaqDQ9+QbCQKBQYcvuwHuGbMm5Ghv/n R7ozSTiJBTQdSIkHOhxoOoHhuwPd4d4jzwtpkb6jyFURZcUif30p2ZKyK8/8KL00HS6oMN4 jj/+ocwzTVUXVOvWgZOYha0eB4noT/7FO36vgHuOjlGBYlMOPUvKAf0vaYVHZCcsFxfT07f BJ6h7mJ71VgCnhnBOVxeFc8mNo3z+/s+48HUVVa/QYuDUTJOBKXY1jALYFm/X5YBkSNx/Xo kixzikuTpJWvyqkOOdYkpDBoCFfrITC4aeyDguNrxVRidJBgifATE1C9Q2mgBPnwqK8GSG0 BPfDxqr/FJjS/w5Fiv/o6XuVovmSA4RgcFt80Io7ekEBaNyDXqGL8cP0fAYbPkx53SLXBxE SimfXv23xJuO79+500CFeayOc7HH8gmT8/pGwvWHbig+QL4RV5grRaOWYuz0eLmN/xlS+CF WGCaQhHYNUN+pqXtsdkZ4e2YKuBmdLW4WoHh2cksUR0du7+8YxCpDUzCv7uy4oHlnImh8wx y08rtH+CMP1iNPRPDoT4ZDabPtPX2TneLPoNpCKTVaUpk/wCeK8OcDFgBsTf9V6lSsDHSl7 xku1ipgsNWF/ooqBxm5I7imI1wElbz6wsvzn7zfLITA6b5SEUwm7j+GgddUnCrSe6k6J9/L /1ablmXD+m8Wj9CcXYftSHk7rZ0YNCN48BLKbgImDjit1zqm233le8tjqdalERytj0MKeXC BXVYT28h//Pl5B38sH+SvtYdPRj/qvfykowZES2V5FaRjm0hbnDb1EmXnFXrnpxBtsKuSyO JSeyKXj35cYbJkchRRqOnzfwroeiFBi+tObjUudCW1mQyVwwCoi9tQmDaOSna3o+UOCnq7q PB2pOUUvLF+RjMhZk5HIp+euYWUF4H6uOZycGW5KR1O3KrFkIC/2RXaxb22168d3x0ab9x/ 14Hd1g/CF6ArmyNKp3dbMLNIwYdmBKnZgRyA52481+QTl4EPsihKsDilwLcKs= X-QQ-XMRINFO: NyFYKkN4Ny6FuXrnB5Ye7Aabb3ujjtK+gg== 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 --- Changes in v2: - Fix the check logic for dp->active_port (0 is valid). - Fix the uninitialized prev_port. - Remove duplicate logic from cdn_dp_switch_port(). - Fix the prototype of cdn_dp_bridge_hpd_notify(). - Properly release connector->fwnode. - Properly release next_bridge. --- drivers/gpu/drm/rockchip/Kconfig | 1 + drivers/gpu/drm/rockchip/cdn-dp-core.c | 333 ++++++++++++++++++++----- drivers/gpu/drm/rockchip/cdn-dp-core.h | 18 +- 3 files changed, 294 insertions(+), 58 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..f2eaad61ba44 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 >=3D 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 =3D NULL; + 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,50 @@ 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; + + 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->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 +664,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 +674,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 +693,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 +728,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 +736,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 +927,17 @@ 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, + struct drm_connector *connector, + 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 +948,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 +997,8 @@ static void cdn_dp_pd_event_work(struct work_struct *wo= rk) { 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 +1057,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 +1082,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 +1106,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 +1142,103 @@ static int cdn_dp_bind(struct device *dev, struct d= evice *master, void *data) return ret; } =20 + if (last_bridge) { + fwnode_handle_put(connector->fwnode); + 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) + goto out; + + 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)) { + ret =3D PTR_ERR(dp_bridge); + goto out; + } + 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) + goto out; + } + + INIT_WORK(&dp->event_work, cdn_dp_pd_event_work); + for (i =3D 0; i < dp->ports; i++) { port =3D dp->port[i]; =20 @@ -1045,7 +1252,7 @@ static int cdn_dp_bind(struct device *dev, struct dev= ice *master, void *data) if (ret) { DRM_DEV_ERROR(dev, "register EXTCON_DISP_DP notifier err\n"); - return ret; + goto out; } } =20 @@ -1054,15 +1261,29 @@ static int cdn_dp_bind(struct device *dev, struct d= evice *master, void *data) schedule_work(&dp->event_work); =20 return 0; + +out: + for (i =3D 0; i < MAX_PHY; i++) + drm_bridge_put(dp->next_bridge_list[i]); + + return ret; } =20 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 +1334,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.54.0