On Mon, Sep 08, 2025 at 03:04:21PM +0200, Neil Armstrong wrote: > 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. > > Signed-off-by: Neil Armstrong <neil.armstr...@linaro.org> > --- > drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 132 > ++++++++++++++++++++++++++++-- > 1 file changed, 124 insertions(+), 8 deletions(-)
Looking at the patch... Would it be possible to make it more generic? I think some of the RockChips also have similar combo USB+DP PHY (and similar issues). I believe, Mediatek might also have the same issue. > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c > b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c > index > 7b5af30f1d028c592500e723ecd27b54ed554709..f3f91a69dc8b81e049cd06f7ab4f04baf57776cd > 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,21 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = > { > { 0x22, 0xff, 0xff, 0xff } > }; > > +static const u32 usb3_data_lane_mapping[][2] = { > + [TYPEC_ORIENTATION_NORMAL] = { 1, 0 }, > + [TYPEC_ORIENTATION_REVERSE] = { 2, 3 }, > +}; > + > +static const u32 dp_2_data_lanes_mapping[][2] = { > + [TYPEC_ORIENTATION_NORMAL] = { 0, 1 }, > + [TYPEC_ORIENTATION_REVERSE] = { 3, 2 }, > +}; > + > +static const u32 dp_4_data_lanes_mapping[][4] = { > + [TYPEC_ORIENTATION_NORMAL] = { 0, 1, 2, 3 }, > + [TYPEC_ORIENTATION_REVERSE] = { 3, 2, 1, 0 }, > +}; > + > struct qmp_combo; > > struct qmp_combo_offsets { > @@ -4167,9 +4183,114 @@ 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_find_property(dev->of_node, "mode-switch", NULL) || > + of_find_property(dev->of_node, "orientation-switch", NULL)) { > + ret = qmp_combo_typec_register(qmp); > + if (ret) > + goto err_node_put; > + } else { At least this needs to be extracted to a function (or set of functions). > + enum typec_orientation usb3_orientation = > TYPEC_ORIENTATION_NONE; > + enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE; > + struct device_node *usb3_ep, *dp_ep; > + u32 data_lanes[4]; > + int count, i; > + > + usb3_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0); > + dp_ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, 1); > + > + if (usb3_ep) { > + ret = of_property_count_u32_elems(usb3_ep, > "data-lanes"); > + if (ret == -EINVAL) > + /* Property isn't here, ignore property */ In all thsese error cases we are leaking a ref count on usb3_ep and dp_ep. > + goto usb3_mapping_done; > + if (ret < 0) > + goto err_node_put; > + > + count = ret; > + if (count != 2) > + /* Property size is invalid, ignore property */ > + goto usb3_mapping_done; > + > + ret = of_property_read_u32_array(usb3_ep, "data-lanes", > data_lanes, count); > + if (ret) > + goto err_node_put; > + > + for (i = TYPEC_ORIENTATION_NORMAL; i <= > TYPEC_ORIENTATION_REVERSE; i++) > + if (!memcmp(data_lanes, > usb3_data_lane_mapping[i], sizeof(u32) * 2)) > + break; > + > + if (i >= TYPEC_ORIENTATION_REVERSE) > + /* Property value is invalid, ignore property */ > + goto usb3_mapping_done; > + > + usb3_orientation = i; > + } > + > +usb3_mapping_done: > + of_node_put(usb3_ep); > + > + if (dp_ep) { > + ret = of_property_count_u32_elems(dp_ep, "data-lanes"); > + if (ret == -EINVAL) > + /* Property isn't here, ignore property */ > + goto dp_mapping_done; > + if (ret < 0) > + goto err_node_put; > + > + count = ret; > + if (count != 2 && count != 4) > + /* Property size is invalid, ignore property */ > + goto dp_mapping_done; > + > + ret = of_property_read_u32_array(dp_ep, "data-lanes", > data_lanes, count); > + > + if (ret) > + goto err_node_put; > + > + for (i = TYPEC_ORIENTATION_NORMAL; i <= > TYPEC_ORIENTATION_REVERSE; i++) { > + switch (count) { > + case 2: > + ret = memcmp(data_lanes, > dp_2_data_lanes_mapping[i], > + sizeof(u32) * count); > + break; > + case 4: > + ret = memcmp(data_lanes, > dp_4_data_lanes_mapping[i], > + sizeof(u32) * count); > + break; > + } > + > + if (!ret) > + break; > + } > + > + if (i >= TYPEC_ORIENTATION_REVERSE) > + /* Property value is invalid, ignore property */ > + goto dp_mapping_done; > + > + dp_orientation = i; > + } > + > +dp_mapping_done: > + of_node_put(dp_ep); > + > + 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 +4310,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 > -- With best wishes Dmitry