Skip to content

Commit f842daf

Browse files
superna9999vinodkoul
authored andcommitted
phy: qcom: qmp-combo: get the USB3 & DisplayPort lanes mapping from DT
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> Tested-by: Xilin Wu <sophon@radxa.com> # qcs6490-radxa-dragon-q6a Reviewed-by: Abel Vesa <abel.vesa@linaro.org> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> Link: https://patch.msgid.link/20251119-topic-x1e80100-hdmi-v7-2-2bee0e66cc1b@linaro.org Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 3faa2d0 commit f842daf

1 file changed

Lines changed: 134 additions & 8 deletions

File tree

drivers/phy/qualcomm/phy-qcom-qmp-combo.c

Lines changed: 134 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/module.h>
1414
#include <linux/of.h>
1515
#include <linux/of_address.h>
16+
#include <linux/of_graph.h>
1617
#include <linux/phy/phy.h>
1718
#include <linux/platform_device.h>
1819
#include <linux/regulator/consumer.h>
@@ -1739,6 +1740,26 @@ static const u8 qmp_dp_v6_pre_emphasis_hbr_rbr[4][4] = {
17391740
{ 0x22, 0xff, 0xff, 0xff }
17401741
};
17411742

1743+
struct qmp_combo_lane_mapping {
1744+
unsigned int lanes_count;
1745+
enum typec_orientation orientation;
1746+
u32 lanes[4];
1747+
};
1748+
1749+
static const struct qmp_combo_lane_mapping usb3_data_lanes[] = {
1750+
{ 2, TYPEC_ORIENTATION_NORMAL, { 1, 0 }},
1751+
{ 2, TYPEC_ORIENTATION_REVERSE, { 2, 3 }},
1752+
};
1753+
1754+
static const struct qmp_combo_lane_mapping dp_data_lanes[] = {
1755+
{ 1, TYPEC_ORIENTATION_NORMAL, { 3 }},
1756+
{ 1, TYPEC_ORIENTATION_REVERSE, { 0 }},
1757+
{ 2, TYPEC_ORIENTATION_NORMAL, { 3, 2 }},
1758+
{ 2, TYPEC_ORIENTATION_REVERSE, { 0, 1 }},
1759+
{ 4, TYPEC_ORIENTATION_NORMAL, { 3, 2, 1, 0 }},
1760+
{ 4, TYPEC_ORIENTATION_REVERSE, { 0, 1, 2, 3 }},
1761+
};
1762+
17421763
struct qmp_combo;
17431764

17441765
struct qmp_combo_offsets {
@@ -4079,6 +4100,84 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, const struct of_phand
40794100
return ERR_PTR(-EINVAL);
40804101
}
40814102

4103+
static void qmp_combo_find_lanes_orientation(const struct qmp_combo_lane_mapping *mapping,
4104+
unsigned int mapping_count,
4105+
u32 *lanes, unsigned int lanes_count,
4106+
enum typec_orientation *orientation)
4107+
{
4108+
int i;
4109+
4110+
for (i = 0; i < mapping_count; i++) {
4111+
if (mapping[i].lanes_count != lanes_count)
4112+
continue;
4113+
if (!memcmp(mapping[i].lanes, lanes, sizeof(u32) * lanes_count)) {
4114+
*orientation = mapping[i].orientation;
4115+
return;
4116+
}
4117+
}
4118+
}
4119+
4120+
static int qmp_combo_get_dt_lanes_mapping(struct device *dev, unsigned int endpoint,
4121+
u32 *data_lanes, unsigned int max,
4122+
unsigned int *count)
4123+
{
4124+
struct device_node *ep __free(device_node) = NULL;
4125+
int ret;
4126+
4127+
ep = of_graph_get_endpoint_by_regs(dev->of_node, 0, endpoint);
4128+
if (!ep)
4129+
return -EINVAL;
4130+
4131+
ret = of_property_count_u32_elems(ep, "data-lanes");
4132+
if (ret < 0)
4133+
return ret;
4134+
4135+
*count = ret;
4136+
if (*count > max)
4137+
return -EINVAL;
4138+
4139+
return of_property_read_u32_array(ep, "data-lanes", data_lanes,
4140+
min_t(unsigned int, *count, max));
4141+
}
4142+
4143+
static int qmp_combo_get_dt_dp_orientation(struct device *dev,
4144+
enum typec_orientation *orientation)
4145+
{
4146+
unsigned int count;
4147+
u32 data_lanes[4];
4148+
int ret;
4149+
4150+
/* DP is described on the first endpoint of the first port */
4151+
ret = qmp_combo_get_dt_lanes_mapping(dev, 0, data_lanes, 4, &count);
4152+
if (ret < 0)
4153+
return ret == -EINVAL ? 0 : ret;
4154+
4155+
/* Search for a match and only update orientation if found */
4156+
qmp_combo_find_lanes_orientation(dp_data_lanes, ARRAY_SIZE(dp_data_lanes),
4157+
data_lanes, count, orientation);
4158+
4159+
return 0;
4160+
}
4161+
4162+
static int qmp_combo_get_dt_usb3_orientation(struct device *dev,
4163+
enum typec_orientation *orientation)
4164+
{
4165+
unsigned int count;
4166+
u32 data_lanes[2];
4167+
int ret;
4168+
4169+
/* USB3 is described on the second endpoint of the first port */
4170+
ret = qmp_combo_get_dt_lanes_mapping(dev, 1, data_lanes, 2, &count);
4171+
if (ret < 0)
4172+
return ret == -EINVAL ? 0 : ret;
4173+
4174+
/* Search for a match and only update orientation if found */
4175+
qmp_combo_find_lanes_orientation(usb3_data_lanes, ARRAY_SIZE(usb3_data_lanes),
4176+
data_lanes, count, orientation);
4177+
4178+
return 0;
4179+
}
4180+
40824181
static int qmp_combo_probe(struct platform_device *pdev)
40834182
{
40844183
struct qmp_combo *qmp;
@@ -4130,9 +4229,41 @@ static int qmp_combo_probe(struct platform_device *pdev)
41304229
if (ret)
41314230
goto err_node_put;
41324231

4133-
ret = qmp_combo_typec_register(qmp);
4134-
if (ret)
4135-
goto err_node_put;
4232+
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
4233+
4234+
if (of_property_present(dev->of_node, "mode-switch") ||
4235+
of_property_present(dev->of_node, "orientation-switch")) {
4236+
ret = qmp_combo_typec_register(qmp);
4237+
if (ret)
4238+
goto err_node_put;
4239+
} else {
4240+
enum typec_orientation dp_orientation = TYPEC_ORIENTATION_NONE;
4241+
enum typec_orientation usb3_orientation = TYPEC_ORIENTATION_NONE;
4242+
4243+
ret = qmp_combo_get_dt_dp_orientation(dev, &dp_orientation);
4244+
if (ret)
4245+
goto err_node_put;
4246+
4247+
ret = qmp_combo_get_dt_usb3_orientation(dev, &usb3_orientation);
4248+
if (ret)
4249+
goto err_node_put;
4250+
4251+
if (dp_orientation == TYPEC_ORIENTATION_NONE &&
4252+
usb3_orientation != TYPEC_ORIENTATION_NONE) {
4253+
qmp->qmpphy_mode = QMPPHY_MODE_USB3_ONLY;
4254+
qmp->orientation = usb3_orientation;
4255+
} else if (usb3_orientation == TYPEC_ORIENTATION_NONE &&
4256+
dp_orientation != TYPEC_ORIENTATION_NONE) {
4257+
qmp->qmpphy_mode = QMPPHY_MODE_DP_ONLY;
4258+
qmp->orientation = dp_orientation;
4259+
} else if (dp_orientation != TYPEC_ORIENTATION_NONE &&
4260+
dp_orientation == usb3_orientation) {
4261+
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
4262+
qmp->orientation = dp_orientation;
4263+
} else {
4264+
dev_warn(dev, "unable to determine orientation & mode from data-lanes");
4265+
}
4266+
}
41364267

41374268
ret = drm_aux_bridge_register(dev);
41384269
if (ret)
@@ -4152,11 +4283,6 @@ static int qmp_combo_probe(struct platform_device *pdev)
41524283
if (ret)
41534284
goto err_node_put;
41544285

4155-
/*
4156-
* The hw default is USB3_ONLY, but USB3+DP mode lets us more easily
4157-
* check both sub-blocks' init tables for blunders at probe time.
4158-
*/
4159-
qmp->qmpphy_mode = QMPPHY_MODE_USB3DP;
41604286

41614287
qmp->usb_phy = devm_phy_create(dev, usb_np, &qmp_combo_usb_phy_ops);
41624288
if (IS_ERR(qmp->usb_phy)) {

0 commit comments

Comments
 (0)