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-usbc: Add DP PHY ops for USB/DP switchable Type-C PHYs

Define qmp_usbc_dp_phy_ops struct to support DP mode on USB/DP
switchable PHYs.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Xiangxu Yin <xiangxu.yin@oss.qualcomm.com>
Link: https://patch.msgid.link/20251215-add-displayport-support-for-qcs615-platform-v8-9-cbc72c88a44e@oss.qualcomm.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Xiangxu Yin and committed by
Vinod Koul
f3198fde 9ab26cb7

+193 -1
+193 -1
drivers/phy/qualcomm/phy-qcom-qmp-usbc.c
··· 29 29 #include "phy-qcom-qmp.h" 30 30 #include "phy-qcom-qmp-pcs-misc-v3.h" 31 31 32 + #include "phy-qcom-qmp-dp-phy.h" 33 + 32 34 #define PHY_INIT_COMPLETE_TIMEOUT 10000 33 35 #define SW_PORTSELECT_VAL BIT(0) 34 36 #define SW_PORTSELECT_MUX BIT(1) ··· 713 711 return 0; 714 712 } 715 713 714 + static int qmp_usbc_dp_enable(struct phy *phy) 715 + { 716 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 717 + const struct qmp_phy_cfg *cfg = qmp->cfg; 718 + int ret; 719 + 720 + if (qmp->dp_init_count) { 721 + dev_err(qmp->dev, "DP already inited\n"); 722 + return 0; 723 + } 724 + 725 + mutex_lock(&qmp->phy_mutex); 726 + 727 + ret = qmp_usbc_com_init(phy); 728 + if (ret) 729 + goto dp_init_unlock; 730 + 731 + qmp_usbc_set_phy_mode(qmp, true); 732 + 733 + cfg->dp_aux_init(qmp); 734 + 735 + qmp->dp_init_count++; 736 + 737 + dp_init_unlock: 738 + mutex_unlock(&qmp->phy_mutex); 739 + return ret; 740 + } 741 + 742 + static int qmp_usbc_dp_disable(struct phy *phy) 743 + { 744 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 745 + 746 + mutex_lock(&qmp->phy_mutex); 747 + 748 + qmp_usbc_com_exit(phy); 749 + 750 + qmp->dp_init_count--; 751 + 752 + mutex_unlock(&qmp->phy_mutex); 753 + 754 + return 0; 755 + } 756 + 757 + static int qmp_usbc_dp_configure(struct phy *phy, union phy_configure_opts *opts) 758 + { 759 + const struct phy_configure_opts_dp *dp_opts = &opts->dp; 760 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 761 + const struct qmp_phy_cfg *cfg = qmp->cfg; 762 + 763 + mutex_lock(&qmp->phy_mutex); 764 + 765 + memcpy(&qmp->dp_opts, dp_opts, sizeof(*dp_opts)); 766 + if (qmp->dp_opts.set_voltages) { 767 + cfg->configure_dp_tx(qmp); 768 + qmp->dp_opts.set_voltages = 0; 769 + } 770 + 771 + mutex_unlock(&qmp->phy_mutex); 772 + 773 + return 0; 774 + } 775 + 776 + static int qmp_usbc_dp_calibrate(struct phy *phy) 777 + { 778 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 779 + const struct qmp_phy_cfg *cfg = qmp->cfg; 780 + int ret = 0; 781 + 782 + mutex_lock(&qmp->phy_mutex); 783 + 784 + if (cfg->calibrate_dp_phy) { 785 + ret = cfg->calibrate_dp_phy(qmp); 786 + if (ret) { 787 + dev_err(qmp->dev, "dp calibrate err(%d)\n", ret); 788 + mutex_unlock(&qmp->phy_mutex); 789 + return ret; 790 + } 791 + } 792 + 793 + mutex_unlock(&qmp->phy_mutex); 794 + return 0; 795 + } 796 + 797 + static int qmp_usbc_dp_serdes_init(struct qmp_usbc *qmp) 798 + { 799 + const struct qmp_phy_cfg *cfg = qmp->cfg; 800 + void __iomem *serdes = qmp->dp_serdes; 801 + const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts; 802 + 803 + qmp_configure(qmp->dev, serdes, cfg->dp_serdes_tbl, 804 + cfg->dp_serdes_tbl_num); 805 + 806 + switch (dp_opts->link_rate) { 807 + case 1620: 808 + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_rbr, 809 + cfg->serdes_tbl_rbr_num); 810 + break; 811 + case 2700: 812 + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr, 813 + cfg->serdes_tbl_hbr_num); 814 + break; 815 + case 5400: 816 + qmp_configure(qmp->dev, serdes, cfg->serdes_tbl_hbr2, 817 + cfg->serdes_tbl_hbr2_num); 818 + break; 819 + default: 820 + /* Other link rates aren't supported */ 821 + return -EINVAL; 822 + } 823 + 824 + return 0; 825 + } 826 + 827 + static int qmp_usbc_dp_power_on(struct phy *phy) 828 + { 829 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 830 + const struct qmp_phy_cfg *cfg = qmp->cfg; 831 + 832 + void __iomem *tx = qmp->dp_tx; 833 + void __iomem *tx2 = qmp->dp_tx2; 834 + 835 + mutex_lock(&qmp->phy_mutex); 836 + 837 + qmp_usbc_dp_serdes_init(qmp); 838 + 839 + qmp_configure_lane(qmp->dev, tx, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 1); 840 + qmp_configure_lane(qmp->dev, tx2, cfg->dp_tx_tbl, cfg->dp_tx_tbl_num, 2); 841 + 842 + /* Configure special DP tx tunings */ 843 + cfg->configure_dp_tx(qmp); 844 + 845 + /* Configure link rate, swing, etc. */ 846 + cfg->configure_dp_phy(qmp); 847 + 848 + mutex_unlock(&qmp->phy_mutex); 849 + 850 + return 0; 851 + } 852 + 853 + static int qmp_usbc_dp_power_off(struct phy *phy) 854 + { 855 + struct qmp_usbc *qmp = phy_get_drvdata(phy); 856 + 857 + mutex_lock(&qmp->phy_mutex); 858 + 859 + /* Assert DP PHY power down */ 860 + writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL); 861 + 862 + mutex_unlock(&qmp->phy_mutex); 863 + 864 + return 0; 865 + } 866 + 716 867 static const struct phy_ops qmp_usbc_usb_phy_ops = { 717 868 .init = qmp_usbc_usb_enable, 718 869 .exit = qmp_usbc_usb_disable, 719 870 .set_mode = qmp_usbc_usb_set_mode, 871 + .owner = THIS_MODULE, 872 + }; 873 + 874 + static const struct phy_ops qmp_usbc_dp_phy_ops = { 875 + .init = qmp_usbc_dp_enable, 876 + .exit = qmp_usbc_dp_disable, 877 + .configure = qmp_usbc_dp_configure, 878 + .calibrate = qmp_usbc_dp_calibrate, 879 + .power_on = qmp_usbc_dp_power_on, 880 + .power_off = qmp_usbc_dp_power_off, 720 881 .owner = THIS_MODULE, 721 882 }; 722 883 ··· 1464 1299 return 0; 1465 1300 } 1466 1301 1302 + static struct phy *qmp_usbc_phy_xlate(struct device *dev, const struct of_phandle_args *args) 1303 + { 1304 + struct qmp_usbc *qmp = dev_get_drvdata(dev); 1305 + 1306 + if (args->args_count == 0) 1307 + return qmp->usb_phy; 1308 + 1309 + switch (args->args[0]) { 1310 + case QMP_USB43DP_USB3_PHY: 1311 + return qmp->usb_phy; 1312 + case QMP_USB43DP_DP_PHY: 1313 + return qmp->dp_phy ?: ERR_PTR(-ENODEV); 1314 + } 1315 + 1316 + return ERR_PTR(-EINVAL); 1317 + } 1318 + 1467 1319 static int qmp_usbc_probe(struct platform_device *pdev) 1468 1320 { 1469 1321 struct device *dev = &pdev->dev; ··· 1551 1369 1552 1370 phy_set_drvdata(qmp->usb_phy, qmp); 1553 1371 1372 + if (qmp->dp_serdes != 0) { 1373 + qmp->dp_phy = devm_phy_create(dev, np, &qmp_usbc_dp_phy_ops); 1374 + if (IS_ERR(qmp->dp_phy)) { 1375 + ret = PTR_ERR(qmp->dp_phy); 1376 + dev_err(dev, "failed to create PHY: %d\n", ret); 1377 + goto err_node_put; 1378 + } 1379 + phy_set_drvdata(qmp->dp_phy, qmp); 1380 + } 1381 + 1554 1382 of_node_put(np); 1555 1383 1556 - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 1384 + phy_provider = devm_of_phy_provider_register(dev, qmp_usbc_phy_xlate); 1557 1385 1558 1386 return PTR_ERR_OR_ZERO(phy_provider); 1559 1387