From: Neil Armstrong <neil.armstrong@linaro.org>
To: Vinod Koul <vkoul@kernel.org>,
Kishon Vijay Abraham I <kishon@kernel.org>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Bjorn Andersson <andersson@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>
Cc: Xilin Wu <sophon@radxa.com>,
linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Neil Armstrong <neil.armstrong@linaro.org>,
Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Subject: [PATCH v5 2/3] phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT
Date: Mon, 06 Oct 2025 15:55:04 +0200 [thread overview]
Message-ID: <20251006-topic-x1e80100-hdmi-v5-2-c006311d59d7@linaro.org> (raw)
In-Reply-To: <20251006-topic-x1e80100-hdmi-v5-0-c006311d59d7@linaro.org>
The QMP USB3/DP Combo PHY hosts an USB3 phy and a DP PHY on top
of a combo glue to route either lanes to the 4 shared physical lanes.
The routing of the lanes can be:
- 2 DP + 2 USB3
- 4 DP
- 2 USB3
Get the lanes mapping from DT and stop registering the USB-C
muxes in favor of a static mode and orientation detemined
by the lanes mapping.
This allows supporting boards with direct connection of USB3 and
DisplayPort lanes to the QMP Combo PHY lanes, not using the
USB-C Altmode feature.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
---
drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 145 ++++++++++++++++++++++++++++--
1 file changed, 137 insertions(+), 8 deletions(-)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index 7b5af30f1d028c592500e723ecd27b54ed554709..da1823fa5daf316cdec72cdb03159f02961f8545 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
@@ -1744,6 +1745,26 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = {
{ 0x22, 0xff, 0xff, 0xff }
};
+struct qmp_combo_lane_mapping {
+ unsigned int lanes_count;
+ enum typec_orientation orientation;
+ u32 lanes[4];
+};
+
+static const struct qmp_combo_lane_mapping usb3_data_lanes[] = {
+ { 2, TYPEC_ORIENTATION_NORMAL, { 1, 0 }},
+ { 2, TYPEC_ORIENTATION_REVERSE, { 2, 3 }},
+};
+
+static const struct qmp_combo_lane_mapping dp_data_lanes[] = {
+ { 1, TYPEC_ORIENTATION_NORMAL, { 3 }},
+ { 1, TYPEC_ORIENTATION_REVERSE, { 0 }},
+ { 2, TYPEC_ORIENTATION_NORMAL, { 3, 2 }},
+ { 2, TYPEC_ORIENTATION_REVERSE, { 0, 1 }},
+ { 4, TYPEC_ORIENTATION_NORMAL, { 3, 2, 1, 0 }},
+ { 4, TYPEC_ORIENTATION_REVERSE, { 0, 1, 2, 3 }},
+};
+
struct qmp_combo;
struct qmp_combo_offsets {
@@ -4117,6 +4138,87 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand
return ERR_PTR(-EINVAL);
}
+static void qmp_combo_find_lanes_orientation(const struct qmp_combo_lane_mapping *mapping,
+ unsigned int mapping_count,
+ u32 *lanes, unsigned int lanes_count,
+ enum typec_orientation *orientation)
+{
+ int i;
+
+ for (i = 0; i < mapping_count; i++) {
+ if (mapping[i].lanes_count != lanes_count)
+ continue;
+ if (!memcmp(mapping[i].lanes, lanes, sizeof(u32) * lanes_count)) {
+ *orientation = mapping[i].orientation;
+ return;
+ }
+ }
+}
+
+static int qmp_combo_get_dt_lanes_mapping(struct device *dev, unsigned int endpoint,
+ u32 *data_lanes, unsigned int max,
+ unsigned int *count)
+{
+ struct device_node *ep;
+ int ret;
+
+ ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, endpoint);
+ if (!ep)
+ return -EINVAL;
+
+ ret = of_property_count_u32_elems(ep, "data-lanes");
+ if (ret < 0)
+ goto err_node_put;
+
+ *count = ret;
+
+ ret = of_property_read_u32_array(ep, "data-lanes", data_lanes,
+ max_t(unsigned int, *count, max));
+
+err_node_put:
+ of_node_put(ep);
+
+ return ret;
+}
+
+static int qmp_combo_get_dt_dp_orientation(struct device *dev,
+ enum typec_orientation *orientation)
+{
+ unsigned int count;
+ u32 data_lanes[4];
+ int ret;
+
+ /* DP is described on the first endpoint of the first port */
+ ret = qmp_combo_get_dt_lanes_mapping(dev, 0, data_lanes, 4, &count);
+ if (ret < 0)
+ return ret == -EINVAL ? 0 : ret;
+
+ /* Search for a match and only update orientation if found */
+ qmp_combo_find_lanes_orientation(dp_data_lanes, ARRAY_SIZE(dp_data_lanes),
+ data_lanes, count, orientation);
+
+ return 0;
+}
+
+static int qmp_combo_get_dt_usb3_orientation(struct device *dev,
+ enum typec_orientation *orientation)
+{
+ unsigned int count;
+ u32 data_lanes[2];
+ int ret;
+
+ /* USB3 is described on the second endpoint of the first port */
+ ret = qmp_combo_get_dt_lanes_mapping(dev, 1, data_lanes, 2, &count);
+ if (ret < 0)
+ return ret == -EINVAL ? 0 : ret;
+
+ /* Search for a match and only update orientation if found */
+ qmp_combo_find_lanes_orientation(usb3_data_lanes, ARRAY_SIZE(usb3_data_lanes),
+ data_lanes, count, orientation);
+
+ return 0;
+}
+
static int qmp_combo_probe(struct platform_device *pdev)
{
struct qmp_combo *qmp;
@@ -4167,9 +4269,41 @@ static int qmp_combo_probe(struct platform_device *pdev)
if (ret)
goto err_node_put;
- ret = qmp_combo_typec_register(qmp);
- if (ret)
- goto err_node_put;
+ qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
+
+ if (of_property_present(dev->of_node, "mode-switch") ||
+ of_property_present(dev->of_node, "orientation-switch")) {
+ ret = qmp_combo_typec_register(qmp);
+ if (ret)
+ goto err_node_put;
+ } else {
+ enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE;
+ enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE;
+
+ ret = qmp_combo_get_dt_dp_orientation(dev, &dp_orientation);
+ if (ret)
+ goto err_node_put;
+
+ ret = qmp_combo_get_dt_usb3_orientation(dev, &usb3_orientation);
+ if (ret)
+ goto err_node_put;
+
+ if (dp_orientation == TYPEC_ORIENTATION_NONE &&
+ usb3_orientation != TYPEC_ORIENTATION_NONE) {
+ qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY;
+ qmp->orientation = usb3_orientation;
+ } else if (usb3_orientation == TYPEC_ORIENTATION_NONE &&
+ dp_orientation != TYPEC_ORIENTATION_NONE) {
+ qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY;
+ qmp->orientation = dp_orientation;
+ } else if (dp_orientation != TYPEC_ORIENTATION_NONE &&
+ dp_orientation == usb3_orientation) {
+ qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
+ qmp->orientation = dp_orientation;
+ } else {
+ dev_warn(dev, "unable to determine orientation & mode from data-lanes");
+ }
+ }
ret = drm_aux_bridge_register(dev);
if (ret)
@@ -4189,11 +4323,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
if (ret)
goto err_node_put;
- /*
- * The hw default is USB3_ONLY, but USB3+DP mode lets us more easily
- * check both sub-blocks' init tables for blunders at probe time.
- */
- qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops);
if (IS_ERR(qmp->usb_phy)) {
--
2.34.1
next prev parent reply other threads:[~2025-10-06 13:55 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-06 13:55 [PATCH v5 0/3] arm64: qcom: x1e78100-lenovo-thinkpad-t14s: add support for HDMI output Neil Armstrong
2025-10-06 13:55 ` [PATCH v5 1/3] dt-bindings: phy: qcom,sc8280xp-qmp-usb43dp-phy: Document lanes mapping when not using in USB-C complex Neil Armstrong
2025-10-09 20:26 ` Rob Herring (Arm)
2025-10-06 13:55 ` Neil Armstrong [this message]
2025-10-08 9:31 ` [PATCH v5 2/3] phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT Konrad Dybcio
2025-10-09 16:42 ` Neil Armstrong
2025-10-10 8:49 ` Konrad Dybcio
2025-10-10 15:28 ` Neil Armstrong
2025-10-09 14:51 ` Xilin Wu
2025-10-09 16:38 ` Neil Armstrong
2025-10-06 13:55 ` [PATCH v5 3/3] arm64: dts: qcom: x1e78100-lenovo-thinkpad-t14s: add HDMI nodes Neil Armstrong
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251006-topic-x1e80100-hdmi-v5-2-c006311d59d7@linaro.org \
--to=neil.armstrong@linaro.org \
--cc=andersson@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dmitry.baryshkov@oss.qualcomm.com \
--cc=kishon@kernel.org \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-phy@lists.infradead.org \
--cc=robh@kernel.org \
--cc=sophon@radxa.com \
--cc=vkoul@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).