Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

phy: qcom: qmp-combo: register a typec mux to change the QMPPHY_MODE

Register a typec mux in order to change the PHY mode on the Type-C
mux events depending on the mode and the svid when in Altmode setup.

The DisplayPort phy should be left enabled if is still powered on
by the DRM DisplayPort controller, so bail out until the DisplayPort
PHY is not powered off.

The Type-C Mode/SVID only changes on plug/unplug, and USB SAFE states
will be set in between of USB-Only, Combo and DisplayPort Only so
this will leave enough time to the DRM DisplayPort controller to
turn of the DisplayPort PHY.

Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
[konrad: renaming, rewording, bug fixes]
Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on Lenovo Thinkpad T14S
Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-5-43272d6eca92@oss.qualcomm.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Neil Armstrong and committed by
Vinod Koul
89627713 dd331112

+113 -5
+113 -5
drivers/phy/qualcomm/phy-qcom-qmp-combo.c
··· 19 19 #include <linux/reset.h> 20 20 #include <linux/slab.h> 21 21 #include <linux/usb/typec.h> 22 + #include <linux/usb/typec_dp.h> 22 23 #include <linux/usb/typec_mux.h> 23 24 24 25 #include <drm/bridge/aux-bridge.h> ··· 1869 1868 1870 1869 struct typec_switch_dev *sw; 1871 1870 enum typec_orientation orientation; 1871 + 1872 + struct typec_mux_dev *mux; 1872 1873 }; 1873 1874 1874 1875 static void qmp_v3_dp_aux_init(struct qmp_combo *qmp); ··· 3805 3802 return 0; 3806 3803 } 3807 3804 3808 - static void qmp_combo_typec_unregister(void *data) 3805 + static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) 3806 + { 3807 + struct qmp_combo *qmp = typec_mux_get_drvdata(mux); 3808 + const struct qmp_phy_cfg *cfg = qmp->cfg; 3809 + enum qmpphy_mode new_mode; 3810 + unsigned int svid; 3811 + 3812 + guard(mutex)(&qmp->phy_mutex); 3813 + 3814 + if (state->alt) 3815 + svid = state->alt->svid; 3816 + else 3817 + svid = 0; 3818 + 3819 + if (svid == USB_TYPEC_DP_SID) { 3820 + switch (state->mode) { 3821 + /* DP Only */ 3822 + case TYPEC_DP_STATE_C: 3823 + case TYPEC_DP_STATE_E: 3824 + new_mode = QMPPHY_MODE_DP_ONLY; 3825 + break; 3826 + 3827 + /* DP + USB */ 3828 + case TYPEC_DP_STATE_D: 3829 + case TYPEC_DP_STATE_F: 3830 + 3831 + /* Safe fallback...*/ 3832 + default: 3833 + new_mode = QMPPHY_MODE_USB3DP; 3834 + break; 3835 + } 3836 + } else { 3837 + /* No DP SVID => don't care, assume it's just USB3 */ 3838 + new_mode = QMPPHY_MODE_USB3_ONLY; 3839 + } 3840 + 3841 + if (new_mode == qmp->qmpphy_mode) { 3842 + dev_dbg(qmp->dev, "typec_mux_set: same qmpphy mode, bail out\n"); 3843 + return 0; 3844 + } 3845 + 3846 + if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) { 3847 + dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n"); 3848 + return 0; 3849 + } 3850 + 3851 + dev_dbg(qmp->dev, "typec_mux_set: switching from qmpphy mode %d to %d\n", 3852 + qmp->qmpphy_mode, new_mode); 3853 + 3854 + qmp->qmpphy_mode = new_mode; 3855 + 3856 + if (qmp->init_count) { 3857 + if (qmp->usb_init_count) 3858 + qmp_combo_usb_power_off(qmp->usb_phy); 3859 + 3860 + if (qmp->dp_init_count) 3861 + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); 3862 + 3863 + qmp_combo_com_exit(qmp, true); 3864 + 3865 + /* Now everything's powered down, power up the right PHYs */ 3866 + qmp_combo_com_init(qmp, true); 3867 + 3868 + if (new_mode == QMPPHY_MODE_DP_ONLY) { 3869 + if (qmp->usb_init_count) 3870 + qmp->usb_init_count--; 3871 + } 3872 + 3873 + if (new_mode == QMPPHY_MODE_USB3DP || new_mode == QMPPHY_MODE_USB3_ONLY) { 3874 + qmp_combo_usb_power_on(qmp->usb_phy); 3875 + if (!qmp->usb_init_count) 3876 + qmp->usb_init_count++; 3877 + } 3878 + 3879 + if (new_mode == QMPPHY_MODE_DP_ONLY || new_mode == QMPPHY_MODE_USB3DP) { 3880 + if (qmp->dp_init_count) 3881 + cfg->dp_aux_init(qmp); 3882 + } 3883 + } 3884 + 3885 + return 0; 3886 + } 3887 + 3888 + static void qmp_combo_typec_switch_unregister(void *data) 3809 3889 { 3810 3890 struct qmp_combo *qmp = data; 3811 3891 3812 3892 typec_switch_unregister(qmp->sw); 3813 3893 } 3814 3894 3815 - static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) 3895 + static void qmp_combo_typec_mux_unregister(void *data) 3896 + { 3897 + struct qmp_combo *qmp = data; 3898 + 3899 + typec_mux_unregister(qmp->mux); 3900 + } 3901 + 3902 + static int qmp_combo_typec_register(struct qmp_combo *qmp) 3816 3903 { 3817 3904 struct typec_switch_desc sw_desc = {}; 3905 + struct typec_mux_desc mux_desc = { }; 3818 3906 struct device *dev = qmp->dev; 3907 + int ret; 3819 3908 3820 3909 sw_desc.drvdata = qmp; 3821 3910 sw_desc.fwnode = dev->fwnode; ··· 3918 3823 return PTR_ERR(qmp->sw); 3919 3824 } 3920 3825 3921 - return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp); 3826 + ret = devm_add_action_or_reset(dev, qmp_combo_typec_switch_unregister, qmp); 3827 + if (ret) 3828 + return ret; 3829 + 3830 + mux_desc.drvdata = qmp; 3831 + mux_desc.fwnode = dev->fwnode; 3832 + mux_desc.set = qmp_combo_typec_mux_set; 3833 + qmp->mux = typec_mux_register(dev, &mux_desc); 3834 + if (IS_ERR(qmp->mux)) { 3835 + dev_err(dev, "Unable to register typec mux: %pe\n", qmp->mux); 3836 + return PTR_ERR(qmp->mux); 3837 + } 3838 + 3839 + return devm_add_action_or_reset(dev, qmp_combo_typec_mux_unregister, qmp); 3922 3840 } 3923 3841 #else 3924 - static int qmp_combo_typec_switch_register(struct qmp_combo *qmp) 3842 + static int qmp_combo_typec_register(struct qmp_combo *qmp) 3925 3843 { 3926 3844 return 0; 3927 3845 } ··· 4167 4059 if (ret) 4168 4060 goto err_node_put; 4169 4061 4170 - ret = qmp_combo_typec_switch_register(qmp); 4062 + ret = qmp_combo_typec_register(qmp); 4171 4063 if (ret) 4172 4064 goto err_node_put; 4173 4065