Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP
switchable PHYs.
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
---
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 163 +++++++++++++++++++++++++++++++
1 file changed, 163 insertions(+)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
index 1508a4a5f57aff85318485b79528325f28a825a4..a1495a2029cf038bb65c36e42d0a4f633e544558 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
@@ -22,6 +22,8 @@
#include <linux/slab.h>
#include <linux/usb/typec.h>
#include <linux/usb/typec_mux.h>
+#include <dt-bindings/phy/phy-qcom-qmp.h>
+#include <drm/bridge/aux-bridge.h>
#include "phy-qcom-qmp-common.h"
@@ -1088,6 +1090,157 @@ static int qmp_usbc_usb_set_mode(struct phy *phy, enum phy_mode mode, int submod
return 0;
}
+static int qmp_usbc_dp_enable(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret;
+
+ if (qmp->dp_init_count) {
+ dev_err(qmp->dev, "DP already inited\n");
+ return 0;
+ }
+
+ mutex_lock(&qmp->phy_mutex);
+
+ ret = qmp_usbc_com_init(phy);
+ if (ret)
+ goto dp_init_unlock;
+
+ cfg->dp_aux_init(qmp);
+
+ qmp->dp_init_count++;
+
+dp_init_unlock:
+ mutex_unlock(&qmp->phy_mutex);
+ return ret;
+}
+
+static int qmp_usbc_dp_disable(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+
+ mutex_lock(&qmp->phy_mutex);
+
+ qmp_usbc_com_exit(phy);
+
+ qmp->dp_init_count--;
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_configure(struct phy *phy, union phy_configure_opts *opts)
+{
+ const struct phy_configure_opts_dp *dp_opts = &opts->dp;
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ mutex_lock(&qmp->phy_mutex);
+
+ memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts));
+ if (qmp->dp_opts.set_voltages) {
+ cfg->configure_dp_tx(qmp);
+ qmp->dp_opts.set_voltages = 0;
+ }
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_calibrate(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ int ret = 0;
+
+ mutex_lock(&qmp->phy_mutex);
+
+ if (cfg->calibrate_dp_phy) {
+ ret = cfg->calibrate_dp_phy(qmp);
+ if (ret) {
+ dev_err(qmp->dev, "dp calibrate err(%d)\n", ret);
+ mutex_unlock(&qmp->phy_mutex);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&qmp->phy_mutex);
+ return 0;
+}
+
+static int qmp_usbc_dp_serdes_init(struct qmp_usbc *qmp)
+{
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+ void __iomem *serdes = qmp->dp_serdes;
+ const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
+
+ qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl,
+ cfg->dp_serdes_tbl_num);
+
+ switch (dp_opts->link_rate) {
+ case 1620:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr,
+ cfg->serdes_tbl_rbr_num);
+ break;
+ case 2700:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr,
+ cfg->serdes_tbl_hbr_num);
+ break;
+ case 5400:
+ qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2,
+ cfg->serdes_tbl_hbr2_num);
+ break;
+ default:
+ /* Other link rates aren't supported */
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qmp_usbc_dp_power_on(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+ const struct qmp_phy_cfg *cfg = qmp->cfg;
+
+ void __iomem *tx = qmp->dp_tx;
+ void __iomem *tx2 = qmp->dp_tx2;
+
+ mutex_lock(&qmp->phy_mutex);
+
+ qmp_usbc_dp_serdes_init(qmp);
+
+ qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1);
+ qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2);
+
+ /* Configure special DP tx tunings */
+ cfg->configure_dp_tx(qmp);
+
+ /* Configure link rate, swing, etc. */
+ cfg->configure_dp_phy(qmp);
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
+static int qmp_usbc_dp_power_off(struct phy *phy)
+{
+ struct qmp_usbc *qmp = phy_get_drvdata(phy);
+
+ mutex_lock(&qmp->phy_mutex);
+
+ /* Assert DP PHY power down */
+ writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
+
+ mutex_unlock(&qmp->phy_mutex);
+
+ return 0;
+}
+
static const struct phy_ops qmp_usbc_usb_phy_ops = {
.init = qmp_usbc_usb_enable,
.exit = qmp_usbc_usb_disable,
@@ -1095,6 +1248,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = {
.owner = THIS_MODULE,
};
+static const struct phy_ops qmp_usbc_dp_phy_ops = {
+ .init = qmp_usbc_dp_enable,
+ .exit = qmp_usbc_dp_disable,
+ .configure = qmp_usbc_dp_configure,
+ .calibrate = qmp_usbc_dp_calibrate,
+ .power_on = qmp_usbc_dp_power_on,
+ .power_off = qmp_usbc_dp_power_off,
+ .owner = THIS_MODULE,
+};
+
static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp)
{
const struct qmp_phy_cfg *cfg = qmp->cfg;
--
2.34.1
On Wed, Aug 20, 2025 at 05:34:51PM +0800, Xiangxu Yin wrote: > Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP > switchable PHYs. > > Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> > --- > drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 163 +++++++++++++++++++++++++++++++ > 1 file changed, 163 insertions(+) > > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c > index 1508a4a5f57aff85318485b79528325f28a825a4..a1495a2029cf038bb65c36e42d0a4f633e544558 100644 > --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c > @@ -22,6 +22,8 @@ > #include <linux/slab.h> > #include <linux/usb/typec.h> > #include <linux/usb/typec_mux.h> > +#include <dt-bindings/phy/phy-qcom-qmp.h> > +#include <drm/bridge/aux-bridge.h> This one is not necessary yet > > #include "phy-qcom-qmp-common.h" > [...] > static const struct phy_ops qmp_usbc_usb_phy_ops = { > .init = qmp_usbc_usb_enable, > .exit = qmp_usbc_usb_disable, > @@ -1095,6 +1248,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { > .owner = THIS_MODULE, > }; > > +static const struct phy_ops qmp_usbc_dp_phy_ops = { Please try restructuring your patches so that there are no unused warnings in the middle of the series. You can split the next patch into 'parse' and 'enable' parts, then squash this patch into the 'enable' one. > + .init = qmp_usbc_dp_enable, > + .exit = qmp_usbc_dp_disable, > + .configure = qmp_usbc_dp_configure, > + .calibrate = qmp_usbc_dp_calibrate, > + .power_on = qmp_usbc_dp_power_on, > + .power_off = qmp_usbc_dp_power_off, > + .owner = THIS_MODULE, > +}; > + > static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) > { > const struct qmp_phy_cfg *cfg = qmp->cfg; > > -- > 2.34.1 > -- With best wishes Dmitry
On 8/20/2025 7:45 PM, Dmitry Baryshkov wrote: > On Wed, Aug 20, 2025 at 05:34:51PM +0800, Xiangxu Yin wrote: >> Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP >> switchable PHYs. >> >> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> >> --- >> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 163 +++++++++++++++++++++++++++++++ >> 1 file changed, 163 insertions(+) >> >> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c >> index 1508a4a5f57aff85318485b79528325f28a825a4..a1495a2029cf038bb65c36e42d0a4f633e544558 100644 >> --- a/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c >> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-usbc.c >> @@ -22,6 +22,8 @@ >> #include <linux/slab.h> >> #include <linux/usb/typec.h> >> #include <linux/usb/typec_mux.h> >> +#include <dt-bindings/phy/phy-qcom-qmp.h> >> +#include <drm/bridge/aux-bridge.h> > This one is not necessary yet Ok, will remove unnecessary aux-bridge related part. >> >> #include "phy-qcom-qmp-common.h" >> > [...] > >> static const struct phy_ops qmp_usbc_usb_phy_ops = { >> .init = qmp_usbc_usb_enable, >> .exit = qmp_usbc_usb_disable, >> @@ -1095,6 +1248,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { >> .owner = THIS_MODULE, >> }; >> >> +static const struct phy_ops qmp_usbc_dp_phy_ops = { > Please try restructuring your patches so that there are no unused > warnings in the middle of the series. You can split the next patch into > 'parse' and 'enable' parts, then squash this patch into the 'enable' > one. You mean it's better to define and register new functions in the same patch where they're first used, to avoid unused warnings? And for things like parse_dt and phy_ops, it's fine to split them into separate patches if each part is used right away? > >> + .init = qmp_usbc_dp_enable, >> + .exit = qmp_usbc_dp_disable, >> + .configure = qmp_usbc_dp_configure, >> + .calibrate = qmp_usbc_dp_calibrate, >> + .power_on = qmp_usbc_dp_power_on, >> + .power_off = qmp_usbc_dp_power_off, >> + .owner = THIS_MODULE, >> +}; >> + >> static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) >> { >> const struct qmp_phy_cfg *cfg = qmp->cfg; >> >> -- >> 2.34.1 >>
On Wed, Aug 27, 2025 at 08:17:39PM +0800, Xiangxu Yin wrote: > > On 8/20/2025 7:45 PM, Dmitry Baryshkov wrote: > > On Wed, Aug 20, 2025 at 05:34:51PM +0800, Xiangxu Yin wrote: > >> Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP > >> switchable PHYs. > >> > >> Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com> > >> --- > >> drivers/phy/qualcomm/phy-qcom-qmp-usbc.c | 163 +++++++++++++++++++++++++++++++ > >> 1 file changed, 163 insertions(+) > >> > >> @@ -1095,6 +1248,16 @@ static const struct phy_ops qmp_usbc_usb_phy_ops = { > >> .owner = THIS_MODULE, > >> }; > >> > >> +static const struct phy_ops qmp_usbc_dp_phy_ops = { > > Please try restructuring your patches so that there are no unused > > warnings in the middle of the series. You can split the next patch into > > 'parse' and 'enable' parts, then squash this patch into the 'enable' > > one. > > > You mean it's better to define and register new functions in the same patch > > where they're first used, to avoid unused warnings? And for things like parse_dt and phy_ops, > > it's fine to split them into separate patches if each part is used right away? Yes. > > > > > >> + .init = qmp_usbc_dp_enable, > >> + .exit = qmp_usbc_dp_disable, > >> + .configure = qmp_usbc_dp_configure, > >> + .calibrate = qmp_usbc_dp_calibrate, > >> + .power_on = qmp_usbc_dp_power_on, > >> + .power_off = qmp_usbc_dp_power_off, > >> + .owner = THIS_MODULE, > >> +}; > >> + > >> static void qmp_usbc_enable_autonomous_mode(struct qmp_usbc *qmp) > >> { > >> const struct qmp_phy_cfg *cfg = qmp->cfg; > >> > >> -- > >> 2.34.1 > >> -- With best wishes Dmitry
© 2016 - 2025 Red Hat, Inc.